@suss/contract-aws-apigateway 0.0.1
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/LICENSE +205 -0
- package/README.md +34 -0
- package/dist/index.cjs +585 -0
- package/dist/index.d.cts +184 -0
- package/dist/index.d.ts +184 -0
- package/dist/index.js +557 -0
- package/package.json +58 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
httpApiToSummaries: () => httpApiToSummaries,
|
|
24
|
+
restApiToSummaries: () => restApiToSummaries
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/http.ts
|
|
29
|
+
var import_behavioral_ir2 = require("@suss/behavioral-ir");
|
|
30
|
+
|
|
31
|
+
// src/shared.ts
|
|
32
|
+
var import_behavioral_ir = require("@suss/behavioral-ir");
|
|
33
|
+
var FRAMEWORK = "apigateway";
|
|
34
|
+
var PROTOCOL = "http";
|
|
35
|
+
function throttleEnforces(throttle) {
|
|
36
|
+
const enforces = (v) => v !== void 0 && v > 0;
|
|
37
|
+
return enforces(throttle.burstLimit) || enforces(throttle.rateLimit);
|
|
38
|
+
}
|
|
39
|
+
function integrationCanTimeOut(integration) {
|
|
40
|
+
return integration.type !== "mock" && integration.type !== "unknown";
|
|
41
|
+
}
|
|
42
|
+
function integrationCanFail(integration) {
|
|
43
|
+
return integration.type !== "mock" && integration.type !== "unknown";
|
|
44
|
+
}
|
|
45
|
+
function buildCorsPreflightSummary(options) {
|
|
46
|
+
const { apiId, path, cors, sourceFile, extraMetadata } = options;
|
|
47
|
+
const ownerKey = `${apiId}:OPTIONS:${path}:cors`;
|
|
48
|
+
const headers = {
|
|
49
|
+
"Access-Control-Allow-Origin": {
|
|
50
|
+
type: "literal",
|
|
51
|
+
value: cors.allowOrigins.join(",")
|
|
52
|
+
},
|
|
53
|
+
"Access-Control-Allow-Methods": {
|
|
54
|
+
type: "literal",
|
|
55
|
+
value: cors.allowMethods.join(",")
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
if (cors.allowHeaders !== void 0 && cors.allowHeaders.length > 0) {
|
|
59
|
+
headers["Access-Control-Allow-Headers"] = {
|
|
60
|
+
type: "literal",
|
|
61
|
+
value: cors.allowHeaders.join(",")
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (cors.exposeHeaders !== void 0 && cors.exposeHeaders.length > 0) {
|
|
65
|
+
headers["Access-Control-Expose-Headers"] = {
|
|
66
|
+
type: "literal",
|
|
67
|
+
value: cors.exposeHeaders.join(",")
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (cors.allowCredentials === true) {
|
|
71
|
+
headers["Access-Control-Allow-Credentials"] = {
|
|
72
|
+
type: "literal",
|
|
73
|
+
value: "true"
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (cors.maxAge !== void 0) {
|
|
77
|
+
headers["Access-Control-Max-Age"] = {
|
|
78
|
+
type: "literal",
|
|
79
|
+
value: String(cors.maxAge)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const transition = {
|
|
83
|
+
id: `${ownerKey}:platform:204`,
|
|
84
|
+
conditions: [
|
|
85
|
+
{
|
|
86
|
+
type: "opaque",
|
|
87
|
+
sourceText: "aws:apigateway:cors-preflight",
|
|
88
|
+
reason: "externalFunction"
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
output: {
|
|
92
|
+
type: "response",
|
|
93
|
+
statusCode: { type: "literal", value: 204 },
|
|
94
|
+
body: null,
|
|
95
|
+
headers
|
|
96
|
+
},
|
|
97
|
+
effects: [],
|
|
98
|
+
location: { start: 0, end: 0 },
|
|
99
|
+
isDefault: false,
|
|
100
|
+
confidence: { source: "derived", level: "high" },
|
|
101
|
+
metadata: {
|
|
102
|
+
source: "aws::apigateway::platform",
|
|
103
|
+
platform: "apiGateway",
|
|
104
|
+
causes: ["cors-preflight"],
|
|
105
|
+
...cors.configRef !== void 0 ? { configRefs: [cors.configRef] } : {}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
kind: "handler",
|
|
110
|
+
location: {
|
|
111
|
+
file: `${sourceFile}:${ownerKey}`,
|
|
112
|
+
range: { start: 0, end: 0 },
|
|
113
|
+
exportName: null
|
|
114
|
+
},
|
|
115
|
+
identity: {
|
|
116
|
+
name: ownerKey,
|
|
117
|
+
exportPath: null,
|
|
118
|
+
boundaryBinding: (0, import_behavioral_ir.restBinding)({
|
|
119
|
+
transport: PROTOCOL,
|
|
120
|
+
method: "OPTIONS",
|
|
121
|
+
path,
|
|
122
|
+
recognition: FRAMEWORK
|
|
123
|
+
})
|
|
124
|
+
},
|
|
125
|
+
inputs: [],
|
|
126
|
+
transitions: [transition],
|
|
127
|
+
gaps: [],
|
|
128
|
+
confidence: { source: "derived", level: "high" },
|
|
129
|
+
metadata: {
|
|
130
|
+
apiId,
|
|
131
|
+
synthetic: "cors-preflight",
|
|
132
|
+
...extraMetadata ?? {}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/transitions.ts
|
|
138
|
+
function makeContribution(cause, configRef) {
|
|
139
|
+
if (configRef === void 0) {
|
|
140
|
+
return { cause };
|
|
141
|
+
}
|
|
142
|
+
return { cause, configRef };
|
|
143
|
+
}
|
|
144
|
+
function handlerTransition(args) {
|
|
145
|
+
return {
|
|
146
|
+
id: `${args.ownerKey}:integration:${args.statusCode}`,
|
|
147
|
+
conditions: [],
|
|
148
|
+
output: {
|
|
149
|
+
type: "response",
|
|
150
|
+
statusCode: { type: "literal", value: args.statusCode },
|
|
151
|
+
body: null,
|
|
152
|
+
headers: {}
|
|
153
|
+
},
|
|
154
|
+
effects: [],
|
|
155
|
+
location: { start: 0, end: 0 },
|
|
156
|
+
isDefault: false,
|
|
157
|
+
confidence: { source: "derived", level: "high" },
|
|
158
|
+
metadata: {
|
|
159
|
+
source: args.source,
|
|
160
|
+
...args.configRef !== void 0 ? { configRef: args.configRef } : {}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function platformTransition(args) {
|
|
165
|
+
if (args.contributions.length === 0) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const causes = unique(args.contributions.map((c) => c.cause));
|
|
169
|
+
const refs = args.contributions.map((c) => c.configRef).filter((r) => r !== void 0);
|
|
170
|
+
const predicate = {
|
|
171
|
+
type: "opaque",
|
|
172
|
+
sourceText: `aws:apigateway:status-${args.statusCode}`,
|
|
173
|
+
reason: "externalFunction"
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
id: `${args.ownerKey}:platform:${args.statusCode}`,
|
|
177
|
+
conditions: [predicate],
|
|
178
|
+
output: {
|
|
179
|
+
type: "response",
|
|
180
|
+
statusCode: { type: "literal", value: args.statusCode },
|
|
181
|
+
body: null,
|
|
182
|
+
headers: {}
|
|
183
|
+
},
|
|
184
|
+
effects: [],
|
|
185
|
+
location: { start: 0, end: 0 },
|
|
186
|
+
isDefault: false,
|
|
187
|
+
confidence: { source: "derived", level: "high" },
|
|
188
|
+
metadata: {
|
|
189
|
+
source: "aws::apigateway::platform",
|
|
190
|
+
platform: "apiGateway",
|
|
191
|
+
causes,
|
|
192
|
+
...refs.length > 0 ? { configRefs: refs } : {}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function unique(values) {
|
|
197
|
+
return Array.from(new Set(values));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/http.ts
|
|
201
|
+
function httpApiToSummaries(config) {
|
|
202
|
+
const sourceFile = config.source ?? `aws-apigateway:${config.id}`;
|
|
203
|
+
const summaries = [];
|
|
204
|
+
for (const route of config.routes) {
|
|
205
|
+
const parsed = parseRouteKey(route.routeKey);
|
|
206
|
+
if (parsed === null) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
summaries.push(buildRouteSummary(route, parsed, config, sourceFile));
|
|
210
|
+
}
|
|
211
|
+
if (config.cors !== void 0) {
|
|
212
|
+
for (const path of uniquePaths(config.routes)) {
|
|
213
|
+
summaries.push(
|
|
214
|
+
buildCorsPreflightSummary({
|
|
215
|
+
apiId: config.id,
|
|
216
|
+
path,
|
|
217
|
+
cors: config.cors,
|
|
218
|
+
sourceFile,
|
|
219
|
+
extraMetadata: { apiVersion: "v2" }
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return summaries;
|
|
225
|
+
}
|
|
226
|
+
function parseRouteKey(routeKey) {
|
|
227
|
+
const trimmed = routeKey.trim();
|
|
228
|
+
if (trimmed === "" || trimmed === "$default") {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const space = trimmed.indexOf(" ");
|
|
232
|
+
if (space < 0) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const method = trimmed.slice(0, space).toUpperCase();
|
|
236
|
+
const path = trimmed.slice(space + 1).trim();
|
|
237
|
+
if (method === "" || path === "") {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
return { method, path };
|
|
241
|
+
}
|
|
242
|
+
function buildRouteSummary(route, parsed, api, sourceFile) {
|
|
243
|
+
const ownerKey = route.name ?? `${api.id}:${parsed.method}:${parsed.path}`;
|
|
244
|
+
const transitions = [];
|
|
245
|
+
for (const code of route.integration.statusCodes) {
|
|
246
|
+
transitions.push(
|
|
247
|
+
handlerTransition({
|
|
248
|
+
ownerKey,
|
|
249
|
+
statusCode: code,
|
|
250
|
+
source: `aws::apigateway::integration.${route.integration.type}`,
|
|
251
|
+
configRef: route.integration.configRef
|
|
252
|
+
})
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
const platformByStatus = collectPlatformContributions(route, api);
|
|
256
|
+
for (const [status, contributions] of platformByStatus) {
|
|
257
|
+
const transition = platformTransition({
|
|
258
|
+
ownerKey,
|
|
259
|
+
statusCode: status,
|
|
260
|
+
contributions
|
|
261
|
+
});
|
|
262
|
+
if (transition !== null) {
|
|
263
|
+
transitions.push(transition);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (transitions.length === 0) {
|
|
267
|
+
transitions.push({
|
|
268
|
+
id: `${ownerKey}:integration:default`,
|
|
269
|
+
conditions: [],
|
|
270
|
+
output: {
|
|
271
|
+
type: "response",
|
|
272
|
+
statusCode: null,
|
|
273
|
+
body: null,
|
|
274
|
+
headers: {}
|
|
275
|
+
},
|
|
276
|
+
effects: [],
|
|
277
|
+
location: { start: 0, end: 0 },
|
|
278
|
+
isDefault: true,
|
|
279
|
+
confidence: { source: "derived", level: "low" },
|
|
280
|
+
metadata: {
|
|
281
|
+
source: `aws::apigateway::integration.${route.integration.type}`
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
kind: "handler",
|
|
287
|
+
location: {
|
|
288
|
+
file: `${sourceFile}:${ownerKey}`,
|
|
289
|
+
range: { start: 0, end: 0 },
|
|
290
|
+
exportName: null
|
|
291
|
+
},
|
|
292
|
+
identity: {
|
|
293
|
+
name: ownerKey,
|
|
294
|
+
exportPath: null,
|
|
295
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
296
|
+
transport: PROTOCOL,
|
|
297
|
+
method: parsed.method,
|
|
298
|
+
path: parsed.path,
|
|
299
|
+
recognition: FRAMEWORK
|
|
300
|
+
})
|
|
301
|
+
},
|
|
302
|
+
inputs: [],
|
|
303
|
+
transitions,
|
|
304
|
+
gaps: [],
|
|
305
|
+
confidence: { source: "derived", level: "high" },
|
|
306
|
+
metadata: {
|
|
307
|
+
apiId: api.id,
|
|
308
|
+
apiVersion: "v2",
|
|
309
|
+
integrationType: route.integration.type,
|
|
310
|
+
http: {
|
|
311
|
+
declaredContract: {
|
|
312
|
+
framework: FRAMEWORK,
|
|
313
|
+
provenance: "independent",
|
|
314
|
+
responses: route.integration.statusCodes.map((statusCode) => ({
|
|
315
|
+
statusCode
|
|
316
|
+
}))
|
|
317
|
+
},
|
|
318
|
+
// Additive pointer to the code that implements this route (SAM
|
|
319
|
+
// Lambda proxy Handler), so a checker can correlate the declared
|
|
320
|
+
// route with the extracted handler summary carrying the same
|
|
321
|
+
// REST binding.
|
|
322
|
+
...route.implementingHandler !== void 0 ? { implementingHandler: route.implementingHandler } : {}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function collectPlatformContributions(route, api) {
|
|
328
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
329
|
+
const add = (status, contribution) => {
|
|
330
|
+
const existing = buckets.get(status);
|
|
331
|
+
if (existing === void 0) {
|
|
332
|
+
buckets.set(status, [contribution]);
|
|
333
|
+
} else {
|
|
334
|
+
existing.push(contribution);
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
const authorizer = resolveAuthorizer(route, api);
|
|
338
|
+
if (authorizer !== null) {
|
|
339
|
+
if (authorizer.identitySourceRequired !== false) {
|
|
340
|
+
add(401, makeContribution("authorization", authorizer.configRef));
|
|
341
|
+
}
|
|
342
|
+
add(403, makeContribution("authorization", authorizer.configRef));
|
|
343
|
+
}
|
|
344
|
+
const throttle = resolveThrottle(route, api);
|
|
345
|
+
if (throttle !== null && throttleEnforces(throttle)) {
|
|
346
|
+
add(429, makeContribution("throttle", throttle.configRef));
|
|
347
|
+
}
|
|
348
|
+
if (integrationCanTimeOut(route.integration)) {
|
|
349
|
+
add(
|
|
350
|
+
504,
|
|
351
|
+
makeContribution("integration-timeout", route.integration.configRef)
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
if (integrationCanFail(route.integration)) {
|
|
355
|
+
add(
|
|
356
|
+
502,
|
|
357
|
+
makeContribution("integration-failure", route.integration.configRef)
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return buckets;
|
|
361
|
+
}
|
|
362
|
+
function resolveAuthorizer(route, api) {
|
|
363
|
+
if (route.authorizer === null) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
if (route.authorizer !== void 0) {
|
|
367
|
+
return route.authorizer;
|
|
368
|
+
}
|
|
369
|
+
return api.defaultAuthorizer ?? null;
|
|
370
|
+
}
|
|
371
|
+
function resolveThrottle(route, api) {
|
|
372
|
+
if (route.throttle !== void 0) {
|
|
373
|
+
return route.throttle;
|
|
374
|
+
}
|
|
375
|
+
return api.defaultThrottle ?? null;
|
|
376
|
+
}
|
|
377
|
+
function uniquePaths(routes) {
|
|
378
|
+
const seen = /* @__PURE__ */ new Set();
|
|
379
|
+
const out = [];
|
|
380
|
+
for (const r of routes) {
|
|
381
|
+
const parsed = parseRouteKey(r.routeKey);
|
|
382
|
+
if (parsed === null || seen.has(parsed.path)) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
seen.add(parsed.path);
|
|
386
|
+
out.push(parsed.path);
|
|
387
|
+
}
|
|
388
|
+
return out;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/rest.ts
|
|
392
|
+
var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
393
|
+
function restApiToSummaries(config) {
|
|
394
|
+
const sourceFile = config.source ?? `aws-apigateway:${config.id}`;
|
|
395
|
+
const summaries = [];
|
|
396
|
+
for (const endpoint of config.endpoints) {
|
|
397
|
+
summaries.push(buildEndpointSummary(endpoint, config, sourceFile));
|
|
398
|
+
}
|
|
399
|
+
if (config.cors !== void 0) {
|
|
400
|
+
for (const endpoint of dedupeByPath(config.endpoints)) {
|
|
401
|
+
summaries.push(
|
|
402
|
+
buildCorsPreflightSummary({
|
|
403
|
+
apiId: config.id,
|
|
404
|
+
path: endpoint.path,
|
|
405
|
+
cors: config.cors,
|
|
406
|
+
sourceFile
|
|
407
|
+
})
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return summaries;
|
|
412
|
+
}
|
|
413
|
+
function buildEndpointSummary(endpoint, api, sourceFile) {
|
|
414
|
+
const method = endpoint.method.toUpperCase();
|
|
415
|
+
const ownerKey = endpoint.name ?? `${api.id}:${method}:${endpoint.path}`;
|
|
416
|
+
const transitions = [];
|
|
417
|
+
for (const code of endpoint.integration.statusCodes) {
|
|
418
|
+
transitions.push(
|
|
419
|
+
handlerTransition({
|
|
420
|
+
ownerKey,
|
|
421
|
+
statusCode: code,
|
|
422
|
+
source: `aws::apigateway::integration.${endpoint.integration.type}`,
|
|
423
|
+
configRef: endpoint.integration.configRef
|
|
424
|
+
})
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
const platformByStatus = collectPlatformContributions2(endpoint, api);
|
|
428
|
+
for (const [status, contributions] of platformByStatus) {
|
|
429
|
+
const transition = platformTransition({
|
|
430
|
+
ownerKey,
|
|
431
|
+
statusCode: status,
|
|
432
|
+
contributions
|
|
433
|
+
});
|
|
434
|
+
if (transition !== null) {
|
|
435
|
+
transitions.push(transition);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (transitions.length === 0) {
|
|
439
|
+
transitions.push({
|
|
440
|
+
id: `${ownerKey}:integration:default`,
|
|
441
|
+
conditions: [],
|
|
442
|
+
output: {
|
|
443
|
+
type: "response",
|
|
444
|
+
statusCode: null,
|
|
445
|
+
body: null,
|
|
446
|
+
headers: {}
|
|
447
|
+
},
|
|
448
|
+
effects: [],
|
|
449
|
+
location: { start: 0, end: 0 },
|
|
450
|
+
isDefault: true,
|
|
451
|
+
confidence: { source: "derived", level: "low" },
|
|
452
|
+
metadata: {
|
|
453
|
+
source: `aws::apigateway::integration.${endpoint.integration.type}`
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
kind: "handler",
|
|
459
|
+
location: {
|
|
460
|
+
file: `${sourceFile}:${ownerKey}`,
|
|
461
|
+
range: { start: 0, end: 0 },
|
|
462
|
+
exportName: null
|
|
463
|
+
},
|
|
464
|
+
identity: {
|
|
465
|
+
name: ownerKey,
|
|
466
|
+
exportPath: null,
|
|
467
|
+
boundaryBinding: (0, import_behavioral_ir3.restBinding)({
|
|
468
|
+
transport: PROTOCOL,
|
|
469
|
+
method,
|
|
470
|
+
path: endpoint.path,
|
|
471
|
+
recognition: FRAMEWORK
|
|
472
|
+
})
|
|
473
|
+
},
|
|
474
|
+
inputs: [],
|
|
475
|
+
transitions,
|
|
476
|
+
gaps: [],
|
|
477
|
+
confidence: { source: "derived", level: "high" },
|
|
478
|
+
metadata: {
|
|
479
|
+
apiId: api.id,
|
|
480
|
+
integrationType: endpoint.integration.type,
|
|
481
|
+
http: {
|
|
482
|
+
// The integration's declared status codes (from MethodResponses
|
|
483
|
+
// in the CFN template) are the declared contract here. Platform-
|
|
484
|
+
// injected transitions (authorizer 401/403, throttle 429, etc.)
|
|
485
|
+
// come from SEPARATE config fields and so are independent from
|
|
486
|
+
// this contract — contract-consistency comparison is meaningful
|
|
487
|
+
// and will surface template-internal inconsistencies.
|
|
488
|
+
declaredContract: {
|
|
489
|
+
framework: FRAMEWORK,
|
|
490
|
+
provenance: "independent",
|
|
491
|
+
responses: endpoint.integration.statusCodes.map((statusCode) => ({
|
|
492
|
+
statusCode
|
|
493
|
+
}))
|
|
494
|
+
},
|
|
495
|
+
// Additive pointer to the code that implements this endpoint
|
|
496
|
+
// (SAM Lambda proxy Handler), so a checker can correlate the
|
|
497
|
+
// declared route with the extracted handler summary carrying the
|
|
498
|
+
// same REST binding.
|
|
499
|
+
...endpoint.implementingHandler !== void 0 ? { implementingHandler: endpoint.implementingHandler } : {}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function collectPlatformContributions2(endpoint, api) {
|
|
505
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
506
|
+
const add = (status, contribution) => {
|
|
507
|
+
const existing = buckets.get(status);
|
|
508
|
+
if (existing === void 0) {
|
|
509
|
+
buckets.set(status, [contribution]);
|
|
510
|
+
} else {
|
|
511
|
+
existing.push(contribution);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
const authorizer = resolveAuthorizer2(endpoint, api);
|
|
515
|
+
if (authorizer !== null) {
|
|
516
|
+
if (authorizer.identitySourceRequired !== false) {
|
|
517
|
+
add(401, makeContribution("authorization", authorizer.configRef));
|
|
518
|
+
}
|
|
519
|
+
add(403, makeContribution("authorization", authorizer.configRef));
|
|
520
|
+
}
|
|
521
|
+
if (endpoint.apiKeyRequired === true) {
|
|
522
|
+
add(403, makeContribution("api-key", endpoint.configRef));
|
|
523
|
+
}
|
|
524
|
+
if (endpoint.requestValidation !== void 0) {
|
|
525
|
+
const v = endpoint.requestValidation;
|
|
526
|
+
if (v.body === true || v.params === true || v.headers === true) {
|
|
527
|
+
add(
|
|
528
|
+
400,
|
|
529
|
+
makeContribution(
|
|
530
|
+
"request-validation",
|
|
531
|
+
v.configRef ?? endpoint.configRef
|
|
532
|
+
)
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
const throttle = resolveThrottle2(endpoint, api);
|
|
537
|
+
if (throttle !== null && throttleEnforces(throttle)) {
|
|
538
|
+
add(429, makeContribution("throttle", throttle.configRef));
|
|
539
|
+
}
|
|
540
|
+
if (integrationCanTimeOut(endpoint.integration)) {
|
|
541
|
+
add(
|
|
542
|
+
504,
|
|
543
|
+
makeContribution("integration-timeout", endpoint.integration.configRef)
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
if (integrationCanFail(endpoint.integration)) {
|
|
547
|
+
add(
|
|
548
|
+
502,
|
|
549
|
+
makeContribution("integration-failure", endpoint.integration.configRef)
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
return buckets;
|
|
553
|
+
}
|
|
554
|
+
function resolveAuthorizer2(endpoint, api) {
|
|
555
|
+
if (endpoint.authorizer === null) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
if (endpoint.authorizer !== void 0) {
|
|
559
|
+
return endpoint.authorizer;
|
|
560
|
+
}
|
|
561
|
+
return api.defaultAuthorizer ?? null;
|
|
562
|
+
}
|
|
563
|
+
function resolveThrottle2(endpoint, api) {
|
|
564
|
+
if (endpoint.throttle !== void 0) {
|
|
565
|
+
return endpoint.throttle;
|
|
566
|
+
}
|
|
567
|
+
return api.defaultThrottle ?? null;
|
|
568
|
+
}
|
|
569
|
+
function dedupeByPath(endpoints) {
|
|
570
|
+
const seen = /* @__PURE__ */ new Set();
|
|
571
|
+
const out = [];
|
|
572
|
+
for (const e of endpoints) {
|
|
573
|
+
if (seen.has(e.path)) {
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
seen.add(e.path);
|
|
577
|
+
out.push(e);
|
|
578
|
+
}
|
|
579
|
+
return out;
|
|
580
|
+
}
|
|
581
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
582
|
+
0 && (module.exports = {
|
|
583
|
+
httpApiToSummaries,
|
|
584
|
+
restApiToSummaries
|
|
585
|
+
});
|