cdk-nextjs 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/.jsii +2467 -2714
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1725 -1909
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +687 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1548 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +852 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +861 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +13 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/post-deploy.lambda.js +3 -2
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  88. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  92. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  93. package/lib/lambdas/post-deploy/prune-s3.d.ts +19 -3
  94. package/lib/lambdas/post-deploy/prune-s3.js +54 -15
  95. package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
  96. package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  103. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  104. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  105. package/lib/nextjs-api.d.ts +107 -18
  106. package/lib/nextjs-api.js +349 -39
  107. package/lib/nextjs-api.test.js +582 -1
  108. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  109. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  110. package/lib/nextjs-build/nextjs-build.js +684 -327
  111. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  112. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  113. package/lib/nextjs-build/patch-fetch.js +1 -1
  114. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  115. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  116. package/lib/nextjs-cache.d.ts +82 -4
  117. package/lib/nextjs-cache.js +186 -10
  118. package/lib/nextjs-cache.test.js +176 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  120. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  121. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  122. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  123. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  124. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  125. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  126. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  127. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  128. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  129. package/lib/nextjs-distribution.d.ts +194 -23
  130. package/lib/nextjs-distribution.js +535 -62
  131. package/lib/nextjs-distribution.test.d.ts +1 -0
  132. package/lib/nextjs-distribution.test.js +697 -0
  133. package/lib/nextjs-post-deploy.d.ts +23 -3
  134. package/lib/nextjs-post-deploy.js +14 -10
  135. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  136. package/lib/nextjs-post-deploy.test.js +34 -0
  137. package/lib/nextjs-static-assets.d.ts +23 -4
  138. package/lib/nextjs-static-assets.js +29 -6
  139. package/lib/nextjs-static-assets.test.js +20 -1
  140. package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
  141. package/lib/root-constructs/nextjs-base-construct.js +144 -34
  142. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  143. package/lib/root-constructs/nextjs-global-containers.js +20 -70
  144. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  145. package/lib/root-constructs/nextjs-global-functions.js +52 -69
  146. package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
  147. package/lib/root-constructs/nextjs-regional-containers.js +17 -15
  148. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  149. package/lib/root-constructs/nextjs-regional-functions.js +8 -25
  150. package/lib/runtime/api-gateway-path.d.ts +34 -0
  151. package/lib/runtime/api-gateway-path.js +71 -0
  152. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  153. package/lib/runtime/api-gateway-path.test.js +65 -0
  154. package/lib/runtime/case-redirect.d.ts +22 -0
  155. package/lib/runtime/case-redirect.js +63 -0
  156. package/lib/runtime/case-redirect.test.d.ts +1 -0
  157. package/lib/runtime/case-redirect.test.js +32 -0
  158. package/lib/runtime/core.d.ts +234 -0
  159. package/lib/runtime/core.js +1213 -0
  160. package/lib/runtime/core.test.d.ts +1 -0
  161. package/lib/runtime/core.test.js +1678 -0
  162. package/lib/runtime/deployment-root.d.ts +13 -0
  163. package/lib/runtime/deployment-root.js +29 -0
  164. package/lib/runtime/dispatch.d.ts +331 -0
  165. package/lib/runtime/dispatch.js +751 -0
  166. package/lib/runtime/dispatch.test.d.ts +1 -0
  167. package/lib/runtime/dispatch.test.js +853 -0
  168. package/lib/runtime/entrypoints.d.ts +57 -0
  169. package/lib/runtime/entrypoints.js +115 -0
  170. package/lib/runtime/http/abort-signal.d.ts +6 -0
  171. package/lib/runtime/http/abort-signal.js +19 -0
  172. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  173. package/lib/runtime/http/abort-signal.test.js +49 -0
  174. package/lib/runtime/http/node-server.d.ts +38 -0
  175. package/lib/runtime/http/node-server.js +99 -0
  176. package/lib/runtime/http/node-server.test.d.ts +1 -0
  177. package/lib/runtime/http/node-server.test.js +96 -0
  178. package/lib/runtime/http/node-sink.d.ts +16 -0
  179. package/lib/runtime/http/node-sink.js +48 -0
  180. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  181. package/lib/runtime/http/node-sink.test.js +66 -0
  182. package/lib/runtime/http/request.d.ts +62 -0
  183. package/lib/runtime/http/request.js +134 -0
  184. package/lib/runtime/http/request.test.d.ts +1 -0
  185. package/lib/runtime/http/request.test.js +103 -0
  186. package/lib/runtime/http/response.d.ts +77 -0
  187. package/lib/runtime/http/response.js +229 -0
  188. package/lib/runtime/http/response.test.d.ts +1 -0
  189. package/lib/runtime/http/response.test.js +178 -0
  190. package/lib/runtime/http/sink.d.ts +73 -0
  191. package/lib/runtime/http/sink.js +188 -0
  192. package/lib/runtime/http/sink.test.d.ts +1 -0
  193. package/lib/runtime/http/sink.test.js +257 -0
  194. package/lib/runtime/image-utils.d.ts +78 -0
  195. package/lib/runtime/image-utils.js +129 -0
  196. package/lib/runtime/image-utils.test.d.ts +1 -0
  197. package/lib/runtime/image-utils.test.js +237 -0
  198. package/lib/runtime/image.d.ts +76 -0
  199. package/lib/runtime/image.js +296 -0
  200. package/lib/runtime/image.test.d.ts +1 -0
  201. package/lib/runtime/image.test.js +405 -0
  202. package/lib/runtime/lambda-event.d.ts +4 -0
  203. package/lib/runtime/lambda-event.js +113 -0
  204. package/lib/runtime/lambda-event.test.d.ts +1 -0
  205. package/lib/runtime/lambda-event.test.js +119 -0
  206. package/lib/runtime/lambda.mjs +41595 -0
  207. package/lib/runtime/load-module.d.ts +8 -0
  208. package/lib/runtime/load-module.js +35 -0
  209. package/lib/runtime/manifest.d.ts +215 -0
  210. package/lib/runtime/manifest.js +118 -0
  211. package/lib/runtime/middleware.d.ts +43 -0
  212. package/lib/runtime/middleware.js +113 -0
  213. package/lib/runtime/middleware.test.d.ts +1 -0
  214. package/lib/runtime/middleware.test.js +259 -0
  215. package/lib/runtime/next-modules.d.ts +55 -0
  216. package/lib/runtime/next-modules.js +124 -0
  217. package/lib/runtime/next-modules.test.d.ts +1 -0
  218. package/lib/runtime/next-modules.test.js +34 -0
  219. package/lib/runtime/public-files.d.ts +32 -0
  220. package/lib/runtime/public-files.js +117 -0
  221. package/lib/runtime/public-files.test.d.ts +1 -0
  222. package/lib/runtime/public-files.test.js +97 -0
  223. package/lib/runtime/server.mjs +41588 -0
  224. package/lib/runtime/static-files.d.ts +50 -0
  225. package/lib/runtime/static-files.js +266 -0
  226. package/lib/runtime/static-files.test.d.ts +1 -0
  227. package/lib/runtime/static-files.test.js +118 -0
  228. package/lib/runtime/util.d.ts +28 -0
  229. package/lib/runtime/util.js +79 -0
  230. package/lib/utils/base-path.d.ts +123 -11
  231. package/lib/utils/base-path.js +276 -39
  232. package/lib/utils/base-path.test.js +275 -50
  233. package/lib/utils/get-architecture.d.ts +7 -8
  234. package/lib/utils/get-architecture.js +12 -13
  235. package/lib/utils/zip-directory.d.ts +14 -0
  236. package/lib/utils/zip-directory.js +121 -0
  237. package/lib/utils/zip-directory.test.d.ts +1 -0
  238. package/lib/utils/zip-directory.test.js +99 -0
  239. package/package.json +22 -3
  240. package/scripts/capture-adapter-fixture.mjs +325 -0
  241. package/scripts/e2e-deploy.sh +398 -0
  242. package/scripts/e2e-harness/README.md +707 -0
  243. package/scripts/e2e-harness/app.js +370 -0
  244. package/scripts/e2e-harness/common.sh +249 -0
  245. package/scripts/e2e-harness/screen.mjs +302 -0
  246. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  247. package/scripts/e2e-harness/type-filters.mjs +47 -0
  248. package/scripts/e2e-logs.sh +75 -0
  249. package/scripts/e2e-offline.sh +91 -0
  250. package/scripts/e2e-sweep.sh +370 -0
  251. package/scripts/e2e-warm.sh +114 -0
  252. package/scripts/zero-config-build.mjs +418 -0
  253. package/docs/1k-concurrent-users-executions.png +0 -0
  254. package/docs/plans/adapter-runtime-release.md +0 -362
  255. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  256. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  257. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  258. package/lib/image-optimization/handler-utils.d.ts +0 -34
  259. package/lib/image-optimization/handler-utils.js +0 -83
  260. package/lib/image-optimization/handler-utils.test.js +0 -178
  261. package/lib/nextjs-build/functions.Dockerfile +0 -31
  262. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  263. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  264. package/lib/utils/experimental-flags.d.ts +0 -24
  265. package/lib/utils/experimental-flags.js +0 -30
  266. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.pruneS3 = pruneS3;
7
+ exports.processBatch = processBatch;
7
8
  // eslint-disable-next-line import/no-extraneous-dependencies
8
9
  const client_s3_1 = require("@aws-sdk/client-s3");
9
10
  // eslint-disable-next-line import/no-extraneous-dependencies
@@ -13,12 +14,43 @@ const s3Client = new client_s3_1.S3Client();
13
14
  // Maximum number of concurrent operations
14
15
  const MAX_CONCURRENT_OPERATIONS = 50;
15
16
  /**
16
- * Given `bucketName`, `currentBuildId`, and `msTtl`, list all objects
17
- * in the bucket and delete any that 1/ do not have a metadata key of "next-build-id"
18
- * and value of `currentBuildId` and 2/ were created more than `msTtl` ago
17
+ * The object metadata key holding the build id, as it comes back from
18
+ * `HeadObject`.
19
+ *
20
+ * `NextjsStaticAssets` hands `BucketDeployment` `metadata: { BUILD_ID }`, and CDK
21
+ * lowercases every user metadata key before putting it on the object
22
+ * (`mapUserMetadata` in `aws-s3-deployment`, and the deployment Lambda lowercases
23
+ * again in `create_metadata_args`). The name this file used to read,
24
+ * "next-build-id", is written by nothing: `objectBuildId` was always `undefined`,
25
+ * so the keep-guard never kept anything and pruning was purely age-based.
26
+ */
27
+ const BUILD_ID_METADATA_KEY = "build_id";
28
+ /**
29
+ * Given `bucketName`, `currentBuildId`, and `msTtl`, list the objects under
30
+ * `keyPrefix`'s `_next/` and delete any that 1/ carry a build id that is not
31
+ * `currentBuildId` and 2/ were created more than `msTtl` ago.
32
+ *
33
+ * An object with no build id at all is kept. It was not uploaded by this
34
+ * construct's `BucketDeployment` — which stamps every object it writes — so
35
+ * nothing here knows whether some other stack is serving it, and deleting a live
36
+ * asset 404s a page while keeping a stale one only costs storage.
19
37
  */
20
38
  async function pruneS3(props) {
21
- const { bucketName, currentBuildId, msTtl } = props;
39
+ const { bucketName, currentBuildId, msTtl, keyPrefix } = props;
40
+ // Surrounding slashes are stripped before use: `NextjsStaticAssets` hands over
41
+ // a bare prefix, but `overrides.customResourceProperties` lets a user set
42
+ // `staticAssetsKeyPrefix` directly, and "base/" or "/base" would build a
43
+ // Prefix ("base//", "/base/") that matches no key at all — pruning would
44
+ // silently become a no-op.
45
+ const bare = (keyPrefix || "").replace(/^\/+/, "").replace(/\/+$/, "");
46
+ // Only `_next/` under the prefix, which is where every build-hashed asset lives
47
+ // and so where old builds pile up. The prefix alone is not a boundary between
48
+ // apps: an app with none owns the bucket root, which holds every other app's
49
+ // `<basePath>/` too, and one at "team" holds another at "team/app". Pruning
50
+ // those deleted the other app's live assets once they were a month old. A
51
+ // `public/` file keeps its key from build to build, so leaving it costs only
52
+ // the storage of one that was removed from the app.
53
+ const prefix = bare ? `${bare}/_next/` : "_next/";
22
54
  const cutoffDate = new Date(Date.now() - msTtl);
23
55
  const objectsToDelete = [];
24
56
  let continuationToken = undefined;
@@ -28,13 +60,18 @@ async function pruneS3(props) {
28
60
  const listObjectsV2Input = {
29
61
  Bucket: bucketName,
30
62
  ContinuationToken: continuationToken,
63
+ Prefix: prefix,
31
64
  };
32
65
  const listResponse = await s3Client.send(new client_s3_1.ListObjectsV2Command(listObjectsV2Input));
33
- if (!listResponse.Contents || listResponse.Contents.length === 0) {
34
- break;
35
- }
66
+ // No `break` on an empty page: `ListObjectsV2` with a `Prefix` can answer with
67
+ // no `Contents` and `IsTruncated: true`, having scanned a window of the bucket
68
+ // that held no matching key. That is exactly the shared-bucket case `keyPrefix`
69
+ // exists for, and breaking here stopped pruning at the first such window, so
70
+ // every older asset past it was never deleted. The loop's own token and page
71
+ // guard below terminate it.
72
+ const contents = listResponse.Contents ?? [];
36
73
  // Filter out objects without keys
37
- const oldObjects = listResponse.Contents.filter((obj) => {
74
+ const oldObjects = contents.filter((obj) => {
38
75
  const lastModified = obj.LastModified || new Date();
39
76
  return obj.Key && lastModified < cutoffDate;
40
77
  });
@@ -48,9 +85,10 @@ async function pruneS3(props) {
48
85
  Bucket: bucketName,
49
86
  Key: object.Key,
50
87
  }));
51
- const objectBuildId = headResponse.Metadata?.["next-build-id"];
52
- // Return the key if it should be deleted
53
- if (objectBuildId !== currentBuildId) {
88
+ const objectBuildId = headResponse.Metadata?.[BUILD_ID_METADATA_KEY];
89
+ // Return the key if it should be deleted. An object with no build id
90
+ // is left alone — see this function's doc comment.
91
+ if (objectBuildId && objectBuildId !== currentBuildId) {
54
92
  return { Key: object.Key };
55
93
  }
56
94
  }
@@ -61,9 +99,10 @@ async function pruneS3(props) {
61
99
  });
62
100
  // Add valid objects to delete list
63
101
  objectsToDelete.push(...checkResults.filter(Boolean));
64
- if (listResponse.NextContinuationToken) {
65
- continuationToken = listResponse.NextContinuationToken;
66
- }
102
+ // Assigned unconditionally: the last page carries no NextContinuationToken,
103
+ // and keeping the previous page's token would re-list that same page until
104
+ // the guard below trips, re-checking every object on it 100 times over.
105
+ continuationToken = listResponse.NextContinuationToken;
67
106
  listObjectsCount++;
68
107
  // assume less than 100K objects (100 * 1K objects per ListObjectsV2Command = 100K)
69
108
  } while (continuationToken && listObjectsCount <= 100);
@@ -103,4 +142,4 @@ async function processBatch(items, batchSize, processFn) {
103
142
  }
104
143
  return results;
105
144
  }
106
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJ1bmUtczMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhcy9wb3N0LWRlcGxveS9wcnVuZS1zMy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQStCQSwwQkEyR0M7QUExSUQsNkRBQTZEO0FBQzdELGtEQU00QjtBQUM1Qiw2REFBNkQ7QUFDN0Qsa0RBQTZCO0FBRTdCLE1BQU0sS0FBSyxHQUFHLElBQUEsZUFBUSxFQUFDLGlDQUFpQyxDQUFDLENBQUM7QUFFMUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxvQkFBUSxFQUFFLENBQUM7QUFDaEMsMENBQTBDO0FBQzFDLE1BQU0seUJBQXlCLEdBQUcsRUFBRSxDQUFDO0FBV3JDOzs7O0dBSUc7QUFDSSxLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQW1CO0lBQy9DLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxHQUFHLEtBQUssQ0FBQztJQUVwRCxNQUFNLFVBQVUsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDaEQsTUFBTSxlQUFlLEdBQXNCLEVBQUUsQ0FBQztJQUU5QyxJQUFJLGlCQUFpQixHQUF1QixTQUFTLENBQUM7SUFDdEQsSUFBSSxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7SUFFekIsR0FBRyxDQUFDO1FBQ0YsNkJBQTZCO1FBQzdCLE1BQU0sa0JBQWtCLEdBQThCO1lBQ3BELE1BQU0sRUFBRSxVQUFVO1lBQ2xCLGlCQUFpQixFQUFFLGlCQUFpQjtTQUNyQyxDQUFDO1FBQ0YsTUFBTSxZQUFZLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUN0QyxJQUFJLGdDQUFvQixDQUFDLGtCQUFrQixDQUFDLENBQzdDLENBQUM7UUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsSUFBSSxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNqRSxNQUFNO1FBQ1IsQ0FBQztRQUVELGtDQUFrQztRQUNsQyxNQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQ3RELE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQyxZQUFZLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNwRCxPQUFPLEdBQUcsQ0FBQyxHQUFHLElBQUksWUFBWSxHQUFHLFVBQVUsQ0FBQztRQUM5QyxDQUFDLENBQUMsQ0FBQztRQUNILEtBQUssQ0FDSCx1REFBdUQsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQ3RGLENBQUM7UUFFRiwwREFBMEQ7UUFDMUQsTUFBTSxZQUFZLEdBQUcsTUFBTSxZQUFZLENBQ3JDLFVBQVUsRUFDVix5QkFBeUIsRUFDekIsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHO2dCQUFFLE9BQU8sSUFBSSxDQUFDO1lBRTdCLElBQUksQ0FBQztnQkFDSCxNQUFNLFlBQVksR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLENBQ3RDLElBQUksNkJBQWlCLENBQUM7b0JBQ3BCLE1BQU0sRUFBRSxVQUFVO29CQUNsQixHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUc7aUJBQ2hCLENBQUMsQ0FDSCxDQUFDO2dCQUVGLE1BQU0sYUFBYSxHQUFHLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFFL0QseUNBQXlDO2dCQUN6QyxJQUFJLGFBQWEsS0FBSyxjQUFjLEVBQUUsQ0FBQztvQkFDckMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzdCLENBQUM7WUFDSCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHlCQUF5QixNQUFNLENBQUMsR0FBRyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDL0QsQ0FBQztZQUVELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQyxDQUNGLENBQUM7UUFFRixtQ0FBbUM7UUFDbkMsZUFBZSxDQUFDLElBQUksQ0FDbEIsR0FBSSxZQUFZLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBdUIsQ0FDdkQsQ0FBQztRQUVGLElBQUksWUFBWSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDdkMsaUJBQWlCLEdBQUcsWUFBWSxDQUFDLHFCQUFxQixDQUFDO1FBQ3pELENBQUM7UUFDRCxnQkFBZ0IsRUFBRSxDQUFDO1FBQ25CLG1GQUFtRjtJQUNyRixDQUFDLFFBQVEsaUJBQWlCLElBQUksZ0JBQWdCLElBQUksR0FBRyxFQUFFO0lBRXZELHNGQUFzRjtJQUN0RixJQUFJLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDL0IsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDO1FBRXpCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxlQUFlLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUN0RCxNQUFNLEtBQUssR0FBRyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDakQsYUFBYSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QixDQUFDO1FBRUQsTUFBTSxZQUFZLENBQ2hCLGFBQWEsRUFDYixDQUFDLEVBQUUsNkNBQTZDO1FBQ2hELEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUNkLElBQUksQ0FBQztnQkFDSCxLQUFLLENBQ0gscUJBQXFCLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsU0FBUyxVQUFVLEVBQUUsQ0FDbEUsQ0FBQztnQkFDRixNQUFNLFFBQVEsQ0FBQyxJQUFJLENBQ2pCLElBQUksZ0NBQW9CLENBQUM7b0JBQ3ZCLE1BQU0sRUFBRSxVQUFVO29CQUNsQixNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFO2lCQUMzQixDQUFDLENBQ0gsQ0FBQztnQkFDRixLQUFLLENBQUMsV0FBVyxLQUFLLENBQUMsTUFBTSxpQkFBaUIsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUM5RCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHlCQUF5QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2xELENBQUM7UUFDSCxDQUFDLENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQ0gsNkJBQTZCLGVBQWUsQ0FBQyxNQUFNLGlCQUFpQixVQUFVLEVBQUUsQ0FDakYsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILEtBQUssVUFBVSxZQUFZLENBQ3pCLEtBQVUsRUFDVixTQUFpQixFQUNqQixTQUFrQztJQUVsQyxNQUFNLE9BQU8sR0FBUSxFQUFFLENBQUM7SUFFeEIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2pELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsQ0FBQztRQUM1QyxNQUFNLFlBQVksR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQzdELE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB7XG4gIFMzQ2xpZW50LFxuICBMaXN0T2JqZWN0c1YyQ29tbWFuZCxcbiAgRGVsZXRlT2JqZWN0c0NvbW1hbmQsXG4gIEhlYWRPYmplY3RDb21tYW5kLFxuICBMaXN0T2JqZWN0c1YyQ29tbWFuZElucHV0LFxufSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXMzXCI7XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXG5pbXBvcnQgZ2V0RGVidWcgZnJvbSBcImRlYnVnXCI7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoXCJjZGstbmV4dGpzOnBvc3QtZGVwbG95OnBydW5lLXMzXCIpO1xuXG5jb25zdCBzM0NsaWVudCA9IG5ldyBTM0NsaWVudCgpO1xuLy8gTWF4aW11bSBudW1iZXIgb2YgY29uY3VycmVudCBvcGVyYXRpb25zXG5jb25zdCBNQVhfQ09OQ1VSUkVOVF9PUEVSQVRJT05TID0gNTA7XG5cbmludGVyZmFjZSBQcnVuZVMzUHJvcHMge1xuICBidWNrZXROYW1lOiBzdHJpbmc7XG4gIGN1cnJlbnRCdWlsZElkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaW1lIHRvIGxpdmUgaW4gbWlsbGlzZWNvbmRzLlxuICAgKi9cbiAgbXNUdGw6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBHaXZlbiBgYnVja2V0TmFtZWAsIGBjdXJyZW50QnVpbGRJZGAsIGFuZCBgbXNUdGxgLCBsaXN0IGFsbCBvYmplY3RzXG4gKiBpbiB0aGUgYnVja2V0IGFuZCBkZWxldGUgYW55IHRoYXQgMS8gZG8gbm90IGhhdmUgYSBtZXRhZGF0YSBrZXkgb2YgXCJuZXh0LWJ1aWxkLWlkXCJcbiAqIGFuZCB2YWx1ZSBvZiBgY3VycmVudEJ1aWxkSWRgIGFuZCAyLyB3ZXJlIGNyZWF0ZWQgbW9yZSB0aGFuIGBtc1R0bGAgYWdvXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwcnVuZVMzKHByb3BzOiBQcnVuZVMzUHJvcHMpIHtcbiAgY29uc3QgeyBidWNrZXROYW1lLCBjdXJyZW50QnVpbGRJZCwgbXNUdGwgfSA9IHByb3BzO1xuXG4gIGNvbnN0IGN1dG9mZkRhdGUgPSBuZXcgRGF0ZShEYXRlLm5vdygpIC0gbXNUdGwpO1xuICBjb25zdCBvYmplY3RzVG9EZWxldGU6IHsgS2V5OiBzdHJpbmcgfVtdID0gW107XG5cbiAgbGV0IGNvbnRpbnVhdGlvblRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIGxldCBsaXN0T2JqZWN0c0NvdW50ID0gMDtcblxuICBkbyB7XG4gICAgLy8gTGlzdCBvYmplY3RzIGluIHRoZSBidWNrZXRcbiAgICBjb25zdCBsaXN0T2JqZWN0c1YySW5wdXQ6IExpc3RPYmplY3RzVjJDb21tYW5kSW5wdXQgPSB7XG4gICAgICBCdWNrZXQ6IGJ1Y2tldE5hbWUsXG4gICAgICBDb250aW51YXRpb25Ub2tlbjogY29udGludWF0aW9uVG9rZW4sXG4gICAgfTtcbiAgICBjb25zdCBsaXN0UmVzcG9uc2UgPSBhd2FpdCBzM0NsaWVudC5zZW5kKFxuICAgICAgbmV3IExpc3RPYmplY3RzVjJDb21tYW5kKGxpc3RPYmplY3RzVjJJbnB1dCksXG4gICAgKTtcblxuICAgIGlmICghbGlzdFJlc3BvbnNlLkNvbnRlbnRzIHx8IGxpc3RSZXNwb25zZS5Db250ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIC8vIEZpbHRlciBvdXQgb2JqZWN0cyB3aXRob3V0IGtleXNcbiAgICBjb25zdCBvbGRPYmplY3RzID0gbGlzdFJlc3BvbnNlLkNvbnRlbnRzLmZpbHRlcigob2JqKSA9PiB7XG4gICAgICBjb25zdCBsYXN0TW9kaWZpZWQgPSBvYmouTGFzdE1vZGlmaWVkIHx8IG5ldyBEYXRlKCk7XG4gICAgICByZXR1cm4gb2JqLktleSAmJiBsYXN0TW9kaWZpZWQgPCBjdXRvZmZEYXRlO1xuICAgIH0pO1xuICAgIGRlYnVnKFxuICAgICAgYENoZWNraW5nIG9sZCBvYmplY3RzIG1ldGFkYXRhIHRvIGRldGVybWluZSBwcnVuaW5nOiAke29sZE9iamVjdHMubWFwKChvKSA9PiBvLktleSl9YCxcbiAgICApO1xuXG4gICAgLy8gUHJvY2VzcyBvYmplY3RzIGluIHBhcmFsbGVsIHdpdGggY29udHJvbGxlZCBjb25jdXJyZW5jeVxuICAgIGNvbnN0IGNoZWNrUmVzdWx0cyA9IGF3YWl0IHByb2Nlc3NCYXRjaChcbiAgICAgIG9sZE9iamVjdHMsXG4gICAgICBNQVhfQ09OQ1VSUkVOVF9PUEVSQVRJT05TLFxuICAgICAgYXN5bmMgKG9iamVjdCkgPT4ge1xuICAgICAgICBpZiAoIW9iamVjdC5LZXkpIHJldHVybiBudWxsO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgaGVhZFJlc3BvbnNlID0gYXdhaXQgczNDbGllbnQuc2VuZChcbiAgICAgICAgICAgIG5ldyBIZWFkT2JqZWN0Q29tbWFuZCh7XG4gICAgICAgICAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgICAgICAgICAgS2V5OiBvYmplY3QuS2V5LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGNvbnN0IG9iamVjdEJ1aWxkSWQgPSBoZWFkUmVzcG9uc2UuTWV0YWRhdGE/LltcIm5leHQtYnVpbGQtaWRcIl07XG5cbiAgICAgICAgICAvLyBSZXR1cm4gdGhlIGtleSBpZiBpdCBzaG91bGQgYmUgZGVsZXRlZFxuICAgICAgICAgIGlmIChvYmplY3RCdWlsZElkICE9PSBjdXJyZW50QnVpbGRJZCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgS2V5OiBvYmplY3QuS2V5IH07XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNoZWNraW5nIG9iamVjdCAke29iamVjdC5LZXl9OmAsIGVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfSxcbiAgICApO1xuXG4gICAgLy8gQWRkIHZhbGlkIG9iamVjdHMgdG8gZGVsZXRlIGxpc3RcbiAgICBvYmplY3RzVG9EZWxldGUucHVzaChcbiAgICAgIC4uLihjaGVja1Jlc3VsdHMuZmlsdGVyKEJvb2xlYW4pIGFzIHsgS2V5OiBzdHJpbmcgfVtdKSxcbiAgICApO1xuXG4gICAgaWYgKGxpc3RSZXNwb25zZS5OZXh0Q29udGludWF0aW9uVG9rZW4pIHtcbiAgICAgIGNvbnRpbnVhdGlvblRva2VuID0gbGlzdFJlc3BvbnNlLk5leHRDb250aW51YXRpb25Ub2tlbjtcbiAgICB9XG4gICAgbGlzdE9iamVjdHNDb3VudCsrO1xuICAgIC8vIGFzc3VtZSBsZXNzIHRoYW4gMTAwSyBvYmplY3RzICgxMDAgKiAxSyBvYmplY3RzIHBlciBMaXN0T2JqZWN0c1YyQ29tbWFuZCA9IDEwMEspXG4gIH0gd2hpbGUgKGNvbnRpbnVhdGlvblRva2VuICYmIGxpc3RPYmplY3RzQ291bnQgPD0gMTAwKTtcblxuICAvLyBEZWxldGUgb2JqZWN0cyBpbiBwYXJhbGxlbCBiYXRjaGVzIChyZXNwZWN0aW5nIFMzJ3MgMTAwMCBvYmplY3RzIHBlciByZXF1ZXN0IGxpbWl0KVxuICBpZiAob2JqZWN0c1RvRGVsZXRlLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBkZWxldGVCYXRjaGVzID0gW107XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG9iamVjdHNUb0RlbGV0ZS5sZW5ndGg7IGkgKz0gMTAwMCkge1xuICAgICAgY29uc3QgYmF0Y2ggPSBvYmplY3RzVG9EZWxldGUuc2xpY2UoaSwgaSArIDEwMDApO1xuICAgICAgZGVsZXRlQmF0Y2hlcy5wdXNoKGJhdGNoKTtcbiAgICB9XG5cbiAgICBhd2FpdCBwcm9jZXNzQmF0Y2goXG4gICAgICBkZWxldGVCYXRjaGVzLFxuICAgICAgNSwgLy8gUHJvY2VzcyB1cCB0byA1IGRlbGV0ZSBiYXRjaGVzIGluIHBhcmFsbGVsXG4gICAgICBhc3luYyAoYmF0Y2gpID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICAgIGBEZWxldGluZyBvYmplY3RzOiAke2JhdGNoLm1hcCgoYikgPT4gYi5LZXkpfSBmcm9tICR7YnVja2V0TmFtZX1gLFxuICAgICAgICAgICk7XG4gICAgICAgICAgYXdhaXQgczNDbGllbnQuc2VuZChcbiAgICAgICAgICAgIG5ldyBEZWxldGVPYmplY3RzQ29tbWFuZCh7XG4gICAgICAgICAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgICAgICAgICAgRGVsZXRlOiB7IE9iamVjdHM6IGJhdGNoIH0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGRlYnVnKGBEZWxldGVkICR7YmF0Y2gubGVuZ3RofSBvYmplY3RzIGZyb20gJHtidWNrZXROYW1lfWApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBkZWxldGluZyBvYmplY3RzOlwiLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgKTtcbiAgfVxuXG4gIGRlYnVnKFxuICAgIGBQcnVuaW5nIGNvbXBsZXRlLiBEZWxldGVkICR7b2JqZWN0c1RvRGVsZXRlLmxlbmd0aH0gb2JqZWN0cyBmcm9tICR7YnVja2V0TmFtZX1gLFxuICApO1xufVxuXG4vKipcbiAqIFByb2Nlc3Mgb2JqZWN0cyBpbiBiYXRjaGVzIHRvIGF2b2lkIG92ZXJ3aGVsbWluZyB0aGUgc3lzdGVtXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHByb2Nlc3NCYXRjaDxULCBSPihcbiAgaXRlbXM6IFRbXSxcbiAgYmF0Y2hTaXplOiBudW1iZXIsXG4gIHByb2Nlc3NGbjogKGl0ZW06IFQpID0+IFByb21pc2U8Uj4sXG4pOiBQcm9taXNlPFJbXT4ge1xuICBjb25zdCByZXN1bHRzOiBSW10gPSBbXTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGl0ZW1zLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICBjb25zdCBiYXRjaCA9IGl0ZW1zLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpO1xuICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcChwcm9jZXNzRm4pKTtcbiAgICByZXN1bHRzLnB1c2goLi4uYmF0Y2hSZXN1bHRzKTtcbiAgfVxuXG4gIHJldHVybiByZXN1bHRzO1xufVxuIl19
145
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJ1bmUtczMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhcy9wb3N0LWRlcGxveS9wcnVuZS1zMy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQXdEQSwwQkFnSUM7QUFLRCxvQ0FjQztBQTNNRCw2REFBNkQ7QUFDN0Qsa0RBTTRCO0FBQzVCLDZEQUE2RDtBQUM3RCxrREFBNkI7QUFFN0IsTUFBTSxLQUFLLEdBQUcsSUFBQSxlQUFRLEVBQUMsaUNBQWlDLENBQUMsQ0FBQztBQUUxRCxNQUFNLFFBQVEsR0FBRyxJQUFJLG9CQUFRLEVBQUUsQ0FBQztBQUNoQywwQ0FBMEM7QUFDMUMsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLENBQUM7QUFrQnJDOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLHFCQUFxQixHQUFHLFVBQVUsQ0FBQztBQUV6Qzs7Ozs7Ozs7O0dBU0c7QUFDSSxLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQW1CO0lBQy9DLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsR0FBRyxLQUFLLENBQUM7SUFDL0QsK0VBQStFO0lBQy9FLDBFQUEwRTtJQUMxRSx5RUFBeUU7SUFDekUseUVBQXlFO0lBQ3pFLDJCQUEyQjtJQUMzQixNQUFNLElBQUksR0FBRyxDQUFDLFNBQVMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDdkUsZ0ZBQWdGO0lBQ2hGLDhFQUE4RTtJQUM5RSw2RUFBNkU7SUFDN0UsNEVBQTRFO0lBQzVFLDBFQUEwRTtJQUMxRSw2RUFBNkU7SUFDN0Usb0RBQW9EO0lBQ3BELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO0lBRWxELE1BQU0sVUFB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QixFQUNqQixTQUFrQztJQUVsQyxNQUFNLE9BQU8sR0FBUSxFQUFFLENBQUM7SUFFeEIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2pELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsQ0FBQztRQUM1QyxNQUFNLFlBQVksR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQzdELE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB7XG4gIFMzQ2xpZW50LFxuICBMaXN0T2JqZWN0c1YyQ29tbWFuZCxcbiAgRGVsZXRlT2JqZWN0c0NvbW1hbmQsXG4gIEhlYWRPYmplY3RDb21tYW5kLFxuICBMaXN0T2JqZWN0c1YyQ29tbWFuZElucHV0LFxufSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXMzXCI7XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXG5pbXBvcnQgZ2V0RGVidWcgZnJvbSBcImRlYnVnXCI7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoXCJjZGstbmV4dGpzOnBvc3QtZGVwbG95OnBydW5lLXMzXCIpO1xuXG5jb25zdCBzM0NsaWVudCA9IG5ldyBTM0NsaWVudCgpO1xuLy8gTWF4aW11bSBudW1iZXIgb2YgY29uY3VycmVudCBvcGVyYXRpb25zXG5jb25zdCBNQVhfQ09OQ1VSUkVOVF9PUEVSQVRJT05TID0gNTA7XG5cbmludGVyZmFjZSBQcnVuZVMzUHJvcHMge1xuICBidWNrZXROYW1lOiBzdHJpbmc7XG4gIGN1cnJlbnRCdWlsZElkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaW1lIHRvIGxpdmUgaW4gbWlsbGlzZWNvbmRzLlxuICAgKi9cbiAgbXNUdGw6IG51bWJlcjtcbiAgLyoqXG4gICAqIFMzIGtleSBwcmVmaXggdGhlIGFwcCdzIHN0YXRpYyBhc3NldHMgbGl2ZSB1bmRlci4gU3Vycm91bmRpbmcgc2xhc2hlcyBhcmVcbiAgICogbm9ybWFsaXplZCBhd2F5LiBTY29wZXMgcHJ1bmluZyB0byB0aGlzIGFwcCdzIGBfbmV4dC9gIG9iamVjdHMgc28gdGhhdCBhcHBzXG4gICAqIG9yIGJyYW5jaGVzIHNoYXJpbmcgb25lIGJ1Y2tldCB1bmRlciBkaWZmZXJlbnQgYGJhc2VQYXRoYHMgZG9uJ3QgZGVsZXRlXG4gICAqIGVhY2ggb3RoZXIncyBhc3NldHMuIEVtcHR5IG9yIG9taXR0ZWQgcHJ1bmVzIGBfbmV4dC9gIGF0IHRoZSBidWNrZXQgcm9vdC5cbiAgICovXG4gIGtleVByZWZpeD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgb2JqZWN0IG1ldGFkYXRhIGtleSBob2xkaW5nIHRoZSBidWlsZCBpZCwgYXMgaXQgY29tZXMgYmFjayBmcm9tXG4gKiBgSGVhZE9iamVjdGAuXG4gKlxuICogYE5leHRqc1N0YXRpY0Fzc2V0c2AgaGFuZHMgYEJ1Y2tldERlcGxveW1lbnRgIGBtZXRhZGF0YTogeyBCVUlMRF9JRCB9YCwgYW5kIENES1xuICogbG93ZXJjYXNlcyBldmVyeSB1c2VyIG1ldGFkYXRhIGtleSBiZWZvcmUgcHV0dGluZyBpdCBvbiB0aGUgb2JqZWN0XG4gKiAoYG1hcFVzZXJNZXRhZGF0YWAgaW4gYGF3cy1zMy1kZXBsb3ltZW50YCwgYW5kIHRoZSBkZXBsb3ltZW50IExhbWJkYSBsb3dlcmNhc2VzXG4gKiBhZ2FpbiBpbiBgY3JlYXRlX21ldGFkYXRhX2FyZ3NgKS4gVGhlIG5hbWUgdGhpcyBmaWxlIHVzZWQgdG8gcmVhZCxcbiAqIFwibmV4dC1idWlsZC1pZFwiLCBpcyB3cml0dGVuIGJ5IG5vdGhpbmc6IGBvYmplY3RCdWlsZElkYCB3YXMgYWx3YXlzIGB1bmRlZmluZWRgLFxuICogc28gdGhlIGtlZXAtZ3VhcmQgbmV2ZXIga2VwdCBhbnl0aGluZyBhbmQgcHJ1bmluZyB3YXMgcHVyZWx5IGFnZS1iYXNlZC5cbiAqL1xuY29uc3QgQlVJTERfSURfTUVUQURBVEFfS0VZID0gXCJidWlsZF9pZFwiO1xuXG4vKipcbiAqIEdpdmVuIGBidWNrZXROYW1lYCwgYGN1cnJlbnRCdWlsZElkYCwgYW5kIGBtc1R0bGAsIGxpc3QgdGhlIG9iamVjdHMgdW5kZXJcbiAqIGBrZXlQcmVmaXhgJ3MgYF9uZXh0L2AgYW5kIGRlbGV0ZSBhbnkgdGhhdCAxLyBjYXJyeSBhIGJ1aWxkIGlkIHRoYXQgaXMgbm90XG4gKiBgY3VycmVudEJ1aWxkSWRgIGFuZCAyLyB3ZXJlIGNyZWF0ZWQgbW9yZSB0aGFuIGBtc1R0bGAgYWdvLlxuICpcbiAqIEFuIG9iamVjdCB3aXRoIG5vIGJ1aWxkIGlkIGF0IGFsbCBpcyBrZXB0LiBJdCB3YXMgbm90IHVwbG9hZGVkIGJ5IHRoaXNcbiAqIGNvbnN0cnVjdCdzIGBCdWNrZXREZXBsb3ltZW50YCDigJQgd2hpY2ggc3RhbXBzIGV2ZXJ5IG9iamVjdCBpdCB3cml0ZXMg4oCUIHNvXG4gKiBub3RoaW5nIGhlcmUga25vd3Mgd2hldGhlciBzb21lIG90aGVyIHN0YWNrIGlzIHNlcnZpbmcgaXQsIGFuZCBkZWxldGluZyBhIGxpdmVcbiAqIGFzc2V0IDQwNHMgYSBwYWdlIHdoaWxlIGtlZXBpbmcgYSBzdGFsZSBvbmUgb25seSBjb3N0cyBzdG9yYWdlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJ1bmVTMyhwcm9wczogUHJ1bmVTM1Byb3BzKSB7XG4gIGNvbnN0IHsgYnVja2V0TmFtZSwgY3VycmVudEJ1aWxkSWQsIG1zVHRsLCBrZXlQcmVmaXggfSA9IHByb3BzO1xuICAvLyBTdXJyb3VuZGluZyBzbGFzaGVzIGFyZSBzdHJpcHBlZCBiZWZvcmUgdXNlOiBgTmV4dGpzU3RhdGljQXNzZXRzYCBoYW5kcyBvdmVyXG4gIC8vIGEgYmFyZSBwcmVmaXgsIGJ1dCBgb3ZlcnJpZGVzLmN1c3RvbVJlc291cmNlUHJvcGVydGllc2AgbGV0cyBhIHVzZXIgc2V0XG4gIC8vIGBzdGF0aWNBc3NldHNLZXlQcmVmaXhgIGRpcmVjdGx5LCBhbmQgXCJiYXNlL1wiIG9yIFwiL2Jhc2VcIiB3b3VsZCBidWlsZCBhXG4gIC8vIFByZWZpeCAoXCJiYXNlLy9cIiwgXCIvYmFzZS9cIikgdGhhdCBtYXRjaGVzIG5vIGtleSBhdCBhbGwg4oCUIHBydW5pbmcgd291bGRcbiAgLy8gc2lsZW50bHkgYmVjb21lIGEgbm8tb3AuXG4gIGNvbnN0IGJhcmUgPSAoa2V5UHJlZml4IHx8IFwiXCIpLnJlcGxhY2UoL15cXC8rLywgXCJcIikucmVwbGFjZSgvXFwvKyQvLCBcIlwiKTtcbiAgLy8gT25seSBgX25leHQvYCB1bmRlciB0aGUgcHJlZml4LCB3aGljaCBpcyB3aGVyZSBldmVyeSBidWlsZC1oYXNoZWQgYXNzZXQgbGl2ZXNcbiAgLy8gYW5kIHNvIHdoZXJlIG9sZCBidWlsZHMgcGlsZSB1cC4gVGhlIHByZWZpeCBhbG9uZSBpcyBub3QgYSBib3VuZGFyeSBiZXR3ZWVuXG4gIC8vIGFwcHM6IGFuIGFwcCB3aXRoIG5vbmUgb3ducyB0aGUgYnVja2V0IHJvb3QsIHdoaWNoIGhvbGRzIGV2ZXJ5IG90aGVyIGFwcCdzXG4gIC8vIGA8YmFzZVBhdGg+L2AgdG9vLCBhbmQgb25lIGF0IFwidGVhbVwiIGhvbGRzIGFub3RoZXIgYXQgXCJ0ZWFtL2FwcFwiLiBQcnVuaW5nXG4gIC8vIHRob3NlIGRlbGV0ZWQgdGhlIG90aGVyIGFwcCdzIGxpdmUgYXNzZXRzIG9uY2UgdGhleSB3ZXJlIGEgbW9udGggb2xkLiBBXG4gIC8vIGBwdWJsaWMvYCBmaWxlIGtlZXBzIGl0cyBrZXkgZnJvbSBidWlsZCB0byBidWlsZCwgc28gbGVhdmluZyBpdCBjb3N0cyBvbmx5XG4gIC8vIHRoZSBzdG9yYWdlIG9mIG9uZSB0aGF0IHdhcyByZW1vdmVkIGZyb20gdGhlIGFwcC5cbiAgY29uc3QgcHJlZml4ID0gYmFyZSA/IGAke2JhcmV9L19uZXh0L2AgOiBcIl9uZXh0L1wiO1xuXG4gIGNvbnN0IGN1dG9mZkRhdGUgPSBuZXcgRGF0ZShEYXRlLm5vdygpIC0gbXNUdGwpO1xuICBjb25zdCBvYmplY3RzVG9EZWxldGU6IHsgS2V5OiBzdHJpbmcgfVtdID0gW107XG5cbiAgbGV0IGNvbnRpbnVhdGlvblRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIGxldCBsaXN0T2JqZWN0c0NvdW50ID0gMDtcblxuICBkbyB7XG4gICAgLy8gTGlzdCBvYmplY3RzIGluIHRoZSBidWNrZXRcbiAgICBjb25zdCBsaXN0T2JqZWN0c1YySW5wdXQ6IExpc3RPYmplY3RzVjJDb21tYW5kSW5wdXQgPSB7XG4gICAgICBCdWNrZXQ6IGJ1Y2tldE5hbWUsXG4gICAgICBDb250aW51YXRpb25Ub2tlbjogY29udGludWF0aW9uVG9rZW4sXG4gICAgICBQcmVmaXg6IHByZWZpeCxcbiAgICB9O1xuICAgIGNvbnN0IGxpc3RSZXNwb25zZSA9IGF3YWl0IHMzQ2xpZW50LnNlbmQoXG4gICAgICBuZXcgTGlzdE9iamVjdHNWMkNvbW1hbmQobGlzdE9iamVjdHNWMklucHV0KSxcbiAgICApO1xuXG4gICAgLy8gTm8gYGJyZWFrYCBvbiBhbiBlbXB0eSBwYWdlOiBgTGlzdE9iamVjdHNWMmAgd2l0aCBhIGBQcmVmaXhgIGNhbiBhbnN3ZXIgd2l0aFxuICAgIC8vIG5vIGBDb250ZW50c2AgYW5kIGBJc1RydW5jYXRlZDogdHJ1ZWAsIGhhdmluZyBzY2FubmVkIGEgd2luZG93IG9mIHRoZSBidWNrZXRcbiAgICAvLyB0aGF0IGhlbGQgbm8gbWF0Y2hpbmcga2V5LiBUaGF0IGlzIGV4YWN0bHkgdGhlIHNoYXJlZC1idWNrZXQgY2FzZSBga2V5UHJlZml4YFxuICAgIC8vIGV4aXN0cyBmb3IsIGFuZCBicmVha2luZyBoZXJlIHN0b3BwZWQgcHJ1bmluZyBhdCB0aGUgZmlyc3Qgc3VjaCB3aW5kb3csIHNvXG4gICAgLy8gZXZlcnkgb2xkZXIgYXNzZXQgcGFzdCBpdCB3YXMgbmV2ZXIgZGVsZXRlZC4gVGhlIGxvb3AncyBvd24gdG9rZW4gYW5kIHBhZ2VcbiAgICAvLyBndWFyZCBiZWxvdyB0ZXJtaW5hdGUgaXQuXG4gICAgY29uc3QgY29udGVudHMgPSBsaXN0UmVzcG9uc2UuQ29udGVudHMgPz8gW107XG5cbiAgICAvLyBGaWx0ZXIgb3V0IG9iamVjdHMgd2l0aG91dCBrZXlzXG4gICAgY29uc3Qgb2xkT2JqZWN0cyA9IGNvbnRlbnRzLmZpbHRlcigob2JqKSA9PiB7XG4gICAgICBjb25zdCBsYXN0TW9kaWZpZWQgPSBvYmouTGFzdE1vZGlmaWVkIHx8IG5ldyBEYXRlKCk7XG4gICAgICByZXR1cm4gb2JqLktleSAmJiBsYXN0TW9kaWZpZWQgPCBjdXRvZmZEYXRlO1xuICAgIH0pO1xuICAgIGRlYnVnKFxuICAgICAgYENoZWNraW5nIG9sZCBvYmplY3RzIG1ldGFkYXRhIHRvIGRldGVybWluZSBwcnVuaW5nOiAke29sZE9iamVjdHMubWFwKChvKSA9PiBvLktleSl9YCxcbiAgICApO1xuXG4gICAgLy8gUHJvY2VzcyBvYmplY3RzIGluIHBhcmFsbGVsIHdpdGggY29udHJvbGxlZCBjb25jdXJyZW5jeVxuICAgIGNvbnN0IGNoZWNrUmVzdWx0cyA9IGF3YWl0IHByb2Nlc3NCYXRjaChcbiAgICAgIG9sZE9iamVjdHMsXG4gICAgICBNQVhfQ09OQ1VSUkVOVF9PUEVSQVRJT05TLFxuICAgICAgYXN5bmMgKG9iamVjdCkgPT4ge1xuICAgICAgICBpZiAoIW9iamVjdC5LZXkpIHJldHVybiBudWxsO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgaGVhZFJlc3BvbnNlID0gYXdhaXQgczNDbGllbnQuc2VuZChcbiAgICAgICAgICAgIG5ldyBIZWFkT2JqZWN0Q29tbWFuZCh7XG4gICAgICAgICAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgICAgICAgICAgS2V5OiBvYmplY3QuS2V5LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGNvbnN0IG9iamVjdEJ1aWxkSWQgPSBoZWFkUmVzcG9uc2UuTWV0YWRhdGE/LltCVUlMRF9JRF9NRVRBREFUQV9LRVldO1xuXG4gICAgICAgICAgLy8gUmV0dXJuIHRoZSBrZXkgaWYgaXQgc2hvdWxkIGJlIGRlbGV0ZWQuIEFuIG9iamVjdCB3aXRoIG5vIGJ1aWxkIGlkXG4gICAgICAgICAgLy8gaXMgbGVmdCBhbG9uZSDigJQgc2VlIHRoaXMgZnVuY3Rpb24ncyBkb2MgY29tbWVudC5cbiAgICAgICAgICBpZiAob2JqZWN0QnVpbGRJZCAmJiBvYmplY3RCdWlsZElkICE9PSBjdXJyZW50QnVpbGRJZCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgS2V5OiBvYmplY3QuS2V5IH07XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNoZWNraW5nIG9iamVjdCAke29iamVjdC5LZXl9OmAsIGVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfSxcbiAgICApO1xuXG4gICAgLy8gQWRkIHZhbGlkIG9iamVjdHMgdG8gZGVsZXRlIGxpc3RcbiAgICBvYmplY3RzVG9EZWxldGUucHVzaChcbiAgICAgIC4uLihjaGVja1Jlc3VsdHMuZmlsdGVyKEJvb2xlYW4pIGFzIHsgS2V5OiBzdHJpbmcgfVtdKSxcbiAgICApO1xuXG4gICAgLy8gQXNzaWduZWQgdW5jb25kaXRpb25hbGx5OiB0aGUgbGFzdCBwYWdlIGNhcnJpZXMgbm8gTmV4dENvbnRpbnVhdGlvblRva2VuLFxuICAgIC8vIGFuZCBrZWVwaW5nIHRoZSBwcmV2aW91cyBwYWdlJ3MgdG9rZW4gd291bGQgcmUtbGlzdCB0aGF0IHNhbWUgcGFnZSB1bnRpbFxuICAgIC8vIHRoZSBndWFyZCBiZWxvdyB0cmlwcywgcmUtY2hlY2tpbmcgZXZlcnkgb2JqZWN0IG9uIGl0IDEwMCB0aW1lcyBvdmVyLlxuICAgIGNvbnRpbnVhdGlvblRva2VuID0gbGlzdFJlc3BvbnNlLk5leHRDb250aW51YXRpb25Ub2tlbjtcbiAgICBsaXN0T2JqZWN0c0NvdW50Kys7XG4gICAgLy8gYXNzdW1lIGxlc3MgdGhhbiAxMDBLIG9iamVjdHMgKDEwMCAqIDFLIG9iamVjdHMgcGVyIExpc3RPYmplY3RzVjJDb21tYW5kID0gMTAwSylcbiAgfSB3aGlsZSAoY29udGludWF0aW9uVG9rZW4gJiYgbGlzdE9iamVjdHNDb3VudCA8PSAxMDApO1xuXG4gIC8vIERlbGV0ZSBvYmplY3RzIGluIHBhcmFsbGVsIGJhdGNoZXMgKHJlc3BlY3RpbmcgUzMncyAxMDAwIG9iamVjdHMgcGVyIHJlcXVlc3QgbGltaXQpXG4gIGlmIChvYmplY3RzVG9EZWxldGUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IGRlbGV0ZUJhdGNoZXMgPSBbXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb2JqZWN0c1RvRGVsZXRlLmxlbmd0aDsgaSArPSAxMDAwKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IG9iamVjdHNUb0RlbGV0ZS5zbGljZShpLCBpICsgMTAwMCk7XG4gICAgICBkZWxldGVCYXRjaGVzLnB1c2goYmF0Y2gpO1xuICAgIH1cblxuICAgIGF3YWl0IHByb2Nlc3NCYXRjaChcbiAgICAgIGRlbGV0ZUJhdGNoZXMsXG4gICAgICA1LCAvLyBQcm9jZXNzIHVwIHRvIDUgZGVsZXRlIGJhdGNoZXMgaW4gcGFyYWxsZWxcbiAgICAgIGFzeW5jIChiYXRjaCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGRlYnVnKFxuICAgICAgICAgICAgYERlbGV0aW5nIG9iamVjdHM6ICR7YmF0Y2gubWFwKChiKSA9PiBiLktleSl9IGZyb20gJHtidWNrZXROYW1lfWAsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBhd2FpdCBzM0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IERlbGV0ZU9iamVjdHNDb21tYW5kKHtcbiAgICAgICAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgICAgICAgICBEZWxldGU6IHsgT2JqZWN0czogYmF0Y2ggfSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgICAgZGVidWcoYERlbGV0ZWQgJHtiYXRjaC5sZW5ndGh9IG9iamVjdHMgZnJvbSAke2J1Y2tldE5hbWV9YCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGRlbGV0aW5nIG9iamVjdHM6XCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICB9XG5cbiAgZGVidWcoXG4gICAgYFBydW5pbmcgY29tcGxldGUuIERlbGV0ZWQgJHtvYmplY3RzVG9EZWxldGUubGVuZ3RofSBvYmplY3RzIGZyb20gJHtidWNrZXROYW1lfWAsXG4gICk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBvYmplY3RzIGluIGJhdGNoZXMgdG8gYXZvaWQgb3ZlcndoZWxtaW5nIHRoZSBzeXN0ZW1cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHByb2Nlc3NCYXRjaDxULCBSPihcbiAgaXRlbXM6IFRbXSxcbiAgYmF0Y2hTaXplOiBudW1iZXIsXG4gIHByb2Nlc3NGbjogKGl0ZW06IFQpID0+IFByb21pc2U8Uj4sXG4pOiBQcm9taXNlPFJbXT4ge1xuICBjb25zdCByZXN1bHRzOiBSW10gPSBbXTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGl0ZW1zLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICBjb25zdCBiYXRjaCA9IGl0ZW1zLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpO1xuICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcChwcm9jZXNzRm4pKTtcbiAgICByZXN1bHRzLnB1c2goLi4uYmF0Y2hSZXN1bHRzKTtcbiAgfVxuXG4gIHJldHVybiByZXN1bHRzO1xufVxuIl19
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable import/no-extraneous-dependencies */
4
+ // Only the client is mocked; the command classes stay real so that assertions
5
+ // can read `command.input`. `send` is looked up through the holder at call time
6
+ // because `prune-s3` constructs its client at module scope, before the mock
7
+ // variables here are initialized.
8
+ jest.mock("@aws-sdk/client-s3", () => ({
9
+ ...jest.requireActual("@aws-sdk/client-s3"),
10
+ S3Client: jest.fn(() => ({
11
+ send: (...args) => holder.send(...args),
12
+ })),
13
+ }));
14
+ const client_s3_1 = require("@aws-sdk/client-s3");
15
+ const prune_s3_1 = require("./prune-s3");
16
+ const holder = { send: jest.fn() };
17
+ const BUCKET = "my-static-assets";
18
+ const CURRENT_BUILD_ID = "build-2";
19
+ const MS_TTL = 1000 * 60 * 60 * 24 * 30;
20
+ /**
21
+ * One page of listed objects, all old enough to prune and each carrying a stale
22
+ * build id, so every one of them is a deletion candidate. That isolates the
23
+ * question this suite is about: which keys `pruneS3` was ever shown.
24
+ */
25
+ function stubBucketContents(keys, buildId = "build-1") {
26
+ const longAgo = new Date(Date.now() - MS_TTL * 2);
27
+ holder.send.mockImplementation((command) => {
28
+ if (command instanceof client_s3_1.ListObjectsV2Command) {
29
+ return Promise.resolve({
30
+ Contents: keys.map((Key) => ({ Key, LastModified: longAgo })),
31
+ });
32
+ }
33
+ if (command instanceof client_s3_1.DeleteObjectsCommand) {
34
+ return Promise.resolve({});
35
+ }
36
+ // HeadObject
37
+ return Promise.resolve({ Metadata: { build_id: buildId } });
38
+ });
39
+ }
40
+ /**
41
+ * Several pages of listed objects, keyed by the continuation token that asks for
42
+ * each one, so the suite can assert how `pruneS3` walks a paginated listing. The
43
+ * last page deliberately carries no NextContinuationToken, as S3 returns it.
44
+ */
45
+ function stubPagedBucketContents(pages) {
46
+ const longAgo = new Date(Date.now() - MS_TTL * 2);
47
+ holder.send.mockImplementation((command) => {
48
+ if (command instanceof client_s3_1.ListObjectsV2Command) {
49
+ const token = command.input.ContinuationToken;
50
+ const index = token ? Number(token.replace("page-", "")) : 0;
51
+ return Promise.resolve({
52
+ Contents: (pages[index] ?? []).map((Key) => ({
53
+ Key,
54
+ LastModified: longAgo,
55
+ })),
56
+ NextContinuationToken: index + 1 < pages.length ? `page-${index + 1}` : undefined,
57
+ });
58
+ }
59
+ if (command instanceof client_s3_1.DeleteObjectsCommand) {
60
+ return Promise.resolve({});
61
+ }
62
+ // HeadObject
63
+ return Promise.resolve({ Metadata: { build_id: "build-1" } });
64
+ });
65
+ }
66
+ function sentCommands(type) {
67
+ return holder.send.mock.calls
68
+ .map(([command]) => command)
69
+ .filter((command) => command instanceof type);
70
+ }
71
+ function listPrefixes() {
72
+ return sentCommands(client_s3_1.ListObjectsV2Command).map((command) => command.input.Prefix);
73
+ }
74
+ function deletedKeys() {
75
+ return sentCommands(client_s3_1.DeleteObjectsCommand).flatMap((command) => (command.input.Delete?.Objects ?? []).map((o) => o.Key));
76
+ }
77
+ function prune(keyPrefix) {
78
+ return (0, prune_s3_1.pruneS3)({
79
+ bucketName: BUCKET,
80
+ currentBuildId: CURRENT_BUILD_ID,
81
+ msTtl: MS_TTL,
82
+ keyPrefix,
83
+ });
84
+ }
85
+ describe("pruneS3", () => {
86
+ beforeEach(() => {
87
+ holder.send.mockReset();
88
+ });
89
+ // Without a Prefix, pruning walks the whole bucket. Two branches sharing one
90
+ // bucket under different basePaths would then delete each other's assets once
91
+ // they aged past msTtl, 404ing the other branch.
92
+ it("scopes the listing to the key prefix", async () => {
93
+ stubBucketContents(["branch-a/_next/static/old.js"]);
94
+ await prune("branch-a");
95
+ expect(listPrefixes()).toEqual(["branch-a/_next/"]);
96
+ });
97
+ // A sibling app whose prefix starts with this one's ("branch-a-staging") is a
98
+ // different app's objects, even though its keys start with "branch-a".
99
+ it("leaves a sibling prefix's assets alone", async () => {
100
+ const longAgo = new Date(Date.now() - MS_TTL * 2);
101
+ const bucket = [
102
+ "branch-a/_next/static/old.js",
103
+ "branch-a-staging/_next/static/old.js",
104
+ ];
105
+ holder.send.mockImplementation((command) => {
106
+ if (command instanceof client_s3_1.ListObjectsV2Command) {
107
+ return Promise.resolve({
108
+ Contents: bucket
109
+ .filter((Key) => Key.startsWith(command.input.Prefix ?? ""))
110
+ .map((Key) => ({ Key, LastModified: longAgo })),
111
+ });
112
+ }
113
+ if (command instanceof client_s3_1.DeleteObjectsCommand) {
114
+ return Promise.resolve({});
115
+ }
116
+ return Promise.resolve({ Metadata: { build_id: "build-1" } });
117
+ });
118
+ await prune("branch-a");
119
+ expect(deletedKeys()).toEqual(["branch-a/_next/static/old.js"]);
120
+ });
121
+ it("takes a nested prefix as NextjsStaticAssets resolved it", async () => {
122
+ stubBucketContents([]);
123
+ await prune("team/app");
124
+ expect(listPrefixes()).toEqual(["team/app/_next/"]);
125
+ });
126
+ // The single-app case, and every deployment predating the prefix being
127
+ // threaded through: an unset prefix prunes `_next/` at the bucket root. Not
128
+ // the whole bucket, which holds every other app's `<basePath>/` as well.
129
+ it.each([
130
+ ["omitted", undefined],
131
+ ["empty", ""],
132
+ ])("lists the root `_next/` when the prefix is %s", async (_label, prefix) => {
133
+ stubBucketContents([]);
134
+ await prune(prefix);
135
+ expect(listPrefixes()).toEqual(["_next/"]);
136
+ });
137
+ // An app at "team" shares its prefix with one at "team/app", whose
138
+ // `team/app/_next/` is not under `team/_next/`.
139
+ it("leaves a nested app's assets out of the listing", async () => {
140
+ stubBucketContents([]);
141
+ await prune("team");
142
+ expect(listPrefixes()).toEqual(["team/_next/"]);
143
+ });
144
+ it("still deletes stale objects within the prefix", async () => {
145
+ stubBucketContents([
146
+ "branch-a/_next/static/old.js",
147
+ "branch-a/_next/static/older.css",
148
+ ]);
149
+ await prune("branch-a");
150
+ expect(deletedKeys().sort()).toEqual([
151
+ "branch-a/_next/static/old.js",
152
+ "branch-a/_next/static/older.css",
153
+ ]);
154
+ });
155
+ it("keeps objects carrying the current build id", async () => {
156
+ stubBucketContents(["branch-a/current.js"], CURRENT_BUILD_ID);
157
+ await prune("branch-a");
158
+ expect(deletedKeys()).toEqual([]);
159
+ });
160
+ // Asserted on the literal key rather than through a shared constant: the name
161
+ // is a contract with CDK, which lowercases the `metadata: { BUILD_ID }` that
162
+ // `NextjsStaticAssets` passes `BucketDeployment`. Reading any other name — this
163
+ // file read "next-build-id" for a long time — makes `objectBuildId` always
164
+ // `undefined`, and a guard that never fires cannot be told from one that has
165
+ // nothing to keep.
166
+ it("reads the build id from the metadata key BucketDeployment writes", async () => {
167
+ const longAgo = new Date(Date.now() - MS_TTL * 2);
168
+ holder.send.mockImplementation((command) => {
169
+ if (command instanceof client_s3_1.ListObjectsV2Command) {
170
+ return Promise.resolve({
171
+ Contents: [{ Key: "branch-a/current.js", LastModified: longAgo }],
172
+ });
173
+ }
174
+ if (command instanceof client_s3_1.DeleteObjectsCommand) {
175
+ return Promise.resolve({});
176
+ }
177
+ return Promise.resolve({
178
+ Metadata: { build_id: CURRENT_BUILD_ID },
179
+ });
180
+ });
181
+ await prune("branch-a");
182
+ expect(deletedKeys()).toEqual([]);
183
+ });
184
+ // Not this construct's object: `BucketDeployment` stamps every file it uploads,
185
+ // so an unstamped one belongs to something else sharing the bucket. Deleting it
186
+ // 404s whatever serves it, while keeping it only costs storage.
187
+ it("keeps an object that carries no build id at all", async () => {
188
+ const longAgo = new Date(Date.now() - MS_TTL * 2);
189
+ holder.send.mockImplementation((command) => {
190
+ if (command instanceof client_s3_1.ListObjectsV2Command) {
191
+ return Promise.resolve({
192
+ Contents: [
193
+ { Key: "branch-a/someone-elses.js", LastModified: longAgo },
194
+ ],
195
+ });
196
+ }
197
+ if (command instanceof client_s3_1.DeleteObjectsCommand) {
198
+ return Promise.resolve({});
199
+ }
200
+ return Promise.resolve({ Metadata: {} });
201
+ });
202
+ await prune("branch-a");
203
+ expect(deletedKeys()).toEqual([]);
204
+ });
205
+ // The construct always hands over a bare prefix, but
206
+ // `overrides.customResourceProperties.staticAssetsKeyPrefix` reaches this
207
+ // directly. "base/" would build a Prefix of "base//" and "/base" one of
208
+ // "/base/", neither of which matches any key, so pruning would silently stop
209
+ // deleting anything at all.
210
+ it.each([
211
+ ["a trailing slash", "branch-a/"],
212
+ ["a leading slash", "/branch-a"],
213
+ ["both", "/branch-a/"],
214
+ ])("normalizes a prefix given with %s", async (_label, prefix) => {
215
+ stubBucketContents([]);
216
+ await prune(prefix);
217
+ expect(listPrefixes()).toEqual(["branch-a/_next/"]);
218
+ });
219
+ describe("pagination", () => {
220
+ it("follows the continuation token across pages", async () => {
221
+ stubPagedBucketContents([["a/one.js"], ["a/two.js"], ["a/three.js"]]);
222
+ await prune("a");
223
+ expect(sentCommands(client_s3_1.ListObjectsV2Command).map((command) => command.input.ContinuationToken)).toEqual([undefined, "page-1", "page-2"]);
224
+ expect(deletedKeys().sort()).toEqual([
225
+ "a/one.js",
226
+ "a/three.js",
227
+ "a/two.js",
228
+ ]);
229
+ });
230
+ // The last page carries no NextContinuationToken. Holding on to the previous
231
+ // page's token re-lists that page until the 100-iteration guard trips,
232
+ // re-HEADing every object on it 100 times over (~100k requests for a full
233
+ // 1000-key page) and pushing duplicate keys into the delete batches — enough
234
+ // to blow the post-deploy Lambda's timeout, which leaves the custom resource
235
+ // waiting on a response that never comes.
236
+ it("stops listing once a page returns no continuation token", async () => {
237
+ stubPagedBucketContents([["a/one.js"], ["a/two.js"]]);
238
+ await prune("a");
239
+ expect(sentCommands(client_s3_1.ListObjectsV2Command)).toHaveLength(2);
240
+ expect(deletedKeys()).toEqual(["a/one.js", "a/two.js"]);
241
+ });
242
+ // S3 scans a window of the bucket per request and filters by `Prefix`
243
+ // afterwards, so a page can come back with no `Contents` and still have a
244
+ // continuation token — exactly the shared-bucket case `keyPrefix` exists for.
245
+ // Stopping there left every older asset past that window undeleted, and the
246
+ // bucket grew without bound with nothing in the logs to say so.
247
+ it("keeps listing past a page whose window held no matching key", async () => {
248
+ stubPagedBucketContents([["a/one.js"], [], ["a/three.js"]]);
249
+ await prune("a");
250
+ expect(sentCommands(client_s3_1.ListObjectsV2Command)).toHaveLength(3);
251
+ expect(deletedKeys().sort()).toEqual(["a/one.js", "a/three.js"]);
252
+ });
253
+ });
254
+ });
255
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJ1bmUtczMudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGFzL3Bvc3QtZGVwbG95L3BydW5lLXMzLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxzREFBc0Q7QUFDdEQsOEVBQThFO0FBQzlFLGdGQUFnRjtBQUNoRiw0RUFBNEU7QUFDNUUsa0NBQWtDO0FBQ2xDLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNyQyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsb0JBQW9CLENBQUM7SUFDM0MsUUFBUSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUN2QixJQUFJLEVBQUUsQ0FBQyxHQUFHLElBQWUsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQztLQUNuRCxDQUFDLENBQUM7Q0FDSixDQUFDLENBQUMsQ0FBQztBQUVKLGtEQUFnRjtBQUNoRix5Q0FBcUM7QUFFckMsTUFBTSxNQUFNLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7QUFFbkMsTUFBTSxNQUFNLEdBQUcsa0JBQWtCLENBQUM7QUFDbEMsTUFBTSxnQkFBZ0IsR0FBRyxTQUFTLENBQUM7QUFDbkMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztBQUV4Qzs7OztHQUlHO0FBQ0gsU0FBUyxrQkFBa0IsQ0FBQyxJQUFjLEVBQUUsT0FBTyxHQUFHLFNBQVM7SUFDN0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNsRCxNQUFNLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUMs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RUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV0RCxNQUFNLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVqQixNQUFNLENBQUMsWUFBWSxDQUFDLGdDQUFvQixDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0QsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDMUQsQ0FBQyxDQUFDLENBQUM7UUFFSCxzRUFBc0U7UUFDdEUsMEVBQTBFO1FBQzFFLDhFQUE4RTtRQUM5RSw0RUFBNEU7UUFDNUUsZ0VBQWdFO1FBQ2hFLEVBQUUsQ0FBQyw2REFBNkQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMzRSx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTVELE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBRWpCLE1BQU0sQ0FBQyxZQUFZLENBQUMsZ0NBQW9CLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMzRCxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUNuRSxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXMgKi9cbi8vIE9ubHkgdGhlIGNsaWVudCBpcyBtb2NrZWQ7IHRoZSBjb21tYW5kIGNsYXNzZXMgc3RheSByZWFsIHNvIHRoYXQgYXNzZXJ0aW9uc1xuLy8gY2FuIHJlYWQgYGNvbW1hbmQuaW5wdXRgLiBgc2VuZGAgaXMgbG9va2VkIHVwIHRocm91Z2ggdGhlIGhvbGRlciBhdCBjYWxsIHRpbWVcbi8vIGJlY2F1c2UgYHBydW5lLXMzYCBjb25zdHJ1Y3RzIGl0cyBjbGllbnQgYXQgbW9kdWxlIHNjb3BlLCBiZWZvcmUgdGhlIG1vY2tcbi8vIHZhcmlhYmxlcyBoZXJlIGFyZSBpbml0aWFsaXplZC5cbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1zM1wiLCAoKSA9PiAoe1xuICAuLi5qZXN0LnJlcXVpcmVBY3R1YWwoXCJAYXdzLXNkay9jbGllbnQtczNcIiksXG4gIFMzQ2xpZW50OiBqZXN0LmZuKCgpID0+ICh7XG4gICAgc2VuZDogKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gaG9sZGVyLnNlbmQoLi4uYXJncyksXG4gIH0pKSxcbn0pKTtcblxuaW1wb3J0IHsgTGlzdE9iamVjdHNWMkNvbW1hbmQsIERlbGV0ZU9iamVjdHNDb21tYW5kIH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHsgcHJ1bmVTMyB9IGZyb20gXCIuL3BydW5lLXMzXCI7XG5cbmNvbnN0IGhvbGRlciA9IHsgc2VuZDogamVzdC5mbigpIH07XG5cbmNvbnN0IEJVQ0tFVCA9IFwibXktc3RhdGljLWFzc2V0c1wiO1xuY29uc3QgQ1VSUkVOVF9CVUlMRF9JRCA9IFwiYnVpbGQtMlwiO1xuY29uc3QgTVNfVFRMID0gMTAwMCAqIDYwICogNjAgKiAyNCAqIDMwO1xuXG4vKipcbiAqIE9uZSBwYWdlIG9mIGxpc3RlZCBvYmplY3RzLCBhbGwgb2xkIGVub3VnaCB0byBwcnVuZSBhbmQgZWFjaCBjYXJyeWluZyBhIHN0YWxlXG4gKiBidWlsZCBpZCwgc28gZXZlcnkgb25lIG9mIHRoZW0gaXMgYSBkZWxldGlvbiBjYW5kaWRhdGUuIFRoYXQgaXNvbGF0ZXMgdGhlXG4gKiBxdWVzdGlvbiB0aGlzIHN1aXRlIGlzIGFib3V0OiB3aGljaCBrZXlzIGBwcnVuZVMzYCB3YXMgZXZlciBzaG93bi5cbiAqL1xuZnVuY3Rpb24gc3R1YkJ1Y2tldENvbnRlbnRzKGtleXM6IHN0cmluZ1tdLCBidWlsZElkID0gXCJidWlsZC0xXCIpOiB2b2lkIHtcbiAgY29uc3QgbG9uZ0FnbyA9IG5ldyBEYXRlKERhdGUubm93KCkgLSBNU19UVEwgKiAyKTtcbiAgaG9sZGVyLnNlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PiB7XG4gICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBMaXN0T2JqZWN0c1YyQ29tbWFuZCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgIENvbnRlbnRzOiBrZXlzLm1hcCgoS2V5KSA9PiAoeyBLZXksIExhc3RNb2RpZmllZDogbG9uZ0FnbyB9KSksXG4gICAgICB9KTtcbiAgICB9XG4gICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBEZWxldGVPYmplY3RzQ29tbWFuZCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7XG4gICAgfVxuICAgIC8vIEhlYWRPYmplY3RcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHsgTWV0YWRhdGE6IHsgYnVpbGRfaWQ6IGJ1aWxkSWQgfSB9KTtcbiAgfSk7XG59XG5cbi8qKlxuICogU2V2ZXJhbCBwYWdlcyBvZiBsaXN0ZWQgb2JqZWN0cywga2V5ZWQgYnkgdGhlIGNvbnRpbnVhdGlvbiB0b2tlbiB0aGF0IGFza3MgZm9yXG4gKiBlYWNoIG9uZSwgc28gdGhlIHN1aXRlIGNhbiBhc3NlcnQgaG93IGBwcnVuZVMzYCB3YWxrcyBhIHBhZ2luYXRlZCBsaXN0aW5nLiBUaGVcbiAqIGxhc3QgcGFnZSBkZWxpYmVyYXRlbHkgY2FycmllcyBubyBOZXh0Q29udGludWF0aW9uVG9rZW4sIGFzIFMzIHJldHVybnMgaXQuXG4gKi9cbmZ1bmN0aW9uIHN0dWJQYWdlZEJ1Y2tldENvbnRlbnRzKHBhZ2VzOiBzdHJpbmdbXVtdKTogdm9pZCB7XG4gIGNvbnN0IGxvbmdBZ28gPSBuZXcgRGF0ZShEYXRlLm5vdygpIC0gTVNfVFRMICogMik7XG4gIGhvbGRlci5zZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT4ge1xuICAgIGlmIChjb21tYW5kIGluc3RhbmNlb2YgTGlzdE9iamVjdHNWMkNvbW1hbmQpIHtcbiAgICAgIGNvbnN0IHRva2VuID0gY29tbWFuZC5pbnB1dC5Db250aW51YXRpb25Ub2tlbjtcbiAgICAgIGNvbnN0IGluZGV4ID0gdG9rZW4gPyBOdW1iZXIodG9rZW4ucmVwbGFjZShcInBhZ2UtXCIsIFwiXCIpKSA6IDA7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgQ29udGVudHM6IChwYWdlc1tpbmRleF0gPz8gW10pLm1hcCgoS2V5KSA9PiAoe1xuICAgICAgICAgIEtleSxcbiAgICAgICAgICBMYXN0TW9kaWZpZWQ6IGxvbmdBZ28sXG4gICAgICAgIH0pKSxcbiAgICAgICAgTmV4dENvbnRpbnVhdGlvblRva2VuOlxuICAgICAgICAgIGluZGV4ICsgMSA8IHBhZ2VzLmxlbmd0aCA/IGBwYWdlLSR7aW5kZXggKyAxfWAgOiB1bmRlZmluZWQsXG4gICAgICB9KTtcbiAgICB9XG4gICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBEZWxldGVPYmplY3RzQ29tbWFuZCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7XG4gICAgfVxuICAgIC8vIEhlYWRPYmplY3RcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHsgTWV0YWRhdGE6IHsgYnVpbGRfaWQ6IFwiYnVpbGQtMVwiIH0gfSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBzZW50Q29tbWFuZHM8VD4odHlwZTogbmV3ICguLi5hcmdzOiBhbnlbXSkgPT4gVCk6IFRbXSB7XG4gIHJldHVybiBob2xkZXIuc2VuZC5tb2NrLmNhbGxzXG4gICAgLm1hcCgoW2NvbW1hbmRdKSA9PiBjb21tYW5kKVxuICAgIC5maWx0ZXIoKGNvbW1hbmQpOiBjb21tYW5kIGlzIFQgPT4gY29tbWFuZCBpbnN0YW5jZW9mIHR5cGUpO1xufVxuXG5mdW5jdGlvbiBsaXN0UHJlZml4ZXMoKTogKHN0cmluZyB8IHVuZGVmaW5lZClbXSB7XG4gIHJldHVybiBzZW50Q29tbWFuZHMoTGlzdE9iamVjdHNWMkNvbW1hbmQpLm1hcChcbiAgICAoY29tbWFuZCkgPT4gY29tbWFuZC5pbnB1dC5QcmVmaXgsXG4gICk7XG59XG5cbmZ1bmN0aW9uIGRlbGV0ZWRLZXlzKCk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIHNlbnRDb21tYW5kcyhEZWxldGVPYmplY3RzQ29tbWFuZCkuZmxhdE1hcCgoY29tbWFuZCkgPT5cbiAgICAoY29tbWFuZC5pbnB1dC5EZWxldGU/Lk9iamVjdHMgPz8gW10pLm1hcCgobykgPT4gby5LZXkgYXMgc3RyaW5nKSxcbiAgKTtcbn1cblxuZnVuY3Rpb24gcHJ1bmUoa2V5UHJlZml4Pzogc3RyaW5nKSB7XG4gIHJldHVybiBwcnVuZVMzKHtcbiAgICBidWNrZXROYW1lOiBCVUNLRVQsXG4gICAgY3VycmVudEJ1aWxkSWQ6IENVUlJFTlRfQlVJTERfSUQsXG4gICAgbXNUdGw6IE1TX1RUTCxcbiAgICBrZXlQcmVmaXgsXG4gIH0pO1xufVxuXG5kZXNjcmliZShcInBydW5lUzNcIiwgKCkgPT4ge1xuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBob2xkZXIuc2VuZC5tb2NrUmVzZXQoKTtcbiAgfSk7XG5cbiAgLy8gV2l0aG91dCBhIFByZWZpeCwgcHJ1bmluZyB3YWxrcyB0aGUgd2hvbGUgYnVja2V0LiBUd28gYnJhbmNoZXMgc2hhcmluZyBvbmVcbiAgLy8gYnVja2V0IHVuZGVyIGRpZmZlcmVudCBiYXNlUGF0aHMgd291bGQgdGhlbiBkZWxldGUgZWFjaCBvdGhlcidzIGFzc2V0cyBvbmNlXG4gIC8vIHRoZXkgYWdlZCBwYXN0IG1zVHRsLCA0MDRpbmcgdGhlIG90aGVyIGJyYW5jaC5cbiAgaXQoXCJzY29wZXMgdGhlIGxpc3RpbmcgdG8gdGhlIGtleSBwcmVmaXhcIiwgYXN5bmMgKCkgPT4ge1xuICAgIHN0dWJCdWNrZXRDb250ZW50cyhbXCJicmFuY2gtYS9fbmV4dC9zdGF0aWMvb2xkLmpzXCJdKTtcblxuICAgIGF3YWl0IHBydW5lKFwiYnJhbmNoLWFcIik7XG5cbiAgICBleHBlY3QobGlzdFByZWZpeGVzKCkpLnRvRXF1YWwoW1wiYnJhbmNoLWEvX25leHQvXCJdKTtcbiAgfSk7XG5cbiAgLy8gQSBzaWJsaW5nIGFwcCB3aG9zZSBwcmVmaXggc3RhcnRzIHdpdGggdGhpcyBvbmUncyAoXCJicmFuY2gtYS1zdGFnaW5nXCIpIGlzIGFcbiAgLy8gZGlmZmVyZW50IGFwcCdzIG9iamVjdHMsIGV2ZW4gdGhvdWdoIGl0cyBrZXlzIHN0YXJ0IHdpdGggXCJicmFuY2gtYVwiLlxuICBpdChcImxlYXZlcyBhIHNpYmxpbmcgcHJlZml4J3MgYXNzZXRzIGFsb25lXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBsb25nQWdvID0gbmV3IERhdGUoRGF0ZS5ub3coKSAtIE1TX1RUTCAqIDIpO1xuICAgIGNvbnN0IGJ1Y2tldCA9IFtcbiAgICAgIFwiYnJhbmNoLWEvX25leHQvc3RhdGljL29sZC5qc1wiLFxuICAgICAgXCJicmFuY2gtYS1zdGFnaW5nL19uZXh0L3N0YXRpYy9vbGQuanNcIixcbiAgICBdO1xuICAgIGhvbGRlci5zZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT4ge1xuICAgICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBMaXN0T2JqZWN0c1YyQ29tbWFuZCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBDb250ZW50czogYnVja2V0XG4gICAgICAgICAgICAuZmlsdGVyKChLZXkpID0+IEtleS5zdGFydHNXaXRoKGNvbW1hbmQuaW5wdXQuUHJlZml4ID8/IFwiXCIpKVxuICAgICAgICAgICAgLm1hcCgoS2V5KSA9PiAoeyBLZXksIExhc3RNb2RpZmllZDogbG9uZ0FnbyB9KSksXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBEZWxldGVPYmplY3RzQ29tbWFuZCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoeyBNZXRhZGF0YTogeyBidWlsZF9pZDogXCJidWlsZC0xXCIgfSB9KTtcbiAgICB9KTtcblxuICAgIGF3YWl0IHBydW5lKFwiYnJhbmNoLWFcIik7XG5cbiAgICBleHBlY3QoZGVsZXRlZEtleXMoKSkudG9FcXVhbChbXCJicmFuY2gtYS9fbmV4dC9zdGF0aWMvb2xkLmpzXCJdKTtcbiAgfSk7XG5cbiAgaXQoXCJ0YWtlcyBhIG5lc3RlZCBwcmVmaXggYXMgTmV4dGpzU3RhdGljQXNzZXRzIHJlc29sdmVkIGl0XCIsIGFzeW5jICgpID0+IHtcbiAgICBzdHViQnVja2V0Q29udGVudHMoW10pO1xuXG4gICAgYXdhaXQgcHJ1bmUoXCJ0ZWFtL2FwcFwiKTtcblxuICAgIGV4cGVjdChsaXN0UHJlZml4ZXMoKSkudG9FcXVhbChbXCJ0ZWFtL2FwcC9fbmV4dC9cIl0pO1xuICB9KTtcblxuICAvLyBUaGUgc2luZ2xlLWFwcCBjYXNlLCBhbmQgZXZlcnkgZGVwbG95bWVudCBwcmVkYXRpbmcgdGhlIHByZWZpeCBiZWluZ1xuICAvLyB0aHJlYWRlZCB0aHJvdWdoOiBhbiB1bnNldCBwcmVmaXggcHJ1bmVzIGBfbmV4dC9gIGF0IHRoZSBidWNrZXQgcm9vdC4gTm90XG4gIC8vIHRoZSB3aG9sZSBidWNrZXQsIHdoaWNoIGhvbGRzIGV2ZXJ5IG90aGVyIGFwcCdzIGA8YmFzZVBhdGg+L2AgYXMgd2VsbC5cbiAgaXQuZWFjaChbXG4gICAgW1wib21pdHRlZFwiLCB1bmRlZmluZWRdLFxuICAgIFtcImVtcHR5XCIsIFwiXCJdLFxuICBdKShcbiAgICBcImxpc3RzIHRoZSByb290IGBfbmV4dC9gIHdoZW4gdGhlIHByZWZpeCBpcyAlc1wiLFxuICAgIGFzeW5jIChfbGFiZWwsIHByZWZpeCkgPT4ge1xuICAgICAgc3R1YkJ1Y2tldENvbnRlbnRzKFtdKTtcblxuICAgICAgYXdhaXQgcHJ1bmUocHJlZml4KTtcblxuICAgICAgZXhwZWN0KGxpc3RQcmVmaXhlcygpKS50b0VxdWFsKFtcIl9uZXh0L1wiXSk7XG4gICAgfSxcbiAgKTtcblxuICAvLyBBbiBhcHAgYXQgXCJ0ZWFtXCIgc2hhcmVzIGl0cyBwcmVmaXggd2l0aCBvbmUgYXQgXCJ0ZWFtL2FwcFwiLCB3aG9zZVxuICAvLyBgdGVhbS9hcHAvX25leHQvYCBpcyBub3QgdW5kZXIgYHRlYW0vX25leHQvYC5cbiAgaXQoXCJsZWF2ZXMgYSBuZXN0ZWQgYXBwJ3MgYXNzZXRzIG91dCBvZiB0aGUgbGlzdGluZ1wiLCBhc3luYyAoKSA9PiB7XG4gICAgc3R1YkJ1Y2tldENvbnRlbnRzKFtdKTtcblxuICAgIGF3YWl0IHBydW5lKFwidGVhbVwiKTtcblxuICAgIGV4cGVjdChsaXN0UHJlZml4ZXMoKSkudG9FcXVhbChbXCJ0ZWFtL19uZXh0L1wiXSk7XG4gIH0pO1xuXG4gIGl0KFwic3RpbGwgZGVsZXRlcyBzdGFsZSBvYmplY3RzIHdpdGhpbiB0aGUgcHJlZml4XCIsIGFzeW5jICgpID0+IHtcbiAgICBzdHViQnVja2V0Q29udGVudHMoW1xuICAgICAgXCJicmFuY2gtYS9fbmV4dC9zdGF0aWMvb2xkLmpzXCIsXG4gICAgICBcImJyYW5jaC1hL19uZXh0L3N0YXRpYy9vbGRlci5jc3NcIixcbiAgICBdKTtcblxuICAgIGF3YWl0IHBydW5lKFwiYnJhbmNoLWFcIik7XG5cbiAgICBleHBlY3QoZGVsZXRlZEtleXMoKS5zb3J0KCkpLnRvRXF1YWwoW1xuICAgICAgXCJicmFuY2gtYS9fbmV4dC9zdGF0aWMvb2xkLmpzXCIsXG4gICAgICBcImJyYW5jaC1hL19uZXh0L3N0YXRpYy9vbGRlci5jc3NcIixcbiAgICBdKTtcbiAgfSk7XG5cbiAgaXQoXCJrZWVwcyBvYmplY3RzIGNhcnJ5aW5nIHRoZSBjdXJyZW50IGJ1aWxkIGlkXCIsIGFzeW5jICgpID0+IHtcbiAgICBzdHViQnVja2V0Q29udGVudHMoW1wiYnJhbmNoLWEvY3VycmVudC5qc1wiXSwgQ1VSUkVOVF9CVUlMRF9JRCk7XG5cbiAgICBhd2FpdCBwcnVuZShcImJyYW5jaC1hXCIpO1xuXG4gICAgZXhwZWN0KGRlbGV0ZWRLZXlzKCkpLnRvRXF1YWwoW10pO1xuICB9KTtcblxuICAvLyBBc3NlcnRlZCBvbiB0aGUgbGl0ZXJhbCBrZXkgcmF0aGVyIHRoYW4gdGhyb3VnaCBhIHNoYXJlZCBjb25zdGFudDogdGhlIG5hbWVcbiAgLy8gaXMgYSBjb250cmFjdCB3aXRoIENESywgd2hpY2ggbG93ZXJjYXNlcyB0aGUgYG1ldGFkYXRhOiB7IEJVSUxEX0lEIH1gIHRoYXRcbiAgLy8gYE5leHRqc1N0YXRpY0Fzc2V0c2AgcGFzc2VzIGBCdWNrZXREZXBsb3ltZW50YC4gUmVhZGluZyBhbnkgb3RoZXIgbmFtZSDigJQgdGhpc1xuICAvLyBmaWxlIHJlYWQgXCJuZXh0LWJ1aWxkLWlkXCIgZm9yIGEgbG9uZyB0aW1lIOKAlCBtYWtlcyBgb2JqZWN0QnVpbGRJZGAgYWx3YXlzXG4gIC8vIGB1bmRlZmluZWRgLCBhbmQgYSBndWFyZCB0aGF0IG5ldmVyIGZpcmVzIGNhbm5vdCBiZSB0b2xkIGZyb20gb25lIHRoYXQgaGFzXG4gIC8vIG5vdGhpbmcgdG8ga2VlcC5cbiAgaXQoXCJyZWFkcyB0aGUgYnVpbGQgaWQgZnJvbSB0aGUgbWV0YWRhdGEga2V5IEJ1Y2tldERlcGxveW1lbnQgd3JpdGVzXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBsb25nQWdvID0gbmV3IERhdGUoRGF0ZS5ub3coKSAtIE1TX1RUTCAqIDIpO1xuICAgIGhvbGRlci5zZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT4ge1xuICAgICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBMaXN0T2JqZWN0c1YyQ29tbWFuZCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBDb250ZW50czogW3sgS2V5OiBcImJyYW5jaC1hL2N1cnJlbnQuanNcIiwgTGFzdE1vZGlmaWVkOiBsb25nQWdvIH1dLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGlmIChjb21tYW5kIGluc3RhbmNlb2YgRGVsZXRlT2JqZWN0c0NvbW1hbmQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgTWV0YWRhdGE6IHsgYnVpbGRfaWQ6IENVUlJFTlRfQlVJTERfSUQgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgYXdhaXQgcHJ1bmUoXCJicmFuY2gtYVwiKTtcblxuICAgIGV4cGVjdChkZWxldGVkS2V5cygpKS50b0VxdWFsKFtdKTtcbiAgfSk7XG5cbiAgLy8gTm90IHRoaXMgY29uc3RydWN0J3Mgb2JqZWN0OiBgQnVja2V0RGVwbG95bWVudGAgc3RhbXBzIGV2ZXJ5IGZpbGUgaXQgdXBsb2FkcyxcbiAgLy8gc28gYW4gdW5zdGFtcGVkIG9uZSBiZWxvbmdzIHRvIHNvbWV0aGluZyBlbHNlIHNoYXJpbmcgdGhlIGJ1Y2tldC4gRGVsZXRpbmcgaXRcbiAgLy8gNDA0cyB3aGF0ZXZlciBzZXJ2ZXMgaXQsIHdoaWxlIGtlZXBpbmcgaXQgb25seSBjb3N0cyBzdG9yYWdlLlxuICBpdChcImtlZXBzIGFuIG9iamVjdCB0aGF0IGNhcnJpZXMgbm8gYnVpbGQgaWQgYXQgYWxsXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBsb25nQWdvID0gbmV3IERhdGUoRGF0ZS5ub3coKSAtIE1TX1RUTCAqIDIpO1xuICAgIGhvbGRlci5zZW5kLm1vY2tJbXBsZW1lbnRhdGlvbigoY29tbWFuZDogdW5rbm93bikgPT4ge1xuICAgICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBMaXN0T2JqZWN0c1YyQ29tbWFuZCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBDb250ZW50czogW1xuICAgICAgICAgICAgeyBLZXk6IFwiYnJhbmNoLWEvc29tZW9uZS1lbHNlcy5qc1wiLCBMYXN0TW9kaWZpZWQ6IGxvbmdBZ28gfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGlmIChjb21tYW5kIGluc3RhbmNlb2YgRGVsZXRlT2JqZWN0c0NvbW1hbmQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHsgTWV0YWRhdGE6IHt9IH0pO1xuICAgIH0pO1xuXG4gICAgYXdhaXQgcHJ1bmUoXCJicmFuY2gtYVwiKTtcblxuICAgIGV4cGVjdChkZWxldGVkS2V5cygpKS50b0VxdWFsKFtdKTtcbiAgfSk7XG5cbiAgLy8gVGhlIGNvbnN0cnVjdCBhbHdheXMgaGFuZHMgb3ZlciBhIGJhcmUgcHJlZml4LCBidXRcbiAgLy8gYG92ZXJyaWRlcy5jdXN0b21SZXNvdXJjZVByb3BlcnRpZXMuc3RhdGljQXNzZXRzS2V5UHJlZml4YCByZWFjaGVzIHRoaXNcbiAgLy8gZGlyZWN0bHkuIFwiYmFzZS9cIiB3b3VsZCBidWlsZCBhIFByZWZpeCBvZiBcImJhc2UvL1wiIGFuZCBcIi9iYXNlXCIgb25lIG9mXG4gIC8vIFwiL2Jhc2UvXCIsIG5laXRoZXIgb2Ygd2hpY2ggbWF0Y2hlcyBhbnkga2V5LCBzbyBwcnVuaW5nIHdvdWxkIHNpbGVudGx5IHN0b3BcbiAgLy8gZGVsZXRpbmcgYW55dGhpbmcgYXQgYWxsLlxuICBpdC5lYWNoKFtcbiAgICBbXCJhIHRyYWlsaW5nIHNsYXNoXCIsIFwiYnJhbmNoLWEvXCJdLFxuICAgIFtcImEgbGVhZGluZyBzbGFzaFwiLCBcIi9icmFuY2gtYVwiXSxcbiAgICBbXCJib3RoXCIsIFwiL2JyYW5jaC1hL1wiXSxcbiAgXSkoXCJub3JtYWxpemVzIGEgcHJlZml4IGdpdmVuIHdpdGggJXNcIiwgYXN5bmMgKF9sYWJlbCwgcHJlZml4KSA9PiB7XG4gICAgc3R1YkJ1Y2tldENvbnRlbnRzKFtdKTtcblxuICAgIGF3YWl0IHBydW5lKHByZWZpeCk7XG5cbiAgICBleHBlY3QobGlzdFByZWZpeGVzKCkpLnRvRXF1YWwoW1wiYnJhbmNoLWEvX25leHQvXCJdKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoXCJwYWdpbmF0aW9uXCIsICgpID0+IHtcbiAgICBpdChcImZvbGxvd3MgdGhlIGNvbnRpbnVhdGlvbiB0b2tlbiBhY3Jvc3MgcGFnZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgc3R1YlBhZ2VkQnVja2V0Q29udGVudHMoW1tcImEvb25lLmpzXCJdLCBbXCJhL3R3by5qc1wiXSwgW1wiYS90aHJlZS5qc1wiXV0pO1xuXG4gICAgICBhd2FpdCBwcnVuZShcImFcIik7XG5cbiAgICAgIGV4cGVjdChcbiAgICAgICAgc2VudENvbW1hbmRzKExpc3RPYmplY3RzVjJDb21tYW5kKS5tYXAoXG4gICAgICAgICAgKGNvbW1hbmQpID0+IGNvbW1hbmQuaW5wdXQuQ29udGludWF0aW9uVG9rZW4sXG4gICAgICAgICksXG4gICAgICApLnRvRXF1YWwoW3VuZGVmaW5lZCwgXCJwYWdlLTFcIiwgXCJwYWdlLTJcIl0pO1xuICAgICAgZXhwZWN0KGRlbGV0ZWRLZXlzKCkuc29ydCgpKS50b0VxdWFsKFtcbiAgICAgICAgXCJhL29uZS5qc1wiLFxuICAgICAgICBcImEvdGhyZWUuanNcIixcbiAgICAgICAgXCJhL3R3by5qc1wiLFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICAvLyBUaGUgbGFzdCBwYWdlIGNhcnJpZXMgbm8gTmV4dENvbnRpbnVhdGlvblRva2VuLiBIb2xkaW5nIG9uIHRvIHRoZSBwcmV2aW91c1xuICAgIC8vIHBhZ2UncyB0b2tlbiByZS1saXN0cyB0aGF0IHBhZ2UgdW50aWwgdGhlIDEwMC1pdGVyYXRpb24gZ3VhcmQgdHJpcHMsXG4gICAgLy8gcmUtSEVBRGluZyBldmVyeSBvYmplY3Qgb24gaXQgMTAwIHRpbWVzIG92ZXIgKH4xMDBrIHJlcXVlc3RzIGZvciBhIGZ1bGxcbiAgICAvLyAxMDAwLWtleSBwYWdlKSBhbmQgcHVzaGluZyBkdXBsaWNhdGUga2V5cyBpbnRvIHRoZSBkZWxldGUgYmF0Y2hlcyDigJQgZW5vdWdoXG4gICAgLy8gdG8gYmxvdyB0aGUgcG9zdC1kZXBsb3kgTGFtYmRhJ3MgdGltZW91dCwgd2hpY2ggbGVhdmVzIHRoZSBjdXN0b20gcmVzb3VyY2VcbiAgICAvLyB3YWl0aW5nIG9uIGEgcmVzcG9uc2UgdGhhdCBuZXZlciBjb21lcy5cbiAgICBpdChcInN0b3BzIGxpc3Rpbmcgb25jZSBhIHBhZ2UgcmV0dXJucyBubyBjb250aW51YXRpb24gdG9rZW5cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgc3R1YlBhZ2VkQnVja2V0Q29udGVudHMoW1tcImEvb25lLmpzXCJdLCBbXCJhL3R3by5qc1wiXV0pO1xuXG4gICAgICBhd2FpdCBwcnVuZShcImFcIik7XG5cbiAgICAgIGV4cGVjdChzZW50Q29tbWFuZHMoTGlzdE9iamVjdHNWMkNvbW1hbmQpKS50b0hhdmVMZW5ndGgoMik7XG4gICAgICBleHBlY3QoZGVsZXRlZEtleXMoKSkudG9FcXVhbChbXCJhL29uZS5qc1wiLCBcImEvdHdvLmpzXCJdKTtcbiAgICB9KTtcblxuICAgIC8vIFMzIHNjYW5zIGEgd2luZG93IG9mIHRoZSBidWNrZXQgcGVyIHJlcXVlc3QgYW5kIGZpbHRlcnMgYnkgYFByZWZpeGBcbiAgICAvLyBhZnRlcndhcmRzLCBzbyBhIHBhZ2UgY2FuIGNvbWUgYmFjayB3aXRoIG5vIGBDb250ZW50c2AgYW5kIHN0aWxsIGhhdmUgYVxuICAgIC8vIGNvbnRpbnVhdGlvbiB0b2tlbiDigJQgZXhhY3RseSB0aGUgc2hhcmVkLWJ1Y2tldCBjYXNlIGBrZXlQcmVmaXhgIGV4aXN0cyBmb3IuXG4gICAgLy8gU3RvcHBpbmcgdGhlcmUgbGVmdCBldmVyeSBvbGRlciBhc3NldCBwYXN0IHRoYXQgd2luZG93IHVuZGVsZXRlZCwgYW5kIHRoZVxuICAgIC8vIGJ1Y2tldCBncmV3IHdpdGhvdXQgYm91bmQgd2l0aCBub3RoaW5nIGluIHRoZSBsb2dzIHRvIHNheSBzby5cbiAgICBpdChcImtlZXBzIGxpc3RpbmcgcGFzdCBhIHBhZ2Ugd2hvc2Ugd2luZG93IGhlbGQgbm8gbWF0Y2hpbmcga2V5XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIHN0dWJQYWdlZEJ1Y2tldENvbnRlbnRzKFtbXCJhL29uZS5qc1wiXSwgW10sIFtcImEvdGhyZWUuanNcIl1dKTtcblxuICAgICAgYXdhaXQgcHJ1bmUoXCJhXCIpO1xuXG4gICAgICBleHBlY3Qoc2VudENvbW1hbmRzKExpc3RPYmplY3RzVjJDb21tYW5kKSkudG9IYXZlTGVuZ3RoKDMpO1xuICAgICAgZXhwZWN0KGRlbGV0ZWRLZXlzKCkuc29ydCgpKS50b0VxdWFsKFtcImEvb25lLmpzXCIsIFwiYS90aHJlZS5qc1wiXSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
@@ -0,0 +1,13 @@
1
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
2
+ import { Construct } from 'constructs';
3
+ /**
4
+ * Props for RedeployStageFunction
5
+ */
6
+ export interface RedeployStageFunctionProps extends lambda.FunctionOptions {
7
+ }
8
+ /**
9
+ * An AWS Lambda function which executes src/lambdas/redeploy-stage/redeploy-stage.
10
+ */
11
+ export declare class RedeployStageFunction extends lambda.Function {
12
+ constructor(scope: Construct, id: string, props?: RedeployStageFunctionProps);
13
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.RedeployStageFunction = void 0;
37
+ // ~~ Generated by projen. To modify, edit .projenrc.ts and run "pnpm dlx projen".
38
+ const path = __importStar(require("path"));
39
+ const lambda = __importStar(require("aws-cdk-lib/aws-lambda"));
40
+ /**
41
+ * An AWS Lambda function which executes src/lambdas/redeploy-stage/redeploy-stage.
42
+ */
43
+ class RedeployStageFunction extends lambda.Function {
44
+ constructor(scope, id, props) {
45
+ super(scope, id, {
46
+ description: 'src/lambdas/redeploy-stage/redeploy-stage.lambda.ts',
47
+ ...props,
48
+ runtime: new lambda.Runtime('nodejs24.x', lambda.RuntimeFamily.NODEJS),
49
+ handler: 'index.handler',
50
+ code: lambda.Code.fromAsset(path.join(__dirname, '../../../assets/lambdas/redeploy-stage/redeploy-stage.lambda')),
51
+ });
52
+ }
53
+ }
54
+ exports.RedeployStageFunction = RedeployStageFunction;
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkZXBsb3ktc3RhZ2UtZnVuY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhcy9yZWRlcGxveS1zdGFnZS9yZWRlcGxveS1zdGFnZS1mdW5jdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxrRkFBa0Y7QUFDbEYsMkNBQTZCO0FBQzdCLCtEQUFpRDtBQVNqRDs7R0FFRztBQUNILE1BQWEscUJBQXNCLFNBQVEsTUFBTSxDQUFDLFFBQVE7SUFDeEQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFrQztRQUMxRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLFdBQVcsRUFBRSxxREFBcUQ7WUFDbEUsR0FBRyxLQUFLO1lBQ1IsT0FBTyxFQUFFLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUM7WUFDdEUsT0FBTyxFQUFFLGVBQWU7WUFDeEIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLDhEQUE4RCxDQUFDLENBQUM7U0FDbEgsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBVkQsc0RBVUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyB+fiBHZW5lcmF0ZWQgYnkgcHJvamVuLiBUbyBtb2RpZnksIGVkaXQgLnByb2plbnJjLnRzIGFuZCBydW4gXCJwbnBtIGRseCBwcm9qZW5cIi5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuLyoqXG4gKiBQcm9wcyBmb3IgUmVkZXBsb3lTdGFnZUZ1bmN0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVkZXBsb3lTdGFnZUZ1bmN0aW9uUHJvcHMgZXh0ZW5kcyBsYW1iZGEuRnVuY3Rpb25PcHRpb25zIHtcbn1cblxuLyoqXG4gKiBBbiBBV1MgTGFtYmRhIGZ1bmN0aW9uIHdoaWNoIGV4ZWN1dGVzIHNyYy9sYW1iZGFzL3JlZGVwbG95LXN0YWdlL3JlZGVwbG95LXN0YWdlLlxuICovXG5leHBvcnQgY2xhc3MgUmVkZXBsb3lTdGFnZUZ1bmN0aW9uIGV4dGVuZHMgbGFtYmRhLkZ1bmN0aW9uIHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM/OiBSZWRlcGxveVN0YWdlRnVuY3Rpb25Qcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwge1xuICAgICAgZGVzY3JpcHRpb246ICdzcmMvbGFtYmRhcy9yZWRlcGxveS1zdGFnZS9yZWRlcGxveS1zdGFnZS5sYW1iZGEudHMnLFxuICAgICAgLi4ucHJvcHMsXG4gICAgICBydW50aW1lOiBuZXcgbGFtYmRhLlJ1bnRpbWUoJ25vZGVqczI0LngnLCBsYW1iZGEuUnVudGltZUZhbWlseS5OT0RFSlMpLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi8uLi9hc3NldHMvbGFtYmRhcy9yZWRlcGxveS1zdGFnZS9yZWRlcGxveS1zdGFnZS5sYW1iZGEnKSksXG4gICAgfSk7XG4gIH1cbn0iXX0=
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Marks the deployments this function makes, so a later run prunes only its
3
+ * own. CloudFormation owns every other deployment on the API and deletes them
4
+ * itself.
5
+ */
6
+ export declare const REDEPLOY_DESCRIPTION_PREFIX = "cdk-nextjs: redeploy after";
7
+ export interface RedeployStageInput {
8
+ readonly restApiId: string;
9
+ readonly stageName: string;
10
+ /** The stack status that triggered the run, for the description. */
11
+ readonly stackStatus: string;
12
+ }
13
+ /**
14
+ * Deploys `stageName` again from the API as it is now, then deletes the
15
+ * deployments earlier runs made that no stage still points at.
16
+ *
17
+ * Why: CloudFormation creates the new `AWS::ApiGateway::Deployment` while
18
+ * resources removed from the template still exist (it deletes them only in
19
+ * `UPDATE_COMPLETE_CLEANUP_IN_PROGRESS`), so that snapshot keeps them. A
20
+ * removed function group's `/api/{proxy+}` stays routable, to a Lambda that is
21
+ * then deleted, and API Gateway answers 500 until the next deployment. This
22
+ * runs on `UPDATE_COMPLETE`, after cleanup, so its snapshot is the real tree.
23
+ */
24
+ export declare function redeployStage({ restApiId, stageName, stackStatus, }: RedeployStageInput): Promise<string>;