Skip to content

Commit 992d9d2

Browse files
committed
Merge changes from stripe/stripe-node master
# Conflicts: # src/Types.d.ts # types/Errors.d.ts
2 parents 9de40bf + d3df0c2 commit 992d9d2

File tree

18 files changed

+1291
-80
lines changed

18 files changed

+1291
-80
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ jobs:
6464
os:
6565
- 'ubuntu-24.04'
6666
node:
67-
# should include even numbers >= 16
67+
# should include even numbers >= 18
6868
# see: https://docs.stripe.com/sdks/versioning?lang=node#stripe-sdk-language-version-support-policy
69+
# note that in Oct 2026, every version will be LTS, so it's not just even numbers anymore
70+
# see: https://nodejs.org/en/blog/announcements/evolving-the-nodejs-release-schedule
6971
- '24'
7072
- '22'
7173
- '20'
7274
- '18'
73-
- '16'
7475
runs-on: ${{ matrix.os }}
7576
permissions:
7677
contents: read
@@ -117,8 +118,7 @@ jobs:
117118
name: Publish
118119
if: >-
119120
(github.event_name == 'workflow_dispatch' || github.event_name == 'push') &&
120-
startsWith(github.ref, 'refs/tags/v') &&
121-
endsWith(github.actor, '-stripe')
121+
startsWith(github.ref, 'refs/tags/v')
122122
needs: [build, test]
123123
runs-on: 'ubuntu-24.04'
124124
permissions:

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ See the [`stripe-node` API docs](https://stripe.com/docs/api?lang=node) for Node
1919

2020
## Requirements
2121

22-
Per our [Language Version Support Policy](https://docs.stripe.com/sdks/versioning?lang=node#stripe-sdk-language-version-support-policy), we currently support all LTS versions of **Node.js 16+**.
22+
Per our [Language Version Support Policy](https://docs.stripe.com/sdks/versioning?lang=node#stripe-sdk-language-version-support-policy), we currently support all LTS versions of **Node.js 18+**.
2323

24-
Support for Node 16 is deprecated and will be removed in an upcoming major version. Read more and see the full schedule in the docs: https://docs.stripe.com/sdks/versioning?lang=node#stripe-sdk-language-version-support-policy
24+
Read more and see the full schedule in the docs: https://docs.stripe.com/sdks/versioning?lang=node#stripe-sdk-language-version-support-policy
2525

2626
## Installation
2727

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
},
2323
"bugs": "https://github.com/stripe/stripe-node/issues",
2424
"engines": {
25-
"node": ">=16"
25+
"node": ">=18"
2626
},
2727
"main": "cjs/stripe.cjs.node.js",
2828
"types": "types/index.d.ts",
@@ -56,7 +56,7 @@
5656
},
5757
"dependencies": {},
5858
"peerDependencies": {
59-
"@types/node": ">=16"
59+
"@types/node": ">=18"
6060
},
6161
"peerDependenciesMeta": {
6262
"@types/node": {

src/Error.ts

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,65 @@ import {RawErrorType, StripeRawError} from './Types.js';
77
export const generateV1Error = (
88
rawStripeError: StripeRawError
99
): StripeError => {
10-
switch (rawStripeError.type) {
11-
case 'card_error':
12-
return new StripeCardError(rawStripeError);
13-
case 'invalid_request_error':
14-
return new StripeInvalidRequestError(rawStripeError);
15-
case 'api_error':
16-
return new StripeAPIError(rawStripeError);
17-
case 'authentication_error':
18-
return new StripeAuthenticationError(rawStripeError);
19-
case 'rate_limit_error':
20-
return new StripeRateLimitError(rawStripeError);
21-
case 'idempotency_error':
10+
const statusCode = rawStripeError.statusCode;
11+
12+
if (
13+
statusCode === 429 ||
14+
(statusCode === 400 && rawStripeError.code === 'rate_limit')
15+
) {
16+
return new StripeRateLimitError(rawStripeError);
17+
}
18+
19+
if (statusCode === 400 || statusCode === 404) {
20+
if (rawStripeError.type === 'idempotency_error') {
2221
return new StripeIdempotencyError(rawStripeError);
22+
}
23+
return new StripeInvalidRequestError(rawStripeError);
24+
}
25+
26+
if (statusCode === 401) {
27+
return new StripeAuthenticationError(rawStripeError);
28+
}
29+
30+
if (statusCode === 402) {
31+
return new StripeCardError(rawStripeError);
32+
}
33+
34+
if (statusCode === 403) {
35+
return new StripePermissionError(rawStripeError);
36+
}
37+
38+
return new StripeAPIError(rawStripeError);
39+
};
40+
41+
export const generateOAuthError = (
42+
rawStripeError: StripeRawError
43+
): StripeError => {
44+
const oauthType = rawStripeError.type;
45+
switch (oauthType) {
2346
case 'invalid_grant':
2447
return new StripeInvalidGrantError(rawStripeError);
48+
case 'invalid_client':
49+
return new StripeInvalidClientError(rawStripeError);
50+
case 'invalid_request':
51+
return new StripeOAuthInvalidRequestError(rawStripeError);
52+
case 'invalid_scope':
53+
return new StripeInvalidScopeError(rawStripeError);
54+
case 'unsupported_grant_type':
55+
return new StripeUnsupportedGrantTypeError(rawStripeError);
56+
case 'unsupported_response_type':
57+
return new StripeUnsupportedResponseTypeError(rawStripeError);
2558
default:
26-
return new StripeUnknownError(rawStripeError);
59+
return new StripeOAuthError(rawStripeError);
2760
}
2861
};
2962

30-
// eslint-disable-next-line complexity
3163
export const generateV2Error = (
3264
rawStripeError: StripeRawError
3365
): StripeError => {
3466
switch (rawStripeError.type) {
67+
case 'idempotency_error':
68+
return new StripeIdempotencyError(rawStripeError);
3569
// switchCases: The beginning of the section generated from our OpenAPI spec
3670
case 'already_canceled':
3771
return new AlreadyCanceledError(rawStripeError);
@@ -240,24 +274,74 @@ export class StripeIdempotencyError extends StripeError {
240274
}
241275
}
242276

277+
/**
278+
* StripeOAuthError is the base error for OAuth-specific errors.
279+
*/
280+
export class StripeOAuthError extends StripeError {
281+
constructor(raw: StripeRawError = {}, type = 'StripeOAuthError') {
282+
super(raw, type);
283+
}
284+
}
285+
243286
/**
244287
* InvalidGrantError is raised when a specified code doesn't exist, is
245288
* expired, has been used, or doesn't belong to you; a refresh token doesn't
246289
* exist, or doesn't belong to you; or if an API key's mode (live or test)
247290
* doesn't match the mode of a code or refresh token.
248291
*/
249-
export class StripeInvalidGrantError extends StripeError {
292+
export class StripeInvalidGrantError extends StripeOAuthError {
250293
constructor(raw: StripeRawError = {}) {
251294
super(raw, 'StripeInvalidGrantError');
252295
}
253296
}
254297

255298
/**
256-
* Any other error from Stripe not specifically captured above
299+
* InvalidClientError is raised when the client_id does not belong to you,
300+
* or an API key is required but not provided.
301+
*/
302+
export class StripeInvalidClientError extends StripeOAuthError {
303+
constructor(raw: StripeRawError = {}) {
304+
super(raw, 'StripeInvalidClientError');
305+
}
306+
}
307+
308+
/**
309+
* OAuthInvalidRequestError is raised when a required parameter is missing,
310+
* or an unsupported parameter or value is provided in the OAuth request.
311+
*/
312+
export class StripeOAuthInvalidRequestError extends StripeOAuthError {
313+
constructor(raw: StripeRawError = {}) {
314+
super(raw, 'StripeOAuthInvalidRequestError');
315+
}
316+
}
317+
318+
/**
319+
* InvalidScopeError is raised when an invalid scope is provided in the
320+
* OAuth request.
321+
*/
322+
export class StripeInvalidScopeError extends StripeOAuthError {
323+
constructor(raw: StripeRawError = {}) {
324+
super(raw, 'StripeInvalidScopeError');
325+
}
326+
}
327+
328+
/**
329+
* UnsupportedGrantTypeError is raised when an unsupported grant_type is
330+
* provided in the OAuth request.
331+
*/
332+
export class StripeUnsupportedGrantTypeError extends StripeOAuthError {
333+
constructor(raw: StripeRawError = {}) {
334+
super(raw, 'StripeUnsupportedGrantTypeError');
335+
}
336+
}
337+
338+
/**
339+
* UnsupportedResponseTypeError is raised when an unsupported response_type
340+
* is provided in the OAuth request.
257341
*/
258-
export class StripeUnknownError extends StripeError {
342+
export class StripeUnsupportedResponseTypeError extends StripeOAuthError {
259343
constructor(raw: StripeRawError = {}) {
260-
super(raw, 'StripeUnknownError');
344+
super(raw, 'StripeUnsupportedResponseTypeError');
261345
}
262346
}
263347

src/RequestSender.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import {
22
StripeAPIError,
3-
StripeAuthenticationError,
43
StripeConnectionError,
54
StripeError,
6-
StripePermissionError,
7-
StripeRateLimitError,
5+
generateOAuthError,
86
generateV1Error,
97
generateV2Error,
108
} from './Error.js';
@@ -172,11 +170,9 @@ export class RequestSender {
172170
.then(
173171
(jsonResponse) => {
174172
if (jsonResponse.error) {
175-
let err;
173+
const isOAuth = typeof jsonResponse.error === 'string';
176174

177-
// Convert OAuth error responses into a standard format
178-
// so that the rest of the error logic can be shared
179-
if (typeof jsonResponse.error === 'string') {
175+
if (isOAuth) {
180176
jsonResponse.error = {
181177
type: jsonResponse.error,
182178
message: jsonResponse.error_description,
@@ -187,12 +183,10 @@ export class RequestSender {
187183
jsonResponse.error.statusCode = statusCode;
188184
jsonResponse.error.requestId = requestId;
189185

190-
if (statusCode === 401) {
191-
err = new StripeAuthenticationError(jsonResponse.error);
192-
} else if (statusCode === 403) {
193-
err = new StripePermissionError(jsonResponse.error);
194-
} else if (statusCode === 429) {
195-
err = new StripeRateLimitError(jsonResponse.error);
186+
let err;
187+
188+
if (isOAuth) {
189+
err = generateOAuthError(jsonResponse.error);
196190
} else if (apiMode === 'v2') {
197191
err = generateV2Error(jsonResponse.error);
198192
} else {

src/StripeResource.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
getAPIMode,
23
getDataFromArgs,
34
getOptionsFromArgs,
45
makeURLInterpolator,
@@ -16,6 +17,7 @@ import {
1617
UrlInterpolator,
1718
} from './Types.js';
1819
import {HttpClientResponseInterface} from './net/HttpClient.js';
20+
import {coerceV2RequestData, coerceV2ResponseData} from './V2Int64.js';
1921

2022
// Provide extension mechanism for Stripe Resource Sub-Classes
2123
StripeResource.extend = protoExtend;
@@ -209,18 +211,35 @@ StripeResource.prototype = {
209211
return;
210212
}
211213

214+
// Coerce int64_string fields in request body: number → string
215+
const apiMode = getAPIMode(spec.fullPath || spec.path);
216+
if (apiMode === 'v2' && spec.requestSchema && opts.bodyData) {
217+
opts.bodyData = coerceV2RequestData(
218+
opts.bodyData,
219+
spec.requestSchema
220+
) as RequestData;
221+
}
222+
212223
function requestCallback(
213224
err: any,
214225
response: HttpClientResponseInterface
215226
): void {
216227
if (err) {
217228
reject(err);
218229
} else {
219-
resolve(
220-
spec.transformResponseData
221-
? spec.transformResponseData(response)
222-
: response
223-
);
230+
// Coerce int64_string fields in response: string → bigint
231+
try {
232+
if (apiMode === 'v2' && spec.responseSchema) {
233+
coerceV2ResponseData(response, spec.responseSchema);
234+
}
235+
resolve(
236+
spec.transformResponseData
237+
? spec.transformResponseData(response)
238+
: response
239+
);
240+
} catch (e) {
241+
reject(e);
242+
}
224243
}
225244
}
226245

src/Types.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export type BufferedFile = {
1515
type: string;
1616
file: {data: Uint8Array};
1717
};
18+
export type V2RuntimeSchema =
19+
| {kind: 'int64_string'}
20+
| {kind: 'object'; fields: Record<string, V2RuntimeSchema>}
21+
| {kind: 'array'; element: V2RuntimeSchema}
22+
| {kind: 'nullable'; inner: V2RuntimeSchema};
1823
export type MethodSpec = {
1924
method: string;
2025
methodType?: string;
@@ -28,6 +33,8 @@ export type MethodSpec = {
2833
host?: string;
2934
transformResponseData?: (response: HttpClientResponseInterface) => any;
3035
usage?: Array<string>;
36+
requestSchema?: V2RuntimeSchema;
37+
responseSchema?: V2RuntimeSchema;
3138
};
3239
export type MultipartRequestData = RequestData | StreamingFile | BufferedFile;
3340
// rawErrorTypeEnum: The beginning of the section generated from our OpenAPI spec

0 commit comments

Comments
 (0)