cdk-nextjs 0.5.15 → 0.6.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 +821 -253
- package/.jsii.tabl.json +1 -1
- package/API.md +787 -18
- package/README.md +3 -3
- package/docs/breaking-changes.md +86 -0
- package/docs/caching-guide.md +6 -0
- package/docs/plans/adapter-runtime-release.md +362 -0
- package/docs/plans/phase-0-image-function-opt-in.md +295 -0
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +13 -0
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/image-optimization/handler-utils.d.ts +34 -0
- package/lib/image-optimization/handler-utils.js +83 -0
- package/lib/image-optimization/handler-utils.test.d.ts +1 -0
- package/lib/image-optimization/handler-utils.test.js +178 -0
- package/lib/image-optimization/handler.mjs +56126 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +4 -2
- package/lib/nextjs-api.d.ts +44 -0
- package/lib/nextjs-api.js +64 -20
- package/lib/nextjs-api.test.d.ts +1 -0
- package/lib/nextjs-api.test.js +144 -0
- package/lib/nextjs-build/nextjs-build.d.ts +60 -0
- package/lib/nextjs-build/nextjs-build.js +184 -27
- package/lib/nextjs-cache.js +1 -1
- package/lib/nextjs-compute/nextjs-containers.js +1 -1
- package/lib/nextjs-compute/nextjs-functions.js +1 -1
- package/lib/nextjs-compute/nextjs-image-function.d.ts +53 -0
- package/lib/nextjs-compute/nextjs-image-function.js +59 -0
- package/lib/nextjs-distribution.d.ts +33 -0
- package/lib/nextjs-distribution.js +39 -11
- package/lib/nextjs-post-deploy.js +1 -1
- package/lib/nextjs-static-assets.d.ts +18 -0
- package/lib/nextjs-static-assets.js +33 -6
- package/lib/nextjs-static-assets.test.d.ts +1 -0
- package/lib/nextjs-static-assets.test.js +58 -0
- package/lib/root-constructs/nextjs-base-construct.d.ts +62 -2
- package/lib/root-constructs/nextjs-base-construct.js +81 -3
- package/lib/root-constructs/nextjs-global-containers.d.ts +6 -1
- package/lib/root-constructs/nextjs-global-containers.js +11 -5
- package/lib/root-constructs/nextjs-global-functions.d.ts +16 -5
- package/lib/root-constructs/nextjs-global-functions.js +23 -21
- package/lib/root-constructs/nextjs-regional-containers.js +1 -1
- package/lib/root-constructs/nextjs-regional-functions.d.ts +11 -5
- package/lib/root-constructs/nextjs-regional-functions.js +17 -21
- package/lib/utils/base-path.d.ts +40 -0
- package/lib/utils/base-path.js +123 -0
- package/lib/utils/base-path.test.d.ts +1 -0
- package/lib/utils/base-path.test.js +163 -0
- package/lib/utils/experimental-flags.d.ts +24 -0
- package/lib/utils/experimental-flags.js +30 -0
- package/lib/utils/get-architecture.d.ts +10 -0
- package/lib/utils/get-architecture.js +17 -2
- package/package.json +3 -1
|
@@ -0,0 +1,178 @@
|
|
|
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 handler_utils_1 = require("./handler-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
|
+
describe("fetchFromS3", () => {
|
|
21
|
+
const mockSend = jest.fn();
|
|
22
|
+
const s3 = new client_s3_1.S3Client({});
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
s3.send = mockSend;
|
|
25
|
+
mockSend.mockReset();
|
|
26
|
+
});
|
|
27
|
+
it("strips the leading slash and uses url as-is for the S3 key", async () => {
|
|
28
|
+
mockSend.mockResolvedValue({
|
|
29
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
30
|
+
ContentType: "image/png",
|
|
31
|
+
ETag: '"abc123"',
|
|
32
|
+
});
|
|
33
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/base/foo.png", "");
|
|
34
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
35
|
+
expect(params).toEqual({
|
|
36
|
+
Bucket: "my-bucket",
|
|
37
|
+
Key: "base/foo.png",
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
it("applies the key prefix once when the url already includes the app basePath", async () => {
|
|
41
|
+
mockSend.mockResolvedValue({
|
|
42
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
43
|
+
ContentType: "image/png",
|
|
44
|
+
ETag: '"abc123"',
|
|
45
|
+
});
|
|
46
|
+
// next-image-loader bakes "/base" into the href for statically imported
|
|
47
|
+
// images, and NextjsStaticAssets uploads under the same prefix, so the
|
|
48
|
+
// key must carry it exactly once.
|
|
49
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/base/_next/static/media/a.png", "/base", "/base");
|
|
50
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
51
|
+
expect(params.Key).toBe("base/_next/static/media/a.png");
|
|
52
|
+
});
|
|
53
|
+
it("applies the key prefix when the url omits the app basePath", async () => {
|
|
54
|
+
mockSend.mockResolvedValue({
|
|
55
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
56
|
+
ContentType: "image/png",
|
|
57
|
+
ETag: '"abc123"',
|
|
58
|
+
});
|
|
59
|
+
// Plain string paths (e.g. `<Image src="/static/foo.jpg">`) are passed
|
|
60
|
+
// through by next/image as written, without basePath baked in, but the
|
|
61
|
+
// S3 key still has it.
|
|
62
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/static/foo.jpg", "/base", "/base");
|
|
63
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
64
|
+
expect(params.Key).toBe("base/static/foo.jpg");
|
|
65
|
+
});
|
|
66
|
+
it("only matches basePath on a path boundary", async () => {
|
|
67
|
+
mockSend.mockResolvedValue({
|
|
68
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
69
|
+
ContentType: "image/png",
|
|
70
|
+
ETag: '"abc123"',
|
|
71
|
+
});
|
|
72
|
+
// "/basement" merely shares a prefix with basePath "/base"; treating it
|
|
73
|
+
// as a match would produce the key "base/ment/logo.png".
|
|
74
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/basement/logo.png", "/base", "/base");
|
|
75
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
76
|
+
expect(params.Key).toBe("base/basement/logo.png");
|
|
77
|
+
});
|
|
78
|
+
// regression test: the Next.js app's own `basePath` (e.g. set to match an
|
|
79
|
+
// API Gateway stage) and the CDK `NextjsStaticAssets` `basePath` prop (key
|
|
80
|
+
// namespacing) are unrelated and don't have to match. A deployment that
|
|
81
|
+
// only sets the former must not leak it into the S3 key.
|
|
82
|
+
it("doesn't apply nextBasePath as a key prefix when the key prefix differs", async () => {
|
|
83
|
+
mockSend.mockResolvedValue({
|
|
84
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
85
|
+
ContentType: "image/png",
|
|
86
|
+
ETag: '"abc123"',
|
|
87
|
+
});
|
|
88
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/static/nextjs-icon-light-background.png", "/prod", "");
|
|
89
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
90
|
+
expect(params.Key).toBe("static/nextjs-icon-light-background.png");
|
|
91
|
+
});
|
|
92
|
+
it("strips nextBasePath from a baked-in href before applying a different key prefix", async () => {
|
|
93
|
+
mockSend.mockResolvedValue({
|
|
94
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
95
|
+
ContentType: "image/png",
|
|
96
|
+
ETag: '"abc123"',
|
|
97
|
+
});
|
|
98
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/prod/_next/static/media/imported-logo.png", "/prod", "");
|
|
99
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
100
|
+
expect(params.Key).toBe("_next/static/media/imported-logo.png");
|
|
101
|
+
});
|
|
102
|
+
it("doesn't double the separator when the key prefix has a trailing slash", async () => {
|
|
103
|
+
mockSend.mockResolvedValue({
|
|
104
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
105
|
+
ContentType: "image/png",
|
|
106
|
+
ETag: '"abc123"',
|
|
107
|
+
});
|
|
108
|
+
// BucketDeployment collapses the trailing slash when uploading, so the
|
|
109
|
+
// object is at "base/static/foo.jpg", not "base//static/foo.jpg".
|
|
110
|
+
await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/static/foo.jpg", "", "/base/");
|
|
111
|
+
const params = client_s3_1.GetObjectCommand.mock.calls[0][0];
|
|
112
|
+
expect(params.Key).toBe("base/static/foo.jpg");
|
|
113
|
+
});
|
|
114
|
+
it("returns the concatenated buffer, content type, and etag", async () => {
|
|
115
|
+
mockSend.mockResolvedValue({
|
|
116
|
+
Body: asyncIterableFrom([Buffer.from("hel"), Buffer.from("lo")]),
|
|
117
|
+
ContentType: "image/jpeg",
|
|
118
|
+
ETag: '"the-etag"',
|
|
119
|
+
});
|
|
120
|
+
const result = await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/foo.jpg", "");
|
|
121
|
+
expect(result.buffer.toString()).toBe("hello");
|
|
122
|
+
expect(result.contentType).toBe("image/jpeg");
|
|
123
|
+
expect(result.etag).toBe('"the-etag"');
|
|
124
|
+
});
|
|
125
|
+
it("returns an empty etag when S3 doesn't provide one", async () => {
|
|
126
|
+
mockSend.mockResolvedValue({
|
|
127
|
+
Body: asyncIterableFrom([Buffer.from("data")]),
|
|
128
|
+
ContentType: null,
|
|
129
|
+
ETag: undefined,
|
|
130
|
+
});
|
|
131
|
+
const result = await (0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/foo.png", "");
|
|
132
|
+
expect(result.etag).toBe("");
|
|
133
|
+
expect(result.contentType).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
it("throws when S3 returns no body", async () => {
|
|
136
|
+
mockSend.mockResolvedValue({ Body: undefined });
|
|
137
|
+
await expect((0, handler_utils_1.fetchFromS3)(s3, "my-bucket", "/missing.png", "")).rejects.toThrow(/Empty response from S3/);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe("getFileNameWithExtension", () => {
|
|
141
|
+
it("derives filename and extension from the url and content type", () => {
|
|
142
|
+
expect((0, handler_utils_1.getFileNameWithExtension)("/foo/bar.png?w=100&q=75", "image/webp")).toBe("bar.webp");
|
|
143
|
+
});
|
|
144
|
+
it("falls back to image.bin when contentType is missing", () => {
|
|
145
|
+
expect((0, handler_utils_1.getFileNameWithExtension)("/foo/bar.png", null)).toBe("image.bin");
|
|
146
|
+
});
|
|
147
|
+
it("falls back to image.bin when the url has no filename segment", () => {
|
|
148
|
+
expect((0, handler_utils_1.getFileNameWithExtension)("/", "image/png")).toBe("image.bin");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe("resolveErrorResponse", () => {
|
|
152
|
+
it("preserves the status code and message from an ImageError", () => {
|
|
153
|
+
const error = new image_optimizer_js_1.ImageError(400, '"url" parameter is not allowed');
|
|
154
|
+
expect((0, handler_utils_1.resolveErrorResponse)(error)).toEqual({
|
|
155
|
+
statusCode: 400,
|
|
156
|
+
message: '"url" parameter is not allowed',
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
it("maps a missing S3 object to the same 400 Next.js's own local-image fetch produces", () => {
|
|
160
|
+
const error = new Error("NoSuchKey: does not exist");
|
|
161
|
+
error.name = "NoSuchKey";
|
|
162
|
+
expect((0, handler_utils_1.resolveErrorResponse)(error)).toEqual({
|
|
163
|
+
statusCode: 400,
|
|
164
|
+
message: "The requested resource isn't a valid image.",
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
it("falls back to 500 for unrecognized errors", () => {
|
|
168
|
+
expect((0, handler_utils_1.resolveErrorResponse)(new Error("boom"))).toEqual({
|
|
169
|
+
statusCode: 500,
|
|
170
|
+
message: "Internal Server Error",
|
|
171
|
+
});
|
|
172
|
+
expect((0, handler_utils_1.resolveErrorResponse)("not an error")).toEqual({
|
|
173
|
+
statusCode: 500,
|
|
174
|
+
message: "Internal Server Error",
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlci11dGlscy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ltYWdlLW9wdGltaXphdGlvbi9oYW5kbGVyLXV0aWxzLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxzREFBc0Q7QUFDdEQsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0FBRWhDLGtEQUFnRTtBQUNoRSw0RUFBaUU7QUFDakUsbURBSXlCO0FBRXpCLFNBQVMsaUJBQWlCLENBQUMsTUFBb0I7SUFDN0MsT0FBTztRQUNMLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQztZQUNwQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDVixPQUFPO2dCQUNMLElBQUksRUFBRSxLQUFLLElBQUksRUFBRSxDQUNmLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTTtvQkFDZixDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtvQkFDckMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFO2FBQ3ZDLENBQUM7UUFDSixDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCxRQUFRLENBQUMsYUFBYSxFQUFFLEdBQUcsRUFBRTtJQUMzQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDM0IsTUFBTSxFQUFFLEdBQUcsSUFBSSxvQkFBUSxDQUFDLEVBQUUsQ0FBd0IsQ0FBQztJQUVuRCxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2IsRUFBMkMsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDO1FBQzdELFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUN2QixDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQyw0REFBNEQsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMxRSxRQUFR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QUFFLEdBQUcsRUFBRTtRQUMzRixNQUFNLEtBQUssR0FBRyxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1FBQ3JELEtBQUssQ0FBQyxJQUFJLEdBQUcsV0FBVyxDQUFDO1FBRXpCLE1BQU0sQ0FBQyxJQUFBLG9DQUFvQixFQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1lBQzFDLFVBQVUsRUFBRSxHQUFHO1lBQ2YsT0FBTyxFQUFFLDZDQUE2QztTQUN2RCxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQywyQ0FBMkMsRUFBRSxHQUFHLEVBQUU7UUFDbkQsTUFBTSxDQUFDLElBQUEsb0NBQW9CLEVBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztZQUN0RCxVQUFVLEVBQUUsR0FBRztZQUNmLE9BQU8sRUFBRSx1QkFBdUI7U0FDakMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxDQUFDLElBQUEsb0NBQW9CLEVBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDbkQsVUFBVSxFQUFFLEdBQUc7WUFDZixPQUFPLEVBQUUsdUJBQXVCO1NBQ2pDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXMgKi9cbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1zM1wiKTtcblxuaW1wb3J0IHsgR2V0T2JqZWN0Q29tbWFuZCwgUzNDbGllbnQgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXMzXCI7XG5pbXBvcnQgeyBJbWFnZUVycm9yIH0gZnJvbSBcIm5leHQvZGlzdC9zZXJ2ZXIvaW1hZ2Utb3B0aW1pemVyLmpzXCI7XG5pbXBvcnQge1xuICBmZXRjaEZyb21TMyxcbiAgZ2V0RmlsZU5hbWVXaXRoRXh0ZW5zaW9uLFxuICByZXNvbHZlRXJyb3JSZXNwb25zZSxcbn0gZnJvbSBcIi4vaGFuZGxlci11dGlsc1wiO1xuXG5mdW5jdGlvbiBhc3luY0l0ZXJhYmxlRnJvbShjaHVua3M6IFVpbnQ4QXJyYXlbXSk6IEFzeW5jSXRlcmFibGU8VWludDhBcnJheT4ge1xuICByZXR1cm4ge1xuICAgIFtTeW1ib2wuYXN5bmNJdGVyYXRvcl0oKSB7XG4gICAgICBsZXQgaSA9IDA7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBuZXh0OiBhc3luYyAoKSA9PlxuICAgICAgICAgIGkgPCBjaHVua3MubGVuZ3RoXG4gICAgICAgICAgICA/IHsgZG9uZTogZmFsc2UsIHZhbHVlOiBjaHVua3NbaSsrXSB9XG4gICAgICAgICAgICA6IHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9LFxuICAgICAgfTtcbiAgICB9LFxuICB9O1xufVxuXG5kZXNjcmliZShcImZldGNoRnJvbVMzXCIsICgpID0+IHtcbiAgY29uc3QgbW9ja1NlbmQgPSBqZXN0LmZuKCk7XG4gIGNvbnN0IHMzID0gbmV3IFMzQ2xpZW50KHt9KSBhcyB1bmtub3duIGFzIFMzQ2xpZW50O1xuXG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIChzMyBhcyB1bmtub3duIGFzIHsgc2VuZDogdHlwZW9mIG1vY2tTZW5kIH0pLnNlbmQgPSBtb2NrU2VuZDtcbiAgICBtb2NrU2VuZC5tb2NrUmVzZXQoKTtcbiAgfSk7XG5cbiAgaXQoXCJzdHJpcHMgdGhlIGxlYWRpbmcgc2xhc2ggYW5kIHVzZXMgdXJsIGFzLWlzIGZvciB0aGUgUzMga2V5XCIsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICBCb2R5OiBhc3luY0l0ZXJhYmxlRnJvbShbQnVmZmVyLmZyb20oXCJkYXRhXCIpXSksXG4gICAgICBDb250ZW50VHlwZTogXCJpbWFnZS9wbmdcIixcbiAgICAgIEVUYWc6ICdcImFiYzEyM1wiJyxcbiAgICB9KTtcblxuICAgIGF3YWl0IGZldGNoRnJvbVMzKHMzLCBcIm15LWJ1Y2tldFwiLCBcIi9iYXNlL2Zvby5wbmdcIiwgXCJcIik7XG5cbiAgICBjb25zdCBwYXJhbXMgPSAoR2V0T2JqZWN0Q29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxsc1swXVswXTtcbiAgICBleHBlY3QocGFyYW1zKS50b0VxdWFsKHtcbiAgICAgIEJ1Y2tldDogXCJteS1idWNrZXRcIixcbiAgICAgIEtleTogXCJiYXNlL2Zvby5wbmdcIixcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJhcHBsaWVzIHRoZSBrZXkgcHJlZml4IG9uY2Ugd2hlbiB0aGUgdXJsIGFscmVhZHkgaW5jbHVkZXMgdGhlIGFwcCBiYXNlUGF0aFwiLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgQm9keTogYXN5bmNJdGVyYWJsZUZyb20oW0J1ZmZlci5mcm9tKFwiZGF0YVwiKV0pLFxuICAgICAgQ29udGVudFR5cGU6IFwiaW1hZ2UvcG5nXCIsXG4gICAgICBFVGFnOiAnXCJhYmMxMjNcIicsXG4gICAgfSk7XG5cbiAgICAvLyBuZXh0LWltYWdlLWxvYWRlciBiYWtlcyBcIi9iYXNlXCIgaW50byB0aGUgaHJlZiBmb3Igc3RhdGljYWxseSBpbXBvcnRlZFxuICAgIC8vIGltYWdlcywgYW5kIE5leHRqc1N0YXRpY0Fzc2V0cyB1cGxvYWRzIHVuZGVyIHRoZSBzYW1lIHByZWZpeCwgc28gdGhlXG4gICAgLy8ga2V5IG11c3QgY2FycnkgaXQgZXhhY3RseSBvbmNlLlxuICAgIGF3YWl0IGZldGNoRnJvbVMzKFxuICAgICAgczMsXG4gICAgICBcIm15LWJ1Y2tldFwiLFxuICAgICAgXCIvYmFzZS9fbmV4dC9zdGF0aWMvbWVkaWEvYS5wbmdcIixcbiAgICAgIFwiL2Jhc2VcIixcbiAgICAgIFwiL2Jhc2VcIixcbiAgICApO1xuXG4gICAgY29uc3QgcGFyYW1zID0gKEdldE9iamVjdENvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHNbMF1bMF07XG4gICAgZXhwZWN0KHBhcmFtcy5LZXkpLnRvQmUoXCJiYXNlL19uZXh0L3N0YXRpYy9tZWRpYS9hLnBuZ1wiKTtcbiAgfSk7XG5cbiAgaXQoXCJhcHBsaWVzIHRoZSBrZXkgcHJlZml4IHdoZW4gdGhlIHVybCBvbWl0cyB0aGUgYXBwIGJhc2VQYXRoXCIsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICBCb2R5OiBhc3luY0l0ZXJhYmxlRnJvbShbQnVmZmVyLmZyb20oXCJkYXRhXCIpXSksXG4gICAgICBDb250ZW50VHlwZTogXCJpbWFnZS9wbmdcIixcbiAgICAgIEVUYWc6ICdcImFiYzEyM1wiJyxcbiAgICB9KTtcblxuICAgIC8vIFBsYWluIHN0cmluZyBwYXRocyAoZS5nLiBgPEltYWdlIHNyYz1cIi9zdGF0aWMvZm9vLmpwZ1wiPmApIGFyZSBwYXNzZWRcbiAgICAvLyB0aHJvdWdoIGJ5IG5leHQvaW1hZ2UgYXMgd3JpdHRlbiwgd2l0aG91dCBiYXNlUGF0aCBiYWtlZCBpbiwgYnV0IHRoZVxuICAgIC8vIFMzIGtleSBzdGlsbCBoYXMgaXQuXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoczMsIFwibXktYnVja2V0XCIsIFwiL3N0YXRpYy9mb28uanBnXCIsIFwiL2Jhc2VcIiwgXCIvYmFzZVwiKTtcblxuICAgIGNvbnN0IHBhcmFtcyA9IChHZXRPYmplY3RDb21tYW5kIGFzIHVua25vd24gYXMgamVzdC5Nb2NrKS5tb2NrLmNhbGxzWzBdWzBdO1xuICAgIGV4cGVjdChwYXJhbXMuS2V5KS50b0JlKFwiYmFzZS9zdGF0aWMvZm9vLmpwZ1wiKTtcbiAgfSk7XG5cbiAgaXQoXCJvbmx5IG1hdGNoZXMgYmFzZVBhdGggb24gYSBwYXRoIGJvdW5kYXJ5XCIsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrU2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICBCb2R5OiBhc3luY0l0ZXJhYmxlRnJvbShbQnVmZmVyLmZyb20oXCJkYXRhXCIpXSksXG4gICAgICBDb250ZW50VHlwZTogXCJpbWFnZS9wbmdcIixcbiAgICAgIEVUYWc6ICdcImFiYzEyM1wiJyxcbiAgICB9KTtcblxuICAgIC8vIFwiL2Jhc2VtZW50XCIgbWVyZWx5IHNoYXJlcyBhIHByZWZpeCB3aXRoIGJhc2VQYXRoIFwiL2Jhc2VcIjsgdHJlYXRpbmcgaXRcbiAgICAvLyBhcyBhIG1hdGNoIHdvdWxkIHByb2R1Y2UgdGhlIGtleSBcImJhc2UvbWVudC9sb2dvLnBuZ1wiLlxuICAgIGF3YWl0IGZldGNoRnJvbVMzKHMzLCBcIm15LWJ1Y2tldFwiLCBcIi9iYXNlbWVudC9sb2dvLnBuZ1wiLCBcIi9iYXNlXCIsIFwiL2Jhc2VcIik7XG5cbiAgICBjb25zdCBwYXJhbXMgPSAoR2V0T2JqZWN0Q29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxsc1swXVswXTtcbiAgICBleHBlY3QocGFyYW1zLktleSkudG9CZShcImJhc2UvYmFzZW1lbnQvbG9nby5wbmdcIik7XG4gIH0pO1xuXG4gIC8vIHJlZ3Jlc3Npb24gdGVzdDogdGhlIE5leHQuanMgYXBwJ3Mgb3duIGBiYXNlUGF0aGAgKGUuZy4gc2V0IHRvIG1hdGNoIGFuXG4gIC8vIEFQSSBHYXRld2F5IHN0YWdlKSBhbmQgdGhlIENESyBgTmV4dGpzU3RhdGljQXNzZXRzYCBgYmFzZVBhdGhgIHByb3AgKGtleVxuICAvLyBuYW1lc3BhY2luZykgYXJlIHVucmVsYXRlZCBhbmQgZG9uJ3QgaGF2ZSB0byBtYXRjaC4gQSBkZXBsb3ltZW50IHRoYXRcbiAgLy8gb25seSBzZXRzIHRoZSBmb3JtZXIgbXVzdCBub3QgbGVhayBpdCBpbnRvIHRoZSBTMyBrZXkuXG4gIGl0KFwiZG9lc24ndCBhcHBseSBuZXh0QmFzZVBhdGggYXMgYSBrZXkgcHJlZml4IHdoZW4gdGhlIGtleSBwcmVmaXggZGlmZmVyc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgQm9keTogYXN5bmNJdGVyYWJsZUZyb20oW0J1ZmZlci5mcm9tKFwiZGF0YVwiKV0pLFxuICAgICAgQ29udGVudFR5cGU6IFwiaW1hZ2UvcG5nXCIsXG4gICAgICBFVGFnOiAnXCJhYmMxMjNcIicsXG4gICAgfSk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIFwiL3N0YXRpYy9uZXh0anMtaWNvbi1saWdodC1iYWNrZ3JvdW5kLnBuZ1wiLFxuICAgICAgXCIvcHJvZFwiLFxuICAgICAgXCJcIixcbiAgICApO1xuXG4gICAgY29uc3QgcGFyYW1zID0gKEdldE9iamVjdENvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHNbMF1bMF07XG4gICAgZXhwZWN0KHBhcmFtcy5LZXkpLnRvQmUoXCJzdGF0aWMvbmV4dGpzLWljb24tbGlnaHQtYmFja2dyb3VuZC5wbmdcIik7XG4gIH0pO1xuXG4gIGl0KFwic3RyaXBzIG5leHRCYXNlUGF0aCBmcm9tIGEgYmFrZWQtaW4gaHJlZiBiZWZvcmUgYXBwbHlpbmcgYSBkaWZmZXJlbnQga2V5IHByZWZpeFwiLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1NlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgQm9keTogYXN5bmNJdGVyYWJsZUZyb20oW0J1ZmZlci5mcm9tKFwiZGF0YVwiKV0pLFxuICAgICAgQ29udGVudFR5cGU6IFwiaW1hZ2UvcG5nXCIsXG4gICAgICBFVGFnOiAnXCJhYmMxMjNcIicsXG4gICAgfSk7XG5cbiAgICBhd2FpdCBmZXRjaEZyb21TMyhcbiAgICAgIHMzLFxuICAgICAgXCJteS1idWNrZXRcIixcbiAgICAgIFwiL3Byb2QvX25leHQvc3RhdGljL21lZGlhL2ltcG9ydGVkLWxvZ28ucG5nXCIsXG4gICAgICBcIi9wcm9kXCIsXG4gICAgICBcIlwiLFxuICAgICk7XG5cbiAgICBjb25zdCBwYXJhbXMgPSAoR2V0T2JqZWN0Q29tbWFuZCBhcyB1bmtub3duIGFzIGplc3QuTW9jaykubW9jay5jYWxsc1swXVswXTtcbiAgICBleHBlY3QocGFyYW1zLktleSkudG9CZShcIl9uZXh0L3N0YXRpYy9tZWRpYS9pbXBvcnRlZC1sb2dvLnBuZ1wiKTtcbiAgfSk7XG5cbiAgaXQoXCJkb2Vzbid0IGRvdWJsZSB0aGUgc2VwYXJhdG9yIHdoZW4gdGhlIGtleSBwcmVmaXggaGFzIGEgdHJhaWxpbmcgc2xhc2hcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IGFzeW5jSXRlcmFibGVGcm9tKFtCdWZmZXIuZnJvbShcImRhdGFcIildKSxcbiAgICAgIENvbnRlbnRUeXBlOiBcImltYWdlL3BuZ1wiLFxuICAgICAgRVRhZzogJ1wiYWJjMTIzXCInLFxuICAgIH0pO1xuXG4gICAgLy8gQnVja2V0RGVwbG95bWVudCBjb2xsYXBzZXMgdGhlIHRyYWlsaW5nIHNsYXNoIHdoZW4gdXBsb2FkaW5nLCBzbyB0aGVcbiAgICAvLyBvYmplY3QgaXMgYXQgXCJiYXNlL3N0YXRpYy9mb28uanBnXCIsIG5vdCBcImJhc2UvL3N0YXRpYy9mb28uanBnXCIuXG4gICAgYXdhaXQgZmV0Y2hGcm9tUzMoczMsIFwibXktYnVja2V0XCIsIFwiL3N0YXRpYy9mb28uanBnXCIsIFwiXCIsIFwiL2Jhc2UvXCIpO1xuXG4gICAgY29uc3QgcGFyYW1zID0gKEdldE9iamVjdENvbW1hbmQgYXMgdW5rbm93biBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHNbMF1bMF07XG4gICAgZXhwZWN0KHBhcmFtcy5LZXkpLnRvQmUoXCJiYXNlL3N0YXRpYy9mb28uanBnXCIpO1xuICB9KTtcblxuICBpdChcInJldHVybnMgdGhlIGNvbmNhdGVuYXRlZCBidWZmZXIsIGNvbnRlbnQgdHlwZSwgYW5kIGV0YWdcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IGFzeW5jSXRlcmFibGVGcm9tKFtCdWZmZXIuZnJvbShcImhlbFwiKSwgQnVmZmVyLmZyb20oXCJsb1wiKV0pLFxuICAgICAgQ29udGVudFR5cGU6IFwiaW1hZ2UvanBlZ1wiLFxuICAgICAgRVRhZzogJ1widGhlLWV0YWdcIicsXG4gICAgfSk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBmZXRjaEZyb21TMyhzMywgXCJteS1idWNrZXRcIiwgXCIvZm9vLmpwZ1wiLCBcIlwiKTtcblxuICAgIGV4cGVjdChyZXN1bHQuYnVmZmVyLnRvU3RyaW5nKCkpLnRvQmUoXCJoZWxsb1wiKTtcbiAgICBleHBlY3QocmVzdWx0LmNvbnRlbnRUeXBlKS50b0JlKFwiaW1hZ2UvanBlZ1wiKTtcbiAgICBleHBlY3QocmVzdWx0LmV0YWcpLnRvQmUoJ1widGhlLWV0YWdcIicpO1xuICB9KTtcblxuICBpdChcInJldHVybnMgYW4gZW1wdHkgZXRhZyB3aGVuIFMzIGRvZXNuJ3QgcHJvdmlkZSBvbmVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IGFzeW5jSXRlcmFibGVGcm9tKFtCdWZmZXIuZnJvbShcImRhdGFcIildKSxcbiAgICAgIENvbnRlbnRUeXBlOiBudWxsLFxuICAgICAgRVRhZzogdW5kZWZpbmVkLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZmV0Y2hGcm9tUzMoczMsIFwibXktYnVja2V0XCIsIFwiL2Zvby5wbmdcIiwgXCJcIik7XG5cbiAgICBleHBlY3QocmVzdWx0LmV0YWcpLnRvQmUoXCJcIik7XG4gICAgZXhwZWN0KHJlc3VsdC5jb250ZW50VHlwZSkudG9CZU51bGwoKTtcbiAgfSk7XG5cbiAgaXQoXCJ0aHJvd3Mgd2hlbiBTMyByZXR1cm5zIG5vIGJvZHlcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tTZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHsgQm9keTogdW5kZWZpbmVkIH0pO1xuXG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgZmV0Y2hGcm9tUzMoczMsIFwibXktYnVja2V0XCIsIFwiL21pc3NpbmcucG5nXCIsIFwiXCIpLFxuICAgICkucmVqZWN0cy50b1Rocm93KC9FbXB0eSByZXNwb25zZSBmcm9tIFMzLyk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiZ2V0RmlsZU5hbWVXaXRoRXh0ZW5zaW9uXCIsICgpID0+IHtcbiAgaXQoXCJkZXJpdmVzIGZpbGVuYW1lIGFuZCBleHRlbnNpb24gZnJvbSB0aGUgdXJsIGFuZCBjb250ZW50IHR5cGVcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChcbiAgICAgIGdldEZpbGVOYW1lV2l0aEV4dGVuc2lvbihcIi9mb28vYmFyLnBuZz93PTEwMCZxPTc1XCIsIFwiaW1hZ2Uvd2VicFwiKSxcbiAgICApLnRvQmUoXCJiYXIud2VicFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJmYWxscyBiYWNrIHRvIGltYWdlLmJpbiB3aGVuIGNvbnRlbnRUeXBlIGlzIG1pc3NpbmdcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChnZXRGaWxlTmFtZVdpdGhFeHRlbnNpb24oXCIvZm9vL2Jhci5wbmdcIiwgbnVsbCkpLnRvQmUoXCJpbWFnZS5iaW5cIik7XG4gIH0pO1xuXG4gIGl0KFwiZmFsbHMgYmFjayB0byBpbWFnZS5iaW4gd2hlbiB0aGUgdXJsIGhhcyBubyBmaWxlbmFtZSBzZWdtZW50XCIsICgpID0+IHtcbiAgICBleHBlY3QoZ2V0RmlsZU5hbWVXaXRoRXh0ZW5zaW9uKFwiL1wiLCBcImltYWdlL3BuZ1wiKSkudG9CZShcImltYWdlLmJpblwiKTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoXCJyZXNvbHZlRXJyb3JSZXNwb25zZVwiLCAoKSA9PiB7XG4gIGl0KFwicHJlc2VydmVzIHRoZSBzdGF0dXMgY29kZSBhbmQgbWVzc2FnZSBmcm9tIGFuIEltYWdlRXJyb3JcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGVycm9yID0gbmV3IEltYWdlRXJyb3IoNDAwLCAnXCJ1cmxcIiBwYXJhbWV0ZXIgaXMgbm90IGFsbG93ZWQnKTtcblxuICAgIGV4cGVjdChyZXNvbHZlRXJyb3JSZXNwb25zZShlcnJvcikpLnRvRXF1YWwoe1xuICAgICAgc3RhdHVzQ29kZTogNDAwLFxuICAgICAgbWVzc2FnZTogJ1widXJsXCIgcGFyYW1ldGVyIGlzIG5vdCBhbGxvd2VkJyxcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJtYXBzIGEgbWlzc2luZyBTMyBvYmplY3QgdG8gdGhlIHNhbWUgNDAwIE5leHQuanMncyBvd24gbG9jYWwtaW1hZ2UgZmV0Y2ggcHJvZHVjZXNcIiwgKCkgPT4ge1xuICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKFwiTm9TdWNoS2V5OiBkb2VzIG5vdCBleGlzdFwiKTtcbiAgICBlcnJvci5uYW1lID0gXCJOb1N1Y2hLZXlcIjtcblxuICAgIGV4cGVjdChyZXNvbHZlRXJyb3JSZXNwb25zZShlcnJvcikpLnRvRXF1YWwoe1xuICAgICAgc3RhdHVzQ29kZTogNDAwLFxuICAgICAgbWVzc2FnZTogXCJUaGUgcmVxdWVzdGVkIHJlc291cmNlIGlzbid0IGEgdmFsaWQgaW1hZ2UuXCIsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwiZmFsbHMgYmFjayB0byA1MDAgZm9yIHVucmVjb2duaXplZCBlcnJvcnNcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChyZXNvbHZlRXJyb3JSZXNwb25zZShuZXcgRXJyb3IoXCJib29tXCIpKSkudG9FcXVhbCh7XG4gICAgICBzdGF0dXNDb2RlOiA1MDAsXG4gICAgICBtZXNzYWdlOiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgIH0pO1xuICAgIGV4cGVjdChyZXNvbHZlRXJyb3JSZXNwb25zZShcIm5vdCBhbiBlcnJvclwiKSkudG9FcXVhbCh7XG4gICAgICBzdGF0dXNDb2RlOiA1MDAsXG4gICAgICBtZXNzYWdlOiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19
|