cdk-nextjs 0.6.2 → 0.7.1
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 +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -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 +1551 -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 +857 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +863 -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 +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- 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/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 +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- 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 +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -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 +13 -5
- package/lib/nextjs-post-deploy.js +13 -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 +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- 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 +1216 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1686 -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 +41600 -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 +71 -0
- package/lib/runtime/next-modules.js +144 -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 +41593 -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 +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- 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,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ImageTooLargeError = void 0;
|
|
4
|
+
exports.fetchFromS3 = fetchFromS3;
|
|
5
|
+
exports.resolveErrorResponse = resolveErrorResponse;
|
|
6
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
7
|
+
/**
|
|
8
|
+
* S3 fetching and error mapping for `/_next/image`, split out from
|
|
9
|
+
* {@link ./image.ts} so it is unit-testable without `next` present.
|
|
10
|
+
*
|
|
11
|
+
* The one value from `next` that this file needs is passed in rather than
|
|
12
|
+
* imported: `next` is external to the shell bundles, so a static `import` here
|
|
13
|
+
* would be hoisted into the bundle where it cannot resolve. `image.ts` requires
|
|
14
|
+
* it through `./next-modules` instead.
|
|
15
|
+
*/
|
|
16
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
17
|
+
const util_1 = require("./util");
|
|
18
|
+
/**
|
|
19
|
+
* Fetches a non-absolute (local) image referenced by an `<Image>` from S3.
|
|
20
|
+
*
|
|
21
|
+
* `url` is inconsistent about the app's `basePath`: next-image-loader bakes it
|
|
22
|
+
* into the href for statically imported images, while plain string paths are
|
|
23
|
+
* passed through as literally written by the app. So it is stripped when present,
|
|
24
|
+
* leaving a path relative to the asset root, and the bucket's own key prefix is
|
|
25
|
+
* applied to that. Deriving the key from `basePath` instead is wrong whenever the
|
|
26
|
+
* two differ, which they do for every API Gateway deployment.
|
|
27
|
+
*
|
|
28
|
+
* The key is percent-decoded, because an S3 key is the file's real name while
|
|
29
|
+
* `url` is a URL path. `public/hello world.jpg` arrives here as
|
|
30
|
+
* `/hello%20world.jpg` — the `url` query value is double-encoded, so decoding the
|
|
31
|
+
* query string leaves one layer — and its object key is `hello world.jpg`.
|
|
32
|
+
* Next.js's own `fetchInternalImage` gets the decode for free, since it makes an
|
|
33
|
+
* HTTP subrequest and its static file server resolves the path against the
|
|
34
|
+
* filesystem; skipping it here 400'd that file
|
|
35
|
+
* (`next-image-legacy/unicode`). Unicode needs nothing: `äöüščří.png` survives
|
|
36
|
+
* the query decode as itself and is already the object's name.
|
|
37
|
+
*
|
|
38
|
+
* Throws {@link ImageTooLargeError} rather than read past `maximumBody`
|
|
39
|
+
* (`images.maximumResponseBody`), which `next start` enforces on local sources
|
|
40
|
+
* too: a large `public/` file would otherwise be read into memory whole.
|
|
41
|
+
*/
|
|
42
|
+
async function fetchFromS3(s3, bucket, url, location, maximumBody) {
|
|
43
|
+
const { urlBasePath, keyPrefix } = location;
|
|
44
|
+
// The key is the path alone. `/logo.png?v=2` is a cache-buster on a file
|
|
45
|
+
// named `logo.png`, and `next start` treats it as one: `fetchInternalImage`
|
|
46
|
+
// routes the href as a request, whose query and fragment never reach the
|
|
47
|
+
// static file lookup. Left on, they became part of the key, which missed.
|
|
48
|
+
// Cut before decoding, so a `?` that is part of the name (`%3F`) survives.
|
|
49
|
+
const path = withoutAssetPrefix(url.split(/[?#]/, 1)[0], location);
|
|
50
|
+
// Matching on a path boundary keeps a sibling like "/basement/logo.png" from
|
|
51
|
+
// being treated as basePath "/base" plus "ment/logo.png". It's still
|
|
52
|
+
// indistinguishable from a real `public/base/` directory, which loses; that's
|
|
53
|
+
// the right trade, since every statically imported image carries the prefix
|
|
54
|
+
// and the alternative costs an S3 round trip per request to detect it.
|
|
55
|
+
const assetPath = (0, util_1.withoutPathPrefix)(path, urlBasePath).replace(/^\/+/, "");
|
|
56
|
+
const prefix = keyPrefix.replace(/^\/+|\/+$/g, "");
|
|
57
|
+
// A malformed encoding that isn't a literal `%` just misses the key and gets
|
|
58
|
+
// the 400 an absent file gets.
|
|
59
|
+
const decoded = (0, util_1.safeDecode)(assetPath);
|
|
60
|
+
const key = prefix ? `${prefix}/${decoded}` : decoded;
|
|
61
|
+
const response = await s3.send(new client_s3_1.GetObjectCommand({
|
|
62
|
+
Bucket: bucket,
|
|
63
|
+
Key: key,
|
|
64
|
+
}));
|
|
65
|
+
const body = response.Body;
|
|
66
|
+
if (!body) {
|
|
67
|
+
throw new Error(`Empty response from S3 for key: ${key}`);
|
|
68
|
+
}
|
|
69
|
+
if ((response.ContentLength ?? 0) > maximumBody) {
|
|
70
|
+
body.destroy?.();
|
|
71
|
+
throw new ImageTooLargeError(key);
|
|
72
|
+
}
|
|
73
|
+
const chunks = [];
|
|
74
|
+
let size = 0;
|
|
75
|
+
// Counted as well, for an object without a `ContentLength`. Throwing out of
|
|
76
|
+
// the loop destroys the stream.
|
|
77
|
+
for await (const chunk of body) {
|
|
78
|
+
size += chunk.byteLength;
|
|
79
|
+
if (size > maximumBody) {
|
|
80
|
+
throw new ImageTooLargeError(key);
|
|
81
|
+
}
|
|
82
|
+
chunks.push(Buffer.from(chunk));
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
buffer: Buffer.concat(chunks),
|
|
86
|
+
contentType: response.ContentType || null,
|
|
87
|
+
etag: response.ETag || "",
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* `/cdn/_next/static/media/logo.png` → `/_next/static/media/logo.png`, for a
|
|
92
|
+
* path `assetPrefix` of `/cdn`: only in front of `/_next/`, the one place
|
|
93
|
+
* Next.js puts it.
|
|
94
|
+
*/
|
|
95
|
+
function withoutAssetPrefix(path, location) {
|
|
96
|
+
const assetPrefix = location.assetPrefix?.replace(/\/+$/, "") ?? "";
|
|
97
|
+
if (!assetPrefix.startsWith("/"))
|
|
98
|
+
return path;
|
|
99
|
+
return path.startsWith(`${assetPrefix}/_next/`)
|
|
100
|
+
? path.slice(assetPrefix.length)
|
|
101
|
+
: path;
|
|
102
|
+
}
|
|
103
|
+
/** A source over `images.maximumResponseBody`; see {@link fetchFromS3}. */
|
|
104
|
+
class ImageTooLargeError extends Error {
|
|
105
|
+
constructor(key) {
|
|
106
|
+
super(`S3 object ${key} is over images.maximumResponseBody`);
|
|
107
|
+
this.name = "ImageTooLargeError";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.ImageTooLargeError = ImageTooLargeError;
|
|
111
|
+
/**
|
|
112
|
+
* Maps an error thrown while processing an image request to the HTTP
|
|
113
|
+
* status/message it should produce, preserving the status Next.js's own
|
|
114
|
+
* `ImageError`/`fetchExternalImage` attach. A source over
|
|
115
|
+
* `images.maximumResponseBody` is the 413 `fetchInternalImage` answers.
|
|
116
|
+
*/
|
|
117
|
+
function resolveErrorResponse(error, ImageError) {
|
|
118
|
+
if (error instanceof ImageError) {
|
|
119
|
+
return { statusCode: error.statusCode, message: error.message };
|
|
120
|
+
}
|
|
121
|
+
if (error instanceof ImageTooLargeError) {
|
|
122
|
+
return {
|
|
123
|
+
statusCode: 413,
|
|
124
|
+
message: '"url" parameter is valid but internal response is invalid',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return { statusCode: 500, message: "Internal Server Error" };
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9pbWFnZS11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUE2REEsa0NBMkRDO0FBaUNELG9EQWlCQztBQTFLRCxzREFBc0Q7QUFDdEQ7Ozs7Ozs7O0dBUUc7QUFDSCxrREFBZ0U7QUFDaEUsaUNBQXVEO0FBMEJ2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1Qkc7QUFDSSxLQUFLLFVBQVUsV0FBVyxDQUMvQixFQUFZLEVBQ1osTUFBYyxFQUNkLEdBQVcsRUFDWCxRQUF5QixFQUN6QixXQUFtQjtJQUVuQixNQUFNLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxHQUFHLFFBQVEsQ0FBQztJQUM1Qyx5RUFBeUU7SUFDekUsNEVBQTRFO0lBQzVFLHlFQUF5RTtJQUN6RSwwRUFBMEU7SUFDMUUsMkVBQTJFO0lBQzNFLE1BQU0sSUFBSSxHQUFHLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ25FLDZFQUE2RTtJQUM3RSxxRUFBcUU7SUFDckUsOEVBQThFO0lBQzlFLDRFQUE0RTtJQUM1RSx1RUFBdUU7SUFDdkUsTUFBTSxTQUFTLEdBQUcsSUFBQSx3QkFBaUIsRUFBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMzRSxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNuRCw2RUFBNkU7SUFDN0UsK0JBQStCO0lBQy9CLE1BQU0sT0FBTyxHQUFHLElBQUEsaUJBQVUsRUFBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxJ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LHVCQUF1QixFQUFFLENBQUM7QUFDL0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuLyoqXG4gKiBTMyBmZXRjaGluZyBhbmQgZXJyb3IgbWFwcGluZyBmb3IgYC9fbmV4dC9pbWFnZWAsIHNwbGl0IG91dCBmcm9tXG4gKiB7QGxpbmsgLi9pbWFnZS50c30gc28gaXQgaXMgdW5pdC10ZXN0YWJsZSB3aXRob3V0IGBuZXh0YCBwcmVzZW50LlxuICpcbiAqIFRoZSBvbmUgdmFsdWUgZnJvbSBgbmV4dGAgdGhhdCB0aGlzIGZpbGUgbmVlZHMgaXMgcGFzc2VkIGluIHJhdGhlciB0aGFuXG4gKiBpbXBvcnRlZDogYG5leHRgIGlzIGV4dGVybmFsIHRvIHRoZSBzaGVsbCBidW5kbGVzLCBzbyBhIHN0YXRpYyBgaW1wb3J0YCBoZXJlXG4gKiB3b3VsZCBiZSBob2lzdGVkIGludG8gdGhlIGJ1bmRsZSB3aGVyZSBpdCBjYW5ub3QgcmVzb2x2ZS4gYGltYWdlLnRzYCByZXF1aXJlc1xuICogaXQgdGhyb3VnaCBgLi9uZXh0LW1vZHVsZXNgIGluc3RlYWQuXG4gKi9cbmltcG9ydCB7IEdldE9iamVjdENvbW1hbmQsIFMzQ2xpZW50IH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHsgc2FmZURlY29kZSwgd2l0aG91dFBhdGhQcmVmaXggfSBmcm9tIFwiLi91dGlsXCI7XG5cbi8qKiBXaGVyZSB0aGUgYXBwIGlzIHNlcnZlZCB2ZXJzdXMgd2hlcmUgaXRzIGFzc2V0cyB3ZXJlIHVwbG9hZGVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTM0Fzc2V0TG9jYXRpb24ge1xuICAvKipcbiAgICogVGhlIGFwcCdzIG93biBgYmFzZVBhdGhgIOKAlCB0aGUgcHJlZml4IG9mIHRoZSAqVVJMKiBpdCBpcyBzZXJ2ZWQgYXQuIE9ubHlcbiAgICogc3RyaXBwZWQgZnJvbSB0aGUgaHJlZiwgbmV2ZXIgdXNlZCB0byBidWlsZCBhIGtleTogb24gdGhlIEFQSSBHYXRld2F5XG4gICAqIGRlcGxveW1lbnQgdHlwZXMgdGhpcyBpcyB0aGUgc3RhZ2UgbmFtZSwgd2hpY2ggbmV2ZXIgYXBwZWFycyBpbiBTMy5cbiAgICovXG4gIHJlYWRvbmx5IHVybEJhc2VQYXRoOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBgTmV4dGpzU3RhdGljQXNzZXRzLmtleVByZWZpeGA6IHRoZSBTMyBrZXkgcHJlZml4IHRoZSBhc3NldHMgd2VyZSB1cGxvYWRlZFxuICAgKiB1bmRlciwgd2l0aG91dCBhIGxlYWRpbmcgc2xhc2guIEVtcHR5IGZvciBhIGJ1Y2tldC1yb290IGRlcGxveW1lbnQuXG4gICAqL1xuICByZWFkb25seSBrZXlQcmVmaXg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBhcHAncyBgYXNzZXRQcmVmaXhgLCB3aGVuIGl0IGlzIGEgcGF0aCAoYC9jZG5gKS4gTmV4dC5qcyBwdXRzIGl0IGluXG4gICAqIGZyb250IG9mIGAvX25leHQvYCBpbiBwbGFjZSBvZiBgYmFzZVBhdGhgLCBzbyBhIHN0YXRpY2FsbHkgaW1wb3J0ZWQgaW1hZ2Unc1xuICAgKiBocmVmIGlzIGAvY2RuL19uZXh0L3N0YXRpYy9tZWRpYS/igKZgLCBhbmQgYG5leHQgc3RhcnRgIHN0cmlwcyBpdCBhZ2FpbiB3aGVuXG4gICAqIGl0IHNlcnZlcyB0aGUgZmlsZS4gQW4gYWJzb2x1dGUgYGFzc2V0UHJlZml4YCBtYWtlcyB0aGUgaHJlZiBhYnNvbHV0ZSwgd2hpY2hcbiAgICogbmV2ZXIgcmVhY2hlcyBoZXJlLlxuICAgKiBAZGVmYXVsdCAtIG5vbmVcbiAgICovXG4gIHJlYWRvbmx5IGFzc2V0UHJlZml4Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEZldGNoZXMgYSBub24tYWJzb2x1dGUgKGxvY2FsKSBpbWFnZSByZWZlcmVuY2VkIGJ5IGFuIGA8SW1hZ2U+YCBmcm9tIFMzLlxuICpcbiAqIGB1cmxgIGlzIGluY29uc2lzdGVudCBhYm91dCB0aGUgYXBwJ3MgYGJhc2VQYXRoYDogbmV4dC1pbWFnZS1sb2FkZXIgYmFrZXMgaXRcbiAqIGludG8gdGhlIGhyZWYgZm9yIHN0YXRpY2FsbHkgaW1wb3J0ZWQgaW1hZ2VzLCB3aGlsZSBwbGFpbiBzdHJpbmcgcGF0aHMgYXJlXG4gKiBwYXNzZWQgdGhyb3VnaCBhcyBsaXRlcmFsbHkgd3JpdHRlbiBieSB0aGUgYXBwLiBTbyBpdCBpcyBzdHJpcHBlZCB3aGVuIHByZXNlbnQsXG4gKiBsZWF2aW5nIGEgcGF0aCByZWxhdGl2ZSB0byB0aGUgYXNzZXQgcm9vdCwgYW5kIHRoZSBidWNrZXQncyBvd24ga2V5IHByZWZpeCBpc1xuICogYXBwbGllZCB0byB0aGF0LiBEZXJpdmluZyB0aGUga2V5IGZyb20gYGJhc2VQYXRoYCBpbnN0ZWFkIGlzIHdyb25nIHdoZW5ldmVyIHRoZVxuICogdHdvIGRpZmZlciwgd2hpY2ggdGhleSBkbyBmb3IgZXZlcnkgQVBJIEdhdGV3YXkgZGVwbG95bWVudC5cbiAqXG4gKiBUaGUga2V5IGlzIHBlcmNlbnQtZGVjb2RlZCwgYmVjYXVzZSBhbiBTMyBrZXkgaXMgdGhlIGZpbGUncyByZWFsIG5hbWUgd2hpbGVcbiAqIGB1cmxgIGlzIGEgVVJMIHBhdGguIGBwdWJsaWMvaGVsbG8gd29ybGQuanBnYCBhcnJpdmVzIGhlcmUgYXNcbiAqIGAvaGVsbG8lMjB3b3JsZC5qcGdgIOKAlCB0aGUgYHVybGAgcXVlcnkgdmFsdWUgaXMgZG91YmxlLWVuY29kZWQsIHNvIGRlY29kaW5nIHRoZVxuICogcXVlcnkgc3RyaW5nIGxlYXZlcyBvbmUgbGF5ZXIg4oCUIGFuZCBpdHMgb2JqZWN0IGtleSBpcyBgaGVsbG8gd29ybGQuanBnYC5cbiAqIE5leHQuanMncyBvd24gYGZldGNoSW50ZXJuYWxJbWFnZWAgZ2V0cyB0aGUgZGVjb2RlIGZvciBmcmVlLCBzaW5jZSBpdCBtYWtlcyBhblxuICogSFRUUCBzdWJyZXF1ZXN0IGFuZCBpdHMgc3RhdGljIGZpbGUgc2VydmVyIHJlc29sdmVzIHRoZSBwYXRoIGFnYWluc3QgdGhlXG4gKiBmaWxlc3lzdGVtOyBza2lwcGluZyBpdCBoZXJlIDQwMCdkIHRoYXQgZmlsZVxuICogKGBuZXh0LWltYWdlLWxlZ2FjeS91bmljb2RlYCkuIFVuaWNvZGUgbmVlZHMgbm90aGluZzogYMOkw7bDvMWhxI3FmcOtLnBuZ2Agc3Vydml2ZXNcbiAqIHRoZSBxdWVyeSBkZWNvZGUgYXMgaXRzZWxmIGFuZCBpcyBhbHJlYWR5IHRoZSBvYmplY3QncyBuYW1lLlxuICpcbiAqIFRocm93cyB7QGxpbmsgSW1hZ2VUb29MYXJnZUVycm9yfSByYXRoZXIgdGhhbiByZWFkIHBhc3QgYG1heGltdW1Cb2R5YFxuICogKGBpbWFnZXMubWF4aW11bVJlc3BvbnNlQm9keWApLCB3aGljaCBgbmV4dCBzdGFydGAgZW5mb3JjZXMgb24gbG9jYWwgc291cmNlc1xuICogdG9vOiBhIGxhcmdlIGBwdWJsaWMvYCBmaWxlIHdvdWxkIG90aGVyd2lzZSBiZSByZWFkIGludG8gbWVtb3J5IHdob2xlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hGcm9tUzMoXG4gIHMzOiBTM0NsaWVudCxcbiAgYnVja2V0OiBzdHJpbmcsXG4gIHVybDogc3RyaW5nLFxuICBsb2NhdGlvbjogUzNBc3NldExvY2F0aW9uLFxuICBtYXhpbXVtQm9keTogbnVtYmVyLFxuKTogUHJvbWlzZTx7IGJ1ZmZlcjogQnVmZmVyOyBjb250ZW50VHlwZTogc3RyaW5nIHwgbnVsbDsgZXRhZzogc3RyaW5nIH0+IHtcbiAgY29uc3QgeyB1cmxCYXNlUGF0aCwga2V5UHJlZml4IH0gPSBsb2NhdGlvbjtcbiAgLy8gVGhlIGtleSBpcyB0aGUgcGF0aCBhbG9uZS4gYC9sb2dvLnBuZz92PTJgIGlzIGEgY2FjaGUtYnVzdGVyIG9uIGEgZmlsZVxuICAvLyBuYW1lZCBgbG9nby5wbmdgLCBhbmQgYG5leHQgc3RhcnRgIHRyZWF0cyBpdCBhcyBvbmU6IGBmZXRjaEludGVybmFsSW1hZ2VgXG4gIC8vIHJvdXRlcyB0aGUgaHJlZiBhcyBhIHJlcXVlc3QsIHdob3NlIHF1ZXJ5IGFuZCBmcmFnbWVudCBuZXZlciByZWFjaCB0aGVcbiAgLy8gc3RhdGljIGZpbGUgbG9va3VwLiBMZWZ0IG9uLCB0aGV5IGJlY2FtZSBwYXJ0IG9mIHRoZSBrZXksIHdoaWNoIG1pc3NlZC5cbiAgLy8gQ3V0IGJlZm9yZSBkZWNvZGluZywgc28gYSBgP2AgdGhhdCBpcyBwYXJ0IG9mIHRoZSBuYW1lIChgJTNGYCkgc3Vydml2ZXMuXG4gIGNvbnN0IHBhdGggPSB3aXRob3V0QXNzZXRQcmVmaXgodXJsLnNwbGl0KC9bPyNdLywgMSlbMF0sIGxvY2F0aW9uKTtcbiAgLy8gTWF0Y2hpbmcgb24gYSBwYXRoIGJvdW5kYXJ5IGtlZXBzIGEgc2libGluZyBsaWtlIFwiL2Jhc2VtZW50L2xvZ28ucG5nXCIgZnJvbVxuICAvLyBiZWluZyB0cmVhdGVkIGFzIGJhc2VQYXRoIFwiL2Jhc2VcIiBwbHVzIFwibWVudC9sb2dvLnBuZ1wiLiBJdCdzIHN0aWxsXG4gIC8vIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYSByZWFsIGBwdWJsaWMvYmFzZS9gIGRpcmVjdG9yeSwgd2hpY2ggbG9zZXM7IHRoYXQnc1xuICAvLyB0aGUgcmlnaHQgdHJhZGUsIHNpbmNlIGV2ZXJ5IHN0YXRpY2FsbHkgaW1wb3J0ZWQgaW1hZ2UgY2FycmllcyB0aGUgcHJlZml4XG4gIC8vIGFuZCB0aGUgYWx0ZXJuYXRpdmUgY29zdHMgYW4gUzMgcm91bmQgdHJpcCBwZXIgcmVxdWVzdCB0byBkZXRlY3QgaXQuXG4gIGNvbnN0IGFzc2V0UGF0aCA9IHdpdGhvdXRQYXRoUHJlZml4KHBhdGgsIHVybEJhc2VQYXRoKS5yZXBsYWNlKC9eXFwvKy8sIFwiXCIpO1xuICBjb25zdCBwcmVmaXggPSBrZXlQcmVmaXgucmVwbGFjZSgvXlxcLyt8XFwvKyQvZywgXCJcIik7XG4gIC8vIEEgbWFsZm9ybWVkIGVuY29kaW5nIHRoYXQgaXNuJ3QgYSBsaXRlcmFsIGAlYCBqdXN0IG1pc3NlcyB0aGUga2V5IGFuZCBnZXRzXG4gIC8vIHRoZSA0MDAgYW4gYWJzZW50IGZpbGUgZ2V0cy5cbiAgY29uc3QgZGVjb2RlZCA9IHNhZmVEZWNvZGUoYXNzZXRQYXRoKTtcbiAgY29uc3Qga2V5ID0gcHJlZml4ID8gYCR7cHJlZml4fS8ke2RlY29kZWR9YCA6IGRlY29kZWQ7XG5cbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzMy5zZW5kKFxuICAgIG5ldyBHZXRPYmplY3RDb21tYW5kKHtcbiAgICAgIEJ1Y2tldDogYnVja2V0LFxuICAgICAgS2V5OiBrZXksXG4gICAgfSksXG4gICk7XG5cbiAgY29uc3QgYm9keSA9IHJlc3BvbnNlLkJvZHk7XG4gIGlmICghYm9keSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRW1wdHkgcmVzcG9uc2UgZnJvbSBTMyBmb3Iga2V5OiAke2tleX1gKTtcbiAgfVxuXG4gIGlmICgocmVzcG9uc2UuQ29udGVudExlbmd0aCA/PyAwKSA+IG1heGltdW1Cb2R5KSB7XG4gICAgKGJvZHkgYXMgeyBkZXN0cm95PzogKCkgPT4gdm9pZCB9KS5kZXN0cm95Py4oKTtcbiAgICB0aHJvdyBuZXcgSW1hZ2VUb29MYXJnZUVycm9yKGtleSk7XG4gIH1cbiAgY29uc3QgY2h1bmtzOiBCdWZmZXJbXSA9IFtdO1xuICBsZXQgc2l6ZSA9IDA7XG4gIC8vIENvdW50ZWQgYXMgd2VsbCwgZm9yIGFuIG9iamVjdCB3aXRob3V0IGEgYENvbnRlbnRMZW5ndGhgLiBUaHJvd2luZyBvdXQgb2ZcbiAgLy8gdGhlIGxvb3AgZGVzdHJveXMgdGhlIHN0cmVhbS5cbiAgZm9yIGF3YWl0IChjb25zdCBjaHVuayBvZiBib2R5IGFzIEFzeW5jSXRlcmFibGU8VWludDhBcnJheT4pIHtcbiAgICBzaXplICs9IGNodW5rLmJ5dGVMZW5ndGg7XG4gICAgaWYgKHNpemUgPiBtYXhpbXVtQm9keSkge1xuICAgICAgdGhyb3cgbmV3IEltYWdlVG9vTGFyZ2VFcnJvcihrZXkpO1xuICAgIH1cbiAgICBjaHVua3MucHVzaChCdWZmZXIuZnJvbShjaHVuaykpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBidWZmZXI6IEJ1ZmZlci5jb25jYXQoY2h1bmtzKSxcbiAgICBjb250ZW50VHlwZTogcmVzcG9uc2UuQ29udGVudFR5cGUgfHwgbnVsbCxcbiAgICBldGFnOiByZXNwb25zZS5FVGFnIHx8IFwiXCIsXG4gIH07XG59XG5cbi8qKlxuICogYC9jZG4vX25leHQvc3RhdGljL21lZGlhL2xvZ28ucG5nYCDihpIgYC9fbmV4dC9zdGF0aWMvbWVkaWEvbG9nby5wbmdgLCBmb3IgYVxuICogcGF0aCBgYXNzZXRQcmVmaXhgIG9mIGAvY2RuYDogb25seSBpbiBmcm9udCBvZiBgL19uZXh0L2AsIHRoZSBvbmUgcGxhY2VcbiAqIE5leHQuanMgcHV0cyBpdC5cbiAqL1xuZnVuY3Rpb24gd2l0aG91dEFzc2V0UHJlZml4KHBhdGg6IHN0cmluZywgbG9jYXRpb246IFMzQXNzZXRMb2NhdGlvbik6IHN0cmluZyB7XG4gIGNvbnN0IGFzc2V0UHJlZml4ID0gbG9jYXRpb24uYXNzZXRQcmVmaXg/LnJlcGxhY2UoL1xcLyskLywgXCJcIikgPz8gXCJcIjtcbiAgaWYgKCFhc3NldFByZWZpeC5zdGFydHNXaXRoKFwiL1wiKSkgcmV0dXJuIHBhdGg7XG4gIHJldHVybiBwYXRoLnN0YXJ0c1dpdGgoYCR7YXNzZXRQcmVmaXh9L19uZXh0L2ApXG4gICAgPyBwYXRoLnNsaWNlKGFzc2V0UHJlZml4Lmxlbmd0aClcbiAgICA6IHBhdGg7XG59XG5cbi8qKiBBIHNvdXJjZSBvdmVyIGBpbWFnZXMubWF4aW11bVJlc3BvbnNlQm9keWA7IHNlZSB7QGxpbmsgZmV0Y2hGcm9tUzN9LiAqL1xuZXhwb3J0IGNsYXNzIEltYWdlVG9vTGFyZ2VFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgcHVibGljIGNvbnN0cnVjdG9yKGtleTogc3RyaW5nKSB7XG4gICAgc3VwZXIoYFMzIG9iamVjdCAke2tleX0gaXMgb3ZlciBpbWFnZXMubWF4aW11bVJlc3BvbnNlQm9keWApO1xuICAgIHRoaXMubmFtZSA9IFwiSW1hZ2VUb29MYXJnZUVycm9yXCI7XG4gIH1cbn1cblxuLyoqIGBJbWFnZUVycm9yYCBmcm9tIGBuZXh0L2Rpc3Qvc2VydmVyL2ltYWdlLW9wdGltaXplci5qc2AuICovXG5leHBvcnQgdHlwZSBJbWFnZUVycm9yQ2xhc3MgPVxuICAodHlwZW9mIGltcG9ydChcIm5leHQvZGlzdC9zZXJ2ZXIvaW1hZ2Utb3B0aW1pemVyLmpzXCIpKVtcIkltYWdlRXJyb3JcIl07XG5cbi8qKlxuICogTWFwcyBhbiBlcnJvciB0aHJvd24gd2hpbGUgcHJvY2Vzc2luZyBhbiBpbWFnZSByZXF1ZXN0IHRvIHRoZSBIVFRQXG4gKiBzdGF0dXMvbWVzc2FnZSBpdCBzaG91bGQgcHJvZHVjZSwgcHJlc2VydmluZyB0aGUgc3RhdHVzIE5leHQuanMncyBvd25cbiAqIGBJbWFnZUVycm9yYC9gZmV0Y2hFeHRlcm5hbEltYWdlYCBhdHRhY2guIEEgc291cmNlIG92ZXJcbiAqIGBpbWFnZXMubWF4aW11bVJlc3BvbnNlQm9keWAgaXMgdGhlIDQxMyBgZmV0Y2hJbnRlcm5hbEltYWdlYCBhbnN3ZXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUVycm9yUmVzcG9uc2UoXG4gIGVycm9yOiB1bmtub3duLFxuICBJbWFnZUVycm9yOiBJbWFnZUVycm9yQ2xhc3MsXG4pOiB7XG4gIHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgbWVzc2FnZTogc3RyaW5nO1xufSB7XG4gIGlmIChlcnJvciBpbnN0YW5jZW9mIEltYWdlRXJyb3IpIHtcbiAgICByZXR1cm4geyBzdGF0dXNDb2RlOiBlcnJvci5zdGF0dXNDb2RlLCBtZXNzYWdlOiBlcnJvci5tZXNzYWdlIH07XG4gIH1cbiAgaWYgKGVycm9yIGluc3RhbmNlb2YgSW1hZ2VUb29MYXJnZUVycm9yKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1c0NvZGU6IDQxMyxcbiAgICAgIG1lc3NhZ2U6ICdcInVybFwiIHBhcmFtZXRlciBpcyB2YWxpZCBidXQgaW50ZXJuYWwgcmVzcG9uc2UgaXMgaW52YWxpZCcsXG4gICAgfTtcbiAgfVxuICByZXR1cm4geyBzdGF0dXNDb2RlOiA1MDAsIG1lc3NhZ2U6IFwiSW50ZXJuYWwgU2VydmVyIEVycm9yXCIgfTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
4
|
+
jest.mock("@aws-sdk/client-s3");
|
|
5
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
6
|
+
const image_optimizer_js_1 = require("next/dist/server/image-optimizer.js");
|
|
7
|
+
const image_utils_1 = require("./image-utils");
|
|
8
|
+
function asyncIterableFrom(chunks) {
|
|
9
|
+
return {
|
|
10
|
+
[Symbol.asyncIterator]() {
|
|
11
|
+
let i = 0;
|
|
12
|
+
return {
|
|
13
|
+
next: async () => i < chunks.length
|
|
14
|
+
? { done: false, value: chunks[i++] }
|
|
15
|
+
: { done: true, value: undefined },
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** No app `basePath`, assets at the root of the bucket: the default. */
|
|
21
|
+
const ROOT = { urlBasePath: "", keyPrefix: "" };
|
|
22
|
+
describe("fetchFromS3", () => {
|
|
23
|
+
const mockSend = jest.fn();
|
|
24
|
+
const s3 = new client_s3_1.S3Client({});
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
s3.send = mockSend;
|
|
27
|
+
mockSend.mockReset();
|
|
28
|
+
});
|
|
29
|
+
const ok = () => mockSend.mockResolvedValue({
|
|
30
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
31
|
+
ContentType: "image/png",
|
|
32
|
+
ETag: '"abc123"',
|
|
33
|
+
});
|
|
34
|
+
const keyOf = () => client_s3_1.GetObjectCommand.mock.calls[0][0].Key;
|
|
35
|
+
it("strips the leading slash when the assets sit at the bucket root", async () => {
|
|
36
|
+
ok();
|
|
37
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/static/foo.png", {
|
|
38
|
+
urlBasePath: "",
|
|
39
|
+
keyPrefix: "",
|
|
40
|
+
}, Infinity);
|
|
41
|
+
expect(client_s3_1.GetObjectCommand.mock.calls[0][0]).toEqual({ Bucket: "my-bucket", Key: "static/foo.png" });
|
|
42
|
+
});
|
|
43
|
+
it("applies the bucket key prefix", async () => {
|
|
44
|
+
ok();
|
|
45
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/static/foo.jpg", {
|
|
46
|
+
urlBasePath: "/base",
|
|
47
|
+
keyPrefix: "base",
|
|
48
|
+
}, Infinity);
|
|
49
|
+
expect(keyOf()).toBe("base/static/foo.jpg");
|
|
50
|
+
});
|
|
51
|
+
it("does not repeat the prefix when the url already carries basePath", async () => {
|
|
52
|
+
ok();
|
|
53
|
+
// next-image-loader bakes `basePath` into the href of a statically imported
|
|
54
|
+
// image, unlike a plain string path.
|
|
55
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/base/_next/static/media/a.png", {
|
|
56
|
+
urlBasePath: "/base",
|
|
57
|
+
keyPrefix: "base",
|
|
58
|
+
}, Infinity);
|
|
59
|
+
expect(keyOf()).toBe("base/_next/static/media/a.png");
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* The API Gateway deployment types serve the app under the stage name, so the
|
|
63
|
+
* app's `basePath` is `/prod` while the assets were uploaded to the root of the
|
|
64
|
+
* bucket. Building the key from `basePath` asks S3 for `prod/...`, which does
|
|
65
|
+
* not exist, and every local `<Image>` 400s.
|
|
66
|
+
*/
|
|
67
|
+
it("strips a basePath that is not part of the key", async () => {
|
|
68
|
+
ok();
|
|
69
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/prod/_next/static/media/a.png", {
|
|
70
|
+
urlBasePath: "/prod",
|
|
71
|
+
keyPrefix: "",
|
|
72
|
+
}, Infinity);
|
|
73
|
+
expect(keyOf()).toBe("_next/static/media/a.png");
|
|
74
|
+
});
|
|
75
|
+
it("leaves a url without basePath alone when there is no key prefix", async () => {
|
|
76
|
+
ok();
|
|
77
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/static/foo.jpg", {
|
|
78
|
+
urlBasePath: "/prod",
|
|
79
|
+
keyPrefix: "",
|
|
80
|
+
}, Infinity);
|
|
81
|
+
expect(keyOf()).toBe("static/foo.jpg");
|
|
82
|
+
});
|
|
83
|
+
// With `assetPrefix: "/cdn"`, a static import's href is
|
|
84
|
+
// `/cdn/_next/static/media/…`, with `basePath` nowhere in it.
|
|
85
|
+
it("strips a path assetPrefix in front of /_next/", async () => {
|
|
86
|
+
ok();
|
|
87
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/cdn/_next/static/media/a.png", {
|
|
88
|
+
urlBasePath: "/base",
|
|
89
|
+
keyPrefix: "",
|
|
90
|
+
assetPrefix: "/cdn/",
|
|
91
|
+
}, Infinity);
|
|
92
|
+
expect(keyOf()).toBe("_next/static/media/a.png");
|
|
93
|
+
});
|
|
94
|
+
it("leaves a public/ file under a directory named like the assetPrefix alone", async () => {
|
|
95
|
+
ok();
|
|
96
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/cdn/logo.png", {
|
|
97
|
+
urlBasePath: "",
|
|
98
|
+
keyPrefix: "",
|
|
99
|
+
assetPrefix: "/cdn",
|
|
100
|
+
}, Infinity);
|
|
101
|
+
expect(keyOf()).toBe("cdn/logo.png");
|
|
102
|
+
});
|
|
103
|
+
it("ignores an absolute assetPrefix", async () => {
|
|
104
|
+
ok();
|
|
105
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/_next/static/media/a.png", {
|
|
106
|
+
urlBasePath: "",
|
|
107
|
+
keyPrefix: "",
|
|
108
|
+
assetPrefix: "https://cdn.example.test",
|
|
109
|
+
}, Infinity);
|
|
110
|
+
expect(keyOf()).toBe("_next/static/media/a.png");
|
|
111
|
+
});
|
|
112
|
+
it("only matches basePath on a path boundary", async () => {
|
|
113
|
+
ok();
|
|
114
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/basement/logo.png", {
|
|
115
|
+
urlBasePath: "/base",
|
|
116
|
+
keyPrefix: "base",
|
|
117
|
+
}, Infinity);
|
|
118
|
+
expect(keyOf()).toBe("base/basement/logo.png");
|
|
119
|
+
});
|
|
120
|
+
// Carried over from #267, which fixed the same bug in the pre-adapter image
|
|
121
|
+
// handler: a `destinationKeyPrefix` override can arrive with a trailing slash.
|
|
122
|
+
it("doesn't double the separator when the key prefix has a trailing slash", async () => {
|
|
123
|
+
ok();
|
|
124
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/static/foo.jpg", {
|
|
125
|
+
urlBasePath: "",
|
|
126
|
+
keyPrefix: "base/",
|
|
127
|
+
}, Infinity);
|
|
128
|
+
expect(keyOf()).toBe("base/static/foo.jpg");
|
|
129
|
+
});
|
|
130
|
+
// `next-image-legacy/unicode`, whose `public/` holds both of these names. The
|
|
131
|
+
// space is what broke: the key is the file's real name, the url is a URL path.
|
|
132
|
+
it.each([
|
|
133
|
+
["/hello%20world.jpg", "hello world.jpg"],
|
|
134
|
+
["/äöüščří.png", "äöüščří.png"],
|
|
135
|
+
["/%C3%A4%C3%B6.png", "äö.png"],
|
|
136
|
+
])("decodes %s into the object's real name", async (url, key) => {
|
|
137
|
+
ok();
|
|
138
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", url, ROOT, Infinity);
|
|
139
|
+
expect(keyOf()).toBe(key);
|
|
140
|
+
});
|
|
141
|
+
// A cache-buster on a local src: `next start` routes the href as a request, so
|
|
142
|
+
// the query and fragment never reach the file lookup.
|
|
143
|
+
it.each([
|
|
144
|
+
["/logo.png?v=2", "logo.png"],
|
|
145
|
+
["/logo.png#top", "logo.png"],
|
|
146
|
+
["/logo.png?v=2#top", "logo.png"],
|
|
147
|
+
["/base/logo.png?v=2", "logo.png"],
|
|
148
|
+
// A `?` that is part of the name arrives encoded and is not a query.
|
|
149
|
+
["/what%3F.png?v=2", "what?.png"],
|
|
150
|
+
])("keys %s by its path alone", async (url, key) => {
|
|
151
|
+
ok();
|
|
152
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", url, {
|
|
153
|
+
urlBasePath: "/base",
|
|
154
|
+
keyPrefix: "",
|
|
155
|
+
}, Infinity);
|
|
156
|
+
expect(keyOf()).toBe(key);
|
|
157
|
+
});
|
|
158
|
+
it("leaves a name that isn't valid percent-encoding alone", async () => {
|
|
159
|
+
ok();
|
|
160
|
+
await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/100%.png", ROOT, Infinity);
|
|
161
|
+
expect(keyOf()).toBe("100%.png");
|
|
162
|
+
});
|
|
163
|
+
it("returns the concatenated buffer, content type, and etag", async () => {
|
|
164
|
+
mockSend.mockResolvedValue({
|
|
165
|
+
Body: asyncIterableFrom([Buffer.from("hel"), Buffer.from("lo")]),
|
|
166
|
+
ContentType: "image/jpeg",
|
|
167
|
+
ETag: '"the-etag"',
|
|
168
|
+
});
|
|
169
|
+
const result = await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/foo.jpg", ROOT, Infinity);
|
|
170
|
+
expect(result.buffer.toString()).toBe("hello");
|
|
171
|
+
expect(result.contentType).toBe("image/jpeg");
|
|
172
|
+
expect(result.etag).toBe('"the-etag"');
|
|
173
|
+
});
|
|
174
|
+
it("returns an empty etag when S3 doesn't provide one", async () => {
|
|
175
|
+
mockSend.mockResolvedValue({
|
|
176
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
177
|
+
ContentType: null,
|
|
178
|
+
ETag: undefined,
|
|
179
|
+
});
|
|
180
|
+
const result = await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/foo.png", ROOT, Infinity);
|
|
181
|
+
expect(result.etag).toBe("");
|
|
182
|
+
expect(result.contentType).toBeNull();
|
|
183
|
+
});
|
|
184
|
+
// `images.maximumResponseBody`, which `next start` enforces on local sources.
|
|
185
|
+
it("refuses an object whose ContentLength is over the limit, unread", async () => {
|
|
186
|
+
const destroy = jest.fn();
|
|
187
|
+
mockSend.mockResolvedValue({
|
|
188
|
+
Body: { ...asyncIterableFrom([Buffer.from("never read")]), destroy },
|
|
189
|
+
ContentLength: 11,
|
|
190
|
+
});
|
|
191
|
+
await expect((0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/big.png", ROOT, 10)).rejects.toBeInstanceOf(image_utils_1.ImageTooLargeError);
|
|
192
|
+
expect(destroy).toHaveBeenCalled();
|
|
193
|
+
});
|
|
194
|
+
it("stops reading once the bytes read pass the limit", async () => {
|
|
195
|
+
mockSend.mockResolvedValue({
|
|
196
|
+
Body: asyncIterableFrom([Buffer.from("hel"), Buffer.from("lo")]),
|
|
197
|
+
});
|
|
198
|
+
await expect((0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/big.png", ROOT, 4)).rejects.toBeInstanceOf(image_utils_1.ImageTooLargeError);
|
|
199
|
+
// At the limit exactly is fine.
|
|
200
|
+
mockSend.mockResolvedValue({
|
|
201
|
+
Body: asyncIterableFrom([Buffer.from("hel"), Buffer.from("lo")]),
|
|
202
|
+
ContentLength: 5,
|
|
203
|
+
});
|
|
204
|
+
const result = await (0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/ok.png", ROOT, 5);
|
|
205
|
+
expect(result.buffer.toString()).toBe("hello");
|
|
206
|
+
});
|
|
207
|
+
it("throws when S3 returns no body", async () => {
|
|
208
|
+
mockSend.mockResolvedValue({ Body: undefined });
|
|
209
|
+
await expect((0, image_utils_1.fetchFromS3)(s3, "my-bucket", "/missing.png", ROOT, Infinity)).rejects.toThrow(/Empty response from S3/);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe("resolveErrorResponse", () => {
|
|
213
|
+
it("preserves the status code and message from an ImageError", () => {
|
|
214
|
+
const error = new image_optimizer_js_1.ImageError(400, '"url" parameter is not allowed');
|
|
215
|
+
expect((0, image_utils_1.resolveErrorResponse)(error, image_optimizer_js_1.ImageError)).toEqual({
|
|
216
|
+
statusCode: 400,
|
|
217
|
+
message: '"url" parameter is not allowed',
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
it("maps a source over images.maximumResponseBody to next start's 413", () => {
|
|
221
|
+
expect((0, image_utils_1.resolveErrorResponse)(new image_utils_1.ImageTooLargeError("big.png"), image_optimizer_js_1.ImageError)).toEqual({
|
|
222
|
+
statusCode: 413,
|
|
223
|
+
message: '"url" parameter is valid but internal response is invalid',
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
it("falls back to 500 for unrecognized errors", () => {
|
|
227
|
+
expect((0, image_utils_1.resolveErrorResponse)(new Error("boom"), image_optimizer_js_1.ImageError)).toEqual({
|
|
228
|
+
statusCode: 500,
|
|
229
|
+
message: "Internal Server Error",
|
|
230
|
+
});
|
|
231
|
+
expect((0, image_utils_1.resolveErrorResponse)("not an error", image_optimizer_js_1.ImageError)).toEqual({
|
|
232
|
+
statusCode: 500,
|
|
233
|
+
message: "Internal Server Error",
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtdXRpbHMudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2ltYWdlLXV0aWxzLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxzREFBc0Q7QUFDdEQsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0FBRWhDLGtEQUFnRTtBQUNoRSw0RUFBaUU7QUFDakUsK0NBSXVCO0FBRXZCLFNBQVMsaUJBQWlCLENBQUMsTUFBb0I7SUFDN0MsT0FBTztRQUNMLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQztZQUNwQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDVixPQUFPO2dCQUNMLElBQUksRUFBRSxLQUFLLElBQUksRUFBRSxDQUNmLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTTtvQkFDZixDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtvQkFDckMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFO2FBQ3ZDLENBQUM7UUFDSixDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCx3RUFBd0U7QUFDeEUsTUFBTSxJQUFJLEdBQUcsRUFBRSxXQUFXLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsQ0FBQztBQUVoRCxRQUFRLENBQUMsYUFBYSxFQUFFLEdBQUcsRUFBRTtJQUMzQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDM0IsTUFBTSxFQUFFLEdBQUcsSUFBSSxvQkFBUSxDQUFDLEVBQUUsQ0FBd0IsQ0FBQztJQUVuRCxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2IsRUFBMkMsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDO1FBQzdELFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUN2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QU0sQ0FDSixJQUFBLGtDQUFvQixFQUFDLElBQUksZ0NBQWtCLENBQUMsU0FBUyxDQUFDLEVBQUUsK0JBQVUsQ0FBQyxDQUNwRSxDQUFDLE9BQU8sQ0FBQztZQUNSLFVBQVUsRUFBRSxHQUFHO1lBQ2YsT0FBTyxFQUFFLDJEQUEyRDtTQUNyRSxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQywyQ0FBMkMsRUFBRSxHQUFHLEVBQUU7UUFDbkQsTUFBTSxDQUFDLElBQUEsa0NBQW9CLEVBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQUUsK0JBQVUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1lBQ2xFLFVBQVUsRUFBRSxHQUFHO1lBQ2YsT0FBTyxFQUFFLHVCQUF1QjtTQUNqQyxDQUFDLENBQUM7UUFDSCxNQUFNLENBQUMsSUFBQSxrQ0FBb0IsRUFBQyxjQUFjLEVBQUUsK0JBQVUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1lBQy9ELFVBQVUsRUFBRSxHQUFHO1lBQ2YsT0FBTyxFQUFFLHVCQUF1QjtTQUNqQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG5qZXN0Lm1vY2soXCJAYXdzLXNkay9jbGllbnQtczNcIik7XG5cbmltcG9ydCB7IEdldE9iamVjdENvbW1hbmQsIFMzQ2xpZW50IH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHsgSW1hZ2VFcnJvciB9IGZyb20gXCJuZXh0L2Rpc3Qvc2VydmVyL2ltYWdlLW9wdGltaXplci5qc1wiO1xuaW1wb3J0IHtcbiAgZmV0Y2hGcm9tUzMsXG4gIEltYWdlVG9vTGFyZ2VFcnJvcixcbiAgcmVzb2x2ZUVycm9yUmVzcG9uc2UsXG59IGZyb20gXCIuL2ltYWdlLXV0aWxzXCI7XG5cbmZ1bmN0aW9uIGFzeW5jSXRlcmFibGVGcm9tKGNodW5rczogVWludDhBcnJheVtdKTogQXN5bmNJdGVyYWJsZTxVaW50OEFycmF5PiB7XG4gIHJldHVybiB7XG4gICAgW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSgpIHtcbiAgICAgIGxldCBpID0gMDtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5leHQ6IGFzeW5jICgpID0+XG4gICAgICAgICAgaSA8IGNodW5rcy5sZW5ndGhcbiAgICAgICAgICAgID8geyBkb25lOiBmYWxzZSwgdmFsdWU6IGNodW5rc1tpKytdIH1cbiAgICAgICAgICAgIDogeyBkb25lOiB0cnVlLCB2YWx1ZTogdW5kZWZpbmVkIH0sXG4gICAgICB9O1xuICAgIH0sXG4gIH07XG59XG5cbi8qKiBObyBhcHAgYGJhc2VQYXRoYCwgYXNzZXRzIGF0IHRoZSByb290IG9mIHRoZSBidWNrZXQ6IHRoZSBkZWZhdWx0LiAqL1xuY29uc3QgUk9PVCA9IHsgdXJsQmFzZVBhdGg6IFwiXCIsIGtleVByZWZpeDogXCJcIiB9O1xuXG5kZXNjcmliZShcImZldGNoRnJvbVMzXCIsICgpID0+IHtcbiAgY29uc3QgbW9ja1NlbmQgPSBqZXN0LmZuKCk7XG4gIGNvbnN0IHMzID0gbmV3IFMzQ2xpZW50KHt9KSBhcyB1bmtub3duIGFzIFMzQ2xpZW50O1xuXG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIChzMyBhcyB1bmtub3duIGFzIHsgc2VuZDogdHlwZW9mIG1vY2tTZW5kIH0pLnNlbmQgPSBtb2NrU2VuZDtcbiAgICBtb2NrU2VuZC5tb2NrUmVzZXQoKTtcbiAgfSk7XG5cbiAgY29uc3Qgb2sgPSAoKSA9PlxuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IGFzeW5jSXRlcmFibGVGcm9tKFtCdWZmZXIuZnJvbShcImRhdGFcIildKSxcbiAgICAgIENvbnRlbnRUeXBlOiBcImltYWdlL3BuZ1wiLFxuICAgICAgRVRhZzogJ1wiYWJjMTIzXCInLFxuICAgIH0pO1xuICBjb25zdCBrZXlPZiA9ICgpID0+XG4gICAgKEdldE9iamVjdENvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHNbMF1bMF0uS2V5O1xuXG4gIGl0KFwic3RyaXBzIHRoZSBsZWFkaW5nIHNsYXNoIHdoZW4gdGhlIGFzc2V0cyBzaXQgYXQgdGhlIGJ1Y2tldCByb290XCIsIGFzeW5jICgpID0+IHtcbiAgICBvaygpO1xuXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoXG4gICAgICBzMyxcbiAgICAgIFwibXktYnVja2V0XCIsXG4gICAgICBcIi9zdGF0aWMvZm9vLnBuZ1wiLFxuICAgICAge1xuICAgICAgICB1cmxCYXNlUGF0aDogXCJcIixcbiAgICAgICAga2V5UHJlZml4OiBcIlwiLFxuICAgICAgfSxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3QoKEdldE9iamVjdENvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHNbMF1bMF0pLnRvRXF1YWwoXG4gICAgICB7IEJ1Y2tldDogXCJteS1idWNrZXRcIiwgS2V5OiBcInN0YXRpYy9mb28ucG5nXCIgfSxcbiAgICApO1xuICB9KTtcblxuICBpdChcImFwcGxpZXMgdGhlIGJ1Y2tldCBrZXkgcHJlZml4XCIsIGFzeW5jICgpID0+IHtcbiAgICBvaygpO1xuXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoXG4gICAgICBzMyxcbiAgICAgIFwibXktYnVja2V0XCIsXG4gICAgICBcIi9zdGF0aWMvZm9vLmpwZ1wiLFxuICAgICAge1xuICAgICAgICB1cmxCYXNlUGF0aDogXCIvYmFzZVwiLFxuICAgICAgICBrZXlQcmVmaXg6IFwiYmFzZVwiLFxuICAgICAgfSxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3Qoa2V5T2YoKSkudG9CZShcImJhc2Uvc3RhdGljL2Zvby5qcGdcIik7XG4gIH0pO1xuXG4gIGl0KFwiZG9lcyBub3QgcmVwZWF0IHRoZSBwcmVmaXggd2hlbiB0aGUgdXJsIGFscmVhZHkgY2FycmllcyBiYXNlUGF0aFwiLCBhc3luYyAoKSA9PiB7XG4gICAgb2soKTtcblxuICAgIC8vIG5leHQtaW1hZ2UtbG9hZGVyIGJha2VzIGBiYXNlUGF0aGAgaW50byB0aGUgaHJlZiBvZiBhIHN0YXRpY2FsbHkgaW1wb3J0ZWRcbiAgICAvLyBpbWFnZSwgdW5saWtlIGEgcGxhaW4gc3RyaW5nIHBhdGguXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoXG4gICAgICBzMyxcbiAgICAgIFwibXktYnVja2V0XCIsXG4gICAgICBcIi9iYXNlL19uZXh0L3N0YXRpYy9tZWRpYS9hLnBuZ1wiLFxuICAgICAge1xuICAgICAgICB1cmxCYXNlUGF0aDogXCIvYmFzZVwiLFxuICAgICAgICBrZXlQcmVmaXg6IFwiYmFzZVwiLFxuICAgICAgfSxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3Qoa2V5T2YoKSkudG9CZShcImJhc2UvX25leHQvc3RhdGljL21lZGlhL2EucG5nXCIpO1xuICB9KTtcblxuICAvKipcbiAgICogVGhlIEFQSSBHYXRld2F5IGRlcGxveW1lbnQgdHlwZXMgc2VydmUgdGhlIGFwcCB1bmRlciB0aGUgc3RhZ2UgbmFtZSwgc28gdGhlXG4gICAqIGFwcCdzIGBiYXNlUGF0aGAgaXMgYC9wcm9kYCB3aGlsZSB0aGUgYXNzZXRzIHdlcmUgdXBsb2FkZWQgdG8gdGhlIHJvb3Qgb2YgdGhlXG4gICAqIGJ1Y2tldC4gQnVpbGRpbmcgdGhlIGtleSBmcm9tIGBiYXNlUGF0aGAgYXNrcyBTMyBmb3IgYHByb2QvLi4uYCwgd2hpY2ggZG9lc1xuICAgKiBub3QgZXhpc3QsIGFuZCBldmVyeSBsb2NhbCBgPEltYWdlPmAgNDAwcy5cbiAgICovXG4gIGl0KFwic3RyaXBzIGEgYmFzZVBhdGggdGhhdCBpcyBub3QgcGFydCBvZiB0aGUga2V5XCIsIGFzeW5jICgpID0+IHtcbiAgICBvaygpO1xuXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoXG4gICAgICBzMyxcbiAgICAgIFwibXktYnVja2V0XCIsXG4gICAgICBcIi9wcm9kL19uZXh0L3N0YXRpYy9tZWRpYS9hLnBuZ1wiLFxuICAgICAge1xuICAgICAgICB1cmxCYXNlUGF0aDogXCIvcHJvZFwiLFxuICAgICAgICBrZXlQcmVmaXg6IFwiXCIsXG4gICAgICB9LFxuICAgICAgSW5maW5pdHksXG4gICAgKTtcblxuICAgIGV4cGVjdChrZXlPZigpKS50b0JlKFwiX25leHQvc3RhdGljL21lZGlhL2EucG5nXCIpO1xuICB9KTtcblxuICBpdChcImxlYXZlcyBhIHVybCB3aXRob3V0IGJhc2VQYXRoIGFsb25lIHdoZW4gdGhlcmUgaXMgbm8ga2V5IHByZWZpeFwiLCBhc3luYyAoKSA9PiB7XG4gICAgb2soKTtcblxuICAgIGF3YWl0IGZldGNoRnJvbVMzKFxuICAgICAgczMsXG4gICAgICBcIm15LWJ1Y2tldFwiLFxuICAgICAgXCIvc3RhdGljL2Zvby5qcGdcIixcbiAgICAgIHtcbiAgICAgICAgdXJsQmFzZVBhdGg6IFwiL3Byb2RcIixcbiAgICAgICAga2V5UHJlZml4OiBcIlwiLFxuICAgICAgfSxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3Qoa2V5T2YoKSkudG9CZShcInN0YXRpYy9mb28uanBnXCIpO1xuICB9KTtcblxuICAvLyBXaXRoIGBhc3NldFByZWZpeDogXCIvY2RuXCJgLCBhIHN0YXRpYyBpbXBvcnQncyBocmVmIGlzXG4gIC8vIGAvY2RuL19uZXh0L3N0YXRpYy9tZWRpYS/igKZgLCB3aXRoIGBiYXNlUGF0aGAgbm93aGVyZSBpbiBpdC5cbiAgaXQoXCJzdHJpcHMgYSBwYXRoIGFzc2V0UHJlZml4IGluIGZyb250IG9mIC9fbmV4dC9cIiwgYXN5bmMgKCkgPT4ge1xuICAgIG9rKCk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIFwiL2Nkbi9fbmV4dC9zdGF0aWMvbWVkaWEvYS5wbmdcIixcbiAgICAgIHtcbiAgICAgICAgdXJsQmFzZVBhdGg6IFwiL2Jhc2VcIixcbiAgICAgICAga2V5UHJlZml4OiBcIlwiLFxuICAgICAgICBhc3NldFByZWZpeDogXCIvY2RuL1wiLFxuICAgICAgfSxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3Qoa2V5T2YoKSkudG9CZShcIl9uZXh0L3N0YXRpYy9tZWRpYS9hLnBuZ1wiKTtcbiAgfSk7XG5cbiAgaXQoXCJsZWF2ZXMgYSBwdWJsaWMvIGZpbGUgdW5kZXIgYSBkaXJlY3RvcnkgbmFtZWQgbGlrZSB0aGUgYXNzZXRQcmVmaXggYWxvbmVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG9rKCk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIFwiL2Nkbi9sb2dvLnBuZ1wiLFxuICAgICAge1xuICAgICAgICB1cmxCYXNlUGF0aDogXCJcIixcbiAgICAgICAga2V5UHJlZml4OiBcIlwiLFxuICAgICAgICBhc3NldFByZWZpeDogXCIvY2RuXCIsXG4gICAgICB9LFxuICAgICAgSW5maW5pdHksXG4gICAgKTtcblxuICAgIGV4cGVjdChrZXlPZigpKS50b0JlKFwiY2RuL2xvZ28ucG5nXCIpO1xuICB9KTtcblxuICBpdChcImlnbm9yZXMgYW4gYWJzb2x1dGUgYXNzZXRQcmVmaXhcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG9rKCk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIFwiL19uZXh0L3N0YXRpYy9tZWRpYS9hLnBuZ1wiLFxuICAgICAge1xuICAgICAgICB1cmxCYXNlUGF0aDogXCJcIixcbiAgICAgICAga2V5UHJlZml4OiBcIlwiLFxuICAgICAgICBhc3NldFByZWZpeDogXCJodHRwczovL2Nkbi5leGFtcGxlLnRlc3RcIixcbiAgICAgIH0sXG4gICAgICBJbmZpbml0eSxcbiAgICApO1xuXG4gICAgZXhwZWN0KGtleU9mKCkpLnRvQmUoXCJfbmV4dC9zdGF0aWMvbWVkaWEvYS5wbmdcIik7XG4gIH0pO1xuXG4gIGl0KFwib25seSBtYXRjaGVzIGJhc2VQYXRoIG9uIGEgcGF0aCBib3VuZGFyeVwiLCBhc3luYyAoKSA9PiB7XG4gICAgb2soKTtcblxuICAgIGF3YWl0IGZldGNoRnJvbVMzKFxuICAgICAgczMsXG4gICAgICBcIm15LWJ1Y2tldFwiLFxuICAgICAgXCIvYmFzZW1lbnQvbG9nby5wbmdcIixcbiAgICAgIHtcbiAgICAgICAgdXJsQmFzZVBhdGg6IFwiL2Jhc2VcIixcbiAgICAgICAga2V5UHJlZml4OiBcImJhc2VcIixcbiAgICAgIH0sXG4gICAgICBJbmZpbml0eSxcbiAgICApO1xuXG4gICAgZXhwZWN0KGtleU9mKCkpLnRvQmUoXCJiYXNlL2Jhc2VtZW50L2xvZ28ucG5nXCIpO1xuICB9KTtcblxuICAvLyBDYXJyaWVkIG92ZXIgZnJvbSAjMjY3LCB3aGljaCBmaXhlZCB0aGUgc2FtZSBidWcgaW4gdGhlIHByZS1hZGFwdGVyIGltYWdlXG4gIC8vIGhhbmRsZXI6IGEgYGRlc3RpbmF0aW9uS2V5UHJlZml4YCBvdmVycmlkZSBjYW4gYXJyaXZlIHdpdGggYSB0cmFpbGluZyBzbGFzaC5cbiAgaXQoXCJkb2Vzbid0IGRvdWJsZSB0aGUgc2VwYXJhdG9yIHdoZW4gdGhlIGtleSBwcmVmaXggaGFzIGEgdHJhaWxpbmcgc2xhc2hcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG9rKCk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIFwiL3N0YXRpYy9mb28uanBnXCIsXG4gICAgICB7XG4gICAgICAgIHVybEJhc2VQYXRoOiBcIlwiLFxuICAgICAgICBrZXlQcmVmaXg6IFwiYmFzZS9cIixcbiAgICAgIH0sXG4gICAgICBJbmZpbml0eSxcbiAgICApO1xuXG4gICAgZXhwZWN0KGtleU9mKCkpLnRvQmUoXCJiYXNlL3N0YXRpYy9mb28uanBnXCIpO1xuICB9KTtcblxuICAvLyBgbmV4dC1pbWFnZS1sZWdhY3kvdW5pY29kZWAsIHdob3NlIGBwdWJsaWMvYCBob2xkcyBib3RoIG9mIHRoZXNlIG5hbWVzLiBUaGVcbiAgLy8gc3BhY2UgaXMgd2hhdCBicm9rZTogdGhlIGtleSBpcyB0aGUgZmlsZSdzIHJlYWwgbmFtZSwgdGhlIHVybCBpcyBhIFVSTCBwYXRoLlxuICBpdC5lYWNoKFtcbiAgICBbXCIvaGVsbG8lMjB3b3JsZC5qcGdcIiwgXCJoZWxsbyB3b3JsZC5qcGdcIl0sXG4gICAgW1wiL8Okw7bDvMWhxI3FmcOtLnBuZ1wiLCBcIsOkw7bDvMWhxI3FmcOtLnBuZ1wiXSxcbiAgICBbXCIvJUMzJUE0JUMzJUI2LnBuZ1wiLCBcIsOkw7YucG5nXCJdLFxuICBdKShcImRlY29kZXMgJXMgaW50byB0aGUgb2JqZWN0J3MgcmVhbCBuYW1lXCIsIGFzeW5jICh1cmwsIGtleSkgPT4ge1xuICAgIG9rKCk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhzMywgXCJteS1idWNrZXRcIiwgdXJsLCBST09ULCBJbmZpbml0eSk7XG5cbiAgICBleHBlY3Qoa2V5T2YoKSkudG9CZShrZXkpO1xuICB9KTtcblxuICAvLyBBIGNhY2hlLWJ1c3RlciBvbiBhIGxvY2FsIHNyYzogYG5leHQgc3RhcnRgIHJvdXRlcyB0aGUgaHJlZiBhcyBhIHJlcXVlc3QsIHNvXG4gIC8vIHRoZSBxdWVyeSBhbmQgZnJhZ21lbnQgbmV2ZXIgcmVhY2ggdGhlIGZpbGUgbG9va3VwLlxuICBpdC5lYWNoKFtcbiAgICBbXCIvbG9nby5wbmc/dj0yXCIsIFwibG9nby5wbmdcIl0sXG4gICAgW1wiL2xvZ28ucG5nI3RvcFwiLCBcImxvZ28ucG5nXCJdLFxuICAgIFtcIi9sb2dvLnBuZz92PTIjdG9wXCIsIFwibG9nby5wbmdcIl0sXG4gICAgW1wiL2Jhc2UvbG9nby5wbmc/dj0yXCIsIFwibG9nby5wbmdcIl0sXG4gICAgLy8gQSBgP2AgdGhhdCBpcyBwYXJ0IG9mIHRoZSBuYW1lIGFycml2ZXMgZW5jb2RlZCBhbmQgaXMgbm90IGEgcXVlcnkuXG4gICAgW1wiL3doYXQlM0YucG5nP3Y9MlwiLCBcIndoYXQ/LnBuZ1wiXSxcbiAgXSkoXCJrZXlzICVzIGJ5IGl0cyBwYXRoIGFsb25lXCIsIGFzeW5jICh1cmwsIGtleSkgPT4ge1xuICAgIG9rKCk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIHVybCxcbiAgICAgIHtcbiAgICAgICAgdXJsQmFzZVBhdGg6IFwiL2Jhc2VcIixcbiAgICAgICAga2V5UHJlZml4OiBcIlwiLFxuICAgICAgfSxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3Qoa2V5T2YoKSkudG9CZShrZXkpO1xuICB9KTtcblxuICBpdChcImxlYXZlcyBhIG5hbWUgdGhhdCBpc24ndCB2YWxpZCBwZXJjZW50LWVuY29kaW5nIGFsb25lXCIsIGFzeW5jICgpID0+IHtcbiAgICBvaygpO1xuXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoczMsIFwibXktYnVja2V0XCIsIFwiLzEwMCUucG5nXCIsIFJPT1QsIEluZmluaXR5KTtcblxuICAgIGV4cGVjdChrZXlPZigpKS50b0JlKFwiMTAwJS5wbmdcIik7XG4gIH0pO1xuXG4gIGl0KFwicmV0dXJucyB0aGUgY29uY2F0ZW5hdGVkIGJ1ZmZlciwgY29udGVudCB0eXBlLCBhbmQgZXRhZ1wiLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgQm9keTogYXN5bmNJdGVyYWJsZUZyb20oW0J1ZmZlci5mcm9tKFwiaGVsXCIpLCBCdWZmZXIuZnJvbShcImxvXCIpXSksXG4gICAgICBDb250ZW50VHlwZTogXCJpbWFnZS9qcGVnXCIsXG4gICAgICBFVGFnOiAnXCJ0aGUtZXRhZ1wiJyxcbiAgICB9KTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZldGNoRnJvbVMzKFxuICAgICAgczMsXG4gICAgICBcIm15LWJ1Y2tldFwiLFxuICAgICAgXCIvZm9vLmpwZ1wiLFxuICAgICAgUk9PVCxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3QocmVzdWx0LmJ1ZmZlci50b1N0cmluZygpKS50b0JlKFwiaGVsbG9cIik7XG4gICAgZXhwZWN0KHJlc3VsdC5jb250ZW50VHlwZSkudG9CZShcImltYWdlL2pwZWdcIik7XG4gICAgZXhwZWN0KHJlc3VsdC5ldGFnKS50b0JlKCdcInRoZS1ldGFnXCInKTtcbiAgfSk7XG5cbiAgaXQoXCJyZXR1cm5zIGFuIGVtcHR5IGV0YWcgd2hlbiBTMyBkb2Vzbid0IHByb3ZpZGUgb25lXCIsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICBCb2R5OiBhc3luY0l0ZXJhYmxlRnJvbShbQnVmZmVyLmZyb20oXCJkYXRhXCIpXSksXG4gICAgICBDb250ZW50VHlwZTogbnVsbCxcbiAgICAgIEVUYWc6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZldGNoRnJvbVMzKFxuICAgICAgczMsXG4gICAgICBcIm15LWJ1Y2tldFwiLFxuICAgICAgXCIvZm9vLnBuZ1wiLFxuICAgICAgUk9PVCxcbiAgICAgIEluZmluaXR5LFxuICAgICk7XG5cbiAgICBleHBlY3QocmVzdWx0LmV0YWcpLnRvQmUoXCJcIik7XG4gICAgZXhwZWN0KHJlc3VsdC5jb250ZW50VHlwZSkudG9CZU51bGwoKTtcbiAgfSk7XG5cbiAgLy8gYGltYWdlcy5tYXhpbXVtUmVzcG9uc2VCb2R5YCwgd2hpY2ggYG5leHQgc3RhcnRgIGVuZm9yY2VzIG9uIGxvY2FsIHNvdXJjZXMuXG4gIGl0KFwicmVmdXNlcyBhbiBvYmplY3Qgd2hvc2UgQ29udGVudExlbmd0aCBpcyBvdmVyIHRoZSBsaW1pdCwgdW5yZWFkXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkZXN0cm95ID0gamVzdC5mbigpO1xuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IHsgLi4uYXN5bmNJdGVyYWJsZUZyb20oW0J1ZmZlci5mcm9tKFwibmV2ZXIgcmVhZFwiKV0pLCBkZXN0cm95IH0sXG4gICAgICBDb250ZW50TGVuZ3RoOiAxMSxcbiAgICB9KTtcblxuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIGZldGNoRnJvbVMzKHMzLCBcIm15LWJ1Y2tldFwiLCBcIi9iaWcucG5nXCIsIFJPT1QsIDEwKSxcbiAgICApLnJlamVjdHMudG9CZUluc3RhbmNlT2YoSW1hZ2VUb29MYXJnZUVycm9yKTtcbiAgICBleHBlY3QoZGVzdHJveSkudG9IYXZlQmVlbkNhbGxlZCgpO1xuICB9KTtcblxuICBpdChcInN0b3BzIHJlYWRpbmcgb25jZSB0aGUgYnl0ZXMgcmVhZCBwYXNzIHRoZSBsaW1pdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgQm9keTogYXN5bmNJdGVyYWJsZUZyb20oW0J1ZmZlci5mcm9tKFwiaGVsXCIpLCBCdWZmZXIuZnJvbShcImxvXCIpXSksXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICBmZXRjaEZyb21TMyhzMywgXCJteS1idWNrZXRcIiwgXCIvYmlnLnBuZ1wiLCBST09ULCA0KSxcbiAgICApLnJlamVjdHMudG9CZUluc3RhbmNlT2YoSW1hZ2VUb29MYXJnZUVycm9yKTtcbiAgICAvLyBBdCB0aGUgbGltaXQgZXhhY3RseSBpcyBmaW5lLlxuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IGFzeW5jSXRlcmFibGVGcm9tKFtCdWZmZXIuZnJvbShcImhlbFwiKSwgQnVmZmVyLmZyb20oXCJsb1wiKV0pLFxuICAgICAgQ29udGVudExlbmd0aDogNSxcbiAgICB9KTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBmZXRjaEZyb21TMyhzMywgXCJteS1idWNrZXRcIiwgXCIvb2sucG5nXCIsIFJPT1QsIDUpO1xuICAgIGV4cGVjdChyZXN1bHQuYnVmZmVyLnRvU3RyaW5nKCkpLnRvQmUoXCJoZWxsb1wiKTtcbiAgfSk7XG5cbiAgaXQoXCJ0aHJvd3Mgd2hlbiBTMyByZXR1cm5zIG5vIGJvZHlcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHsgQm9keTogdW5kZWZpbmVkIH0pO1xuXG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgZmV0Y2hGcm9tUzMoczMsIFwibXktYnVja2V0XCIsIFwiL21pc3NpbmcucG5nXCIsIFJPT1QsIEluZmluaXR5KSxcbiAgICApLnJlamVjdHMudG9UaHJvdygvRW1wdHkgcmVzcG9uc2UgZnJvbSBTMy8pO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcInJlc29sdmVFcnJvclJlc3BvbnNlXCIsICgpID0+IHtcbiAgaXQoXCJwcmVzZXJ2ZXMgdGhlIHN0YXR1cyBjb2RlIGFuZCBtZXNzYWdlIGZyb20gYW4gSW1hZ2VFcnJvclwiLCAoKSA9PiB7XG4gICAgY29uc3QgZXJyb3IgPSBuZXcgSW1hZ2VFcnJvcig0MDAsICdcInVybFwiIHBhcmFtZXRlciBpcyBub3QgYWxsb3dlZCcpO1xuXG4gICAgZXhwZWN0KHJlc29sdmVFcnJvclJlc3BvbnNlKGVycm9yLCBJbWFnZUVycm9yKSkudG9FcXVhbCh7XG4gICAgICBzdGF0dXNDb2RlOiA0MDAsXG4gICAgICBtZXNzYWdlOiAnXCJ1cmxcIiBwYXJhbWV0ZXIgaXMgbm90IGFsbG93ZWQnLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcIm1hcHMgYSBzb3VyY2Ugb3ZlciBpbWFnZXMubWF4aW11bVJlc3BvbnNlQm9keSB0byBuZXh0IHN0YXJ0J3MgNDEzXCIsICgpID0+IHtcbiAgICBleHBlY3QoXG4gICAgICByZXNvbHZlRXJyb3JSZXNwb25zZShuZXcgSW1hZ2VUb29MYXJnZUVycm9yKFwiYmlnLnBuZ1wiKSwgSW1hZ2VFcnJvciksXG4gICAgKS50b0VxdWFsKHtcbiAgICAgIHN0YXR1c0NvZGU6IDQxMyxcbiAgICAgIG1lc3NhZ2U6ICdcInVybFwiIHBhcmFtZXRlciBpcyB2YWxpZCBidXQgaW50ZXJuYWwgcmVzcG9uc2UgaXMgaW52YWxpZCcsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwiZmFsbHMgYmFjayB0byA1MDAgZm9yIHVucmVjb2duaXplZCBlcnJvcnNcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChyZXNvbHZlRXJyb3JSZXNwb25zZShuZXcgRXJyb3IoXCJib29tXCIpLCBJbWFnZUVycm9yKSkudG9FcXVhbCh7XG4gICAgICBzdGF0dXNDb2RlOiA1MDAsXG4gICAgICBtZXNzYWdlOiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgIH0pO1xuICAgIGV4cGVjdChyZXNvbHZlRXJyb3JSZXNwb25zZShcIm5vdCBhbiBlcnJvclwiLCBJbWFnZUVycm9yKSkudG9FcXVhbCh7XG4gICAgICBzdGF0dXNDb2RlOiA1MDAsXG4gICAgICBtZXNzYWdlOiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ShimIncomingMessage } from "./http/request";
|
|
2
|
+
import { ShimServerResponse } from "./http/response";
|
|
3
|
+
import { AdapterManifest } from "./manifest";
|
|
4
|
+
export interface ImageOptimizerOptions {
|
|
5
|
+
readonly deploymentRoot: string;
|
|
6
|
+
readonly manifest: AdapterManifest;
|
|
7
|
+
/**
|
|
8
|
+
* `CDK_NEXTJS_STATIC_ASSETS_BUCKET_NAME`. Empty when the sources are on disk
|
|
9
|
+
* (`NextjsRegionalContainers`), which sends every one to `fetchInternal`.
|
|
10
|
+
*/
|
|
11
|
+
readonly bucket: string;
|
|
12
|
+
/**
|
|
13
|
+
* `CDK_NEXTJS_STATIC_ASSETS_KEY_PREFIX`. Empty when the assets sit at the root
|
|
14
|
+
* of the bucket, which is the default.
|
|
15
|
+
*/
|
|
16
|
+
readonly bucketKeyPrefix: string;
|
|
17
|
+
/**
|
|
18
|
+
* Requests a local source from the app's own routes, for one S3 has no file
|
|
19
|
+
* for: `<Image src="/api/avatar?id=42">`, served by a route handler. `next
|
|
20
|
+
* start` fetches every local source that way (`fetchInternalImage`); here it
|
|
21
|
+
* is the fallback, since nearly every source is a file, and a `GetObject` is
|
|
22
|
+
* far cheaper than a route invocation.
|
|
23
|
+
*
|
|
24
|
+
* Given the request being optimized, for its authority; like `next start`,
|
|
25
|
+
* the viewer's cookies and other headers are not the implementation's to
|
|
26
|
+
* forward. And given `images.maximumResponseBody`, past which it stops
|
|
27
|
+
* reading and answers {@link InternalImageResponse.tooLarge}.
|
|
28
|
+
*/
|
|
29
|
+
readonly fetchInternal: (href: string, req: ShimIncomingMessage, maximumResponseBody: number) => Promise<InternalImageResponse>;
|
|
30
|
+
/**
|
|
31
|
+
* Loads the `cacheHandler` module from its file URL. A seam for tests, which
|
|
32
|
+
* run as CommonJS and cannot `import()` a URL.
|
|
33
|
+
* @default - `import()`
|
|
34
|
+
*/
|
|
35
|
+
readonly importModule?: (url: string) => Promise<unknown>;
|
|
36
|
+
}
|
|
37
|
+
/** The response {@link ImageOptimizerOptions.fetchInternal} got. */
|
|
38
|
+
export interface InternalImageResponse {
|
|
39
|
+
readonly statusCode: number;
|
|
40
|
+
readonly headers: Readonly<Record<string, string | string[] | undefined>>;
|
|
41
|
+
readonly body: Buffer;
|
|
42
|
+
/**
|
|
43
|
+
* The `functionGroups` group whose package has the route that serves the
|
|
44
|
+
* source, when it is not this function's: there is no response to use, and
|
|
45
|
+
* the optimizer answers an explicit 502 rather than a "not a valid image".
|
|
46
|
+
*/
|
|
47
|
+
readonly otherGroup?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The body passed `images.maximumResponseBody`, so it was cut off: a 413, as
|
|
50
|
+
* `next start` answers.
|
|
51
|
+
*/
|
|
52
|
+
readonly tooLarge?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export declare class RuntimeImageOptimizer {
|
|
55
|
+
private readonly options;
|
|
56
|
+
private readonly s3;
|
|
57
|
+
private loaded?;
|
|
58
|
+
private imageCache?;
|
|
59
|
+
constructor(options: ImageOptimizerOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Whether the app serves `/_next/image` at all. `next start` answers 404
|
|
62
|
+
* when `images.unoptimized` is set or a non-default `loader` is configured
|
|
63
|
+
* (`next-server.js`), and so does the runtime: otherwise anyone can make the
|
|
64
|
+
* compute run sharp and write the image cache on an endpoint the app turned
|
|
65
|
+
* off.
|
|
66
|
+
*/
|
|
67
|
+
isEnabled(): boolean;
|
|
68
|
+
handle(req: ShimIncomingMessage, res: ShimServerResponse, url: URL, waitUntil: (promise: Promise<unknown>) => void): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Evicted on failure, as `EntrypointRegistry.load` evicts a failed module load:
|
|
71
|
+
* a transient failure importing the `cacheHandler` (EMFILE under a cold-start
|
|
72
|
+
* burst) would otherwise 500 every image request until the sandbox recycles.
|
|
73
|
+
*/
|
|
74
|
+
private loadCache;
|
|
75
|
+
private fetchLocal;
|
|
76
|
+
}
|