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,50 @@
1
+ import type { ShimIncomingMessage } from "./http/request";
2
+ import { ShimServerResponse } from "./http/response";
3
+ /**
4
+ * Returns `false` when the file is not in the deployment package, which is the
5
+ * caller's cue to fall through to a 404.
6
+ *
7
+ * That happens by design on every type but `NextjsRegionalContainers`, for `<distDir>/static` and
8
+ * `public/` alike: neither is staged, being a second copy of bytes already in
9
+ * S3. A `public/` file is then served by {@link serveS3PublicFile}; a
10
+ * `<distDir>/static` one only gets here through a rewrite onto it, and is a 404.
11
+ * The `NextjsRegionalContainers` image copies both in, so there they are found.
12
+ */
13
+ export declare function serveStaticFile(req: ShimIncomingMessage, res: ShimServerResponse, deploymentRoot: string, filePath: string, options: {
14
+ readonly etag: boolean;
15
+ }): Promise<boolean>;
16
+ /** Where a type without `public/` on disk finds a file it does not carry. */
17
+ export interface S3PublicFile {
18
+ /** `CDK_NEXTJS_STATIC_ASSETS_BUCKET_NAME`. */
19
+ readonly bucket: string;
20
+ /**
21
+ * `NextjsStaticAssets.keyPrefix`, without a leading slash; empty for a
22
+ * bucket-root deployment. `public/` is uploaded to the root of it.
23
+ */
24
+ readonly keyPrefix: string;
25
+ /** The file's path relative to `public/`, unencoded: its real name. */
26
+ readonly file: string;
27
+ readonly etag: boolean;
28
+ }
29
+ /**
30
+ * A `public/` file from the assets bucket, for the types whose deployment
31
+ * roots list `public/` without carrying it. Returns `false` when the object is not there,
32
+ * which is the caller's cue to fall through to a 404 as for a file missing from
33
+ * disk.
34
+ *
35
+ * What `send` would have answered, as far as S3 can say it: the object's
36
+ * `Content-Type`, `Content-Length`, `Last-Modified` and — unless
37
+ * `generateEtags` is off — `ETag`; a 304 for a matching `If-None-Match` or, as
38
+ * `fresh` has it, an `If-Modified-Since` without one; and a 206 or 416 for a
39
+ * `Range`. S3 evaluates all of them itself.
40
+ *
41
+ * `Cache-Control` is, in order: a `headers()` rule's, the object's own
42
+ * `CacheControl` metadata — what the edge serves the file's own URL with, so a
43
+ * rewrite onto it caches the same way — and `send`'s default,
44
+ * `public, max-age=0`.
45
+ *
46
+ * `If-Range` is not evaluated, because S3 has no counterpart: with one present
47
+ * the `Range` is dropped and the whole file sent with a 200, which RFC 9110
48
+ * allows (a server may ignore `Range`) and a range client accepts.
49
+ */
50
+ export declare function serveS3PublicFile(req: ShimIncomingMessage, res: ShimServerResponse, file: S3PublicFile): Promise<boolean>;
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serveStaticFile = serveStaticFile;
4
+ exports.serveS3PublicFile = serveS3PublicFile;
5
+ /**
6
+ * Serving the static files that nothing in front of the compute answers.
7
+ *
8
+ * `NextjsStaticAssets` uploads `<distDir>/static` and `public` to S3, and
9
+ * CloudFront / API Gateway route a file's own URL there — except on
10
+ * `NextjsRegionalContainers`, which has nothing in front of it. What still
11
+ * reaches the runtime is a file some *other* URL lands on: a `rewrites` entry
12
+ * or a middleware rewrite onto `/maintenance.html`, `/en-US/robots.txt` in an
13
+ * i18n app. The `NextjsRegionalContainers` image copies `public` and
14
+ * `<distDir>/static` in and serves them off disk; the other types carry
15
+ * neither, so a `public/` file is streamed from the assets bucket instead
16
+ * ({@link serveS3PublicFile}).
17
+ * Everything else in `manifest.staticFiles` lives under `<distDir>/server` —
18
+ * `404.html`, `500.html`, `favicon.ico.body`, fully-static Pages Router HTML —
19
+ * and reaches us, exactly as it reaches `next start`.
20
+ *
21
+ * Next.js's own `serveStatic` is used rather than a `createReadStream`, because it
22
+ * is `send` underneath and that brings conditional requests (`If-None-Match`,
23
+ * `If-Modified-Since`), `Range`, `ETag`, `Last-Modified`, and content-type
24
+ * detection. Reimplementing those is how a "simple" file server ends up
25
+ * disagreeing with `next start` on a 304.
26
+ */
27
+ /* eslint-disable import/no-extraneous-dependencies */
28
+ const node_path_1 = require("node:path");
29
+ const node_stream_1 = require("node:stream");
30
+ const client_s3_1 = require("@aws-sdk/client-s3");
31
+ const response_1 = require("./http/response");
32
+ const next_modules_1 = require("./next-modules");
33
+ const util_1 = require("./util");
34
+ const SERVE_STATIC = "next/dist/server/serve-static.js";
35
+ /** Resolved on the first static-file request; see {@link nextModule}. */
36
+ let serveStaticModule;
37
+ /**
38
+ * Returns `false` when the file is not in the deployment package, which is the
39
+ * caller's cue to fall through to a 404.
40
+ *
41
+ * That happens by design on every type but `NextjsRegionalContainers`, for `<distDir>/static` and
42
+ * `public/` alike: neither is staged, being a second copy of bytes already in
43
+ * S3. A `public/` file is then served by {@link serveS3PublicFile}; a
44
+ * `<distDir>/static` one only gets here through a rewrite onto it, and is a 404.
45
+ * The `NextjsRegionalContainers` image copies both in, so there they are found.
46
+ */
47
+ async function serveStaticFile(req, res, deploymentRoot, filePath, options) {
48
+ serveStaticModule ??= (0, next_modules_1.nextModule)(SERVE_STATIC);
49
+ const { serveStatic, getContentType } = serveStaticModule;
50
+ setBodyFileContentType(res, filePath, getContentType);
51
+ try {
52
+ // Encoded, and relative to a `root`, which is how `next start` calls it:
53
+ // `send` percent-decodes whatever path it is handed, as though it were a
54
+ // URL. A raw filesystem path broke on any file name with a `%` in it —
55
+ // `100%.png` failed to decode and answered an empty 400, and `a%20b.txt`
56
+ // was looked up as `a b.txt`, serving a different file if there was one.
57
+ await serveStatic(req, (0, response_1.asServerResponse)(res), `/${filePath.split("/").map(encodeURIComponent).join("/")}`, { root: deploymentRoot, etag: options.etag });
58
+ return true;
59
+ }
60
+ catch (error) {
61
+ if (isMissingFile(error)) {
62
+ return false;
63
+ }
64
+ const status = httpErrorStatus(error);
65
+ // `send` emits its error before the first byte, so the head is still ours to
66
+ // set; the guard is only for a shell that already committed one.
67
+ if (status !== undefined && !res.headersSent) {
68
+ res.statusCode = status;
69
+ res.end();
70
+ return true;
71
+ }
72
+ throw error;
73
+ }
74
+ }
75
+ /**
76
+ * The status a `send` error carries, for the errors that are the *client's*, not
77
+ * ours.
78
+ *
79
+ * `serveStatic` is `send` underneath, and `send` rejects a failed precondition
80
+ * with a 412 and an unsatisfiable `Range` with a 416 — both attached to the error
81
+ * as `statusCode`. `next start` maps them back onto the response
82
+ * (`next/dist/server/lib/router-server.js` special-cases 400/412/416); letting
83
+ * them fall through to the caller's error path (`NextjsRuntime.sendError`, which
84
+ * answers 500 with the app's error page) instead turned `If-Match: "stale"` into
85
+ * a 500 and `Range: bytes=99999-` into a 500.
86
+ *
87
+ * Only 4xx is honored: a 5xx from `send` is a real failure and belongs in the
88
+ * error path, with the stack.
89
+ */
90
+ function httpErrorStatus(error) {
91
+ const status = error?.statusCode;
92
+ if (typeof status === "number" && status >= 400 && status < 500) {
93
+ return status;
94
+ }
95
+ return undefined;
96
+ }
97
+ /**
98
+ * `send` types a response from the file's own extension, and a static metadata
99
+ * route ships as `<route>.body` — `robots.txt.body`, `manifest.webmanifest.body`,
100
+ * `favicon.ico.body`. `.body` is not a media type, so every one of them would go
101
+ * out as `application/octet-stream`.
102
+ *
103
+ * Next.js's adapter API is where the type is lost: `build-complete.ts` pushes
104
+ * these through `isStaticMetadataFile()` as a bare `STATIC_FILE` — `id`,
105
+ * `pathname`, `filePath`, and nothing else — while the headers the route handler
106
+ * actually set sit unreferenced in a sibling `<route>.meta`. `next start` reads
107
+ * that file through the response cache and answers `text/plain`.
108
+ *
109
+ * Stripping `.body` puts the route's own extension back on the end, which for
110
+ * this population is the same answer: the set is closed (`favicon.ico`, `icon.*`,
111
+ * `apple-icon.*`, `opengraph-image.*`, `twitter-image.*`, `sitemap.xml`,
112
+ * `robots.txt`, `manifest.{json,webmanifest}`) and every member's type is implied
113
+ * by its extension. `send` skips its own detection when `Content-Type` is already
114
+ * set (`send/index.js`, `type()`), so this wins without reaching for `opts`.
115
+ */
116
+ function setBodyFileContentType(res, filePath, getContentType) {
117
+ if (!filePath.endsWith(".body") || res.getHeader("Content-Type")) {
118
+ return;
119
+ }
120
+ const ext = (0, node_path_1.extname)(filePath.slice(0, -".body".length)).slice(1);
121
+ if (!ext) {
122
+ return;
123
+ }
124
+ const contentType = getContentType(ext);
125
+ if (contentType) {
126
+ res.setHeader("Content-Type", contentType);
127
+ }
128
+ }
129
+ function isMissingFile(error) {
130
+ const code = error?.code;
131
+ // ENOENT covers a missing file and `send`'s "No directory access"; ENOTDIR is
132
+ // what a path segment that exists as a file produces.
133
+ return code === "ENOENT" || code === "ENOTDIR";
134
+ }
135
+ /**
136
+ * A `public/` file from the assets bucket, for the types whose deployment
137
+ * roots list `public/` without carrying it. Returns `false` when the object is not there,
138
+ * which is the caller's cue to fall through to a 404 as for a file missing from
139
+ * disk.
140
+ *
141
+ * What `send` would have answered, as far as S3 can say it: the object's
142
+ * `Content-Type`, `Content-Length`, `Last-Modified` and — unless
143
+ * `generateEtags` is off — `ETag`; a 304 for a matching `If-None-Match` or, as
144
+ * `fresh` has it, an `If-Modified-Since` without one; and a 206 or 416 for a
145
+ * `Range`. S3 evaluates all of them itself.
146
+ *
147
+ * `Cache-Control` is, in order: a `headers()` rule's, the object's own
148
+ * `CacheControl` metadata — what the edge serves the file's own URL with, so a
149
+ * rewrite onto it caches the same way — and `send`'s default,
150
+ * `public, max-age=0`.
151
+ *
152
+ * `If-Range` is not evaluated, because S3 has no counterpart: with one present
153
+ * the `Range` is dropped and the whole file sent with a 200, which RFC 9110
154
+ * allows (a server may ignore `Range`) and a range client accepts.
155
+ */
156
+ async function serveS3PublicFile(req, res, file) {
157
+ const prefix = file.keyPrefix.replace(/^\/+|\/+$/g, "");
158
+ const key = prefix ? `${prefix}/${file.file}` : file.file;
159
+ const ifNoneMatch = file.etag
160
+ ? (0, util_1.firstValue)(req.headers["if-none-match"])
161
+ : undefined;
162
+ // `fresh` ignores it next to an `If-None-Match`, even one it cannot match
163
+ // because `generateEtags` is off.
164
+ const ifModifiedSince = req.headers["if-none-match"]
165
+ ? undefined
166
+ : httpDate((0, util_1.firstValue)(req.headers["if-modified-since"]));
167
+ const range = req.headers["if-range"]
168
+ ? undefined
169
+ : (0, util_1.firstValue)(req.headers.range);
170
+ let object;
171
+ try {
172
+ object = await (0, util_1.s3Client)().send(req.method === "HEAD"
173
+ ? new client_s3_1.HeadObjectCommand({
174
+ Bucket: file.bucket,
175
+ Key: key,
176
+ IfNoneMatch: ifNoneMatch,
177
+ IfModifiedSince: ifModifiedSince,
178
+ Range: range,
179
+ })
180
+ : new client_s3_1.GetObjectCommand({
181
+ Bucket: file.bucket,
182
+ Key: key,
183
+ IfNoneMatch: ifNoneMatch,
184
+ IfModifiedSince: ifModifiedSince,
185
+ Range: range,
186
+ }));
187
+ }
188
+ catch (error) {
189
+ const status = error
190
+ .$metadata?.httpStatusCode;
191
+ if (status === 304) {
192
+ if (!res.getHeader("Cache-Control")) {
193
+ res.setHeader("Cache-Control", "public, max-age=0");
194
+ }
195
+ // The object's own, not the client's `If-None-Match`, which can be a
196
+ // list or `*`.
197
+ const etag = error.$response?.headers?.etag;
198
+ if (etag)
199
+ res.setHeader("ETag", etag);
200
+ res.statusCode = 304;
201
+ res.end();
202
+ return true;
203
+ }
204
+ if (status === 416) {
205
+ // S3's `InvalidRange`. `send` adds `Content-Range: bytes */<size>`, which
206
+ // S3's error does not carry; the status is what a client acts on.
207
+ res.statusCode = 416;
208
+ res.setHeader("Accept-Ranges", "bytes");
209
+ res.end();
210
+ return true;
211
+ }
212
+ const name = error?.name;
213
+ if (status === 404 || name === "NoSuchKey" || name === "NotFound") {
214
+ return false;
215
+ }
216
+ throw error;
217
+ }
218
+ if (!res.getHeader("Content-Type") && object.ContentType) {
219
+ res.setHeader("Content-Type", object.ContentType);
220
+ }
221
+ if (!res.getHeader("Cache-Control")) {
222
+ res.setHeader("Cache-Control", object.CacheControl || "public, max-age=0");
223
+ }
224
+ if (object.AcceptRanges)
225
+ res.setHeader("Accept-Ranges", object.AcceptRanges);
226
+ if (object.ContentRange) {
227
+ res.statusCode = 206;
228
+ res.setHeader("Content-Range", object.ContentRange);
229
+ }
230
+ if (file.etag && object.ETag)
231
+ res.setHeader("ETag", object.ETag);
232
+ if (object.LastModified) {
233
+ res.setHeader("Last-Modified", object.LastModified.toUTCString());
234
+ }
235
+ if (object.ContentLength !== undefined) {
236
+ res.setHeader("Content-Length", String(object.ContentLength));
237
+ }
238
+ const body = object.Body;
239
+ if (req.method === "HEAD" || !body) {
240
+ res.end();
241
+ return true;
242
+ }
243
+ const stream = body instanceof node_stream_1.Readable
244
+ ? body
245
+ : node_stream_1.Readable.from(body);
246
+ try {
247
+ for await (const chunk of stream) {
248
+ if (!res.write(chunk) && !(await (0, util_1.drained)(res))) {
249
+ // The client went away; the rest of the object is not wanted.
250
+ return true;
251
+ }
252
+ }
253
+ res.end();
254
+ }
255
+ finally {
256
+ // A no-op once fully read; otherwise it releases the S3 connection.
257
+ stream.destroy();
258
+ }
259
+ return true;
260
+ }
261
+ /** An HTTP date, or `undefined` for one that does not parse, as `fresh` treats it. */
262
+ function httpDate(value) {
263
+ const date = value ? new Date(value) : undefined;
264
+ return date && !Number.isNaN(date.getTime()) ? date : undefined;
265
+ }
266
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLWZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3RhdGljLWZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBbURBLDBDQXFDQztBQXdHRCw4Q0E2R0M7QUE3U0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILHNEQUFzRDtBQUN0RCx5Q0FBb0M7QUFDcEMsNkNBQXVDO0FBQ3ZDLGtEQUk0QjtBQUU1Qiw4Q0FBdUU7QUFDdkUsaURBQTRDO0FBQzVDLGlDQUF1RDtBQUV2RCxNQUFNLFlBQVksR0FBRyxrQ0FBa0MsQ0FBQztBQUd4RCx5RUFBeUU7QUFDekUsSUFBSSxpQkFBZ0QsQ0FBQztBQUVyRDs7Ozs7Ozs7O0dBU0c7QUFDSSxLQUFLLFVBQVUsZUFBZSxDQUNuQyxHQUF3QixFQUN4QixHQUF1QixFQUN2QixjQUFzQixFQUN0QixRQUFnQixFQUNoQixPQUFtQztJQUVuQyxpQkFBaUIsS0FBSyxJQUFBLHlCQUFVLEVBQW9CLFlBQVksQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLEdBQUcsaUJBQWlCLENBQUM7SUFDMUQsc0JBQXNCLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxjQUFjLENBQUMsQ0FBQztJQUN0RCxJQUFJLENBQUM7UUFDSCx5RUFBeUU7UUFDekUseUVBQXlFO1FBQ3pFLHVFQUF1RTtRQUN2RSx5RUFBeUU7UUFDekUseUVBQXlFO1FBQ3pFLE1BQU0sV0FBVyxDQUNmLEdBQW1ELEVBQ25ELElBQUEsMkJBQWdCLEVBQUMsR0FBRyxDQUFDLEVBQ3JCLElBQUksUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFDM0QsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLENB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QyxDQUFDO0lBQ3ZELElBQUksQ0FBQztRQUNILElBQUksS0FBSyxFQUFFLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ2pDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLElBQUEsY0FBTyxFQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDL0MsOERBQThEO2dCQUM5RCxPQUFPLElBQUksQ0FBQztZQUNkLENBQUM7UUFDSCxDQUFDO1FBQ0QsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ1osQ0FBQztZQUFTLENBQUM7UUFDVCxvRUFBb0U7UUFDcEUsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ25CLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxzRkFBc0Y7QUFDdEYsU0FBUyxRQUFRLENBQUMsS0FBeUI7SUFDekMsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2pELE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDbEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VydmluZyB0aGUgc3RhdGljIGZpbGVzIHRoYXQgbm90aGluZyBpbiBmcm9udCBvZiB0aGUgY29tcHV0ZSBhbnN3ZXJzLlxuICpcbiAqIGBOZXh0anNTdGF0aWNBc3NldHNgIHVwbG9hZHMgYDxkaXN0RGlyPi9zdGF0aWNgIGFuZCBgcHVibGljYCB0byBTMywgYW5kXG4gKiBDbG91ZEZyb250IC8gQVBJIEdhdGV3YXkgcm91dGUgYSBmaWxlJ3Mgb3duIFVSTCB0aGVyZSDigJQgZXhjZXB0IG9uXG4gKiBgTmV4dGpzUmVnaW9uYWxDb250YWluZXJzYCwgd2hpY2ggaGFzIG5vdGhpbmcgaW4gZnJvbnQgb2YgaXQuIFdoYXQgc3RpbGxcbiAqIHJlYWNoZXMgdGhlIHJ1bnRpbWUgaXMgYSBmaWxlIHNvbWUgKm90aGVyKiBVUkwgbGFuZHMgb246IGEgYHJld3JpdGVzYCBlbnRyeVxuICogb3IgYSBtaWRkbGV3YXJlIHJld3JpdGUgb250byBgL21haW50ZW5hbmNlLmh0bWxgLCBgL2VuLVVTL3JvYm90cy50eHRgIGluIGFuXG4gKiBpMThuIGFwcC4gVGhlIGBOZXh0anNSZWdpb25hbENvbnRhaW5lcnNgIGltYWdlIGNvcGllcyBgcHVibGljYCBhbmRcbiAqIGA8ZGlzdERpcj4vc3RhdGljYCBpbiBhbmQgc2VydmVzIHRoZW0gb2ZmIGRpc2s7IHRoZSBvdGhlciB0eXBlcyBjYXJyeVxuICogbmVpdGhlciwgc28gYSBgcHVibGljL2AgZmlsZSBpcyBzdHJlYW1lZCBmcm9tIHRoZSBhc3NldHMgYnVja2V0IGluc3RlYWRcbiAqICh7QGxpbmsgc2VydmVTM1B1YmxpY0ZpbGV9KS5cbiAqIEV2ZXJ5dGhpbmcgZWxzZSBpbiBgbWFuaWZlc3Quc3RhdGljRmlsZXNgIGxpdmVzIHVuZGVyIGA8ZGlzdERpcj4vc2VydmVyYCDigJRcbiAqIGA0MDQuaHRtbGAsIGA1MDAuaHRtbGAsIGBmYXZpY29uLmljby5ib2R5YCwgZnVsbHktc3RhdGljIFBhZ2VzIFJvdXRlciBIVE1MIOKAlFxuICogYW5kIHJlYWNoZXMgdXMsIGV4YWN0bHkgYXMgaXQgcmVhY2hlcyBgbmV4dCBzdGFydGAuXG4gKlxuICogTmV4dC5qcydzIG93biBgc2VydmVTdGF0aWNgIGlzIHVzZWQgcmF0aGVyIHRoYW4gYSBgY3JlYXRlUmVhZFN0cmVhbWAsIGJlY2F1c2UgaXRcbiAqIGlzIGBzZW5kYCB1bmRlcm5lYXRoIGFuZCB0aGF0IGJyaW5ncyBjb25kaXRpb25hbCByZXF1ZXN0cyAoYElmLU5vbmUtTWF0Y2hgLFxuICogYElmLU1vZGlmaWVkLVNpbmNlYCksIGBSYW5nZWAsIGBFVGFnYCwgYExhc3QtTW9kaWZpZWRgLCBhbmQgY29udGVudC10eXBlXG4gKiBkZXRlY3Rpb24uIFJlaW1wbGVtZW50aW5nIHRob3NlIGlzIGhvdyBhIFwic2ltcGxlXCIgZmlsZSBzZXJ2ZXIgZW5kcyB1cFxuICogZGlzYWdyZWVpbmcgd2l0aCBgbmV4dCBzdGFydGAgb24gYSAzMDQuXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0IHsgZXh0bmFtZSB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IFJlYWRhYmxlIH0gZnJvbSBcIm5vZGU6c3RyZWFtXCI7XG5pbXBvcnQge1xuICBHZXRPYmplY3RDb21tYW5kLFxuICBHZXRPYmplY3RDb21tYW5kT3V0cHV0LFxuICBIZWFkT2JqZWN0Q29tbWFuZCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHR5cGUgeyBTaGltSW5jb21pbmdNZXNzYWdlIH0gZnJvbSBcIi4vaHR0cC9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBhc1NlcnZlclJlc3BvbnNlLCBTaGltU2VydmVyUmVzcG9uc2UgfSBmcm9tIFwiLi9odHRwL3Jlc3BvbnNlXCI7XG5pbXBvcnQgeyBuZXh0TW9kdWxlIH0gZnJvbSBcIi4vbmV4dC1tb2R1bGVzXCI7XG5pbXBvcnQgeyBkcmFpbmVkLCBmaXJzdFZhbHVlLCBzM0NsaWVudCB9IGZyb20gXCIuL3V0aWxcIjtcblxuY29uc3QgU0VSVkVfU1RBVElDID0gXCJuZXh0L2Rpc3Qvc2VydmVyL3NlcnZlLXN0YXRpYy5qc1wiO1xudHlwZSBTZXJ2ZVN0YXRpY01vZHVsZSA9IHR5cGVvZiBpbXBvcnQoXCJuZXh0L2Rpc3Qvc2VydmVyL3NlcnZlLXN0YXRpYy5qc1wiKTtcblxuLyoqIFJlc29sdmVkIG9uIHRoZSBmaXJzdCBzdGF0aWMtZmlsZSByZXF1ZXN0OyBzZWUge0BsaW5rIG5leHRNb2R1bGV9LiAqL1xubGV0IHNlcnZlU3RhdGljTW9kdWxlOiBTZXJ2ZVN0YXRpY01vZHVsZSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZXR1cm5zIGBmYWxzZWAgd2hlbiB0aGUgZmlsZSBpcyBub3QgaW4gdGhlIGRlcGxveW1lbnQgcGFja2FnZSwgd2hpY2ggaXMgdGhlXG4gKiBjYWxsZXIncyBjdWUgdG8gZmFsbCB0aHJvdWdoIHRvIGEgNDA0LlxuICpcbiAqIFRoYXQgaGFwcGVucyBieSBkZXNpZ24gb24gZXZlcnkgdHlwZSBidXQgYE5leHRqc1JlZ2lvbmFsQ29udGFpbmVyc2AsIGZvciBgPGRpc3REaXI+L3N0YXRpY2AgYW5kXG4gKiBgcHVibGljL2AgYWxpa2U6IG5laXRoZXIgaXMgc3RhZ2VkLCBiZWluZyBhIHNlY29uZCBjb3B5IG9mIGJ5dGVzIGFscmVhZHkgaW5cbiAqIFMzLiBBIGBwdWJsaWMvYCBmaWxlIGlzIHRoZW4gc2VydmVkIGJ5IHtAbGluayBzZXJ2ZVMzUHVibGljRmlsZX07IGFcbiAqIGA8ZGlzdERpcj4vc3RhdGljYCBvbmUgb25seSBnZXRzIGhlcmUgdGhyb3VnaCBhIHJld3JpdGUgb250byBpdCwgYW5kIGlzIGEgNDA0LlxuICogVGhlIGBOZXh0anNSZWdpb25hbENvbnRhaW5lcnNgIGltYWdlIGNvcGllcyBib3RoIGluLCBzbyB0aGVyZSB0aGV5IGFyZSBmb3VuZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlcnZlU3RhdGljRmlsZShcbiAgcmVxOiBTaGltSW5jb21pbmdNZXNzYWdlLFxuICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgZGVwbG95bWVudFJvb3Q6IHN0cmluZyxcbiAgZmlsZVBhdGg6IHN0cmluZyxcbiAgb3B0aW9uczogeyByZWFkb25seSBldGFnOiBib29sZWFuIH0sXG4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgc2VydmVTdGF0aWNNb2R1bGUgPz89IG5leHRNb2R1bGU8U2VydmVTdGF0aWNNb2R1bGU+KFNFUlZFX1NUQVRJQyk7XG4gIGNvbnN0IHsgc2VydmVTdGF0aWMsIGdldENvbnRlbnRUeXBlIH0gPSBzZXJ2ZVN0YXRpY01vZHVsZTtcbiAgc2V0Qm9keUZpbGVDb250ZW50VHlwZShyZXMsIGZpbGVQYXRoLCBnZXRDb250ZW50VHlwZSk7XG4gIHRyeSB7XG4gICAgLy8gRW5jb2RlZCwgYW5kIHJlbGF0aXZlIHRvIGEgYHJvb3RgLCB3aGljaCBpcyBob3cgYG5leHQgc3RhcnRgIGNhbGxzIGl0OlxuICAgIC8vIGBzZW5kYCBwZXJjZW50LWRlY29kZXMgd2hhdGV2ZXIgcGF0aCBpdCBpcyBoYW5kZWQsIGFzIHRob3VnaCBpdCB3ZXJlIGFcbiAgICAvLyBVUkwuIEEgcmF3IGZpbGVzeXN0ZW0gcGF0aCBicm9rZSBvbiBhbnkgZmlsZSBuYW1lIHdpdGggYSBgJWAgaW4gaXQg4oCUXG4gICAgLy8gYDEwMCUucG5nYCBmYWlsZWQgdG8gZGVjb2RlIGFuZCBhbnN3ZXJlZCBhbiBlbXB0eSA0MDAsIGFuZCBgYSUyMGIudHh0YFxuICAgIC8vIHdhcyBsb29rZWQgdXAgYXMgYGEgYi50eHRgLCBzZXJ2aW5nIGEgZGlmZmVyZW50IGZpbGUgaWYgdGhlcmUgd2FzIG9uZS5cbiAgICBhd2FpdCBzZXJ2ZVN0YXRpYyhcbiAgICAgIHJlcSBhcyB1bmtub3duIGFzIFBhcmFtZXRlcnM8dHlwZW9mIHNlcnZlU3RhdGljPlswXSxcbiAgICAgIGFzU2VydmVyUmVzcG9uc2UocmVzKSxcbiAgICAgIGAvJHtmaWxlUGF0aC5zcGxpdChcIi9cIikubWFwKGVuY29kZVVSSUNvbXBvbmVudCkuam9pbihcIi9cIil9YCxcbiAgICAgIHsgcm9vdDogZGVwbG95bWVudFJvb3QsIGV0YWc6IG9wdGlvbnMuZXRhZyB9LFxuICAgICk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGlzTWlzc2luZ0ZpbGUoZXJyb3IpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IHN0YXR1cyA9IGh0dHBFcnJvclN0YXR1cyhlcnJvcik7XG4gICAgLy8gYHNlbmRgIGVtaXRzIGl0cyBlcnJvciBiZWZvcmUgdGhlIGZpcnN0IGJ5dGUsIHNvIHRoZSBoZWFkIGlzIHN0aWxsIG91cnMgdG9cbiAgICAvLyBzZXQ7IHRoZSBndWFyZCBpcyBvbmx5IGZvciBhIHNoZWxsIHRoYXQgYWxyZWFkeSBjb21taXR0ZWQgb25lLlxuICAgIGlmIChzdGF0dXMgIT09IHVuZGVmaW5lZCAmJiAhcmVzLmhlYWRlcnNTZW50KSB7XG4gICAgICByZXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcbiAgICAgIHJlcy5lbmQoKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBzdGF0dXMgYSBgc2VuZGAgZXJyb3IgY2FycmllcywgZm9yIHRoZSBlcnJvcnMgdGhhdCBhcmUgdGhlICpjbGllbnQncyosIG5vdFxuICogb3Vycy5cbiAqXG4gKiBgc2VydmVTdGF0aWNgIGlzIGBzZW5kYCB1bmRlcm5lYXRoLCBhbmQgYHNlbmRgIHJlamVjdHMgYSBmYWlsZWQgcHJlY29uZGl0aW9uXG4gKiB3aXRoIGEgNDEyIGFuZCBhbiB1bnNhdGlzZmlhYmxlIGBSYW5nZWAgd2l0aCBhIDQxNiDigJQgYm90aCBhdHRhY2hlZCB0byB0aGUgZXJyb3JcbiAqIGFzIGBzdGF0dXNDb2RlYC4gYG5leHQgc3RhcnRgIG1hcHMgdGhlbSBiYWNrIG9udG8gdGhlIHJlc3BvbnNlXG4gKiAoYG5leHQvZGlzdC9zZXJ2ZXIvbGliL3JvdXRlci1zZXJ2ZXIuanNgIHNwZWNpYWwtY2FzZXMgNDAwLzQxMi80MTYpOyBsZXR0aW5nXG4gKiB0aGVtIGZhbGwgdGhyb3VnaCB0byB0aGUgY2FsbGVyJ3MgZXJyb3IgcGF0aCAoYE5leHRqc1J1bnRpbWUuc2VuZEVycm9yYCwgd2hpY2hcbiAqIGFuc3dlcnMgNTAwIHdpdGggdGhlIGFwcCdzIGVycm9yIHBhZ2UpIGluc3RlYWQgdHVybmVkIGBJZi1NYXRjaDogXCJzdGFsZVwiYCBpbnRvXG4gKiBhIDUwMCBhbmQgYFJhbmdlOiBieXRlcz05OTk5OS1gIGludG8gYSA1MDAuXG4gKlxuICogT25seSA0eHggaXMgaG9ub3JlZDogYSA1eHggZnJvbSBgc2VuZGAgaXMgYSByZWFsIGZhaWx1cmUgYW5kIGJlbG9uZ3MgaW4gdGhlXG4gKiBlcnJvciBwYXRoLCB3aXRoIHRoZSBzdGFjay5cbiAqL1xuZnVuY3Rpb24gaHR0cEVycm9yU3RhdHVzKGVycm9yOiB1bmtub3duKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc3RhdHVzID0gKGVycm9yIGFzIHsgc3RhdHVzQ29kZT86IHVua25vd24gfSB8IG51bGwpPy5zdGF0dXNDb2RlO1xuICBpZiAodHlwZW9mIHN0YXR1cyA9PT0gXCJudW1iZXJcIiAmJiBzdGF0dXMgPj0gNDAwICYmIHN0YXR1cyA8IDUwMCkge1xuICAgIHJldHVybiBzdGF0dXM7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBgc2VuZGAgdHlwZXMgYSByZXNwb25zZSBmcm9tIHRoZSBmaWxlJ3Mgb3duIGV4dGVuc2lvbiwgYW5kIGEgc3RhdGljIG1ldGFkYXRhXG4gKiByb3V0ZSBzaGlwcyBhcyBgPHJvdXRlPi5ib2R5YCDigJQgYHJvYm90cy50eHQuYm9keWAsIGBtYW5pZmVzdC53ZWJtYW5pZmVzdC5ib2R5YCxcbiAqIGBmYXZpY29uLmljby5ib2R5YC4gYC5ib2R5YCBpcyBub3QgYSBtZWRpYSB0eXBlLCBzbyBldmVyeSBvbmUgb2YgdGhlbSB3b3VsZCBnb1xuICogb3V0IGFzIGBhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1gLlxuICpcbiAqIE5leHQuanMncyBhZGFwdGVyIEFQSSBpcyB3aGVyZSB0aGUgdHlwZSBpcyBsb3N0OiBgYnVpbGQtY29tcGxldGUudHNgIHB1c2hlc1xuICogdGhlc2UgdGhyb3VnaCBgaXNTdGF0aWNNZXRhZGF0YUZpbGUoKWAgYXMgYSBiYXJlIGBTVEFUSUNfRklMRWAg4oCUIGBpZGAsXG4gKiBgcGF0aG5hbWVgLCBgZmlsZVBhdGhgLCBhbmQgbm90aGluZyBlbHNlIOKAlCB3aGlsZSB0aGUgaGVhZGVycyB0aGUgcm91dGUgaGFuZGxlclxuICogYWN0dWFsbHkgc2V0IHNpdCB1bnJlZmVyZW5jZWQgaW4gYSBzaWJsaW5nIGA8cm91dGU+Lm1ldGFgLiBgbmV4dCBzdGFydGAgcmVhZHNcbiAqIHRoYXQgZmlsZSB0aHJvdWdoIHRoZSByZXNwb25zZSBjYWNoZSBhbmQgYW5zd2VycyBgdGV4dC9wbGFpbmAuXG4gKlxuICogU3RyaXBwaW5nIGAuYm9keWAgcHV0cyB0aGUgcm91dGUncyBvd24gZXh0ZW5zaW9uIGJhY2sgb24gdGhlIGVuZCwgd2hpY2ggZm9yXG4gKiB0aGlzIHBvcHVsYXRpb24gaXMgdGhlIHNhbWUgYW5zd2VyOiB0aGUgc2V0IGlzIGNsb3NlZCAoYGZhdmljb24uaWNvYCwgYGljb24uKmAsXG4gKiBgYXBwbGUtaWNvbi4qYCwgYG9wZW5ncmFwaC1pbWFnZS4qYCwgYHR3aXR0ZXItaW1hZ2UuKmAsIGBzaXRlbWFwLnhtbGAsXG4gKiBgcm9ib3RzLnR4dGAsIGBtYW5pZmVzdC57anNvbix3ZWJtYW5pZmVzdH1gKSBhbmQgZXZlcnkgbWVtYmVyJ3MgdHlwZSBpcyBpbXBsaWVkXG4gKiBieSBpdHMgZXh0ZW5zaW9uLiBgc2VuZGAgc2tpcHMgaXRzIG93biBkZXRlY3Rpb24gd2hlbiBgQ29udGVudC1UeXBlYCBpcyBhbHJlYWR5XG4gKiBzZXQgKGBzZW5kL2luZGV4LmpzYCwgYHR5cGUoKWApLCBzbyB0aGlzIHdpbnMgd2l0aG91dCByZWFjaGluZyBmb3IgYG9wdHNgLlxuICovXG5mdW5jdGlvbiBzZXRCb2R5RmlsZUNvbnRlbnRUeXBlKFxuICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgZmlsZVBhdGg6IHN0cmluZyxcbiAgZ2V0Q29udGVudFR5cGU6IFNlcnZlU3RhdGljTW9kdWxlW1wiZ2V0Q29udGVudFR5cGVcIl0sXG4pOiB2b2lkIHtcbiAgaWYgKCFmaWxlUGF0aC5lbmRzV2l0aChcIi5ib2R5XCIpIHx8IHJlcy5nZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIikpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgY29uc3QgZXh0ID0gZXh0bmFtZShmaWxlUGF0aC5zbGljZSgwLCAtXCIuYm9keVwiLmxlbmd0aCkpLnNsaWNlKDEpO1xuICBpZiAoIWV4dCkge1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBjb250ZW50VHlwZSA9IGdldENvbnRlbnRUeXBlKGV4dCk7XG4gIGlmIChjb250ZW50VHlwZSkge1xuICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgY29udGVudFR5cGUpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGlzTWlzc2luZ0ZpbGUoZXJyb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgY29uc3QgY29kZSA9IChlcnJvciBhcyB7IGNvZGU/OiBzdHJpbmcgfSB8IG51bGwpPy5jb2RlO1xuICAvLyBFTk9FTlQgY292ZXJzIGEgbWlzc2luZyBmaWxlIGFuZCBgc2VuZGAncyBcIk5vIGRpcmVjdG9yeSBhY2Nlc3NcIjsgRU5PVERJUiBpc1xuICAvLyB3aGF0IGEgcGF0aCBzZWdtZW50IHRoYXQgZXhpc3RzIGFzIGEgZmlsZSBwcm9kdWNlcy5cbiAgcmV0dXJuIGNvZGUgPT09IFwiRU5PRU5UXCIgfHwgY29kZSA9PT0gXCJFTk9URElSXCI7XG59XG5cbi8qKiBXaGVyZSBhIHR5cGUgd2l0aG91dCBgcHVibGljL2Agb24gZGlzayBmaW5kcyBhIGZpbGUgaXQgZG9lcyBub3QgY2FycnkuICovXG5leHBvcnQgaW50ZXJmYWNlIFMzUHVibGljRmlsZSB7XG4gIC8qKiBgQ0RLX05FWFRKU19TVEFUSUNfQVNTRVRTX0JVQ0tFVF9OQU1FYC4gKi9cbiAgcmVhZG9ubHkgYnVja2V0OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBgTmV4dGpzU3RhdGljQXNzZXRzLmtleVByZWZpeGAsIHdpdGhvdXQgYSBsZWFkaW5nIHNsYXNoOyBlbXB0eSBmb3IgYVxuICAgKiBidWNrZXQtcm9vdCBkZXBsb3ltZW50LiBgcHVibGljL2AgaXMgdXBsb2FkZWQgdG8gdGhlIHJvb3Qgb2YgaXQuXG4gICAqL1xuICByZWFkb25seSBrZXlQcmVmaXg6IHN0cmluZztcbiAgLyoqIFRoZSBmaWxlJ3MgcGF0aCByZWxhdGl2ZSB0byBgcHVibGljL2AsIHVuZW5jb2RlZDogaXRzIHJlYWwgbmFtZS4gKi9cbiAgcmVhZG9ubHkgZmlsZTogc3RyaW5nO1xuICByZWFkb25seSBldGFnOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEEgYHB1YmxpYy9gIGZpbGUgZnJvbSB0aGUgYXNzZXRzIGJ1Y2tldCwgZm9yIHRoZSB0eXBlcyB3aG9zZSBkZXBsb3ltZW50XG4gKiByb290cyBsaXN0IGBwdWJsaWMvYCB3aXRob3V0IGNhcnJ5aW5nIGl0LiBSZXR1cm5zIGBmYWxzZWAgd2hlbiB0aGUgb2JqZWN0IGlzIG5vdCB0aGVyZSxcbiAqIHdoaWNoIGlzIHRoZSBjYWxsZXIncyBjdWUgdG8gZmFsbCB0aHJvdWdoIHRvIGEgNDA0IGFzIGZvciBhIGZpbGUgbWlzc2luZyBmcm9tXG4gKiBkaXNrLlxuICpcbiAqIFdoYXQgYHNlbmRgIHdvdWxkIGhhdmUgYW5zd2VyZWQsIGFzIGZhciBhcyBTMyBjYW4gc2F5IGl0OiB0aGUgb2JqZWN0J3NcbiAqIGBDb250ZW50LVR5cGVgLCBgQ29udGVudC1MZW5ndGhgLCBgTGFzdC1Nb2RpZmllZGAgYW5kIOKAlCB1bmxlc3NcbiAqIGBnZW5lcmF0ZUV0YWdzYCBpcyBvZmYg4oCUIGBFVGFnYDsgYSAzMDQgZm9yIGEgbWF0Y2hpbmcgYElmLU5vbmUtTWF0Y2hgIG9yLCBhc1xuICogYGZyZXNoYCBoYXMgaXQsIGFuIGBJZi1Nb2RpZmllZC1TaW5jZWAgd2l0aG91dCBvbmU7IGFuZCBhIDIwNiBvciA0MTYgZm9yIGFcbiAqIGBSYW5nZWAuIFMzIGV2YWx1YXRlcyBhbGwgb2YgdGhlbSBpdHNlbGYuXG4gKlxuICogYENhY2hlLUNvbnRyb2xgIGlzLCBpbiBvcmRlcjogYSBgaGVhZGVycygpYCBydWxlJ3MsIHRoZSBvYmplY3QncyBvd25cbiAqIGBDYWNoZUNvbnRyb2xgIG1ldGFkYXRhIOKAlCB3aGF0IHRoZSBlZGdlIHNlcnZlcyB0aGUgZmlsZSdzIG93biBVUkwgd2l0aCwgc28gYVxuICogcmV3cml0ZSBvbnRvIGl0IGNhY2hlcyB0aGUgc2FtZSB3YXkg4oCUIGFuZCBgc2VuZGAncyBkZWZhdWx0LFxuICogYHB1YmxpYywgbWF4LWFnZT0wYC5cbiAqXG4gKiBgSWYtUmFuZ2VgIGlzIG5vdCBldmFsdWF0ZWQsIGJlY2F1c2UgUzMgaGFzIG5vIGNvdW50ZXJwYXJ0OiB3aXRoIG9uZSBwcmVzZW50XG4gKiB0aGUgYFJhbmdlYCBpcyBkcm9wcGVkIGFuZCB0aGUgd2hvbGUgZmlsZSBzZW50IHdpdGggYSAyMDAsIHdoaWNoIFJGQyA5MTEwXG4gKiBhbGxvd3MgKGEgc2VydmVyIG1heSBpZ25vcmUgYFJhbmdlYCkgYW5kIGEgcmFuZ2UgY2xpZW50IGFjY2VwdHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZXJ2ZVMzUHVibGljRmlsZShcbiAgcmVxOiBTaGltSW5jb21pbmdNZXNzYWdlLFxuICByZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSxcbiAgZmlsZTogUzNQdWJsaWNGaWxlLFxuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IHByZWZpeCA9IGZpbGUua2V5UHJlZml4LnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpO1xuICBjb25zdCBrZXkgPSBwcmVmaXggPyBgJHtwcmVmaXh9LyR7ZmlsZS5maWxlfWAgOiBmaWxlLmZpbGU7XG4gIGNvbnN0IGlmTm9uZU1hdGNoID0gZmlsZS5ldGFnXG4gICAgPyBmaXJzdFZhbHVlKHJlcS5oZWFkZXJzW1wiaWYtbm9uZS1tYXRjaFwiXSlcbiAgICA6IHVuZGVmaW5lZDtcbiAgLy8gYGZyZXNoYCBpZ25vcmVzIGl0IG5leHQgdG8gYW4gYElmLU5vbmUtTWF0Y2hgLCBldmVuIG9uZSBpdCBjYW5ub3QgbWF0Y2hcbiAgLy8gYmVjYXVzZSBgZ2VuZXJhdGVFdGFnc2AgaXMgb2ZmLlxuICBjb25zdCBpZk1vZGlmaWVkU2luY2UgPSByZXEuaGVhZGVyc1tcImlmLW5vbmUtbWF0Y2hcIl1cbiAgICA/IHVuZGVmaW5lZFxuICAgIDogaHR0cERhdGUoZmlyc3RWYWx1ZShyZXEuaGVhZGVyc1tcImlmLW1vZGlmaWVkLXNpbmNlXCJdKSk7XG4gIGNvbnN0IHJhbmdlID0gcmVxLmhlYWRlcnNbXCJpZi1yYW5nZVwiXVxuICAgID8gdW5kZWZpbmVkXG4gICAgOiBmaXJzdFZhbHVlKHJlcS5oZWFkZXJzLnJhbmdlKTtcbiAgbGV0IG9iamVjdDogT21pdDxHZXRPYmplY3RDb21tYW5kT3V0cHV0LCBcIkJvZHlcIj4gJiB7IEJvZHk/OiB1bmtub3duIH07XG4gIHRyeSB7XG4gICAgb2JqZWN0ID0gYXdhaXQgczNDbGllbnQoKS5zZW5kKFxuICAgICAgcmVxLm1ldGhvZCA9PT0gXCJIRUFEXCJcbiAgICAgICAgPyBuZXcgSGVhZE9iamVjdENvbW1hbmQoe1xuICAgICAgICAgICAgQnVja2V0OiBmaWxlLmJ1Y2tldCxcbiAgICAgICAgICAgIEtleToga2V5LFxuICAgICAgICAgICAgSWZOb25lTWF0Y2g6IGlmTm9uZU1hdGNoLFxuICAgICAgICAgICAgSWZNb2RpZmllZFNpbmNlOiBpZk1vZGlmaWVkU2luY2UsXG4gICAgICAgICAgICBSYW5nZTogcmFuZ2UsXG4gICAgICAgICAgfSlcbiAgICAgICAgOiBuZXcgR2V0T2JqZWN0Q29tbWFuZCh7XG4gICAgICAgICAgICBCdWNrZXQ6IGZpbGUuYnVja2V0LFxuICAgICAgICAgICAgS2V5OiBrZXksXG4gICAgICAgICAgICBJZk5vbmVNYXRjaDogaWZOb25lTWF0Y2gsXG4gICAgICAgICAgICBJZk1vZGlmaWVkU2luY2U6IGlmTW9kaWZpZWRTaW5jZSxcbiAgICAgICAgICAgIFJhbmdlOiByYW5nZSxcbiAgICAgICAgICB9KSxcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGNvbnN0IHN0YXR1cyA9IChlcnJvciBhcyB7ICRtZXRhZGF0YT86IHsgaHR0cFN0YXR1c0NvZGU/OiBudW1iZXIgfSB9KVxuICAgICAgLiRtZXRhZGF0YT8uaHR0cFN0YXR1c0NvZGU7XG4gICAgaWYgKHN0YXR1cyA9PT0gMzA0KSB7XG4gICAgICBpZiAoIXJlcy5nZXRIZWFkZXIoXCJDYWNoZS1Db250cm9sXCIpKSB7XG4gICAgICAgIHJlcy5zZXRIZWFkZXIoXCJDYWNoZS1Db250cm9sXCIsIFwicHVibGljLCBtYXgtYWdlPTBcIik7XG4gICAgICB9XG4gICAgICAvLyBUaGUgb2JqZWN0J3Mgb3duLCBub3QgdGhlIGNsaWVudCdzIGBJZi1Ob25lLU1hdGNoYCwgd2hpY2ggY2FuIGJlIGFcbiAgICAgIC8vIGxpc3Qgb3IgYCpgLlxuICAgICAgY29uc3QgZXRhZyA9IChcbiAgICAgICAgZXJyb3IgYXMgeyAkcmVzcG9uc2U/OiB7IGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH0gfVxuICAgICAgKS4kcmVzcG9uc2U/LmhlYWRlcnM/LmV0YWc7XG4gICAgICBpZiAoZXRhZykgcmVzLnNldEhlYWRlcihcIkVUYWdcIiwgZXRhZyk7XG4gICAgICByZXMuc3RhdHVzQ29kZSA9IDMwNDtcbiAgICAgIHJlcy5lbmQoKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpZiAoc3RhdHVzID09PSA0MTYpIHtcbiAgICAgIC8vIFMzJ3MgYEludmFsaWRSYW5nZWAuIGBzZW5kYCBhZGRzIGBDb250ZW50LVJhbmdlOiBieXRlcyAqLzxzaXplPmAsIHdoaWNoXG4gICAgICAvLyBTMydzIGVycm9yIGRvZXMgbm90IGNhcnJ5OyB0aGUgc3RhdHVzIGlzIHdoYXQgYSBjbGllbnQgYWN0cyBvbi5cbiAgICAgIHJlcy5zdGF0dXNDb2RlID0gNDE2O1xuICAgICAgcmVzLnNldEhlYWRlcihcIkFjY2VwdC1SYW5nZXNcIiwgXCJieXRlc1wiKTtcbiAgICAgIHJlcy5lbmQoKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBjb25zdCBuYW1lID0gKGVycm9yIGFzIHsgbmFtZT86IHN0cmluZyB9IHwgbnVsbCk/Lm5hbWU7XG4gICAgaWYgKHN0YXR1cyA9PT0gNDA0IHx8IG5hbWUgPT09IFwiTm9TdWNoS2V5XCIgfHwgbmFtZSA9PT0gXCJOb3RGb3VuZFwiKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHRocm93IGVycm9yO1xuICB9XG5cbiAgaWYgKCFyZXMuZ2V0SGVhZGVyKFwiQ29udGVudC1UeXBlXCIpICYmIG9iamVjdC5Db250ZW50VHlwZSkge1xuICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgb2JqZWN0LkNvbnRlbnRUeXBlKTtcbiAgfVxuICBpZiAoIXJlcy5nZXRIZWFkZXIoXCJDYWNoZS1Db250cm9sXCIpKSB7XG4gICAgcmVzLnNldEhlYWRlcihcIkNhY2hlLUNvbnRyb2xcIiwgb2JqZWN0LkNhY2hlQ29udHJvbCB8fCBcInB1YmxpYywgbWF4LWFnZT0wXCIpO1xuICB9XG4gIGlmIChvYmplY3QuQWNjZXB0UmFuZ2VzKSByZXMuc2V0SGVhZGVyKFwiQWNjZXB0LVJhbmdlc1wiLCBvYmplY3QuQWNjZXB0UmFuZ2VzKTtcbiAgaWYgKG9iamVjdC5Db250ZW50UmFuZ2UpIHtcbiAgICByZXMuc3RhdHVzQ29kZSA9IDIwNjtcbiAgICByZXMuc2V0SGVhZGVyKFwiQ29udGVudC1SYW5nZVwiLCBvYmplY3QuQ29udGVudFJhbmdlKTtcbiAgfVxuICBpZiAoZmlsZS5ldGFnICYmIG9iamVjdC5FVGFnKSByZXMuc2V0SGVhZGVyKFwiRVRhZ1wiLCBvYmplY3QuRVRhZyk7XG4gIGlmIChvYmplY3QuTGFzdE1vZGlmaWVkKSB7XG4gICAgcmVzLnNldEhlYWRlcihcIkxhc3QtTW9kaWZpZWRcIiwgb2JqZWN0Lkxhc3RNb2RpZmllZC50b1VUQ1N0cmluZygpKTtcbiAgfVxuICBpZiAob2JqZWN0LkNvbnRlbnRMZW5ndGggIT09IHVuZGVmaW5lZCkge1xuICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LUxlbmd0aFwiLCBTdHJpbmcob2JqZWN0LkNvbnRlbnRMZW5ndGgpKTtcbiAgfVxuICBjb25zdCBib2R5ID0gb2JqZWN0LkJvZHk7XG4gIGlmIChyZXEubWV0aG9kID09PSBcIkhFQURcIiB8fCAhYm9keSkge1xuICAgIHJlcy5lbmQoKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBjb25zdCBzdHJlYW0gPVxuICAgIGJvZHkgaW5zdGFuY2VvZiBSZWFkYWJsZVxuICAgICAgPyBib2R5XG4gICAgICA6IFJlYWRhYmxlLmZyb20oYm9keSBhcyBBc3luY0l0ZXJhYmxlPFVpbnQ4QXJyYXk+KTtcbiAgdHJ5IHtcbiAgICBmb3IgYXdhaXQgKGNvbnN0IGNodW5rIG9mIHN0cmVhbSkge1xuICAgICAgaWYgKCFyZXMud3JpdGUoY2h1bmspICYmICEoYXdhaXQgZHJhaW5lZChyZXMpKSkge1xuICAgICAgICAvLyBUaGUgY2xpZW50IHdlbnQgYXdheTsgdGhlIHJlc3Qgb2YgdGhlIG9iamVjdCBpcyBub3Qgd2FudGVkLlxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmVzLmVuZCgpO1xuICB9IGZpbmFsbHkge1xuICAgIC8vIEEgbm8tb3Agb25jZSBmdWxseSByZWFkOyBvdGhlcndpc2UgaXQgcmVsZWFzZXMgdGhlIFMzIGNvbm5lY3Rpb24uXG4gICAgc3RyZWFtLmRlc3Ryb3koKTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqIEFuIEhUVFAgZGF0ZSwgb3IgYHVuZGVmaW5lZGAgZm9yIG9uZSB0aGF0IGRvZXMgbm90IHBhcnNlLCBhcyBgZnJlc2hgIHRyZWF0cyBpdC4gKi9cbmZ1bmN0aW9uIGh0dHBEYXRlKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBEYXRlIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZGF0ZSA9IHZhbHVlID8gbmV3IERhdGUodmFsdWUpIDogdW5kZWZpbmVkO1xuICByZXR1cm4gZGF0ZSAmJiAhTnVtYmVyLmlzTmFOKGRhdGUuZ2V0VGltZSgpKSA/IGRhdGUgOiB1bmRlZmluZWQ7XG59XG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable import/no-extraneous-dependencies */
4
+ const node_stream_1 = require("node:stream");
5
+ const client_s3_1 = require("@aws-sdk/client-s3");
6
+ const request_1 = require("./http/request");
7
+ const response_1 = require("./http/response");
8
+ const static_files_1 = require("./static-files");
9
+ const send$ = jest.spyOn(client_s3_1.S3Client.prototype, "send");
10
+ afterEach(() => send$.mockReset());
11
+ afterAll(() => send$.mockRestore());
12
+ const FILE = { bucket: "assets", keyPrefix: "", file: "big.bin", etag: true };
13
+ function serve(method, res = new response_1.ShimServerResponse(), headers = {}, file = FILE) {
14
+ const req = new request_1.ShimIncomingMessage({ method, url: "/big.bin", headers });
15
+ return { res, served: (0, static_files_1.serveS3PublicFile)(req, res, file) };
16
+ }
17
+ /** Chunks bigger than the response's buffer, so every write is refused. */
18
+ const CHUNK = Buffer.alloc(64 * 1024, "a");
19
+ describe("serveS3PublicFile", () => {
20
+ it("asks S3 for the head alone for a HEAD, and sends no body", async () => {
21
+ send$.mockImplementation((async () => ({
22
+ ContentType: "application/octet-stream",
23
+ ContentLength: 3,
24
+ ETag: '"e1"',
25
+ })));
26
+ const { res, served } = serve("HEAD");
27
+ const chunks = [];
28
+ res.on("data", (chunk) => chunks.push(chunk));
29
+ expect(await served).toBe(true);
30
+ expect(send$.mock.calls[0][0]).toBeInstanceOf(client_s3_1.HeadObjectCommand);
31
+ expect(res.getHeader("Content-Length")).toBe("3");
32
+ expect(res.getHeader("ETag")).toBe('"e1"');
33
+ expect(res.writableEnded).toBe(true);
34
+ expect(Buffer.concat(chunks).length).toBe(0);
35
+ });
36
+ // `generateEtags: false`: no ETag to revalidate with, only Last-Modified.
37
+ it("answers If-Modified-Since with a 304, as send does", async () => {
38
+ send$.mockImplementation((async () => {
39
+ throw Object.assign(new Error("Not Modified"), {
40
+ $metadata: { httpStatusCode: 304 },
41
+ });
42
+ }));
43
+ const since = "Wed, 21 Oct 2015 07:28:00 GMT";
44
+ const { res, served } = serve("GET", undefined, { "if-modified-since": since }, { ...FILE, etag: false });
45
+ expect(await served).toBe(true);
46
+ expect(res.statusCode).toBe(304);
47
+ const input = send$.mock.calls[0][0].input;
48
+ expect(input.IfModifiedSince).toEqual(new Date(since));
49
+ expect(input.IfNoneMatch).toBeUndefined();
50
+ });
51
+ // The 304's ETag is the object's, not the client's list of candidates.
52
+ it.each([
53
+ ["the object's ETag", { headers: { etag: '"e1"' } }, '"e1"'],
54
+ ["no ETag without one", undefined, undefined],
55
+ ])("answers an If-None-Match list with %s", async (_, $response, etag) => {
56
+ send$.mockImplementation((async () => {
57
+ throw Object.assign(new Error("Not Modified"), {
58
+ $metadata: { httpStatusCode: 304 },
59
+ $response,
60
+ });
61
+ }));
62
+ const { res, served } = serve("GET", undefined, {
63
+ "if-none-match": '"e0", "e1"',
64
+ });
65
+ expect(await served).toBe(true);
66
+ expect(res.statusCode).toBe(304);
67
+ expect(res.getHeader("ETag")).toBe(etag);
68
+ });
69
+ // `fresh` ignores If-Modified-Since next to an If-None-Match.
70
+ it("leaves If-Modified-Since out next to an If-None-Match", async () => {
71
+ send$.mockImplementation((async () => ({})));
72
+ await serve("HEAD", undefined, {
73
+ "if-none-match": '"e1"',
74
+ "if-modified-since": "Wed, 21 Oct 2015 07:28:00 GMT",
75
+ }).served;
76
+ const input = send$.mock.calls[0][0].input;
77
+ expect(input.IfNoneMatch).toBe('"e1"');
78
+ expect(input.IfModifiedSince).toBeUndefined();
79
+ });
80
+ it("rethrows an S3 error that is not a missing object", async () => {
81
+ send$.mockImplementation((async () => {
82
+ throw Object.assign(new Error("Access Denied"), {
83
+ name: "AccessDenied",
84
+ $metadata: { httpStatusCode: 403 },
85
+ });
86
+ }));
87
+ await expect(serve("GET").served).rejects.toThrow("Access Denied");
88
+ });
89
+ it("waits for the client to drain before reading more of the object", async () => {
90
+ send$.mockImplementation((async () => ({
91
+ Body: node_stream_1.Readable.from([CHUNK, CHUNK, CHUNK]),
92
+ })));
93
+ const { res, served } = serve("GET");
94
+ expect(send$.mock.calls[0][0]).toBeInstanceOf(client_s3_1.GetObjectCommand);
95
+ // Nothing reads the response yet, so the first write is refused and the
96
+ // rest of the object waits.
97
+ await new Promise((resolve) => setImmediate(resolve));
98
+ expect(res.writableEnded).toBe(false);
99
+ let received = 0;
100
+ res.on("data", (chunk) => (received += chunk.length));
101
+ expect(await served).toBe(true);
102
+ expect(res.writableEnded).toBe(true);
103
+ await new Promise((resolve) => res.once("end", resolve));
104
+ expect(received).toBe(3 * CHUNK.length);
105
+ });
106
+ it("stops reading the object when the client disconnects", async () => {
107
+ const body = node_stream_1.Readable.from([CHUNK, CHUNK, CHUNK]);
108
+ send$.mockImplementation((async () => ({ Body: body })));
109
+ const { res, served } = serve("GET");
110
+ await new Promise((resolve) => setImmediate(resolve));
111
+ res.destroy();
112
+ expect(await served).toBe(true);
113
+ expect(res.writableEnded).toBe(false);
114
+ // Destroyed, which is what releases the S3 connection.
115
+ expect(body.destroyed).toBe(true);
116
+ });
117
+ });
118
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLWZpbGVzLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9zdGF0aWMtZmlsZXMudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHNEQUFzRDtBQUN0RCw2Q0FBdUM7QUFDdkMsa0RBSTRCO0FBQzVCLDRDQUFxRDtBQUNyRCw4Q0FBcUQ7QUFDckQsaURBQW1EO0FBRW5ELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsb0JBQVEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDckQsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO0FBQ25DLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztBQUVwQyxNQUFNLElBQUksR0FBRyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQztBQUU5RSxTQUFTLEtBQUssQ0FDWixNQUFjLEVBQ2QsR0FBRyxHQUFHLElBQUksNkJBQWtCLEVBQUUsRUFDOUIsVUFBa0MsRUFBRSxFQUNwQyxJQUFJLEdBQUcsSUFBSTtJQUVYLE1BQU0sR0FBRyxHQUFHLElBQUksNkJBQW1CLENBQUMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLElBQUEsZ0NBQWlCLEVBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO0FBQzVELENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxFQUFFLEdBQUcsQ0FBQyxD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QUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ2xELEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFVLENBQUMsQ0FBQztRQUNsRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNyQyxNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUN0RCxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDZCxNQUFNLENBQUMsTUFBTSxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEMsdURBQXVEO1FBQ3ZELE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3BDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXMgKi9cbmltcG9ydCB7IFJlYWRhYmxlIH0gZnJvbSBcIm5vZGU6c3RyZWFtXCI7XG5pbXBvcnQge1xuICBHZXRPYmplY3RDb21tYW5kLFxuICBIZWFkT2JqZWN0Q29tbWFuZCxcbiAgUzNDbGllbnQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtczNcIjtcbmltcG9ydCB7IFNoaW1JbmNvbWluZ01lc3NhZ2UgfSBmcm9tIFwiLi9odHRwL3JlcXVlc3RcIjtcbmltcG9ydCB7IFNoaW1TZXJ2ZXJSZXNwb25zZSB9IGZyb20gXCIuL2h0dHAvcmVzcG9uc2VcIjtcbmltcG9ydCB7IHNlcnZlUzNQdWJsaWNGaWxlIH0gZnJvbSBcIi4vc3RhdGljLWZpbGVzXCI7XG5cbmNvbnN0IHNlbmQkID0gamVzdC5zcHlPbihTM0NsaWVudC5wcm90b3R5cGUsIFwic2VuZFwiKTtcbmFmdGVyRWFjaCgoKSA9PiBzZW5kJC5tb2NrUmVzZXQoKSk7XG5hZnRlckFsbCgoKSA9PiBzZW5kJC5tb2NrUmVzdG9yZSgpKTtcblxuY29uc3QgRklMRSA9IHsgYnVja2V0OiBcImFzc2V0c1wiLCBrZXlQcmVmaXg6IFwiXCIsIGZpbGU6IFwiYmlnLmJpblwiLCBldGFnOiB0cnVlIH07XG5cbmZ1bmN0aW9uIHNlcnZlKFxuICBtZXRob2Q6IHN0cmluZyxcbiAgcmVzID0gbmV3IFNoaW1TZXJ2ZXJSZXNwb25zZSgpLFxuICBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge30sXG4gIGZpbGUgPSBGSUxFLFxuKSB7XG4gIGNvbnN0IHJlcSA9IG5ldyBTaGltSW5jb21pbmdNZXNzYWdlKHsgbWV0aG9kLCB1cmw6IFwiL2JpZy5iaW5cIiwgaGVhZGVycyB9KTtcbiAgcmV0dXJuIHsgcmVzLCBzZXJ2ZWQ6IHNlcnZlUzNQdWJsaWNGaWxlKHJlcSwgcmVzLCBmaWxlKSB9O1xufVxuXG4vKiogQ2h1bmtzIGJpZ2dlciB0aGFuIHRoZSByZXNwb25zZSdzIGJ1ZmZlciwgc28gZXZlcnkgd3JpdGUgaXMgcmVmdXNlZC4gKi9cbmNvbnN0IENIVU5LID0gQnVmZmVyLmFsbG9jKDY0ICogMTAyNCwgXCJhXCIpO1xuXG5kZXNjcmliZShcInNlcnZlUzNQdWJsaWNGaWxlXCIsICgpID0+IHtcbiAgaXQoXCJhc2tzIFMzIGZvciB0aGUgaGVhZCBhbG9uZSBmb3IgYSBIRUFELCBhbmQgc2VuZHMgbm8gYm9keVwiLCBhc3luYyAoKSA9PiB7XG4gICAgc2VuZCQubW9ja0ltcGxlbWVudGF0aW9uKChhc3luYyAoKSA9PiAoe1xuICAgICAgQ29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtXCIsXG4gICAgICBDb250ZW50TGVuZ3RoOiAzLFxuICAgICAgRVRhZzogJ1wiZTFcIicsXG4gICAgfSkpIGFzIG5ldmVyKTtcbiAgICBjb25zdCB7IHJlcywgc2VydmVkIH0gPSBzZXJ2ZShcIkhFQURcIik7XG4gICAgY29uc3QgY2h1bmtzOiBCdWZmZXJbXSA9IFtdO1xuICAgIHJlcy5vbihcImRhdGFcIiwgKGNodW5rOiBCdWZmZXIpID0+IGNodW5rcy5wdXNoKGNodW5rKSk7XG4gICAgZXhwZWN0KGF3YWl0IHNlcnZlZCkudG9CZSh0cnVlKTtcbiAgICBleHBlY3Qoc2VuZCQubW9jay5jYWxsc1swXVswXSkudG9CZUluc3RhbmNlT2YoSGVhZE9iamVjdENvbW1hbmQpO1xuICAgIGV4cGVjdChyZXMuZ2V0SGVhZGVyKFwiQ29udGVudC1MZW5ndGhcIikpLnRvQmUoXCIzXCIpO1xuICAgIGV4cGVjdChyZXMuZ2V0SGVhZGVyKFwiRVRhZ1wiKSkudG9CZSgnXCJlMVwiJyk7XG4gICAgZXhwZWN0KHJlcy53cml0YWJsZUVuZGVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChCdWZmZXIuY29uY2F0KGNodW5rcykubGVuZ3RoKS50b0JlKDApO1xuICB9KTtcblxuICAvLyBgZ2VuZXJhdGVFdGFnczogZmFsc2VgOiBubyBFVGFnIHRvIHJldmFsaWRhdGUgd2l0aCwgb25seSBMYXN0LU1vZGlmaWVkLlxuICBpdChcImFuc3dlcnMgSWYtTW9kaWZpZWQtU2luY2Ugd2l0aCBhIDMwNCwgYXMgc2VuZCBkb2VzXCIsIGFzeW5jICgpID0+IHtcbiAgICBzZW5kJC5tb2NrSW1wbGVtZW50YXRpb24oKGFzeW5jICgpID0+IHtcbiAgICAgIHRocm93IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKFwiTm90IE1vZGlmaWVkXCIpLCB7XG4gICAgICAgICRtZXRhZGF0YTogeyBodHRwU3RhdHVzQ29kZTogMzA0IH0sXG4gICAgICB9KTtcbiAgICB9KSBhcyBuZXZlcik7XG4gICAgY29uc3Qgc2luY2UgPSBcIldlZCwgMjEgT2N0IDIwMTUgMDc6Mjg6MDAgR01UXCI7XG4gICAgY29uc3QgeyByZXMsIHNlcnZlZCB9ID0gc2VydmUoXG4gICAgICBcIkdFVFwiLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgeyBcImlmLW1vZGlmaWVkLXNpbmNlXCI6IHNpbmNlIH0sXG4gICAgICB7IC4uLkZJTEUsIGV0YWc6IGZhbHNlIH0sXG4gICAgKTtcbiAgICBleHBlY3QoYXdhaXQgc2VydmVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChyZXMuc3RhdHVzQ29kZSkudG9CZSgzMDQpO1xuICAgIGNvbnN0IGlucHV0ID0gKHNlbmQkLm1vY2suY2FsbHNbMF1bMF0gYXMgR2V0T2JqZWN0Q29tbWFuZCkuaW5wdXQ7XG4gICAgZXhwZWN0KGlucHV0LklmTW9kaWZpZWRTaW5jZSkudG9FcXVhbChuZXcgRGF0ZShzaW5jZSkpO1xuICAgIGV4cGVjdChpbnB1dC5JZk5vbmVNYXRjaCkudG9CZVVuZGVmaW5lZCgpO1xuICB9KTtcblxuICAvLyBUaGUgMzA0J3MgRVRhZyBpcyB0aGUgb2JqZWN0J3MsIG5vdCB0aGUgY2xpZW50J3MgbGlzdCBvZiBjYW5kaWRhdGVzLlxuICBpdC5lYWNoKFtcbiAgICBbXCJ0aGUgb2JqZWN0J3MgRVRhZ1wiLCB7IGhlYWRlcnM6IHsgZXRhZzogJ1wiZTFcIicgfSB9LCAnXCJlMVwiJ10sXG4gICAgW1wibm8gRVRhZyB3aXRob3V0IG9uZVwiLCB1bmRlZmluZWQsIHVuZGVmaW5lZF0sXG4gIF0pKFwiYW5zd2VycyBhbiBJZi1Ob25lLU1hdGNoIGxpc3Qgd2l0aCAlc1wiLCBhc3luYyAoXywgJHJlc3BvbnNlLCBldGFnKSA9PiB7XG4gICAgc2VuZCQubW9ja0ltcGxlbWVudGF0aW9uKChhc3luYyAoKSA9PiB7XG4gICAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihcIk5vdCBNb2RpZmllZFwiKSwge1xuICAgICAgICAkbWV0YWRhdGE6IHsgaHR0cFN0YXR1c0NvZGU6IDMwNCB9LFxuICAgICAgICAkcmVzcG9uc2UsXG4gICAgICB9KTtcbiAgICB9KSBhcyBuZXZlcik7XG4gICAgY29uc3QgeyByZXMsIHNlcnZlZCB9ID0gc2VydmUoXCJHRVRcIiwgdW5kZWZpbmVkLCB7XG4gICAgICBcImlmLW5vbmUtbWF0Y2hcIjogJ1wiZTBcIiwgXCJlMVwiJyxcbiAgICB9KTtcbiAgICBleHBlY3QoYXdhaXQgc2VydmVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChyZXMuc3RhdHVzQ29kZSkudG9CZSgzMDQpO1xuICAgIGV4cGVjdChyZXMuZ2V0SGVhZGVyKFwiRVRhZ1wiKSkudG9CZShldGFnKTtcbiAgfSk7XG5cbiAgLy8gYGZyZXNoYCBpZ25vcmVzIElmLU1vZGlmaWVkLVNpbmNlIG5leHQgdG8gYW4gSWYtTm9uZS1NYXRjaC5cbiAgaXQoXCJsZWF2ZXMgSWYtTW9kaWZpZWQtU2luY2Ugb3V0IG5leHQgdG8gYW4gSWYtTm9uZS1NYXRjaFwiLCBhc3luYyAoKSA9PiB7XG4gICAgc2VuZCQubW9ja0ltcGxlbWVudGF0aW9uKChhc3luYyAoKSA9PiAoe30pKSBhcyBuZXZlcik7XG4gICAgYXdhaXQgc2VydmUoXCJIRUFEXCIsIHVuZGVmaW5lZCwge1xuICAgICAgXCJpZi1ub25lLW1hdGNoXCI6ICdcImUxXCInLFxuICAgICAgXCJpZi1tb2RpZmllZC1zaW5jZVwiOiBcIldlZCwgMjEgT2N0IDIwMTUgMDc6Mjg6MDAgR01UXCIsXG4gICAgfSkuc2VydmVkO1xuICAgIGNvbnN0IGlucHV0ID0gKHNlbmQkLm1vY2suY2FsbHNbMF1bMF0gYXMgSGVhZE9iamVjdENvbW1hbmQpLmlucHV0O1xuICAgIGV4cGVjdChpbnB1dC5JZk5vbmVNYXRjaCkudG9CZSgnXCJlMVwiJyk7XG4gICAgZXhwZWN0KGlucHV0LklmTW9kaWZpZWRTaW5jZSkudG9CZVVuZGVmaW5lZCgpO1xuICB9KTtcblxuICBpdChcInJldGhyb3dzIGFuIFMzIGVycm9yIHRoYXQgaXMgbm90IGEgbWlzc2luZyBvYmplY3RcIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQkLm1vY2tJbXBsZW1lbnRhdGlvbigoYXN5bmMgKCkgPT4ge1xuICAgICAgdGhyb3cgT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoXCJBY2Nlc3MgRGVuaWVkXCIpLCB7XG4gICAgICAgIG5hbWU6IFwiQWNjZXNzRGVuaWVkXCIsXG4gICAgICAgICRtZXRhZGF0YTogeyBodHRwU3RhdHVzQ29kZTogNDAzIH0sXG4gICAgICB9KTtcbiAgICB9KSBhcyBuZXZlcik7XG4gICAgYXdhaXQgZXhwZWN0KHNlcnZlKFwiR0VUXCIpLnNlcnZlZCkucmVqZWN0cy50b1Rocm93KFwiQWNjZXNzIERlbmllZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJ3YWl0cyBmb3IgdGhlIGNsaWVudCB0byBkcmFpbiBiZWZvcmUgcmVhZGluZyBtb3JlIG9mIHRoZSBvYmplY3RcIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQkLm1vY2tJbXBsZW1lbnRhdGlvbigoYXN5bmMgKCkgPT4gKHtcbiAgICAgIEJvZHk6IFJlYWRhYmxlLmZyb20oW0NIVU5LLCBDSFVOSywgQ0hVTktdKSxcbiAgICB9KSkgYXMgbmV2ZXIpO1xuICAgIGNvbnN0IHsgcmVzLCBzZXJ2ZWQgfSA9IHNlcnZlKFwiR0VUXCIpO1xuICAgIGV4cGVjdChzZW5kJC5tb2NrLmNhbGxzWzBdWzBdKS50b0JlSW5zdGFuY2VPZihHZXRPYmplY3RDb21tYW5kKTtcbiAgICAvLyBOb3RoaW5nIHJlYWRzIHRoZSByZXNwb25zZSB5ZXQsIHNvIHRoZSBmaXJzdCB3cml0ZSBpcyByZWZ1c2VkIGFuZCB0aGVcbiAgICAvLyByZXN0IG9mIHRoZSBvYmplY3Qgd2FpdHMuXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldEltbWVkaWF0ZShyZXNvbHZlKSk7XG4gICAgZXhwZWN0KHJlcy53cml0YWJsZUVuZGVkKS50b0JlKGZhbHNlKTtcblxuICAgIGxldCByZWNlaXZlZCA9IDA7XG4gICAgcmVzLm9uKFwiZGF0YVwiLCAoY2h1bms6IEJ1ZmZlcikgPT4gKHJlY2VpdmVkICs9IGNodW5rLmxlbmd0aCkpO1xuICAgIGV4cGVjdChhd2FpdCBzZXJ2ZWQpLnRvQmUodHJ1ZSk7XG4gICAgZXhwZWN0KHJlcy53cml0YWJsZUVuZGVkKS50b0JlKHRydWUpO1xuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiByZXMub25jZShcImVuZFwiLCByZXNvbHZlKSk7XG4gICAgZXhwZWN0KHJlY2VpdmVkKS50b0JlKDMgKiBDSFVOSy5sZW5ndGgpO1xuICB9KTtcblxuICBpdChcInN0b3BzIHJlYWRpbmcgdGhlIG9iamVjdCB3aGVuIHRoZSBjbGllbnQgZGlzY29ubmVjdHNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGJvZHkgPSBSZWFkYWJsZS5mcm9tKFtDSFVOSywgQ0hVTkssIENIVU5LXSk7XG4gICAgc2VuZCQubW9ja0ltcGxlbWVudGF0aW9uKChhc3luYyAoKSA9PiAoeyBCb2R5OiBib2R5IH0pKSBhcyBuZXZlcik7XG4gICAgY29uc3QgeyByZXMsIHNlcnZlZCB9ID0gc2VydmUoXCJHRVRcIik7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldEltbWVkaWF0ZShyZXNvbHZlKSk7XG4gICAgcmVzLmRlc3Ryb3koKTtcbiAgICBleHBlY3QoYXdhaXQgc2VydmVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChyZXMud3JpdGFibGVFbmRlZCkudG9CZShmYWxzZSk7XG4gICAgLy8gRGVzdHJveWVkLCB3aGljaCBpcyB3aGF0IHJlbGVhc2VzIHRoZSBTMyBjb25uZWN0aW9uLlxuICAgIGV4cGVjdChib2R5LmRlc3Ryb3llZCkudG9CZSh0cnVlKTtcbiAgfSk7XG59KTtcbiJdfQ==
@@ -0,0 +1,28 @@
1
+ /** Small helpers more than one runtime module needs. */
2
+ import { S3Client } from "@aws-sdk/client-s3";
3
+ import type { ShimServerResponse } from "./http/response";
4
+ /** The first of a repeated header, or the header. */
5
+ export declare function firstValue(value: string | string[] | undefined): string | undefined;
6
+ /**
7
+ * `removePathPrefix` (`next/dist/shared/lib/router/utils/remove-path-prefix.js`):
8
+ * strips `prefix` on a path boundary only, so `/docsearch` is not under `/docs`.
9
+ * An absolute-URL `assetPrefix` never matches a pathname, so it is a no-op
10
+ * there, as it is in Next.
11
+ */
12
+ export declare function withoutPathPrefix(pathname: string, prefix: string): string;
13
+ /**
14
+ * A query back into a query string, repeats and all. A key with no value — an
15
+ * optional catch-all the request left unset — is left out rather than sent as
16
+ * `undefined`.
17
+ */
18
+ export declare function toSearch(query: Readonly<Record<string, string | string[] | undefined>>): string;
19
+ /**
20
+ * `decodeURIComponent`, or `value` as given when it isn't valid
21
+ * percent-encoding, which is what a literal `%` in a path segment or filename
22
+ * looks like (`/100%.png`).
23
+ */
24
+ export declare function safeDecode(value: string): string;
25
+ /** Resolves `true` on `drain`, `false` if the response closes first. */
26
+ export declare function drained(res: ShimServerResponse): Promise<boolean>;
27
+ /** The one S3 client, for the image optimizer and `public/` files alike. */
28
+ export declare function s3Client(): S3Client;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.firstValue = firstValue;
4
+ exports.withoutPathPrefix = withoutPathPrefix;
5
+ exports.toSearch = toSearch;
6
+ exports.safeDecode = safeDecode;
7
+ exports.drained = drained;
8
+ exports.s3Client = s3Client;
9
+ /* eslint-disable import/no-extraneous-dependencies */
10
+ /** Small helpers more than one runtime module needs. */
11
+ const client_s3_1 = require("@aws-sdk/client-s3");
12
+ const base_path_1 = require("../utils/base-path");
13
+ /** The first of a repeated header, or the header. */
14
+ function firstValue(value) {
15
+ return Array.isArray(value) ? value[0] : value;
16
+ }
17
+ /**
18
+ * `removePathPrefix` (`next/dist/shared/lib/router/utils/remove-path-prefix.js`):
19
+ * strips `prefix` on a path boundary only, so `/docsearch` is not under `/docs`.
20
+ * An absolute-URL `assetPrefix` never matches a pathname, so it is a no-op
21
+ * there, as it is in Next.
22
+ */
23
+ function withoutPathPrefix(pathname, prefix) {
24
+ if (!(0, base_path_1.hasPathPrefix)(pathname, prefix)) {
25
+ return pathname;
26
+ }
27
+ return pathname.slice(prefix.length) || "/";
28
+ }
29
+ /**
30
+ * A query back into a query string, repeats and all. A key with no value — an
31
+ * optional catch-all the request left unset — is left out rather than sent as
32
+ * `undefined`.
33
+ */
34
+ function toSearch(query) {
35
+ const search = new URLSearchParams();
36
+ for (const [key, value] of Object.entries(query)) {
37
+ for (const item of Array.isArray(value) ? value : [value]) {
38
+ if (item !== undefined)
39
+ search.append(key, item);
40
+ }
41
+ }
42
+ return search.toString();
43
+ }
44
+ /**
45
+ * `decodeURIComponent`, or `value` as given when it isn't valid
46
+ * percent-encoding, which is what a literal `%` in a path segment or filename
47
+ * looks like (`/100%.png`).
48
+ */
49
+ function safeDecode(value) {
50
+ try {
51
+ return decodeURIComponent(value);
52
+ }
53
+ catch {
54
+ return value;
55
+ }
56
+ }
57
+ /** Resolves `true` on `drain`, `false` if the response closes first. */
58
+ function drained(res) {
59
+ if (res.destroyed)
60
+ return Promise.resolve(false);
61
+ return new Promise((resolve) => {
62
+ const onDrain = () => settle(true);
63
+ const onClose = () => settle(false);
64
+ const settle = (value) => {
65
+ res.off("drain", onDrain);
66
+ res.off("close", onClose);
67
+ resolve(value);
68
+ };
69
+ res.once("drain", onDrain);
70
+ res.once("close", onClose);
71
+ });
72
+ }
73
+ let s3;
74
+ /** The one S3 client, for the image optimizer and `public/` files alike. */
75
+ function s3Client() {
76
+ s3 ??= new client_s3_1.S3Client({});
77
+ return s3;
78
+ }
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL3V0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFPQSxnQ0FJQztBQVFELDhDQUtDO0FBT0QsNEJBVUM7QUFPRCxnQ0FNQztBQUdELDBCQWFDO0FBS0QsNEJBR0M7QUE5RUQsc0RBQXNEO0FBQ3RELHdEQUF3RDtBQUN4RCxrREFBOEM7QUFFOUMsa0RBQW1EO0FBRW5ELHFEQUFxRDtBQUNyRCxTQUFnQixVQUFVLENBQ3hCLEtBQW9DO0lBRXBDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFDakQsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsUUFBZ0IsRUFBRSxNQUFjO0lBQ2hFLElBQUksQ0FBQyxJQUFBLHlCQUFhLEVBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDckMsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksR0FBRyxDQUFDO0FBQzlDLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsUUFBUSxDQUN0QixLQUE4RDtJQUU5RCxNQUFNLE1BQU0sR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO0lBQ3JDLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDakQsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMxRCxJQUFJLElBQUksS0FBSyxTQUFTO2dCQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ25ELENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7QUFDM0IsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixVQUFVLENBQUMsS0FBYTtJQUN0QyxJQUFJLENBQUM7UUFDSCxPQUFPLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDO0FBRUQsd0VBQXdFO0FBQ3hFLFNBQWdCLE9BQU8sQ0FBQyxHQUF1QjtJQUM3QyxJQUFJLEdBQUcsQ0FBQyxTQUFTO1FBQUUsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pELE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUM3QixNQUFNLE9BQU8sR0FBRyxHQUFTLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekMsTUFBTSxPQUFPLEdBQUcsR0FBUyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFDLE1BQU0sTUFBTSxHQUFHLENBQUMsS0FBYyxFQUFRLEVBQUU7WUFDdEMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDMUIsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDMUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pCLENBQUMsQ0FBQztRQUNGLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzNCLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzdCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELElBQUksRUFBd0IsQ0FBQztBQUU3Qiw0RUFBNEU7QUFDNUUsU0FBZ0IsUUFBUTtJQUN0QixFQUFFLEtBQUssSUFBSSxvQkFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3hCLE9BQU8sRUFBRSxDQUFDO0FBQ1osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuLyoqIFNtYWxsIGhlbHBlcnMgbW9yZSB0aGFuIG9uZSBydW50aW1lIG1vZHVsZSBuZWVkcy4gKi9cbmltcG9ydCB7IFMzQ2xpZW50IH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHR5cGUgeyBTaGltU2VydmVyUmVzcG9uc2UgfSBmcm9tIFwiLi9odHRwL3Jlc3BvbnNlXCI7XG5pbXBvcnQgeyBoYXNQYXRoUHJlZml4IH0gZnJvbSBcIi4uL3V0aWxzL2Jhc2UtcGF0aFwiO1xuXG4vKiogVGhlIGZpcnN0IG9mIGEgcmVwZWF0ZWQgaGVhZGVyLCBvciB0aGUgaGVhZGVyLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpcnN0VmFsdWUoXG4gIHZhbHVlOiBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZCxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlWzBdIDogdmFsdWU7XG59XG5cbi8qKlxuICogYHJlbW92ZVBhdGhQcmVmaXhgIChgbmV4dC9kaXN0L3NoYXJlZC9saWIvcm91dGVyL3V0aWxzL3JlbW92ZS1wYXRoLXByZWZpeC5qc2ApOlxuICogc3RyaXBzIGBwcmVmaXhgIG9uIGEgcGF0aCBib3VuZGFyeSBvbmx5LCBzbyBgL2RvY3NlYXJjaGAgaXMgbm90IHVuZGVyIGAvZG9jc2AuXG4gKiBBbiBhYnNvbHV0ZS1VUkwgYGFzc2V0UHJlZml4YCBuZXZlciBtYXRjaGVzIGEgcGF0aG5hbWUsIHNvIGl0IGlzIGEgbm8tb3BcbiAqIHRoZXJlLCBhcyBpdCBpcyBpbiBOZXh0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aG91dFBhdGhQcmVmaXgocGF0aG5hbWU6IHN0cmluZywgcHJlZml4OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAoIWhhc1BhdGhQcmVmaXgocGF0aG5hbWUsIHByZWZpeCkpIHtcbiAgICByZXR1cm4gcGF0aG5hbWU7XG4gIH1cbiAgcmV0dXJuIHBhdGhuYW1lLnNsaWNlKHByZWZpeC5sZW5ndGgpIHx8IFwiL1wiO1xufVxuXG4vKipcbiAqIEEgcXVlcnkgYmFjayBpbnRvIGEgcXVlcnkgc3RyaW5nLCByZXBlYXRzIGFuZCBhbGwuIEEga2V5IHdpdGggbm8gdmFsdWUg4oCUIGFuXG4gKiBvcHRpb25hbCBjYXRjaC1hbGwgdGhlIHJlcXVlc3QgbGVmdCB1bnNldCDigJQgaXMgbGVmdCBvdXQgcmF0aGVyIHRoYW4gc2VudCBhc1xuICogYHVuZGVmaW5lZGAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b1NlYXJjaChcbiAgcXVlcnk6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkPj4sXG4pOiBzdHJpbmcge1xuICBjb25zdCBzZWFyY2ggPSBuZXcgVVJMU2VhcmNoUGFyYW1zKCk7XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHF1ZXJ5KSkge1xuICAgIGZvciAoY29uc3QgaXRlbSBvZiBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlIDogW3ZhbHVlXSkge1xuICAgICAgaWYgKGl0ZW0gIT09IHVuZGVmaW5lZCkgc2VhcmNoLmFwcGVuZChrZXksIGl0ZW0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gc2VhcmNoLnRvU3RyaW5nKCk7XG59XG5cbi8qKlxuICogYGRlY29kZVVSSUNvbXBvbmVudGAsIG9yIGB2YWx1ZWAgYXMgZ2l2ZW4gd2hlbiBpdCBpc24ndCB2YWxpZFxuICogcGVyY2VudC1lbmNvZGluZywgd2hpY2ggaXMgd2hhdCBhIGxpdGVyYWwgYCVgIGluIGEgcGF0aCBzZWdtZW50IG9yIGZpbGVuYW1lXG4gKiBsb29rcyBsaWtlIChgLzEwMCUucG5nYCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYWZlRGVjb2RlKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICB0cnkge1xuICAgIHJldHVybiBkZWNvZGVVUklDb21wb25lbnQodmFsdWUpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cbn1cblxuLyoqIFJlc29sdmVzIGB0cnVlYCBvbiBgZHJhaW5gLCBgZmFsc2VgIGlmIHRoZSByZXNwb25zZSBjbG9zZXMgZmlyc3QuICovXG5leHBvcnQgZnVuY3Rpb24gZHJhaW5lZChyZXM6IFNoaW1TZXJ2ZXJSZXNwb25zZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAocmVzLmRlc3Ryb3llZCkgcmV0dXJuIFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGNvbnN0IG9uRHJhaW4gPSAoKTogdm9pZCA9PiBzZXR0bGUodHJ1ZSk7XG4gICAgY29uc3Qgb25DbG9zZSA9ICgpOiB2b2lkID0+IHNldHRsZShmYWxzZSk7XG4gICAgY29uc3Qgc2V0dGxlID0gKHZhbHVlOiBib29sZWFuKTogdm9pZCA9PiB7XG4gICAgICByZXMub2ZmKFwiZHJhaW5cIiwgb25EcmFpbik7XG4gICAgICByZXMub2ZmKFwiY2xvc2VcIiwgb25DbG9zZSk7XG4gICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICB9O1xuICAgIHJlcy5vbmNlKFwiZHJhaW5cIiwgb25EcmFpbik7XG4gICAgcmVzLm9uY2UoXCJjbG9zZVwiLCBvbkNsb3NlKTtcbiAgfSk7XG59XG5cbmxldCBzMzogUzNDbGllbnQgfCB1bmRlZmluZWQ7XG5cbi8qKiBUaGUgb25lIFMzIGNsaWVudCwgZm9yIHRoZSBpbWFnZSBvcHRpbWl6ZXIgYW5kIGBwdWJsaWMvYCBmaWxlcyBhbGlrZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzM0NsaWVudCgpOiBTM0NsaWVudCB7XG4gIHMzID8/PSBuZXcgUzNDbGllbnQoe30pO1xuICByZXR1cm4gczM7XG59XG4iXX0=