cdk-nextjs 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/.jsii +2404 -2723
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1681 -1930
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +667 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1548 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +852 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +861 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  88. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  92. package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
  93. package/lib/lambdas/post-deploy/prune-s3.js +41 -12
  94. package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
  95. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  96. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  103. package/lib/nextjs-api.d.ts +102 -18
  104. package/lib/nextjs-api.js +338 -38
  105. package/lib/nextjs-api.test.js +537 -1
  106. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  107. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  108. package/lib/nextjs-build/nextjs-build.js +684 -327
  109. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  110. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  111. package/lib/nextjs-build/patch-fetch.js +1 -1
  112. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  113. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  114. package/lib/nextjs-cache.d.ts +82 -4
  115. package/lib/nextjs-cache.js +186 -10
  116. package/lib/nextjs-cache.test.js +176 -1
  117. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  118. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  120. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  121. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  122. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  123. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  124. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  125. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  126. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  127. package/lib/nextjs-distribution.d.ts +194 -23
  128. package/lib/nextjs-distribution.js +535 -62
  129. package/lib/nextjs-distribution.test.d.ts +1 -0
  130. package/lib/nextjs-distribution.test.js +697 -0
  131. package/lib/nextjs-post-deploy.d.ts +13 -5
  132. package/lib/nextjs-post-deploy.js +13 -10
  133. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  134. package/lib/nextjs-post-deploy.test.js +34 -0
  135. package/lib/nextjs-static-assets.d.ts +17 -4
  136. package/lib/nextjs-static-assets.js +22 -5
  137. package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
  138. package/lib/root-constructs/nextjs-base-construct.js +139 -47
  139. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  140. package/lib/root-constructs/nextjs-global-containers.js +20 -71
  141. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  142. package/lib/root-constructs/nextjs-global-functions.js +52 -70
  143. package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
  144. package/lib/root-constructs/nextjs-regional-containers.js +8 -15
  145. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  146. package/lib/root-constructs/nextjs-regional-functions.js +8 -26
  147. package/lib/runtime/api-gateway-path.d.ts +34 -0
  148. package/lib/runtime/api-gateway-path.js +71 -0
  149. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  150. package/lib/runtime/api-gateway-path.test.js +65 -0
  151. package/lib/runtime/case-redirect.d.ts +22 -0
  152. package/lib/runtime/case-redirect.js +63 -0
  153. package/lib/runtime/case-redirect.test.d.ts +1 -0
  154. package/lib/runtime/case-redirect.test.js +32 -0
  155. package/lib/runtime/core.d.ts +234 -0
  156. package/lib/runtime/core.js +1213 -0
  157. package/lib/runtime/core.test.d.ts +1 -0
  158. package/lib/runtime/core.test.js +1678 -0
  159. package/lib/runtime/deployment-root.d.ts +13 -0
  160. package/lib/runtime/deployment-root.js +29 -0
  161. package/lib/runtime/dispatch.d.ts +331 -0
  162. package/lib/runtime/dispatch.js +751 -0
  163. package/lib/runtime/dispatch.test.d.ts +1 -0
  164. package/lib/runtime/dispatch.test.js +853 -0
  165. package/lib/runtime/entrypoints.d.ts +57 -0
  166. package/lib/runtime/entrypoints.js +115 -0
  167. package/lib/runtime/http/abort-signal.d.ts +6 -0
  168. package/lib/runtime/http/abort-signal.js +19 -0
  169. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  170. package/lib/runtime/http/abort-signal.test.js +49 -0
  171. package/lib/runtime/http/node-server.d.ts +38 -0
  172. package/lib/runtime/http/node-server.js +99 -0
  173. package/lib/runtime/http/node-server.test.d.ts +1 -0
  174. package/lib/runtime/http/node-server.test.js +96 -0
  175. package/lib/runtime/http/node-sink.d.ts +16 -0
  176. package/lib/runtime/http/node-sink.js +48 -0
  177. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  178. package/lib/runtime/http/node-sink.test.js +66 -0
  179. package/lib/runtime/http/request.d.ts +62 -0
  180. package/lib/runtime/http/request.js +134 -0
  181. package/lib/runtime/http/request.test.d.ts +1 -0
  182. package/lib/runtime/http/request.test.js +103 -0
  183. package/lib/runtime/http/response.d.ts +77 -0
  184. package/lib/runtime/http/response.js +229 -0
  185. package/lib/runtime/http/response.test.d.ts +1 -0
  186. package/lib/runtime/http/response.test.js +178 -0
  187. package/lib/runtime/http/sink.d.ts +73 -0
  188. package/lib/runtime/http/sink.js +188 -0
  189. package/lib/runtime/http/sink.test.d.ts +1 -0
  190. package/lib/runtime/http/sink.test.js +257 -0
  191. package/lib/runtime/image-utils.d.ts +78 -0
  192. package/lib/runtime/image-utils.js +129 -0
  193. package/lib/runtime/image-utils.test.d.ts +1 -0
  194. package/lib/runtime/image-utils.test.js +237 -0
  195. package/lib/runtime/image.d.ts +76 -0
  196. package/lib/runtime/image.js +296 -0
  197. package/lib/runtime/image.test.d.ts +1 -0
  198. package/lib/runtime/image.test.js +405 -0
  199. package/lib/runtime/lambda-event.d.ts +4 -0
  200. package/lib/runtime/lambda-event.js +113 -0
  201. package/lib/runtime/lambda-event.test.d.ts +1 -0
  202. package/lib/runtime/lambda-event.test.js +119 -0
  203. package/lib/runtime/lambda.mjs +41595 -0
  204. package/lib/runtime/load-module.d.ts +8 -0
  205. package/lib/runtime/load-module.js +35 -0
  206. package/lib/runtime/manifest.d.ts +215 -0
  207. package/lib/runtime/manifest.js +118 -0
  208. package/lib/runtime/middleware.d.ts +43 -0
  209. package/lib/runtime/middleware.js +113 -0
  210. package/lib/runtime/middleware.test.d.ts +1 -0
  211. package/lib/runtime/middleware.test.js +259 -0
  212. package/lib/runtime/next-modules.d.ts +55 -0
  213. package/lib/runtime/next-modules.js +124 -0
  214. package/lib/runtime/next-modules.test.d.ts +1 -0
  215. package/lib/runtime/next-modules.test.js +34 -0
  216. package/lib/runtime/public-files.d.ts +32 -0
  217. package/lib/runtime/public-files.js +117 -0
  218. package/lib/runtime/public-files.test.d.ts +1 -0
  219. package/lib/runtime/public-files.test.js +97 -0
  220. package/lib/runtime/server.mjs +41588 -0
  221. package/lib/runtime/static-files.d.ts +50 -0
  222. package/lib/runtime/static-files.js +266 -0
  223. package/lib/runtime/static-files.test.d.ts +1 -0
  224. package/lib/runtime/static-files.test.js +118 -0
  225. package/lib/runtime/util.d.ts +28 -0
  226. package/lib/runtime/util.js +79 -0
  227. package/lib/utils/base-path.d.ts +106 -13
  228. package/lib/utils/base-path.js +254 -41
  229. package/lib/utils/base-path.test.js +219 -51
  230. package/lib/utils/get-architecture.d.ts +7 -8
  231. package/lib/utils/get-architecture.js +12 -13
  232. package/lib/utils/zip-directory.d.ts +14 -0
  233. package/lib/utils/zip-directory.js +121 -0
  234. package/lib/utils/zip-directory.test.d.ts +1 -0
  235. package/lib/utils/zip-directory.test.js +99 -0
  236. package/package.json +22 -3
  237. package/scripts/capture-adapter-fixture.mjs +325 -0
  238. package/scripts/e2e-deploy.sh +398 -0
  239. package/scripts/e2e-harness/README.md +707 -0
  240. package/scripts/e2e-harness/app.js +370 -0
  241. package/scripts/e2e-harness/common.sh +249 -0
  242. package/scripts/e2e-harness/screen.mjs +302 -0
  243. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  244. package/scripts/e2e-harness/type-filters.mjs +47 -0
  245. package/scripts/e2e-logs.sh +75 -0
  246. package/scripts/e2e-offline.sh +91 -0
  247. package/scripts/e2e-sweep.sh +370 -0
  248. package/scripts/e2e-warm.sh +114 -0
  249. package/scripts/zero-config-build.mjs +418 -0
  250. package/docs/1k-concurrent-users-executions.png +0 -0
  251. package/docs/plans/adapter-runtime-release.md +0 -362
  252. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  253. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  254. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  255. package/lib/image-optimization/handler-utils.d.ts +0 -34
  256. package/lib/image-optimization/handler-utils.js +0 -83
  257. package/lib/image-optimization/handler-utils.test.js +0 -178
  258. package/lib/nextjs-build/functions.Dockerfile +0 -31
  259. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  260. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  261. package/lib/utils/experimental-flags.d.ts +0 -24
  262. package/lib/utils/experimental-flags.js +0 -30
  263. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,361 @@
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
+ jest.mock("@aws-sdk/client-dynamodb");
6
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
7
+ const client_s3_1 = require("@aws-sdk/client-s3");
8
+ const aws_cache_store_1 = require("./aws-cache-store");
9
+ /** The input an automocked SDK command was constructed with. */
10
+ const commandInput = (command, type) => {
11
+ const mock = type;
12
+ return mock.mock.calls[mock.mock.instances.indexOf(command)][0];
13
+ };
14
+ describe("resolveAwsCacheConfig", () => {
15
+ const env = process.env;
16
+ beforeEach(() => {
17
+ process.env = { ...env };
18
+ });
19
+ afterAll(() => {
20
+ process.env = env;
21
+ });
22
+ it("reads the environment the constructs set", () => {
23
+ process.env.CDK_NEXTJS_CACHE_BUCKET_NAME = "bucket";
24
+ process.env.CDK_NEXTJS_REVALIDATION_TABLE_NAME = "table";
25
+ process.env.CDK_NEXTJS_BUILD_ID = "build";
26
+ process.env.AWS_REGION = "eu-west-1";
27
+ expect((0, aws_cache_store_1.resolveAwsCacheConfig)()).toEqual({
28
+ bucketName: "bucket",
29
+ tableName: "table",
30
+ buildId: "build",
31
+ region: "eu-west-1",
32
+ });
33
+ });
34
+ it("reports what is unset as empty", () => {
35
+ delete process.env.CDK_NEXTJS_CACHE_BUCKET_NAME;
36
+ delete process.env.CDK_NEXTJS_REVALIDATION_TABLE_NAME;
37
+ delete process.env.CDK_NEXTJS_BUILD_ID;
38
+ delete process.env.AWS_REGION;
39
+ expect((0, aws_cache_store_1.resolveAwsCacheConfig)()).toEqual({
40
+ bucketName: "",
41
+ tableName: "",
42
+ buildId: "",
43
+ region: "us-east-1",
44
+ });
45
+ });
46
+ });
47
+ describe("S3 keys", () => {
48
+ it("keeps the incremental cache's {buildId}/{key}.json convention", () => {
49
+ expect((0, aws_cache_store_1.buildS3Key)("b", "/")).toBe("b/index.json");
50
+ expect((0, aws_cache_store_1.buildS3Key)("b", "")).toBe("b/index.json");
51
+ expect((0, aws_cache_store_1.buildS3Key)("b", "/blog/post")).toBe("b/blog/post.json");
52
+ expect((0, aws_cache_store_1.buildS3Key)("b", "abc123")).toBe("b/abc123.json");
53
+ });
54
+ it("puts 'use cache' entries where no incremental key can land", () => {
55
+ const key = (0, aws_cache_store_1.useCacheS3Key)("b", "f".repeat(64));
56
+ expect(key).toBe(`b/_use-cache/${"f".repeat(64)}.entry`);
57
+ // Even a route spelled like the use-cache key gets `.json` appended.
58
+ expect((0, aws_cache_store_1.buildS3Key)("b", `/_use-cache/${"f".repeat(64)}.entry`)).not.toBe(key);
59
+ expect(key.endsWith(".json")).toBe(false);
60
+ });
61
+ });
62
+ describe("tag markers", () => {
63
+ it("writes what markerFor applies locally", () => {
64
+ for (const durations of [undefined, {}, { expire: 60 }]) {
65
+ const update = (0, aws_cache_store_1.markerUpdate)(1000, durations);
66
+ const local = (0, aws_cache_store_1.markerFor)(1000, durations);
67
+ const written = {};
68
+ for (const [name, value] of Object.entries(update.ExpressionAttributeValues)) {
69
+ written[name.slice(1)] = Number(value.N);
70
+ }
71
+ expect(written).toEqual(local);
72
+ }
73
+ expect((0, aws_cache_store_1.markerFor)(1000, { expire: 60 })).toEqual({
74
+ staleAt: 1000,
75
+ expiredAt: 61000,
76
+ });
77
+ });
78
+ it("keeps an earlier expiredAt a profile with no expire leaves", () => {
79
+ // The row keeps it (`SET staleAt` only), so an instance learning of the
80
+ // second revalidation from the log has to keep it too.
81
+ const first = (0, aws_cache_store_1.markerFor)(1000, { expire: 60 });
82
+ const second = (0, aws_cache_store_1.markerFor)(2000, {});
83
+ expect((0, aws_cache_store_1.mergeMarkers)(first, second)).toEqual({
84
+ staleAt: 2000,
85
+ expiredAt: 61000,
86
+ });
87
+ expect((0, aws_cache_store_1.mergeMarkers)(second, first)).toEqual({
88
+ staleAt: 2000,
89
+ expiredAt: 61000,
90
+ });
91
+ // A newer `expire` still replaces it.
92
+ expect((0, aws_cache_store_1.mergeMarkers)(first, (0, aws_cache_store_1.markerFor)(2000, { expire: 1 }))).toEqual({
93
+ staleAt: 2000,
94
+ expiredAt: 3000,
95
+ });
96
+ });
97
+ it("judges an entry the way the incremental cache always has", () => {
98
+ // Expired outright after creation.
99
+ expect((0, aws_cache_store_1.markerState)({ revalidatedAt: 20 }, 10, 30)).toBe("expired");
100
+ // Revalidated before the entry was created: no effect.
101
+ expect((0, aws_cache_store_1.markerState)({ revalidatedAt: 5 }, 10, 30)).toBe("fresh");
102
+ // A profile: stale now, expired once `expiredAt` passes.
103
+ expect((0, aws_cache_store_1.markerState)({ staleAt: 20, expiredAt: 50 }, 10, 30)).toBe("stale");
104
+ expect((0, aws_cache_store_1.markerState)({ staleAt: 20, expiredAt: 50 }, 10, 60)).toBe("expired");
105
+ // `expire: 0`: stale and expired at once.
106
+ expect((0, aws_cache_store_1.markerState)({ staleAt: 20, expiredAt: 20 }, 10, 30)).toBe("expired");
107
+ expect((0, aws_cache_store_1.markerState)({}, 10, 30)).toBe("fresh");
108
+ });
109
+ });
110
+ describe("TagMarkerTable", () => {
111
+ const send = jest.fn();
112
+ let table;
113
+ beforeEach(() => {
114
+ send.mockReset();
115
+ client_dynamodb_1.DynamoDBClient.mockImplementation(() => ({ send }));
116
+ table = new aws_cache_store_1.TagMarkerTable(new client_dynamodb_1.DynamoDBClient({}), "tbl", "build");
117
+ });
118
+ it("writes the marker row under the build", async () => {
119
+ send.mockResolvedValue({});
120
+ await table.write("posts", 1000, { expire: 1 });
121
+ const input = commandInput(send.mock.calls[0][0], client_dynamodb_1.UpdateItemCommand);
122
+ expect(input).toEqual({
123
+ TableName: "tbl",
124
+ Key: { pk: { S: "build" }, sk: { S: "posts" } },
125
+ UpdateExpression: "SET staleAt = :staleAt, expiredAt = :expiredAt",
126
+ ExpressionAttributeValues: {
127
+ ":staleAt": { N: "1000" },
128
+ ":expiredAt": { N: "2000" },
129
+ },
130
+ ReturnValues: "ALL_NEW",
131
+ });
132
+ });
133
+ it("reads markers in batches of 100 and parses them", async () => {
134
+ send.mockImplementation((command) => {
135
+ const { RequestItems } = commandInput(command, client_dynamodb_1.BatchGetItemCommand);
136
+ const keys = RequestItems.tbl.Keys;
137
+ return Promise.resolve({
138
+ Responses: {
139
+ tbl: keys
140
+ .filter(({ sk }) => sk.S.endsWith("0"))
141
+ .map(({ sk }) => ({ sk, revalidatedAt: { N: "7" } })),
142
+ },
143
+ });
144
+ });
145
+ const tags = Array.from({ length: 150 }, (_, i) => `t${i}`);
146
+ const markers = await table.read([...tags, "t0"]);
147
+ expect(send).toHaveBeenCalledTimes(2);
148
+ expect(markers.size).toBe(15);
149
+ expect(markers.get("t10")).toEqual({
150
+ revalidatedAt: 7,
151
+ staleAt: undefined,
152
+ expiredAt: undefined,
153
+ });
154
+ });
155
+ // A read-back after the write is eventually consistent, so it can return
156
+ // the marker from before it: the writer tracks what the write returned.
157
+ it("returns the row as the write left it", async () => {
158
+ send.mockResolvedValueOnce({
159
+ Attributes: {
160
+ sk: { S: "posts" },
161
+ revalidatedAt: { N: "5000" },
162
+ staleAt: { N: "10" },
163
+ },
164
+ });
165
+ expect(await table.write("posts", 5000, undefined)).toEqual({
166
+ revalidatedAt: 5000,
167
+ staleAt: 10,
168
+ expiredAt: undefined,
169
+ });
170
+ send.mockResolvedValueOnce({});
171
+ expect(await table.write("posts", 6000, undefined)).toBeUndefined();
172
+ });
173
+ it("asks again for unprocessed keys, and gives up after three tries", async () => {
174
+ const unprocessed = {
175
+ UnprocessedKeys: {
176
+ tbl: { Keys: [{ pk: { S: "build" }, sk: { S: "a" } }] },
177
+ },
178
+ };
179
+ send.mockResolvedValueOnce(unprocessed).mockResolvedValueOnce({
180
+ Responses: { tbl: [{ sk: { S: "a" }, staleAt: { N: "3" } }] },
181
+ });
182
+ expect((await table.read(["a"])).get("a")?.staleAt).toBe(3);
183
+ send.mockResolvedValue(unprocessed);
184
+ await expect(table.read(["a"])).rejects.toThrow(/unread after retrying/);
185
+ });
186
+ });
187
+ describe("RevalidationLog", () => {
188
+ const send = jest.fn();
189
+ let log;
190
+ beforeEach(() => {
191
+ send.mockReset();
192
+ client_dynamodb_1.DynamoDBClient.mockImplementation(() => ({ send }));
193
+ log = new aws_cache_store_1.RevalidationLog(new client_dynamodb_1.DynamoDBClient({}), "tbl", "build");
194
+ });
195
+ it("puts one row per revalidation under the build's log, with a TTL", async () => {
196
+ send.mockResolvedValue({});
197
+ const at = 1_727_000_000_123;
198
+ await log.put("user#42", at, { staleAt: 5, expiredAt: 6 });
199
+ expect(commandInput(send.mock.calls[0][0], client_dynamodb_1.PutItemCommand)).toEqual({
200
+ TableName: "tbl",
201
+ Item: {
202
+ pk: { S: "build#log" },
203
+ sk: { S: "001727000000123#user#42" },
204
+ ttl: { N: String(Math.ceil((at + aws_cache_store_1.REVALIDATION_LOG_TTL_MS) / 1000)) },
205
+ staleAt: { N: "5" },
206
+ expiredAt: { N: "6" },
207
+ },
208
+ ConditionExpression: "attribute_not_exists(sk)",
209
+ });
210
+ });
211
+ it("moves a row to the next millisecond rather than overwrite another revalidation", async () => {
212
+ // `updateTag('x')` and `revalidateTag('x', 'max')` in one millisecond.
213
+ const taken = Object.assign(new Error("taken"), {
214
+ name: "ConditionalCheckFailedException",
215
+ });
216
+ send.mockRejectedValueOnce(taken).mockResolvedValueOnce({});
217
+ await log.put("x", 1000.5, { revalidatedAt: 5 });
218
+ expect(send.mock.calls.map(([command]) => commandInput(command, client_dynamodb_1.PutItemCommand).Item.sk.S)).toEqual(["000000000001000#x", "000000000001001#x"]);
219
+ });
220
+ it("gives up after a bounded number of collisions, and on other errors at once", async () => {
221
+ const taken = Object.assign(new Error("taken"), {
222
+ name: "ConditionalCheckFailedException",
223
+ });
224
+ send.mockRejectedValue(taken);
225
+ await expect(log.put("x", 1000, {})).rejects.toBe(taken);
226
+ expect(send).toHaveBeenCalledTimes(5);
227
+ send.mockReset();
228
+ const throttled = new Error("throttled");
229
+ send.mockRejectedValue(throttled);
230
+ await expect(log.put("x", 1000, {})).rejects.toBe(throttled);
231
+ expect(send).toHaveBeenCalledTimes(1);
232
+ });
233
+ it("queries from a zero-padded cursor and parses the tag after it", async () => {
234
+ send
235
+ .mockResolvedValueOnce({
236
+ Items: [
237
+ { sk: { S: "000000000001000#a" }, revalidatedAt: { N: "7" } },
238
+ { sk: { S: "not a log row" } },
239
+ ],
240
+ LastEvaluatedKey: { pk: { S: "build#log" }, sk: { S: "x" } },
241
+ })
242
+ .mockResolvedValueOnce({
243
+ Items: [{ sk: { S: "000000000002000#user#42" }, staleAt: { N: "8" } }],
244
+ });
245
+ const { rows, truncated } = await log.query(999.5);
246
+ const first = commandInput(send.mock.calls[0][0], client_dynamodb_1.QueryCommand);
247
+ expect(first).toMatchObject({
248
+ TableName: "tbl",
249
+ KeyConditionExpression: "pk = :pk AND sk >= :since",
250
+ ExpressionAttributeValues: {
251
+ ":pk": { S: "build#log" },
252
+ ":since": { S: "000000000000999" },
253
+ },
254
+ });
255
+ expect(commandInput(send.mock.calls[1][0], client_dynamodb_1.QueryCommand).ExclusiveStartKey).toEqual({ pk: { S: "build#log" }, sk: { S: "x" } });
256
+ expect(truncated).toBe(false);
257
+ expect(rows).toEqual([
258
+ {
259
+ sk: "000000000001000#a",
260
+ at: 1000,
261
+ tag: "a",
262
+ marker: { revalidatedAt: 7, staleAt: undefined, expiredAt: undefined },
263
+ },
264
+ {
265
+ sk: "000000000002000#user#42",
266
+ at: 2000,
267
+ tag: "user#42",
268
+ marker: { revalidatedAt: undefined, staleAt: 8, expiredAt: undefined },
269
+ },
270
+ ]);
271
+ });
272
+ it("stops after its page bound and says so", async () => {
273
+ send.mockResolvedValue({
274
+ Items: [],
275
+ LastEvaluatedKey: { pk: { S: "build#log" }, sk: { S: "x" } },
276
+ });
277
+ expect((await log.query(0)).truncated).toBe(true);
278
+ expect(send).toHaveBeenCalledTimes(aws_cache_store_1.REVALIDATION_LOG_MAX_PAGES);
279
+ });
280
+ });
281
+ describe("CacheBucket", () => {
282
+ const send = jest.fn();
283
+ let bucket;
284
+ beforeEach(() => {
285
+ send.mockReset();
286
+ client_s3_1.S3Client.mockImplementation(() => ({ send }));
287
+ bucket = new aws_cache_store_1.CacheBucket(new client_s3_1.S3Client({}), "bkt");
288
+ });
289
+ it("reads an object as text", async () => {
290
+ send.mockResolvedValue({
291
+ Body: { transformToString: jest.fn().mockResolvedValue("{}") },
292
+ ContentType: "application/json",
293
+ });
294
+ expect(await bucket.get("k")).toBe("{}");
295
+ expect(commandInput(send.mock.calls[0][0], client_s3_1.GetObjectCommand)).toEqual({
296
+ Bucket: "bkt",
297
+ Key: "k",
298
+ });
299
+ });
300
+ it("answers a missing object or body with undefined, and throws the rest", async () => {
301
+ send.mockRejectedValueOnce(new client_s3_1.NoSuchKey({ message: "missing", $metadata: {} }));
302
+ expect(await bucket.get("k")).toBeUndefined();
303
+ send.mockResolvedValueOnce({ Body: null });
304
+ expect(await bucket.get("k")).toBeUndefined();
305
+ send.mockRejectedValueOnce(new Error("AccessDenied"));
306
+ await expect(bucket.get("k")).rejects.toThrow("AccessDenied");
307
+ });
308
+ it("writes JSON", async () => {
309
+ send.mockResolvedValue({});
310
+ await bucket.putJson("k", "{}");
311
+ expect(commandInput(send.mock.calls[0][0], client_s3_1.PutObjectCommand)).toEqual({
312
+ Bucket: "bkt",
313
+ Key: "k",
314
+ Body: "{}",
315
+ ContentType: "application/json; charset=utf-8",
316
+ });
317
+ });
318
+ });
319
+ describe("TrackedTagMarkers", () => {
320
+ it("does not skip a row for an untracked tag that its first read missed", async () => {
321
+ // The writer puts the log row and the marker at the same time, and the
322
+ // marker read is eventually consistent: `refresh` can see the row, then
323
+ // `ensure` read the marker from before it. Marked applied while the tag
324
+ // was untracked, the row was skipped by every query the lookback returned
325
+ // it to, and the instance served the stale entry until the rolling re-read.
326
+ let clock = 1_000_000;
327
+ const revalidatedAt = 999_000;
328
+ const row = {
329
+ sk: `${String(clock).padStart(15, "0")}#posts`,
330
+ at: clock,
331
+ tag: "posts",
332
+ marker: { revalidatedAt },
333
+ };
334
+ const query = jest.fn(async (since) => ({
335
+ rows: [row].filter((r) => r.at >= since),
336
+ truncated: false,
337
+ }));
338
+ // A replica that has not seen the write yet.
339
+ const read = jest.fn(async () => new Map());
340
+ const markers = new aws_cache_store_1.TrackedTagMarkers({
341
+ markers: { read },
342
+ log: { query },
343
+ refreshIntervalMs: 1000,
344
+ clock: () => clock,
345
+ random: () => 0,
346
+ });
347
+ // Something tracked, so the refresh queries the log.
348
+ await markers.ensure(["other"]);
349
+ clock += 1000;
350
+ await markers.refresh();
351
+ await markers.ensure(["posts"]);
352
+ expect(markers.get("posts")).toEqual({});
353
+ clock += 1000;
354
+ await markers.refresh();
355
+ expect(query).toHaveBeenCalledTimes(2);
356
+ expect(markers.get("posts")).toEqual({ revalidatedAt });
357
+ // Only the one read each tag's first use costs.
358
+ expect(read).toHaveBeenCalledTimes(2);
359
+ });
360
+ });
361
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLWNhY2hlLXN0b3JlLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWRhcHRlci9hd3MtY2FjaGUtc3RvcmUudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHNEQUFzRDtBQUN0RCxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7QUFDaEMsSUFBSSxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBRXRDLDhEQU1rQztBQUNsQyxrREFLNEI7QUFDNUIsdURBZ0IyQjtBQUUzQixnRUFBZ0U7QUFDaEUsTUFBTSxZQUFZLEdBQUcsQ0FBQyxPQUFnQixFQUFFLElBQWEsRUFBRSxFQUFFO0lBQ3ZELE1BQU0sSUFBSSxHQUFHLElBQWlCLENBQUM7SUFDL0IsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNsRSxDQUFDLENBQUM7QUFFRixRQUFRLENBQUMsdUJBQXVCLEVBQUUsR0FBRyxFQUFFO0lBQ3JDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUM7SUFDeEIsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLE9BQU8sQ0FBQyxHQUFHLEdBQUcsRUFBRSxHQUFHLEdBQUcsRUFBRSxDQUFDO0lBQzNCLENBQUMsQ0FBQyxDQUFDO0lBQ0gsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUNaLE9BQU8sQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQ3BCLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLDBDQUEwQyxFQUFFLEdBQUcsRUFBRTtRQUNsRCxPQUFPLENBQUMsR0FBRyxDQUFDLDRCQUE0QixHQUFHLFFBQVEsQ0FBQztRQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLGtDQUFrQyxHQUFHLE9BQU8sQ0FBQztR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QUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRXpDLEtBQUssSUFBSSxJQUFJLENBQUM7UUFDZCxNQUFNLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN4QixNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3hELGdEQUFnRDtRQUNoRCxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuamVzdC5tb2NrKFwiQGF3cy1zZGsvY2xpZW50LXMzXCIpO1xuamVzdC5tb2NrKFwiQGF3cy1zZGsvY2xpZW50LWR5bmFtb2RiXCIpO1xuXG5pbXBvcnQge1xuICBCYXRjaEdldEl0ZW1Db21tYW5kLFxuICBEeW5hbW9EQkNsaWVudCxcbiAgUHV0SXRlbUNvbW1hbmQsXG4gIFF1ZXJ5Q29tbWFuZCxcbiAgVXBkYXRlSXRlbUNvbW1hbmQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtZHluYW1vZGJcIjtcbmltcG9ydCB7XG4gIEdldE9iamVjdENvbW1hbmQsXG4gIE5vU3VjaEtleSxcbiAgUHV0T2JqZWN0Q29tbWFuZCxcbiAgUzNDbGllbnQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtczNcIjtcbmltcG9ydCB7XG4gIGJ1aWxkUzNLZXksXG4gIENhY2hlQnVja2V0LFxuICBtYXJrZXJGb3IsXG4gIG1hcmtlclN0YXRlLFxuICBtYXJrZXJVcGRhdGUsXG4gIG1lcmdlTWFya2VycyxcbiAgcmVzb2x2ZUF3c0NhY2hlQ29uZmlnLFxuICBSRVZBTElEQVRJT05fTE9HX01BWF9QQUdFUyxcbiAgUkVWQUxJREFUSU9OX0xPR19UVExfTVMsXG4gIFJldmFsaWRhdGlvbkxvZyxcbiAgUmV2YWxpZGF0aW9uTG9nUm93LFxuICBUYWdNYXJrZXIsXG4gIFRhZ01hcmtlclRhYmxlLFxuICBUcmFja2VkVGFnTWFya2VycyxcbiAgdXNlQ2FjaGVTM0tleSxcbn0gZnJvbSBcIi4vYXdzLWNhY2hlLXN0b3JlXCI7XG5cbi8qKiBUaGUgaW5wdXQgYW4gYXV0b21vY2tlZCBTREsgY29tbWFuZCB3YXMgY29uc3RydWN0ZWQgd2l0aC4gKi9cbmNvbnN0IGNvbW1hbmRJbnB1dCA9IChjb21tYW5kOiB1bmtub3duLCB0eXBlOiB1bmtub3duKSA9PiB7XG4gIGNvbnN0IG1vY2sgPSB0eXBlIGFzIGplc3QuTW9jaztcbiAgcmV0dXJuIG1vY2subW9jay5jYWxsc1ttb2NrLm1vY2suaW5zdGFuY2VzLmluZGV4T2YoY29tbWFuZCldWzBdO1xufTtcblxuZGVzY3JpYmUoXCJyZXNvbHZlQXdzQ2FjaGVDb25maWdcIiwgKCkgPT4ge1xuICBjb25zdCBlbnYgPSBwcm9jZXNzLmVudjtcbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgcHJvY2Vzcy5lbnYgPSB7IC4uLmVudiB9O1xuICB9KTtcbiAgYWZ0ZXJBbGwoKCkgPT4ge1xuICAgIHByb2Nlc3MuZW52ID0gZW52O1xuICB9KTtcblxuICBpdChcInJlYWRzIHRoZSBlbnZpcm9ubWVudCB0aGUgY29uc3RydWN0cyBzZXRcIiwgKCkgPT4ge1xuICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQ0FDSEVfQlVDS0VUX05BTUUgPSBcImJ1Y2tldFwiO1xuICAgIHByb2Nlc3MuZW52LkNES19ORVhUSlNfUkVWQUxJREFUSU9OX1RBQkxFX05BTUUgPSBcInRhYmxlXCI7XG4gICAgcHJvY2Vzcy5lbnYuQ0RLX05FWFRKU19CVUlMRF9JRCA9IFwiYnVpbGRcIjtcbiAgICBwcm9jZXNzLmVudi5BV1NfUkVHSU9OID0gXCJldS13ZXN0LTFcIjtcbiAgICBleHBlY3QocmVzb2x2ZUF3c0NhY2hlQ29uZmlnKCkpLnRvRXF1YWwoe1xuICAgICAgYnVja2V0TmFtZTogXCJidWNrZXRcIixcbiAgICAgIHRhYmxlTmFtZTogXCJ0YWJsZVwiLFxuICAgICAgYnVpbGRJZDogXCJidWlsZFwiLFxuICAgICAgcmVnaW9uOiBcImV1LXdlc3QtMVwiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcInJlcG9ydHMgd2hhdCBpcyB1bnNldCBhcyBlbXB0eVwiLCAoKSA9PiB7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQ0FDSEVfQlVDS0VUX05BTUU7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfUkVWQUxJREFUSU9OX1RBQkxFX05BTUU7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkNES19ORVhUSlNfQlVJTERfSUQ7XG4gICAgZGVsZXRlIHByb2Nlc3MuZW52LkFXU19SRUdJT047XG4gICAgZXhwZWN0KHJlc29sdmVBd3NDYWNoZUNvbmZpZygpKS50b0VxdWFsKHtcbiAgICAgIGJ1Y2tldE5hbWU6IFwiXCIsXG4gICAgICB0YWJsZU5hbWU6IFwiXCIsXG4gICAgICBidWlsZElkOiBcIlwiLFxuICAgICAgcmVnaW9uOiBcInVzLWVhc3QtMVwiLFxuICAgIH0pO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcIlMzIGtleXNcIiwgKCkgPT4ge1xuICBpdChcImtlZXBzIHRoZSBpbmNyZW1lbnRhbCBjYWNoZSdzIHtidWlsZElkfS97a2V5fS5qc29uIGNvbnZlbnRpb25cIiwgKCkgPT4ge1xuICAgIGV4cGVjdChidWlsZFMzS2V5KFwiYlwiLCBcIi9cIikpLnRvQmUoXCJiL2luZGV4Lmpzb25cIik7XG4gICAgZXhwZWN0KGJ1aWxkUzNLZXkoXCJiXCIsIFwiXCIpKS50b0JlKFwiYi9pbmRleC5qc29uXCIpO1xuICAgIGV4cGVjdChidWlsZFMzS2V5KFwiYlwiLCBcIi9ibG9nL3Bvc3RcIikpLnRvQmUoXCJiL2Jsb2cvcG9zdC5qc29uXCIpO1xuICAgIGV4cGVjdChidWlsZFMzS2V5KFwiYlwiLCBcImFiYzEyM1wiKSkudG9CZShcImIvYWJjMTIzLmpzb25cIik7XG4gIH0pO1xuXG4gIGl0KFwicHV0cyAndXNlIGNhY2hlJyBlbnRyaWVzIHdoZXJlIG5vIGluY3JlbWVudGFsIGtleSBjYW4gbGFuZFwiLCAoKSA9PiB7XG4gICAgY29uc3Qga2V5ID0gdXNlQ2FjaGVTM0tleShcImJcIiwgXCJmXCIucmVwZWF0KDY0KSk7XG4gICAgZXhwZWN0KGtleSkudG9CZShgYi9fdXNlLWNhY2hlLyR7XCJmXCIucmVwZWF0KDY0KX0uZW50cnlgKTtcbiAgICAvLyBFdmVuIGEgcm91dGUgc3BlbGxlZCBsaWtlIHRoZSB1c2UtY2FjaGUga2V5IGdldHMgYC5qc29uYCBhcHBlbmRlZC5cbiAgICBleHBlY3QoYnVpbGRTM0tleShcImJcIiwgYC9fdXNlLWNhY2hlLyR7XCJmXCIucmVwZWF0KDY0KX0uZW50cnlgKSkubm90LnRvQmUoXG4gICAgICBrZXksXG4gICAgKTtcbiAgICBleHBlY3Qoa2V5LmVuZHNXaXRoKFwiLmpzb25cIikpLnRvQmUoZmFsc2UpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcInRhZyBtYXJrZXJzXCIsICgpID0+IHtcbiAgaXQoXCJ3cml0ZXMgd2hhdCBtYXJrZXJGb3IgYXBwbGllcyBsb2NhbGx5XCIsICgpID0+IHtcbiAgICBmb3IgKGNvbnN0IGR1cmF0aW9ucyBvZiBbdW5kZWZpbmVkLCB7fSwgeyBleHBpcmU6IDYwIH1dKSB7XG4gICAgICBjb25zdCB1cGRhdGUgPSBtYXJrZXJVcGRhdGUoMTAwMCwgZHVyYXRpb25zKTtcbiAgICAgIGNvbnN0IGxvY2FsID0gbWFya2VyRm9yKDEwMDAsIGR1cmF0aW9ucyk7XG4gICAgICBjb25zdCB3cml0dGVuOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge307XG4gICAgICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoXG4gICAgICAgIHVwZGF0ZS5FeHByZXNzaW9uQXR0cmlidXRlVmFsdWVzISxcbiAgICAgICkpIHtcbiAgICAgICAgd3JpdHRlbltuYW1lLnNsaWNlKDEpXSA9IE51bWJlcih2YWx1ZS5OKTtcbiAgICAgIH1cbiAgICAgIGV4cGVjdCh3cml0dGVuKS50b0VxdWFsKGxvY2FsKTtcbiAgICB9XG4gICAgZXhwZWN0KG1hcmtlckZvcigxMDAwLCB7IGV4cGlyZTogNjAgfSkpLnRvRXF1YWwoe1xuICAgICAgc3RhbGVBdDogMTAwMCxcbiAgICAgIGV4cGlyZWRBdDogNjEwMDAsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwia2VlcHMgYW4gZWFybGllciBleHBpcmVkQXQgYSBwcm9maWxlIHdpdGggbm8gZXhwaXJlIGxlYXZlc1wiLCAoKSA9PiB7XG4gICAgLy8gVGhlIHJvdyBrZWVwcyBpdCAoYFNFVCBzdGFsZUF0YCBvbmx5KSwgc28gYW4gaW5zdGFuY2UgbGVhcm5pbmcgb2YgdGhlXG4gICAgLy8gc2Vjb25kIHJldmFsaWRhdGlvbiBmcm9tIHRoZSBsb2cgaGFzIHRvIGtlZXAgaXQgdG9vLlxuICAgIGNvbnN0IGZpcnN0ID0gbWFya2VyRm9yKDEwMDAsIHsgZXhwaXJlOiA2MCB9KTtcbiAgICBjb25zdCBzZWNvbmQgPSBtYXJrZXJGb3IoMjAwMCwge30pO1xuICAgIGV4cGVjdChtZXJnZU1hcmtlcnMoZmlyc3QsIHNlY29uZCkpLnRvRXF1YWwoe1xuICAgICAgc3RhbGVBdDogMjAwMCxcbiAgICAgIGV4cGlyZWRBdDogNjEwMDAsXG4gICAgfSk7XG4gICAgZXhwZWN0KG1lcmdlTWFya2VycyhzZWNvbmQsIGZpcnN0KSkudG9FcXVhbCh7XG4gICAgICBzdGFsZUF0OiAyMDAwLFxuICAgICAgZXhwaXJlZEF0OiA2MTAwMCxcbiAgICB9KTtcbiAgICAvLyBBIG5ld2VyIGBleHBpcmVgIHN0aWxsIHJlcGxhY2VzIGl0LlxuICAgIGV4cGVjdChtZXJnZU1hcmtlcnMoZmlyc3QsIG1hcmtlckZvcigyMDAwLCB7IGV4cGlyZTogMSB9KSkpLnRvRXF1YWwoe1xuICAgICAgc3RhbGVBdDogMjAwMCxcbiAgICAgIGV4cGlyZWRBdDogMzAwMCxcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoXCJqdWRnZXMgYW4gZW50cnkgdGhlIHdheSB0aGUgaW5jcmVtZW50YWwgY2FjaGUgYWx3YXlzIGhhc1wiLCAoKSA9PiB7XG4gICAgLy8gRXhwaXJlZCBvdXRyaWdodCBhZnRlciBjcmVhdGlvbi5cbiAgICBleHBlY3QobWFya2VyU3RhdGUoeyByZXZhbGlkYXRlZEF0OiAyMCB9LCAxMCwgMzApKS50b0JlKFwiZXhwaXJlZFwiKTtcbiAgICAvLyBSZXZhbGlkYXRlZCBiZWZvcmUgdGhlIGVudHJ5IHdhcyBjcmVhdGVkOiBubyBlZmZlY3QuXG4gICAgZXhwZWN0KG1hcmtlclN0YXRlKHsgcmV2YWxpZGF0ZWRBdDogNSB9LCAxMCwgMzApKS50b0JlKFwiZnJlc2hcIik7XG4gICAgLy8gQSBwcm9maWxlOiBzdGFsZSBub3csIGV4cGlyZWQgb25jZSBgZXhwaXJlZEF0YCBwYXNzZXMuXG4gICAgZXhwZWN0KG1hcmtlclN0YXRlKHsgc3RhbGVBdDogMjAsIGV4cGlyZWRBdDogNTAgfSwgMTAsIDMwKSkudG9CZShcInN0YWxlXCIpO1xuICAgIGV4cGVjdChtYXJrZXJTdGF0ZSh7IHN0YWxlQXQ6IDIwLCBleHBpcmVkQXQ6IDUwIH0sIDEwLCA2MCkpLnRvQmUoXCJleHBpcmVkXCIpO1xuICAgIC8vIGBleHBpcmU6IDBgOiBzdGFsZSBhbmQgZXhwaXJlZCBhdCBvbmNlLlxuICAgIGV4cGVjdChtYXJrZXJTdGF0ZSh7IHN0YWxlQXQ6IDIwLCBleHBpcmVkQXQ6IDIwIH0sIDEwLCAzMCkpLnRvQmUoXCJleHBpcmVkXCIpO1xuICAgIGV4cGVjdChtYXJrZXJTdGF0ZSh7fSwgMTAsIDMwKSkudG9CZShcImZyZXNoXCIpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcIlRhZ01hcmtlclRhYmxlXCIsICgpID0+IHtcbiAgY29uc3Qgc2VuZCA9IGplc3QuZm4oKTtcbiAgbGV0IHRhYmxlOiBUYWdNYXJrZXJUYWJsZTtcblxuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBzZW5kLm1vY2tSZXNldCgpO1xuICAgIChEeW5hbW9EQkNsaWVudCBhcyBqZXN0Lk1vY2spLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiAoeyBzZW5kIH0pKTtcbiAgICB0YWJsZSA9IG5ldyBUYWdNYXJrZXJUYWJsZShuZXcgRHluYW1vREJDbGllbnQoe30pLCBcInRibFwiLCBcImJ1aWxkXCIpO1xuICB9KTtcblxuICBpdChcIndyaXRlcyB0aGUgbWFya2VyIHJvdyB1bmRlciB0aGUgYnVpbGRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgIGF3YWl0IHRhYmxlLndyaXRlKFwicG9zdHNcIiwgMTAwMCwgeyBleHBpcmU6IDEgfSk7XG4gICAgY29uc3QgaW5wdXQgPSBjb21tYW5kSW5wdXQoc2VuZC5tb2NrLmNhbGxzWzBdWzBdLCBVcGRhdGVJdGVtQ29tbWFuZCk7XG4gICAgZXhwZWN0KGlucHV0KS50b0VxdWFsKHtcbiAgICAgIFRhYmxlTmFtZTogXCJ0YmxcIixcbiAgICAgIEtleTogeyBwazogeyBTOiBcImJ1aWxkXCIgfSwgc2s6IHsgUzogXCJwb3N0c1wiIH0gfSxcbiAgICAgIFVwZGF0ZUV4cHJlc3Npb246IFwiU0VUIHN0YWxlQXQgPSA6c3RhbGVBdCwgZXhwaXJlZEF0ID0gOmV4cGlyZWRBdFwiLFxuICAgICAgRXhwcmVzc2lvbkF0dHJpYnV0ZVZhbHVlczoge1xuICAgICAgICBcIjpzdGFsZUF0XCI6IHsgTjogXCIxMDAwXCIgfSxcbiAgICAgICAgXCI6ZXhwaXJlZEF0XCI6IHsgTjogXCIyMDAwXCIgfSxcbiAgICAgIH0sXG4gICAgICBSZXR1cm5WYWx1ZXM6IFwiQUxMX05FV1wiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcInJlYWRzIG1hcmtlcnMgaW4gYmF0Y2hlcyBvZiAxMDAgYW5kIHBhcnNlcyB0aGVtXCIsIGFzeW5jICgpID0+IHtcbiAgICBzZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT4ge1xuICAgICAgY29uc3QgeyBSZXF1ZXN0SXRlbXMgfSA9IGNvbW1hbmRJbnB1dChjb21tYW5kLCBCYXRjaEdldEl0ZW1Db21tYW5kKTtcbiAgICAgIGNvbnN0IGtleXMgPSBSZXF1ZXN0SXRlbXMudGJsLktleXMgYXMgeyBzazogeyBTOiBzdHJpbmcgfSB9W107XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgUmVzcG9uc2VzOiB7XG4gICAgICAgICAgdGJsOiBrZXlzXG4gICAgICAgICAgICAuZmlsdGVyKCh7IHNrIH0pID0+IHNrLlMuZW5kc1dpdGgoXCIwXCIpKVxuICAgICAgICAgICAgLm1hcCgoeyBzayB9KSA9PiAoeyBzaywgcmV2YWxpZGF0ZWRBdDogeyBOOiBcIjdcIiB9IH0pKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGNvbnN0IHRhZ3MgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiAxNTAgfSwgKF8sIGkpID0+IGB0JHtpfWApO1xuICAgIGNvbnN0IG1hcmtlcnMgPSBhd2FpdCB0YWJsZS5yZWFkKFsuLi50YWdzLCBcInQwXCJdKTtcbiAgICBleHBlY3Qoc2VuZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDIpO1xuICAgIGV4cGVjdChtYXJrZXJzLnNpemUpLnRvQmUoMTUpO1xuICAgIGV4cGVjdChtYXJrZXJzLmdldChcInQxMFwiKSkudG9FcXVhbCh7XG4gICAgICByZXZhbGlkYXRlZEF0OiA3LFxuICAgICAgc3RhbGVBdDogdW5kZWZpbmVkLFxuICAgICAgZXhwaXJlZEF0OiB1bmRlZmluZWQsXG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vIEEgcmVhZC1iYWNrIGFmdGVyIHRoZSB3cml0ZSBpcyBldmVudHVhbGx5IGNvbnNpc3RlbnQsIHNvIGl0IGNhbiByZXR1cm5cbiAgLy8gdGhlIG1hcmtlciBmcm9tIGJlZm9yZSBpdDogdGhlIHdyaXRlciB0cmFja3Mgd2hhdCB0aGUgd3JpdGUgcmV0dXJuZWQuXG4gIGl0KFwicmV0dXJucyB0aGUgcm93IGFzIHRoZSB3cml0ZSBsZWZ0IGl0XCIsIGFzeW5jICgpID0+IHtcbiAgICBzZW5kLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBBdHRyaWJ1dGVzOiB7XG4gICAgICAgIHNrOiB7IFM6IFwicG9zdHNcIiB9LFxuICAgICAgICByZXZhbGlkYXRlZEF0OiB7IE46IFwiNTAwMFwiIH0sXG4gICAgICAgIHN0YWxlQXQ6IHsgTjogXCIxMFwiIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGV4cGVjdChhd2FpdCB0YWJsZS53cml0ZShcInBvc3RzXCIsIDUwMDAsIHVuZGVmaW5lZCkpLnRvRXF1YWwoe1xuICAgICAgcmV2YWxpZGF0ZWRBdDogNTAwMCxcbiAgICAgIHN0YWxlQXQ6IDEwLFxuICAgICAgZXhwaXJlZEF0OiB1bmRlZmluZWQsXG4gICAgfSk7XG4gICAgc2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe30pO1xuICAgIGV4cGVjdChhd2FpdCB0YWJsZS53cml0ZShcInBvc3RzXCIsIDYwMDAsIHVuZGVmaW5lZCkpLnRvQmVVbmRlZmluZWQoKTtcbiAgfSk7XG5cbiAgaXQoXCJhc2tzIGFnYWluIGZvciB1bnByb2Nlc3NlZCBrZXlzLCBhbmQgZ2l2ZXMgdXAgYWZ0ZXIgdGhyZWUgdHJpZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHVucHJvY2Vzc2VkID0ge1xuICAgICAgVW5wcm9jZXNzZWRLZXlzOiB7XG4gICAgICAgIHRibDogeyBLZXlzOiBbeyBwazogeyBTOiBcImJ1aWxkXCIgfSwgc2s6IHsgUzogXCJhXCIgfSB9XSB9LFxuICAgICAgfSxcbiAgICB9O1xuICAgIHNlbmQubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHVucHJvY2Vzc2VkKS5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgUmVzcG9uc2VzOiB7IHRibDogW3sgc2s6IHsgUzogXCJhXCIgfSwgc3RhbGVBdDogeyBOOiBcIjNcIiB9IH1dIH0sXG4gICAgfSk7XG4gICAgZXhwZWN0KChhd2FpdCB0YWJsZS5yZWFkKFtcImFcIl0pKS5nZXQoXCJhXCIpPy5zdGFsZUF0KS50b0JlKDMpO1xuXG4gICAgc2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZSh1bnByb2Nlc3NlZCk7XG4gICAgYXdhaXQgZXhwZWN0KHRhYmxlLnJlYWQoW1wiYVwiXSkpLnJlamVjdHMudG9UaHJvdygvdW5yZWFkIGFmdGVyIHJldHJ5aW5nLyk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwiUmV2YWxpZGF0aW9uTG9nXCIsICgpID0+IHtcbiAgY29uc3Qgc2VuZCA9IGplc3QuZm4oKTtcbiAgbGV0IGxvZzogUmV2YWxpZGF0aW9uTG9nO1xuXG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIHNlbmQubW9ja1Jlc2V0KCk7XG4gICAgKER5bmFtb0RCQ2xpZW50IGFzIGplc3QuTW9jaykubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+ICh7IHNlbmQgfSkpO1xuICAgIGxvZyA9IG5ldyBSZXZhbGlkYXRpb25Mb2cobmV3IER5bmFtb0RCQ2xpZW50KHt9KSwgXCJ0YmxcIiwgXCJidWlsZFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJwdXRzIG9uZSByb3cgcGVyIHJldmFsaWRhdGlvbiB1bmRlciB0aGUgYnVpbGQncyBsb2csIHdpdGggYSBUVExcIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgIGNvbnN0IGF0ID0gMV83MjdfMDAwXzAwMF8xMjM7XG4gICAgYXdhaXQgbG9nLnB1dChcInVzZXIjNDJcIiwgYXQsIHsgc3RhbGVBdDogNSwgZXhwaXJlZEF0OiA2IH0pO1xuICAgIGV4cGVjdChjb21tYW5kSW5wdXQoc2VuZC5tb2NrLmNhbGxzWzBdWzBdLCBQdXRJdGVtQ29tbWFuZCkpLnRvRXF1YWwoe1xuICAgICAgVGFibGVOYW1lOiBcInRibFwiLFxuICAgICAgSXRlbToge1xuICAgICAgICBwazogeyBTOiBcImJ1aWxkI2xvZ1wiIH0sXG4gICAgICAgIHNrOiB7IFM6IFwiMDAxNzI3MDAwMDAwMTIzI3VzZXIjNDJcIiB9LFxuICAgICAgICB0dGw6IHsgTjogU3RyaW5nKE1hdGguY2VpbCgoYXQgKyBSRVZBTElEQVRJT05fTE9HX1RUTF9NUykgLyAxMDAwKSkgfSxcbiAgICAgICAgc3RhbGVBdDogeyBOOiBcIjVcIiB9LFxuICAgICAgICBleHBpcmVkQXQ6IHsgTjogXCI2XCIgfSxcbiAgICAgIH0sXG4gICAgICBDb25kaXRpb25FeHByZXNzaW9uOiBcImF0dHJpYnV0ZV9ub3RfZXhpc3RzKHNrKVwiLFxuICAgIH0pO1xuICB9KTtcblxuICBpdChcIm1vdmVzIGEgcm93IHRvIHRoZSBuZXh0IG1pbGxpc2Vjb25kIHJhdGhlciB0aGFuIG92ZXJ3cml0ZSBhbm90aGVyIHJldmFsaWRhdGlvblwiLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gYHVwZGF0ZVRhZygneCcpYCBhbmQgYHJldmFsaWRhdGVUYWcoJ3gnLCAnbWF4JylgIGluIG9uZSBtaWxsaXNlY29uZC5cbiAgICBjb25zdCB0YWtlbiA9IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKFwidGFrZW5cIiksIHtcbiAgICAgIG5hbWU6IFwiQ29uZGl0aW9uYWxDaGVja0ZhaWxlZEV4Y2VwdGlvblwiLFxuICAgIH0pO1xuICAgIHNlbmQubW9ja1JlamVjdGVkVmFsdWVPbmNlKHRha2VuKS5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe30pO1xuICAgIGF3YWl0IGxvZy5wdXQoXCJ4XCIsIDEwMDAuNSwgeyByZXZhbGlkYXRlZEF0OiA1IH0pO1xuICAgIGV4cGVjdChcbiAgICAgIHNlbmQubW9jay5jYWxscy5tYXAoXG4gICAgICAgIChbY29tbWFuZF0pID0+IGNvbW1hbmRJbnB1dChjb21tYW5kLCBQdXRJdGVtQ29tbWFuZCkuSXRlbS5zay5TLFxuICAgICAgKSxcbiAgICApLnRvRXF1YWwoW1wiMDAwMDAwMDAwMDAxMDAwI3hcIiwgXCIwMDAwMDAwMDAwMDEwMDEjeFwiXSk7XG4gIH0pO1xuXG4gIGl0KFwiZ2l2ZXMgdXAgYWZ0ZXIgYSBib3VuZGVkIG51bWJlciBvZiBjb2xsaXNpb25zLCBhbmQgb24gb3RoZXIgZXJyb3JzIGF0IG9uY2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHRha2VuID0gT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoXCJ0YWtlblwiKSwge1xuICAgICAgbmFtZTogXCJDb25kaXRpb25hbENoZWNrRmFpbGVkRXhjZXB0aW9uXCIsXG4gICAgfSk7XG4gICAgc2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZSh0YWtlbik7XG4gICAgYXdhaXQgZXhwZWN0KGxvZy5wdXQoXCJ4XCIsIDEwMDAsIHt9KSkucmVqZWN0cy50b0JlKHRha2VuKTtcbiAgICBleHBlY3Qoc2VuZCkudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDUpO1xuXG4gICAgc2VuZC5tb2NrUmVzZXQoKTtcbiAgICBjb25zdCB0aHJvdHRsZWQgPSBuZXcgRXJyb3IoXCJ0aHJvdHRsZWRcIik7XG4gICAgc2VuZC5tb2NrUmVqZWN0ZWRWYWx1ZSh0aHJvdHRsZWQpO1xuICAgIGF3YWl0IGV4cGVjdChsb2cucHV0KFwieFwiLCAxMDAwLCB7fSkpLnJlamVjdHMudG9CZSh0aHJvdHRsZWQpO1xuICAgIGV4cGVjdChzZW5kKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMSk7XG4gIH0pO1xuXG4gIGl0KFwicXVlcmllcyBmcm9tIGEgemVyby1wYWRkZWQgY3Vyc29yIGFuZCBwYXJzZXMgdGhlIHRhZyBhZnRlciBpdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgc2VuZFxuICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICAgIEl0ZW1zOiBbXG4gICAgICAgICAgeyBzazogeyBTOiBcIjAwMDAwMDAwMDAwMTAwMCNhXCIgfSwgcmV2YWxpZGF0ZWRBdDogeyBOOiBcIjdcIiB9IH0sXG4gICAgICAgICAgeyBzazogeyBTOiBcIm5vdCBhIGxvZyByb3dcIiB9IH0sXG4gICAgICAgIF0sXG4gICAgICAgIExhc3RFdmFsdWF0ZWRLZXk6IHsgcGs6IHsgUzogXCJidWlsZCNsb2dcIiB9LCBzazogeyBTOiBcInhcIiB9IH0sXG4gICAgICB9KVxuICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICAgIEl0ZW1zOiBbeyBzazogeyBTOiBcIjAwMDAwMDAwMDAwMjAwMCN1c2VyIzQyXCIgfSwgc3RhbGVBdDogeyBOOiBcIjhcIiB9IH1dLFxuICAgICAgfSk7XG4gICAgY29uc3QgeyByb3dzLCB0cnVuY2F0ZWQgfSA9IGF3YWl0IGxvZy5xdWVyeSg5OTkuNSk7XG5cbiAgICBjb25zdCBmaXJzdCA9IGNvbW1hbmRJbnB1dChzZW5kLm1vY2suY2FsbHNbMF1bMF0sIFF1ZXJ5Q29tbWFuZCk7XG4gICAgZXhwZWN0KGZpcnN0KS50b01hdGNoT2JqZWN0KHtcbiAgICAgIFRhYmxlTmFtZTogXCJ0YmxcIixcbiAgICAgIEtleUNvbmRpdGlvbkV4cHJlc3Npb246IFwicGsgPSA6cGsgQU5EIHNrID49IDpzaW5jZVwiLFxuICAgICAgRXhwcmVzc2lvbkF0dHJpYnV0ZVZhbHVlczoge1xuICAgICAgICBcIjpwa1wiOiB7IFM6IFwiYnVpbGQjbG9nXCIgfSxcbiAgICAgICAgXCI6c2luY2VcIjogeyBTOiBcIjAwMDAwMDAwMDAwMDk5OVwiIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGV4cGVjdChcbiAgICAgIGNvbW1hbmRJbnB1dChzZW5kLm1vY2suY2FsbHNbMV1bMF0sIFF1ZXJ5Q29tbWFuZCkuRXhjbHVzaXZlU3RhcnRLZXksXG4gICAgKS50b0VxdWFsKHsgcGs6IHsgUzogXCJidWlsZCNsb2dcIiB9LCBzazogeyBTOiBcInhcIiB9IH0pO1xuICAgIGV4cGVjdCh0cnVuY2F0ZWQpLnRvQmUoZmFsc2UpO1xuICAgIGV4cGVjdChyb3dzKS50b0VxdWFsKFtcbiAgICAgIHtcbiAgICAgICAgc2s6IFwiMDAwMDAwMDAwMDAxMDAwI2FcIixcbiAgICAgICAgYXQ6IDEwMDAsXG4gICAgICAgIHRhZzogXCJhXCIsXG4gICAgICAgIG1hcmtlcjogeyByZXZhbGlkYXRlZEF0OiA3LCBzdGFsZUF0OiB1bmRlZmluZWQsIGV4cGlyZWRBdDogdW5kZWZpbmVkIH0sXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBzazogXCIwMDAwMDAwMDAwMDIwMDAjdXNlciM0MlwiLFxuICAgICAgICBhdDogMjAwMCxcbiAgICAgICAgdGFnOiBcInVzZXIjNDJcIixcbiAgICAgICAgbWFya2VyOiB7IHJldmFsaWRhdGVkQXQ6IHVuZGVmaW5lZCwgc3RhbGVBdDogOCwgZXhwaXJlZEF0OiB1bmRlZmluZWQgfSxcbiAgICAgIH0sXG4gICAgXSk7XG4gIH0pO1xuXG4gIGl0KFwic3RvcHMgYWZ0ZXIgaXRzIHBhZ2UgYm91bmQgYW5kIHNheXMgc29cIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgSXRlbXM6IFtdLFxuICAgICAgTGFzdEV2YWx1YXRlZEtleTogeyBwazogeyBTOiBcImJ1aWxkI2xvZ1wiIH0sIHNrOiB7IFM6IFwieFwiIH0gfSxcbiAgICB9KTtcbiAgICBleHBlY3QoKGF3YWl0IGxvZy5xdWVyeSgwKSkudHJ1bmNhdGVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChzZW5kKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoUkVWQUxJREFUSU9OX0xPR19NQVhfUEFHRVMpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcIkNhY2hlQnVja2V0XCIsICgpID0+IHtcbiAgY29uc3Qgc2VuZCA9IGplc3QuZm4oKTtcbiAgbGV0IGJ1Y2tldDogQ2FjaGVCdWNrZXQ7XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgc2VuZC5tb2NrUmVzZXQoKTtcbiAgICAoUzNDbGllbnQgYXMgamVzdC5Nb2NrKS5tb2NrSW1wbGVtZW50YXRpb24oKCkgPT4gKHsgc2VuZCB9KSk7XG4gICAgYnVja2V0ID0gbmV3IENhY2hlQnVja2V0KG5ldyBTM0NsaWVudCh7fSksIFwiYmt0XCIpO1xuICB9KTtcblxuICBpdChcInJlYWRzIGFuIG9iamVjdCBhcyB0ZXh0XCIsIGFzeW5jICgpID0+IHtcbiAgICBzZW5kLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgIEJvZHk6IHsgdHJhbnNmb3JtVG9TdHJpbmc6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShcInt9XCIpIH0sXG4gICAgICBDb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgfSk7XG4gICAgZXhwZWN0KGF3YWl0IGJ1Y2tldC5nZXQoXCJrXCIpKS50b0JlKFwie31cIik7XG4gICAgZXhwZWN0KGNvbW1hbmRJbnB1dChzZW5kLm1vY2suY2FsbHNbMF1bMF0sIEdldE9iamVjdENvbW1hbmQpKS50b0VxdWFsKHtcbiAgICAgIEJ1Y2tldDogXCJia3RcIixcbiAgICAgIEtleTogXCJrXCIsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KFwiYW5zd2VycyBhIG1pc3Npbmcgb2JqZWN0IG9yIGJvZHkgd2l0aCB1bmRlZmluZWQsIGFuZCB0aHJvd3MgdGhlIHJlc3RcIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQubW9ja1JlamVjdGVkVmFsdWVPbmNlKFxuICAgICAgbmV3IE5vU3VjaEtleSh7IG1lc3NhZ2U6IFwibWlzc2luZ1wiLCAkbWV0YWRhdGE6IHt9IH0pLFxuICAgICk7XG4gICAgZXhwZWN0KGF3YWl0IGJ1Y2tldC5nZXQoXCJrXCIpKS50b0JlVW5kZWZpbmVkKCk7XG4gICAgc2VuZC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBCb2R5OiBudWxsIH0pO1xuICAgIGV4cGVjdChhd2FpdCBidWNrZXQuZ2V0KFwia1wiKSkudG9CZVVuZGVmaW5lZCgpO1xuICAgIHNlbmQubW9ja1JlamVjdGVkVmFsdWVPbmNlKG5ldyBFcnJvcihcIkFjY2Vzc0RlbmllZFwiKSk7XG4gICAgYXdhaXQgZXhwZWN0KGJ1Y2tldC5nZXQoXCJrXCIpKS5yZWplY3RzLnRvVGhyb3coXCJBY2Nlc3NEZW5pZWRcIik7XG4gIH0pO1xuXG4gIGl0KFwid3JpdGVzIEpTT05cIiwgYXN5bmMgKCkgPT4ge1xuICAgIHNlbmQubW9ja1Jlc29sdmVkVmFsdWUoe30pO1xuICAgIGF3YWl0IGJ1Y2tldC5wdXRKc29uKFwia1wiLCBcInt9XCIpO1xuICAgIGV4cGVjdChjb21tYW5kSW5wdXQoc2VuZC5tb2NrLmNhbGxzWzBdWzBdLCBQdXRPYmplY3RDb21tYW5kKSkudG9FcXVhbCh7XG4gICAgICBCdWNrZXQ6IFwiYmt0XCIsXG4gICAgICBLZXk6IFwia1wiLFxuICAgICAgQm9keTogXCJ7fVwiLFxuICAgICAgQ29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOFwiLFxuICAgIH0pO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZShcIlRyYWNrZWRUYWdNYXJrZXJzXCIsICgpID0+IHtcbiAgaXQoXCJkb2VzIG5vdCBza2lwIGEgcm93IGZvciBhbiB1bnRyYWNrZWQgdGFnIHRoYXQgaXRzIGZpcnN0IHJlYWQgbWlzc2VkXCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBUaGUgd3JpdGVyIHB1dHMgdGhlIGxvZyByb3cgYW5kIHRoZSBtYXJrZXIgYXQgdGhlIHNhbWUgdGltZSwgYW5kIHRoZVxuICAgIC8vIG1hcmtlciByZWFkIGlzIGV2ZW50dWFsbHkgY29uc2lzdGVudDogYHJlZnJlc2hgIGNhbiBzZWUgdGhlIHJvdywgdGhlblxuICAgIC8vIGBlbnN1cmVgIHJlYWQgdGhlIG1hcmtlciBmcm9tIGJlZm9yZSBpdC4gTWFya2VkIGFwcGxpZWQgd2hpbGUgdGhlIHRhZ1xuICAgIC8vIHdhcyB1bnRyYWNrZWQsIHRoZSByb3cgd2FzIHNraXBwZWQgYnkgZXZlcnkgcXVlcnkgdGhlIGxvb2tiYWNrIHJldHVybmVkXG4gICAgLy8gaXQgdG8sIGFuZCB0aGUgaW5zdGFuY2Ugc2VydmVkIHRoZSBzdGFsZSBlbnRyeSB1bnRpbCB0aGUgcm9sbGluZyByZS1yZWFkLlxuICAgIGxldCBjbG9jayA9IDFfMDAwXzAwMDtcbiAgICBjb25zdCByZXZhbGlkYXRlZEF0ID0gOTk5XzAwMDtcbiAgICBjb25zdCByb3c6IFJldmFsaWRhdGlvbkxvZ1JvdyA9IHtcbiAgICAgIHNrOiBgJHtTdHJpbmcoY2xvY2spLnBhZFN0YXJ0KDE1LCBcIjBcIil9I3Bvc3RzYCxcbiAgICAgIGF0OiBjbG9jayxcbiAgICAgIHRhZzogXCJwb3N0c1wiLFxuICAgICAgbWFya2VyOiB7IHJldmFsaWRhdGVkQXQgfSxcbiAgICB9O1xuICAgIGNvbnN0IHF1ZXJ5ID0gamVzdC5mbihhc3luYyAoc2luY2U6IG51bWJlcikgPT4gKHtcbiAgICAgIHJvd3M6IFtyb3ddLmZpbHRlcigocikgPT4gci5hdCA+PSBzaW5jZSksXG4gICAgICB0cnVuY2F0ZWQ6IGZhbHNlLFxuICAgIH0pKTtcbiAgICAvLyBBIHJlcGxpY2EgdGhhdCBoYXMgbm90IHNlZW4gdGhlIHdyaXRlIHlldC5cbiAgICBjb25zdCByZWFkID0gamVzdC5mbihhc3luYyAoKSA9PiBuZXcgTWFwPHN0cmluZywgVGFnTWFya2VyPigpKTtcbiAgICBjb25zdCBtYXJrZXJzID0gbmV3IFRyYWNrZWRUYWdNYXJrZXJzKHtcbiAgICAgIG1hcmtlcnM6IHsgcmVhZCB9IGFzIHVua25vd24gYXMgVGFnTWFya2VyVGFibGUsXG4gICAgICBsb2c6IHsgcXVlcnkgfSBhcyB1bmtub3duIGFzIFJldmFsaWRhdGlvbkxvZyxcbiAgICAgIHJlZnJlc2hJbnRlcnZhbE1zOiAxMDAwLFxuICAgICAgY2xvY2s6ICgpID0+IGNsb2NrLFxuICAgICAgcmFuZG9tOiAoKSA9PiAwLFxuICAgIH0pO1xuICAgIC8vIFNvbWV0aGluZyB0cmFja2VkLCBzbyB0aGUgcmVmcmVzaCBxdWVyaWVzIHRoZSBsb2cuXG4gICAgYXdhaXQgbWFya2Vycy5lbnN1cmUoW1wib3RoZXJcIl0pO1xuXG4gICAgY2xvY2sgKz0gMTAwMDtcbiAgICBhd2FpdCBtYXJrZXJzLnJlZnJlc2goKTtcbiAgICBhd2FpdCBtYXJrZXJzLmVuc3VyZShbXCJwb3N0c1wiXSk7XG4gICAgZXhwZWN0KG1hcmtlcnMuZ2V0KFwicG9zdHNcIikpLnRvRXF1YWwoe30pO1xuXG4gICAgY2xvY2sgKz0gMTAwMDtcbiAgICBhd2FpdCBtYXJrZXJzLnJlZnJlc2goKTtcbiAgICBleHBlY3QocXVlcnkpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygyKTtcbiAgICBleHBlY3QobWFya2Vycy5nZXQoXCJwb3N0c1wiKSkudG9FcXVhbCh7IHJldmFsaWRhdGVkQXQgfSk7XG4gICAgLy8gT25seSB0aGUgb25lIHJlYWQgZWFjaCB0YWcncyBmaXJzdCB1c2UgY29zdHMuXG4gICAgZXhwZWN0KHJlYWQpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygyKTtcbiAgfSk7XG59KTtcbiJdfQ==
@@ -0,0 +1,80 @@
1
+ import { NextAdapter } from "next";
2
+ import { FunctionGroupSpec } from "./function-groups";
3
+ import { AdapterManifest } from "../runtime/manifest";
4
+ /**
5
+ * The `onBuildComplete` argument. Derived from the `next` typings rather than
6
+ * restated so a `next` bump surfaces as a compile error here.
7
+ */
8
+ export type BuildCompleteContext = Parameters<NonNullable<NextAdapter["onBuildComplete"]>>[0];
9
+ /**
10
+ * Staging key (repo-root-relative POSIX) → absolute source path on the build
11
+ * machine. The deduped union that replaces the standalone tree.
12
+ */
13
+ export type StagingPlan = ReadonlyMap<string, string>;
14
+ export interface BuildOutputsOptions {
15
+ /**
16
+ * The directory `next build` was invoked from. Defaults to `process.cwd()`,
17
+ * which is the real answer inside `onBuildComplete`; a parameter only so the
18
+ * unit tests can drive the fixtures' synthetic project dirs.
19
+ */
20
+ readonly buildCwd?: string;
21
+ /**
22
+ * Resolved `functionGroups`. Defaults to {@link FUNCTION_GROUPS_ENV_VAR},
23
+ * which is how the constructs get them here: `onBuildComplete` runs inside
24
+ * `next build` and cannot read CDK props.
25
+ *
26
+ * `undefined` means one deployment root holding every route, which is the
27
+ * default and the only thing the Containers types ever do.
28
+ */
29
+ readonly functionGroups?: FunctionGroupSpec[];
30
+ }
31
+ /** One deployment root: the staging plan for it, and where it goes. */
32
+ export interface StagedGroup {
33
+ /**
34
+ * Group name, `default` for the implicit group. Always present — a build with
35
+ * no `functionGroups` produces exactly one {@link StagedGroup} named `default`,
36
+ * so callers never branch on "is this split".
37
+ */
38
+ readonly name: string;
39
+ /**
40
+ * Directory inside `cdk-nextjs-adapter`, POSIX: `app` when not splitting,
41
+ * `groups/<name>` when splitting.
42
+ */
43
+ readonly dirName: string;
44
+ readonly staging: StagingPlan;
45
+ }
46
+ export interface BuildAdapterManifestResult {
47
+ readonly manifest: AdapterManifest;
48
+ /** One entry per deployment root to stage. Length 1 unless splitting. */
49
+ readonly groups: StagedGroup[];
50
+ }
51
+ /** A staged deployment root on disk. */
52
+ export interface StagedGroupResult {
53
+ readonly name: string;
54
+ /** Absolute path to the deployment root. */
55
+ readonly path: string;
56
+ readonly fileCount: number;
57
+ }
58
+ export interface WriteBuildOutputsResult extends BuildAdapterManifestResult {
59
+ /** Absolute path to `<distDir>/cdk-nextjs-adapter`. */
60
+ readonly adapterDir: string;
61
+ /** Absolute path to the written manifest. */
62
+ readonly manifestPath: string;
63
+ /** One per deployment root, in the order they were staged. */
64
+ readonly stagedGroups: StagedGroupResult[];
65
+ }
66
+ /**
67
+ * Build the manifest and staging plan, stage the files, and write the manifest.
68
+ * Called from `onBuildComplete`, which is the only place that holds the build
69
+ * outputs.
70
+ */
71
+ export declare function writeBuildOutputs(ctx: BuildCompleteContext, options?: BuildOutputsOptions): Promise<WriteBuildOutputsResult>;
72
+ /**
73
+ * The pure half of {@link writeBuildOutputs}: everything derived from the build
74
+ * outputs, with no writes. Split out so it can be unit tested against committed
75
+ * `onBuildComplete` fixtures.
76
+ *
77
+ * Throws on any non-Node output and on any staging key two outputs map to
78
+ * different content.
79
+ */
80
+ export declare function buildAdapterManifest(ctx: BuildCompleteContext, options?: BuildOutputsOptions): BuildAdapterManifestResult;