@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.
Files changed (40) hide show
  1. package/bin/gateway-mock/routes/payments-context.mjs +260 -0
  2. package/bin/gateway-mock/routes/payments.mjs +47 -1
  3. package/lib/http/bindRuntimeAuth.d.ts +53 -0
  4. package/lib/http/bindRuntimeAuth.d.ts.map +1 -0
  5. package/lib/http/bindRuntimeAuth.test.d.ts +2 -0
  6. package/lib/http/bindRuntimeAuth.test.d.ts.map +1 -0
  7. package/lib/http/index.d.ts +2 -0
  8. package/lib/http/index.d.ts.map +1 -1
  9. package/lib/http/index.js +284 -76
  10. package/lib/http/index.js.map +1 -1
  11. package/lib/http/index.mjs +282 -76
  12. package/lib/http/index.mjs.map +1 -1
  13. package/lib/http/mcpGenerator/mcpGenerator.d.ts.map +1 -1
  14. package/lib/http/middleware/internal/validationDiagnostic.d.ts +3 -0
  15. package/lib/http/middleware/internal/validationDiagnostic.d.ts.map +1 -0
  16. package/lib/http/middleware/request/auth.middleware.d.ts +0 -11
  17. package/lib/http/middleware/request/auth.middleware.d.ts.map +1 -1
  18. package/lib/http/middleware/request/parse.middleware.d.ts.map +1 -1
  19. package/lib/http/middleware/response/enrichExpressLikeSend.middleware.d.ts.map +1 -1
  20. package/lib/http/middleware/response/parse.middleware.d.ts.map +1 -1
  21. package/lib/http/openApiV3Generator/openApiV3Generator.d.ts.map +1 -1
  22. package/lib/http/paymentsClient.d.ts.map +1 -1
  23. package/lib/http/registerDelegatedSurface.d.ts +28 -0
  24. package/lib/http/registerDelegatedSurface.d.ts.map +1 -0
  25. package/lib/http/registerDelegatedSurface.test.d.ts +2 -0
  26. package/lib/http/registerDelegatedSurface.test.d.ts.map +1 -0
  27. package/lib/http/router/discriminateBody.d.ts +2 -1
  28. package/lib/http/router/discriminateBody.d.ts.map +1 -1
  29. package/lib/http/router/expressLikeRouter.d.ts.map +1 -1
  30. package/lib/persistence/compliantField.d.ts.map +1 -1
  31. package/lib/persistence/index.js +1 -6
  32. package/lib/persistence/index.js.map +1 -1
  33. package/lib/persistence/index.mjs +1 -6
  34. package/lib/persistence/index.mjs.map +1 -1
  35. package/lib/ws/asyncApiV3Generator/asyncApiV3Generator.d.ts.map +1 -1
  36. package/lib/ws/index.js +94 -8
  37. package/lib/ws/index.js.map +1 -1
  38. package/lib/ws/index.mjs +94 -8
  39. package/lib/ws/index.mjs.map +1 -1
  40. package/package.json +4 -4
@@ -1,3 +1,65 @@
1
+ // src/http/bindRuntimeAuth.ts
2
+ function bindRuntimeAuth(details, binding) {
3
+ const policy = { ...details.auth };
4
+ const keys = Object.keys(binding);
5
+ const credentials = { ...binding };
6
+ const invalid = () => {
7
+ throw new Error("Invalid runtime authentication binding");
8
+ };
9
+ const allowedPolicy = policy.scheme === "jwt" ? [
10
+ "scheme",
11
+ "headerName",
12
+ "tokenPrefix",
13
+ "sessionSchema",
14
+ "allowedRoles",
15
+ "allowedPermissions"
16
+ ] : ["scheme", "headerName", "tokenPrefix"];
17
+ if (Object.keys(policy).some((key) => !allowedPolicy.includes(key)))
18
+ invalid();
19
+ for (const key of ["headerName", "tokenPrefix"]) {
20
+ if (policy[key] !== void 0 && (typeof policy[key] !== "string" || !policy[key]))
21
+ invalid();
22
+ }
23
+ if (policy.scheme === "jwt" && policy.allowedRoles === void 0 && policy.allowedPermissions === void 0)
24
+ invalid();
25
+ let authentication;
26
+ if (policy.scheme === "jwt") {
27
+ if (keys.some(
28
+ (key) => !["jwksPublicKeyUrl", "signatureKey", "decodeResource"].includes(key)
29
+ ))
30
+ invalid();
31
+ const keyFields = keys.filter((key) => key !== "decodeResource");
32
+ if (keyFields.length !== 1 || typeof credentials[keyFields[0]] !== "string" || !credentials[keyFields[0]])
33
+ invalid();
34
+ const decodeResource = credentials.decodeResource;
35
+ if (decodeResource !== void 0 && typeof decodeResource !== "function")
36
+ invalid();
37
+ delete credentials.decodeResource;
38
+ authentication = {
39
+ jwt: credentials,
40
+ ...decodeResource === void 0 ? {} : { decodeResource }
41
+ };
42
+ } else if (policy.scheme === "hmac") {
43
+ 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(
44
+ (key) => typeof key !== "string" || !key
45
+ ))
46
+ invalid();
47
+ authentication = { hmac: credentials };
48
+ } else {
49
+ return invalid();
50
+ }
51
+ delete policy.scheme;
52
+ for (const key of ["allowedRoles", "allowedPermissions"]) {
53
+ if (policy[key] !== void 0) {
54
+ const values = policy[key];
55
+ if (!Array.isArray(values) || values.some((value) => typeof value !== "string"))
56
+ invalid();
57
+ policy[key] = new Set(values);
58
+ }
59
+ }
60
+ return { ...details, auth: { ...policy, ...authentication } };
61
+ }
62
+
1
63
  // src/http/middleware/request/cors.middleware.ts
2
64
  import corsMiddleware from "cors";
3
65
  function cors(corsOptions) {
@@ -473,7 +535,7 @@ function createContext(schemaValidator) {
473
535
  }
474
536
 
475
537
  // src/http/router/discriminateBody.ts
476
- function discriminateBody(schemaValidator, body) {
538
+ function discriminateBody(schemaValidator, body, inputProjection) {
477
539
  if (body == null) {
478
540
  return void 0;
479
541
  }
@@ -523,7 +585,7 @@ function discriminateBody(schemaValidator, body) {
523
585
  parserType: "text",
524
586
  schema: maybeTypedBody
525
587
  };
526
- } else if (schemaValidator.openapi(maybeTypedBody).format === "binary") {
588
+ } else if ((inputProjection ?? schemaValidator.openapi(maybeTypedBody)).format === "binary") {
527
589
  return {
528
590
  contentType: "application/octet-stream",
529
591
  parserType: "file",
@@ -955,15 +1017,23 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
955
1017
  if (!parsedKeyId || !parsedTimestamp || !parsedNonce || !parsedSignature) {
956
1018
  return invalidAuthorizationTokenFormat;
957
1019
  }
958
- const verificationResult = await auth.verificationFunction({
959
- method: req?.method ?? "",
960
- path: req?.path ?? "",
961
- body: req?._rawBody ?? req?.body,
962
- timestamp: new Date(parsedTimestamp),
963
- nonce: parsedNonce,
964
- signature: parsedSignature,
965
- secretKey: collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
966
- });
1020
+ let verificationResult = false;
1021
+ const signedPaths = hmacSignedPaths(req);
1022
+ for (const path of signedPaths) {
1023
+ verificationResult = Boolean(await auth.verificationFunction({
1024
+ method: req?.method ?? "",
1025
+ path,
1026
+ body: req?._rawBody ?? req?.body,
1027
+ timestamp: new Date(parsedTimestamp),
1028
+ nonce: parsedNonce,
1029
+ signature: parsedSignature,
1030
+ secretKey: collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
1031
+ }));
1032
+ if (verificationResult) {
1033
+ if (path !== signedPaths[0]) warnMountRelativeHmacPath();
1034
+ break;
1035
+ }
1036
+ }
967
1037
  if (!verificationResult) {
968
1038
  return invalidAuthorizationSignature;
969
1039
  }
@@ -1130,6 +1200,25 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
1130
1200
  }
1131
1201
  }
1132
1202
  }
1203
+ function acceptMountRelativeHmacPaths() {
1204
+ const value = typeof process === "undefined" ? void 0 : process.env?.HMAC_ACCEPT_MOUNT_RELATIVE_PATHS;
1205
+ return value == null || !["false", "0"].includes(value.trim().toLowerCase());
1206
+ }
1207
+ var warnedMountRelativeHmacPath = false;
1208
+ function warnMountRelativeHmacPath() {
1209
+ if (warnedMountRelativeHmacPath) return;
1210
+ warnedMountRelativeHmacPath = true;
1211
+ console.warn(
1212
+ "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."
1213
+ );
1214
+ }
1215
+ function hmacSignedPaths(req) {
1216
+ const relative = req?.path ?? "";
1217
+ const wire = (req?.originalUrl ?? req?.url ?? relative).split("?")[0] || relative;
1218
+ const paths = [wire];
1219
+ if (relative !== wire && acceptMountRelativeHmacPaths()) paths.push(relative);
1220
+ return paths;
1221
+ }
1133
1222
  async function parseRequestAuth(req, res, next) {
1134
1223
  const access = req.contractDetails.access;
1135
1224
  if (access === "public") {
@@ -1367,6 +1456,21 @@ function isRequestShape(maybeResponseShape) {
1367
1456
  return maybeResponseShape != null && ("body" in maybeResponseShape || "query" in maybeResponseShape || "params" in maybeResponseShape || "headers" in maybeResponseShape);
1368
1457
  }
1369
1458
 
1459
+ // src/http/middleware/internal/validationDiagnostic.ts
1460
+ var sendingDiagnostics = /* @__PURE__ */ new WeakSet();
1461
+ function isValidationDiagnostic(response) {
1462
+ return sendingDiagnostics.has(response);
1463
+ }
1464
+ function sendValidationDiagnostic(response, send) {
1465
+ const alreadySending = sendingDiagnostics.has(response);
1466
+ sendingDiagnostics.add(response);
1467
+ try {
1468
+ return send();
1469
+ } finally {
1470
+ if (!alreadySending) sendingDiagnostics.delete(response);
1471
+ }
1472
+ }
1473
+
1370
1474
  // src/http/middleware/request/parse.middleware.ts
1371
1475
  function parse(req, res, next) {
1372
1476
  const globalOptions = req._globalOptions?.();
@@ -1448,14 +1552,13 @@ function parse(req, res, next) {
1448
1552
  default:
1449
1553
  case void 0:
1450
1554
  case "error":
1451
- res.type("application/json");
1555
+ res.type("text/plain");
1452
1556
  res.status(400);
1453
1557
  if (hasSend(res)) {
1454
- res.send(
1455
- `${collectedParseErrors ?? prettyPrintParseErrors2(parsedRequest.errors, "Request")}
1558
+ const diagnostic = `${collectedParseErrors ?? prettyPrintParseErrors2(parsedRequest.errors, "Request")}
1456
1559
 
1457
- Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
1458
- );
1560
+ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`;
1561
+ sendValidationDiagnostic(res, () => res.send(diagnostic));
1459
1562
  } else {
1460
1563
  next?.(new Error("Request is not sendable."));
1461
1564
  }
@@ -1864,13 +1967,25 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1864
1967
  span: void 0
1865
1968
  },
1866
1969
  _rawBody: void 0,
1867
- _parsedVersions: void 0
1970
+ _parsedVersions: void 0,
1971
+ // hyper-express's content parser reads the body through its Request's
1972
+ // body readers; serve the body the call was given.
1973
+ buffer: async () => Buffer.from(
1974
+ typeof req.body === "string" ? req.body : JSON.stringify(req.body)
1975
+ ),
1976
+ json: async () => req.body,
1977
+ text: async () => typeof req.body === "string" ? req.body : JSON.stringify(req.body)
1868
1978
  };
1869
1979
  const res = {
1870
1980
  statusCode: 200,
1981
+ // hyper-express's response enrichment reads the status and headers
1982
+ // from these fields, which its own Response keeps.
1983
+ _status_code: 200,
1984
+ _headers: responseHeaders,
1871
1985
  status: (code) => {
1872
1986
  statusCode = code;
1873
1987
  res.statusCode = code;
1988
+ res._status_code = code;
1874
1989
  return res;
1875
1990
  },
1876
1991
  send: (message) => {
@@ -1890,6 +2005,8 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1890
2005
  return res;
1891
2006
  },
1892
2007
  getHeader: (key) => responseHeaders[key],
2008
+ getHeaders: () => ({ ...responseHeaders }),
2009
+ locals: {},
1893
2010
  type: (contentType) => {
1894
2011
  responseHeaders["content-type"] = contentType;
1895
2012
  return res;
@@ -1908,31 +2025,59 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1908
2025
  version
1909
2026
  };
1910
2027
  const executeMiddlewares = request?.executeMiddlewares ?? false;
2028
+ const cHandler = controllerHandler;
1911
2029
  if (executeMiddlewares && middlewares.length > 0) {
1912
- const allHandlers = [...middlewares];
1913
- let cursor = allHandlers.shift();
1914
- if (cursor) {
1915
- for (const fn of allHandlers) {
1916
- await cursor(req, res, (err) => {
1917
- if (err) {
1918
- throw err;
2030
+ const chain = middlewares;
2031
+ await new Promise((resolve, reject) => {
2032
+ let settled = false;
2033
+ let responded = false;
2034
+ let controllerStarted = false;
2035
+ const finish = (error) => {
2036
+ if (settled) return;
2037
+ settled = true;
2038
+ if (error) reject(error);
2039
+ else resolve();
2040
+ };
2041
+ res.on("finish", () => {
2042
+ responded = true;
2043
+ if (!controllerStarted) finish();
2044
+ });
2045
+ const run = async (index) => {
2046
+ try {
2047
+ if (index === chain.length) {
2048
+ controllerStarted = true;
2049
+ await cHandler(req, res, (err) => {
2050
+ if (err) {
2051
+ throw err;
2052
+ }
2053
+ });
2054
+ finish();
2055
+ return;
1919
2056
  }
1920
- cursor = fn;
1921
- });
1922
- }
1923
- await cursor(req, res, async (err) => {
1924
- if (err) {
1925
- throw err;
2057
+ let calledNext = false;
2058
+ await chain[index](req, res, (err) => {
2059
+ calledNext = true;
2060
+ if (err) {
2061
+ throw err;
2062
+ }
2063
+ return run(index + 1);
2064
+ });
2065
+ if (!calledNext && chain[index].length < 3 && !responded) {
2066
+ await run(index + 1);
2067
+ }
2068
+ } catch (error) {
2069
+ finish(error);
1926
2070
  }
1927
- });
1928
- }
2071
+ };
2072
+ void run(0);
2073
+ });
2074
+ } else {
2075
+ await cHandler(req, res, (err) => {
2076
+ if (err) {
2077
+ throw err;
2078
+ }
2079
+ });
1929
2080
  }
1930
- const cHandler = controllerHandler;
1931
- await cHandler(req, res, (err) => {
1932
- if (err) {
1933
- throw err;
1934
- }
1935
- });
1936
2081
  return {
1937
2082
  code: Number(statusCode),
1938
2083
  response: responseMessage,
@@ -3420,7 +3565,7 @@ function loadStripe() {
3420
3565
  function stripeGatewayFetch(settings, fetchImpl = fetch) {
3421
3566
  const base = new URL(settings.gatewayUrl);
3422
3567
  const basePath = base.pathname.replace(/\/+$/, "");
3423
- return async (input, init = {}) => {
3568
+ const signedFetch = async (input, init = {}) => {
3424
3569
  const original = new URL(
3425
3570
  typeof input === "string" || input instanceof URL ? input : input.url
3426
3571
  );
@@ -3460,6 +3605,13 @@ function stripeGatewayFetch(settings, fetchImpl = fetch) {
3460
3605
  }
3461
3606
  );
3462
3607
  };
3608
+ const preconnect = Reflect.get(fetchImpl, "preconnect");
3609
+ if (typeof preconnect === "function") {
3610
+ Object.defineProperty(signedFetch, "preconnect", {
3611
+ value: (_input, options2) => Reflect.apply(preconnect, fetchImpl, [base.origin, options2])
3612
+ });
3613
+ }
3614
+ return signedFetch;
3463
3615
  }
3464
3616
  function createStripeClient(options2 = {}) {
3465
3617
  const StripeClass = options2.Stripe ?? loadStripe();
@@ -4692,10 +4844,10 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
4692
4844
  let bodySchema;
4693
4845
  let responsesSchemas;
4694
4846
  if (route.contractDetails.versions) {
4695
- const version2 = route.contractDetails.versions[index];
4847
+ const version2 = Object.values(route.contractDetails.versions)[index];
4848
+ responsesSchemas = version2.responses;
4696
4849
  if (version2.body && schemaValidator.parse(inputSchema, args).ok) {
4697
4850
  bodySchema = version2.body;
4698
- responsesSchemas = version2.responses;
4699
4851
  }
4700
4852
  } else {
4701
4853
  bodySchema = route.contractDetails.body;
@@ -4706,7 +4858,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
4706
4858
  if (discriminatedBody) {
4707
4859
  switch (discriminatedBody.parserType) {
4708
4860
  case "json": {
4709
- parsedBody = safeStringify4(body);
4861
+ parsedBody = body === void 0 ? void 0 : JSON.stringify(body);
4710
4862
  break;
4711
4863
  }
4712
4864
  case "text": {
@@ -4772,11 +4924,11 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
4772
4924
  ).toString();
4773
4925
  url += queryString ? `?${queryString}` : "";
4774
4926
  }
4775
- const response = await fetch(encodeURI(url), {
4927
+ const response = await fetch(url, {
4776
4928
  method: route.method.toUpperCase(),
4777
4929
  headers: {
4778
4930
  ...headers,
4779
- ...discriminatedBody?.contentType != "multipart/form-data" ? {
4931
+ ...discriminatedBody?.contentType != "multipart/form-data" && (contentType ?? discriminatedBody?.contentType) !== void 0 ? {
4780
4932
  "Content-Type": contentType ?? discriminatedBody?.contentType
4781
4933
  } : {}
4782
4934
  },
@@ -4856,7 +5008,12 @@ function isResponseCompiledSchema(schema) {
4856
5008
  }
4857
5009
 
4858
5010
  // src/http/middleware/response/parse.middleware.ts
5011
+ var sendingValidationError = /* @__PURE__ */ new WeakSet();
4859
5012
  function parse2(req, res, next) {
5013
+ if (sendingValidationError.has(res)) {
5014
+ next?.();
5015
+ return;
5016
+ }
4860
5017
  let headers;
4861
5018
  let responses;
4862
5019
  const globalOptions = req._globalOptions?.();
@@ -4899,15 +5056,35 @@ function parse2(req, res, next) {
4899
5056
  responses = responseSchemas.responses;
4900
5057
  }
4901
5058
  const statusCode = Number(res.statusCode);
4902
- const parsedResponse = schemaValidator.parse(
4903
- [400, 401, 404, 403, 500].includes(statusCode) ? schemaValidator.union([schemaValidator.string, responses?.[statusCode]]) : responses?.[statusCode],
4904
- res.bodyData
4905
- );
5059
+ const defaultErrorStatus = [400, 401, 404, 403, 500].includes(statusCode);
5060
+ const missingResponseSchema = !defaultErrorStatus && !Object.prototype.hasOwnProperty.call(responses, statusCode);
5061
+ if (missingResponseSchema && collapsedOptions !== "warning") {
5062
+ throw new Error(`Undocumented response status ${statusCode}`);
5063
+ }
5064
+ const declaredResponse = responses?.[statusCode];
5065
+ const defaultErrorResponse = () => {
5066
+ try {
5067
+ return schemaValidator.parse(
5068
+ schemaValidator.union([schemaValidator.string, declaredResponse]),
5069
+ res.bodyData
5070
+ );
5071
+ } catch (error) {
5072
+ if (declaredResponse === void 0) throw error;
5073
+ const declared = schemaValidator.parse(declaredResponse, res.bodyData);
5074
+ if (declared.ok) return declared;
5075
+ const message = schemaValidator.parse(
5076
+ schemaValidator.string,
5077
+ res.bodyData
5078
+ );
5079
+ return message.ok ? message : declared;
5080
+ }
5081
+ };
5082
+ const parsedResponse = missingResponseSchema ? { ok: true } : defaultErrorStatus ? defaultErrorResponse() : schemaValidator.parse(declaredResponse, res.bodyData);
4906
5083
  const parsedHeaders = schemaValidator.parse(
4907
5084
  headers ?? schemaValidator.unknown,
4908
5085
  res.getHeaders()
4909
5086
  );
4910
- const parseErrors = [];
5087
+ const parseErrors = missingResponseSchema ? [`Response: Undocumented response status ${statusCode}`] : [];
4911
5088
  if (!parsedHeaders.ok) {
4912
5089
  const headerErrors = prettyPrintParseErrors3(parsedHeaders.errors, "Header");
4913
5090
  if (headerErrors) {
@@ -4924,21 +5101,26 @@ function parse2(req, res, next) {
4924
5101
  }
4925
5102
  }
4926
5103
  if (parseErrors.length > 0) {
4927
- switch (req.contractDetails.options?.responseValidation) {
5104
+ switch (collapsedOptions) {
4928
5105
  default:
4929
5106
  case void 0:
4930
5107
  case "error":
4931
5108
  res.type("text/plain");
4932
5109
  res.status(500);
4933
5110
  if (hasSend(res)) {
4934
- res.send(
4935
- `Invalid response:
5111
+ sendingValidationError.add(res);
5112
+ try {
5113
+ res.send(
5114
+ `Invalid response:
4936
5115
  ${parseErrors.join(
4937
- "\n\n"
4938
- )}
5116
+ "\n\n"
5117
+ )}
4939
5118
 
4940
5119
  Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
4941
- );
5120
+ );
5121
+ } finally {
5122
+ sendingValidationError.delete(res);
5123
+ }
4942
5124
  } else {
4943
5125
  next?.(new Error("Response is not sendable."));
4944
5126
  }
@@ -4949,8 +5131,6 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
4949
5131
  ${parseErrors.join("\n\n")}`
4950
5132
  );
4951
5133
  break;
4952
- case "none":
4953
- break;
4954
5134
  }
4955
5135
  }
4956
5136
  next?.();
@@ -5004,6 +5184,10 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
5004
5184
  originalSend.call(instance, data);
5005
5185
  return;
5006
5186
  }
5187
+ if (typeof data === "string" && isValidationDiagnostic(res)) {
5188
+ originalSend.call(instance, data);
5189
+ return;
5190
+ }
5007
5191
  let responses;
5008
5192
  if (req.contractDetails.responses == null && (req.contractDetails.versions == null || Object.values(req.contractDetails.versions).some(
5009
5193
  (version) => version?.responses == null
@@ -5013,7 +5197,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
5013
5197
  if (req.contractDetails.responses != null) {
5014
5198
  responses = req.contractDetails.responses;
5015
5199
  } else {
5016
- responses = req.contractDetails.versions[req.version].responses;
5200
+ responses = req.contractDetails.versions[req.version]?.responses ?? {};
5017
5201
  }
5018
5202
  }
5019
5203
  const responseBodies = discriminateResponseBodies(
@@ -5235,7 +5419,16 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
5235
5419
  for (const key in discriminatedResponseBodiesResult) {
5236
5420
  coercedResponses[key] = {
5237
5421
  description: httpStatusCodes_default[key],
5238
- content: contentResolver(
5422
+ // Undefined/void represent no response body, not a JSON null payload.
5423
+ // Check the schema kind rather than its OpenAPI projection: null and
5424
+ // nullish also project to null but still admit an actual JSON body.
5425
+ content: schemaValidator.undefined !== void 0 && typedSchemaValidator.isInstanceOf(
5426
+ discriminatedResponseBodiesResult[key].schema,
5427
+ schemaValidator.undefined
5428
+ ) || schemaValidator.void !== void 0 && typedSchemaValidator.isInstanceOf(
5429
+ discriminatedResponseBodiesResult[key].schema,
5430
+ schemaValidator.void
5431
+ ) ? void 0 : contentResolver(
5239
5432
  schemaValidator,
5240
5433
  discriminatedResponseBodiesResult[key].schema,
5241
5434
  discriminatedResponseBodiesResult[key].contentType
@@ -5271,15 +5464,21 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
5271
5464
  operationObject.parameters?.push({
5272
5465
  name: key,
5273
5466
  in: "path",
5467
+ required: true,
5274
5468
  schema: typedSchemaValidator.openapi(params[key])
5275
5469
  });
5276
5470
  }
5277
5471
  }
5278
- const discriminatedBodyResult = body ? discriminateBody(schemaValidator, body) : null;
5472
+ const adapter = schemaValidator;
5473
+ const bareProjection = body && adapter.isSchema(body) ? adapter.openapiRequestBody?.(body) : void 0;
5474
+ const discriminatedBodyResult = body ? discriminateBody(schemaValidator, body, bareProjection?.schema) : null;
5279
5475
  if (discriminatedBodyResult) {
5476
+ const projection = bareProjection ?? adapter.openapiRequestBody?.(discriminatedBodyResult.schema);
5280
5477
  operationObject.requestBody = {
5281
- required: true,
5282
- content: contentResolver(
5478
+ required: projection?.required ?? true,
5479
+ content: projection ? {
5480
+ [discriminatedBodyResult.contentType]: { schema: projection.schema }
5481
+ } : contentResolver(
5283
5482
  schemaValidator,
5284
5483
  discriminatedBodyResult.schema,
5285
5484
  discriminatedBodyResult.contentType
@@ -5314,25 +5513,14 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
5314
5513
  content: contentResolver(schemaValidator, schemaValidator.string)
5315
5514
  };
5316
5515
  if ("basic" in auth) {
5317
- operationObject.security = [
5318
- {
5319
- basic: Array.from(
5320
- "allowedPermissions" in auth && auth.allowedPermissions instanceof Set ? auth.allowedPermissions.values() : []
5321
- )
5322
- }
5323
- ];
5516
+ operationObject.security = [{ basic: [] }];
5324
5517
  securitySchemes["basic"] = {
5325
5518
  type: "http",
5326
5519
  scheme: "basic"
5327
5520
  };
5328
5521
  } else if (auth) {
5329
- operationObject.security = [
5330
- {
5331
- [auth.headerName !== "Authorization" ? "bearer" : "apiKey"]: Array.from(
5332
- "allowedPermissions" in auth && auth.allowedPermissions instanceof Set ? auth.allowedPermissions.values() : []
5333
- )
5334
- }
5335
- ];
5522
+ const schemeName = auth.headerName || "Authorization";
5523
+ operationObject.security = [{ [schemeName]: [] }];
5336
5524
  if (auth.headerName && auth.headerName !== "Authorization") {
5337
5525
  securitySchemes[auth.headerName] = {
5338
5526
  type: "apiKey",
@@ -5563,6 +5751,22 @@ var RateLimiter = class {
5563
5751
  return READ_METHODS.has(method.toUpperCase()) ? "read" : "write";
5564
5752
  }
5565
5753
  };
5754
+
5755
+ // src/http/registerDelegatedSurface.ts
5756
+ function registerDelegatedSurface(surface, mount, register) {
5757
+ 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(
5758
+ (callback) => typeof callback !== "string" || !callback.startsWith("/")
5759
+ )) {
5760
+ throw new Error("Invalid delegated HTTP surface descriptor");
5761
+ }
5762
+ const paths = Array.isArray(mount.paths) ? mount.paths : [mount.paths];
5763
+ if (mount.basePath !== "" && !mount.basePath.startsWith("/") || paths.length === 0 || paths.some(
5764
+ (path) => !path.startsWith("/") || mount.basePath !== "" && !path.startsWith(mount.basePath + "/")
5765
+ )) {
5766
+ throw new Error("Invalid delegated HTTP surface mount");
5767
+ }
5768
+ return register(mount);
5769
+ }
5566
5770
  export {
5567
5771
  ATTR_API_NAME,
5568
5772
  ATTR_APPLICATION_ID,
@@ -5600,6 +5804,7 @@ export {
5600
5804
  auditComplianceAccess,
5601
5805
  auditEnabled,
5602
5806
  auditEventType,
5807
+ bindRuntimeAuth,
5603
5808
  createContext,
5604
5809
  createEmailClient,
5605
5810
  createHmacToken,
@@ -5653,6 +5858,7 @@ export {
5653
5858
  put,
5654
5859
  recordMetric,
5655
5860
  recordRequestAudit,
5861
+ registerDelegatedSurface,
5656
5862
  resetProcessHandlersForTesting,
5657
5863
  signPlatformEvent,
5658
5864
  smsSegments,