@forklaunch/core 3.2.1 → 3.3.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/bin/gateway-mock/routes/payments-context.mjs +260 -0
- package/bin/gateway-mock/routes/payments.mjs +47 -1
- package/lib/http/bindRuntimeAuth.d.ts +53 -0
- package/lib/http/bindRuntimeAuth.d.ts.map +1 -0
- package/lib/http/bindRuntimeAuth.test.d.ts +2 -0
- package/lib/http/bindRuntimeAuth.test.d.ts.map +1 -0
- package/lib/http/index.d.ts +2 -0
- package/lib/http/index.d.ts.map +1 -1
- package/lib/http/index.js +284 -76
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +282 -76
- package/lib/http/index.mjs.map +1 -1
- package/lib/http/mcpGenerator/mcpGenerator.d.ts.map +1 -1
- package/lib/http/middleware/internal/validationDiagnostic.d.ts +3 -0
- package/lib/http/middleware/internal/validationDiagnostic.d.ts.map +1 -0
- package/lib/http/middleware/request/auth.middleware.d.ts +0 -11
- package/lib/http/middleware/request/auth.middleware.d.ts.map +1 -1
- package/lib/http/middleware/request/parse.middleware.d.ts.map +1 -1
- package/lib/http/middleware/response/enrichExpressLikeSend.middleware.d.ts.map +1 -1
- package/lib/http/middleware/response/parse.middleware.d.ts.map +1 -1
- package/lib/http/openApiV3Generator/openApiV3Generator.d.ts.map +1 -1
- package/lib/http/paymentsClient.d.ts.map +1 -1
- package/lib/http/registerDelegatedSurface.d.ts +28 -0
- package/lib/http/registerDelegatedSurface.d.ts.map +1 -0
- package/lib/http/registerDelegatedSurface.test.d.ts +2 -0
- package/lib/http/registerDelegatedSurface.test.d.ts.map +1 -0
- package/lib/http/router/discriminateBody.d.ts +2 -1
- package/lib/http/router/discriminateBody.d.ts.map +1 -1
- package/lib/http/router/expressLikeRouter.d.ts.map +1 -1
- package/lib/persistence/compliantField.d.ts.map +1 -1
- package/lib/persistence/index.js +1 -6
- package/lib/persistence/index.js.map +1 -1
- package/lib/persistence/index.mjs +1 -6
- package/lib/persistence/index.mjs.map +1 -1
- package/lib/ws/asyncApiV3Generator/asyncApiV3Generator.d.ts.map +1 -1
- package/lib/ws/index.js +94 -8
- package/lib/ws/index.js.map +1 -1
- package/lib/ws/index.mjs +94 -8
- package/lib/ws/index.mjs.map +1 -1
- package/package.json +4 -4
package/lib/http/index.js
CHANGED
|
@@ -66,6 +66,7 @@ __export(http_exports, {
|
|
|
66
66
|
auditComplianceAccess: () => auditComplianceAccess,
|
|
67
67
|
auditEnabled: () => auditEnabled,
|
|
68
68
|
auditEventType: () => auditEventType,
|
|
69
|
+
bindRuntimeAuth: () => bindRuntimeAuth,
|
|
69
70
|
createContext: () => createContext,
|
|
70
71
|
createEmailClient: () => createEmailClient,
|
|
71
72
|
createHmacToken: () => createHmacToken,
|
|
@@ -119,6 +120,7 @@ __export(http_exports, {
|
|
|
119
120
|
put: () => put,
|
|
120
121
|
recordMetric: () => recordMetric,
|
|
121
122
|
recordRequestAudit: () => recordRequestAudit,
|
|
123
|
+
registerDelegatedSurface: () => registerDelegatedSurface,
|
|
122
124
|
resetProcessHandlersForTesting: () => resetProcessHandlersForTesting,
|
|
123
125
|
signPlatformEvent: () => signPlatformEvent,
|
|
124
126
|
smsSegments: () => smsSegments,
|
|
@@ -134,6 +136,68 @@ __export(http_exports, {
|
|
|
134
136
|
});
|
|
135
137
|
module.exports = __toCommonJS(http_exports);
|
|
136
138
|
|
|
139
|
+
// src/http/bindRuntimeAuth.ts
|
|
140
|
+
function bindRuntimeAuth(details, binding) {
|
|
141
|
+
const policy = { ...details.auth };
|
|
142
|
+
const keys = Object.keys(binding);
|
|
143
|
+
const credentials = { ...binding };
|
|
144
|
+
const invalid = () => {
|
|
145
|
+
throw new Error("Invalid runtime authentication binding");
|
|
146
|
+
};
|
|
147
|
+
const allowedPolicy = policy.scheme === "jwt" ? [
|
|
148
|
+
"scheme",
|
|
149
|
+
"headerName",
|
|
150
|
+
"tokenPrefix",
|
|
151
|
+
"sessionSchema",
|
|
152
|
+
"allowedRoles",
|
|
153
|
+
"allowedPermissions"
|
|
154
|
+
] : ["scheme", "headerName", "tokenPrefix"];
|
|
155
|
+
if (Object.keys(policy).some((key) => !allowedPolicy.includes(key)))
|
|
156
|
+
invalid();
|
|
157
|
+
for (const key of ["headerName", "tokenPrefix"]) {
|
|
158
|
+
if (policy[key] !== void 0 && (typeof policy[key] !== "string" || !policy[key]))
|
|
159
|
+
invalid();
|
|
160
|
+
}
|
|
161
|
+
if (policy.scheme === "jwt" && policy.allowedRoles === void 0 && policy.allowedPermissions === void 0)
|
|
162
|
+
invalid();
|
|
163
|
+
let authentication;
|
|
164
|
+
if (policy.scheme === "jwt") {
|
|
165
|
+
if (keys.some(
|
|
166
|
+
(key) => !["jwksPublicKeyUrl", "signatureKey", "decodeResource"].includes(key)
|
|
167
|
+
))
|
|
168
|
+
invalid();
|
|
169
|
+
const keyFields = keys.filter((key) => key !== "decodeResource");
|
|
170
|
+
if (keyFields.length !== 1 || typeof credentials[keyFields[0]] !== "string" || !credentials[keyFields[0]])
|
|
171
|
+
invalid();
|
|
172
|
+
const decodeResource = credentials.decodeResource;
|
|
173
|
+
if (decodeResource !== void 0 && typeof decodeResource !== "function")
|
|
174
|
+
invalid();
|
|
175
|
+
delete credentials.decodeResource;
|
|
176
|
+
authentication = {
|
|
177
|
+
jwt: credentials,
|
|
178
|
+
...decodeResource === void 0 ? {} : { decodeResource }
|
|
179
|
+
};
|
|
180
|
+
} else if (policy.scheme === "hmac") {
|
|
181
|
+
if (keys.length !== 1 || keys[0] !== "secretKeys" || !credentials.secretKeys || typeof credentials.secretKeys !== "object" || Array.isArray(credentials.secretKeys) || Object.keys(credentials.secretKeys).length === 0 || Object.values(credentials.secretKeys).some(
|
|
182
|
+
(key) => typeof key !== "string" || !key
|
|
183
|
+
))
|
|
184
|
+
invalid();
|
|
185
|
+
authentication = { hmac: credentials };
|
|
186
|
+
} else {
|
|
187
|
+
return invalid();
|
|
188
|
+
}
|
|
189
|
+
delete policy.scheme;
|
|
190
|
+
for (const key of ["allowedRoles", "allowedPermissions"]) {
|
|
191
|
+
if (policy[key] !== void 0) {
|
|
192
|
+
const values = policy[key];
|
|
193
|
+
if (!Array.isArray(values) || values.some((value) => typeof value !== "string"))
|
|
194
|
+
invalid();
|
|
195
|
+
policy[key] = new Set(values);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { ...details, auth: { ...policy, ...authentication } };
|
|
199
|
+
}
|
|
200
|
+
|
|
137
201
|
// src/http/middleware/request/cors.middleware.ts
|
|
138
202
|
var import_cors = __toESM(require("cors"));
|
|
139
203
|
function cors(corsOptions) {
|
|
@@ -594,7 +658,7 @@ function createContext(schemaValidator) {
|
|
|
594
658
|
}
|
|
595
659
|
|
|
596
660
|
// src/http/router/discriminateBody.ts
|
|
597
|
-
function discriminateBody(schemaValidator, body) {
|
|
661
|
+
function discriminateBody(schemaValidator, body, inputProjection) {
|
|
598
662
|
if (body == null) {
|
|
599
663
|
return void 0;
|
|
600
664
|
}
|
|
@@ -644,7 +708,7 @@ function discriminateBody(schemaValidator, body) {
|
|
|
644
708
|
parserType: "text",
|
|
645
709
|
schema: maybeTypedBody
|
|
646
710
|
};
|
|
647
|
-
} else if (schemaValidator.openapi(maybeTypedBody).format === "binary") {
|
|
711
|
+
} else if ((inputProjection ?? schemaValidator.openapi(maybeTypedBody)).format === "binary") {
|
|
648
712
|
return {
|
|
649
713
|
contentType: "application/octet-stream",
|
|
650
714
|
parserType: "file",
|
|
@@ -1074,15 +1138,23 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
1074
1138
|
if (!parsedKeyId || !parsedTimestamp || !parsedNonce || !parsedSignature) {
|
|
1075
1139
|
return invalidAuthorizationTokenFormat;
|
|
1076
1140
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1141
|
+
let verificationResult = false;
|
|
1142
|
+
const signedPaths = hmacSignedPaths(req);
|
|
1143
|
+
for (const path of signedPaths) {
|
|
1144
|
+
verificationResult = Boolean(await auth.verificationFunction({
|
|
1145
|
+
method: req?.method ?? "",
|
|
1146
|
+
path,
|
|
1147
|
+
body: req?._rawBody ?? req?.body,
|
|
1148
|
+
timestamp: new Date(parsedTimestamp),
|
|
1149
|
+
nonce: parsedNonce,
|
|
1150
|
+
signature: parsedSignature,
|
|
1151
|
+
secretKey: collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
|
|
1152
|
+
}));
|
|
1153
|
+
if (verificationResult) {
|
|
1154
|
+
if (path !== signedPaths[0]) warnMountRelativeHmacPath();
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1086
1158
|
if (!verificationResult) {
|
|
1087
1159
|
return invalidAuthorizationSignature;
|
|
1088
1160
|
}
|
|
@@ -1249,6 +1321,25 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
1249
1321
|
}
|
|
1250
1322
|
}
|
|
1251
1323
|
}
|
|
1324
|
+
function acceptMountRelativeHmacPaths() {
|
|
1325
|
+
const value = typeof process === "undefined" ? void 0 : process.env?.HMAC_ACCEPT_MOUNT_RELATIVE_PATHS;
|
|
1326
|
+
return value == null || !["false", "0"].includes(value.trim().toLowerCase());
|
|
1327
|
+
}
|
|
1328
|
+
var warnedMountRelativeHmacPath = false;
|
|
1329
|
+
function warnMountRelativeHmacPath() {
|
|
1330
|
+
if (warnedMountRelativeHmacPath) return;
|
|
1331
|
+
warnedMountRelativeHmacPath = true;
|
|
1332
|
+
console.warn(
|
|
1333
|
+
"Accepted an HMAC signature over the router-relative path. Sign the full request path instead; set HMAC_ACCEPT_MOUNT_RELATIVE_PATHS=false to reject the deprecated form."
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
function hmacSignedPaths(req) {
|
|
1337
|
+
const relative = req?.path ?? "";
|
|
1338
|
+
const wire = (req?.originalUrl ?? req?.url ?? relative).split("?")[0] || relative;
|
|
1339
|
+
const paths = [wire];
|
|
1340
|
+
if (relative !== wire && acceptMountRelativeHmacPaths()) paths.push(relative);
|
|
1341
|
+
return paths;
|
|
1342
|
+
}
|
|
1252
1343
|
async function parseRequestAuth(req, res, next) {
|
|
1253
1344
|
const access = req.contractDetails.access;
|
|
1254
1345
|
if (access === "public") {
|
|
@@ -1482,6 +1573,21 @@ function isRequestShape(maybeResponseShape) {
|
|
|
1482
1573
|
return maybeResponseShape != null && ("body" in maybeResponseShape || "query" in maybeResponseShape || "params" in maybeResponseShape || "headers" in maybeResponseShape);
|
|
1483
1574
|
}
|
|
1484
1575
|
|
|
1576
|
+
// src/http/middleware/internal/validationDiagnostic.ts
|
|
1577
|
+
var sendingDiagnostics = /* @__PURE__ */ new WeakSet();
|
|
1578
|
+
function isValidationDiagnostic(response) {
|
|
1579
|
+
return sendingDiagnostics.has(response);
|
|
1580
|
+
}
|
|
1581
|
+
function sendValidationDiagnostic(response, send) {
|
|
1582
|
+
const alreadySending = sendingDiagnostics.has(response);
|
|
1583
|
+
sendingDiagnostics.add(response);
|
|
1584
|
+
try {
|
|
1585
|
+
return send();
|
|
1586
|
+
} finally {
|
|
1587
|
+
if (!alreadySending) sendingDiagnostics.delete(response);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1485
1591
|
// src/http/middleware/request/parse.middleware.ts
|
|
1486
1592
|
function parse(req, res, next) {
|
|
1487
1593
|
const globalOptions = req._globalOptions?.();
|
|
@@ -1563,14 +1669,13 @@ function parse(req, res, next) {
|
|
|
1563
1669
|
default:
|
|
1564
1670
|
case void 0:
|
|
1565
1671
|
case "error":
|
|
1566
|
-
res.type("
|
|
1672
|
+
res.type("text/plain");
|
|
1567
1673
|
res.status(400);
|
|
1568
1674
|
if (hasSend(res)) {
|
|
1569
|
-
|
|
1570
|
-
`${collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")}
|
|
1675
|
+
const diagnostic = `${collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")}
|
|
1571
1676
|
|
|
1572
|
-
Correlation id: ${req.context.correlationId ?? "No correlation ID"}
|
|
1573
|
-
);
|
|
1677
|
+
Correlation id: ${req.context.correlationId ?? "No correlation ID"}`;
|
|
1678
|
+
sendValidationDiagnostic(res, () => res.send(diagnostic));
|
|
1574
1679
|
} else {
|
|
1575
1680
|
next?.(new Error("Request is not sendable."));
|
|
1576
1681
|
}
|
|
@@ -1979,13 +2084,25 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
1979
2084
|
span: void 0
|
|
1980
2085
|
},
|
|
1981
2086
|
_rawBody: void 0,
|
|
1982
|
-
_parsedVersions: void 0
|
|
2087
|
+
_parsedVersions: void 0,
|
|
2088
|
+
// hyper-express's content parser reads the body through its Request's
|
|
2089
|
+
// body readers; serve the body the call was given.
|
|
2090
|
+
buffer: async () => Buffer.from(
|
|
2091
|
+
typeof req.body === "string" ? req.body : JSON.stringify(req.body)
|
|
2092
|
+
),
|
|
2093
|
+
json: async () => req.body,
|
|
2094
|
+
text: async () => typeof req.body === "string" ? req.body : JSON.stringify(req.body)
|
|
1983
2095
|
};
|
|
1984
2096
|
const res = {
|
|
1985
2097
|
statusCode: 200,
|
|
2098
|
+
// hyper-express's response enrichment reads the status and headers
|
|
2099
|
+
// from these fields, which its own Response keeps.
|
|
2100
|
+
_status_code: 200,
|
|
2101
|
+
_headers: responseHeaders,
|
|
1986
2102
|
status: (code) => {
|
|
1987
2103
|
statusCode = code;
|
|
1988
2104
|
res.statusCode = code;
|
|
2105
|
+
res._status_code = code;
|
|
1989
2106
|
return res;
|
|
1990
2107
|
},
|
|
1991
2108
|
send: (message) => {
|
|
@@ -2005,6 +2122,8 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
2005
2122
|
return res;
|
|
2006
2123
|
},
|
|
2007
2124
|
getHeader: (key) => responseHeaders[key],
|
|
2125
|
+
getHeaders: () => ({ ...responseHeaders }),
|
|
2126
|
+
locals: {},
|
|
2008
2127
|
type: (contentType) => {
|
|
2009
2128
|
responseHeaders["content-type"] = contentType;
|
|
2010
2129
|
return res;
|
|
@@ -2023,31 +2142,59 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
2023
2142
|
version
|
|
2024
2143
|
};
|
|
2025
2144
|
const executeMiddlewares = request?.executeMiddlewares ?? false;
|
|
2145
|
+
const cHandler = controllerHandler;
|
|
2026
2146
|
if (executeMiddlewares && middlewares.length > 0) {
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2147
|
+
const chain = middlewares;
|
|
2148
|
+
await new Promise((resolve, reject) => {
|
|
2149
|
+
let settled = false;
|
|
2150
|
+
let responded = false;
|
|
2151
|
+
let controllerStarted = false;
|
|
2152
|
+
const finish = (error) => {
|
|
2153
|
+
if (settled) return;
|
|
2154
|
+
settled = true;
|
|
2155
|
+
if (error) reject(error);
|
|
2156
|
+
else resolve();
|
|
2157
|
+
};
|
|
2158
|
+
res.on("finish", () => {
|
|
2159
|
+
responded = true;
|
|
2160
|
+
if (!controllerStarted) finish();
|
|
2161
|
+
});
|
|
2162
|
+
const run = async (index) => {
|
|
2163
|
+
try {
|
|
2164
|
+
if (index === chain.length) {
|
|
2165
|
+
controllerStarted = true;
|
|
2166
|
+
await cHandler(req, res, (err) => {
|
|
2167
|
+
if (err) {
|
|
2168
|
+
throw err;
|
|
2169
|
+
}
|
|
2170
|
+
});
|
|
2171
|
+
finish();
|
|
2172
|
+
return;
|
|
2034
2173
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2174
|
+
let calledNext = false;
|
|
2175
|
+
await chain[index](req, res, (err) => {
|
|
2176
|
+
calledNext = true;
|
|
2177
|
+
if (err) {
|
|
2178
|
+
throw err;
|
|
2179
|
+
}
|
|
2180
|
+
return run(index + 1);
|
|
2181
|
+
});
|
|
2182
|
+
if (!calledNext && chain[index].length < 3 && !responded) {
|
|
2183
|
+
await run(index + 1);
|
|
2184
|
+
}
|
|
2185
|
+
} catch (error) {
|
|
2186
|
+
finish(error);
|
|
2041
2187
|
}
|
|
2042
|
-
}
|
|
2043
|
-
|
|
2188
|
+
};
|
|
2189
|
+
void run(0);
|
|
2190
|
+
});
|
|
2191
|
+
} else {
|
|
2192
|
+
await cHandler(req, res, (err) => {
|
|
2193
|
+
if (err) {
|
|
2194
|
+
throw err;
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2044
2197
|
}
|
|
2045
|
-
const cHandler = controllerHandler;
|
|
2046
|
-
await cHandler(req, res, (err) => {
|
|
2047
|
-
if (err) {
|
|
2048
|
-
throw err;
|
|
2049
|
-
}
|
|
2050
|
-
});
|
|
2051
2198
|
return {
|
|
2052
2199
|
code: Number(statusCode),
|
|
2053
2200
|
response: responseMessage,
|
|
@@ -3536,7 +3683,7 @@ function loadStripe() {
|
|
|
3536
3683
|
function stripeGatewayFetch(settings, fetchImpl = fetch) {
|
|
3537
3684
|
const base = new URL(settings.gatewayUrl);
|
|
3538
3685
|
const basePath = base.pathname.replace(/\/+$/, "");
|
|
3539
|
-
|
|
3686
|
+
const signedFetch = async (input, init = {}) => {
|
|
3540
3687
|
const original = new URL(
|
|
3541
3688
|
typeof input === "string" || input instanceof URL ? input : input.url
|
|
3542
3689
|
);
|
|
@@ -3576,6 +3723,13 @@ function stripeGatewayFetch(settings, fetchImpl = fetch) {
|
|
|
3576
3723
|
}
|
|
3577
3724
|
);
|
|
3578
3725
|
};
|
|
3726
|
+
const preconnect = Reflect.get(fetchImpl, "preconnect");
|
|
3727
|
+
if (typeof preconnect === "function") {
|
|
3728
|
+
Object.defineProperty(signedFetch, "preconnect", {
|
|
3729
|
+
value: (_input, options2) => Reflect.apply(preconnect, fetchImpl, [base.origin, options2])
|
|
3730
|
+
});
|
|
3731
|
+
}
|
|
3732
|
+
return signedFetch;
|
|
3579
3733
|
}
|
|
3580
3734
|
function createStripeClient(options2 = {}) {
|
|
3581
3735
|
const StripeClass = options2.Stripe ?? loadStripe();
|
|
@@ -4808,10 +4962,10 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
4808
4962
|
let bodySchema;
|
|
4809
4963
|
let responsesSchemas;
|
|
4810
4964
|
if (route.contractDetails.versions) {
|
|
4811
|
-
const version2 = route.contractDetails.versions[index];
|
|
4965
|
+
const version2 = Object.values(route.contractDetails.versions)[index];
|
|
4966
|
+
responsesSchemas = version2.responses;
|
|
4812
4967
|
if (version2.body && schemaValidator.parse(inputSchema, args).ok) {
|
|
4813
4968
|
bodySchema = version2.body;
|
|
4814
|
-
responsesSchemas = version2.responses;
|
|
4815
4969
|
}
|
|
4816
4970
|
} else {
|
|
4817
4971
|
bodySchema = route.contractDetails.body;
|
|
@@ -4822,7 +4976,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
4822
4976
|
if (discriminatedBody) {
|
|
4823
4977
|
switch (discriminatedBody.parserType) {
|
|
4824
4978
|
case "json": {
|
|
4825
|
-
parsedBody =
|
|
4979
|
+
parsedBody = body === void 0 ? void 0 : JSON.stringify(body);
|
|
4826
4980
|
break;
|
|
4827
4981
|
}
|
|
4828
4982
|
case "text": {
|
|
@@ -4888,11 +5042,11 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
4888
5042
|
).toString();
|
|
4889
5043
|
url += queryString ? `?${queryString}` : "";
|
|
4890
5044
|
}
|
|
4891
|
-
const response = await fetch(
|
|
5045
|
+
const response = await fetch(url, {
|
|
4892
5046
|
method: route.method.toUpperCase(),
|
|
4893
5047
|
headers: {
|
|
4894
5048
|
...headers,
|
|
4895
|
-
...discriminatedBody?.contentType != "multipart/form-data" ? {
|
|
5049
|
+
...discriminatedBody?.contentType != "multipart/form-data" && (contentType ?? discriminatedBody?.contentType) !== void 0 ? {
|
|
4896
5050
|
"Content-Type": contentType ?? discriminatedBody?.contentType
|
|
4897
5051
|
} : {}
|
|
4898
5052
|
},
|
|
@@ -4970,7 +5124,12 @@ function isResponseCompiledSchema(schema) {
|
|
|
4970
5124
|
}
|
|
4971
5125
|
|
|
4972
5126
|
// src/http/middleware/response/parse.middleware.ts
|
|
5127
|
+
var sendingValidationError = /* @__PURE__ */ new WeakSet();
|
|
4973
5128
|
function parse2(req, res, next) {
|
|
5129
|
+
if (sendingValidationError.has(res)) {
|
|
5130
|
+
next?.();
|
|
5131
|
+
return;
|
|
5132
|
+
}
|
|
4974
5133
|
let headers;
|
|
4975
5134
|
let responses;
|
|
4976
5135
|
const globalOptions = req._globalOptions?.();
|
|
@@ -5013,15 +5172,35 @@ function parse2(req, res, next) {
|
|
|
5013
5172
|
responses = responseSchemas.responses;
|
|
5014
5173
|
}
|
|
5015
5174
|
const statusCode = Number(res.statusCode);
|
|
5016
|
-
const
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5175
|
+
const defaultErrorStatus = [400, 401, 404, 403, 500].includes(statusCode);
|
|
5176
|
+
const missingResponseSchema = !defaultErrorStatus && !Object.prototype.hasOwnProperty.call(responses, statusCode);
|
|
5177
|
+
if (missingResponseSchema && collapsedOptions !== "warning") {
|
|
5178
|
+
throw new Error(`Undocumented response status ${statusCode}`);
|
|
5179
|
+
}
|
|
5180
|
+
const declaredResponse = responses?.[statusCode];
|
|
5181
|
+
const defaultErrorResponse = () => {
|
|
5182
|
+
try {
|
|
5183
|
+
return schemaValidator.parse(
|
|
5184
|
+
schemaValidator.union([schemaValidator.string, declaredResponse]),
|
|
5185
|
+
res.bodyData
|
|
5186
|
+
);
|
|
5187
|
+
} catch (error) {
|
|
5188
|
+
if (declaredResponse === void 0) throw error;
|
|
5189
|
+
const declared = schemaValidator.parse(declaredResponse, res.bodyData);
|
|
5190
|
+
if (declared.ok) return declared;
|
|
5191
|
+
const message = schemaValidator.parse(
|
|
5192
|
+
schemaValidator.string,
|
|
5193
|
+
res.bodyData
|
|
5194
|
+
);
|
|
5195
|
+
return message.ok ? message : declared;
|
|
5196
|
+
}
|
|
5197
|
+
};
|
|
5198
|
+
const parsedResponse = missingResponseSchema ? { ok: true } : defaultErrorStatus ? defaultErrorResponse() : schemaValidator.parse(declaredResponse, res.bodyData);
|
|
5020
5199
|
const parsedHeaders = schemaValidator.parse(
|
|
5021
5200
|
headers ?? schemaValidator.unknown,
|
|
5022
5201
|
res.getHeaders()
|
|
5023
5202
|
);
|
|
5024
|
-
const parseErrors = [];
|
|
5203
|
+
const parseErrors = missingResponseSchema ? [`Response: Undocumented response status ${statusCode}`] : [];
|
|
5025
5204
|
if (!parsedHeaders.ok) {
|
|
5026
5205
|
const headerErrors = (0, import_validator3.prettyPrintParseErrors)(parsedHeaders.errors, "Header");
|
|
5027
5206
|
if (headerErrors) {
|
|
@@ -5038,21 +5217,26 @@ function parse2(req, res, next) {
|
|
|
5038
5217
|
}
|
|
5039
5218
|
}
|
|
5040
5219
|
if (parseErrors.length > 0) {
|
|
5041
|
-
switch (
|
|
5220
|
+
switch (collapsedOptions) {
|
|
5042
5221
|
default:
|
|
5043
5222
|
case void 0:
|
|
5044
5223
|
case "error":
|
|
5045
5224
|
res.type("text/plain");
|
|
5046
5225
|
res.status(500);
|
|
5047
5226
|
if (hasSend(res)) {
|
|
5048
|
-
|
|
5049
|
-
|
|
5227
|
+
sendingValidationError.add(res);
|
|
5228
|
+
try {
|
|
5229
|
+
res.send(
|
|
5230
|
+
`Invalid response:
|
|
5050
5231
|
${parseErrors.join(
|
|
5051
|
-
|
|
5052
|
-
|
|
5232
|
+
"\n\n"
|
|
5233
|
+
)}
|
|
5053
5234
|
|
|
5054
5235
|
Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
5055
|
-
|
|
5236
|
+
);
|
|
5237
|
+
} finally {
|
|
5238
|
+
sendingValidationError.delete(res);
|
|
5239
|
+
}
|
|
5056
5240
|
} else {
|
|
5057
5241
|
next?.(new Error("Response is not sendable."));
|
|
5058
5242
|
}
|
|
@@ -5063,8 +5247,6 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
|
5063
5247
|
${parseErrors.join("\n\n")}`
|
|
5064
5248
|
);
|
|
5065
5249
|
break;
|
|
5066
|
-
case "none":
|
|
5067
|
-
break;
|
|
5068
5250
|
}
|
|
5069
5251
|
}
|
|
5070
5252
|
next?.();
|
|
@@ -5106,6 +5288,10 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
|
5106
5288
|
originalSend.call(instance, data);
|
|
5107
5289
|
return;
|
|
5108
5290
|
}
|
|
5291
|
+
if (typeof data === "string" && isValidationDiagnostic(res)) {
|
|
5292
|
+
originalSend.call(instance, data);
|
|
5293
|
+
return;
|
|
5294
|
+
}
|
|
5109
5295
|
let responses;
|
|
5110
5296
|
if (req.contractDetails.responses == null && (req.contractDetails.versions == null || Object.values(req.contractDetails.versions).some(
|
|
5111
5297
|
(version) => version?.responses == null
|
|
@@ -5115,7 +5301,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
|
5115
5301
|
if (req.contractDetails.responses != null) {
|
|
5116
5302
|
responses = req.contractDetails.responses;
|
|
5117
5303
|
} else {
|
|
5118
|
-
responses = req.contractDetails.versions[req.version]
|
|
5304
|
+
responses = req.contractDetails.versions[req.version]?.responses ?? {};
|
|
5119
5305
|
}
|
|
5120
5306
|
}
|
|
5121
5307
|
const responseBodies = discriminateResponseBodies(
|
|
@@ -5337,7 +5523,16 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
|
|
|
5337
5523
|
for (const key in discriminatedResponseBodiesResult) {
|
|
5338
5524
|
coercedResponses[key] = {
|
|
5339
5525
|
description: httpStatusCodes_default[key],
|
|
5340
|
-
|
|
5526
|
+
// Undefined/void represent no response body, not a JSON null payload.
|
|
5527
|
+
// Check the schema kind rather than its OpenAPI projection: null and
|
|
5528
|
+
// nullish also project to null but still admit an actual JSON body.
|
|
5529
|
+
content: schemaValidator.undefined !== void 0 && typedSchemaValidator.isInstanceOf(
|
|
5530
|
+
discriminatedResponseBodiesResult[key].schema,
|
|
5531
|
+
schemaValidator.undefined
|
|
5532
|
+
) || schemaValidator.void !== void 0 && typedSchemaValidator.isInstanceOf(
|
|
5533
|
+
discriminatedResponseBodiesResult[key].schema,
|
|
5534
|
+
schemaValidator.void
|
|
5535
|
+
) ? void 0 : contentResolver(
|
|
5341
5536
|
schemaValidator,
|
|
5342
5537
|
discriminatedResponseBodiesResult[key].schema,
|
|
5343
5538
|
discriminatedResponseBodiesResult[key].contentType
|
|
@@ -5373,15 +5568,21 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
|
|
|
5373
5568
|
operationObject.parameters?.push({
|
|
5374
5569
|
name: key,
|
|
5375
5570
|
in: "path",
|
|
5571
|
+
required: true,
|
|
5376
5572
|
schema: typedSchemaValidator.openapi(params[key])
|
|
5377
5573
|
});
|
|
5378
5574
|
}
|
|
5379
5575
|
}
|
|
5380
|
-
const
|
|
5576
|
+
const adapter = schemaValidator;
|
|
5577
|
+
const bareProjection = body && adapter.isSchema(body) ? adapter.openapiRequestBody?.(body) : void 0;
|
|
5578
|
+
const discriminatedBodyResult = body ? discriminateBody(schemaValidator, body, bareProjection?.schema) : null;
|
|
5381
5579
|
if (discriminatedBodyResult) {
|
|
5580
|
+
const projection = bareProjection ?? adapter.openapiRequestBody?.(discriminatedBodyResult.schema);
|
|
5382
5581
|
operationObject.requestBody = {
|
|
5383
|
-
required: true,
|
|
5384
|
-
content:
|
|
5582
|
+
required: projection?.required ?? true,
|
|
5583
|
+
content: projection ? {
|
|
5584
|
+
[discriminatedBodyResult.contentType]: { schema: projection.schema }
|
|
5585
|
+
} : contentResolver(
|
|
5385
5586
|
schemaValidator,
|
|
5386
5587
|
discriminatedBodyResult.schema,
|
|
5387
5588
|
discriminatedBodyResult.contentType
|
|
@@ -5416,25 +5617,14 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
|
|
|
5416
5617
|
content: contentResolver(schemaValidator, schemaValidator.string)
|
|
5417
5618
|
};
|
|
5418
5619
|
if ("basic" in auth) {
|
|
5419
|
-
operationObject.security = [
|
|
5420
|
-
{
|
|
5421
|
-
basic: Array.from(
|
|
5422
|
-
"allowedPermissions" in auth && auth.allowedPermissions instanceof Set ? auth.allowedPermissions.values() : []
|
|
5423
|
-
)
|
|
5424
|
-
}
|
|
5425
|
-
];
|
|
5620
|
+
operationObject.security = [{ basic: [] }];
|
|
5426
5621
|
securitySchemes["basic"] = {
|
|
5427
5622
|
type: "http",
|
|
5428
5623
|
scheme: "basic"
|
|
5429
5624
|
};
|
|
5430
5625
|
} else if (auth) {
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
[auth.headerName !== "Authorization" ? "bearer" : "apiKey"]: Array.from(
|
|
5434
|
-
"allowedPermissions" in auth && auth.allowedPermissions instanceof Set ? auth.allowedPermissions.values() : []
|
|
5435
|
-
)
|
|
5436
|
-
}
|
|
5437
|
-
];
|
|
5626
|
+
const schemeName = auth.headerName || "Authorization";
|
|
5627
|
+
operationObject.security = [{ [schemeName]: [] }];
|
|
5438
5628
|
if (auth.headerName && auth.headerName !== "Authorization") {
|
|
5439
5629
|
securitySchemes[auth.headerName] = {
|
|
5440
5630
|
type: "apiKey",
|
|
@@ -5665,6 +5855,22 @@ var RateLimiter = class {
|
|
|
5665
5855
|
return READ_METHODS.has(method.toUpperCase()) ? "read" : "write";
|
|
5666
5856
|
}
|
|
5667
5857
|
};
|
|
5858
|
+
|
|
5859
|
+
// src/http/registerDelegatedSurface.ts
|
|
5860
|
+
function registerDelegatedSurface(surface, mount, register) {
|
|
5861
|
+
if (!surface.id || !surface.provider || surface.coverage !== "provider-owned" || !surface.client.package || !surface.client.export || surface.runtime.basePath !== "runtime-resolved" || typeof surface.runtime.openApi !== "boolean" || !Array.isArray(surface.callbacks) || surface.callbacks.some(
|
|
5862
|
+
(callback) => typeof callback !== "string" || !callback.startsWith("/")
|
|
5863
|
+
)) {
|
|
5864
|
+
throw new Error("Invalid delegated HTTP surface descriptor");
|
|
5865
|
+
}
|
|
5866
|
+
const paths = Array.isArray(mount.paths) ? mount.paths : [mount.paths];
|
|
5867
|
+
if (mount.basePath !== "" && !mount.basePath.startsWith("/") || paths.length === 0 || paths.some(
|
|
5868
|
+
(path) => !path.startsWith("/") || mount.basePath !== "" && !path.startsWith(mount.basePath + "/")
|
|
5869
|
+
)) {
|
|
5870
|
+
throw new Error("Invalid delegated HTTP surface mount");
|
|
5871
|
+
}
|
|
5872
|
+
return register(mount);
|
|
5873
|
+
}
|
|
5668
5874
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5669
5875
|
0 && (module.exports = {
|
|
5670
5876
|
ATTR_API_NAME,
|
|
@@ -5703,6 +5909,7 @@ var RateLimiter = class {
|
|
|
5703
5909
|
auditComplianceAccess,
|
|
5704
5910
|
auditEnabled,
|
|
5705
5911
|
auditEventType,
|
|
5912
|
+
bindRuntimeAuth,
|
|
5706
5913
|
createContext,
|
|
5707
5914
|
createEmailClient,
|
|
5708
5915
|
createHmacToken,
|
|
@@ -5756,6 +5963,7 @@ var RateLimiter = class {
|
|
|
5756
5963
|
put,
|
|
5757
5964
|
recordMetric,
|
|
5758
5965
|
recordRequestAudit,
|
|
5966
|
+
registerDelegatedSurface,
|
|
5759
5967
|
resetProcessHandlersForTesting,
|
|
5760
5968
|
signPlatformEvent,
|
|
5761
5969
|
smsSegments,
|