Skip to content

Commit 2c9facd

Browse files
Merge pull request #2720 from stripe/latest-codegen-beta
Update generated code for beta
2 parents 27844ca + cc3a4b5 commit 2c9facd

117 files changed

Lines changed: 3163 additions & 659 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ module.exports = {
170170
'no-useless-return': 'error',
171171
'no-var': 'off',
172172
'no-void': 'error',
173-
'no-warning-comments': 'error',
173+
'no-warning-comments': 'warn',
174174
'no-whitespace-before-property': 'error',
175175
'no-with': 'error',
176176
'nonblock-statement-body-position': 'error',
@@ -287,5 +287,20 @@ module.exports = {
287287
'@typescript-eslint/explicit-function-return-type': 'off',
288288
},
289289
},
290+
{
291+
files: ['src/**/*.ts'],
292+
rules: {
293+
'wintertc-compat': 'error',
294+
},
295+
},
296+
{
297+
files: [
298+
'src/**/Node*.ts',
299+
'src/stripe.*.node.ts',
300+
],
301+
rules: {
302+
'wintertc-compat': 'off',
303+
},
304+
},
290305
],
291306
};

CODEGEN_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
826bf48af8bcd391512daeaf283b8486347b14c8
1+
d59a1f4bdea3032b8e282d40badc032cb021fc60

OPENAPI_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v2253
1+
v2277

eslint-rules/wintertc-compat.js

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/**
2+
* ESLint rule: wintertc-compat
3+
*
4+
* Flags usage of APIs not in the WinterTC Minimum Common Web Platform API
5+
* spec (ECMA-429). Designed to catch cross-runtime compatibility issues in
6+
* code that must run in Node.js, browsers, Deno, Bun, and other runtimes.
7+
*
8+
* Spec: https://min-common-api.proposal.wintertc.org/
9+
*/
10+
11+
'use strict';
12+
13+
// Complete list of Node.js built-in modules.
14+
// See: https://nodejs.org/api/modules.html#built-in-modules
15+
const NODE_BUILTIN_MODULES = new Set([
16+
'assert',
17+
'assert/strict',
18+
'async_hooks',
19+
'buffer',
20+
'child_process',
21+
'cluster',
22+
'console',
23+
'constants',
24+
'crypto',
25+
'dgram',
26+
'diagnostics_channel',
27+
'dns',
28+
'dns/promises',
29+
'domain',
30+
'events',
31+
'fs',
32+
'fs/promises',
33+
'http',
34+
'http2',
35+
'https',
36+
'inspector',
37+
'module',
38+
'net',
39+
'os',
40+
'path',
41+
'path/posix',
42+
'path/win32',
43+
'perf_hooks',
44+
'process',
45+
'punycode',
46+
'querystring',
47+
'readline',
48+
'readline/promises',
49+
'repl',
50+
'stream',
51+
'stream/consumers',
52+
'stream/promises',
53+
'stream/web',
54+
'string_decoder',
55+
'sys',
56+
'test',
57+
'timers',
58+
'timers/promises',
59+
'tls',
60+
'trace_events',
61+
'tty',
62+
'url',
63+
'util',
64+
'util/types',
65+
'v8',
66+
'vm',
67+
'wasi',
68+
'worker_threads',
69+
'zlib',
70+
]);
71+
72+
// Node.js-specific globals that are not in the WinterTC spec or ECMAScript.
73+
const NODE_GLOBALS = new Set([
74+
'Buffer',
75+
'process',
76+
'__dirname',
77+
'__filename',
78+
'global',
79+
'require',
80+
'module',
81+
'exports',
82+
]);
83+
84+
function findVariable(scope, name) {
85+
let s = scope;
86+
while (s) {
87+
const found = s.variables.find((v) => v.name === name);
88+
if (found) {
89+
return found;
90+
}
91+
s = s.upper;
92+
}
93+
return null;
94+
}
95+
96+
module.exports = {
97+
meta: {
98+
type: 'problem',
99+
docs: {
100+
description:
101+
'Disallow Node.js-specific APIs in cross-runtime code per the WinterTC Minimum Common Web Platform API spec (ECMA-429)',
102+
url: 'https://min-common-api.proposal.wintertc.org/',
103+
},
104+
messages: {
105+
nodeImport:
106+
"Import from Node.js built-in module '{{source}}' is not available in all runtimes.",
107+
nodeGlobal:
108+
"'{{name}}' is a Node.js-specific global not available in all runtimes.",
109+
nodeType:
110+
"'NodeJS.{{name}}' is a Node.js-specific type. Use a cross-runtime alternative.",
111+
},
112+
schema: [],
113+
},
114+
115+
create(context) {
116+
return {
117+
// Flag imports from Node.js built-in modules (both bare and node: prefix).
118+
ImportDeclaration(node) {
119+
const source = node.source.value;
120+
const moduleName = source.startsWith('node:')
121+
? source.slice(5)
122+
: source;
123+
124+
if (NODE_BUILTIN_MODULES.has(moduleName)) {
125+
context.report({
126+
node: node.source,
127+
messageId: 'nodeImport',
128+
data: {source},
129+
});
130+
}
131+
},
132+
133+
// Flag require() calls for Node.js built-in modules.
134+
CallExpression(node) {
135+
if (
136+
node.callee.type === 'Identifier' &&
137+
node.callee.name === 'require' &&
138+
node.arguments.length > 0 &&
139+
node.arguments[0].type === 'Literal' &&
140+
typeof node.arguments[0].value === 'string'
141+
) {
142+
const source = node.arguments[0].value;
143+
const moduleName = source.startsWith('node:')
144+
? source.slice(5)
145+
: source;
146+
147+
if (NODE_BUILTIN_MODULES.has(moduleName)) {
148+
context.report({
149+
node: node.arguments[0],
150+
messageId: 'nodeImport',
151+
data: {source},
152+
});
153+
}
154+
}
155+
},
156+
157+
// Flag references to Node.js-specific globals.
158+
Identifier(node) {
159+
if (!NODE_GLOBALS.has(node.name)) {
160+
return;
161+
}
162+
163+
// Skip property accesses: obj.Buffer, obj.process, etc.
164+
if (
165+
node.parent.type === 'MemberExpression' &&
166+
node.parent.property === node &&
167+
!node.parent.computed
168+
) {
169+
return;
170+
}
171+
172+
// Skip variable declarations: const Buffer = ...
173+
if (
174+
node.parent.type === 'VariableDeclarator' &&
175+
node.parent.id === node
176+
) {
177+
return;
178+
}
179+
180+
// Skip function parameter names
181+
if (
182+
node.parent.type === 'FunctionDeclaration' ||
183+
node.parent.type === 'FunctionExpression' ||
184+
node.parent.type === 'ArrowFunctionExpression'
185+
) {
186+
if (node.parent.params && node.parent.params.includes(node)) {
187+
return;
188+
}
189+
}
190+
191+
// Skip object property keys: { process: ... }
192+
if (
193+
node.parent.type === 'Property' &&
194+
node.parent.key === node &&
195+
!node.parent.computed
196+
) {
197+
return;
198+
}
199+
200+
// Skip import specifiers: import { Buffer } from '...' (caught by ImportDeclaration)
201+
if (
202+
node.parent.type === 'ImportSpecifier' ||
203+
node.parent.type === 'ImportDefaultSpecifier' ||
204+
node.parent.type === 'ImportNamespaceSpecifier'
205+
) {
206+
return;
207+
}
208+
209+
// Only flag actual global references, not locally-scoped variables.
210+
const scope = context.getScope();
211+
const variable = findVariable(scope, node.name);
212+
if (variable && variable.defs.length > 0) {
213+
return;
214+
}
215+
216+
context.report({
217+
node,
218+
messageId: 'nodeGlobal',
219+
data: {name: node.name},
220+
});
221+
},
222+
223+
// Flag NodeJS.* type references (e.g., NodeJS.ReadableStream, NodeJS.Timeout).
224+
TSTypeReference(node) {
225+
if (
226+
node.typeName &&
227+
node.typeName.type === 'TSQualifiedName' &&
228+
node.typeName.left &&
229+
node.typeName.left.type === 'Identifier' &&
230+
node.typeName.left.name === 'NodeJS'
231+
) {
232+
context.report({
233+
node,
234+
messageId: 'nodeType',
235+
data: {name: node.typeName.right.name},
236+
});
237+
}
238+
},
239+
};
240+
},
241+
};

examples/snippets/event_notification_handler_endpoint.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// File copied from our code generator; changes here will be overwritten.
2+
13
/**
24
* event_notification_handler_endpoint.ts - receive and process event notifications like the
35
* v1.billing.meter.error_report_triggered event.

examples/snippets/event_notification_webhook_handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// File copied from our code generator; changes here will be overwritten.
2+
13
/**
24
* event_notification_webhook_handler.ts - receive and process event notifications like the
35
* v1.billing.meter.error_report_triggered event.

justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ lint: (lint-check "--fix")
5353

5454
# run style checks without changing anything
5555
lint-check *args: install
56-
eslint --ext .js,.ts . {{ args }}
56+
eslint --rulesdir eslint-rules --ext .js,.ts . {{ args }}
5757

5858
# reinstall dependencies, if needed
5959
install:

src/RequestSender.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {RawRequestOptions, RequestOptions} from './lib.js';
2525
import {HttpClient, HttpClientResponseInterface} from './net/HttpClient.js';
2626
import {Stripe} from './stripe.core.js';
2727
import {
28-
emitWarning,
2928
jsonStringifyRequestData,
3029
normalizeHeaders,
3130
queryStringifyRequestData,
@@ -418,7 +417,7 @@ export class RequestSender {
418417
// and fix these cases as they are semantically incorrect.
419418
if (methodHasPayload || contentLength) {
420419
if (!methodHasPayload) {
421-
emitWarning(
420+
this._stripe._platformFunctions.emitWarning(
422421
`${method} method had non-zero contentLength but no payload is expected for this verb`
423422
);
424423
}
@@ -470,7 +469,7 @@ export class RequestSender {
470469
if (
471470
this._stripe._prevRequestMetrics.length > this._maxBufferedRequestMetric
472471
) {
473-
emitWarning(
472+
this._stripe._platformFunctions.emitWarning(
474473
'Request metrics buffer is full, dropping telemetry message.'
475474
);
476475
} else {
@@ -580,7 +579,7 @@ export class RequestSender {
580579
headers: RequestHeaders,
581580
requestRetries: number,
582581
retryAfter: number | null
583-
): NodeJS.Timeout => {
582+
): ReturnType<typeof setTimeout> => {
584583
return setTimeout(
585584
requestFn,
586585
this._getSleepTimeInMS(requestRetries, retryAfter),

src/StripeEventNotificationHandler.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
// File copied from our code generator; changes here will be overwritten.
2+
13
import {Stripe} from './stripe.core.js';
24
import * as Events from './resources/V2/Core/Events.js';
35

46
export interface UnhandledNotificationDetails {
57
isKnownEventType: boolean;
68
}
79

8-
type FallbackCallback = (
10+
export type FallbackCallback = (
911
event: Events.UnknownEventNotification,
1012
client: Stripe,
1113
details: UnhandledNotificationDetails
@@ -147,8 +149,8 @@ export class StripeEventNotificationHandler {
147149

148150
public async handle(
149151
// these types are duplicated in the manual types, so they're just here for internal use
150-
rawBody: string | Buffer,
151-
signature: string | Buffer
152+
rawBody: string | Uint8Array,
153+
signature: string | Uint8Array
152154
): Promise<void> {
153155
// we're not worried about thread safety here because we expect callbacks will be registered synchronously on app startup
154156
this.hasHandledEvent = true;

src/Types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* eslint-disable camelcase */
2+
// TODO(DEVSDK-3113): Remove EventEmitter from shared types in next major version.
3+
// eslint-disable-next-line wintertc-compat
24
import {EventEmitter} from 'events';
35
import {
46
HttpClientInterface,

0 commit comments

Comments
 (0)