Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't mutate error.type during minification #2043

Merged
merged 5 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ tags
coverage
.idea
testProjects/**/node_modules
testProjects/**/dist
testProjects/**/package-lock.json
testProjects/**/_worker.*
66 changes: 53 additions & 13 deletions src/Error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export class StripeError extends Error {
readonly setup_intent?: any;
readonly source?: any;

constructor(raw: StripeRawError = {}) {
constructor(raw: StripeRawError = {}, type: string | null = null) {
super(raw.message);
this.type = this.constructor.name;
this.type = type || this.constructor.name;

this.raw = raw;
this.rawType = raw.type;
Expand Down Expand Up @@ -86,47 +86,75 @@ export class StripeError extends Error {
* CardError is raised when a user enters a card that can't be charged for
* some reason.
*/
export class StripeCardError extends StripeError {}
export class StripeCardError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeCardError');
}
}

/**
* InvalidRequestError is raised when a request is initiated with invalid
* parameters.
*/
export class StripeInvalidRequestError extends StripeError {}
export class StripeInvalidRequestError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeInvalidRequestError');
}
}

/**
* APIError is a generic error that may be raised in cases where none of the
* other named errors cover the problem. It could also be raised in the case
* that a new error has been introduced in the API, but this version of the
* Node.JS SDK doesn't know how to handle it.
*/
export class StripeAPIError extends StripeError {}
export class StripeAPIError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeAPIError');
}
}

/**
* AuthenticationError is raised when invalid credentials are used to connect
* to Stripe's servers.
*/
export class StripeAuthenticationError extends StripeError {}
export class StripeAuthenticationError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeAuthenticationError');
}
}

/**
* PermissionError is raised in cases where access was attempted on a resource
* that wasn't allowed.
*/
export class StripePermissionError extends StripeError {}
export class StripePermissionError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripePermissionError');
}
}

/**
* RateLimitError is raised in cases where an account is putting too much load
* on Stripe's API servers (usually by performing too many requests). Please
* back off on request rate.
*/
export class StripeRateLimitError extends StripeError {}
export class StripeRateLimitError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeRateLimitError');
}
}

/**
* StripeConnectionError is raised in the event that the SDK can't connect to
* Stripe's servers. That can be for a variety of different reasons from a
* downed network to a bad TLS certificate.
*/
export class StripeConnectionError extends StripeError {}
export class StripeConnectionError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeConnectionError');
}
}

/**
* SignatureVerificationError is raised when the signature verification for a
Expand All @@ -141,7 +169,7 @@ export class StripeSignatureVerificationError extends StripeError {
payload: string | Uint8Array,
raw: StripeRawError = {}
) {
super(raw);
super(raw, 'StripeSignatureVerificationError');
this.header = header;
this.payload = payload;
}
Expand All @@ -151,17 +179,29 @@ export class StripeSignatureVerificationError extends StripeError {
* IdempotencyError is raised in cases where an idempotency key was used
* improperly.
*/
export class StripeIdempotencyError extends StripeError {}
export class StripeIdempotencyError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeIdempotencyError');
}
}

/**
* InvalidGrantError is raised when a specified code doesn't exist, is
* expired, has been used, or doesn't belong to you; a refresh token doesn't
* exist, or doesn't belong to you; or if an API key's mode (live or test)
* doesn't match the mode of a code or refresh token.
*/
export class StripeInvalidGrantError extends StripeError {}
export class StripeInvalidGrantError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeInvalidGrantError');
}
}

/**
* Any other error from Stripe not specifically captured above
*/
export class StripeUnknownError extends StripeError {}
export class StripeUnknownError extends StripeError {
constructor(raw: StripeRawError = {}) {
super(raw, 'StripeUnknownError');
}
}
12 changes: 11 additions & 1 deletion test/Error.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,17 @@ describe('Error', () => {
expect(e).to.have.property('statusCode', 400);
});

it('has subclasses which provide `.type` as their name', () => {
it('respects subclasses overriding `.type` in constructor', () => {
class Foo extends Error.StripeError {
constructor(raw: any) {
super(raw, 'Foo');
}
}
const err = new Foo({message: 'hi'});
expect(err).to.have.property('type', 'Foo');
});

it('defaults setting `.type` to subclass name', () => {
class Foo extends Error.StripeError {}
const err = new Foo({message: 'hi'});
expect(err).to.have.property('type', 'Foo');
Expand Down
16 changes: 16 additions & 0 deletions test/Integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ describe('Integration test', function() {
await runTestProject('mjs-ts');
});

describe('esbuild', () => {
anniel-stripe marked this conversation as resolved.
Show resolved Hide resolved
it('should not change error.type when minified', async function() {
// Node supports ES Modules starting at v12
if (nodeVersion <= 12) {
this.skip();
}

await testExec(`
cd testProjects/esbuild && rm -rf node_modules && rm -rf dist
npm install &&
npm run build &&
npm run start
`);
});
});

const runTestCloudflareProject = (projectName: string): Promise<void> => {
if (process.versions.node < '16.13') {
console.log('Wrangler requires at least node.js v16.13.0, skipping test');
Expand Down
35 changes: 35 additions & 0 deletions testProjects/esbuild/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {Stripe} from 'stripe';
import assert from 'assert';

// API key is null to trigger an authentication error
const stripe = new Stripe(null, {
host: process.env.STRIPE_MOCK_HOST || 'localhost',
port: process.env.STRIPE_MOCK_PORT || 12111,
protocol: 'http',
});

try {
throw new stripe.errors.StripeUnknownError({
charge: 'foo',
unknown_prop: 'bar',
});
} catch (e) {
assert (e instanceof stripe.errors.StripeUnknownError);
assert (e.type === 'StripeUnknownError');
}

async function exampleFunction(args) {
try {
await stripe.paymentIntents.create(args);
} catch (e) {
assert (e instanceof stripe.errors.StripeAuthenticationError);
assert (e.type === 'StripeAuthenticationError');
}
}

exampleFunction({
// The required parameter currency is missing
amount: 2000,
confirm: true,
payment_method: 'pm_card_visa',
});
17 changes: 17 additions & 0 deletions testProjects/esbuild/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "mjs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"stripe": "file:../../"
},
"scripts": {
"clean": "rm -rf node_modules && rm -rf dist",
"build": "esbuild index.js --bundle --platform=node --minify --target=es2020 --outdir=dist",
"start": "node dist/index.js"
},
"devDependencies": {
"esbuild": "^0.20.2"
}
}
Loading