fix/split providers (#271)

* refactor: ♻️ add explicit return to services

* refactor: ♻️ use provider get method

* refactor: ♻️ move obfuscation logic to router & separate public service

* build: 💚 add changeset
This commit is contained in:
Adrian Pilarczyk 2023-03-13 10:57:18 +01:00 committed by GitHub
parent 56a4dbb3a3
commit b46a9f3e70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 154 additions and 209 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-app-taxes": patch
---
Fix the create provider error. Add explicit return types to configuration services. Move obfuscating logic to routers and public services.

View file

@ -1,4 +1,5 @@
import { z } from "zod";
import { obfuscateSecret } from "../../lib/utils";
export const avataxConfigSchema = z.object({
name: z.string().min(1, { message: "Name requires at least one character." }),
@ -27,3 +28,15 @@ export const avataxInstanceConfigSchema = z.object({
});
export type AvataxInstanceConfig = z.infer<typeof avataxInstanceConfigSchema>;
export const obfuscateAvataxConfig = (config: AvataxConfig) => ({
...config,
username: obfuscateSecret(config.username),
password: obfuscateSecret(config.password),
});
export const obfuscateAvataxInstances = (instances: AvataxInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateAvataxConfig(instance.config),
}));

View file

@ -1,8 +1,9 @@
import { z } from "zod";
import { logger as pinoLogger } from "../../lib/logger";
import { isObfuscated } from "../../lib/utils";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
import { avataxConfigSchema } from "./avatax-config";
import { avataxConfigSchema, obfuscateAvataxConfig } from "./avatax-config";
import { AvataxConfigurationService } from "./avatax-configuration.service";
const getInputSchema = z.object({
@ -15,12 +16,14 @@ const deleteInputSchema = z.object({
const patchInputSchema = z.object({
id: z.string(),
value: avataxConfigSchema.partial(),
});
const putInputSchema = z.object({
id: z.string(),
value: avataxConfigSchema,
value: avataxConfigSchema.partial().transform((c) => {
const { username, password, ...config } = c ?? {};
return {
...config,
...(username && !isObfuscated(username) && { username }),
...(password && !isObfuscated(password) && { password }),
};
}),
});
const postInputSchema = z.object({
@ -43,7 +46,7 @@ export const avataxConfigurationRouter = router({
logger.debug({ result }, "avataxConfigurationRouter.get finished");
return result;
return { ...result, config: obfuscateAvataxConfig(result.config) };
}),
post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
@ -94,23 +97,6 @@ export const avataxConfigurationRouter = router({
logger.debug({ result }, "avataxConfigurationRouter.patch finished");
return result;
}),
put: protectedClientProcedure.input(putInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "avataxConfigurationRouter.put",
});
logger.debug("avataxConfigurationRouter.put called");
const { apiClient, saleorApiUrl } = ctx;
const avataxConfigurationService = new AvataxConfigurationService(apiClient, saleorApiUrl);
const result = await avataxConfigurationService.put(input.id, input.value);
logger.debug({ result }, "avataxConfigurationRouter.put finished");
return result;
}),
});

View file

@ -1,54 +1,14 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { isObfuscated, obfuscateSecret } from "../../lib/utils";
import { createSettingsManager } from "../app-configuration/metadata-manager";
import { CrudSettingsConfigurator } from "../crud-settings/crud-settings.service";
import { providersSchema } from "../providers-configuration/providers-config";
import { TAX_PROVIDER_KEY } from "../providers-configuration/providers-configuration-service";
import { TAX_PROVIDER_KEY } from "../providers-configuration/public-providers-configuration-service";
import { AvataxClient } from "./avatax-client";
import {
AvataxConfig,
avataxConfigSchema,
AvataxInstanceConfig,
avataxInstanceConfigSchema,
} from "./avatax-config";
const obfuscateConfig = (config: AvataxConfig) => ({
...config,
username: obfuscateSecret(config.username),
password: obfuscateSecret(config.password),
});
const obfuscateProvidersConfig = (instances: AvataxInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const getSchema = avataxInstanceConfigSchema.transform((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const patchSchema = avataxConfigSchema.partial().transform((c) => {
const { username, password, ...config } = c ?? {};
return {
...config,
...(username && !isObfuscated(username) && { username }),
...(password && !isObfuscated(password) && { password }),
};
});
const putSchema = avataxConfigSchema.transform((c) => {
const { username, password, ...config } = c;
return {
...config,
...(!isObfuscated(username) && { username }),
...(!isObfuscated(password) && { password }),
};
});
import { AvataxConfig, AvataxInstanceConfig, avataxInstanceConfigSchema } from "./avatax-config";
const getSchema = avataxInstanceConfigSchema;
export class AvataxConfigurationService {
private crudSettingsConfigurator: CrudSettingsConfigurator;
private logger: pino.Logger;
@ -65,7 +25,7 @@ export class AvataxConfigurationService {
});
}
async getAll() {
async getAll(): Promise<AvataxInstanceConfig[]> {
this.logger.debug(".getAll called");
const { data } = await this.crudSettingsConfigurator.readAll();
const validation = providersSchema.safeParse(data);
@ -79,10 +39,10 @@ export class AvataxConfigurationService {
(instance) => instance.provider === "avatax"
) as AvataxInstanceConfig[];
return obfuscateProvidersConfig(instances);
return instances;
}
async get(id: string) {
async get(id: string): Promise<AvataxInstanceConfig> {
this.logger.debug(`.get called with id: ${id}`);
const { data } = await this.crudSettingsConfigurator.read(id);
this.logger.debug({ setting: data }, `Fetched setting from crudSettingsConfigurator`);
@ -97,7 +57,7 @@ export class AvataxConfigurationService {
return validation.data;
}
async post(config: AvataxConfig) {
async post(config: AvataxConfig): Promise<{ id: string }> {
this.logger.debug(`.post called with value: ${JSON.stringify(config)}`);
const avataxClient = new AvataxClient(config);
const validation = await avataxClient.ping();
@ -106,45 +66,40 @@ export class AvataxConfigurationService {
this.logger.error(validation.error);
throw new Error(validation.error);
}
const result = await this.crudSettingsConfigurator.create({
provider: "avatax",
config: config,
});
return result.data;
}
async patch(id: string, config: Partial<AvataxConfig>) {
async patch(id: string, config: Partial<AvataxConfig>): Promise<void> {
this.logger.debug(`.patch called with id: ${id} and value: ${JSON.stringify(config)}`);
const result = await this.get(id);
const data = await this.get(id);
// omit the key "id" from the result
const { id: _, ...setting } = result;
const validation = patchSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
const { id: _, ...setting } = data;
return this.crudSettingsConfigurator.update(id, {
...setting,
config: { ...setting.config, ...validation.data },
config: { ...setting.config, ...config },
});
}
async put(id: string, config: AvataxConfig) {
const result = await this.get(id);
async put(id: string, config: AvataxConfig): Promise<void> {
const data = await this.get(id);
// omit the key "id" from the result
const { id: _, ...setting } = result;
const validation = putSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
const { id: _, ...setting } = data;
this.logger.debug(`.put called with id: ${id} and value: ${JSON.stringify(config)}`);
return this.crudSettingsConfigurator.update(id, {
...setting,
config: { ...validation.data },
config: { ...config },
});
}
async delete(id: string) {
async delete(id: string): Promise<void> {
this.logger.debug(`.delete called with id: ${id}`);
return this.crudSettingsConfigurator.delete(id);
}

View file

@ -13,10 +13,10 @@ import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
import { useInstanceId } from "../../taxes/tax-context";
import { trpcClient } from "../../trpc/trpc-client";
import { AppLink } from "../../ui/app-link";
import { useInstanceId } from "../../taxes/tax-context";
import { avataxConfigSchema, avataxInstanceConfigSchema } from "../avatax-config";
import { avataxConfigSchema } from "../avatax-config";
const useStyles = makeStyles((theme) => ({
reverseRow: {
@ -59,8 +59,12 @@ export const AvataxConfigurationForm = () => {
);
},
});
const { data: providersConfig, refetch: refetchProvidersConfigurationData } =
trpcClient.providersConfiguration.getAll.useQuery(undefined, {
const { refetch: refetchProvidersConfigurationData } =
trpcClient.providersConfiguration.getAll.useQuery();
const { data: instance } = trpcClient.avataxConfiguration.get.useQuery(
{ id: instanceId ?? "" },
{
enabled: !!instanceId,
onError(error) {
appBridge?.dispatch(
actions.Notification({
@ -70,9 +74,8 @@ export const AvataxConfigurationForm = () => {
})
);
},
});
const instance = providersConfig?.find((instance) => instance.id === instanceId);
}
);
const resetInstanceId = () => {
setInstanceId(null);
@ -89,7 +92,7 @@ export const AvataxConfigurationForm = () => {
const { mutate: createMutation, isLoading: isCreateLoading } =
trpcClient.avataxConfiguration.post.useMutation({
onSuccess({ data: { id } }) {
onSuccess({ id }) {
setInstanceId(id);
refetchProvidersConfigurationData();
appBridge?.dispatch(

View file

@ -6,7 +6,7 @@ import { TaxJarConfigurationService } from "../taxjar/taxjar-configuration.servi
export const TAX_PROVIDER_KEY = "tax-providers";
export class TaxProvidersConfigurationService {
export class PrivateTaxProvidersConfigurationService {
private avataxConfigurationService: AvataxConfigurationService;
private taxJarConfigurationService: TaxJarConfigurationService;
private logger: pino.Logger;
@ -14,7 +14,7 @@ export class TaxProvidersConfigurationService {
this.avataxConfigurationService = new AvataxConfigurationService(client, saleorApiUrl);
this.taxJarConfigurationService = new TaxJarConfigurationService(client, saleorApiUrl);
this.logger = createLogger({
service: "TaxProvidersConfigurationService",
service: "PrivateTaxProvidersConfigurationService",
metadataKey: TAX_PROVIDER_KEY,
});
}
@ -23,7 +23,6 @@ export class TaxProvidersConfigurationService {
this.logger.debug(".getAll called");
const taxJar = await this.taxJarConfigurationService.getAll();
const avatax = await this.avataxConfigurationService.getAll();
// todo: add more clever way of joining the two. Maybe add updated_at date to the config and use it to sort?
return [...taxJar, ...avatax];
}
}

View file

@ -1,7 +1,7 @@
import { logger as pinoLogger } from "../../lib/logger";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
import { TaxProvidersConfigurationService } from "./providers-configuration-service";
import { PublicTaxProvidersConfigurationService } from "./public-providers-configuration-service";
export const providersConfigurationRouter = router({
getAll: protectedClientProcedure.query(async ({ ctx }) => {
@ -9,6 +9,6 @@ export const providersConfigurationRouter = router({
logger.debug("providersConfigurationRouter.fetch called");
return new TaxProvidersConfigurationService(ctx.apiClient, ctx.saleorApiUrl).getAll();
return new PublicTaxProvidersConfigurationService(ctx.apiClient, ctx.saleorApiUrl).getAll();
}),
});

View file

@ -0,0 +1,30 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { obfuscateAvataxInstances } from "../avatax/avatax-config";
import { AvataxConfigurationService } from "../avatax/avatax-configuration.service";
import { obfuscateTaxJarInstances } from "../taxjar/taxjar-config";
import { TaxJarConfigurationService } from "../taxjar/taxjar-configuration.service";
export const TAX_PROVIDER_KEY = "tax-providers";
export class PublicTaxProvidersConfigurationService {
private avataxConfigurationService: AvataxConfigurationService;
private taxJarConfigurationService: TaxJarConfigurationService;
private logger: pino.Logger;
constructor(client: Client, saleorApiUrl: string) {
this.avataxConfigurationService = new AvataxConfigurationService(client, saleorApiUrl);
this.taxJarConfigurationService = new TaxJarConfigurationService(client, saleorApiUrl);
this.logger = createLogger({
service: "PublicTaxProvidersConfigurationService",
metadataKey: TAX_PROVIDER_KEY,
});
}
async getAll() {
this.logger.debug(".getAll called");
const taxJar = await this.taxJarConfigurationService.getAll();
const avatax = await this.avataxConfigurationService.getAll();
return [...obfuscateTaxJarInstances(taxJar), ...obfuscateAvataxInstances(avatax)];
}
}

View file

@ -21,3 +21,14 @@ export const taxJarInstanceConfigSchema = z.object({
});
export type TaxJarInstanceConfig = z.infer<typeof taxJarInstanceConfigSchema>;
export const obfuscateTaxJarConfig = (config: TaxJarConfig) => ({
...config,
apiKey: obfuscateSecret(config.apiKey),
});
export const obfuscateTaxJarInstances = (instances: TaxJarInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateTaxJarConfig(instance.config),
}));

View file

@ -1,8 +1,9 @@
import { z } from "zod";
import { logger as pinoLogger } from "../../lib/logger";
import { isObfuscated } from "../../lib/utils";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
import { taxJarConfigSchema } from "./taxjar-config";
import { obfuscateTaxJarConfig, taxJarConfigSchema } from "./taxjar-config";
import { TaxJarConfigurationService } from "./taxjar-configuration.service";
const getInputSchema = z.object({
@ -15,12 +16,13 @@ const deleteInputSchema = z.object({
const patchInputSchema = z.object({
id: z.string(),
value: taxJarConfigSchema.partial(),
});
const putInputSchema = z.object({
id: z.string(),
value: taxJarConfigSchema,
value: taxJarConfigSchema.partial().transform((c) => {
const { apiKey, ...config } = c ?? {};
return {
...config,
...(apiKey && !isObfuscated(apiKey) && { apiKey }),
};
}),
});
const postInputSchema = z.object({
@ -43,7 +45,7 @@ export const taxjarConfigurationRouter = router({
logger.debug({ result }, "taxjarConfigurationRouter.get finished");
return result;
return { ...result, config: obfuscateTaxJarConfig(result.config) };
}),
post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
@ -94,23 +96,6 @@ export const taxjarConfigurationRouter = router({
logger.debug({ result }, "taxjarConfigurationRouter.patch finished");
return result;
}),
put: protectedClientProcedure.input(putInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "taxjarConfigurationRouter.put",
});
logger.debug("taxjarConfigurationRouter.put called");
const { apiClient, saleorApiUrl } = ctx;
const taxjarConfigurationService = new TaxJarConfigurationService(apiClient, saleorApiUrl);
const result = await taxjarConfigurationService.put(input.id, input.value);
logger.debug({ result }, "taxjarConfigurationRouter.put finished");
return result;
}),
});

View file

@ -1,50 +1,14 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { isObfuscated, obfuscateSecret } from "../../lib/utils";
import { createSettingsManager } from "../app-configuration/metadata-manager";
import { CrudSettingsConfigurator } from "../crud-settings/crud-settings.service";
import { providersSchema } from "../providers-configuration/providers-config";
import { TAX_PROVIDER_KEY } from "../providers-configuration/providers-configuration-service";
import { TAX_PROVIDER_KEY } from "../providers-configuration/public-providers-configuration-service";
import { TaxJarClient } from "./taxjar-client";
import {
TaxJarConfig,
taxJarConfigSchema,
TaxJarInstanceConfig,
taxJarInstanceConfigSchema,
} from "./taxjar-config";
import { TaxJarConfig, TaxJarInstanceConfig, taxJarInstanceConfigSchema } from "./taxjar-config";
const obfuscateConfig = (config: TaxJarConfig) => ({
...config,
apiKey: obfuscateSecret(config.apiKey),
});
const obfuscateProvidersConfig = (instances: TaxJarInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const getSchema = taxJarInstanceConfigSchema.transform((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const patchSchema = taxJarConfigSchema.partial().transform((c) => {
const { apiKey, ...config } = c ?? {};
return {
...config,
...(apiKey && !isObfuscated(apiKey) && { apiKey }),
};
});
const putSchema = taxJarConfigSchema.transform((c) => {
const { apiKey, ...config } = c;
return {
...config,
...(!isObfuscated(apiKey) && { apiKey }),
};
});
const getSchema = taxJarInstanceConfigSchema;
export class TaxJarConfigurationService {
private crudSettingsConfigurator: CrudSettingsConfigurator;
@ -62,7 +26,7 @@ export class TaxJarConfigurationService {
});
}
async getAll() {
async getAll(): Promise<TaxJarInstanceConfig[]> {
this.logger.debug(".getAll called");
const { data } = await this.crudSettingsConfigurator.readAll();
this.logger.debug({ settings: data }, `Fetched settings from crudSettingsConfigurator`);
@ -77,12 +41,12 @@ export class TaxJarConfigurationService {
(instance) => instance.provider === "taxjar"
) as TaxJarInstanceConfig[];
return obfuscateProvidersConfig(instances);
return instances;
}
async get(id: string) {
async get(id: string): Promise<TaxJarInstanceConfig> {
this.logger.debug(`.get called with id: ${id}`);
const { data } = await this.crudSettingsConfigurator.read(id);
const data = await this.crudSettingsConfigurator.read(id);
this.logger.debug({ setting: data }, `Fetched setting from crudSettingsConfigurator`);
const validation = getSchema.safeParse(data);
@ -95,7 +59,7 @@ export class TaxJarConfigurationService {
return validation.data;
}
async post(config: TaxJarConfig) {
async post(config: TaxJarConfig): Promise<{ id: string }> {
this.logger.debug(`.post called with value: ${JSON.stringify(config)}`);
const taxJarClient = new TaxJarClient(config);
const validation = await taxJarClient.ping();
@ -104,49 +68,39 @@ export class TaxJarConfigurationService {
this.logger.error({ error: validation.error }, "Validation error while post");
throw new Error(validation.error);
}
return this.crudSettingsConfigurator.create({
const result = await this.crudSettingsConfigurator.create({
provider: "taxjar",
config: config,
});
return result.data;
}
async patch(id: string, config: Partial<TaxJarConfig>) {
async patch(id: string, config: Partial<TaxJarConfig>): Promise<void> {
this.logger.debug(`.patch called with id: ${id} and value: ${JSON.stringify(config)}`);
const result = await this.get(id);
const data = await this.get(id);
// omit the key "id" from the result
const { id: _, ...setting } = result;
const validation = patchSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
const { id: _, ...setting } = data;
return this.crudSettingsConfigurator.update(id, {
...setting,
config: { ...setting.config, ...validation.data },
config: { ...setting.config, ...config },
});
}
async put(id: string, config: TaxJarConfig) {
const result = await this.get(id);
async put(id: string, config: TaxJarConfig): Promise<void> {
const data = await this.get(id);
// omit the key "id" from the result
const { id: _, ...setting } = result;
const validation = putSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
const { id: _, ...setting } = data;
this.logger.debug(`.put called with id: ${id} and value: ${JSON.stringify(config)}`);
return this.crudSettingsConfigurator.update(id, {
...setting,
config: { ...validation.data },
config: { ...config },
});
}
async delete(id: string) {
async delete(id: string): Promise<void> {
this.logger.debug(`.delete called with id: ${id}`);
return this.crudSettingsConfigurator.delete(id);
}

View file

@ -13,9 +13,9 @@ import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
import { trpcClient } from "../../trpc/trpc-client";
import { useInstanceId } from "../../taxes/tax-context";
import { taxJarConfigSchema, taxJarInstanceConfigSchema } from "../taxjar-config";
import { trpcClient } from "../../trpc/trpc-client";
import { taxJarConfigSchema } from "../taxjar-config";
const useStyles = makeStyles((theme) => ({
reverseRow: {
@ -61,8 +61,12 @@ export const TaxJarConfigurationForm = () => {
},
});
const { data: providersConfigurationData, refetch: refetchProvidersConfigurationData } =
trpcClient.providersConfiguration.getAll.useQuery(undefined, {
const { refetch: refetchProvidersConfigurationData } =
trpcClient.providersConfiguration.getAll.useQuery();
const { data: instance } = trpcClient.avataxConfiguration.get.useQuery(
{ id: instanceId ?? "" },
{
enabled: !!instanceId,
onError(error) {
appBridge?.dispatch(
actions.Notification({
@ -72,13 +76,12 @@ export const TaxJarConfigurationForm = () => {
})
);
},
});
const instance = providersConfigurationData?.find((instance) => instance.id === instanceId);
}
);
const { mutate: createMutation, isLoading: isCreateLoading } =
trpcClient.taxJarConfiguration.post.useMutation({
onSuccess({ data: { id } }) {
onSuccess({ id }) {
setInstanceId(id);
refetchProvidersConfigurationData();
refetchChannelConfigurationData();

View file

@ -5,7 +5,8 @@ import { createClient } from "../../../lib/graphql";
import { createLogger } from "../../../lib/logger";
import { calculateTaxesPayloadSchema, ExpectedWebhookPayload } from "../../../lib/saleor/schema";
import { GetChannelsConfigurationService } from "../../../modules/channels-configuration/get-channels-configuration.service";
import { TaxProvidersConfigurationService } from "../../../modules/providers-configuration/providers-configuration-service";
import { PrivateTaxProvidersConfigurationService } from "../../../modules/providers-configuration/private-providers-configuration-service";
import { ActiveTaxProvider } from "../../../modules/taxes/active-tax-provider";
export const config = {
@ -43,7 +44,7 @@ export default checkoutCalculateTaxesSyncWebhook.createHandler(async (req, res,
Promise.resolve({ token: authData.token })
);
const providersConfig = await new TaxProvidersConfigurationService(
const providersConfig = await new PrivateTaxProvidersConfigurationService(
client,
authData.saleorApiUrl
).getAll();

View file

@ -5,7 +5,7 @@ import { createClient } from "../../../lib/graphql";
import { createLogger } from "../../../lib/logger";
import { calculateTaxesPayloadSchema, ExpectedWebhookPayload } from "../../../lib/saleor/schema";
import { GetChannelsConfigurationService } from "../../../modules/channels-configuration/get-channels-configuration.service";
import { TaxProvidersConfigurationService } from "../../../modules/providers-configuration/providers-configuration-service";
import { PrivateTaxProvidersConfigurationService } from "../../../modules/providers-configuration/private-providers-configuration-service";
import { ActiveTaxProvider } from "../../../modules/taxes/active-tax-provider";
export const config = {
@ -42,7 +42,7 @@ export default orderCalculateTaxesSyncWebhook.createHandler(async (req, res, ctx
const client = createClient(authData.saleorApiUrl, async () =>
Promise.resolve({ token: authData.token })
);
const providersConfig = await new TaxProvidersConfigurationService(
const providersConfig = await new PrivateTaxProvidersConfigurationService(
client,
authData.saleorApiUrl
).getAll();