apiwatcher-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changesets/stripe/2025-09-30.clover__2026-08-26.dahlia.json +4576 -0
- package/changesets/stripe/index.json +16 -0
- package/data/stripe/events.json +271 -0
- package/data/stripe/method-map.json +5718 -0
- package/dist/changeset/index-file.d.ts +30 -0
- package/dist/changeset/index-file.d.ts.map +1 -0
- package/dist/changeset/index-file.js +34 -0
- package/dist/changeset/index-file.js.map +1 -0
- package/dist/changeset/load.d.ts +21 -0
- package/dist/changeset/load.d.ts.map +1 -0
- package/dist/changeset/load.js +113 -0
- package/dist/changeset/load.js.map +1 -0
- package/dist/changeset/types.d.ts +97 -0
- package/dist/changeset/types.d.ts.map +1 -0
- package/dist/changeset/types.js +18 -0
- package/dist/changeset/types.js.map +1 -0
- package/dist/changeset/version.d.ts +17 -0
- package/dist/changeset/version.d.ts.map +1 -0
- package/dist/changeset/version.js +33 -0
- package/dist/changeset/version.js.map +1 -0
- package/dist/cli/args.d.ts +15 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +82 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +333 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +92 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/report/impact.d.ts +40 -0
- package/dist/report/impact.d.ts.map +1 -0
- package/dist/report/impact.js +331 -0
- package/dist/report/impact.js.map +1 -0
- package/dist/report/impact.test.d.ts +2 -0
- package/dist/report/impact.test.d.ts.map +1 -0
- package/dist/report/impact.test.js +247 -0
- package/dist/report/impact.test.js.map +1 -0
- package/dist/report/render.d.ts +9 -0
- package/dist/report/render.d.ts.map +1 -0
- package/dist/report/render.js +211 -0
- package/dist/report/render.js.map +1 -0
- package/dist/scanner/ast.d.ts +74 -0
- package/dist/scanner/ast.d.ts.map +1 -0
- package/dist/scanner/ast.js +930 -0
- package/dist/scanner/ast.js.map +1 -0
- package/dist/scanner/paths.d.ts +42 -0
- package/dist/scanner/paths.d.ts.map +1 -0
- package/dist/scanner/paths.js +179 -0
- package/dist/scanner/paths.js.map +1 -0
- package/dist/scanner/scan.d.ts +11 -0
- package/dist/scanner/scan.d.ts.map +1 -0
- package/dist/scanner/scan.js +268 -0
- package/dist/scanner/scan.js.map +1 -0
- package/dist/scanner/scan.test.d.ts +2 -0
- package/dist/scanner/scan.test.d.ts.map +1 -0
- package/dist/scanner/scan.test.js +134 -0
- package/dist/scanner/scan.test.js.map +1 -0
- package/dist/scanner/types.d.ts +74 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +7 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/scanner/version.d.ts +23 -0
- package/dist/scanner/version.d.ts.map +1 -0
- package/dist/scanner/version.js +155 -0
- package/dist/scanner/version.js.map +1 -0
- package/dist/scanner/walk.d.ts +26 -0
- package/dist/scanner/walk.d.ts.map +1 -0
- package/dist/scanner/walk.js +117 -0
- package/dist/scanner/walk.js.map +1 -0
- package/dist/scanner/wrapper.test.d.ts +2 -0
- package/dist/scanner/wrapper.test.d.ts.map +1 -0
- package/dist/scanner/wrapper.test.js +92 -0
- package/dist/scanner/wrapper.test.js.map +1 -0
- package/dist/specdiff/build-method-map.d.ts +6 -0
- package/dist/specdiff/build-method-map.d.ts.map +1 -0
- package/dist/specdiff/build-method-map.js +231 -0
- package/dist/specdiff/build-method-map.js.map +1 -0
- package/dist/specdiff/compat.d.ts +20 -0
- package/dist/specdiff/compat.d.ts.map +1 -0
- package/dist/specdiff/compat.js +58 -0
- package/dist/specdiff/compat.js.map +1 -0
- package/dist/specdiff/diff.d.ts +28 -0
- package/dist/specdiff/diff.d.ts.map +1 -0
- package/dist/specdiff/diff.js +529 -0
- package/dist/specdiff/diff.js.map +1 -0
- package/dist/specdiff/diff.test.d.ts +2 -0
- package/dist/specdiff/diff.test.d.ts.map +1 -0
- package/dist/specdiff/diff.test.js +260 -0
- package/dist/specdiff/diff.test.js.map +1 -0
- package/dist/specdiff/fetch.d.ts +28 -0
- package/dist/specdiff/fetch.d.ts.map +1 -0
- package/dist/specdiff/fetch.js +68 -0
- package/dist/specdiff/fetch.js.map +1 -0
- package/dist/specdiff/methodmap.d.ts +45 -0
- package/dist/specdiff/methodmap.d.ts.map +1 -0
- package/dist/specdiff/methodmap.js +109 -0
- package/dist/specdiff/methodmap.js.map +1 -0
- package/dist/specdiff/openapi.d.ts +166 -0
- package/dist/specdiff/openapi.d.ts.map +1 -0
- package/dist/specdiff/openapi.js +282 -0
- package/dist/specdiff/openapi.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import { diffSpecs } from './diff.js';
|
|
4
|
+
import { classifyTypeChange } from './compat.js';
|
|
5
|
+
import { flattenOwnFields } from './openapi.js';
|
|
6
|
+
/** Minimal spec builder so each test states only what it is about. */
|
|
7
|
+
function spec(version, body = {}) {
|
|
8
|
+
return {
|
|
9
|
+
openapi: '3.0.0',
|
|
10
|
+
info: { version },
|
|
11
|
+
paths: {},
|
|
12
|
+
components: { schemas: {} },
|
|
13
|
+
...body,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function formBody(properties, required = []) {
|
|
17
|
+
return {
|
|
18
|
+
content: {
|
|
19
|
+
'application/x-www-form-urlencoded': {
|
|
20
|
+
schema: { type: 'object', properties, ...(required.length > 0 ? { required } : {}) },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
test('flattenOwnFields treats $ref as a boundary', () => {
|
|
26
|
+
const s = spec('2025-01-01', {
|
|
27
|
+
components: {
|
|
28
|
+
schemas: {
|
|
29
|
+
parent: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
own: { type: 'string' },
|
|
33
|
+
child: { $ref: '#/components/schemas/child' },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
child: { type: 'object', properties: { deep: { type: 'string' } } },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const fields = flattenOwnFields(s, s.components?.schemas?.parent);
|
|
41
|
+
assert.deepEqual([...fields.keys()].sort(), ['child', 'own']);
|
|
42
|
+
// `child.deep` belongs to the child schema and is diffed there, not here.
|
|
43
|
+
assert.equal(fields.has('child.deep'), false);
|
|
44
|
+
});
|
|
45
|
+
test('flattenOwnFields marks a field required only when every ancestor is', () => {
|
|
46
|
+
const s = spec('2025-01-01', {
|
|
47
|
+
components: {
|
|
48
|
+
schemas: {
|
|
49
|
+
root: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
required: ['mandatory'],
|
|
52
|
+
properties: {
|
|
53
|
+
mandatory: { type: 'object', required: ['inner'], properties: { inner: { type: 'string' } } },
|
|
54
|
+
optional: { type: 'object', required: ['inner'], properties: { inner: { type: 'string' } } },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const fields = flattenOwnFields(s, s.components?.schemas?.root);
|
|
61
|
+
assert.equal(fields.get('mandatory.inner')?.requiredPath, true);
|
|
62
|
+
// Required inside an optional object: only binds callers who send the parent.
|
|
63
|
+
assert.equal(fields.get('optional.inner')?.required, true);
|
|
64
|
+
assert.equal(fields.get('optional.inner')?.requiredPath, false);
|
|
65
|
+
});
|
|
66
|
+
test('a removed endpoint is breaking', () => {
|
|
67
|
+
const before = spec('2025-01-01', { paths: { '/v1/old': { get: { operationId: 'GetOld' } } } });
|
|
68
|
+
const after = spec('2025-06-01', { paths: {} });
|
|
69
|
+
const cs = diffSpecs(before, after);
|
|
70
|
+
assert.equal(cs.changes.length, 1);
|
|
71
|
+
assert.equal(cs.changes[0]?.kind, 'removed');
|
|
72
|
+
assert.equal(cs.changes[0]?.location, 'operation');
|
|
73
|
+
assert.equal(cs.changes[0]?.severity, 'breaking');
|
|
74
|
+
assert.equal(cs.from, '2025-01-01');
|
|
75
|
+
assert.equal(cs.to, '2025-06-01');
|
|
76
|
+
});
|
|
77
|
+
test('a new endpoint is reported only with includeAdditive', () => {
|
|
78
|
+
const before = spec('2025-01-01', { paths: {} });
|
|
79
|
+
const after = spec('2025-06-01', { paths: { '/v1/new': { get: {} } } });
|
|
80
|
+
assert.equal(diffSpecs(before, after).changes.length, 0);
|
|
81
|
+
const withAdditive = diffSpecs(before, after, { includeAdditive: true });
|
|
82
|
+
assert.equal(withAdditive.changes.length, 1);
|
|
83
|
+
assert.equal(withAdditive.changes[0]?.severity, 'additive');
|
|
84
|
+
});
|
|
85
|
+
test('removing a request parameter does not also report its children', () => {
|
|
86
|
+
const before = spec('2025-01-01', {
|
|
87
|
+
paths: {
|
|
88
|
+
'/v1/x': {
|
|
89
|
+
post: {
|
|
90
|
+
requestBody: formBody({
|
|
91
|
+
tipping: {
|
|
92
|
+
type: 'object',
|
|
93
|
+
properties: { bgn: { type: 'object', properties: { amount: { type: 'integer' } } } },
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
const after = spec('2025-06-01', {
|
|
101
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ tipping: { type: 'object', properties: {} } }) } } },
|
|
102
|
+
});
|
|
103
|
+
const removed = diffSpecs(before, after).changes.filter((c) => c.kind === 'removed');
|
|
104
|
+
assert.deepEqual(removed.map((c) => c.field), ['tipping.bgn']);
|
|
105
|
+
});
|
|
106
|
+
test('an unrelated field pair is not mistaken for a rename', () => {
|
|
107
|
+
const before = spec('2025-01-01', {
|
|
108
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ bgn: { type: 'string' } }) } } },
|
|
109
|
+
});
|
|
110
|
+
const after = spec('2025-06-01', {
|
|
111
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ gip: { type: 'string' } }) } } },
|
|
112
|
+
});
|
|
113
|
+
const kinds = diffSpecs(before, after, { includeAdditive: true })
|
|
114
|
+
.changes.map((c) => c.kind)
|
|
115
|
+
.sort();
|
|
116
|
+
// Two unrelated currency keys: a removal and an addition, never a rename.
|
|
117
|
+
assert.deepEqual(kinds, ['added', 'removed']);
|
|
118
|
+
});
|
|
119
|
+
test('a genuine rename is detected', () => {
|
|
120
|
+
const before = spec('2025-01-01', {
|
|
121
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ risk_level: { type: 'string' } }) } } },
|
|
122
|
+
});
|
|
123
|
+
const after = spec('2025-06-01', {
|
|
124
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ level: { type: 'string' } }) } } },
|
|
125
|
+
});
|
|
126
|
+
const changes = diffSpecs(before, after).changes;
|
|
127
|
+
assert.equal(changes.length, 1);
|
|
128
|
+
assert.equal(changes[0]?.kind, 'renamed');
|
|
129
|
+
assert.equal(changes[0]?.field, 'risk_level');
|
|
130
|
+
assert.equal(changes[0]?.replacement, 'level');
|
|
131
|
+
});
|
|
132
|
+
test('a newly required nested parameter says what it is conditional on', () => {
|
|
133
|
+
const before = spec('2025-01-01', {
|
|
134
|
+
paths: {
|
|
135
|
+
'/v1/x': {
|
|
136
|
+
post: {
|
|
137
|
+
requestBody: formBody({
|
|
138
|
+
cfg: { type: 'object', properties: { a: { type: 'string' } } },
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
const after = spec('2025-06-01', {
|
|
145
|
+
paths: {
|
|
146
|
+
'/v1/x': {
|
|
147
|
+
post: {
|
|
148
|
+
requestBody: formBody({
|
|
149
|
+
cfg: { type: 'object', required: ['a'], properties: { a: { type: 'string' } } },
|
|
150
|
+
}),
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
const changes = diffSpecs(before, after).changes;
|
|
156
|
+
assert.equal(changes.length, 1);
|
|
157
|
+
assert.equal(changes[0]?.kind, 'required');
|
|
158
|
+
assert.match(changes[0]?.note ?? '', /whenever "cfg" is provided/);
|
|
159
|
+
});
|
|
160
|
+
test('a top-level newly required parameter is stated unconditionally', () => {
|
|
161
|
+
const before = spec('2025-01-01', {
|
|
162
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ a: { type: 'string' } }) } } },
|
|
163
|
+
});
|
|
164
|
+
const after = spec('2025-06-01', {
|
|
165
|
+
paths: { '/v1/x': { post: { requestBody: formBody({ a: { type: 'string' } }, ['a']) } } },
|
|
166
|
+
});
|
|
167
|
+
const changes = diffSpecs(before, after).changes;
|
|
168
|
+
assert.equal(changes[0]?.kind, 'required');
|
|
169
|
+
assert.doesNotMatch(changes[0]?.note ?? '', /whenever/);
|
|
170
|
+
});
|
|
171
|
+
test('response changes are attributed to the endpoints returning the resource', () => {
|
|
172
|
+
const build = (props, version) => spec(version, {
|
|
173
|
+
paths: {
|
|
174
|
+
'/v1/widgets/{id}': {
|
|
175
|
+
get: {
|
|
176
|
+
responses: {
|
|
177
|
+
'200': { content: { 'application/json': { schema: { $ref: '#/components/schemas/widget' } } } },
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
components: {
|
|
183
|
+
schemas: { widget: { type: 'object', 'x-resourceId': 'widget', properties: props } },
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
const cs = diffSpecs(build({ keep: { type: 'string' }, gone: { type: 'string' } }, '2025-01-01'), build({ keep: { type: 'string' } }, '2025-06-01'));
|
|
187
|
+
assert.equal(cs.changes.length, 1);
|
|
188
|
+
const change = cs.changes[0];
|
|
189
|
+
assert.equal(change?.kind, 'removed');
|
|
190
|
+
assert.equal(change?.location, 'response');
|
|
191
|
+
assert.equal(change?.resource, 'widget');
|
|
192
|
+
assert.equal(change?.field, 'gone');
|
|
193
|
+
assert.deepEqual(change?.endpoints, [{ method: 'get', path: '/v1/widgets/{id}' }]);
|
|
194
|
+
assert.deepEqual(change?.fieldPaths, ['gone']);
|
|
195
|
+
});
|
|
196
|
+
test('a nested resource change cites the path a caller reads it through', () => {
|
|
197
|
+
const build = (childProps, version) => spec(version, {
|
|
198
|
+
paths: {
|
|
199
|
+
'/v1/parents': {
|
|
200
|
+
get: {
|
|
201
|
+
responses: {
|
|
202
|
+
'200': { content: { 'application/json': { schema: { $ref: '#/components/schemas/parent' } } } },
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
components: {
|
|
208
|
+
schemas: {
|
|
209
|
+
parent: {
|
|
210
|
+
type: 'object',
|
|
211
|
+
properties: {
|
|
212
|
+
items: { type: 'array', items: { $ref: '#/components/schemas/item' } },
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
item: { type: 'object', properties: childProps },
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
const cs = diffSpecs(build({ amount: { type: 'integer' }, legacy: { type: 'string' } }, '2025-01-01'), build({ amount: { type: 'integer' } }, '2025-06-01'));
|
|
220
|
+
const change = cs.changes.find((c) => c.resource === 'item');
|
|
221
|
+
assert.ok(change, 'expected a change on the item schema');
|
|
222
|
+
assert.equal(change?.field, 'legacy');
|
|
223
|
+
// Reported once against `item`, but citeable at the path callers actually use.
|
|
224
|
+
assert.deepEqual(change?.fieldPaths, ['items[].legacy']);
|
|
225
|
+
});
|
|
226
|
+
test('a removed webhook event is breaking', () => {
|
|
227
|
+
const withEvents = (events, version) => spec(version, {
|
|
228
|
+
components: {
|
|
229
|
+
schemas: Object.fromEntries(events.map((e) => [e, { 'x-stripeEvent': { type: e } }])),
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
const cs = diffSpecs(withEvents(['a.b', 'c.d'], '2025-01-01'), withEvents(['a.b'], '2025-06-01'));
|
|
233
|
+
assert.equal(cs.changes.length, 1);
|
|
234
|
+
assert.equal(cs.changes[0]?.location, 'event');
|
|
235
|
+
assert.equal(cs.changes[0]?.event, 'c.d');
|
|
236
|
+
assert.equal(cs.changes[0]?.severity, 'breaking');
|
|
237
|
+
});
|
|
238
|
+
// --- type compatibility ----------------------------------------------------
|
|
239
|
+
test('enum widening is additive, narrowing breaks only the sending side', () => {
|
|
240
|
+
const narrow = 'enum(a|b)';
|
|
241
|
+
const wide = 'enum(a|b|c)';
|
|
242
|
+
assert.equal(classifyTypeChange(narrow, wide, 'request').severity, 'additive');
|
|
243
|
+
assert.equal(classifyTypeChange(narrow, wide, 'response').severity, 'additive');
|
|
244
|
+
// Losing an accepted value breaks callers who send it.
|
|
245
|
+
assert.equal(classifyTypeChange(wide, narrow, 'request').severity, 'breaking');
|
|
246
|
+
// Losing a returned value only leaves a dead branch behind.
|
|
247
|
+
assert.equal(classifyTypeChange(wide, narrow, 'response').severity, 'additive');
|
|
248
|
+
});
|
|
249
|
+
test('a scalar type swap is breaking in both directions', () => {
|
|
250
|
+
for (const direction of ['request', 'response']) {
|
|
251
|
+
const verdict = classifyTypeChange('integer', 'string', direction);
|
|
252
|
+
assert.equal(verdict.changed, true);
|
|
253
|
+
assert.equal(verdict.severity, 'breaking');
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
test('identical signatures are not a change', () => {
|
|
257
|
+
assert.equal(classifyTypeChange('enum(a|b)', 'enum(b|a)', 'request').changed, false);
|
|
258
|
+
assert.equal(classifyTypeChange('string', 'string', 'response').changed, false);
|
|
259
|
+
});
|
|
260
|
+
//# sourceMappingURL=diff.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.test.js","sourceRoot":"","sources":["../../src/specdiff/diff.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { OpenApiSpec } from './openapi.js';
|
|
2
|
+
export declare const STRIPE_SPEC_REPO = "stripe/openapi";
|
|
3
|
+
/** The `.sdk.` variant carries `x-stripeOperations`, which the plain spec omits. */
|
|
4
|
+
export declare const STRIPE_SPEC_PATH = "openapi/spec3.sdk.json";
|
|
5
|
+
export interface SpecCommit {
|
|
6
|
+
sha: string;
|
|
7
|
+
date: string;
|
|
8
|
+
}
|
|
9
|
+
/** Commits that touched the spec, newest first. */
|
|
10
|
+
export declare function listSpecCommits(options?: {
|
|
11
|
+
perPage?: number;
|
|
12
|
+
until?: string;
|
|
13
|
+
}): Promise<SpecCommit[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a ref to the commit that last touched the spec.
|
|
16
|
+
*
|
|
17
|
+
* The watcher records where it stopped so the next run can diff forward from
|
|
18
|
+
* there. Recording a branch name instead of a SHA would mean diffing a moving
|
|
19
|
+
* target against itself and silently finding nothing, so always pin.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveSpecCommit(ref: string): Promise<string>;
|
|
22
|
+
/** Fetch the spec at a git ref. ~10MB, so callers should cache. */
|
|
23
|
+
export declare function fetchSpecAt(ref: string): Promise<OpenApiSpec>;
|
|
24
|
+
export declare function readSpecFile(file: string): Promise<OpenApiSpec>;
|
|
25
|
+
/** `"2026-08-26.dahlia"` -> a safe filename segment. */
|
|
26
|
+
export declare function versionSlug(version: string): string;
|
|
27
|
+
export declare function changesetFilename(from: string, to: string): string;
|
|
28
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/specdiff/fetch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AACjD,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,2BAA2B,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAsBD,mDAAmD;AACnD,wBAAsB,eAAe,CAAC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAChG,UAAU,EAAE,CACb,CAWA;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQpE;AAED,mEAAmE;AACnE,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAKnE;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAErE;AAED,wDAAwD;AACxD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAElE"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
export const STRIPE_SPEC_REPO = 'stripe/openapi';
|
|
3
|
+
/** The `.sdk.` variant carries `x-stripeOperations`, which the plain spec omits. */
|
|
4
|
+
export const STRIPE_SPEC_PATH = 'openapi/spec3.sdk.json';
|
|
5
|
+
function ghHeaders() {
|
|
6
|
+
const headers = {
|
|
7
|
+
accept: 'application/vnd.github+json',
|
|
8
|
+
'user-agent': 'apiwatcher-spec-watcher',
|
|
9
|
+
};
|
|
10
|
+
// Unauthenticated GitHub allows 60 requests/hour, which is plenty for a cron
|
|
11
|
+
// but not for local iteration. Honour a token when one is present.
|
|
12
|
+
const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;
|
|
13
|
+
if (token)
|
|
14
|
+
headers.authorization = `Bearer ${token}`;
|
|
15
|
+
return headers;
|
|
16
|
+
}
|
|
17
|
+
async function ghJson(url) {
|
|
18
|
+
const res = await fetch(url, { headers: ghHeaders() });
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
throw new Error(`GitHub ${res.status} ${res.statusText} for ${url}`);
|
|
21
|
+
}
|
|
22
|
+
return (await res.json());
|
|
23
|
+
}
|
|
24
|
+
/** Commits that touched the spec, newest first. */
|
|
25
|
+
export async function listSpecCommits(options = {}) {
|
|
26
|
+
const params = new URLSearchParams({
|
|
27
|
+
path: STRIPE_SPEC_PATH,
|
|
28
|
+
per_page: String(options.perPage ?? 30),
|
|
29
|
+
});
|
|
30
|
+
if (options.until)
|
|
31
|
+
params.set('until', options.until);
|
|
32
|
+
const commits = await ghJson(`https://api.github.com/repos/${STRIPE_SPEC_REPO}/commits?${params.toString()}`);
|
|
33
|
+
return commits.map((c) => ({ sha: c.sha, date: c.commit.committer.date }));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a ref to the commit that last touched the spec.
|
|
37
|
+
*
|
|
38
|
+
* The watcher records where it stopped so the next run can diff forward from
|
|
39
|
+
* there. Recording a branch name instead of a SHA would mean diffing a moving
|
|
40
|
+
* target against itself and silently finding nothing, so always pin.
|
|
41
|
+
*/
|
|
42
|
+
export async function resolveSpecCommit(ref) {
|
|
43
|
+
const params = new URLSearchParams({ path: STRIPE_SPEC_PATH, sha: ref, per_page: '1' });
|
|
44
|
+
const commits = await ghJson(`https://api.github.com/repos/${STRIPE_SPEC_REPO}/commits?${params.toString()}`);
|
|
45
|
+
const sha = commits[0]?.sha;
|
|
46
|
+
if (!sha)
|
|
47
|
+
throw new Error(`Could not resolve ${STRIPE_SPEC_REPO}@${ref} to a commit`);
|
|
48
|
+
return sha;
|
|
49
|
+
}
|
|
50
|
+
/** Fetch the spec at a git ref. ~10MB, so callers should cache. */
|
|
51
|
+
export async function fetchSpecAt(ref) {
|
|
52
|
+
const url = `https://raw.githubusercontent.com/${STRIPE_SPEC_REPO}/${ref}/${STRIPE_SPEC_PATH}`;
|
|
53
|
+
const res = await fetch(url, { headers: { 'user-agent': 'apiwatcher-spec-watcher' } });
|
|
54
|
+
if (!res.ok)
|
|
55
|
+
throw new Error(`Failed to fetch spec at ${ref}: ${res.status} ${res.statusText}`);
|
|
56
|
+
return (await res.json());
|
|
57
|
+
}
|
|
58
|
+
export async function readSpecFile(file) {
|
|
59
|
+
return JSON.parse(await readFile(file, 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
/** `"2026-08-26.dahlia"` -> a safe filename segment. */
|
|
62
|
+
export function versionSlug(version) {
|
|
63
|
+
return version.replace(/[^a-z0-9.-]/gi, '_');
|
|
64
|
+
}
|
|
65
|
+
export function changesetFilename(from, to) {
|
|
66
|
+
return `${versionSlug(from)}__${versionSlug(to)}.json`;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/specdiff/fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SdkMethodRef } from '../changeset/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Maps an HTTP endpoint to the stripe-node calls that reach it, and back.
|
|
4
|
+
*
|
|
5
|
+
* Generated from the stripe package's own generated resource files, so it is
|
|
6
|
+
* ground truth rather than a guess at Stripe's pluralization rules.
|
|
7
|
+
*/
|
|
8
|
+
export interface MethodMap {
|
|
9
|
+
/** stripe-node version the map was generated from. */
|
|
10
|
+
sdkVersion: string;
|
|
11
|
+
generatedAt: string;
|
|
12
|
+
/** `"post /v1/payment_intents"` -> [{ namespace: 'paymentIntents', method: 'create' }] */
|
|
13
|
+
byEndpoint: Record<string, SdkMethodRef[]>;
|
|
14
|
+
/** `"paymentIntents.create"` -> { method: 'post', path: '/v1/payment_intents' } */
|
|
15
|
+
byCall: Record<string, {
|
|
16
|
+
method: string;
|
|
17
|
+
path: string;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export declare function endpointKey(method: string, path: string): string;
|
|
21
|
+
export declare function callKey(namespace: string, method: string): string;
|
|
22
|
+
/** Walk up from this module looking for the committed map. */
|
|
23
|
+
export declare function defaultMethodMapPath(): string | null;
|
|
24
|
+
/** The webhook event types a spec version defines. */
|
|
25
|
+
export interface EventCatalog {
|
|
26
|
+
apiVersion: string;
|
|
27
|
+
generatedAt: string;
|
|
28
|
+
events: string[];
|
|
29
|
+
}
|
|
30
|
+
export declare function defaultEventCatalogPath(): string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Known event types, used to tell a real webhook event string apart from any
|
|
33
|
+
* other dotted lowercase literal. Without it the scanner has to guess from
|
|
34
|
+
* context and reports lower confidence.
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadEventCatalog(file?: string): Promise<ReadonlySet<string> | null>;
|
|
37
|
+
export declare function loadMethodMap(file?: string): Promise<MethodMap>;
|
|
38
|
+
/**
|
|
39
|
+
* Endpoint paths in the spec use `{customer}`; stripe-node builds them from
|
|
40
|
+
* template literals. Both sides normalize to `{}` so they compare equal
|
|
41
|
+
* regardless of what the parameter happens to be called.
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizePath(path: string): string;
|
|
44
|
+
export declare function lookupSdkMethods(map: MethodMap, method: string, path: string): SdkMethodRef[];
|
|
45
|
+
//# sourceMappingURL=methodmap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methodmap.d.ts","sourceRoot":"","sources":["../../src/specdiff/methodmap.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IAC3C,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE;AASD,8DAA8D;AAC9D,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAUpD;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAUvD;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CASzF;AAED,wBAAsB,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAQrE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAyBD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAI7F"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
export function endpointKey(method, path) {
|
|
7
|
+
return `${method.toLowerCase()} ${path}`;
|
|
8
|
+
}
|
|
9
|
+
export function callKey(namespace, method) {
|
|
10
|
+
return `${namespace}.${method}`;
|
|
11
|
+
}
|
|
12
|
+
const EMPTY = {
|
|
13
|
+
sdkVersion: 'unknown',
|
|
14
|
+
generatedAt: new Date(0).toISOString(),
|
|
15
|
+
byEndpoint: {},
|
|
16
|
+
byCall: {},
|
|
17
|
+
};
|
|
18
|
+
/** Walk up from this module looking for the committed map. */
|
|
19
|
+
export function defaultMethodMapPath() {
|
|
20
|
+
let dir = HERE;
|
|
21
|
+
for (let i = 0; i < 8; i++) {
|
|
22
|
+
const candidate = join(dir, 'data', 'stripe', 'method-map.json');
|
|
23
|
+
if (existsSync(candidate))
|
|
24
|
+
return candidate;
|
|
25
|
+
const parent = dirname(dir);
|
|
26
|
+
if (parent === dir)
|
|
27
|
+
break;
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
export function defaultEventCatalogPath() {
|
|
33
|
+
let dir = HERE;
|
|
34
|
+
for (let i = 0; i < 8; i++) {
|
|
35
|
+
const candidate = join(dir, 'data', 'stripe', 'events.json');
|
|
36
|
+
if (existsSync(candidate))
|
|
37
|
+
return candidate;
|
|
38
|
+
const parent = dirname(dir);
|
|
39
|
+
if (parent === dir)
|
|
40
|
+
break;
|
|
41
|
+
dir = parent;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Known event types, used to tell a real webhook event string apart from any
|
|
47
|
+
* other dotted lowercase literal. Without it the scanner has to guess from
|
|
48
|
+
* context and reports lower confidence.
|
|
49
|
+
*/
|
|
50
|
+
export async function loadEventCatalog(file) {
|
|
51
|
+
const path = file ? resolve(file) : defaultEventCatalogPath();
|
|
52
|
+
if (!path || !existsSync(path))
|
|
53
|
+
return null;
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
56
|
+
return Array.isArray(parsed.events) ? new Set(parsed.events) : null;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function loadMethodMap(file) {
|
|
63
|
+
const path = file ? resolve(file) : defaultMethodMapPath();
|
|
64
|
+
if (!path || !existsSync(path))
|
|
65
|
+
return EMPTY;
|
|
66
|
+
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
67
|
+
if (!parsed.byEndpoint || !parsed.byCall) {
|
|
68
|
+
throw new Error(`${path}: not a method map (missing byEndpoint/byCall)`);
|
|
69
|
+
}
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Endpoint paths in the spec use `{customer}`; stripe-node builds them from
|
|
74
|
+
* template literals. Both sides normalize to `{}` so they compare equal
|
|
75
|
+
* regardless of what the parameter happens to be called.
|
|
76
|
+
*/
|
|
77
|
+
export function normalizePath(path) {
|
|
78
|
+
return path.replace(/\{[^}]*\}/g, '{}');
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parameter names differ between sources — the spec says `{intent}`, stripe-node
|
|
82
|
+
* builds `{id}` — so lookups fall back to a name-insensitive index. Built once
|
|
83
|
+
* per map and cached, since the differ calls this for every operation.
|
|
84
|
+
*/
|
|
85
|
+
const normalizedIndexes = new WeakMap();
|
|
86
|
+
function normalizedIndex(map) {
|
|
87
|
+
const cached = normalizedIndexes.get(map);
|
|
88
|
+
if (cached)
|
|
89
|
+
return cached;
|
|
90
|
+
const index = new Map();
|
|
91
|
+
for (const [key, refs] of Object.entries(map.byEndpoint)) {
|
|
92
|
+
const sep = key.indexOf(' ');
|
|
93
|
+
const normalized = `${key.slice(0, sep)} ${normalizePath(key.slice(sep + 1))}`;
|
|
94
|
+
const bucket = index.get(normalized);
|
|
95
|
+
if (bucket)
|
|
96
|
+
bucket.push(...refs);
|
|
97
|
+
else
|
|
98
|
+
index.set(normalized, [...refs]);
|
|
99
|
+
}
|
|
100
|
+
normalizedIndexes.set(map, index);
|
|
101
|
+
return index;
|
|
102
|
+
}
|
|
103
|
+
export function lookupSdkMethods(map, method, path) {
|
|
104
|
+
const exact = map.byEndpoint[endpointKey(method, path)];
|
|
105
|
+
if (exact)
|
|
106
|
+
return exact;
|
|
107
|
+
return normalizedIndex(map).get(`${method.toLowerCase()} ${normalizePath(path)}`) ?? [];
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=methodmap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methodmap.js","sourceRoot":"","sources":["../../src/specdiff/methodmap.ts"],"names":[],"mappings":"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"}
|