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.
- package/.jsii +2467 -2714
- package/.jsii.tabl.json +1 -1
- package/API.md +1725 -1909
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +687 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1548 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +13 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/post-deploy.lambda.js +3 -2
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +19 -3
- package/lib/lambdas/post-deploy/prune-s3.js +54 -15
- package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +107 -18
- package/lib/nextjs-api.js +349 -39
- package/lib/nextjs-api.test.js +582 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +23 -3
- package/lib/nextjs-post-deploy.js +14 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +23 -4
- package/lib/nextjs-static-assets.js +29 -6
- package/lib/nextjs-static-assets.test.js +20 -1
- package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
- package/lib/root-constructs/nextjs-base-construct.js +144 -34
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -70
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -69
- package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
- package/lib/root-constructs/nextjs-regional-containers.js +17 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -25
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41595 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +55 -0
- package/lib/runtime/next-modules.js +124 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41588 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +123 -11
- package/lib/utils/base-path.js +276 -39
- package/lib/utils/base-path.test.js +275 -50
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLWZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3RhdGljLWZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBbURBLDBDQXFDQztBQXdHRCw4Q0E2R0M7QUE3U0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILHNEQUFzRDtBQUN0RCx5Q0FBb0M7QUFDcEMsNkNBQXVDO0FBQ3ZDLGtEQUk0QjtBQUU1Qiw4Q0FBdUU7QUFDdkUsaURBQTRDO0FBQzVDLGlDQUF1RDtBQUV2RCxNQUFNLFlBQVksR0FBRyxrQ0FBa0MsQ0FBQztBQUd4RCx5RUFBeUU7QUFDekUsSUFBSSxpQkFBZ0QsQ0FBQztBQUVyRDs7Ozs7Ozs7O0dBU0c7QUFDSSxLQUFLLFVBQVUsZUFBZSxDQUNuQyxHQUF3QixFQUN4QixHQUF1QixFQUN2QixjQUFzQixFQUN0QixRQUFnQixFQUNoQixPQUFtQztJQUVuQyxpQkFBaUIsS0FBSyxJQUFBLHlCQUFVLEVBQW9CLFlBQVksQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLEdBQUcsaUJBQWlCLENBQUM7SUFDMUQsc0JBQXNCLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxjQUFjLENBQUMsQ0FBQztJQUN0RCxJQUFJLENBQUM7UUFDSCx5RUFBeUU7UUFDekUseUVBQXlFO1FBQ3pFLHVFQUF1RTtRQUN2RSx5RUFBeUU7UUFDekUseUVBQXlFO1FBQ3pFLE1BQU0sV0FBVyxDQUNmLEdBQW1ELEVBQ25ELElBQUEsMkJBQWdCLEVBQUMsR0FBRyxDQUFDLEVBQ3JCLElBQUksUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFDM0QsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQzdDLENBQUM7UUFDRixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsSUFBSSxhQUFhLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFDRCxNQUFNLE1BQU0sR0FBRyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEMsNkVBQTZFO1FBQzdFLGlFQUFpRTtRQUNqRSxJQUFJLE1BQU0sS0FBSyxTQUFTLElBQUksQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDN0MsR0FBRyxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUM7WUFDeEIsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ1YsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQ0QsTUFBTSxLQUFLLENBQUM7SUFDZCxDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsU0FBUyxlQUFlLENBQUMsS0FBYztJQUNyQyxNQUFNLE1BQU0sR0FBSSxLQUF5QyxFQUFFLFVBQVUsQ0FBQztJQUN0RSxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxNQUFNLElBQUksR0FBRyxJQUFJLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNoRSxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxTQUFTLHNCQUFzQixDQUM3QixHQUF1QixFQUN2QixRQUFnQixFQUNoQixjQUFtRDtJQUVuRCxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUM7UUFDakUsT0FBTztJQUNULENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxJQUFBLG1CQUFPLEVBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakUsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ1QsT0FBTztJQUNULENBQUM7SUFDRCxNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUNoQixHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUM3QyxDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFDLEtBQWM7SUFDbkMsTUFBTSxJQUFJLEdBQUksS0FBa0MsRUFBRSxJQUFJLENBQUM7SUFDdkQsOEVBQThFO0lBQzlFLHNEQUFzRDtJQUN0RCxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxLQUFLLFNBQVMsQ0FBQztBQUNqRCxDQUFDO0FBZ0JEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUNJLEtBQUssVUFBVSxpQkFBaUIsQ0FDckMsR0FBd0IsRUFDeEIsR0FBdUIsRUFDdkIsSUFBa0I7SUFFbEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3hELE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQzFELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJO1FBQzNCLENBQUMsQ0FBQyxJQUFBLGlCQUFVLEVBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUMxQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2QsMEVBQTBFO0lBQzFFLGtDQUFrQztJQUNsQyxNQUFNLGVBQWUsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQztRQUNsRCxDQUFDLENBQUMsU0FBUztRQUNYLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBQSxpQkFBVSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0QsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUM7UUFDbkMsQ0FBQyxDQUFDLFNBQVM7UUFDWCxDQUFDLENBQUMsSUFBQSxpQkFBVSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDbEMsSUFBSSxNQUFpRSxDQUFDO0lBQ3RFLElBQUksQ0FBQztRQUNILE1BQU0sR0FBRyxNQUFNLElBQUEsZUFBUSxHQUFFLENBQUMsSUFBSSxDQUM1QixHQUFHLENBQUMsTUFBTSxLQUFLLE1BQU07WUFDbkIsQ0FBQyxDQUFDLElBQUksNkJBQWlCLENBQUM7Z0JBQ3BCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtnQkFDbkIsR0FBRyxFQUFFLEdBQUc7Z0JBQ1IsV0FBVyxFQUFFLFdBQVc7Z0JBQ3hCLGVBQWUsRUFBRSxlQUFlO2dCQUNoQyxLQUFLLEVBQUUsS0FBSzthQUNiLENBQUM7WUFDSixDQUFDLENBQUMsSUFBSSw0QkFBZ0IsQ0FBQztnQkFDbkIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO2dCQUNuQixHQUFHLEVBQUUsR0FBRztnQkFDUixXQUFXLEVBQUUsV0FBVztnQkFDeEIsZUFBZSxFQUFFLGVBQWU7Z0JBQ2hDLEtBQUssRUFBRSxLQUFLO2FBQ2IsQ0FBQyxDQUNQLENBQUM7SUFDSixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE1BQU0sTUFBTSxHQUFJLEtBQXFEO2FBQ2xFLFNBQVMsRUFBRSxjQUFjLENBQUM7UUFDN0IsSUFBSSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDbkIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztnQkFDcEMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztZQUN0RCxDQUFDO1lBQ0QscUVBQXFFO1lBQ3JFLGVBQWU7WUFDZixNQUFNLElBQUksR0FDUixLQUNELENBQUMsU0FBUyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUM7WUFDM0IsSUFBSSxJQUFJO2dCQUFFLEdBQUcsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ3RDLEdBQUcsQ0FBQyxVQUFVLEdBQUcsR0FBRyxDQUFDO1lBQ3JCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNWLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELElBQUksTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ25CLDBFQUEwRTtZQUMxRSxrRUFBa0U7WUFDbEUsR0FBRyxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUM7WUFDckIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDeEMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ1YsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQ0QsTUFBTSxJQUFJLEdBQUksS0FBa0MsRUFBRSxJQUFJLENBQUM7UUFDdkQsSUFBSSxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksS0FBSyxXQUFXLElBQUksSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ2xFLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUNELE1BQU0sS0FBSyxDQUFDO0lBQ2QsQ0FBQztJQUVELElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN6RCxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUNELElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7UUFDcEMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsTUFBTSxDQUFDLFlBQVksSUFBSSxtQkFBbUIsQ0FBQyxDQUFDO0lBQzdFLENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxZQUFZO1FBQUUsR0FBRyxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzdFLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3hCLEdBQUcsQ0FBQyxVQUFVLEdBQUcsR0FBRyxDQUFDO1FBQ3JCLEdBQUcsQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBQ0QsSUFBSSxJQUFJLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJO1FBQUUsR0FBRyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pFLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3hCLEdBQUcsQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsYUFBYSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3ZDLEdBQUcsQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFDRCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQ3pCLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDVixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFDRCxNQUFNLE1BQU0sR0FDVixJQUFJLFlBQVksc0JBQVE7UUFDdEIsQ0FBQyxDQUFDLElBQUk7UUFDTixDQUFDLENBQUMsc0JBQVEsQ0FBQyxJQUFJLENBQUMsSUFBaUMsQ0FBQyxDQUFDO0lBQ3ZELElBQUksQ0FBQztRQUNILElBQUksS0FBSyxFQUFFLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ2pDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLElBQUEsY0FBTyxFQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDL0MsOERBQThEO2dCQUM5RCxPQUFPLElBQUksQ0FBQztZQUNkLENBQUM7UUFDSCxDQUFDO1FBQ0QsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ1osQ0FBQztZQUFTLENBQUM7UUFDVCxvRUFBb0U7UUFDcEUsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ25CLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxzRkFBc0Y7QUFDdEYsU0FBUyxRQUFRLENBQUMsS0FBeUI7SUFDekMsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2pELE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDbEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VydmluZyB0aGUgc3RhdGljIGZpbGVzIHRoYXQgbm90aGluZyBpbiBmcm9udCBvZiB0aGUgY29tcHV0ZSBhbnN3ZXJzLlxuICpcbiAqIGBOZXh0anNTdGF0aWNBc3NldHNgIHVwbG9hZHMgYDxkaXN0RGlyPi9zdGF0aWNgIGFuZCBgcHVibGljYCB0byBTMywgYW5kXG4gKiBDbG91ZEZyb250IC8gQVBJIEdhdGV3YXkgcm91dGUgYSBmaWxlJ3Mgb3duIFVSTCB0aGVyZSDigJQgZXhjZXB0IG9uXG4gKiBgTmV4dGpzUmVnaW9uYWxDb250YWluZXJzYCwgd2hpY2ggaGFzIG5vdGhpbmcgaW4gZnJvbnQgb2YgaXQuIFdoYXQgc3RpbGxcbiAqIHJlYWNoZXMgdGhlIHJ1bnRpbWUgaXMgYSBmaWxlIHNvbWUgKm90aGVyKiBVUkwgbGFuZHMgb246IGEgYHJld3JpdGVzYCBlbnRyeVxuICogb3IgYSBtaWRkbGV3YXJlIHJld3JpdGUgb250byBgL21haW50ZW5hbmNlLmh0bWxgLCBgL2VuLVVTL3JvYm90cy50eHRgIGluIGFuXG4gKiBpMThuIGFwcC4gVGhlIGBOZXh0anNSZWdpb25hbENvbnRhaW5lcnNgIGltYWdlIGNvcGllcyBgcHVibGljYCBhbmRcbiAqIGA8ZGlzdERpcj4vc3RhdGljYCBpbiBhbmQgc2VydmVzIHRoZW0gb2ZmIGRpc2s7IHRoZSBvdGhlciB0eXBlcyBjYXJyeVxuICogbmVpdGhlciwgc28gYSBgcHVibGljL2AgZmlsZSBpcyBzdHJlYW1lZCBmcm9tIHRoZSBhc3NldHMgYnVja2V0IGluc3RlYWRcbiAqICh7QGxpbmsgc2VydmVTM1B1YmxpY0ZpbGV9KS5cbiAqIEV2ZXJ5dGhpbmcgZWxzZSBpbiBgbWFuaWZlc3Quc3RhdGljRmlsZXNgIGxpdmVzIHVuZGVyIGA8ZGlzdERpcj4vc2VydmVyYCDigJRcbiAqIGA0MDQuaHRtbGAsIGA1MDAuaHRtbGAsIGBmYXZpY29uLmljby5ib2R5YCwgZnVsbHktc3RhdGljIFBhZ2VzIFJvdXRlciBIVE1MIOKAlFxuICogYW5kIHJlYWNoZXMgdXMsIGV4YWN0bHkgYXMgaXQgcmVhY2hlcyBgbmV4dCBzdGFydGAuXG4gKlxuICogTmV4dC5qcydzIG93biBgc2VydmVTdGF0aWNgIGlzIHVzZWQgcmF0aGVyIHRoYW4gYSBgY3JlYXRlUmVhZFN0cmVhbWAsIGJlY2F1c2UgaXRcbiAqIGlzIGBzZW5kYCB1bmRlcm5lYXRoIGFuZCB0aGF0IGJyaW5ncyBjb25kaXRpb25hbCByZXF1ZXN0cyAoYElmLU5vbmUtTWF0Y2hgLFxuICogYElmLU1vZGlmaWVkLVNpbmNlYCksIGBSYW5nZWAsIGBFVGFnYCwgYExhc3QtTW9kaWZpZWRgLCBhbmQgY29udGVudC10eXBlXG4gKiBkZXRlY3Rpb24uIFJlaW1wbGVtZW50aW5nIHRob3NlIGlzIGhvdyBhIFwic2ltcGxlXCIgZmlsZSBzZXJ2ZXIgZW5kcyB1cFxuICogZGlzYWdyZWVpbmcgd2l0aCBgbmV4dCBzdGFydGAgb24gYSAzMDQuXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0IHsgZXh0bmFtZSB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IFJlYWRhYmxlIH0gZnJvbSBcIm5vZGU6c3RyZWFtXCI7XG5pbXBvcnQge1xuICBHZXRPYmplY3RDb21tYW5kLFxuICBHZXRPYmplY3RDb21tYW5kT3V0cHV0LFxuICBIZWFkT2JqZWN0Q29tbWFuZCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHR5cGUgeyBTaGltSW5jb21pbmdNZXNzYWdlIH0gZnJvbSBcIi4vaHR0cC9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBhc1NlcnZlclJlc3BvbnNlLCBTaGltU2VydmVyUmVzcG9uc2UgfSBmcm9tIFwiLi9odHRwL3Jlc3BvbnNlXCI7XG5pbXBvcnQgeyBuZXh0TW9kdWxlIH0gZnJvbSBcIi4vbmV4dC1tb2R1bGVzXCI7XG5pbXBvcnQgeyBkcmFpbmVkLCBmaXJzdFZhbHVlLCBzM0NsaWVudCB9IGZyb20gXCIuL3V0aWxcIjtcblxuY29uc3QgU0VSVkVfU1RBVElDID0gXCJuZXh0L2Rpc3Qvc2VydmVyL3NlcnZlLXN0YXRpYy5qc1wiO1xudHlwZSBTZXJ2ZVN0YXRpY01vZHVsZSA9IHR5cGVvZiBpbXBvcnQoXCJuZXh0L2Rpc3Qvc2VydmVyL3NlcnZlLXN0YXRpYy5qc1wiKTtcblxuLyoqIFJlc29sdmVkIG9uIHRoZSBmaXJzdCBzdGF0aWMtZmlsZSByZXF1ZXN0OyBzZWUge0BsaW5rIG5leHRNb2R1bGV9LiAqL1xubGV0IHNlcnZlU3RhdGljTW9kdWxlOiBTZXJ2ZVN0YXRpY01vZHVsZSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZXR1cm5zIGBmYWxzZWAgd2hlbiB0aGUgZmlsZSBpcyBub3QgaW4gdGhlIGRlcGxveW1lbnQgcGFja2FnZSwgd2hpY2ggaXMgdGhlXG4gKiBjYWxsZXIncyBjdWUgdG8gZmFsbCB0aHJvdWdoIHRvIGEgNDA0LlxuICpcbiAqIFRoYXQgaGFwcGVucyBieSBkZXNpZ24gb24gZXZlcnkgdHlwZSBidXQgYE5leHRqc1JlZ2lvbmFsQ29udGFpbmVyc2AsIGZvciBgPGRpc3REaXI+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=
|