Compare commits
6 commits
main
...
taxes/impr
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f9cee07aa7 | ||
![]() |
20e8ed4086 | ||
![]() |
24c31d733a | ||
![]() |
ce7b5cc5e1 | ||
![]() |
df4da32b4a | ||
![]() |
3c20d095ff |
25 changed files with 303 additions and 164 deletions
|
@ -31,6 +31,8 @@
|
||||||
"graphql-tag": "^2.12.6",
|
"graphql-tag": "^2.12.6",
|
||||||
"jotai": "^2.4.2",
|
"jotai": "^2.4.2",
|
||||||
"jsdom": "^20.0.3",
|
"jsdom": "^20.0.3",
|
||||||
|
"modern-errors": "^6.0.0",
|
||||||
|
"modern-errors-serialize": "^5.0.0",
|
||||||
"next": "13.4.8",
|
"next": "13.4.8",
|
||||||
"pino": "^8.14.1",
|
"pino": "^8.14.1",
|
||||||
"pino-pretty": "^10.0.0",
|
"pino-pretty": "^10.0.0",
|
||||||
|
|
6
apps/taxes/src/error.ts
Normal file
6
apps/taxes/src/error.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import ModernError from "modern-errors";
|
||||||
|
import modernErrorsSerialize from "modern-errors-serialize";
|
||||||
|
|
||||||
|
export const BaseError = ModernError.subclass("BaseError", {
|
||||||
|
plugins: [modernErrorsSerialize],
|
||||||
|
});
|
|
@ -1,41 +1,7 @@
|
||||||
import { NextApiResponse } from "next";
|
import { NextApiResponse } from "next";
|
||||||
|
|
||||||
import { AvalaraError } from "avatax/lib/AvaTaxClient";
|
|
||||||
import { ZodError } from "zod";
|
|
||||||
import { createLogger, Logger } from "../../lib/logger";
|
import { createLogger, Logger } from "../../lib/logger";
|
||||||
|
import { TaxBadWebhookPayloadError, TaxCriticalError } from "../taxes/tax-error";
|
||||||
class WebhookErrorResolver {
|
|
||||||
private logger: Logger;
|
|
||||||
constructor() {
|
|
||||||
this.logger = createLogger({ event: "WebhookErrorResolver" });
|
|
||||||
}
|
|
||||||
|
|
||||||
private resolveErrorMessage(error: unknown) {
|
|
||||||
if (error instanceof ZodError) {
|
|
||||||
this.logger.error(error.message, "Unexpected Zod error caught:");
|
|
||||||
this.logger.debug(error.stack, "Error details:");
|
|
||||||
return error.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error instanceof AvalaraError) {
|
|
||||||
this.logger.error(error.message, "Unexpected Avalara error caught:");
|
|
||||||
this.logger.debug(error.stack, "Error stack:");
|
|
||||||
this.logger.debug(error.target, "Error target:");
|
|
||||||
return error.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error instanceof Error) {
|
|
||||||
this.logger.error(error.stack, "Unexpected error caught:");
|
|
||||||
return error.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Internal server error";
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(error: unknown) {
|
|
||||||
return this.resolveErrorMessage(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WebhookResponse {
|
export class WebhookResponse {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
@ -43,15 +9,30 @@ export class WebhookResponse {
|
||||||
this.logger = createLogger({ event: "WebhookResponse" });
|
this.logger = createLogger({ event: "WebhookResponse" });
|
||||||
}
|
}
|
||||||
|
|
||||||
error(error: unknown) {
|
private respondWithBadRequest(errorMessage: string) {
|
||||||
const errorResolver = new WebhookErrorResolver();
|
// Are we sure its 400?
|
||||||
const errorMessage = errorResolver.resolve(error);
|
return this.res.status(400).json({ error: errorMessage });
|
||||||
|
}
|
||||||
this.logger.debug({ errorMessage }, "Responding to Saleor with error:");
|
|
||||||
|
|
||||||
|
private respondWithInternalServerError(errorMessage: string) {
|
||||||
return this.res.status(500).json({ error: errorMessage });
|
return this.res.status(500).json({ error: errorMessage });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error(error: unknown) {
|
||||||
|
if (error instanceof TaxBadWebhookPayloadError) {
|
||||||
|
this.logger.warn({ error }, "TaxBadWebhookPayloadError occurred");
|
||||||
|
return this.respondWithBadRequest(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error instanceof TaxCriticalError) {
|
||||||
|
this.logger.error({ error }, "TaxCriticalError occurred");
|
||||||
|
return this.respondWithInternalServerError(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.error({ error }, "Unexpected error occurred");
|
||||||
|
return this.respondWithInternalServerError("Unexpected error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
success(data?: unknown) {
|
success(data?: unknown) {
|
||||||
return this.res.status(200).json(data ?? {});
|
return this.res.status(200).json(data ?? {});
|
||||||
}
|
}
|
||||||
|
|
17
apps/taxes/src/modules/avatax/avatax-error-normalizer.ts
Normal file
17
apps/taxes/src/modules/avatax/avatax-error-normalizer.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { createLogger } from "../../lib/logger";
|
||||||
|
import { AvalaraError } from "avatax/lib/AvaTaxClient";
|
||||||
|
import { TaxExternalError, TaxUnexpectedError } from "../taxes/tax-error";
|
||||||
|
|
||||||
|
export class AvataxErrorNormalizer {
|
||||||
|
private logger = createLogger({ name: "AvataxErrorNormalizer" });
|
||||||
|
|
||||||
|
normalize(error: unknown) {
|
||||||
|
if (error instanceof AvalaraError) {
|
||||||
|
this.logger.debug(error.stack, "AvalaraError occurred");
|
||||||
|
|
||||||
|
return new TaxExternalError(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TaxUnexpectedError.normalize(error);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import { AvataxConfig } from "../avatax-connection-schema";
|
||||||
import { ClientLogger } from "../../logs/client-logger";
|
import { ClientLogger } from "../../logs/client-logger";
|
||||||
import { AvataxCalculateTaxesPayloadService } from "./avatax-calculate-taxes-payload.service";
|
import { AvataxCalculateTaxesPayloadService } from "./avatax-calculate-taxes-payload.service";
|
||||||
import { AvataxCalculateTaxesResponseTransformer } from "./avatax-calculate-taxes-response-transformer";
|
import { AvataxCalculateTaxesResponseTransformer } from "./avatax-calculate-taxes-response-transformer";
|
||||||
|
import { AvataxErrorNormalizer } from "../avatax-error-normalizer";
|
||||||
|
|
||||||
export const SHIPPING_ITEM_CODE = "Shipping";
|
export const SHIPPING_ITEM_CODE = "Shipping";
|
||||||
|
|
||||||
|
@ -67,6 +68,8 @@ export class AvataxCalculateTaxesAdapter
|
||||||
|
|
||||||
return transformedResponse;
|
return transformedResponse;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errorNormalizer = new AvataxErrorNormalizer();
|
||||||
|
|
||||||
this.clientLogger.push({
|
this.clientLogger.push({
|
||||||
event: "[CalculateTaxes] createTransaction",
|
event: "[CalculateTaxes] createTransaction",
|
||||||
status: "error",
|
status: "error",
|
||||||
|
@ -75,7 +78,7 @@ export class AvataxCalculateTaxesAdapter
|
||||||
output: error,
|
output: error,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
throw error;
|
throw errorNormalizer.normalize(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { DocumentType } from "avatax/lib/enums/DocumentType";
|
import { DocumentType } from "avatax/lib/enums/DocumentType";
|
||||||
import { TaxBaseFragment } from "../../../../generated/graphql";
|
import { CalculateTaxesPayload } from "../../../pages/api/webhooks/checkout-calculate-taxes";
|
||||||
import { discountUtils } from "../../taxes/discount-utils";
|
import { discountUtils } from "../../taxes/discount-utils";
|
||||||
|
import { TaxUnexpectedError } from "../../taxes/tax-error";
|
||||||
|
import { taxProviderUtils } from "../../taxes/tax-provider-utils";
|
||||||
import { avataxAddressFactory } from "../address-factory";
|
import { avataxAddressFactory } from "../address-factory";
|
||||||
import { AvataxClient, CreateTransactionArgs } from "../avatax-client";
|
import { AvataxClient, CreateTransactionArgs } from "../avatax-client";
|
||||||
import { AvataxConfig, defaultAvataxConfig } from "../avatax-connection-schema";
|
import { AvataxConfig, defaultAvataxConfig } from "../avatax-connection-schema";
|
||||||
|
import { AvataxEntityTypeMatcher } from "../avatax-entity-type-matcher";
|
||||||
import { AvataxTaxCodeMatches } from "../tax-code/avatax-tax-code-match-repository";
|
import { AvataxTaxCodeMatches } from "../tax-code/avatax-tax-code-match-repository";
|
||||||
import { AvataxCalculateTaxesPayloadLinesTransformer } from "./avatax-calculate-taxes-payload-lines-transformer";
|
import { AvataxCalculateTaxesPayloadLinesTransformer } from "./avatax-calculate-taxes-payload-lines-transformer";
|
||||||
import { AvataxEntityTypeMatcher } from "../avatax-entity-type-matcher";
|
|
||||||
import { taxProviderUtils } from "../../taxes/tax-provider-utils";
|
|
||||||
import { CalculateTaxesPayload } from "../../../pages/api/webhooks/checkout-calculate-taxes";
|
|
||||||
|
|
||||||
export class AvataxCalculateTaxesPayloadTransformer {
|
export class AvataxCalculateTaxesPayloadTransformer {
|
||||||
private matchDocumentType(config: AvataxConfig): DocumentType {
|
private matchDocumentType(config: AvataxConfig): DocumentType {
|
||||||
|
@ -31,7 +31,7 @@ export class AvataxCalculateTaxesPayloadTransformer {
|
||||||
return taxProviderUtils.resolveStringOrThrow(payload.taxBase.sourceObject.userEmail);
|
return taxProviderUtils.resolveStringOrThrow(payload.taxBase.sourceObject.userEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Cannot resolve customer code");
|
throw new TaxUnexpectedError("Cannot resolve customer code");
|
||||||
}
|
}
|
||||||
|
|
||||||
async transform(
|
async transform(
|
||||||
|
|
|
@ -14,11 +14,11 @@ export class AvataxCalculateTaxesResponseLinesTransformer {
|
||||||
return {
|
return {
|
||||||
total_gross_amount: taxProviderUtils.resolveOptionalOrThrow(
|
total_gross_amount: taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line.lineAmount,
|
line.lineAmount,
|
||||||
new Error("line.lineAmount is undefined")
|
"line.lineAmount is undefined",
|
||||||
),
|
),
|
||||||
total_net_amount: taxProviderUtils.resolveOptionalOrThrow(
|
total_net_amount: taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line.lineAmount,
|
line.lineAmount,
|
||||||
new Error("line.lineAmount is undefined")
|
"line.lineAmount is undefined",
|
||||||
),
|
),
|
||||||
tax_rate: 0,
|
tax_rate: 0,
|
||||||
};
|
};
|
||||||
|
@ -26,21 +26,21 @@ export class AvataxCalculateTaxesResponseLinesTransformer {
|
||||||
|
|
||||||
const lineTaxCalculated = taxProviderUtils.resolveOptionalOrThrow(
|
const lineTaxCalculated = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line.taxCalculated,
|
line.taxCalculated,
|
||||||
new Error("line.taxCalculated is undefined")
|
"line.taxCalculated is undefined",
|
||||||
);
|
);
|
||||||
const lineTotalNetAmount = taxProviderUtils.resolveOptionalOrThrow(
|
const lineTotalNetAmount = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line.taxableAmount,
|
line.taxableAmount,
|
||||||
new Error("line.taxableAmount is undefined")
|
"line.taxableAmount is undefined",
|
||||||
);
|
);
|
||||||
const lineTotalGrossAmount = numbers.roundFloatToTwoDecimals(
|
const lineTotalGrossAmount = numbers.roundFloatToTwoDecimals(
|
||||||
lineTotalNetAmount + lineTaxCalculated
|
lineTotalNetAmount + lineTaxCalculated,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total_gross_amount: lineTotalGrossAmount,
|
total_gross_amount: lineTotalGrossAmount,
|
||||||
total_net_amount: lineTotalNetAmount,
|
total_net_amount: lineTotalNetAmount,
|
||||||
/*
|
/*
|
||||||
* avatax doesnt return combined tax rate
|
* avatax doesn't return combined tax rate
|
||||||
* // todo: calculate percentage tax rate
|
* // todo: calculate percentage tax rate
|
||||||
*/ tax_rate: 0,
|
*/ tax_rate: 0,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { SHIPPING_ITEM_CODE } from "./avatax-calculate-taxes-adapter";
|
||||||
|
|
||||||
export class AvataxCalculateTaxesResponseShippingTransformer {
|
export class AvataxCalculateTaxesResponseShippingTransformer {
|
||||||
transform(
|
transform(
|
||||||
transaction: TransactionModel
|
transaction: TransactionModel,
|
||||||
): Pick<
|
): Pick<
|
||||||
CalculateTaxesResponse,
|
CalculateTaxesResponse,
|
||||||
"shipping_price_gross_amount" | "shipping_price_net_amount" | "shipping_tax_rate"
|
"shipping_price_gross_amount" | "shipping_price_net_amount" | "shipping_tax_rate"
|
||||||
|
@ -25,14 +25,14 @@ export class AvataxCalculateTaxesResponseShippingTransformer {
|
||||||
return {
|
return {
|
||||||
shipping_price_gross_amount: taxProviderUtils.resolveOptionalOrThrow(
|
shipping_price_gross_amount: taxProviderUtils.resolveOptionalOrThrow(
|
||||||
shippingLine.lineAmount,
|
shippingLine.lineAmount,
|
||||||
new Error("shippingLine.lineAmount is undefined")
|
"shippingLine.lineAmount is undefined",
|
||||||
),
|
),
|
||||||
shipping_price_net_amount: taxProviderUtils.resolveOptionalOrThrow(
|
shipping_price_net_amount: taxProviderUtils.resolveOptionalOrThrow(
|
||||||
shippingLine.lineAmount,
|
shippingLine.lineAmount,
|
||||||
new Error("shippingLine.lineAmount is undefined")
|
"shippingLine.lineAmount is undefined",
|
||||||
),
|
),
|
||||||
/*
|
/*
|
||||||
* avatax doesnt return combined tax rate
|
* avatax doesn't return combined tax rate
|
||||||
* // todo: calculate percentage tax rate
|
* // todo: calculate percentage tax rate
|
||||||
*/
|
*/
|
||||||
shipping_tax_rate: 0,
|
shipping_tax_rate: 0,
|
||||||
|
@ -41,14 +41,14 @@ export class AvataxCalculateTaxesResponseShippingTransformer {
|
||||||
|
|
||||||
const shippingTaxCalculated = taxProviderUtils.resolveOptionalOrThrow(
|
const shippingTaxCalculated = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
shippingLine.taxCalculated,
|
shippingLine.taxCalculated,
|
||||||
new Error("shippingLine.taxCalculated is undefined")
|
"shippingLine.taxCalculated is undefined",
|
||||||
);
|
);
|
||||||
const shippingTaxableAmount = taxProviderUtils.resolveOptionalOrThrow(
|
const shippingTaxableAmount = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
shippingLine.taxableAmount,
|
shippingLine.taxableAmount,
|
||||||
new Error("shippingLine.taxableAmount is undefined")
|
"shippingLine.taxableAmount is undefined",
|
||||||
);
|
);
|
||||||
const shippingGrossAmount = numbers.roundFloatToTwoDecimals(
|
const shippingGrossAmount = numbers.roundFloatToTwoDecimals(
|
||||||
shippingTaxableAmount + shippingTaxCalculated
|
shippingTaxableAmount + shippingTaxCalculated,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { AddressResolutionModel } from "avatax/lib/models/AddressResolutionModel";
|
|
||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import { AvataxValidationResponseResolver } from "./avatax-validation-response-resolver";
|
|
||||||
import { ResolutionQuality } from "avatax/lib/enums/ResolutionQuality";
|
|
||||||
import { JurisdictionType } from "avatax/lib/enums/JurisdictionType";
|
|
||||||
|
|
||||||
const mockFailedValidationResponse: AddressResolutionModel = {
|
|
||||||
address: {
|
|
||||||
line1: "2000 Main Street",
|
|
||||||
city: "Irvine",
|
|
||||||
region: "CA",
|
|
||||||
country: "US",
|
|
||||||
postalCode: "92614",
|
|
||||||
},
|
|
||||||
coordinates: {
|
|
||||||
latitude: 33.684884,
|
|
||||||
longitude: -117.851321,
|
|
||||||
},
|
|
||||||
resolutionQuality: ResolutionQuality.Intersection,
|
|
||||||
taxAuthorities: [
|
|
||||||
{
|
|
||||||
avalaraId: "AGAM",
|
|
||||||
jurisdictionName: "CALIFORNIA",
|
|
||||||
jurisdictionType: JurisdictionType.State,
|
|
||||||
signatureCode: "AGAM",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
summary: "The address is not deliverable.",
|
|
||||||
details:
|
|
||||||
"The physical location exists but there are no homes on this street. One reason might be railroad tracks or rivers running alongside this street, as they would prevent construction of homes in this location.",
|
|
||||||
refersTo: "address",
|
|
||||||
severity: "Error",
|
|
||||||
source: "Avalara.AvaTax.Services.Address",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockSuccessfulValidationResponse: AddressResolutionModel = {
|
|
||||||
...mockFailedValidationResponse,
|
|
||||||
messages: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("AvataxValidationResponseResolver", () => {
|
|
||||||
const responseResolver = new AvataxValidationResponseResolver();
|
|
||||||
|
|
||||||
it("should throw error when messages", () => {
|
|
||||||
expect(() => responseResolver.resolve(mockFailedValidationResponse)).toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw error when no messages", () => {
|
|
||||||
expect(() => responseResolver.resolve(mockSuccessfulValidationResponse)).not.toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not return anything when no messages", () => {
|
|
||||||
expect(responseResolver.resolve(mockSuccessfulValidationResponse)).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { AddressResolutionModel } from "avatax/lib/models/AddressResolutionModel";
|
|
||||||
|
|
||||||
export class AvataxValidationResponseResolver {
|
|
||||||
resolve(response: AddressResolutionModel) {
|
|
||||||
if (response.messages && response.messages.length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
"The provided address is invalid. Please visit https://developer.avalara.com/avatax/address-validation/ to learn about address formatting."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,7 @@ import { AvataxClient, VoidTransactionArgs } from "../avatax-client";
|
||||||
import { AvataxConfig } from "../avatax-connection-schema";
|
import { AvataxConfig } from "../avatax-connection-schema";
|
||||||
import { ClientLogger } from "../../logs/client-logger";
|
import { ClientLogger } from "../../logs/client-logger";
|
||||||
import { AvataxOrderCancelledPayloadTransformer } from "./avatax-order-cancelled-payload-transformer";
|
import { AvataxOrderCancelledPayloadTransformer } from "./avatax-order-cancelled-payload-transformer";
|
||||||
|
import { AvataxErrorNormalizer } from "../avatax-error-normalizer";
|
||||||
|
|
||||||
export type AvataxOrderCancelledTarget = VoidTransactionArgs;
|
export type AvataxOrderCancelledTarget = VoidTransactionArgs;
|
||||||
|
|
||||||
|
@ -43,6 +44,8 @@ export class AvataxOrderCancelledAdapter implements WebhookAdapter<OrderCancelle
|
||||||
|
|
||||||
this.logger.debug(`Successfully voided the transaction of id: ${target.transactionCode}`);
|
this.logger.debug(`Successfully voided the transaction of id: ${target.transactionCode}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errorNormalizer = new AvataxErrorNormalizer();
|
||||||
|
|
||||||
this.clientLogger.push({
|
this.clientLogger.push({
|
||||||
event: "[OrderCancelled] voidTransaction",
|
event: "[OrderCancelled] voidTransaction",
|
||||||
status: "error",
|
status: "error",
|
||||||
|
@ -51,6 +54,8 @@ export class AvataxOrderCancelledAdapter implements WebhookAdapter<OrderCancelle
|
||||||
output: error,
|
output: error,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
throw errorNormalizer.normalize(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { AuthData } from "@saleor/app-sdk/APL";
|
import { AuthData } from "@saleor/app-sdk/APL";
|
||||||
import { OrderConfirmedSubscriptionFragment } from "../../../../generated/graphql";
|
import { OrderConfirmedSubscriptionFragment } from "../../../../generated/graphql";
|
||||||
import { Logger, createLogger } from "../../../lib/logger";
|
import { Logger, createLogger } from "../../../lib/logger";
|
||||||
|
import { ClientLogger } from "../../logs/client-logger";
|
||||||
import { CreateOrderResponse } from "../../taxes/tax-provider-webhook";
|
import { CreateOrderResponse } from "../../taxes/tax-provider-webhook";
|
||||||
import { WebhookAdapter } from "../../taxes/tax-webhook-adapter";
|
import { WebhookAdapter } from "../../taxes/tax-webhook-adapter";
|
||||||
import { AvataxClient } from "../avatax-client";
|
import { AvataxClient } from "../avatax-client";
|
||||||
import { AvataxConfig } from "../avatax-connection-schema";
|
import { AvataxConfig } from "../avatax-connection-schema";
|
||||||
import { ClientLogger } from "../../logs/client-logger";
|
|
||||||
import { AvataxOrderConfirmedPayloadService } from "./avatax-order-confirmed-payload.service";
|
import { AvataxOrderConfirmedPayloadService } from "./avatax-order-confirmed-payload.service";
|
||||||
import { AvataxOrderConfirmedResponseTransformer } from "./avatax-order-confirmed-response-transformer";
|
import { AvataxOrderConfirmedResponseTransformer } from "./avatax-order-confirmed-response-transformer";
|
||||||
|
import { AvataxErrorNormalizer } from "../avatax-error-normalizer";
|
||||||
|
|
||||||
type AvataxOrderConfirmedPayload = {
|
type AvataxOrderConfirmedPayload = {
|
||||||
order: OrderConfirmedSubscriptionFragment;
|
order: OrderConfirmedSubscriptionFragment;
|
||||||
|
@ -68,6 +69,8 @@ export class AvataxOrderConfirmedAdapter
|
||||||
|
|
||||||
return transformedResponse;
|
return transformedResponse;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errorNormalizer = new AvataxErrorNormalizer();
|
||||||
|
|
||||||
this.clientLogger.push({
|
this.clientLogger.push({
|
||||||
event: "[OrderConfirmed] createTransaction",
|
event: "[OrderConfirmed] createTransaction",
|
||||||
status: "error",
|
status: "error",
|
||||||
|
@ -76,7 +79,8 @@ export class AvataxOrderConfirmedAdapter
|
||||||
output: error,
|
output: error,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
throw error;
|
|
||||||
|
throw errorNormalizer.normalize(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,7 @@ export class AvataxOrderConfirmedResponseTransformer {
|
||||||
return {
|
return {
|
||||||
id: taxProviderUtils.resolveOptionalOrThrow(
|
id: taxProviderUtils.resolveOptionalOrThrow(
|
||||||
response.code,
|
response.code,
|
||||||
new Error(
|
"Could not update the order metadata with AvaTax transaction code because it was not returned from the createTransaction mutation.",
|
||||||
"Could not update the order metadata with AvaTax transaction code because it was not returned from the createTransaction mutation."
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
18
apps/taxes/src/modules/taxes/tax-error.ts
Normal file
18
apps/taxes/src/modules/taxes/tax-error.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { BaseError } from "../../error";
|
||||||
|
|
||||||
|
const TaxError = BaseError.subclass("TaxError");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Errors that happen if there is not enough data in webhook payload to proceed with the process. Is not reported.
|
||||||
|
* Better name: BadRequestError?
|
||||||
|
*/
|
||||||
|
export const TaxBadWebhookPayloadError = TaxError.subclass("TaxBadWebhookPayloadError");
|
||||||
|
|
||||||
|
// Breaks the process. Is reported.
|
||||||
|
export const TaxCriticalError = TaxError.subclass("TaxCriticalError");
|
||||||
|
|
||||||
|
// Error that shouldn't happen. Should provide extra insights for debugging.
|
||||||
|
export const TaxUnexpectedError = TaxCriticalError.subclass("TaxUnexpectedError");
|
||||||
|
|
||||||
|
// Error that happens when external service returns an error
|
||||||
|
export const TaxExternalError = TaxCriticalError.subclass("TaxExternalError");
|
|
@ -9,9 +9,7 @@ describe("taxProviderUtils", () => {
|
||||||
expect(() => taxProviderUtils.resolveOptionalOrThrow(undefined)).toThrowError();
|
expect(() => taxProviderUtils.resolveOptionalOrThrow(undefined)).toThrowError();
|
||||||
});
|
});
|
||||||
it("throws a custom error if value is undefined", () => {
|
it("throws a custom error if value is undefined", () => {
|
||||||
expect(() =>
|
expect(() => taxProviderUtils.resolveOptionalOrThrow(undefined, "test")).toThrowError("test");
|
||||||
taxProviderUtils.resolveOptionalOrThrow(undefined, new Error("test"))
|
|
||||||
).toThrowError("test");
|
|
||||||
}),
|
}),
|
||||||
it("returns value if value is not undefined", () => {
|
it("returns value if value is not undefined", () => {
|
||||||
expect(taxProviderUtils.resolveOptionalOrThrow("test")).toBe("test");
|
expect(taxProviderUtils.resolveOptionalOrThrow("test")).toBe("test");
|
||||||
|
|
|
@ -1,25 +1,34 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { TaxUnexpectedError } from "./tax-error";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The providers sdk types claim to sometimes return undefined.
|
* The providers sdk types claim to sometimes return undefined.
|
||||||
* If it ever happens, we have nothing to fall back to, so we throw an error.
|
* If it ever happens, we have nothing to fall back to, so we throw an error.
|
||||||
* Should only be used for values that are required for further calculation.
|
* Should only be used for values that are required for further calculation.
|
||||||
*/
|
*/
|
||||||
function resolveOptionalOrThrow<T>(value: T | undefined | null, error?: Error): T {
|
function resolveOptionalOrThrow<T>(value: T | undefined | null, errorMessage?: string): T {
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
throw error
|
throw new TaxUnexpectedError(
|
||||||
? error
|
errorMessage
|
||||||
: new Error("Could not resolve data. Value needed for further calculation is undefined.");
|
? errorMessage
|
||||||
|
: "Could not resolve data. Value needed for further calculation is undefined.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveStringOrThrow(value: string | undefined | null): string {
|
function resolveStringOrThrow(value: string | undefined | null): string {
|
||||||
return z
|
const parseResult = z
|
||||||
.string({ required_error: "This field must be defined." })
|
.string({ required_error: "This field must be defined." })
|
||||||
.min(1, { message: "This field can not be empty." })
|
.min(1, { message: "This field can not be empty." })
|
||||||
.parse(value);
|
.safeParse(value);
|
||||||
|
|
||||||
|
if (!parseResult.success) {
|
||||||
|
throw new TaxUnexpectedError(parseResult.error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseResult.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const taxProviderUtils = {
|
export const taxProviderUtils = {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { TaxJarConfig } from "../taxjar-connection-schema";
|
||||||
import { TaxJarCalculateTaxesPayloadService } from "./taxjar-calculate-taxes-payload-service";
|
import { TaxJarCalculateTaxesPayloadService } from "./taxjar-calculate-taxes-payload-service";
|
||||||
import { TaxJarCalculateTaxesResponseTransformer } from "./taxjar-calculate-taxes-response-transformer";
|
import { TaxJarCalculateTaxesResponseTransformer } from "./taxjar-calculate-taxes-response-transformer";
|
||||||
import { ClientLogger } from "../../logs/client-logger";
|
import { ClientLogger } from "../../logs/client-logger";
|
||||||
|
import { TaxJarErrorNormalizer } from "../taxjar-error-normalizer";
|
||||||
|
|
||||||
export type TaxJarCalculateTaxesPayload = {
|
export type TaxJarCalculateTaxesPayload = {
|
||||||
taxBase: TaxBaseFragment;
|
taxBase: TaxBaseFragment;
|
||||||
|
@ -70,6 +71,8 @@ export class TaxJarCalculateTaxesAdapter
|
||||||
|
|
||||||
return transformedResponse;
|
return transformedResponse;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errorNormalizer = new TaxJarErrorNormalizer();
|
||||||
|
|
||||||
this.clientLogger.push({
|
this.clientLogger.push({
|
||||||
event: "[CalculateTaxes] fetchTaxForOrder",
|
event: "[CalculateTaxes] fetchTaxForOrder",
|
||||||
status: "error",
|
status: "error",
|
||||||
|
@ -78,7 +81,8 @@ export class TaxJarCalculateTaxesAdapter
|
||||||
output: error,
|
output: error,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
throw error;
|
|
||||||
|
throw errorNormalizer.normalize(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,14 @@ import {
|
||||||
*/
|
*/
|
||||||
export function matchPayloadLinesToResponseLines(
|
export function matchPayloadLinesToResponseLines(
|
||||||
payloadLines: TaxBaseFragment["lines"],
|
payloadLines: TaxBaseFragment["lines"],
|
||||||
responseLines: NonNullable<Breakdown["line_items"]>
|
responseLines: NonNullable<Breakdown["line_items"]>,
|
||||||
) {
|
) {
|
||||||
return payloadLines.map((payloadLine) => {
|
return payloadLines.map((payloadLine) => {
|
||||||
const responseLine = responseLines.find((line) => line.id === payloadLine.sourceLine.id);
|
const responseLine = responseLines.find((line) => line.id === payloadLine.sourceLine.id);
|
||||||
|
|
||||||
if (!responseLine) {
|
if (!responseLine) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Saleor product line with id ${payloadLine.sourceLine.id} not found in TaxJar response.`
|
`Saleor product line with id ${payloadLine.sourceLine.id} not found in TaxJar response.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export function matchPayloadLinesToResponseLines(
|
||||||
export class TaxJarCalculateTaxesResponseLinesTransformer {
|
export class TaxJarCalculateTaxesResponseLinesTransformer {
|
||||||
transform(
|
transform(
|
||||||
payload: TaxJarCalculateTaxesPayload,
|
payload: TaxJarCalculateTaxesPayload,
|
||||||
response: TaxForOrderRes
|
response: TaxForOrderRes,
|
||||||
): TaxJarCalculateTaxesResponse["lines"] {
|
): TaxJarCalculateTaxesResponse["lines"] {
|
||||||
const responseLines = response.tax.breakdown?.line_items ?? [];
|
const responseLines = response.tax.breakdown?.line_items ?? [];
|
||||||
|
|
||||||
|
@ -40,15 +40,15 @@ export class TaxJarCalculateTaxesResponseLinesTransformer {
|
||||||
return lines.map((line) => {
|
return lines.map((line) => {
|
||||||
const taxableAmount = taxProviderUtils.resolveOptionalOrThrow(
|
const taxableAmount = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line?.taxable_amount,
|
line?.taxable_amount,
|
||||||
new Error("Line taxable amount is required to calculate net amount")
|
"Line taxable amount is required to calculate net amount",
|
||||||
);
|
);
|
||||||
const taxCollectable = taxProviderUtils.resolveOptionalOrThrow(
|
const taxCollectable = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line?.tax_collectable,
|
line?.tax_collectable,
|
||||||
new Error("Line tax collectable is required to calculate net amount")
|
"Line tax collectable is required to calculate net amount",
|
||||||
);
|
);
|
||||||
const taxRate = taxProviderUtils.resolveOptionalOrThrow(
|
const taxRate = taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line?.combined_tax_rate,
|
line?.combined_tax_rate,
|
||||||
new Error("Line combined tax rate is required to calculate net amount")
|
"Line combined tax rate is required to calculate net amount",
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { TaxJarConfig } from "../taxjar-connection-schema";
|
||||||
import { TaxJarOrderConfirmedPayloadService } from "./taxjar-order-confirmed-payload.service";
|
import { TaxJarOrderConfirmedPayloadService } from "./taxjar-order-confirmed-payload.service";
|
||||||
import { TaxJarOrderConfirmedResponseTransformer } from "./taxjar-order-confirmed-response-transformer";
|
import { TaxJarOrderConfirmedResponseTransformer } from "./taxjar-order-confirmed-response-transformer";
|
||||||
import { ClientLogger } from "../../logs/client-logger";
|
import { ClientLogger } from "../../logs/client-logger";
|
||||||
|
import { TaxJarErrorNormalizer } from "../taxjar-error-normalizer";
|
||||||
|
|
||||||
export type TaxJarOrderConfirmedPayload = {
|
export type TaxJarOrderConfirmedPayload = {
|
||||||
order: OrderConfirmedSubscriptionFragment;
|
order: OrderConfirmedSubscriptionFragment;
|
||||||
|
@ -67,6 +68,8 @@ export class TaxJarOrderConfirmedAdapter
|
||||||
|
|
||||||
return transformedResponse;
|
return transformedResponse;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errorNormalizer = new TaxJarErrorNormalizer();
|
||||||
|
|
||||||
this.clientLogger.push({
|
this.clientLogger.push({
|
||||||
event: "[OrderConfirmed] createOrder",
|
event: "[OrderConfirmed] createOrder",
|
||||||
status: "error",
|
status: "error",
|
||||||
|
@ -75,7 +78,7 @@ export class TaxJarOrderConfirmedAdapter
|
||||||
output: error,
|
output: error,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
throw error;
|
throw errorNormalizer.normalize(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,14 @@ export function sumPayloadLines(lines: LineItem[]): number {
|
||||||
prev +
|
prev +
|
||||||
taxProviderUtils.resolveOptionalOrThrow(
|
taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line.unit_price,
|
line.unit_price,
|
||||||
new Error("Line unit_price is required to calculate order taxes")
|
"Line unit_price is required to calculate order taxes",
|
||||||
) *
|
) *
|
||||||
taxProviderUtils.resolveOptionalOrThrow(
|
taxProviderUtils.resolveOptionalOrThrow(
|
||||||
line.quantity,
|
line.quantity,
|
||||||
new Error("Line quantity is required to calculate order taxes")
|
"Line quantity is required to calculate order taxes",
|
||||||
|
),
|
||||||
|
0,
|
||||||
),
|
),
|
||||||
0
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export class TaxJarOrderConfirmedPayloadTransformer {
|
||||||
transform(
|
transform(
|
||||||
order: OrderConfirmedSubscriptionFragment,
|
order: OrderConfirmedSubscriptionFragment,
|
||||||
taxJarConfig: TaxJarConfig,
|
taxJarConfig: TaxJarConfig,
|
||||||
matches: TaxJarTaxCodeMatches
|
matches: TaxJarTaxCodeMatches,
|
||||||
): TaxJarOrderConfirmedTarget {
|
): TaxJarOrderConfirmedTarget {
|
||||||
const linesTransformer = new TaxJarOrderConfirmedPayloadLinesTransformer();
|
const linesTransformer = new TaxJarOrderConfirmedPayloadLinesTransformer();
|
||||||
const lineItems = linesTransformer.transform(order.lines, matches);
|
const lineItems = linesTransformer.transform(order.lines, matches);
|
||||||
|
|
17
apps/taxes/src/modules/taxjar/taxjar-error-normalizer.ts
Normal file
17
apps/taxes/src/modules/taxjar/taxjar-error-normalizer.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { TaxjarError } from "taxjar/dist/util/types";
|
||||||
|
import { createLogger } from "../../lib/logger";
|
||||||
|
import { TaxExternalError, TaxUnexpectedError } from "../taxes/tax-error";
|
||||||
|
|
||||||
|
export class TaxJarErrorNormalizer {
|
||||||
|
private logger = createLogger({ name: "TaxJarErrorNormalizer" });
|
||||||
|
|
||||||
|
normalize(error: unknown) {
|
||||||
|
if (error instanceof TaxjarError) {
|
||||||
|
this.logger.debug(error.stack, "TaxjarError occurred");
|
||||||
|
|
||||||
|
return new TaxExternalError(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TaxUnexpectedError.normalize(error);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import { saleorApp } from "../../../../saleor-app";
|
||||||
import { createLogger } from "../../../lib/logger";
|
import { createLogger } from "../../../lib/logger";
|
||||||
import { WebhookResponse } from "../../../modules/app/webhook-response";
|
import { WebhookResponse } from "../../../modules/app/webhook-response";
|
||||||
import { getActiveConnectionService } from "../../../modules/taxes/get-active-connection-service";
|
import { getActiveConnectionService } from "../../../modules/taxes/get-active-connection-service";
|
||||||
|
import { TaxBadWebhookPayloadError } from "../../../modules/taxes/tax-error";
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
|
@ -21,11 +22,11 @@ export type CalculateTaxesPayload = Extract<
|
||||||
|
|
||||||
function verifyCalculateTaxesPayload(payload: CalculateTaxesPayload) {
|
function verifyCalculateTaxesPayload(payload: CalculateTaxesPayload) {
|
||||||
if (!payload.taxBase.lines.length) {
|
if (!payload.taxBase.lines.length) {
|
||||||
throw new Error("No lines found in taxBase");
|
throw new TaxBadWebhookPayloadError("No lines found in taxBase");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!payload.taxBase.address) {
|
if (!payload.taxBase.address) {
|
||||||
throw new Error("No address found in taxBase");
|
throw new TaxBadWebhookPayloadError("No address found in taxBase");
|
||||||
}
|
}
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { saleorApp } from "../../../../saleor-app";
|
||||||
import { createLogger } from "../../../lib/logger";
|
import { createLogger } from "../../../lib/logger";
|
||||||
import { getActiveConnectionService } from "../../../modules/taxes/get-active-connection-service";
|
import { getActiveConnectionService } from "../../../modules/taxes/get-active-connection-service";
|
||||||
import { WebhookResponse } from "../../../modules/app/webhook-response";
|
import { WebhookResponse } from "../../../modules/app/webhook-response";
|
||||||
|
import { TaxBadWebhookPayloadError } from "../../../modules/taxes/tax-error";
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
|
@ -18,11 +19,11 @@ type CalculateTaxesPayload = Extract<CalculateTaxesEventFragment, { __typename:
|
||||||
|
|
||||||
function verifyCalculateTaxesPayload(payload: CalculateTaxesPayload) {
|
function verifyCalculateTaxesPayload(payload: CalculateTaxesPayload) {
|
||||||
if (!payload.taxBase.lines.length) {
|
if (!payload.taxBase.lines.length) {
|
||||||
throw new Error("No lines found in taxBase");
|
throw new TaxBadWebhookPayloadError("No lines found in taxBase");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!payload.taxBase.address) {
|
if (!payload.taxBase.address) {
|
||||||
throw new Error("No address found in taxBase");
|
throw new TaxBadWebhookPayloadError("No address found in taxBase");
|
||||||
}
|
}
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"words": [
|
"words": [
|
||||||
|
"Autocommit",
|
||||||
"Adyen",
|
"Adyen",
|
||||||
"Afterpay",
|
"Afterpay",
|
||||||
"Algolia",
|
"Algolia",
|
||||||
|
|
149
pnpm-lock.yaml
149
pnpm-lock.yaml
|
@ -1,9 +1,5 @@
|
||||||
lockfileVersion: '6.0'
|
lockfileVersion: '6.0'
|
||||||
|
|
||||||
settings:
|
|
||||||
autoInstallPeers: true
|
|
||||||
excludeLinksFromLockfile: false
|
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
'@saleor/app-sdk': 0.43.1
|
'@saleor/app-sdk': 0.43.1
|
||||||
|
|
||||||
|
@ -1521,6 +1517,12 @@ importers:
|
||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^20.0.3
|
specifier: ^20.0.3
|
||||||
version: 20.0.3
|
version: 20.0.3
|
||||||
|
modern-errors:
|
||||||
|
specifier: ^6.0.0
|
||||||
|
version: 6.0.0
|
||||||
|
modern-errors-serialize:
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0(modern-errors@6.0.0)
|
||||||
next:
|
next:
|
||||||
specifier: 13.4.8
|
specifier: 13.4.8
|
||||||
version: 13.4.8(@babel/core@7.22.17)(react-dom@18.2.0)(react@18.2.0)
|
version: 13.4.8(@babel/core@7.22.17)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
@ -14210,11 +14212,34 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/error-class-utils@3.0.0:
|
||||||
|
resolution: {integrity: sha512-L26cyYkaV6nzbUbmDRNSXAZfcuQy4cvEDvD+WoRF6c6nIEEydfgn7grd+idf2xLVYaTHnn7yYQjaz+Dnx+N1lQ==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/error-custom-class@9.0.0:
|
||||||
|
resolution: {integrity: sha512-cfXOxbwRQpXLUSecZctO/GPtKm9auTd2v1eY4CsclMgRkse/h5w59V1u1p7LdStVnw/SCbROcsd5zLenauvlRw==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
error-class-utils: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/error-ex@1.3.2:
|
/error-ex@1.3.2:
|
||||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish: 0.2.1
|
is-arrayish: 0.2.1
|
||||||
|
|
||||||
|
/error-serializer@6.0.1:
|
||||||
|
resolution: {integrity: sha512-SDEXcpWyys6yd6zLcC+s5bGnfe+xWxBJoC7p+o72c5F+hDdgdWc8LB8EOvcdqs7U+rzInYldFpiqSwmC3VZUeg==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
is-error-instance: 2.0.0
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
safe-json-value: 2.0.1
|
||||||
|
set-error-class: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/error-stack-parser@2.1.4:
|
/error-stack-parser@2.1.4:
|
||||||
resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==}
|
resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -15206,6 +15231,11 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
|
/filter-obj@5.1.0:
|
||||||
|
resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/final-form-arrays@3.1.0(final-form@4.20.9):
|
/final-form-arrays@3.1.0(final-form@4.20.9):
|
||||||
resolution: {integrity: sha512-TWBvun+AopgBLw9zfTFHBllnKMVNEwCEyDawphPuBGGqNsuhGzhT7yewHys64KFFwzIs6KEteGLpKOwvTQEscQ==}
|
resolution: {integrity: sha512-TWBvun+AopgBLw9zfTFHBllnKMVNEwCEyDawphPuBGGqNsuhGzhT7yewHys64KFFwzIs6KEteGLpKOwvTQEscQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -16362,6 +16392,11 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/is-error-instance@2.0.0:
|
||||||
|
resolution: {integrity: sha512-5RuM+oFY0P5MRa1nXJo6IcTx9m2VyXYhRtb4h0olsi2GHci4bqZ6akHk+GmCYvDrAR9yInbiYdr2pnoqiOMw/Q==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-extglob@2.1.1:
|
/is-extglob@2.1.1:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -16465,6 +16500,11 @@ packages:
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/is-plain-obj@4.1.0:
|
||||||
|
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-plain-object@2.0.4:
|
/is-plain-object@2.0.4:
|
||||||
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
|
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -17624,6 +17664,16 @@ packages:
|
||||||
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/merge-error-cause@4.0.1:
|
||||||
|
resolution: {integrity: sha512-fTPQshSNjhq6BGvoe5F6xezzcWTn98rog8Ra0gJ0jqgwZXizPNRyg/pjhWX5+pXYanecSPUXa17uEM/RwZfKXw==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
set-error-class: 2.0.0
|
||||||
|
set-error-props: 5.0.0
|
||||||
|
wrap-error-message: 2.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/merge-stream@2.0.0:
|
/merge-stream@2.0.0:
|
||||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -18150,6 +18200,32 @@ packages:
|
||||||
pkg-types: 1.0.3
|
pkg-types: 1.0.3
|
||||||
ufo: 1.2.0
|
ufo: 1.2.0
|
||||||
|
|
||||||
|
/modern-errors-serialize@5.0.0(modern-errors@6.0.0):
|
||||||
|
resolution: {integrity: sha512-vKtplFTL+nooOabeOsX2ur9tSgXCzvKOY15WAx1bwq9Cz6yETipqKilZX+bGXFrTRptUOotuACRWhQ+46wWguQ==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
peerDependencies:
|
||||||
|
modern-errors: ^6.0.0
|
||||||
|
dependencies:
|
||||||
|
error-serializer: 6.0.1
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
modern-errors: 6.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/modern-errors@6.0.0:
|
||||||
|
resolution: {integrity: sha512-IgtbY9ITQfbtZUdoIiqOwReV+Z2iL82OtwWTNV9cusKT/SvNivIAXKyGjEGcoCpLc+32UZp0DuqXViIDAG44Zg==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
error-class-utils: 3.0.0
|
||||||
|
error-custom-class: 9.0.0
|
||||||
|
filter-obj: 5.1.0
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
merge-error-cause: 4.0.1
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
set-error-message: 2.0.1
|
||||||
|
set-error-props: 5.0.0
|
||||||
|
set-error-stack: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/moment@2.29.4:
|
/moment@2.29.4:
|
||||||
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
|
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -18412,6 +18488,14 @@ packages:
|
||||||
abbrev: 1.1.1
|
abbrev: 1.1.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/normalize-exception@3.0.0:
|
||||||
|
resolution: {integrity: sha512-SMZtWSLjls45KBgwvS2jWyXLtOI9j90JyQ6tJstl91Gti4W7QwZyF/nWwlFRz/Cx4Gy70DAtLT0EzXYXcPJJUw==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
is-error-instance: 2.0.0
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/normalize-package-data@2.5.0:
|
/normalize-package-data@2.5.0:
|
||||||
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
|
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -19962,6 +20046,13 @@ packages:
|
||||||
resolve: 1.22.2
|
resolve: 1.22.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/redefine-property@2.0.0:
|
||||||
|
resolution: {integrity: sha512-7UfHFiHkePd9mb/vYMPYuAPjAa/77xGQ1S6laaWNQkz5gVJAtYpoWYQ5iFL/ZcDxXZVqnD7N4aFFnIn4T36Sbw==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/redent@3.0.0:
|
/redent@3.0.0:
|
||||||
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
|
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -20304,6 +20395,14 @@ packages:
|
||||||
/safe-buffer@5.2.1:
|
/safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
|
/safe-json-value@2.0.1:
|
||||||
|
resolution: {integrity: sha512-vvoBxKVyksxwqzNDoD2vLVkcvbjYBFXS/CghUrFDsrP0wgTaw+/gIyOADNYa1vyPmICLUWH7RNh0FtwmFsEQCQ==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/safe-regex-test@1.0.0:
|
/safe-regex-test@1.0.0:
|
||||||
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
|
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -20461,6 +20560,36 @@ packages:
|
||||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/set-error-class@2.0.0:
|
||||||
|
resolution: {integrity: sha512-ZBXDmoj+bWd+vJbA8VZE/aVQ6NL5iu2AVMtUyVIVXVMEi4oozCGPZAPjaJJZ4k8koLYb0OAFcyIRb0T6XiCuXg==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/set-error-message@2.0.1:
|
||||||
|
resolution: {integrity: sha512-s/eeP0f4ed1S3fl0KbxZoy5Pbeg5D6Nbple9nut4VPwHTvEIk5r7vKq0FwjNjszdUPdlTrs4GJCOkWUqWeTeWg==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/set-error-props@5.0.0:
|
||||||
|
resolution: {integrity: sha512-AKeNtJ7f9HUzB9Vw9KWiKKe6NR5b8hJoVVnXGN+ZkEj0jTfM0ggL+I2O/14zfJn9lgUqGgMgyjjRhldp7eTpeA==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
is-error-instance: 2.0.0
|
||||||
|
is-plain-obj: 4.1.0
|
||||||
|
redefine-property: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/set-error-stack@2.0.0:
|
||||||
|
resolution: {integrity: sha512-mABWr7mmaY1EVBMXWo32t6byRkKclJ3gipglE2+XGBZxDEk0+zVumRfWyAK3s/EB/TbbUm1Gp0H8VvqlFkMa+g==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/set-harmonic-interval@1.0.1:
|
/set-harmonic-interval@1.0.1:
|
||||||
resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==}
|
resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==}
|
||||||
engines: {node: '>=6.9'}
|
engines: {node: '>=6.9'}
|
||||||
|
@ -22460,6 +22589,14 @@ packages:
|
||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
|
|
||||||
|
/wrap-error-message@2.0.1:
|
||||||
|
resolution: {integrity: sha512-LrBMsWJ85HKjLs5ABjhZeW7mWpwsAoV16iqmhEXUf4Y2GvdLwrqK4FPGNNoAi7a20wy4wHU2ci61wQfcOgz/Kw==}
|
||||||
|
engines: {node: '>=16.17.0'}
|
||||||
|
dependencies:
|
||||||
|
normalize-exception: 3.0.0
|
||||||
|
set-error-message: 2.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/wrappy@1.0.2:
|
/wrappy@1.0.2:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
|
|
||||||
|
@ -22673,3 +22810,7 @@ packages:
|
||||||
|
|
||||||
/zod@3.21.4:
|
/zod@3.21.4:
|
||||||
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
Loading…
Reference in a new issue