perf: Do not import Stripe lib in getServerErrorFromUnknown (#19578)
* Do not import stripe lib in getServerErrorFromUnknown * address comment * remove comment * add url * keep the location * remove space * add unit test for getServerErrorFromUnknown * improve
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { z } from "zod";
|
||||
|
||||
// Copied from node_modules/stripe/types/Errors.d.ts because stripe lib doesn't expose these types
|
||||
// Ref: https://github.com/stripe/stripe-node/blob/master/types/Errors.d.ts#L194
|
||||
interface StripeInvalidRequestError extends Error {
|
||||
readonly type: "StripeInvalidRequestError";
|
||||
readonly rawType: "invalid_request_error";
|
||||
/**
|
||||
* A human-readable message giving more details about the error. For card errors, these messages can
|
||||
* be shown to your users.
|
||||
*/
|
||||
readonly message: string;
|
||||
/**
|
||||
* For card errors, a short string describing the kind of card error that occurred.
|
||||
*
|
||||
* @docs https://stripe.com/docs/error-codes
|
||||
*/
|
||||
readonly code?: string;
|
||||
|
||||
/**
|
||||
* A URL to more information about the error code reported.
|
||||
*
|
||||
* @docs https://stripe.com/docs/error-codes
|
||||
*/
|
||||
readonly doc_url?: string;
|
||||
|
||||
/**
|
||||
* Typically a 4xx or 5xx.
|
||||
*/
|
||||
readonly statusCode?: number;
|
||||
|
||||
readonly raw: unknown;
|
||||
|
||||
readonly headers: {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
readonly requestId: string;
|
||||
|
||||
/**
|
||||
* The parameter the error relates to if the error is parameter-specific. You can use this to display a
|
||||
* message near the correct form field, for example.
|
||||
*/
|
||||
readonly param?: string;
|
||||
}
|
||||
|
||||
const errorSchema = z.object({
|
||||
name: z.string(),
|
||||
message: z.string(),
|
||||
stack: z.string().optional(),
|
||||
});
|
||||
|
||||
export const stripeInvalidRequestErrorSchema = errorSchema.extend({
|
||||
type: z.literal("StripeInvalidRequestError"),
|
||||
rawType: z.literal("invalid_request_error"),
|
||||
code: z.string().optional(),
|
||||
doc_url: z.string().optional(),
|
||||
statusCode: z.number().optional(),
|
||||
raw: z.unknown(),
|
||||
headers: z.record(z.string()),
|
||||
requestId: z.string(),
|
||||
param: z.string().optional(),
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { expect, it, describe } from "vitest";
|
||||
|
||||
import { HttpError } from "../http-error";
|
||||
import { getServerErrorFromUnknown } from "./getServerErrorFromUnknown";
|
||||
|
||||
describe("getServerErrorFromUnknown", () => {
|
||||
it("should handle a StripeInvalidRequestError", () => {
|
||||
const stripeError = {
|
||||
name: "StripeInvalidRequestError",
|
||||
type: "StripeInvalidRequestError",
|
||||
rawType: "invalid_request_error",
|
||||
message: "No such customer: cus_12345; a valid customer ID is required.",
|
||||
code: "resource_missing",
|
||||
doc_url: "https://stripe.com/docs/error-codes/resource-missing",
|
||||
statusCode: 400,
|
||||
raw: {
|
||||
error: { type: "invalid_request_error", message: "No such customer" },
|
||||
},
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"request-id": "req_abc123xyz",
|
||||
},
|
||||
requestId: "req_abc123xyz",
|
||||
param: "customer",
|
||||
};
|
||||
Object.setPrototypeOf(stripeError, Error.prototype);
|
||||
const result = getServerErrorFromUnknown(stripeError);
|
||||
expect(result).toBeInstanceOf(HttpError);
|
||||
expect(result.statusCode).toBe(400);
|
||||
expect(result.message).toBe(stripeError.message);
|
||||
expect(result.cause).toEqual(stripeError);
|
||||
expect(result.name).toBe("HttpError");
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import Stripe from "stripe";
|
||||
import type { ZodIssue } from "zod";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import { stripeInvalidRequestErrorSchema } from "@calcom/app-store/_utils/stripe.types";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -56,8 +56,9 @@ export function getServerErrorFromUnknown(cause: unknown): HttpError {
|
||||
if (isPrismaError(cause)) {
|
||||
return getServerErrorFromPrismaError(cause);
|
||||
}
|
||||
if (cause instanceof Stripe.errors.StripeInvalidRequestError) {
|
||||
return getHttpError({ statusCode: 400, cause });
|
||||
const parsedStripeError = stripeInvalidRequestErrorSchema.safeParse(cause);
|
||||
if (parsedStripeError.success) {
|
||||
return getHttpError({ statusCode: 400, cause: parsedStripeError.data });
|
||||
}
|
||||
if (cause instanceof HttpError) {
|
||||
const redactedCause = redactError(cause);
|
||||
|
||||
Reference in New Issue
Block a user