cdk-nextjs 0.6.1 → 0.7.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 (266) hide show
  1. package/.jsii +2467 -2714
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1725 -1909
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +687 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1548 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +852 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +861 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +13 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/post-deploy.lambda.js +3 -2
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  88. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  92. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  93. package/lib/lambdas/post-deploy/prune-s3.d.ts +19 -3
  94. package/lib/lambdas/post-deploy/prune-s3.js +54 -15
  95. package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
  96. package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  103. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  104. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  105. package/lib/nextjs-api.d.ts +107 -18
  106. package/lib/nextjs-api.js +349 -39
  107. package/lib/nextjs-api.test.js +582 -1
  108. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  109. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  110. package/lib/nextjs-build/nextjs-build.js +684 -327
  111. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  112. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  113. package/lib/nextjs-build/patch-fetch.js +1 -1
  114. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  115. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  116. package/lib/nextjs-cache.d.ts +82 -4
  117. package/lib/nextjs-cache.js +186 -10
  118. package/lib/nextjs-cache.test.js +176 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  120. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  121. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  122. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  123. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  124. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  125. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  126. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  127. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  128. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  129. package/lib/nextjs-distribution.d.ts +194 -23
  130. package/lib/nextjs-distribution.js +535 -62
  131. package/lib/nextjs-distribution.test.d.ts +1 -0
  132. package/lib/nextjs-distribution.test.js +697 -0
  133. package/lib/nextjs-post-deploy.d.ts +23 -3
  134. package/lib/nextjs-post-deploy.js +14 -10
  135. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  136. package/lib/nextjs-post-deploy.test.js +34 -0
  137. package/lib/nextjs-static-assets.d.ts +23 -4
  138. package/lib/nextjs-static-assets.js +29 -6
  139. package/lib/nextjs-static-assets.test.js +20 -1
  140. package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
  141. package/lib/root-constructs/nextjs-base-construct.js +144 -34
  142. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  143. package/lib/root-constructs/nextjs-global-containers.js +20 -70
  144. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  145. package/lib/root-constructs/nextjs-global-functions.js +52 -69
  146. package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
  147. package/lib/root-constructs/nextjs-regional-containers.js +17 -15
  148. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  149. package/lib/root-constructs/nextjs-regional-functions.js +8 -25
  150. package/lib/runtime/api-gateway-path.d.ts +34 -0
  151. package/lib/runtime/api-gateway-path.js +71 -0
  152. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  153. package/lib/runtime/api-gateway-path.test.js +65 -0
  154. package/lib/runtime/case-redirect.d.ts +22 -0
  155. package/lib/runtime/case-redirect.js +63 -0
  156. package/lib/runtime/case-redirect.test.d.ts +1 -0
  157. package/lib/runtime/case-redirect.test.js +32 -0
  158. package/lib/runtime/core.d.ts +234 -0
  159. package/lib/runtime/core.js +1213 -0
  160. package/lib/runtime/core.test.d.ts +1 -0
  161. package/lib/runtime/core.test.js +1678 -0
  162. package/lib/runtime/deployment-root.d.ts +13 -0
  163. package/lib/runtime/deployment-root.js +29 -0
  164. package/lib/runtime/dispatch.d.ts +331 -0
  165. package/lib/runtime/dispatch.js +751 -0
  166. package/lib/runtime/dispatch.test.d.ts +1 -0
  167. package/lib/runtime/dispatch.test.js +853 -0
  168. package/lib/runtime/entrypoints.d.ts +57 -0
  169. package/lib/runtime/entrypoints.js +115 -0
  170. package/lib/runtime/http/abort-signal.d.ts +6 -0
  171. package/lib/runtime/http/abort-signal.js +19 -0
  172. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  173. package/lib/runtime/http/abort-signal.test.js +49 -0
  174. package/lib/runtime/http/node-server.d.ts +38 -0
  175. package/lib/runtime/http/node-server.js +99 -0
  176. package/lib/runtime/http/node-server.test.d.ts +1 -0
  177. package/lib/runtime/http/node-server.test.js +96 -0
  178. package/lib/runtime/http/node-sink.d.ts +16 -0
  179. package/lib/runtime/http/node-sink.js +48 -0
  180. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  181. package/lib/runtime/http/node-sink.test.js +66 -0
  182. package/lib/runtime/http/request.d.ts +62 -0
  183. package/lib/runtime/http/request.js +134 -0
  184. package/lib/runtime/http/request.test.d.ts +1 -0
  185. package/lib/runtime/http/request.test.js +103 -0
  186. package/lib/runtime/http/response.d.ts +77 -0
  187. package/lib/runtime/http/response.js +229 -0
  188. package/lib/runtime/http/response.test.d.ts +1 -0
  189. package/lib/runtime/http/response.test.js +178 -0
  190. package/lib/runtime/http/sink.d.ts +73 -0
  191. package/lib/runtime/http/sink.js +188 -0
  192. package/lib/runtime/http/sink.test.d.ts +1 -0
  193. package/lib/runtime/http/sink.test.js +257 -0
  194. package/lib/runtime/image-utils.d.ts +78 -0
  195. package/lib/runtime/image-utils.js +129 -0
  196. package/lib/runtime/image-utils.test.d.ts +1 -0
  197. package/lib/runtime/image-utils.test.js +237 -0
  198. package/lib/runtime/image.d.ts +76 -0
  199. package/lib/runtime/image.js +296 -0
  200. package/lib/runtime/image.test.d.ts +1 -0
  201. package/lib/runtime/image.test.js +405 -0
  202. package/lib/runtime/lambda-event.d.ts +4 -0
  203. package/lib/runtime/lambda-event.js +113 -0
  204. package/lib/runtime/lambda-event.test.d.ts +1 -0
  205. package/lib/runtime/lambda-event.test.js +119 -0
  206. package/lib/runtime/lambda.mjs +41595 -0
  207. package/lib/runtime/load-module.d.ts +8 -0
  208. package/lib/runtime/load-module.js +35 -0
  209. package/lib/runtime/manifest.d.ts +215 -0
  210. package/lib/runtime/manifest.js +118 -0
  211. package/lib/runtime/middleware.d.ts +43 -0
  212. package/lib/runtime/middleware.js +113 -0
  213. package/lib/runtime/middleware.test.d.ts +1 -0
  214. package/lib/runtime/middleware.test.js +259 -0
  215. package/lib/runtime/next-modules.d.ts +55 -0
  216. package/lib/runtime/next-modules.js +124 -0
  217. package/lib/runtime/next-modules.test.d.ts +1 -0
  218. package/lib/runtime/next-modules.test.js +34 -0
  219. package/lib/runtime/public-files.d.ts +32 -0
  220. package/lib/runtime/public-files.js +117 -0
  221. package/lib/runtime/public-files.test.d.ts +1 -0
  222. package/lib/runtime/public-files.test.js +97 -0
  223. package/lib/runtime/server.mjs +41588 -0
  224. package/lib/runtime/static-files.d.ts +50 -0
  225. package/lib/runtime/static-files.js +266 -0
  226. package/lib/runtime/static-files.test.d.ts +1 -0
  227. package/lib/runtime/static-files.test.js +118 -0
  228. package/lib/runtime/util.d.ts +28 -0
  229. package/lib/runtime/util.js +79 -0
  230. package/lib/utils/base-path.d.ts +123 -11
  231. package/lib/utils/base-path.js +276 -39
  232. package/lib/utils/base-path.test.js +275 -50
  233. package/lib/utils/get-architecture.d.ts +7 -8
  234. package/lib/utils/get-architecture.js +12 -13
  235. package/lib/utils/zip-directory.d.ts +14 -0
  236. package/lib/utils/zip-directory.js +121 -0
  237. package/lib/utils/zip-directory.test.d.ts +1 -0
  238. package/lib/utils/zip-directory.test.js +99 -0
  239. package/package.json +22 -3
  240. package/scripts/capture-adapter-fixture.mjs +325 -0
  241. package/scripts/e2e-deploy.sh +398 -0
  242. package/scripts/e2e-harness/README.md +707 -0
  243. package/scripts/e2e-harness/app.js +370 -0
  244. package/scripts/e2e-harness/common.sh +249 -0
  245. package/scripts/e2e-harness/screen.mjs +302 -0
  246. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  247. package/scripts/e2e-harness/type-filters.mjs +47 -0
  248. package/scripts/e2e-logs.sh +75 -0
  249. package/scripts/e2e-offline.sh +91 -0
  250. package/scripts/e2e-sweep.sh +370 -0
  251. package/scripts/e2e-warm.sh +114 -0
  252. package/scripts/zero-config-build.mjs +418 -0
  253. package/docs/1k-concurrent-users-executions.png +0 -0
  254. package/docs/plans/adapter-runtime-release.md +0 -362
  255. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  256. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  257. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  258. package/lib/image-optimization/handler-utils.d.ts +0 -34
  259. package/lib/image-optimization/handler-utils.js +0 -83
  260. package/lib/image-optimization/handler-utils.test.js +0 -178
  261. package/lib/nextjs-build/functions.Dockerfile +0 -31
  262. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  263. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  264. package/lib/utils/experimental-flags.d.ts +0 -24
  265. package/lib/utils/experimental-flags.js +0 -30
  266. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Loading and invoking build-output entrypoints.
3
+ *
4
+ * All four invocable output types — `app-page`, `app-route`, `page`, `page-api` —
5
+ * export the same `handler(req, res, ctx)` from
6
+ * `next/dist/build/templates/{app-page,app-route,pages,pages-api}.js`, so there
7
+ * is nothing to switch on: `AdapterEntrypoint.type` is carried for diagnostics,
8
+ * not dispatch.
9
+ *
10
+ * Loading is lazy and memoized per file. Lazy because a cold start that requires
11
+ * every route's module pays for the whole app on the first request; memoized
12
+ * because locale variants and `_next/data` siblings of one route all resolve to
13
+ * the same `filePath`.
14
+ */
15
+ import type { IncomingMessage, ServerResponse } from "node:http";
16
+ import { AdapterEntrypoint, AdapterManifest } from "./manifest";
17
+ /**
18
+ * Per-request context, the third argument of every entrypoint `handler`.
19
+ *
20
+ * `requestMeta` is `RequestMeta` from `next/dist/server/request-meta`, typed
21
+ * loosely here so this module does not need a `next` type import.
22
+ */
23
+ export interface EntrypointContext {
24
+ readonly waitUntil?: (promise: Promise<unknown>) => void;
25
+ readonly requestMeta?: Record<string, unknown>;
26
+ }
27
+ export type EntrypointHandler = (req: IncomingMessage, res: ServerResponse, ctx: EntrypointContext) => Promise<void | null | undefined>;
28
+ export declare class EntrypointRegistry {
29
+ private readonly root;
30
+ private readonly manifest;
31
+ private readonly handlers;
32
+ /**
33
+ * @param root absolute path the manifest's repo-root-relative `filePath`s
34
+ * resolve against — the staging root, which is `process.cwd()` at runtime.
35
+ * @param manifest used only to explain a failed load; see {@link ownedRouteError}.
36
+ */
37
+ constructor(root: string, manifest: AdapterManifest);
38
+ load(entrypoint: AdapterEntrypoint): Promise<EntrypointHandler>;
39
+ }
40
+ /**
41
+ * A request for a route packaged into another `functionGroups` group.
42
+ *
43
+ * The runtime answers it with a 308 to the URL's canonical spelling when case
44
+ * is the only difference (`caseCanonicalPath`), and a 404 otherwise, not a 500. The usual way here is a URL the
45
+ * edge matches differently from Next.js: CloudFront behaviors and API Gateway
46
+ * resources are case-sensitive and Next.js's route matching is not, so
47
+ * `/API/reports/1` misses the `api/reports/*` behavior, reaches the default
48
+ * group, and matches `/api/reports/[id]` there. At the edge that is a different
49
+ * URL, one no group serves, and a 404 says so; a 500 blamed the deployment.
50
+ */
51
+ export declare class RouteInOtherGroupError extends Error {
52
+ /** The group whose package has the route. */
53
+ readonly owner: string;
54
+ constructor(message: string,
55
+ /** The group whose package has the route. */
56
+ owner: string, options?: ErrorOptions);
57
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RouteInOtherGroupError = exports.EntrypointRegistry = void 0;
4
+ const node_path_1 = require("node:path");
5
+ const load_module_1 = require("./load-module");
6
+ const manifest_1 = require("./manifest");
7
+ class EntrypointRegistry {
8
+ root;
9
+ manifest;
10
+ handlers = new Map();
11
+ /**
12
+ * @param root absolute path the manifest's repo-root-relative `filePath`s
13
+ * resolve against — the staging root, which is `process.cwd()` at runtime.
14
+ * @param manifest used only to explain a failed load; see {@link ownedRouteError}.
15
+ */
16
+ constructor(root, manifest) {
17
+ this.root = root;
18
+ this.manifest = manifest;
19
+ }
20
+ load(entrypoint) {
21
+ let handler = this.handlers.get(entrypoint.filePath);
22
+ if (!handler) {
23
+ handler = loadEntrypointHandler(this.root, entrypoint, this.manifest);
24
+ // Cached as the promise so two concurrent first requests for one route
25
+ // share a single (expensive) module load.
26
+ this.handlers.set(entrypoint.filePath, handler);
27
+ // Evicted on failure, because the cache is keyed on the file and not on
28
+ // the attempt: a load can fail for a reason that has nothing to do with the
29
+ // file (EMFILE under a cold-start burst, an allocation near the memory
30
+ // limit), and a cached rejection makes that transient failure permanent —
31
+ // the same 500 for every later request until the sandbox is recycled.
32
+ handler.catch(() => {
33
+ if (this.handlers.get(entrypoint.filePath) === handler) {
34
+ this.handlers.delete(entrypoint.filePath);
35
+ }
36
+ });
37
+ }
38
+ return handler;
39
+ }
40
+ }
41
+ exports.EntrypointRegistry = EntrypointRegistry;
42
+ async function loadEntrypointHandler(root, entrypoint, manifest) {
43
+ const absolute = (0, node_path_1.join)(root, entrypoint.filePath);
44
+ let exports;
45
+ try {
46
+ exports = await (0, load_module_1.loadBuiltModule)(absolute);
47
+ }
48
+ catch (error) {
49
+ const message = `Could not load the entrypoint for "${entrypoint.id}" from ` +
50
+ `"${absolute}" (manifest filePath "${entrypoint.filePath}", type ` +
51
+ `"${entrypoint.type}"). The deployment package is incomplete.`;
52
+ const owner = owningGroup(entrypoint, manifest);
53
+ if (owner) {
54
+ throw new RouteInOtherGroupError(message + ownedRouteError(owner.self, owner.owner), owner.owner, { cause: error });
55
+ }
56
+ throw new Error(message, { cause: error });
57
+ }
58
+ return (0, load_module_1.requireFunctionExport)(exports, "handler", () => `The entrypoint for "${entrypoint.id}" at "${absolute}"`);
59
+ }
60
+ /**
61
+ * A request for a route packaged into another `functionGroups` group.
62
+ *
63
+ * The runtime answers it with a 308 to the URL's canonical spelling when case
64
+ * is the only difference (`caseCanonicalPath`), and a 404 otherwise, not a 500. The usual way here is a URL the
65
+ * edge matches differently from Next.js: CloudFront behaviors and API Gateway
66
+ * resources are case-sensitive and Next.js's route matching is not, so
67
+ * `/API/reports/1` misses the `api/reports/*` behavior, reaches the default
68
+ * group, and matches `/api/reports/[id]` there. At the edge that is a different
69
+ * URL, one no group serves, and a 404 says so; a 500 blamed the deployment.
70
+ */
71
+ class RouteInOtherGroupError extends Error {
72
+ owner;
73
+ constructor(message,
74
+ /** The group whose package has the route. */
75
+ owner, options) {
76
+ super(message, options);
77
+ this.owner = owner;
78
+ this.name = "RouteInOtherGroupError";
79
+ }
80
+ }
81
+ exports.RouteInOtherGroupError = RouteInOtherGroupError;
82
+ /**
83
+ * The one thing splitting can break that nothing else can: a request arriving at
84
+ * a function whose package does not contain the route.
85
+ *
86
+ * Every group ships the same manifest, so the function knows the route exists and
87
+ * which group owns it; what it does not have is the file. Without this the
88
+ * symptom is a module-not-found on a path nobody wrote, and the cause — a
89
+ * CloudFront behavior or API Gateway resource pointing at the wrong function, or
90
+ * a URL whose case the edge did not match — is several layers away. With it, the
91
+ * log names both groups.
92
+ */
93
+ function owningGroup(entrypoint, manifest) {
94
+ const groups = manifest.groups;
95
+ const self = process.env[manifest_1.FUNCTION_GROUP_ENV_VAR];
96
+ if (!groups || !self) {
97
+ return undefined;
98
+ }
99
+ const templates = Object.entries(manifest.entrypoints)
100
+ .filter(([, candidate]) => candidate.id === entrypoint.id)
101
+ .map(([template]) => template);
102
+ const owner = Object.entries(groups).find(([, owned]) => owned.some((template) => templates.includes(template)))?.[0];
103
+ return owner && owner !== self ? { self, owner } : undefined;
104
+ }
105
+ function ownedRouteError(self, owner) {
106
+ return (` This function is \`functionGroups\` group "${self}", but this route was ` +
107
+ `packaged into group "${owner}" — so the request reached the wrong function. ` +
108
+ `Check that the route pattern in group "${owner}" covers the URL that was ` +
109
+ `requested: a pattern can be too narrow at the edge while still claiming the ` +
110
+ `route at build time (for example "/reports/**" claims "/reports/[id]" but ` +
111
+ `the CloudFront behavior it becomes, "reports/*", does not match "/reports"), ` +
112
+ `and the edge matches case-sensitively where Next.js does not ("/API/x" ` +
113
+ `misses an "api/*" behavior).`);
114
+ }
115
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50cnlwb2ludHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9lbnRyeXBvaW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFlQSx5Q0FBaUM7QUFDakMsK0NBQXVFO0FBQ3ZFLHlDQUlvQjtBQW1CcEIsTUFBYSxrQkFBa0I7SUFTVjtJQUNBO0lBVEYsUUFBUSxHQUFHLElBQUksR0FBRyxFQUFzQyxDQUFDO0lBRTFFOzs7O09BSUc7SUFDSCxZQUNtQixJQUFZLEVBQ1osUUFBeUI7UUFEekIsU0FBSSxHQUFKLElBQUksQ0FBUTtRQUNaLGFBQVEsR0FBUixRQUFRLENBQWlCO0lBQ3pDLENBQUM7SUFFRyxJQUFJLENBQUMsVUFBNkI7UUFDdkMsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNiLE9BQU8sR0FBRyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDdEUsdUVBQXVFO1lBQ3ZFLDBDQUEwQztZQUMxQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2hELHdFQUF3RTtZQUN4RSw0RUFBNEU7WUFDNUUsdUVBQXVFO1lBQ3ZFLDBFQUEwRTtZQUMxRSxzRUFBc0U7WUFDdEUsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7Z0JBQ2pCLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLE9BQU8sRUFBRSxDQUFDO29CQUN2RCxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzVDLENBQUM7WUFD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Q0FBQyxDQUFDO0lBQ1AsT0FBTyxLQUFLLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUMvRCxDQUFDO0FBRUQsU0FBUyxlQUFlLENBQUMsSUFBWSxFQUFFLEtBQWE7SUFDbEQsT0FBTyxDQUNMLCtDQUErQyxJQUFJLHdCQUF3QjtRQUMzRSx3QkFBd0IsS0FBSyxpREFBaUQ7UUFDOUUsMENBQTBDLEtBQUssNEJBQTRCO1FBQzNFLDhFQUE4RTtRQUM5RSw0RUFBNEU7UUFDNUUsK0VBQStFO1FBQy9FLHlFQUF5RTtRQUN6RSw4QkFBOEIsQ0FDL0IsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIExvYWRpbmcgYW5kIGludm9raW5nIGJ1aWxkLW91dHB1dCBlbnRyeXBvaW50cy5cbiAqXG4gKiBBbGwgZm91ciBpbnZvY2FibGUgb3V0cHV0IHR5cGVzIOKAlCBgYXBwLXBhZ2VgLCBgYXBwLXJvdXRlYCwgYHBhZ2VgLCBgcGFnZS1hcGlgIOKAlFxuICogZXhwb3J0IHRoZSBzYW1lIGBoYW5kbGVyKHJlcSwgcmVzLCBjdHgpYCBmcm9tXG4gKiBgbmV4dC9kaXN0L2J1aWxkL3RlbXBsYXRlcy97YXBwLXBhZ2UsYXBwLXJvdXRlLHBhZ2VzLHBhZ2VzLWFwaX0uanNgLCBzbyB0aGVyZVxuICogaXMgbm90aGluZyB0byBzd2l0Y2ggb246IGBBZGFwdGVyRW50cnlwb2ludC50eXBlYCBpcyBjYXJyaWVkIGZvciBkaWFnbm9zdGljcyxcbiAqIG5vdCBkaXNwYXRjaC5cbiAqXG4gKiBMb2FkaW5nIGlzIGxhenkgYW5kIG1lbW9pemVkIHBlciBmaWxlLiBMYXp5IGJlY2F1c2UgYSBjb2xkIHN0YXJ0IHRoYXQgcmVxdWlyZXNcbiAqIGV2ZXJ5IHJvdXRlJ3MgbW9kdWxlIHBheXMgZm9yIHRoZSB3aG9sZSBhcHAgb24gdGhlIGZpcnN0IHJlcXVlc3Q7IG1lbW9pemVkXG4gKiBiZWNhdXNlIGxvY2FsZSB2YXJpYW50cyBhbmQgYF9uZXh0L2RhdGFgIHNpYmxpbmdzIG9mIG9uZSByb3V0ZSBhbGwgcmVzb2x2ZSB0b1xuICogdGhlIHNhbWUgYGZpbGVQYXRoYC5cbiAqL1xuaW1wb3J0IHR5cGUgeyBJbmNvbWluZ01lc3NhZ2UsIFNlcnZlclJlc3BvbnNlIH0gZnJvbSBcIm5vZGU6aHR0cFwiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGxvYWRCdWlsdE1vZHVsZSwgcmVxdWlyZUZ1bmN0aW9uRXhwb3J0IH0gZnJvbSBcIi4vbG9hZC1tb2R1bGVcIjtcbmltcG9ydCB7XG4gIEFkYXB0ZXJFbnRyeXBvaW50LFxuICBBZGFwdGVyTWFuaWZlc3QsXG4gIEZVTkNUSU9OX0dST1VQX0VOVl9WQVIsXG59IGZyb20gXCIuL21hbmlmZXN0XCI7XG5cbi8qKlxuICogUGVyLXJlcXVlc3QgY29udGV4dCwgdGhlIHRoaXJkIGFyZ3VtZW50IG9mIGV2ZXJ5IGVudHJ5cG9pbnQgYGhhbmRsZXJgLlxuICpcbiAqIGByZXF1ZXN0TWV0YWAgaXMgYFJlcXVlc3RNZXRhYCBmcm9tIGBuZXh0L2Rpc3Qvc2VydmVyL3JlcXVlc3QtbWV0YWAsIHR5cGVkXG4gKiBsb29zZWx5IGhlcmUgc28gdGhpcyBtb2R1bGUgZG9lcyBub3QgbmVlZCBhIGBuZXh0YCB0eXBlIGltcG9ydC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbnRyeXBvaW50Q29udGV4dCB7XG4gIHJlYWRvbmx5IHdhaXRVbnRpbD86IChwcm9taXNlOiBQcm9taXNlPHVua25vd24+KSA9PiB2b2lkO1xuICByZWFkb25seSByZXF1ZXN0TWV0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xufVxuXG5leHBvcnQgdHlwZSBFbnRyeXBvaW50SGFuZGxlciA9IChcbiAgcmVxOiBJbmNvbWluZ01lc3NhZ2UsXG4gIHJlczogU2VydmVyUmVzcG9uc2UsXG4gIGN0eDogRW50cnlwb2ludENvbnRleHQsXG4pID0+IFByb21pc2U8dm9pZCB8IG51bGwgfCB1bmRlZmluZWQ+O1xuXG5leHBvcnQgY2xhc3MgRW50cnlwb2ludFJlZ2lzdHJ5IHtcbiAgcHJpdmF0ZSByZWFkb25seSBoYW5kbGVycyA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPEVudHJ5cG9pbnRIYW5kbGVyPj4oKTtcblxuICAvKipcbiAgICogQHBhcmFtIHJvb3QgYWJzb2x1dGUgcGF0aCB0aGUgbWFuaWZlc3QncyByZXBvLXJvb3QtcmVsYXRpdmUgYGZpbGVQYXRoYHNcbiAgICogcmVzb2x2ZSBhZ2FpbnN0IOKAlCB0aGUgc3RhZ2luZyByb290LCB3aGljaCBpcyBgcHJvY2Vzcy5jd2QoKWAgYXQgcnVudGltZS5cbiAgICogQHBhcmFtIG1hbmlmZXN0IHVzZWQgb25seSB0byBleHBsYWluIGEgZmFpbGVkIGxvYWQ7IHNlZSB7QGxpbmsgb3duZWRSb3V0ZUVycm9yfS5cbiAgICovXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJvb3Q6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1hbmlmZXN0OiBBZGFwdGVyTWFuaWZlc3QsXG4gICkge31cblxuICBwdWJsaWMgbG9hZChlbnRyeXBvaW50OiBBZGFwdGVyRW50cnlwb2ludCk6IFByb21pc2U8RW50cnlwb2ludEhhbmRsZXI+IHtcbiAgICBsZXQgaGFuZGxlciA9IHRoaXMuaGFuZGxlcnMuZ2V0KGVudHJ5cG9pbnQuZmlsZVBhdGgpO1xuICAgIGlmICghaGFuZGxlcikge1xuICAgICAgaGFuZGxlciA9IGxvYWRFbnRyeXBvaW50SGFuZGxlcih0aGlzLnJvb3QsIGVudHJ5cG9pbnQsIHRoaXMubWFuaWZlc3QpO1xuICAgICAgLy8gQ2FjaGVkIGFzIHRoZSBwcm9taXNlIHNvIHR3byBjb25jdXJyZW50IGZpcnN0IHJlcXVlc3RzIGZvciBvbmUgcm91dGVcbiAgICAgIC8vIHNoYXJlIGEgc2luZ2xlIChleHBlbnNpdmUpIG1vZHVsZSBsb2FkLlxuICAgICAgdGhpcy5oYW5kbGVycy5zZXQoZW50cnlwb2ludC5maWxlUGF0aCwgaGFuZGxlcik7XG4gICAgICAvLyBFdmljdGVkIG9uIGZhaWx1cmUsIGJlY2F1c2UgdGhlIGNhY2hlIGlzIGtleWVkIG9uIHRoZSBmaWxlIGFuZCBub3Qgb25cbiAgICAgIC8vIHRoZSBhdHRlbXB0OiBhIGxvYWQgY2FuIGZhaWwgZm9yIGEgcmVhc29uIHRoYXQgaGFzIG5vdGhpbmcgdG8gZG8gd2l0aCB0aGVcbiAgICAgIC8vIGZpbGUgKEVNRklMRSB1bmRlciBhIGNvbGQtc3RhcnQgYnVyc3QsIGFuIGFsbG9jYXRpb24gbmVhciB0aGUgbWVtb3J5XG4gICAgICAvLyBsaW1pdCksIGFuZCBhIGNhY2hlZCByZWplY3Rpb24gbWFrZXMgdGhhdCB0cmFuc2llbnQgZmFpbHVyZSBwZXJtYW5lbnQg4oCUXG4gICAgICAvLyB0aGUgc2FtZSA1MDAgZm9yIGV2ZXJ5IGxhdGVyIHJlcXVlc3QgdW50aWwgdGhlIHNhbmRib3ggaXMgcmVjeWNsZWQuXG4gICAgICBoYW5kbGVyLmNhdGNoKCgpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaGFuZGxlcnMuZ2V0KGVudHJ5cG9pbnQuZmlsZVBhdGgpID09PSBoYW5kbGVyKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVycy5kZWxldGUoZW50cnlwb2ludC5maWxlUGF0aCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gaGFuZGxlcjtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBsb2FkRW50cnlwb2ludEhhbmRsZXIoXG4gIHJvb3Q6IHN0cmluZyxcbiAgZW50cnlwb2ludDogQWRhcHRlckVudHJ5cG9pbnQsXG4gIG1hbmlmZXN0OiBBZGFwdGVyTWFuaWZlc3QsXG4pOiBQcm9taXNlPEVudHJ5cG9pbnRIYW5kbGVyPiB7XG4gIGNvbnN0IGFic29sdXRlID0gam9pbihyb290LCBlbnRyeXBvaW50LmZpbGVQYXRoKTtcbiAgbGV0IGV4cG9ydHM6IHVua25vd247XG4gIHRyeSB7XG4gICAgZXhwb3J0cyA9IGF3YWl0IGxvYWRCdWlsdE1vZHVsZShhYnNvbHV0ZSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc3QgbWVzc2FnZSA9XG4gICAgICBgQ291bGQgbm90IGxvYWQgdGhlIGVudHJ5cG9pbnQgZm9yIFwiJHtlbnRyeXBvaW50LmlkfVwiIGZyb20gYCArXG4gICAgICBgXCIke2Fic29sdXRlfVwiIChtYW5pZmVzdCBmaWxlUGF0aCBcIiR7ZW50cnlwb2ludC5maWxlUGF0aH1cIiwgdHlwZSBgICtcbiAgICAgIGBcIiR7ZW50cnlwb2ludC50eXBlfVwiKS4gVGhlIGRlcGxveW1lbnQgcGFja2FnZSBpcyBpbmNvbXBsZXRlLmA7XG4gICAgY29uc3Qgb3duZXIgPSBvd25pbmdHcm91cChlbnRyeXBvaW50LCBtYW5pZmVzdCk7XG4gICAgaWYgKG93bmVyKSB7XG4gICAgICB0aHJvdyBuZXcgUm91dGVJbk90aGVyR3JvdXBFcnJvcihcbiAgICAgICAgbWVzc2FnZSArIG93bmVkUm91dGVFcnJvcihvd25lci5zZWxmLCBvd25lci5vd25lciksXG4gICAgICAgIG93bmVyLm93bmVyLFxuICAgICAgICB7IGNhdXNlOiBlcnJvciB9LFxuICAgICAgKTtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UsIHsgY2F1c2U6IGVycm9yIH0pO1xuICB9XG4gIHJldHVybiByZXF1aXJlRnVuY3Rpb25FeHBvcnQ8RW50cnlwb2ludEhhbmRsZXI+KFxuICAgIGV4cG9ydHMsXG4gICAgXCJoYW5kbGVyXCIsXG4gICAgKCkgPT4gYFRoZSBlbnRyeXBvaW50IGZvciBcIiR7ZW50cnlwb2ludC5pZH1cIiBhdCBcIiR7YWJzb2x1dGV9XCJgLFxuICApO1xufVxuXG4vKipcbiAqIEEgcmVxdWVzdCBmb3IgYSByb3V0ZSBwYWNrYWdlZCBpbnRvIGFub3RoZXIgYGZ1bmN0aW9uR3JvdXBzYCBncm91cC5cbiAqXG4gKiBUaGUgcnVudGltZSBhbnN3ZXJzIGl0IHdpdGggYSAzMDggdG8gdGhlIFVSTCdzIGNhbm9uaWNhbCBzcGVsbGluZyB3aGVuIGNhc2VcbiAqIGlzIHRoZSBvbmx5IGRpZmZlcmVuY2UgKGBjYXNlQ2Fub25pY2FsUGF0aGApLCBhbmQgYSA0MDQgb3RoZXJ3aXNlLCBub3QgYSA1MDAuIFRoZSB1c3VhbCB3YXkgaGVyZSBpcyBhIFVSTCB0aGVcbiAqIGVkZ2UgbWF0Y2hlcyBkaWZmZXJlbnRseSBmcm9tIE5leHQuanM6IENsb3VkRnJvbnQgYmVoYXZpb3JzIGFuZCBBUEkgR2F0ZXdheVxuICogcmVzb3VyY2VzIGFyZSBjYXNlLXNlbnNpdGl2ZSBhbmQgTmV4dC5qcydzIHJvdXRlIG1hdGNoaW5nIGlzIG5vdCwgc29cbiAqIGAvQVBJL3JlcG9ydHMvMWAgbWlzc2VzIHRoZSBgYXBpL3JlcG9ydHMvKmAgYmVoYXZpb3IsIHJlYWNoZXMgdGhlIGRlZmF1bHRcbiAqIGdyb3VwLCBhbmQgbWF0Y2hlcyBgL2FwaS9yZXBvcnRzL1tpZF1gIHRoZXJlLiBBdCB0aGUgZWRnZSB0aGF0IGlzIGEgZGlmZmVyZW50XG4gKiBVUkwsIG9uZSBubyBncm91cCBzZXJ2ZXMsIGFuZCBhIDQwNCBzYXlzIHNvOyBhIDUwMCBibGFtZWQgdGhlIGRlcGxveW1lbnQuXG4gKi9cbmV4cG9ydCBjbGFzcyBSb3V0ZUluT3RoZXJHcm91cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgbWVzc2FnZTogc3RyaW5nLFxuICAgIC8qKiBUaGUgZ3JvdXAgd2hvc2UgcGFja2FnZSBoYXMgdGhlIHJvdXRlLiAqL1xuICAgIHB1YmxpYyByZWFkb25seSBvd25lcjogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBFcnJvck9wdGlvbnMsXG4gICkge1xuICAgIHN1cGVyKG1lc3NhZ2UsIG9wdGlvbnMpO1xuICAgIHRoaXMubmFtZSA9IFwiUm91dGVJbk90aGVyR3JvdXBFcnJvclwiO1xuICB9XG59XG5cbi8qKlxuICogVGhlIG9uZSB0aGluZyBzcGxpdHRpbmcgY2FuIGJyZWFrIHRoYXQgbm90aGluZyBlbHNlIGNhbjogYSByZXF1ZXN0IGFycml2aW5nIGF0XG4gKiBhIGZ1bmN0aW9uIHdob3NlIHBhY2thZ2UgZG9lcyBub3QgY29udGFpbiB0aGUgcm91dGUuXG4gKlxuICogRXZlcnkgZ3JvdXAgc2hpcHMgdGhlIHNhbWUgbWFuaWZlc3QsIHNvIHRoZSBmdW5jdGlvbiBrbm93cyB0aGUgcm91dGUgZXhpc3RzIGFuZFxuICogd2hpY2ggZ3JvdXAgb3ducyBpdDsgd2hhdCBpdCBkb2VzIG5vdCBoYXZlIGlzIHRoZSBmaWxlLiBXaXRob3V0IHRoaXMgdGhlXG4gKiBzeW1wdG9tIGlzIGEgbW9kdWxlLW5vdC1mb3VuZCBvbiBhIHBhdGggbm9ib2R5IHdyb3RlLCBhbmQgdGhlIGNhdXNlIOKAlCBhXG4gKiBDbG91ZEZyb250IGJlaGF2aW9yIG9yIEFQSSBHYXRld2F5IHJlc291cmNlIHBvaW50aW5nIGF0IHRoZSB3cm9uZyBmdW5jdGlvbiwgb3JcbiAqIGEgVVJMIHdob3NlIGNhc2UgdGhlIGVkZ2UgZGlkIG5vdCBtYXRjaCDigJQgaXMgc2V2ZXJhbCBsYXllcnMgYXdheS4gV2l0aCBpdCwgdGhlXG4gKiBsb2cgbmFtZXMgYm90aCBncm91cHMuXG4gKi9cbmZ1bmN0aW9uIG93bmluZ0dyb3VwKFxuICBlbnRyeXBvaW50OiBBZGFwdGVyRW50cnlwb2ludCxcbiAgbWFuaWZlc3Q6IEFkYXB0ZXJNYW5pZmVzdCxcbik6IHsgcmVhZG9ubHkgc2VsZjogc3RyaW5nOyByZWFkb25seSBvd25lcjogc3RyaW5nIH0gfCB1bmRlZmluZWQge1xuICBjb25zdCBncm91cHMgPSBtYW5pZmVzdC5ncm91cHM7XG4gIGNvbnN0IHNlbGYgPSBwcm9jZXNzLmVudltGVU5DVElPTl9HUk9VUF9FTlZfVkFSXTtcbiAgaWYgKCFncm91cHMgfHwgIXNlbGYpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IHRlbXBsYXRlcyA9IE9iamVjdC5lbnRyaWVzKG1hbmlmZXN0LmVudHJ5cG9pbnRzKVxuICAgIC5maWx0ZXIoKFssIGNhbmRpZGF0ZV0pID0+IGNhbmRpZGF0ZS5pZCA9PT0gZW50cnlwb2ludC5pZClcbiAgICAubWFwKChbdGVtcGxhdGVdKSA9PiB0ZW1wbGF0ZSk7XG4gIGNvbnN0IG93bmVyID0gT2JqZWN0LmVudHJpZXMoZ3JvdXBzKS5maW5kKChbLCBvd25lZF0pID0+XG4gICAgb3duZWQuc29tZSgodGVtcGxhdGUpID0+IHRlbXBsYXRlcy5pbmNsdWRlcyh0ZW1wbGF0ZSkpLFxuICApPy5bMF07XG4gIHJldHVybiBvd25lciAmJiBvd25lciAhPT0gc2VsZiA/IHsgc2VsZiwgb3duZXIgfSA6IHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gb3duZWRSb3V0ZUVycm9yKHNlbGY6IHN0cmluZywgb3duZXI6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiAoXG4gICAgYCBUaGlzIGZ1bmN0aW9uIGlzIFxcYGZ1bmN0aW9uR3JvdXBzXFxgIGdyb3VwIFwiJHtzZWxmfVwiLCBidXQgdGhpcyByb3V0ZSB3YXMgYCArXG4gICAgYHBhY2thZ2VkIGludG8gZ3JvdXAgXCIke293bmVyfVwiIOKAlCBzbyB0aGUgcmVxdWVzdCByZWFjaGVkIHRoZSB3cm9uZyBmdW5jdGlvbi4gYCArXG4gICAgYENoZWNrIHRoYXQgdGhlIHJvdXRlIHBhdHRlcm4gaW4gZ3JvdXAgXCIke293bmVyfVwiIGNvdmVycyB0aGUgVVJMIHRoYXQgd2FzIGAgK1xuICAgIGByZXF1ZXN0ZWQ6IGEgcGF0dGVybiBjYW4gYmUgdG9vIG5hcnJvdyBhdCB0aGUgZWRnZSB3aGlsZSBzdGlsbCBjbGFpbWluZyB0aGUgYCArXG4gICAgYHJvdXRlIGF0IGJ1aWxkIHRpbWUgKGZvciBleGFtcGxlIFwiL3JlcG9ydHMvKipcIiBjbGFpbXMgXCIvcmVwb3J0cy9baWRdXCIgYnV0IGAgK1xuICAgIGB0aGUgQ2xvdWRGcm9udCBiZWhhdmlvciBpdCBiZWNvbWVzLCBcInJlcG9ydHMvKlwiLCBkb2VzIG5vdCBtYXRjaCBcIi9yZXBvcnRzXCIpLCBgICtcbiAgICBgYW5kIHRoZSBlZGdlIG1hdGNoZXMgY2FzZS1zZW5zaXRpdmVseSB3aGVyZSBOZXh0LmpzIGRvZXMgbm90IChcIi9BUEkveFwiIGAgK1xuICAgIGBtaXNzZXMgYW4gXCJhcGkvKlwiIGJlaGF2aW9yKS5gXG4gICk7XG59XG4iXX0=
@@ -0,0 +1,6 @@
1
+ /**
2
+ * An `AbortSignal` that fires when the client of a `node:http` request goes
3
+ * away, for the Containers shell to hand the runtime as `RuntimeRequest.signal`.
4
+ */
5
+ import type { IncomingMessage, ServerResponse } from "node:http";
6
+ export declare function clientAbortSignal(req: IncomingMessage, res: ServerResponse): AbortSignal;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientAbortSignal = clientAbortSignal;
4
+ function clientAbortSignal(req, res) {
5
+ const aborted = new AbortController();
6
+ req.once("aborted", () => aborted.abort());
7
+ // `aborted` only fires while the request body is still arriving. A client that
8
+ // sent a complete request and then left — a long-poll, an SSE stream — is only
9
+ // seen as the response's socket closing before the response finished, which
10
+ // is also how `next start` notices it (`res.on('close')` in
11
+ // `signalFromNodeResponse`).
12
+ res.once("close", () => {
13
+ if (!res.writableFinished) {
14
+ aborted.abort();
15
+ }
16
+ });
17
+ return aborted.signal;
18
+ }
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJvcnQtc2lnbmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3J1bnRpbWUvaHR0cC9hYm9ydC1zaWduYWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFNQSw4Q0FpQkM7QUFqQkQsU0FBZ0IsaUJBQWlCLENBQy9CLEdBQW9CLEVBQ3BCLEdBQW1CO0lBRW5CLE1BQU0sT0FBTyxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7SUFDdEMsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDM0MsK0VBQStFO0lBQy9FLCtFQUErRTtJQUMvRSw0RUFBNEU7SUFDNUUsNERBQTREO0lBQzVELDZCQUE2QjtJQUM3QixHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUU7UUFDckIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzFCLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNsQixDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDSCxPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUM7QUFDeEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQW4gYEFib3J0U2lnbmFsYCB0aGF0IGZpcmVzIHdoZW4gdGhlIGNsaWVudCBvZiBhIGBub2RlOmh0dHBgIHJlcXVlc3QgZ29lc1xuICogYXdheSwgZm9yIHRoZSBDb250YWluZXJzIHNoZWxsIHRvIGhhbmQgdGhlIHJ1bnRpbWUgYXMgYFJ1bnRpbWVSZXF1ZXN0LnNpZ25hbGAuXG4gKi9cbmltcG9ydCB0eXBlIHsgSW5jb21pbmdNZXNzYWdlLCBTZXJ2ZXJSZXNwb25zZSB9IGZyb20gXCJub2RlOmh0dHBcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIGNsaWVudEFib3J0U2lnbmFsKFxuICByZXE6IEluY29taW5nTWVzc2FnZSxcbiAgcmVzOiBTZXJ2ZXJSZXNwb25zZSxcbik6IEFib3J0U2lnbmFsIHtcbiAgY29uc3QgYWJvcnRlZCA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgcmVxLm9uY2UoXCJhYm9ydGVkXCIsICgpID0+IGFib3J0ZWQuYWJvcnQoKSk7XG4gIC8vIGBhYm9ydGVkYCBvbmx5IGZpcmVzIHdoaWxlIHRoZSByZXF1ZXN0IGJvZHkgaXMgc3RpbGwgYXJyaXZpbmcuIEEgY2xpZW50IHRoYXRcbiAgLy8gc2VudCBhIGNvbXBsZXRlIHJlcXVlc3QgYW5kIHRoZW4gbGVmdCDigJQgYSBsb25nLXBvbGwsIGFuIFNTRSBzdHJlYW0g4oCUIGlzIG9ubHlcbiAgLy8gc2VlbiBhcyB0aGUgcmVzcG9uc2UncyBzb2NrZXQgY2xvc2luZyBiZWZvcmUgdGhlIHJlc3BvbnNlIGZpbmlzaGVkLCB3aGljaFxuICAvLyBpcyBhbHNvIGhvdyBgbmV4dCBzdGFydGAgbm90aWNlcyBpdCAoYHJlcy5vbignY2xvc2UnKWAgaW5cbiAgLy8gYHNpZ25hbEZyb21Ob2RlUmVzcG9uc2VgKS5cbiAgcmVzLm9uY2UoXCJjbG9zZVwiLCAoKSA9PiB7XG4gICAgaWYgKCFyZXMud3JpdGFibGVGaW5pc2hlZCkge1xuICAgICAgYWJvcnRlZC5hYm9ydCgpO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiBhYm9ydGVkLnNpZ25hbDtcbn1cbiJdfQ==
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_http_1 = require("node:http");
4
+ const abort_signal_1 = require("./abort-signal");
5
+ /** A server whose handler hands each request's signal to `onSignal`. */
6
+ function listen(handler) {
7
+ const server = (0, node_http_1.createServer)((req, res) => handler((0, abort_signal_1.clientAbortSignal)(req, res), res));
8
+ return new Promise((resolve) => server.listen(0, "127.0.0.1", () => resolve({ server, port: server.address().port })));
9
+ }
10
+ describe("clientAbortSignal", () => {
11
+ let server;
12
+ afterEach(() => new Promise((resolve) => server ? server.close(() => resolve()) : resolve()));
13
+ // A long-poll: the request is complete, so `aborted` never fires on it.
14
+ it("fires when the client leaves after sending a complete request", async () => {
15
+ let signal;
16
+ const seen = new Promise((resolve) => {
17
+ void listen((s, res) => {
18
+ signal = s;
19
+ res.writeHead(200);
20
+ res.write("waiting");
21
+ s.addEventListener("abort", () => resolve());
22
+ }).then((listening) => {
23
+ server = listening.server;
24
+ const req = (0, node_http_1.request)({ port: listening.port, path: "/" }, (res) => {
25
+ res.once("data", () => req.destroy());
26
+ });
27
+ req.end();
28
+ });
29
+ });
30
+ await seen;
31
+ expect(signal.aborted).toBe(true);
32
+ });
33
+ it("stays quiet for a response that finished", async () => {
34
+ let signal;
35
+ const closed = new Promise((resolve) => {
36
+ void listen((s, res) => {
37
+ signal = s;
38
+ res.once("close", () => resolve());
39
+ res.end("done");
40
+ }).then((listening) => {
41
+ server = listening.server;
42
+ (0, node_http_1.request)({ port: listening.port, path: "/" }, (res) => res.resume()).end();
43
+ });
44
+ });
45
+ await closed;
46
+ expect(signal.aborted).toBe(false);
47
+ });
48
+ });
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJvcnQtc2lnbmFsLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcnVudGltZS9odHRwL2Fib3J0LXNpZ25hbC50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEseUNBQTBEO0FBRTFELGlEQUFtRDtBQUVuRCx3RUFBd0U7QUFDeEUsU0FBUyxNQUFNLENBQ2IsT0FHUztJQUVULE1BQU0sTUFBTSxHQUFHLElBQUEsd0JBQVksRUFBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUN2QyxPQUFPLENBQUMsSUFBQSxnQ0FBaUIsRUFBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQzFDLENBQUM7SUFDRixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FDN0IsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLEdBQUcsRUFBRSxDQUNqQyxPQUFPLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFHLE1BQU0sQ0FBQyxPQUFPLEVBQWtCLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FDbEUsQ0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxHQUFHLEVBQUU7SUFDakMsSUFBSSxNQUEwQixDQUFDO0lBQy9CLFNBQVMsQ0FDUCxHQUFHLEVBQUUsQ0FDSCxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQzVCLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FDbkQsQ0FDSixDQUFDO0lBRUYsd0VBQXdFO0lBQ3hFLEVBQUUsQ0FBQywrREFBK0QsRUFBRSxLQUFLLElBQUksRUFBRTtRQUM3RSxJQUFJLE1BQW9CLENBQUM7UUFDekIsTUFBTSxJQUFJLEdBQUcsSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUN6QyxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRTtnQkFDckIsTUFBTSxHQUFHLENBQUMsQ0FBQztnQkFDWCxHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNuQixHQUFHLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNyQixDQUFDLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDL0MsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUU7Z0JBQ3BCLE1BQU0sR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO2dCQUMxQixNQUFNLEdBQUcsR0FBRyxJQUFBLG1CQUFPLEVBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtvQkFDL0QsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7Z0JBQ3hDLENBQUMsQ0FBQyxDQUFDO2dCQUNILEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNaLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLElBQUksQ0FBQztRQUNYLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3BDLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLDBDQUEwQyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ3hELElBQUksTUFBb0IsQ0FBQztRQUN6QixNQUFNLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQzNDLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFO2dCQUNyQixNQUFNLEdBQUcsQ0FBQyxDQUFDO2dCQUNYLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7Z0JBQ25DLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDbEIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUU7Z0JBQ3BCLE1BQU0sR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO2dCQUMxQixJQUFBLG1CQUFPLEVBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUNuRCxHQUFHLENBQUMsTUFBTSxFQUFFLENBQ2IsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNWLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLE1BQU0sQ0FBQztRQUNiLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVTZXJ2ZXIsIHJlcXVlc3QsIFNlcnZlciB9IGZyb20gXCJub2RlOmh0dHBcIjtcbmltcG9ydCB0eXBlIHsgQWRkcmVzc0luZm8gfSBmcm9tIFwibm9kZTpuZXRcIjtcbmltcG9ydCB7IGNsaWVudEFib3J0U2lnbmFsIH0gZnJvbSBcIi4vYWJvcnQtc2lnbmFsXCI7XG5cbi8qKiBBIHNlcnZlciB3aG9zZSBoYW5kbGVyIGhhbmRzIGVhY2ggcmVxdWVzdCdzIHNpZ25hbCB0byBgb25TaWduYWxgLiAqL1xuZnVuY3Rpb24gbGlzdGVuKFxuICBoYW5kbGVyOiAoXG4gICAgc2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgICByZXM6IGltcG9ydChcIm5vZGU6aHR0cFwiKS5TZXJ2ZXJSZXNwb25zZSxcbiAgKSA9PiB2b2lkLFxuKTogUHJvbWlzZTx7IHNlcnZlcjogU2VydmVyOyBwb3J0OiBudW1iZXIgfT4ge1xuICBjb25zdCBzZXJ2ZXIgPSBjcmVhdGVTZXJ2ZXIoKHJlcSwgcmVzKSA9PlxuICAgIGhhbmRsZXIoY2xpZW50QWJvcnRTaWduYWwocmVxLCByZXMpLCByZXMpLFxuICApO1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgc2VydmVyLmxpc3RlbigwLCBcIjEyNy4wLjAuMVwiLCAoKSA9PlxuICAgICAgcmVzb2x2ZSh7IHNlcnZlciwgcG9ydDogKHNlcnZlci5hZGRyZXNzKCkgYXMgQWRkcmVzc0luZm8pLnBvcnQgfSksXG4gICAgKSxcbiAgKTtcbn1cblxuZGVzY3JpYmUoXCJjbGllbnRBYm9ydFNpZ25hbFwiLCAoKSA9PiB7XG4gIGxldCBzZXJ2ZXI6IFNlcnZlciB8IHVuZGVmaW5lZDtcbiAgYWZ0ZXJFYWNoKFxuICAgICgpID0+XG4gICAgICBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT5cbiAgICAgICAgc2VydmVyID8gc2VydmVyLmNsb3NlKCgpID0+IHJlc29sdmUoKSkgOiByZXNvbHZlKCksXG4gICAgICApLFxuICApO1xuXG4gIC8vIEEgbG9uZy1wb2xsOiB0aGUgcmVxdWVzdCBpcyBjb21wbGV0ZSwgc28gYGFib3J0ZWRgIG5ldmVyIGZpcmVzIG9uIGl0LlxuICBpdChcImZpcmVzIHdoZW4gdGhlIGNsaWVudCBsZWF2ZXMgYWZ0ZXIgc2VuZGluZyBhIGNvbXBsZXRlIHJlcXVlc3RcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGxldCBzaWduYWwhOiBBYm9ydFNpZ25hbDtcbiAgICBjb25zdCBzZWVuID0gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgIHZvaWQgbGlzdGVuKChzLCByZXMpID0+IHtcbiAgICAgICAgc2lnbmFsID0gcztcbiAgICAgICAgcmVzLndyaXRlSGVhZCgyMDApO1xuICAgICAgICByZXMud3JpdGUoXCJ3YWl0aW5nXCIpO1xuICAgICAgICBzLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCAoKSA9PiByZXNvbHZlKCkpO1xuICAgICAgfSkudGhlbigobGlzdGVuaW5nKSA9PiB7XG4gICAgICAgIHNlcnZlciA9IGxpc3RlbmluZy5zZXJ2ZXI7XG4gICAgICAgIGNvbnN0IHJlcSA9IHJlcXVlc3QoeyBwb3J0OiBsaXN0ZW5pbmcucG9ydCwgcGF0aDogXCIvXCIgfSwgKHJlcykgPT4ge1xuICAgICAgICAgIHJlcy5vbmNlKFwiZGF0YVwiLCAoKSA9PiByZXEuZGVzdHJveSgpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJlcS5lbmQoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGF3YWl0IHNlZW47XG4gICAgZXhwZWN0KHNpZ25hbC5hYm9ydGVkKS50b0JlKHRydWUpO1xuICB9KTtcblxuICBpdChcInN0YXlzIHF1aWV0IGZvciBhIHJlc3BvbnNlIHRoYXQgZmluaXNoZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGxldCBzaWduYWwhOiBBYm9ydFNpZ25hbDtcbiAgICBjb25zdCBjbG9zZWQgPSBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgdm9pZCBsaXN0ZW4oKHMsIHJlcykgPT4ge1xuICAgICAgICBzaWduYWwgPSBzO1xuICAgICAgICByZXMub25jZShcImNsb3NlXCIsICgpID0+IHJlc29sdmUoKSk7XG4gICAgICAgIHJlcy5lbmQoXCJkb25lXCIpO1xuICAgICAgfSkudGhlbigobGlzdGVuaW5nKSA9PiB7XG4gICAgICAgIHNlcnZlciA9IGxpc3RlbmluZy5zZXJ2ZXI7XG4gICAgICAgIHJlcXVlc3QoeyBwb3J0OiBsaXN0ZW5pbmcucG9ydCwgcGF0aDogXCIvXCIgfSwgKHJlcykgPT5cbiAgICAgICAgICByZXMucmVzdW1lKCksXG4gICAgICAgICkuZW5kKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBhd2FpdCBjbG9zZWQ7XG4gICAgZXhwZWN0KHNpZ25hbC5hYm9ydGVkKS50b0JlKGZhbHNlKTtcbiAgfSk7XG59KTtcbiJdfQ==
@@ -0,0 +1,38 @@
1
+ import type { IncomingHttpHeaders, IncomingMessage, Server } from "node:http";
2
+ import type { NextjsRuntime } from "../core";
3
+ /** Methods RFC 9110 allows a body on, and only when one is actually framed. */
4
+ export declare function hasRequestBody(req: IncomingMessage): boolean;
5
+ export interface RuntimeServer {
6
+ readonly server: Server;
7
+ /**
8
+ * Stops accepting connections, then resolves once the open ones are gone and
9
+ * every request's `waitUntil` work has settled.
10
+ */
11
+ shutdown(): Promise<void>;
12
+ }
13
+ export interface RuntimeServerOptions {
14
+ /**
15
+ * Whether every request comes through CloudFront, which sets
16
+ * `cloudfront-forwarded-proto` itself. True only on Global Containers, whose
17
+ * ALB is reachable through the distribution's VPC origin alone
18
+ * (`CDK_NEXTJS_TRUST_CLOUDFRONT_PROTO`, set by the construct). See
19
+ * {@link viewerHeaders}.
20
+ */
21
+ readonly trustCloudFrontProto?: boolean;
22
+ }
23
+ export declare function createRuntimeServer(runtime: Pick<NextjsRuntime, "handle">, options?: RuntimeServerOptions): RuntimeServer;
24
+ /**
25
+ * The request's headers, with `x-forwarded-proto` naming the viewer's protocol
26
+ * when that is known.
27
+ *
28
+ * Behind CloudFront without a certificate, CloudFront reaches the ALB over plain
29
+ * HTTP, so the ALB's `x-forwarded-proto` is `http` for an app every viewer
30
+ * reaches over HTTPS. The runtime builds absolute URLs from it - `request.url`,
31
+ * `req.nextUrl.origin`, and the origin Next.js forwards a server action to,
32
+ * where CloudFront then answered 307 and `test/e2e/app-dir/action-forward-loop`
33
+ * failed. CloudFront's own `cloudfront-forwarded-proto` is the viewer's, but it
34
+ * is trusted only when every request comes through CloudFront: anywhere else a
35
+ * client could send it straight to the ALB and pick the scheme of URLs a cached
36
+ * page then serves to everyone.
37
+ */
38
+ export declare function viewerHeaders(headers: IncomingHttpHeaders, trustCloudFrontProto: boolean | undefined): IncomingHttpHeaders;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasRequestBody = hasRequestBody;
4
+ exports.createRuntimeServer = createRuntimeServer;
5
+ exports.viewerHeaders = viewerHeaders;
6
+ /**
7
+ * The container shell's `node:http` server, and its shutdown.
8
+ *
9
+ * Its own module rather than inline in `server.mts` so it can be tested without
10
+ * starting the server that module starts on import.
11
+ */
12
+ const node_http_1 = require("node:http");
13
+ const abort_signal_1 = require("./abort-signal");
14
+ const node_sink_1 = require("./node-sink");
15
+ /**
16
+ * Longer than the ALB's idle timeout (60 s by default). With Node's default of
17
+ * 5 s, the server closes keep-alive connections the ALB still considers open;
18
+ * the ALB answers the next request on one with a 502, and CloudFront caches
19
+ * that 502 for its error caching TTL, failing every request for the path until
20
+ * it expires. An ALB with a longer idle timeout needs this raised to match.
21
+ * https://docs.aws.amazon.com/elasticloadbalancing/latest/application/edit-load-balancer-attributes.html#connection-idle-timeout
22
+ */
23
+ const KEEP_ALIVE_TIMEOUT_MS = 65_000;
24
+ /** Methods RFC 9110 allows a body on, and only when one is actually framed. */
25
+ function hasRequestBody(req) {
26
+ if (req.method === "GET" || req.method === "HEAD") {
27
+ return false;
28
+ }
29
+ return (req.headers["content-length"] !== undefined ||
30
+ req.headers["transfer-encoding"] !== undefined);
31
+ }
32
+ function createRuntimeServer(runtime, options = {}) {
33
+ // `handle` resolves only once the `waitUntil` work a request registered — ISR
34
+ // revalidation, notably — has settled, which is after its response and its
35
+ // connection are done. Tracked so shutdown can wait for that too.
36
+ const inFlight = new Set();
37
+ const server = (0, node_http_1.createServer)((req, res) => {
38
+ const handled = serve(runtime, req, res, options)
39
+ .catch((error) => {
40
+ // `NextjsRuntime.handle` answers 500 itself, so reaching this means the
41
+ // shell's own translation failed.
42
+ console.error("The container shell failed to handle a request:", error);
43
+ if (!res.headersSent) {
44
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
45
+ }
46
+ res.end("Internal Server Error");
47
+ })
48
+ .finally(() => inFlight.delete(handled));
49
+ inFlight.add(handled);
50
+ });
51
+ server.keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS;
52
+ // must exceed keepAliveTimeout, or Node can drop a connection that just
53
+ // started sending a request's headers
54
+ server.headersTimeout = KEEP_ALIVE_TIMEOUT_MS + 1_000;
55
+ // `server.close` alone is not enough: it calls back once the connections are
56
+ // gone, and a revalidation still running in `waitUntil` would be killed
57
+ // mid-write, losing the fresh entry.
58
+ const shutdown = () => new Promise((resolve) => {
59
+ server.close(() => {
60
+ void Promise.allSettled(inFlight).then(() => resolve());
61
+ });
62
+ });
63
+ return { server, shutdown };
64
+ }
65
+ /**
66
+ * The request's headers, with `x-forwarded-proto` naming the viewer's protocol
67
+ * when that is known.
68
+ *
69
+ * Behind CloudFront without a certificate, CloudFront reaches the ALB over plain
70
+ * HTTP, so the ALB's `x-forwarded-proto` is `http` for an app every viewer
71
+ * reaches over HTTPS. The runtime builds absolute URLs from it - `request.url`,
72
+ * `req.nextUrl.origin`, and the origin Next.js forwards a server action to,
73
+ * where CloudFront then answered 307 and `test/e2e/app-dir/action-forward-loop`
74
+ * failed. CloudFront's own `cloudfront-forwarded-proto` is the viewer's, but it
75
+ * is trusted only when every request comes through CloudFront: anywhere else a
76
+ * client could send it straight to the ALB and pick the scheme of URLs a cached
77
+ * page then serves to everyone.
78
+ */
79
+ function viewerHeaders(headers, trustCloudFrontProto) {
80
+ const viewerProto = headers["cloudfront-forwarded-proto"];
81
+ if (!trustCloudFrontProto || typeof viewerProto !== "string") {
82
+ return headers;
83
+ }
84
+ return { ...headers, "x-forwarded-proto": viewerProto };
85
+ }
86
+ async function serve(runtime, req, res, options) {
87
+ await runtime.handle({
88
+ method: req.method ?? "GET",
89
+ url: req.url ?? "/",
90
+ headers: viewerHeaders(req.headers, options.trustCloudFrontProto),
91
+ body: hasRequestBody(req) ? req : undefined,
92
+ remoteAddress: req.socket.remoteAddress,
93
+ // TLS terminates at the ALB (Regional) or CloudFront (Global); the hop to
94
+ // this container is plaintext HTTP/1.1.
95
+ encrypted: false,
96
+ signal: (0, abort_signal_1.clientAbortSignal)(req, res),
97
+ }, new node_sink_1.NodeResponseSink(res));
98
+ }
99
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1zZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcnVudGltZS9odHRwL25vZGUtc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBNEJBLHdDQVFDO0FBc0JELGtEQXVDQztBQWdCRCxzQ0FTQztBQTFIRDs7Ozs7R0FLRztBQUNILHlDQUF5QztBQVF6QyxpREFBbUQ7QUFDbkQsMkNBQStDO0FBRS9DOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLHFCQUFxQixHQUFHLE1BQU0sQ0FBQztBQUVyQywrRUFBK0U7QUFDL0UsU0FBZ0IsY0FBYyxDQUFDLEdBQW9CO0lBQ2pELElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxLQUFLLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxNQUFNLEVBQUUsQ0FBQztRQUNsRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxPQUFPLENBQ0wsR0FBRyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLFNBQVM7UUFDM0MsR0FBRyxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLFNBQVMsQ0FDL0MsQ0FBQztBQUNKLENBQUM7QUFzQkQsU0FBZ0IsbUJBQW1CLENBQ2pDLE9BQXNDLEVBQ3RDLFVBQWdDLEVBQUU7SUFFbEMsOEVBQThFO0lBQzlFLDJFQUEyRTtJQUMzRSxrRUFBa0U7SUFDbEUsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQWlCLENBQUM7SUFFMUMsTUFBTSxNQUFNLEdBQUcsSUFBQSx3QkFBWSxFQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO1FBQ3ZDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUM7YUFDOUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDZix3RUFBd0U7WUFDeEUsa0NBQWtDO1lBQ2xDLE9BQU8sQ0FBQyxLQUFLLENBQUMsaURBQWlELEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDeEUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDckIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxjQUFjLEVBQUUsMkJBQTJCLEVBQUUsQ0FBQyxDQUFDO1lBQ3RFLENBQUM7WUFDRCxHQUFHLENBQUMsR0FBRyxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFDbkMsQ0FBQyxDQUFDO2FBQ0QsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUMzQyxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3hCLENBQUMsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxDQUFDLGdCQUFnQixHQUFHLHFCQUFxQixDQUFDO0lBQ2hELHdFQUF3RTtJQUN4RSxzQ0FBc0M7SUFDdEMsTUFBTSxDQUFDLGNBQWMsR0FBRyxxQkFBcUIsR0FBRyxLQUFLLENBQUM7SUFFdEQsNkVBQTZFO0lBQzdFLHdFQUF3RTtJQUN4RSxxQ0FBcUM7SUFDckMsTUFBTSxRQUFRLEdBQUcsR0FBRyxFQUFFLENBQ3BCLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDNUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7WUFDaEIsS0FBSyxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQzFELENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFTCxPQUFPLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDO0FBQzlCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsU0FBZ0IsYUFBYSxDQUMzQixPQUE0QixFQUM1QixvQkFBeUM7SUFFekMsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixDQUFDLENBQUM7SUFDMUQsSUFBSSxDQUFDLG9CQUFvQixJQUFJLE9BQU8sV0FBVyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzdELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFDRCxPQUFPLEVBQUUsR0FBRyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsV0FBVyxFQUFFLENBQUM7QUFDMUQsQ0FBQztBQUVELEtBQUssVUFBVSxLQUFLLENBQ2xCLE9BQXNDLEVBQ3RDLEdBQW9CLEVBQ3BCLEdBQW1CLEVBQ25CLE9BQTZCO0lBRTdCLE1BQU0sT0FBTyxDQUFDLE1BQU0sQ0FDbEI7UUFDRSxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sSUFBSSxLQUFLO1FBQzNCLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUc7UUFDbkIsT0FBTyxFQUFFLGFBQWEsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQztRQUNqRSxJQUFJLEVBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVM7UUFDM0MsYUFBYSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYTtRQUN2QywwRUFBMEU7UUFDMUUsd0NBQXdDO1FBQ3hDLFNBQVMsRUFBRSxLQUFLO1FBQ2hCLE1BQU0sRUFBRSxJQUFBLGdDQUFpQixFQUFDLEdBQUcsRUFBRSxHQUFHLENBQUM7S0FDcEMsRUFDRCxJQUFJLDRCQUFnQixDQUFDLEdBQUcsQ0FBQyxDQUMxQixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhlIGNvbnRhaW5lciBzaGVsbCdzIGBub2RlOmh0dHBgIHNlcnZlciwgYW5kIGl0cyBzaHV0ZG93bi5cbiAqXG4gKiBJdHMgb3duIG1vZHVsZSByYXRoZXIgdGhhbiBpbmxpbmUgaW4gYHNlcnZlci5tdHNgIHNvIGl0IGNhbiBiZSB0ZXN0ZWQgd2l0aG91dFxuICogc3RhcnRpbmcgdGhlIHNlcnZlciB0aGF0IG1vZHVsZSBzdGFydHMgb24gaW1wb3J0LlxuICovXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXIgfSBmcm9tIFwibm9kZTpodHRwXCI7XG5pbXBvcnQgdHlwZSB7XG4gIEluY29taW5nSHR0cEhlYWRlcnMsXG4gIEluY29taW5nTWVzc2FnZSxcbiAgU2VydmVyLFxuICBTZXJ2ZXJSZXNwb25zZSxcbn0gZnJvbSBcIm5vZGU6aHR0cFwiO1xuaW1wb3J0IHR5cGUgeyBOZXh0anNSdW50aW1lIH0gZnJvbSBcIi4uL2NvcmVcIjtcbmltcG9ydCB7IGNsaWVudEFib3J0U2lnbmFsIH0gZnJvbSBcIi4vYWJvcnQtc2lnbmFsXCI7XG5pbXBvcnQgeyBOb2RlUmVzcG9uc2VTaW5rIH0gZnJvbSBcIi4vbm9kZS1zaW5rXCI7XG5cbi8qKlxuICogTG9uZ2VyIHRoYW4gdGhlIEFMQidzIGlkbGUgdGltZW91dCAoNjAgcyBieSBkZWZhdWx0KS4gV2l0aCBOb2RlJ3MgZGVmYXVsdCBvZlxuICogNSBzLCB0aGUgc2VydmVyIGNsb3NlcyBrZWVwLWFsaXZlIGNvbm5lY3Rpb25zIHRoZSBBTEIgc3RpbGwgY29uc2lkZXJzIG9wZW47XG4gKiB0aGUgQUxCIGFuc3dlcnMgdGhlIG5leHQgcmVxdWVzdCBvbiBvbmUgd2l0aCBhIDUwMiwgYW5kIENsb3VkRnJvbnQgY2FjaGVzXG4gKiB0aGF0IDUwMiBmb3IgaXRzIGVycm9yIGNhY2hpbmcgVFRMLCBmYWlsaW5nIGV2ZXJ5IHJlcXVlc3QgZm9yIHRoZSBwYXRoIHVudGlsXG4gKiBpdCBleHBpcmVzLiBBbiBBTEIgd2l0aCBhIGxvbmdlciBpZGxlIHRpbWVvdXQgbmVlZHMgdGhpcyByYWlzZWQgdG8gbWF0Y2guXG4gKiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZWxhc3RpY2xvYWRiYWxhbmNpbmcvbGF0ZXN0L2FwcGxpY2F0aW9uL2VkaXQtbG9hZC1iYWxhbmNlci1hdHRyaWJ1dGVzLmh0bWwjY29ubmVjdGlvbi1pZGxlLXRpbWVvdXRcbiAqL1xuY29uc3QgS0VFUF9BTElWRV9USU1FT1VUX01TID0gNjVfMDAwO1xuXG4vKiogTWV0aG9kcyBSRkMgOTExMCBhbGxvd3MgYSBib2R5IG9uLCBhbmQgb25seSB3aGVuIG9uZSBpcyBhY3R1YWxseSBmcmFtZWQuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzUmVxdWVzdEJvZHkocmVxOiBJbmNvbWluZ01lc3NhZ2UpOiBib29sZWFuIHtcbiAgaWYgKHJlcS5tZXRob2QgPT09IFwiR0VUXCIgfHwgcmVxLm1ldGhvZCA9PT0gXCJIRUFEXCIpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIChcbiAgICByZXEuaGVhZGVyc1tcImNvbnRlbnQtbGVuZ3RoXCJdICE9PSB1bmRlZmluZWQgfHxcbiAgICByZXEuaGVhZGVyc1tcInRyYW5zZmVyLWVuY29kaW5nXCJdICE9PSB1bmRlZmluZWRcbiAgKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSdW50aW1lU2VydmVyIHtcbiAgcmVhZG9ubHkgc2VydmVyOiBTZXJ2ZXI7XG4gIC8qKlxuICAgKiBTdG9wcyBhY2NlcHRpbmcgY29ubmVjdGlvbnMsIHRoZW4gcmVzb2x2ZXMgb25jZSB0aGUgb3BlbiBvbmVzIGFyZSBnb25lIGFuZFxuICAgKiBldmVyeSByZXF1ZXN0J3MgYHdhaXRVbnRpbGAgd29yayBoYXMgc2V0dGxlZC5cbiAgICovXG4gIHNodXRkb3duKCk6IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUnVudGltZVNlcnZlck9wdGlvbnMge1xuICAvKipcbiAgICogV2hldGhlciBldmVyeSByZXF1ZXN0IGNvbWVzIHRocm91Z2ggQ2xvdWRGcm9udCwgd2hpY2ggc2V0c1xuICAgKiBgY2xvdWRmcm9udC1mb3J3YXJkZWQtcHJvdG9gIGl0c2VsZi4gVHJ1ZSBvbmx5IG9uIEdsb2JhbCBDb250YWluZXJzLCB3aG9zZVxuICAgKiBBTEIgaXMgcmVhY2hhYmxlIHRocm91Z2ggdGhlIGRpc3RyaWJ1dGlvbidzIFZQQyBvcmlnaW4gYWxvbmVcbiAgICogKGBDREtfTkVYVEpTX1RSVVNUX0NMT1VERlJPTlRfUFJPVE9gLCBzZXQgYnkgdGhlIGNvbnN0cnVjdCkuIFNlZVxuICAgKiB7QGxpbmsgdmlld2VySGVhZGVyc30uXG4gICAqL1xuICByZWFkb25seSB0cnVzdENsb3VkRnJvbnRQcm90bz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVSdW50aW1lU2VydmVyKFxuICBydW50aW1lOiBQaWNrPE5leHRqc1J1bnRpbWUsIFwiaGFuZGxlXCI+LFxuICBvcHRpb25zOiBSdW50aW1lU2VydmVyT3B0aW9ucyA9IHt9LFxuKTogUnVudGltZVNlcnZlciB7XG4gIC8vIGBoYW5kbGVgIHJlc29sdmVzIG9ubHkgb25jZSB0aGUgYHdhaXRVbnRpbGAgd29yayBhIHJlcXVlc3QgcmVnaXN0ZXJlZCDigJQgSVNSXG4gIC8vIHJldmFsaWRhdGlvbiwgbm90YWJseSDigJQgaGFzIHNldHRsZWQsIHdoaWNoIGlzIGFmdGVyIGl0cyByZXNwb25zZSBhbmQgaXRzXG4gIC8vIGNvbm5lY3Rpb24gYXJlIGRvbmUuIFRyYWNrZWQgc28gc2h1dGRvd24gY2FuIHdhaXQgZm9yIHRoYXQgdG9vLlxuICBjb25zdCBpbkZsaWdodCA9IG5ldyBTZXQ8UHJvbWlzZTx2b2lkPj4oKTtcblxuICBjb25zdCBzZXJ2ZXIgPSBjcmVhdGVTZXJ2ZXIoKHJlcSwgcmVzKSA9PiB7XG4gICAgY29uc3QgaGFuZGxlZCA9IHNlcnZlKHJ1bnRpbWUsIHJlcSwgcmVzLCBvcHRpb25zKVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAvLyBgTmV4dGpzUnVudGltZS5oYW5kbGVgIGFuc3dlcnMgNTAwIGl0c2VsZiwgc28gcmVhY2hpbmcgdGhpcyBtZWFucyB0aGVcbiAgICAgICAgLy8gc2hlbGwncyBvd24gdHJhbnNsYXRpb24gZmFpbGVkLlxuICAgICAgICBjb25zb2xlLmVycm9yKFwiVGhlIGNvbnRhaW5lciBzaGVsbCBmYWlsZWQgdG8gaGFuZGxlIGEgcmVxdWVzdDpcIiwgZXJyb3IpO1xuICAgICAgICBpZiAoIXJlcy5oZWFkZXJzU2VudCkge1xuICAgICAgICAgIHJlcy53cml0ZUhlYWQoNTAwLCB7IFwiQ29udGVudC1UeXBlXCI6IFwidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOFwiIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJlcy5lbmQoXCJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcIik7XG4gICAgICB9KVxuICAgICAgLmZpbmFsbHkoKCkgPT4gaW5GbGlnaHQuZGVsZXRlKGhhbmRsZWQpKTtcbiAgICBpbkZsaWdodC5hZGQoaGFuZGxlZCk7XG4gIH0pO1xuICBzZXJ2ZXIua2VlcEFsaXZlVGltZW91dCA9IEtFRVBfQUxJVkVfVElNRU9VVF9NUztcbiAgLy8gbXVzdCBleGNlZWQga2VlcEFsaXZlVGltZW91dCwgb3IgTm9kZSBjYW4gZHJvcCBhIGNvbm5lY3Rpb24gdGhhdCBqdXN0XG4gIC8vIHN0YXJ0ZWQgc2VuZGluZyBhIHJlcXVlc3QncyBoZWFkZXJzXG4gIHNlcnZlci5oZWFkZXJzVGltZW91dCA9IEtFRVBfQUxJVkVfVElNRU9VVF9NUyArIDFfMDAwO1xuXG4gIC8vIGBzZXJ2ZXIuY2xvc2VgIGFsb25lIGlzIG5vdCBlbm91Z2g6IGl0IGNhbGxzIGJhY2sgb25jZSB0aGUgY29ubmVjdGlvbnMgYXJlXG4gIC8vIGdvbmUsIGFuZCBhIHJldmFsaWRhdGlvbiBzdGlsbCBydW5uaW5nIGluIGB3YWl0VW50aWxgIHdvdWxkIGJlIGtpbGxlZFxuICAvLyBtaWQtd3JpdGUsIGxvc2luZyB0aGUgZnJlc2ggZW50cnkuXG4gIGNvbnN0IHNodXRkb3duID0gKCkgPT5cbiAgICBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgc2VydmVyLmNsb3NlKCgpID0+IHtcbiAgICAgICAgdm9pZCBQcm9taXNlLmFsbFNldHRsZWQoaW5GbGlnaHQpLnRoZW4oKCkgPT4gcmVzb2x2ZSgpKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gIHJldHVybiB7IHNlcnZlciwgc2h1dGRvd24gfTtcbn1cblxuLyoqXG4gKiBUaGUgcmVxdWVzdCdzIGhlYWRlcnMsIHdpdGggYHgtZm9yd2FyZGVkLXByb3RvYCBuYW1pbmcgdGhlIHZpZXdlcidzIHByb3RvY29sXG4gKiB3aGVuIHRoYXQgaXMga25vd24uXG4gKlxuICogQmVoaW5kIENsb3VkRnJvbnQgd2l0aG91dCBhIGNlcnRpZmljYXRlLCBDbG91ZEZyb250IHJlYWNoZXMgdGhlIEFMQiBvdmVyIHBsYWluXG4gKiBIVFRQLCBzbyB0aGUgQUxCJ3MgYHgtZm9yd2FyZGVkLXByb3RvYCBpcyBgaHR0cGAgZm9yIGFuIGFwcCBldmVyeSB2aWV3ZXJcbiAqIHJlYWNoZXMgb3ZlciBIVFRQUy4gVGhlIHJ1bnRpbWUgYnVpbGRzIGFic29sdXRlIFVSTHMgZnJvbSBpdCAtIGByZXF1ZXN0LnVybGAsXG4gKiBgcmVxLm5leHRVcmwub3JpZ2luYCwgYW5kIHRoZSBvcmlnaW4gTmV4dC5qcyBmb3J3YXJkcyBhIHNlcnZlciBhY3Rpb24gdG8sXG4gKiB3aGVyZSBDbG91ZEZyb250IHRoZW4gYW5zd2VyZWQgMzA3IGFuZCBgdGVzdC9lMmUvYXBwLWRpci9hY3Rpb24tZm9yd2FyZC1sb29wYFxuICogZmFpbGVkLiBDbG91ZEZyb250J3Mgb3duIGBjbG91ZGZyb250LWZvcndhcmRlZC1wcm90b2AgaXMgdGhlIHZpZXdlcidzLCBidXQgaXRcbiAqIGlzIHRydXN0ZWQgb25seSB3aGVuIGV2ZXJ5IHJlcXVlc3QgY29tZXMgdGhyb3VnaCBDbG91ZEZyb250OiBhbnl3aGVyZSBlbHNlIGFcbiAqIGNsaWVudCBjb3VsZCBzZW5kIGl0IHN0cmFpZ2h0IHRvIHRoZSBBTEIgYW5kIHBpY2sgdGhlIHNjaGVtZSBvZiBVUkxzIGEgY2FjaGVkXG4gKiBwYWdlIHRoZW4gc2VydmVzIHRvIGV2ZXJ5b25lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmlld2VySGVhZGVycyhcbiAgaGVhZGVyczogSW5jb21pbmdIdHRwSGVhZGVycyxcbiAgdHJ1c3RDbG91ZEZyb250UHJvdG86IGJvb2xlYW4gfCB1bmRlZmluZWQsXG4pOiBJbmNvbWluZ0h0dHBIZWFkZXJzIHtcbiAgY29uc3Qgdmlld2VyUHJvdG8gPSBoZWFkZXJzW1wiY2xvdWRmcm9udC1mb3J3YXJkZWQtcHJvdG9cIl07XG4gIGlmICghdHJ1c3RDbG91ZEZyb250UHJvdG8gfHwgdHlwZW9mIHZpZXdlclByb3RvICE9PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIGhlYWRlcnM7XG4gIH1cbiAgcmV0dXJuIHsgLi4uaGVhZGVycywgXCJ4LWZvcndhcmRlZC1wcm90b1wiOiB2aWV3ZXJQcm90byB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiBzZXJ2ZShcbiAgcnVudGltZTogUGljazxOZXh0anNSdW50aW1lLCBcImhhbmRsZVwiPixcbiAgcmVxOiBJbmNvbWluZ01lc3NhZ2UsXG4gIHJlczogU2VydmVyUmVzcG9uc2UsXG4gIG9wdGlvbnM6IFJ1bnRpbWVTZXJ2ZXJPcHRpb25zLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHJ1bnRpbWUuaGFuZGxlKFxuICAgIHtcbiAgICAgIG1ldGhvZDogcmVxLm1ldGhvZCA/PyBcIkdFVFwiLFxuICAgICAgdXJsOiByZXEudXJsID8/IFwiL1wiLFxuICAgICAgaGVhZGVyczogdmlld2VySGVhZGVycyhyZXEuaGVhZGVycywgb3B0aW9ucy50cnVzdENsb3VkRnJvbnRQcm90byksXG4gICAgICBib2R5OiBoYXNSZXF1ZXN0Qm9keShyZXEpID8gcmVxIDogdW5kZWZpbmVkLFxuICAgICAgcmVtb3RlQWRkcmVzczogcmVxLnNvY2tldC5yZW1vdGVBZGRyZXNzLFxuICAgICAgLy8gVExTIHRlcm1pbmF0ZXMgYXQgdGhlIEFMQiAoUmVnaW9uYWwpIG9yIENsb3VkRnJvbnQgKEdsb2JhbCk7IHRoZSBob3AgdG9cbiAgICAgIC8vIHRoaXMgY29udGFpbmVyIGlzIHBsYWludGV4dCBIVFRQLzEuMS5cbiAgICAgIGVuY3J5cHRlZDogZmFsc2UsXG4gICAgICBzaWduYWw6IGNsaWVudEFib3J0U2lnbmFsKHJlcSwgcmVzKSxcbiAgICB9LFxuICAgIG5ldyBOb2RlUmVzcG9uc2VTaW5rKHJlcyksXG4gICk7XG59XG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_http_1 = require("node:http");
4
+ const node_server_1 = require("./node-server");
5
+ /** A real server around a stub runtime, and one request to it. */
6
+ async function withServer(handle, run) {
7
+ const { server, shutdown } = (0, node_server_1.createRuntimeServer)({ handle });
8
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
9
+ const { port } = server.address();
10
+ const get = () => new Promise((resolve, reject) => {
11
+ // No keep-alive agent, so the connection closes with the response and
12
+ // `server.close` is not left waiting on an idle socket.
13
+ const req = (0, node_http_1.request)({ port, host: "127.0.0.1", path: "/", agent: false }, (res) => {
14
+ let body = "";
15
+ res.setEncoding("utf-8");
16
+ res.on("data", (chunk) => (body += chunk));
17
+ res.on("end", () => resolve({ status: res.statusCode, body }));
18
+ });
19
+ req.on("error", reject);
20
+ req.end();
21
+ });
22
+ try {
23
+ return await run(get, shutdown);
24
+ }
25
+ finally {
26
+ server.close();
27
+ }
28
+ }
29
+ describe("viewerHeaders", () => {
30
+ // Global Containers without a certificate: CloudFront reaches the ALB over
31
+ // HTTP, so the ALB says `http` while the viewer used HTTPS.
32
+ const behindCloudFront = {
33
+ host: "d111.cloudfront.net",
34
+ "x-forwarded-proto": "http",
35
+ "cloudfront-forwarded-proto": "https",
36
+ };
37
+ it("takes the viewer's protocol from CloudFront when every request comes through it", () => {
38
+ expect((0, node_server_1.viewerHeaders)(behindCloudFront, true)["x-forwarded-proto"]).toBe("https");
39
+ });
40
+ it("ignores cloudfront-forwarded-proto a client could have sent the ALB itself", () => {
41
+ expect((0, node_server_1.viewerHeaders)(behindCloudFront, false)["x-forwarded-proto"]).toBe("http");
42
+ expect((0, node_server_1.viewerHeaders)(behindCloudFront, undefined)).toBe(behindCloudFront);
43
+ });
44
+ it("keeps x-forwarded-proto when CloudFront sent no protocol", () => {
45
+ const headers = { host: "alb.example.test", "x-forwarded-proto": "http" };
46
+ expect((0, node_server_1.viewerHeaders)(headers, true)).toBe(headers);
47
+ });
48
+ });
49
+ describe("hasRequestBody", () => {
50
+ const message = (method, headers = {}) => ({ method, headers });
51
+ it("is false for GET and HEAD, whatever their framing says", () => {
52
+ expect((0, node_server_1.hasRequestBody)(message("GET", { "content-length": "3" }))).toBe(false);
53
+ expect((0, node_server_1.hasRequestBody)(message("HEAD", { "transfer-encoding": "chunked" }))).toBe(false);
54
+ });
55
+ it("is true only for a body that is actually framed", () => {
56
+ expect((0, node_server_1.hasRequestBody)(message("POST"))).toBe(false);
57
+ expect((0, node_server_1.hasRequestBody)(message("POST", { "content-length": "0" }))).toBe(true);
58
+ expect((0, node_server_1.hasRequestBody)(message("DELETE", { "transfer-encoding": "chunked" }))).toBe(true);
59
+ });
60
+ });
61
+ describe("createRuntimeServer", () => {
62
+ it("answers a plain 500 when the shell itself fails", async () => {
63
+ const error = jest.spyOn(console, "error").mockImplementation(() => { });
64
+ try {
65
+ const response = await withServer(async () => {
66
+ throw new Error("translation failed");
67
+ }, (get) => get());
68
+ expect(response).toEqual({ status: 500, body: "Internal Server Error" });
69
+ expect(String(error.mock.calls[0][0])).toMatch(/container shell failed/);
70
+ }
71
+ finally {
72
+ error.mockRestore();
73
+ }
74
+ });
75
+ // What an ECS rolling deploy does: SIGTERM while an ISR regeneration is still
76
+ // running in `waitUntil`, after its response has gone out.
77
+ it("shuts down only once in-flight waitUntil work has settled", async () => {
78
+ let release;
79
+ const waitUntilWork = new Promise((resolve) => (release = resolve));
80
+ const handle = async (_request, sink) => {
81
+ sink.begin({ statusCode: 200, headers: {}, cookies: [] }).end("ok");
82
+ await waitUntilWork;
83
+ };
84
+ await withServer(handle, async (get, shutdown) => {
85
+ expect(await get()).toEqual({ status: 200, body: "ok" });
86
+ let stopped = false;
87
+ const stopping = shutdown().then(() => (stopped = true));
88
+ await new Promise((resolve) => setTimeout(resolve, 20));
89
+ expect(stopped).toBe(false);
90
+ release();
91
+ await stopping;
92
+ expect(stopped).toBe(true);
93
+ });
94
+ });
95
+ });
96
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1zZXJ2ZXIudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9ydW50aW1lL2h0dHAvbm9kZS1zZXJ2ZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLHlDQUFtRDtBQUduRCwrQ0FJdUI7QUFJdkIsa0VBQWtFO0FBQ2xFLEtBQUssVUFBVSxVQUFVLENBQ3ZCLE1BQWMsRUFDZCxHQUdlO0lBRWYsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxJQUFBLGlDQUFtQixFQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM3RCxNQUFNLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUM3RSxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxDQUFDLE9BQU8sRUFBaUIsQ0FBQztJQUNqRCxNQUFNLEdBQUcsR0FBRyxHQUFHLEVBQUUsQ0FDZixJQUFJLE9BQU8sQ0FBb0MsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDakUsc0VBQXNFO1FBQ3RFLHdEQUF3RDtRQUN4RCxNQUFNLEdBQUcsR0FBRyxJQUFBLG1CQUFXLEVBQ3JCLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQ3BELENBQUMsR0FBRyxFQUFFLEVBQUU7WUFDTixJQUFJLElBQUksR0FBRyxFQUFFLENBQUM7WUFDZCxHQUFHLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3pCLEdBQUcsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQzNDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxHQUFHLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNqRSxDQUFDLENBQ0YsQ0FBQztRQUNGLEdBQUcsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3hCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUNaLENBQUMsQ0FBQyxDQUFDO0lBQ0wsSUFBSSxDQUFDO1FBQ0gsT0FBTyxNQUFNLEdBQUcsQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDbEMsQ0FBQztZQUFTLENBQUM7UUFDVCxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDakIsQ0FBQztBQUNILENBQUM7QUFFRCxRQUFRLENBQUMsZUFBZSxFQUFFLEdBQUcsRUFBRTtJQUM3QiwyRUFBMkU7SUFDM0UsNERBQTREO0lBQzVELE1BQU0sZ0JBQWdCLEdBQUc7UUFDdkIsSUFBSSxFQUFFLHFCQUFxQjtRQUMzQixtQkFBbUIsRUFBRSxNQUFNO1FBQzNCLDRCQUE0QixFQUFFLE9BQU87S0FDdEMsQ0FBQztJQUVGLEVBQUUsQ0FBQyxpRkFBaUYsRUFBRSxHQUFHLEVBQUU7UUFDekYsTUFBTSxDQUFDLElBQUEsMkJBQWEsRUFBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUNyRSxPQUFPLENBQ1IsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLDRFQUE0RSxFQUFFLEdBQUcsRUFBRTtRQUNwRixNQUFNLENBQUMsSUFBQSwyQkFBYSxFQUFDLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQ3RFLE1BQU0sQ0FDUCxDQUFDO1FBQ0YsTUFBTSxDQUFDLElBQUEsMkJBQWEsRUFBQyxnQkFBZ0IsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzVFLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLDBEQUEwRCxFQUFFLEdBQUcsRUFBRTtRQUNsRSxNQUFNLE9BQU8sR0FBRyxFQUFFLElBQUksRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLEVBQUUsQ0FBQztRQUMxRSxNQUFNLENBQUMsSUFBQSwyQkFBYSxFQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNyRCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLGdCQUFnQixFQUFFLEdBQUcsRUFBRTtJQUM5QixNQUFNLE9BQU8sR0FBRyxDQUFDLE1BQWMsRUFBRSxVQUFrQyxFQUFFLEVBQUUsRUFBRSxDQUN2RSxDQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxDQUErQixDQUFDO0lBRXRELEVBQUUsQ0FBQyx3REFBd0QsRUFBRSxHQUFHLEVBQUU7UUFDaEUsTUFBTSxDQUFDLElBQUEsNEJBQWMsRUFBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUNwRSxLQUFLLENBQ04sQ0FBQztRQUNGLE1BQU0sQ0FDSixJQUFBLDRCQUFjLEVBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLG1CQUFtQixFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FDcEUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEIsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsaURBQWlELEVBQUUsR0FBRyxFQUFFO1FBQ3pELE1BQU0sQ0FBQyxJQUFBLDRCQUFjLEVBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDcEQsTUFBTSxDQUFDLElBQUEsNEJBQWMsRUFBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUNyRSxJQUFJLENBQ0wsQ0FBQztRQUNGLE1BQU0sQ0FDSixJQUFBLDRCQUFjLEVBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLG1CQUFtQixFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FDdEUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDZixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLHFCQUFxQixFQUFFLEdBQUcsRUFBRTtJQUNuQyxFQUFFLENBQUMsaURBQWlELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDL0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsa0JBQWtCLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7UUFDeEUsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxVQUFVLENBQy9CLEtBQUssSUFBSSxFQUFFO2dCQUNULE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUN4QyxDQUFDLEVBQ0QsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUNmLENBQUM7WUFDRixNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsdUJBQXVCLEVBQUUsQ0FBQyxDQUFDO1lBQ3pFLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQzNFLENBQUM7Z0JBQVMsQ0FBQztZQUNULEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0QixDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7SUFFSCw4RUFBOEU7SUFDOUUsMkRBQTJEO0lBQzNELEVBQUUsQ0FBQywyREFBMkQsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN6RSxJQUFJLE9BQW9CLENBQUM7UUFDekIsTUFBTSxhQUFhLEdBQUcsSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDMUUsTUFBTSxNQUFNLEdBQVcsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsRUFBRTtZQUM5QyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNwRSxNQUFNLGFBQWEsQ0FBQztRQUN0QixDQUFDLENBQUM7UUFDRixNQUFNLFVBQVUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsRUFBRTtZQUMvQyxNQUFNLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFFekQsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDO1lBQ3BCLE1BQU0sUUFBUSxHQUFHLFFBQVEsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3pELE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN4RCxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRTVCLE9BQU8sRUFBRSxDQUFDO1lBQ1YsTUFBTSxRQUFRLENBQUM7WUFDZixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgSW5jb21pbmdNZXNzYWdlIH0gZnJvbSBcIm5vZGU6aHR0cFwiO1xuaW1wb3J0IHsgcmVxdWVzdCBhcyBodHRwUmVxdWVzdCB9IGZyb20gXCJub2RlOmh0dHBcIjtcbmltcG9ydCB0eXBlIHsgQWRkcmVzc0luZm8gfSBmcm9tIFwibm9kZTpuZXRcIjtcbmltcG9ydCB0eXBlIHsgTmV4dGpzUnVudGltZSB9IGZyb20gXCIuLi9jb3JlXCI7XG5pbXBvcnQge1xuICBjcmVhdGVSdW50aW1lU2VydmVyLFxuICBoYXNSZXF1ZXN0Qm9keSxcbiAgdmlld2VySGVhZGVycyxcbn0gZnJvbSBcIi4vbm9kZS1zZXJ2ZXJcIjtcblxudHlwZSBIYW5kbGUgPSBOZXh0anNSdW50aW1lW1wiaGFuZGxlXCJdO1xuXG4vKiogQSByZWFsIHNlcnZlciBhcm91bmQgYSBzdHViIHJ1bnRpbWUsIGFuZCBvbmUgcmVxdWVzdCB0byBpdC4gKi9cbmFzeW5jIGZ1bmN0aW9uIHdpdGhTZXJ2ZXI8VD4oXG4gIGhhbmRsZTogSGFuZGxlLFxuICBydW46IChcbiAgICBnZXQ6ICgpID0+IFByb21pc2U8eyBzdGF0dXM/OiBudW1iZXI7IGJvZHk6IHN0cmluZyB9PixcbiAgICBzaHV0ZG93bjogKCkgPT4gUHJvbWlzZTx2b2lkPixcbiAgKSA9PiBQcm9taXNlPFQ+LFxuKTogUHJvbWlzZTxUPiB7XG4gIGNvbnN0IHsgc2VydmVyLCBzaHV0ZG93biB9ID0gY3JlYXRlUnVudGltZVNlcnZlcih7IGhhbmRsZSB9KTtcbiAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHNlcnZlci5saXN0ZW4oMCwgXCIxMjcuMC4wLjFcIiwgcmVzb2x2ZSkpO1xuICBjb25zdCB7IHBvcnQgfSA9IHNlcnZlci5hZGRyZXNzKCkgYXMgQWRkcmVzc0luZm87XG4gIGNvbnN0IGdldCA9ICgpID0+XG4gICAgbmV3IFByb21pc2U8eyBzdGF0dXM/OiBudW1iZXI7IGJvZHk6IHN0cmluZyB9PigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAvLyBObyBrZWVwLWFsaXZlIGFnZW50LCBzbyB0aGUgY29ubmVjdGlvbiBjbG9zZXMgd2l0aCB0aGUgcmVzcG9uc2UgYW5kXG4gICAgICAvLyBgc2VydmVyLmNsb3NlYCBpcyBub3QgbGVmdCB3YWl0aW5nIG9uIGFuIGlkbGUgc29ja2V0LlxuICAgICAgY29uc3QgcmVxID0gaHR0cFJlcXVlc3QoXG4gICAgICAgIHsgcG9ydCwgaG9zdDogXCIxMjcuMC4wLjFcIiwgcGF0aDogXCIvXCIsIGFnZW50OiBmYWxzZSB9LFxuICAgICAgICAocmVzKSA9PiB7XG4gICAgICAgICAgbGV0IGJvZHkgPSBcIlwiO1xuICAgICAgICAgIHJlcy5zZXRFbmNvZGluZyhcInV0Zi04XCIpO1xuICAgICAgICAgIHJlcy5vbihcImRhdGFcIiwgKGNodW5rKSA9PiAoYm9keSArPSBjaHVuaykpO1xuICAgICAgICAgIHJlcy5vbihcImVuZFwiLCAoKSA9PiByZXNvbHZlKHsgc3RhdHVzOiByZXMuc3RhdHVzQ29kZSwgYm9keSB9KSk7XG4gICAgICAgIH0sXG4gICAgICApO1xuICAgICAgcmVxLm9uKFwiZXJyb3JcIiwgcmVqZWN0KTtcbiAgICAgIHJlcS5lbmQoKTtcbiAgICB9KTtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgcnVuKGdldCwgc2h1dGRvd24pO1xuICB9IGZpbmFsbHkge1xuICAgIHNlcnZlci5jbG9zZSgpO1xuICB9XG59XG5cbmRlc2NyaWJlKFwidmlld2VySGVhZGVyc1wiLCAoKSA9PiB7XG4gIC8vIEdsb2JhbCBDb250YWluZXJzIHdpdGhvdXQgYSBjZXJ0aWZpY2F0ZTogQ2xvdWRGcm9udCByZWFjaGVzIHRoZSBBTEIgb3ZlclxuICAvLyBIVFRQLCBzbyB0aGUgQUxCIHNheXMgYGh0dHBgIHdoaWxlIHRoZSB2aWV3ZXIgdXNlZCBIVFRQUy5cbiAgY29uc3QgYmVoaW5kQ2xvdWRGcm9udCA9IHtcbiAgICBob3N0OiBcImQxMTEuY2xvdWRmcm9udC5uZXRcIixcbiAgICBcIngtZm9yd2FyZGVkLXByb3RvXCI6IFwiaHR0cFwiLFxuICAgIFwiY2xvdWRmcm9udC1mb3J3YXJkZWQtcHJvdG9cIjogXCJodHRwc1wiLFxuICB9O1xuXG4gIGl0KFwidGFrZXMgdGhlIHZpZXdlcidzIHByb3RvY29sIGZyb20gQ2xvdWRGcm9udCB3aGVuIGV2ZXJ5IHJlcXVlc3QgY29tZXMgdGhyb3VnaCBpdFwiLCAoKSA9PiB7XG4gICAgZXhwZWN0KHZpZXdlckhlYWRlcnMoYmVoaW5kQ2xvdWRGcm9udCwgdHJ1ZSlbXCJ4LWZvcndhcmRlZC1wcm90b1wiXSkudG9CZShcbiAgICAgIFwiaHR0cHNcIixcbiAgICApO1xuICB9KTtcblxuICBpdChcImlnbm9yZXMgY2xvdWRmcm9udC1mb3J3YXJkZWQtcHJvdG8gYSBjbGllbnQgY291bGQgaGF2ZSBzZW50IHRoZSBBTEIgaXRzZWxmXCIsICgpID0+IHtcbiAgICBleHBlY3Qodmlld2VySGVhZGVycyhiZWhpbmRDbG91ZEZyb250LCBmYWxzZSlbXCJ4LWZvcndhcmRlZC1wcm90b1wiXSkudG9CZShcbiAgICAgIFwiaHR0cFwiLFxuICAgICk7XG4gICAgZXhwZWN0KHZpZXdlckhlYWRlcnMoYmVoaW5kQ2xvdWRGcm9udCwgdW5kZWZpbmVkKSkudG9CZShiZWhpbmRDbG91ZEZyb250KTtcbiAgfSk7XG5cbiAgaXQoXCJrZWVwcyB4LWZvcndhcmRlZC1wcm90byB3aGVuIENsb3VkRnJvbnQgc2VudCBubyBwcm90b2NvbFwiLCAoKSA9PiB7XG4gICAgY29uc3QgaGVhZGVycyA9IHsgaG9zdDogXCJhbGIuZXhhbXBsZS50ZXN0XCIsIFwieC1mb3J3YXJkZWQtcHJvdG9cIjogXCJodHRwXCIgfTtcbiAgICBleHBlY3Qodmlld2VySGVhZGVycyhoZWFkZXJzLCB0cnVlKSkudG9CZShoZWFkZXJzKTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJoYXNSZXF1ZXN0Qm9keVwiLCAoKSA9PiB7XG4gIGNvbnN0IG1lc3NhZ2UgPSAobWV0aG9kOiBzdHJpbmcsIGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fSkgPT5cbiAgICAoeyBtZXRob2QsIGhlYWRlcnMgfSkgYXMgdW5rbm93biBhcyBJbmNvbWluZ01lc3NhZ2U7XG5cbiAgaXQoXCJpcyBmYWxzZSBmb3IgR0VUIGFuZCBIRUFELCB3aGF0ZXZlciB0aGVpciBmcmFtaW5nIHNheXNcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChoYXNSZXF1ZXN0Qm9keShtZXNzYWdlKFwiR0VUXCIsIHsgXCJjb250ZW50LWxlbmd0aFwiOiBcIjNcIiB9KSkpLnRvQmUoXG4gICAgICBmYWxzZSxcbiAgICApO1xuICAgIGV4cGVjdChcbiAgICAgIGhhc1JlcXVlc3RCb2R5KG1lc3NhZ2UoXCJIRUFEXCIsIHsgXCJ0cmFuc2Zlci1lbmNvZGluZ1wiOiBcImNodW5rZWRcIiB9KSksXG4gICAgKS50b0JlKGZhbHNlKTtcbiAgfSk7XG5cbiAgaXQoXCJpcyB0cnVlIG9ubHkgZm9yIGEgYm9keSB0aGF0IGlzIGFjdHVhbGx5IGZyYW1lZFwiLCAoKSA9PiB7XG4gICAgZXhwZWN0KGhhc1JlcXVlc3RCb2R5KG1lc3NhZ2UoXCJQT1NUXCIpKSkudG9CZShmYWxzZSk7XG4gICAgZXhwZWN0KGhhc1JlcXVlc3RCb2R5KG1lc3NhZ2UoXCJQT1NUXCIsIHsgXCJjb250ZW50LWxlbmd0aFwiOiBcIjBcIiB9KSkpLnRvQmUoXG4gICAgICB0cnVlLFxuICAgICk7XG4gICAgZXhwZWN0KFxuICAgICAgaGFzUmVxdWVzdEJvZHkobWVzc2FnZShcIkRFTEVURVwiLCB7IFwidHJhbnNmZXItZW5jb2RpbmdcIjogXCJjaHVua2VkXCIgfSkpLFxuICAgICkudG9CZSh0cnVlKTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJjcmVhdGVSdW50aW1lU2VydmVyXCIsICgpID0+IHtcbiAgaXQoXCJhbnN3ZXJzIGEgcGxhaW4gNTAwIHdoZW4gdGhlIHNoZWxsIGl0c2VsZiBmYWlsc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZXJyb3IgPSBqZXN0LnNweU9uKGNvbnNvbGUsIFwiZXJyb3JcIikubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHt9KTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB3aXRoU2VydmVyKFxuICAgICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwidHJhbnNsYXRpb24gZmFpbGVkXCIpO1xuICAgICAgICB9LFxuICAgICAgICAoZ2V0KSA9PiBnZXQoKSxcbiAgICAgICk7XG4gICAgICBleHBlY3QocmVzcG9uc2UpLnRvRXF1YWwoeyBzdGF0dXM6IDUwMCwgYm9keTogXCJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcIiB9KTtcbiAgICAgIGV4cGVjdChTdHJpbmcoZXJyb3IubW9jay5jYWxsc1swXVswXSkpLnRvTWF0Y2goL2NvbnRhaW5lciBzaGVsbCBmYWlsZWQvKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgZXJyb3IubW9ja1Jlc3RvcmUoKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFdoYXQgYW4gRUNTIHJvbGxpbmcgZGVwbG95IGRvZXM6IFNJR1RFUk0gd2hpbGUgYW4gSVNSIHJlZ2VuZXJhdGlvbiBpcyBzdGlsbFxuICAvLyBydW5uaW5nIGluIGB3YWl0VW50aWxgLCBhZnRlciBpdHMgcmVzcG9uc2UgaGFzIGdvbmUgb3V0LlxuICBpdChcInNodXRzIGRvd24gb25seSBvbmNlIGluLWZsaWdodCB3YWl0VW50aWwgd29yayBoYXMgc2V0dGxlZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgbGV0IHJlbGVhc2UhOiAoKSA9PiB2b2lkO1xuICAgIGNvbnN0IHdhaXRVbnRpbFdvcmsgPSBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4gKHJlbGVhc2UgPSByZXNvbHZlKSk7XG4gICAgY29uc3QgaGFuZGxlOiBIYW5kbGUgPSBhc3luYyAoX3JlcXVlc3QsIHNpbmspID0+IHtcbiAgICAgIHNpbmsuYmVnaW4oeyBzdGF0dXNDb2RlOiAyMDAsIGhlYWRlcnM6IHt9LCBjb29raWVzOiBbXSB9KS5lbmQoXCJva1wiKTtcbiAgICAgIGF3YWl0IHdhaXRVbnRpbFdvcms7XG4gICAgfTtcbiAgICBhd2FpdCB3aXRoU2VydmVyKGhhbmRsZSwgYXN5bmMgKGdldCwgc2h1dGRvd24pID0+IHtcbiAgICAgIGV4cGVjdChhd2FpdCBnZXQoKSkudG9FcXVhbCh7IHN0YXR1czogMjAwLCBib2R5OiBcIm9rXCIgfSk7XG5cbiAgICAgIGxldCBzdG9wcGVkID0gZmFsc2U7XG4gICAgICBjb25zdCBzdG9wcGluZyA9IHNodXRkb3duKCkudGhlbigoKSA9PiAoc3RvcHBlZCA9IHRydWUpKTtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDIwKSk7XG4gICAgICBleHBlY3Qoc3RvcHBlZCkudG9CZShmYWxzZSk7XG5cbiAgICAgIHJlbGVhc2UoKTtcbiAgICAgIGF3YWl0IHN0b3BwaW5nO1xuICAgICAgZXhwZWN0KHN0b3BwZWQpLnRvQmUodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The container shell's {@link ResponseSink}: the head goes to a real
3
+ * `node:http` `ServerResponse`, which is then the stream the body is piped into.
4
+ *
5
+ * Its own module rather than inline in `server.mts` so it can be tested without
6
+ * starting the server that module starts on import.
7
+ */
8
+ import type { ServerResponse } from "node:http";
9
+ import type { Writable } from "node:stream";
10
+ import type { ResponseHead } from "./response";
11
+ import type { ResponseSink } from "./sink";
12
+ export declare class NodeResponseSink implements ResponseSink {
13
+ private readonly res;
14
+ constructor(res: ServerResponse);
15
+ begin(head: ResponseHead): Writable;
16
+ }