cdk-nextjs 0.7.6 → 0.7.8

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 (65) hide show
  1. package/.jsii +3 -3
  2. package/.jsii.tabl.json +1 -1
  3. package/README.md +12 -3
  4. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +31 -13
  5. package/docs/adapter-runtime.md +1 -1
  6. package/docs/caching-guide.md +11 -1
  7. package/docs/harness-coverage.md +154 -73
  8. package/lib/adapter/adapter.mjs +12 -3
  9. package/lib/adapter/aws-cache-store.d.ts +221 -3
  10. package/lib/adapter/aws-cache-store.js +481 -35
  11. package/lib/adapter/aws-cache-store.test.js +706 -3
  12. package/lib/adapter/cache-handler.d.ts +5 -3
  13. package/lib/adapter/cache-handler.js +16 -10
  14. package/lib/adapter/cache-handler.mjs +517 -49
  15. package/lib/adapter/cache-handler.test.js +44 -1
  16. package/lib/adapter/cache-utils.d.ts +22 -0
  17. package/lib/adapter/cache-utils.js +44 -1
  18. package/lib/adapter/function-groups.js +17 -4
  19. package/lib/adapter/function-groups.test.js +33 -1
  20. package/lib/adapter/memory-cache-handler.d.ts +5 -1
  21. package/lib/adapter/memory-cache-handler.js +6 -2
  22. package/lib/adapter/s3-cache-handler.d.ts +12 -1
  23. package/lib/adapter/s3-cache-handler.js +30 -8
  24. package/lib/adapter/s3-cache-handler.test.js +84 -2
  25. package/lib/adapter/use-cache-common.d.ts +66 -1
  26. package/lib/adapter/use-cache-common.js +142 -19
  27. package/lib/adapter/use-cache-common.test.js +174 -1
  28. package/lib/adapter/use-cache-default-handler.js +36 -6
  29. package/lib/adapter/use-cache-default-handler.mjs +553 -47
  30. package/lib/adapter/use-cache-handlers.test.js +247 -7
  31. package/lib/adapter/use-cache-remote-handler.js +9 -7
  32. package/lib/adapter/use-cache-remote-handler.mjs +542 -45
  33. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +2 -1
  34. package/lib/lambdas/post-deploy/prune-revalidation-table.js +35 -13
  35. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +19 -1
  36. package/lib/nextjs-api.js +1 -1
  37. package/lib/nextjs-build/nextjs-build.js +1 -1
  38. package/lib/nextjs-cache.js +1 -1
  39. package/lib/nextjs-compute/nextjs-containers.js +1 -1
  40. package/lib/nextjs-compute/nextjs-functions.js +1 -1
  41. package/lib/nextjs-distribution.js +1 -1
  42. package/lib/nextjs-post-deploy.js +1 -1
  43. package/lib/nextjs-static-assets.js +1 -1
  44. package/lib/root-constructs/nextjs-base-construct.js +1 -1
  45. package/lib/root-constructs/nextjs-global-containers.js +1 -1
  46. package/lib/root-constructs/nextjs-global-functions.js +1 -1
  47. package/lib/root-constructs/nextjs-regional-containers.js +1 -1
  48. package/lib/root-constructs/nextjs-regional-functions.js +1 -1
  49. package/lib/runtime/core.js +20 -4
  50. package/lib/runtime/core.test.js +17 -1
  51. package/lib/runtime/image-utils.d.ts +8 -9
  52. package/lib/runtime/image-utils.js +16 -1
  53. package/lib/runtime/image-utils.test.js +13 -1
  54. package/lib/runtime/image.js +9 -3
  55. package/lib/runtime/lambda.mjs +66 -18
  56. package/lib/runtime/server.mjs +66 -18
  57. package/lib/runtime/tag-manifest.d.ts +40 -0
  58. package/lib/runtime/tag-manifest.js +59 -0
  59. package/lib/runtime/tag-manifest.test.d.ts +1 -0
  60. package/lib/runtime/tag-manifest.test.js +47 -0
  61. package/package.json +3 -3
  62. package/scripts/e2e-deploy.sh +7 -2
  63. package/scripts/e2e-harness/README.md +72 -35
  64. package/scripts/e2e-harness/screen.mjs +148 -7
  65. package/scripts/playwright-install-deps.sh +40 -0
@@ -25058,7 +25058,7 @@ var require_dist_cjs11 = __commonJS({
25058
25058
  var { setCredentialFeature: setCredentialFeature2 } = (init_client3(), __toCommonJS(client_exports2));
25059
25059
  var { CredentialsProviderError: CredentialsProviderError2, parseKnownFiles: parseKnownFiles2, getProfileName: getProfileName2 } = (init_config2(), __toCommonJS(config_exports));
25060
25060
  var { HttpRequest: HttpRequest2 } = (init_protocols(), __toCommonJS(protocols_exports));
25061
- var { createHash: createHash6, createPrivateKey, createPublicKey, sign: sign3 } = __require("node:crypto");
25061
+ var { createHash: createHash7, createPrivateKey, createPublicKey, sign: sign3 } = __require("node:crypto");
25062
25062
  var { promises } = __require("node:fs");
25063
25063
  var { homedir: homedir2 } = __require("node:os");
25064
25064
  var { dirname: dirname3, join: join12 } = __require("node:path");
@@ -25227,7 +25227,7 @@ var require_dist_cjs11 = __commonJS({
25227
25227
  getTokenFilePath() {
25228
25228
  const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join12(homedir2(), ".aws", "login", "cache");
25229
25229
  const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
25230
- const loginSessionSha256 = createHash6("sha256").update(loginSessionBytes).digest("hex");
25230
+ const loginSessionSha256 = createHash7("sha256").update(loginSessionBytes).digest("hex");
25231
25231
  return join12(directory, `${loginSessionSha256}.json`);
25232
25232
  }
25233
25233
  derToRawSignature(derSignature) {
@@ -35889,9 +35889,9 @@ var require_dist_cjs16 = __commonJS({
35889
35889
  }
35890
35890
  });
35891
35891
 
35892
- // node_modules/.pnpm/@next+routing@16.3.8/node_modules/@next/routing/dist/index.js
35892
+ // node_modules/.pnpm/@next+routing@16.4.0/node_modules/@next/routing/dist/index.js
35893
35893
  var require_dist = __commonJS({
35894
- "node_modules/.pnpm/@next+routing@16.3.8/node_modules/@next/routing/dist/index.js"(exports, module) {
35894
+ "node_modules/.pnpm/@next+routing@16.4.0/node_modules/@next/routing/dist/index.js"(exports, module) {
35895
35895
  (() => {
35896
35896
  "use strict";
35897
35897
  var e5 = {};
@@ -36012,22 +36012,37 @@ var require_dist = __commonJS({
36012
36012
  return true;
36013
36013
  }
36014
36014
  function replaceDestination(e6, t8, n4) {
36015
- let a5 = e6;
36015
+ const a5 = Object.keys(n4);
36016
36016
  if (t8) {
36017
36017
  for (let e7 = 1; e7 < t8.length; e7++) {
36018
- const n5 = t8[e7] ?? "";
36019
- a5 = a5.replace(new RegExp(`\\$${e7}`, "g"), n5);
36018
+ a5.push(String(e7));
36020
36019
  }
36021
36020
  if (t8.groups) {
36022
- for (const [e7, n5] of Object.entries(t8.groups)) {
36023
- a5 = a5.replace(new RegExp(`\\$${e7}`, "g"), n5 ?? "");
36024
- }
36021
+ a5.push(...Object.keys(t8.groups));
36025
36022
  }
36026
36023
  }
36027
- for (const [e7, t9] of Object.entries(n4)) {
36028
- a5 = a5.replace(new RegExp(`\\$${e7}`, "g"), t9);
36024
+ if (a5.length === 0) {
36025
+ return e6;
36029
36026
  }
36030
- return a5;
36027
+ const s2 = a5.sort(((e7, t9) => t9.length - e7.length)).map(((e7) => {
36028
+ const t9 = e7.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
36029
+ return /^\d+$/.test(e7) ? `${t9}(?!\\d)` : t9;
36030
+ })).join("|");
36031
+ return e6.replace(new RegExp(`\\$(${s2})`, "g"), ((e7, a6) => {
36032
+ if (t8) {
36033
+ const e8 = Number(a6);
36034
+ if (Number.isInteger(e8) && e8 > 0 && e8 < t8.length && String(e8) === a6) {
36035
+ return t8[e8] ?? "";
36036
+ }
36037
+ if (t8.groups && Object.hasOwn(t8.groups, a6)) {
36038
+ return t8.groups[a6] ?? "";
36039
+ }
36040
+ }
36041
+ if (Object.hasOwn(n4, a6)) {
36042
+ return n4[a6];
36043
+ }
36044
+ return e7;
36045
+ }));
36031
36046
  }
36032
36047
  function isExternalDestination(e6) {
36033
36048
  return e6.startsWith("http://") || e6.startsWith("https://");
@@ -38023,6 +38038,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
38023
38038
 
38024
38039
  // src/runtime/image-utils.ts
38025
38040
  var import_client_s32 = __toESM(require_dist_cjs16());
38041
+ import { createHash as createHash6 } from "node:crypto";
38026
38042
  async function fetchFromS3(s32, bucket, url, location, maximumBody) {
38027
38043
  const { urlBasePath, keyPrefix } = location;
38028
38044
  const path = withoutAssetPrefix(url.split(/[?#]/, 1)[0], location);
@@ -38070,6 +38086,12 @@ var ImageTooLargeError = class extends Error {
38070
38086
  this.name = "ImageTooLargeError";
38071
38087
  }
38072
38088
  };
38089
+ function extractEtag(etag, imageBuffer) {
38090
+ if (etag) {
38091
+ return Buffer.from(etag).toString("base64url");
38092
+ }
38093
+ return createHash6("sha256").update(imageBuffer).digest("base64url");
38094
+ }
38073
38095
  function resolveErrorResponse(error2, ImageError) {
38074
38096
  if (error2 instanceof ImageError) {
38075
38097
  return { statusCode: error2.statusCode, message: error2.message };
@@ -38241,6 +38263,9 @@ var RuntimeImageOptimizer = class {
38241
38263
  waitUntil
38242
38264
  }
38243
38265
  );
38266
+ if (entry && "error" in entry) {
38267
+ throw entry.error;
38268
+ }
38244
38269
  const value = entry?.value;
38245
38270
  if (value?.kind !== IMAGE_KIND) {
38246
38271
  throw new Error("The image cache returned no image entry");
@@ -38296,7 +38321,8 @@ var RuntimeImageOptimizer = class {
38296
38321
  buffer: result.buffer,
38297
38322
  contentType: result.contentType,
38298
38323
  cacheControl: null,
38299
- etag: result.etag
38324
+ // Encoded as for a route's response: `fetchInternalImage` does too.
38325
+ etag: extractEtag(result.etag, result.buffer)
38300
38326
  };
38301
38327
  } catch (error2) {
38302
38328
  const missing = error2 instanceof Error && error2.name === "NoSuchKey";
@@ -38326,7 +38352,7 @@ var RuntimeImageOptimizer = class {
38326
38352
  buffer: response.body,
38327
38353
  contentType: firstValue(response.headers["content-type"]) ?? null,
38328
38354
  cacheControl: firstValue(response.headers["cache-control"]) ?? null,
38329
- etag: optimizer.extractEtag(
38355
+ etag: extractEtag(
38330
38356
  firstValue(response.headers.etag) ?? null,
38331
38357
  response.body
38332
38358
  )
@@ -38647,7 +38673,26 @@ function httpDate(value) {
38647
38673
  return date2 && !Number.isNaN(date2.getTime()) ? date2 : void 0;
38648
38674
  }
38649
38675
 
38676
+ // src/runtime/tag-manifest.ts
38677
+ import { AsyncLocalStorage } from "node:async_hooks";
38678
+ var OUTSIDE_REQUEST_SYMBOL = /* @__PURE__ */ Symbol.for(
38679
+ "cdk-nextjs.outside-request-context"
38680
+ );
38681
+ function captureOutsideRequest() {
38682
+ const global = globalThis;
38683
+ global[OUTSIDE_REQUEST_SYMBOL] ??= AsyncLocalStorage.snapshot();
38684
+ }
38685
+ var TAG_MANIFEST_SYMBOL = /* @__PURE__ */ Symbol.for(
38686
+ "cdk-nextjs.use-cache.tag-manifest"
38687
+ );
38688
+ async function catchUpTags(render) {
38689
+ const global = globalThis;
38690
+ const manifest = global[TAG_MANIFEST_SYMBOL];
38691
+ return manifest ? manifest.catchUp(render) : render();
38692
+ }
38693
+
38650
38694
  // src/runtime/core.ts
38695
+ captureOutsideRequest();
38651
38696
  var NextjsRuntime = class {
38652
38697
  constructor(options) {
38653
38698
  this.options = options;
@@ -38794,7 +38839,7 @@ var NextjsRuntime = class {
38794
38839
  const search = toSearch(invocationQuery);
38795
38840
  req.url = search ? `${pathname}?${search}` : pathname;
38796
38841
  req.headers = toIncomingHttpHeaders(result.requestHeaders);
38797
- await handler2(req, asServerResponse(res), {
38842
+ const options = {
38798
38843
  waitUntil,
38799
38844
  requestMeta: {
38800
38845
  // The resolved query, stated rather than left to be re-derived.
@@ -38869,7 +38914,9 @@ var NextjsRuntime = class {
38869
38914
  // mocked `req`/`res`).
38870
38915
  revalidate: (config) => this.revalidate(config, request)
38871
38916
  }
38872
- });
38917
+ };
38918
+ const render = () => handler2(req, asServerResponse(res), options);
38919
+ await (result.entrypoint.type === "app-page" ? catchUpTags(render) : render());
38873
38920
  if (!res.writableEnded && result.entrypoint.type !== "page-api") {
38874
38921
  res.end();
38875
38922
  }
@@ -39156,7 +39203,8 @@ var NextjsRuntime = class {
39156
39203
  if (target.kind === "entrypoint") {
39157
39204
  const handler2 = await this.entrypoints.load(target.entrypoint);
39158
39205
  req.url = requestedUrl ?? req.url;
39159
- await handler2(req, asServerResponse(res), { waitUntil });
39206
+ const render = () => handler2(req, asServerResponse(res), { waitUntil });
39207
+ await (target.entrypoint.type === "app-page" ? catchUpTags(render) : render());
39160
39208
  if (!res.writableEnded) {
39161
39209
  res.end();
39162
39210
  }
@@ -25058,7 +25058,7 @@ var require_dist_cjs11 = __commonJS({
25058
25058
  var { setCredentialFeature: setCredentialFeature2 } = (init_client3(), __toCommonJS(client_exports2));
25059
25059
  var { CredentialsProviderError: CredentialsProviderError2, parseKnownFiles: parseKnownFiles2, getProfileName: getProfileName2 } = (init_config2(), __toCommonJS(config_exports));
25060
25060
  var { HttpRequest: HttpRequest2 } = (init_protocols(), __toCommonJS(protocols_exports));
25061
- var { createHash: createHash6, createPrivateKey, createPublicKey, sign: sign3 } = __require("node:crypto");
25061
+ var { createHash: createHash7, createPrivateKey, createPublicKey, sign: sign3 } = __require("node:crypto");
25062
25062
  var { promises } = __require("node:fs");
25063
25063
  var { homedir: homedir2 } = __require("node:os");
25064
25064
  var { dirname: dirname3, join: join12 } = __require("node:path");
@@ -25227,7 +25227,7 @@ var require_dist_cjs11 = __commonJS({
25227
25227
  getTokenFilePath() {
25228
25228
  const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join12(homedir2(), ".aws", "login", "cache");
25229
25229
  const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
25230
- const loginSessionSha256 = createHash6("sha256").update(loginSessionBytes).digest("hex");
25230
+ const loginSessionSha256 = createHash7("sha256").update(loginSessionBytes).digest("hex");
25231
25231
  return join12(directory, `${loginSessionSha256}.json`);
25232
25232
  }
25233
25233
  derToRawSignature(derSignature) {
@@ -35889,9 +35889,9 @@ var require_dist_cjs16 = __commonJS({
35889
35889
  }
35890
35890
  });
35891
35891
 
35892
- // node_modules/.pnpm/@next+routing@16.3.8/node_modules/@next/routing/dist/index.js
35892
+ // node_modules/.pnpm/@next+routing@16.4.0/node_modules/@next/routing/dist/index.js
35893
35893
  var require_dist = __commonJS({
35894
- "node_modules/.pnpm/@next+routing@16.3.8/node_modules/@next/routing/dist/index.js"(exports, module) {
35894
+ "node_modules/.pnpm/@next+routing@16.4.0/node_modules/@next/routing/dist/index.js"(exports, module) {
35895
35895
  (() => {
35896
35896
  "use strict";
35897
35897
  var e5 = {};
@@ -36012,22 +36012,37 @@ var require_dist = __commonJS({
36012
36012
  return true;
36013
36013
  }
36014
36014
  function replaceDestination(e6, t8, n4) {
36015
- let a5 = e6;
36015
+ const a5 = Object.keys(n4);
36016
36016
  if (t8) {
36017
36017
  for (let e7 = 1; e7 < t8.length; e7++) {
36018
- const n5 = t8[e7] ?? "";
36019
- a5 = a5.replace(new RegExp(`\\$${e7}`, "g"), n5);
36018
+ a5.push(String(e7));
36020
36019
  }
36021
36020
  if (t8.groups) {
36022
- for (const [e7, n5] of Object.entries(t8.groups)) {
36023
- a5 = a5.replace(new RegExp(`\\$${e7}`, "g"), n5 ?? "");
36024
- }
36021
+ a5.push(...Object.keys(t8.groups));
36025
36022
  }
36026
36023
  }
36027
- for (const [e7, t9] of Object.entries(n4)) {
36028
- a5 = a5.replace(new RegExp(`\\$${e7}`, "g"), t9);
36024
+ if (a5.length === 0) {
36025
+ return e6;
36029
36026
  }
36030
- return a5;
36027
+ const s2 = a5.sort(((e7, t9) => t9.length - e7.length)).map(((e7) => {
36028
+ const t9 = e7.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
36029
+ return /^\d+$/.test(e7) ? `${t9}(?!\\d)` : t9;
36030
+ })).join("|");
36031
+ return e6.replace(new RegExp(`\\$(${s2})`, "g"), ((e7, a6) => {
36032
+ if (t8) {
36033
+ const e8 = Number(a6);
36034
+ if (Number.isInteger(e8) && e8 > 0 && e8 < t8.length && String(e8) === a6) {
36035
+ return t8[e8] ?? "";
36036
+ }
36037
+ if (t8.groups && Object.hasOwn(t8.groups, a6)) {
36038
+ return t8.groups[a6] ?? "";
36039
+ }
36040
+ }
36041
+ if (Object.hasOwn(n4, a6)) {
36042
+ return n4[a6];
36043
+ }
36044
+ return e7;
36045
+ }));
36031
36046
  }
36032
36047
  function isExternalDestination(e6) {
36033
36048
  return e6.startsWith("http://") || e6.startsWith("https://");
@@ -38023,6 +38038,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
38023
38038
 
38024
38039
  // src/runtime/image-utils.ts
38025
38040
  var import_client_s32 = __toESM(require_dist_cjs16());
38041
+ import { createHash as createHash6 } from "node:crypto";
38026
38042
  async function fetchFromS3(s32, bucket, url, location, maximumBody) {
38027
38043
  const { urlBasePath, keyPrefix } = location;
38028
38044
  const path = withoutAssetPrefix(url.split(/[?#]/, 1)[0], location);
@@ -38070,6 +38086,12 @@ var ImageTooLargeError = class extends Error {
38070
38086
  this.name = "ImageTooLargeError";
38071
38087
  }
38072
38088
  };
38089
+ function extractEtag(etag, imageBuffer) {
38090
+ if (etag) {
38091
+ return Buffer.from(etag).toString("base64url");
38092
+ }
38093
+ return createHash6("sha256").update(imageBuffer).digest("base64url");
38094
+ }
38073
38095
  function resolveErrorResponse(error2, ImageError) {
38074
38096
  if (error2 instanceof ImageError) {
38075
38097
  return { statusCode: error2.statusCode, message: error2.message };
@@ -38241,6 +38263,9 @@ var RuntimeImageOptimizer = class {
38241
38263
  waitUntil
38242
38264
  }
38243
38265
  );
38266
+ if (entry && "error" in entry) {
38267
+ throw entry.error;
38268
+ }
38244
38269
  const value = entry?.value;
38245
38270
  if (value?.kind !== IMAGE_KIND) {
38246
38271
  throw new Error("The image cache returned no image entry");
@@ -38296,7 +38321,8 @@ var RuntimeImageOptimizer = class {
38296
38321
  buffer: result.buffer,
38297
38322
  contentType: result.contentType,
38298
38323
  cacheControl: null,
38299
- etag: result.etag
38324
+ // Encoded as for a route's response: `fetchInternalImage` does too.
38325
+ etag: extractEtag(result.etag, result.buffer)
38300
38326
  };
38301
38327
  } catch (error2) {
38302
38328
  const missing = error2 instanceof Error && error2.name === "NoSuchKey";
@@ -38326,7 +38352,7 @@ var RuntimeImageOptimizer = class {
38326
38352
  buffer: response.body,
38327
38353
  contentType: firstValue(response.headers["content-type"]) ?? null,
38328
38354
  cacheControl: firstValue(response.headers["cache-control"]) ?? null,
38329
- etag: optimizer.extractEtag(
38355
+ etag: extractEtag(
38330
38356
  firstValue(response.headers.etag) ?? null,
38331
38357
  response.body
38332
38358
  )
@@ -38647,7 +38673,26 @@ function httpDate(value) {
38647
38673
  return date2 && !Number.isNaN(date2.getTime()) ? date2 : void 0;
38648
38674
  }
38649
38675
 
38676
+ // src/runtime/tag-manifest.ts
38677
+ import { AsyncLocalStorage } from "node:async_hooks";
38678
+ var OUTSIDE_REQUEST_SYMBOL = /* @__PURE__ */ Symbol.for(
38679
+ "cdk-nextjs.outside-request-context"
38680
+ );
38681
+ function captureOutsideRequest() {
38682
+ const global = globalThis;
38683
+ global[OUTSIDE_REQUEST_SYMBOL] ??= AsyncLocalStorage.snapshot();
38684
+ }
38685
+ var TAG_MANIFEST_SYMBOL = /* @__PURE__ */ Symbol.for(
38686
+ "cdk-nextjs.use-cache.tag-manifest"
38687
+ );
38688
+ async function catchUpTags(render) {
38689
+ const global = globalThis;
38690
+ const manifest = global[TAG_MANIFEST_SYMBOL];
38691
+ return manifest ? manifest.catchUp(render) : render();
38692
+ }
38693
+
38650
38694
  // src/runtime/core.ts
38695
+ captureOutsideRequest();
38651
38696
  var NextjsRuntime = class {
38652
38697
  constructor(options) {
38653
38698
  this.options = options;
@@ -38794,7 +38839,7 @@ var NextjsRuntime = class {
38794
38839
  const search = toSearch(invocationQuery);
38795
38840
  req.url = search ? `${pathname}?${search}` : pathname;
38796
38841
  req.headers = toIncomingHttpHeaders(result.requestHeaders);
38797
- await handler(req, asServerResponse(res), {
38842
+ const options = {
38798
38843
  waitUntil,
38799
38844
  requestMeta: {
38800
38845
  // The resolved query, stated rather than left to be re-derived.
@@ -38869,7 +38914,9 @@ var NextjsRuntime = class {
38869
38914
  // mocked `req`/`res`).
38870
38915
  revalidate: (config) => this.revalidate(config, request)
38871
38916
  }
38872
- });
38917
+ };
38918
+ const render = () => handler(req, asServerResponse(res), options);
38919
+ await (result.entrypoint.type === "app-page" ? catchUpTags(render) : render());
38873
38920
  if (!res.writableEnded && result.entrypoint.type !== "page-api") {
38874
38921
  res.end();
38875
38922
  }
@@ -39156,7 +39203,8 @@ var NextjsRuntime = class {
39156
39203
  if (target.kind === "entrypoint") {
39157
39204
  const handler = await this.entrypoints.load(target.entrypoint);
39158
39205
  req.url = requestedUrl ?? req.url;
39159
- await handler(req, asServerResponse(res), { waitUntil });
39206
+ const render = () => handler(req, asServerResponse(res), { waitUntil });
39207
+ await (target.entrypoint.type === "app-page" ? catchUpTags(render) : render());
39160
39208
  if (!res.writableEnded) {
39161
39209
  res.end();
39162
39210
  }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The key {@link outsideRequest}'s context is kept under on `globalThis`, for
3
+ * the same reason as {@link TAG_MANIFEST_SYMBOL}.
4
+ */
5
+ export declare const OUTSIDE_REQUEST_SYMBOL: unique symbol;
6
+ /**
7
+ * Capture the context the runtime's module loads in, outside any request.
8
+ * Called once, at load; a later call keeps the first capture.
9
+ */
10
+ export declare function captureOutsideRequest(): void;
11
+ /**
12
+ * Run `fn` in the context {@link captureOutsideRequest} captured, where Next.js's
13
+ * request stores are unset: or in the current one, if nothing was captured
14
+ * (outside the runtime, as in unit tests).
15
+ *
16
+ * Next.js 16.4 patches `Date.now()`, `new Date()`, `Math.random()` and
17
+ * `crypto`'s random functions to end a staged render's static stage when one is
18
+ * called during it (`node-environment-extensions/io-utils`), judged by its
19
+ * request store. Cache handler work called from inside the render - the tag
20
+ * refresh's clock reads, the AWS SDK's request signing and invocation ids - is
21
+ * not the render's, but it runs in the render's context, so it counted: a
22
+ * draft mode page's static stage ended empty, and the client cached nothing
23
+ * from it.
24
+ */
25
+ export declare function outsideRequest<T>(fn: () => T): T;
26
+ /**
27
+ * The key the process's tag manifest (`TrackedTagMarkers`, from the adapter's
28
+ * `sharedTagManifest`) is kept under on `globalThis`, since the runtime and the
29
+ * cache handlers are separate bundles.
30
+ */
31
+ export declare const TAG_MANIFEST_SYMBOL: unique symbol;
32
+ /**
33
+ * Render a page, after waiting for the revalidation log query if the instance
34
+ * has fallen behind on it (sat idle, or thawed): here, before Next.js starts
35
+ * rendering, rather than inside the first `'use cache'` lookup, where the wait
36
+ * cuts a staged render's static stage short. Just `render` until a cache
37
+ * handler first creates the manifest, and then there is nothing to catch up
38
+ * on. Rejects only as `render` does.
39
+ */
40
+ export declare function catchUpTags<T>(render: () => Promise<T>): Promise<T>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TAG_MANIFEST_SYMBOL = exports.OUTSIDE_REQUEST_SYMBOL = void 0;
4
+ exports.captureOutsideRequest = captureOutsideRequest;
5
+ exports.outsideRequest = outsideRequest;
6
+ exports.catchUpTags = catchUpTags;
7
+ const node_async_hooks_1 = require("node:async_hooks");
8
+ /**
9
+ * The key {@link outsideRequest}'s context is kept under on `globalThis`, for
10
+ * the same reason as {@link TAG_MANIFEST_SYMBOL}.
11
+ */
12
+ exports.OUTSIDE_REQUEST_SYMBOL = Symbol.for("cdk-nextjs.outside-request-context");
13
+ /**
14
+ * Capture the context the runtime's module loads in, outside any request.
15
+ * Called once, at load; a later call keeps the first capture.
16
+ */
17
+ function captureOutsideRequest() {
18
+ const global = globalThis;
19
+ global[exports.OUTSIDE_REQUEST_SYMBOL] ??= node_async_hooks_1.AsyncLocalStorage.snapshot();
20
+ }
21
+ /**
22
+ * Run `fn` in the context {@link captureOutsideRequest} captured, where Next.js's
23
+ * request stores are unset: or in the current one, if nothing was captured
24
+ * (outside the runtime, as in unit tests).
25
+ *
26
+ * Next.js 16.4 patches `Date.now()`, `new Date()`, `Math.random()` and
27
+ * `crypto`'s random functions to end a staged render's static stage when one is
28
+ * called during it (`node-environment-extensions/io-utils`), judged by its
29
+ * request store. Cache handler work called from inside the render - the tag
30
+ * refresh's clock reads, the AWS SDK's request signing and invocation ids - is
31
+ * not the render's, but it runs in the render's context, so it counted: a
32
+ * draft mode page's static stage ended empty, and the client cached nothing
33
+ * from it.
34
+ */
35
+ function outsideRequest(fn) {
36
+ const global = globalThis;
37
+ const run = global[exports.OUTSIDE_REQUEST_SYMBOL];
38
+ return run ? run(fn) : fn();
39
+ }
40
+ /**
41
+ * The key the process's tag manifest (`TrackedTagMarkers`, from the adapter's
42
+ * `sharedTagManifest`) is kept under on `globalThis`, since the runtime and the
43
+ * cache handlers are separate bundles.
44
+ */
45
+ exports.TAG_MANIFEST_SYMBOL = Symbol.for("cdk-nextjs.use-cache.tag-manifest");
46
+ /**
47
+ * Render a page, after waiting for the revalidation log query if the instance
48
+ * has fallen behind on it (sat idle, or thawed): here, before Next.js starts
49
+ * rendering, rather than inside the first `'use cache'` lookup, where the wait
50
+ * cuts a staged render's static stage short. Just `render` until a cache
51
+ * handler first creates the manifest, and then there is nothing to catch up
52
+ * on. Rejects only as `render` does.
53
+ */
54
+ async function catchUpTags(render) {
55
+ const global = globalThis;
56
+ const manifest = global[exports.TAG_MANIFEST_SYMBOL];
57
+ return manifest ? manifest.catchUp(render) : render();
58
+ }
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFnLW1hbmlmZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvdGFnLW1hbmlmZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQWlCQSxzREFHQztBQWdCRCx3Q0FJQztBQW1CRCxrQ0FNQztBQWpFRCx1REFBcUQ7QUFHckQ7OztHQUdHO0FBQ1UsUUFBQSxzQkFBc0IsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUM5QyxvQ0FBb0MsQ0FDckMsQ0FBQztBQUlGOzs7R0FHRztBQUNILFNBQWdCLHFCQUFxQjtJQUNuQyxNQUFNLE1BQU0sR0FBRyxVQUEwRCxDQUFDO0lBQzFFLE1BQU0sQ0FBQyw4QkFBc0IsQ0FBQyxLQUFLLG9DQUFpQixDQUFDLFFBQVEsRUFBRSxDQUFDO0FBQ2xFLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFJLEVBQVc7SUFDM0MsTUFBTSxNQUFNLEdBQUcsVUFBMEQsQ0FBQztJQUMxRSxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsOEJBQXNCLENBQUMsQ0FBQztJQUMzQyxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUM5QixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNVLFFBQUEsbUJBQW1CLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FDM0MsbUNBQW1DLENBQ3BDLENBQUM7QUFFRjs7Ozs7OztHQU9HO0FBQ0ksS0FBSyxVQUFVLFdBQVcsQ0FBSSxNQUF3QjtJQUMzRCxNQUFNLE1BQU0sR0FBRyxVQUVkLENBQUM7SUFDRixNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsMkJBQW1CLENBQUMsQ0FBQztJQUM3QyxPQUFPLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7QUFDeEQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFzeW5jTG9jYWxTdG9yYWdlIH0gZnJvbSBcIm5vZGU6YXN5bmNfaG9va3NcIjtcbmltcG9ydCB0eXBlIHsgVHJhY2tlZFRhZ01hcmtlcnMgfSBmcm9tIFwiLi4vYWRhcHRlci9hd3MtY2FjaGUtc3RvcmVcIjtcblxuLyoqXG4gKiBUaGUga2V5IHtAbGluayBvdXRzaWRlUmVxdWVzdH0ncyBjb250ZXh0IGlzIGtlcHQgdW5kZXIgb24gYGdsb2JhbFRoaXNgLCBmb3JcbiAqIHRoZSBzYW1lIHJlYXNvbiBhcyB7QGxpbmsgVEFHX01BTklGRVNUX1NZTUJPTH0uXG4gKi9cbmV4cG9ydCBjb25zdCBPVVRTSURFX1JFUVVFU1RfU1lNQk9MID0gU3ltYm9sLmZvcihcbiAgXCJjZGstbmV4dGpzLm91dHNpZGUtcmVxdWVzdC1jb250ZXh0XCIsXG4pO1xuXG50eXBlIENvbnRleHRSdW5uZXIgPSA8VD4oZm46ICgpID0+IFQpID0+IFQ7XG5cbi8qKlxuICogQ2FwdHVyZSB0aGUgY29udGV4dCB0aGUgcnVudGltZSdzIG1vZHVsZSBsb2FkcyBpbiwgb3V0c2lkZSBhbnkgcmVxdWVzdC5cbiAqIENhbGxlZCBvbmNlLCBhdCBsb2FkOyBhIGxhdGVyIGNhbGwga2VlcHMgdGhlIGZpcnN0IGNhcHR1cmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjYXB0dXJlT3V0c2lkZVJlcXVlc3QoKTogdm9pZCB7XG4gIGNvbnN0IGdsb2JhbCA9IGdsb2JhbFRoaXMgYXMgeyBbT1VUU0lERV9SRVFVRVNUX1NZTUJPTF0/OiBDb250ZXh0UnVubmVyIH07XG4gIGdsb2JhbFtPVVRTSURFX1JFUVVFU1RfU1lNQk9MXSA/Pz0gQXN5bmNMb2NhbFN0b3JhZ2Uuc25hcHNob3QoKTtcbn1cblxuLyoqXG4gKiBSdW4gYGZuYCBpbiB0aGUgY29udGV4dCB7QGxpbmsgY2FwdHVyZU91dHNpZGVSZXF1ZXN0fSBjYXB0dXJlZCwgd2hlcmUgTmV4dC5qcydzXG4gKiByZXF1ZXN0IHN0b3JlcyBhcmUgdW5zZXQ6IG9yIGluIHRoZSBjdXJyZW50IG9uZSwgaWYgbm90aGluZyB3YXMgY2FwdHVyZWRcbiAqIChvdXRzaWRlIHRoZSBydW50aW1lLCBhcyBpbiB1bml0IHRlc3RzKS5cbiAqXG4gKiBOZXh0LmpzIDE2LjQgcGF0Y2hlcyBgRGF0ZS5ub3coKWAsIGBuZXcgRGF0ZSgpYCwgYE1hdGgucmFuZG9tKClgIGFuZFxuICogYGNyeXB0b2AncyByYW5kb20gZnVuY3Rpb25zIHRvIGVuZCBhIHN0YWdlZCByZW5kZXIncyBzdGF0aWMgc3RhZ2Ugd2hlbiBvbmUgaXNcbiAqIGNhbGxlZCBkdXJpbmcgaXQgKGBub2RlLWVudmlyb25tZW50LWV4dGVuc2lvbnMvaW8tdXRpbHNgKSwganVkZ2VkIGJ5IGl0c1xuICogcmVxdWVzdCBzdG9yZS4gQ2FjaGUgaGFuZGxlciB3b3JrIGNhbGxlZCBmcm9tIGluc2lkZSB0aGUgcmVuZGVyIC0gdGhlIHRhZ1xuICogcmVmcmVzaCdzIGNsb2NrIHJlYWRzLCB0aGUgQVdTIFNESydzIHJlcXVlc3Qgc2lnbmluZyBhbmQgaW52b2NhdGlvbiBpZHMgLSBpc1xuICogbm90IHRoZSByZW5kZXIncywgYnV0IGl0IHJ1bnMgaW4gdGhlIHJlbmRlcidzIGNvbnRleHQsIHNvIGl0IGNvdW50ZWQ6IGFcbiAqIGRyYWZ0IG1vZGUgcGFnZSdzIHN0YXRpYyBzdGFnZSBlbmRlZCBlbXB0eSwgYW5kIHRoZSBjbGllbnQgY2FjaGVkIG5vdGhpbmdcbiAqIGZyb20gaXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvdXRzaWRlUmVxdWVzdDxUPihmbjogKCkgPT4gVCk6IFQge1xuICBjb25zdCBnbG9iYWwgPSBnbG9iYWxUaGlzIGFzIHsgW09VVFNJREVfUkVRVUVTVF9TWU1CT0xdPzogQ29udGV4dFJ1bm5lciB9O1xuICBjb25zdCBydW4gPSBnbG9iYWxbT1VUU0lERV9SRVFVRVNUX1NZTUJPTF07XG4gIHJldHVybiBydW4gPyBydW4oZm4pIDogZm4oKTtcbn1cblxuLyoqXG4gKiBUaGUga2V5IHRoZSBwcm9jZXNzJ3MgdGFnIG1hbmlmZXN0IChgVHJhY2tlZFRhZ01hcmtlcnNgLCBmcm9tIHRoZSBhZGFwdGVyJ3NcbiAqIGBzaGFyZWRUYWdNYW5pZmVzdGApIGlzIGtlcHQgdW5kZXIgb24gYGdsb2JhbFRoaXNgLCBzaW5jZSB0aGUgcnVudGltZSBhbmQgdGhlXG4gKiBjYWNoZSBoYW5kbGVycyBhcmUgc2VwYXJhdGUgYnVuZGxlcy5cbiAqL1xuZXhwb3J0IGNvbnN0IFRBR19NQU5JRkVTVF9TWU1CT0wgPSBTeW1ib2wuZm9yKFxuICBcImNkay1uZXh0anMudXNlLWNhY2hlLnRhZy1tYW5pZmVzdFwiLFxuKTtcblxuLyoqXG4gKiBSZW5kZXIgYSBwYWdlLCBhZnRlciB3YWl0aW5nIGZvciB0aGUgcmV2YWxpZGF0aW9uIGxvZyBxdWVyeSBpZiB0aGUgaW5zdGFuY2VcbiAqIGhhcyBmYWxsZW4gYmVoaW5kIG9uIGl0IChzYXQgaWRsZSwgb3IgdGhhd2VkKTogaGVyZSwgYmVmb3JlIE5leHQuanMgc3RhcnRzXG4gKiByZW5kZXJpbmcsIHJhdGhlciB0aGFuIGluc2lkZSB0aGUgZmlyc3QgYCd1c2UgY2FjaGUnYCBsb29rdXAsIHdoZXJlIHRoZSB3YWl0XG4gKiBjdXRzIGEgc3RhZ2VkIHJlbmRlcidzIHN0YXRpYyBzdGFnZSBzaG9ydC4gSnVzdCBgcmVuZGVyYCB1bnRpbCBhIGNhY2hlXG4gKiBoYW5kbGVyIGZpcnN0IGNyZWF0ZXMgdGhlIG1hbmlmZXN0LCBhbmQgdGhlbiB0aGVyZSBpcyBub3RoaW5nIHRvIGNhdGNoIHVwXG4gKiBvbi4gUmVqZWN0cyBvbmx5IGFzIGByZW5kZXJgIGRvZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjYXRjaFVwVGFnczxUPihyZW5kZXI6ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgY29uc3QgZ2xvYmFsID0gZ2xvYmFsVGhpcyBhcyB7XG4gICAgW1RBR19NQU5JRkVTVF9TWU1CT0xdPzogUGljazxUcmFja2VkVGFnTWFya2VycywgXCJjYXRjaFVwXCI+O1xuICB9O1xuICBjb25zdCBtYW5pZmVzdCA9IGdsb2JhbFtUQUdfTUFOSUZFU1RfU1lNQk9MXTtcbiAgcmV0dXJuIG1hbmlmZXN0ID8gbWFuaWZlc3QuY2F0Y2hVcChyZW5kZXIpIDogcmVuZGVyKCk7XG59XG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_async_hooks_1 = require("node:async_hooks");
4
+ const tag_manifest_1 = require("./tag-manifest");
5
+ const global = globalThis;
6
+ afterEach(() => {
7
+ delete global[tag_manifest_1.TAG_MANIFEST_SYMBOL];
8
+ delete global[tag_manifest_1.OUTSIDE_REQUEST_SYMBOL];
9
+ });
10
+ describe("catchUpTags", () => {
11
+ it("just renders before a cache handler creates the manifest", async () => {
12
+ await expect((0, tag_manifest_1.catchUpTags)(async () => "page")).resolves.toBe("page");
13
+ });
14
+ it("renders through the manifest the cache handlers share", async () => {
15
+ const manifest = {
16
+ catchUp: jest.fn(async (render) => render()),
17
+ };
18
+ global[tag_manifest_1.TAG_MANIFEST_SYMBOL] = manifest;
19
+ await expect((0, tag_manifest_1.catchUpTags)(async () => "page")).resolves.toBe("page");
20
+ expect(manifest.catchUp).toHaveBeenCalledTimes(1);
21
+ });
22
+ });
23
+ describe("outsideRequest", () => {
24
+ // Stands in for Next.js's request store.
25
+ const request = new node_async_hooks_1.AsyncLocalStorage();
26
+ it("runs in the context captured at load, where no request store is set", async () => {
27
+ (0, tag_manifest_1.captureOutsideRequest)();
28
+ await request.run("page render", async () => {
29
+ expect((0, tag_manifest_1.outsideRequest)(() => request.getStore())).toBeUndefined();
30
+ // Awaited work it starts stays outside too.
31
+ await expect((0, tag_manifest_1.outsideRequest)(async () => {
32
+ await Promise.resolve();
33
+ return request.getStore();
34
+ })).resolves.toBeUndefined();
35
+ expect(request.getStore()).toBe("page render");
36
+ });
37
+ });
38
+ it("keeps the first capture", () => {
39
+ (0, tag_manifest_1.captureOutsideRequest)();
40
+ request.run("page render", () => (0, tag_manifest_1.captureOutsideRequest)());
41
+ request.run("another render", () => expect((0, tag_manifest_1.outsideRequest)(() => request.getStore())).toBeUndefined());
42
+ });
43
+ it("runs in the current context when nothing was captured", () => {
44
+ request.run("page render", () => expect((0, tag_manifest_1.outsideRequest)(() => request.getStore())).toBe("page render"));
45
+ });
46
+ });
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFnLW1hbmlmZXN0LnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS90YWctbWFuaWZlc3QudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHVEQUFxRDtBQUNyRCxpREFNd0I7QUFFeEIsTUFBTSxNQUFNLEdBQUcsVUFHZCxDQUFDO0FBRUYsU0FBUyxDQUFDLEdBQUcsRUFBRTtJQUNiLE9BQU8sTUFBTSxDQUFDLGtDQUFtQixDQUFDLENBQUM7SUFDbkMsT0FBTyxNQUFNLENBQUMscUNBQXNCLENBQUMsQ0FBQztBQUN4QyxDQUFDLENBQUMsQ0FBQztBQUVILFFBQVEsQ0FBQyxhQUFhLEVBQUUsR0FBRyxFQUFFO0lBQzNCLEVBQUUsQ0FBQywwREFBMEQsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN4RSxNQUFNLE1BQU0sQ0FBQyxJQUFBLDBCQUFXLEVBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdEUsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsdURBQXVELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDckUsTUFBTSxRQUFRLEdBQUc7WUFDZixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsTUFBNkIsRUFBRSxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUM7U0FDcEUsQ0FBQztRQUNGLE1BQU0sQ0FBQyxrQ0FBbUIsQ0FBQyxHQUFHLFFBQVEsQ0FBQztRQUN2QyxNQUFNLE1BQU0sQ0FBQyxJQUFBLDBCQUFXLEVBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDcEUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLGdCQUFnQixFQUFFLEdBQUcsRUFBRTtJQUM5Qix5Q0FBeUM7SUFDekMsTUFBTSxPQUFPLEdBQUcsSUFBSSxvQ0FBaUIsRUFBVSxDQUFDO0lBRWhELEVBQUUsQ0FBQyxxRUFBcUUsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNuRixJQUFBLG9DQUFxQixHQUFFLENBQUM7UUFDeEIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMxQyxNQUFNLENBQUMsSUFBQSw2QkFBYyxFQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDakUsNENBQTRDO1lBQzVDLE1BQU0sTUFBTSxDQUNWLElBQUEsNkJBQWMsRUFBQyxLQUFLLElBQUksRUFBRTtnQkFDeEIsTUFBTSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ3hCLE9BQU8sT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQzVCLENBQUMsQ0FBQyxDQUNILENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzNCLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQyx5QkFBeUIsRUFBRSxHQUFHLEVBQUU7UUFDakMsSUFBQSxvQ0FBcUIsR0FBRSxDQUFDO1FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUEsb0NBQXFCLEdBQUUsQ0FBQyxDQUFDO1FBQzFELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFLENBQ2pDLE1BQU0sQ0FBQyxJQUFBLDZCQUFjLEVBQUMsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FDakUsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLHVEQUF1RCxFQUFFLEdBQUcsRUFBRTtRQUMvRCxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxHQUFHLEVBQUUsQ0FDOUIsTUFBTSxDQUFDLElBQUEsNkJBQWMsRUFBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FDckUsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBc3luY0xvY2FsU3RvcmFnZSB9IGZyb20gXCJub2RlOmFzeW5jX2hvb2tzXCI7XG5pbXBvcnQge1xuICBjYXB0dXJlT3V0c2lkZVJlcXVlc3QsXG4gIGNhdGNoVXBUYWdzLFxuICBPVVRTSURFX1JFUVVFU1RfU1lNQk9MLFxuICBvdXRzaWRlUmVxdWVzdCxcbiAgVEFHX01BTklGRVNUX1NZTUJPTCxcbn0gZnJvbSBcIi4vdGFnLW1hbmlmZXN0XCI7XG5cbmNvbnN0IGdsb2JhbCA9IGdsb2JhbFRoaXMgYXMge1xuICBbVEFHX01BTklGRVNUX1NZTUJPTF0/OiB1bmtub3duO1xuICBbT1VUU0lERV9SRVFVRVNUX1NZTUJPTF0/OiB1bmtub3duO1xufTtcblxuYWZ0ZXJFYWNoKCgpID0+IHtcbiAgZGVsZXRlIGdsb2JhbFtUQUdfTUFOSUZFU1RfU1lNQk9MXTtcbiAgZGVsZXRlIGdsb2JhbFtPVVRTSURFX1JFUVVFU1RfU1lNQk9MXTtcbn0pO1xuXG5kZXNjcmliZShcImNhdGNoVXBUYWdzXCIsICgpID0+IHtcbiAgaXQoXCJqdXN0IHJlbmRlcnMgYmVmb3JlIGEgY2FjaGUgaGFuZGxlciBjcmVhdGVzIHRoZSBtYW5pZmVzdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgZXhwZWN0KGNhdGNoVXBUYWdzKGFzeW5jICgpID0+IFwicGFnZVwiKSkucmVzb2x2ZXMudG9CZShcInBhZ2VcIik7XG4gIH0pO1xuXG4gIGl0KFwicmVuZGVycyB0aHJvdWdoIHRoZSBtYW5pZmVzdCB0aGUgY2FjaGUgaGFuZGxlcnMgc2hhcmVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IG1hbmlmZXN0ID0ge1xuICAgICAgY2F0Y2hVcDogamVzdC5mbihhc3luYyAocmVuZGVyOiAoKSA9PiBQcm9taXNlPHN0cmluZz4pID0+IHJlbmRlcigpKSxcbiAgICB9O1xuICAgIGdsb2JhbFtUQUdfTUFOSUZFU1RfU1lNQk9MXSA9IG1hbmlmZXN0O1xuICAgIGF3YWl0IGV4cGVjdChjYXRjaFVwVGFncyhhc3luYyAoKSA9PiBcInBhZ2VcIikpLnJlc29sdmVzLnRvQmUoXCJwYWdlXCIpO1xuICAgIGV4cGVjdChtYW5pZmVzdC5jYXRjaFVwKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMSk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKFwib3V0c2lkZVJlcXVlc3RcIiwgKCkgPT4ge1xuICAvLyBTdGFuZHMgaW4gZm9yIE5leHQuanMncyByZXF1ZXN0IHN0b3JlLlxuICBjb25zdCByZXF1ZXN0ID0gbmV3IEFzeW5jTG9jYWxTdG9yYWdlPHN0cmluZz4oKTtcblxuICBpdChcInJ1bnMgaW4gdGhlIGNvbnRleHQgY2FwdHVyZWQgYXQgbG9hZCwgd2hlcmUgbm8gcmVxdWVzdCBzdG9yZSBpcyBzZXRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNhcHR1cmVPdXRzaWRlUmVxdWVzdCgpO1xuICAgIGF3YWl0IHJlcXVlc3QucnVuKFwicGFnZSByZW5kZXJcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgZXhwZWN0KG91dHNpZGVSZXF1ZXN0KCgpID0+IHJlcXVlc3QuZ2V0U3RvcmUoKSkpLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIC8vIEF3YWl0ZWQgd29yayBpdCBzdGFydHMgc3RheXMgb3V0c2lkZSB0b28uXG4gICAgICBhd2FpdCBleHBlY3QoXG4gICAgICAgIG91dHNpZGVSZXF1ZXN0KGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgICByZXR1cm4gcmVxdWVzdC5nZXRTdG9yZSgpO1xuICAgICAgICB9KSxcbiAgICAgICkucmVzb2x2ZXMudG9CZVVuZGVmaW5lZCgpO1xuICAgICAgZXhwZWN0KHJlcXVlc3QuZ2V0U3RvcmUoKSkudG9CZShcInBhZ2UgcmVuZGVyXCIpO1xuICAgIH0pO1xuICB9KTtcblxuICBpdChcImtlZXBzIHRoZSBmaXJzdCBjYXB0dXJlXCIsICgpID0+IHtcbiAgICBjYXB0dXJlT3V0c2lkZVJlcXVlc3QoKTtcbiAgICByZXF1ZXN0LnJ1bihcInBhZ2UgcmVuZGVyXCIsICgpID0+IGNhcHR1cmVPdXRzaWRlUmVxdWVzdCgpKTtcbiAgICByZXF1ZXN0LnJ1bihcImFub3RoZXIgcmVuZGVyXCIsICgpID0+XG4gICAgICBleHBlY3Qob3V0c2lkZVJlcXVlc3QoKCkgPT4gcmVxdWVzdC5nZXRTdG9yZSgpKSkudG9CZVVuZGVmaW5lZCgpLFxuICAgICk7XG4gIH0pO1xuXG4gIGl0KFwicnVucyBpbiB0aGUgY3VycmVudCBjb250ZXh0IHdoZW4gbm90aGluZyB3YXMgY2FwdHVyZWRcIiwgKCkgPT4ge1xuICAgIHJlcXVlc3QucnVuKFwicGFnZSByZW5kZXJcIiwgKCkgPT5cbiAgICAgIGV4cGVjdChvdXRzaWRlUmVxdWVzdCgoKSA9PiByZXF1ZXN0LmdldFN0b3JlKCkpKS50b0JlKFwicGFnZSByZW5kZXJcIiksXG4gICAgKTtcbiAgfSk7XG59KTtcbiJdfQ==
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "@aws-sdk/client-ssm": "^3.1141.0",
22
22
  "@aws-sdk/lib-storage": "^3.1141.0",
23
23
  "@mrgrain/jsii-struct-builder": "^0.7.64",
24
- "@next/routing": "16.3.8",
24
+ "@next/routing": "16.4.0",
25
25
  "@smithy/signature-v4": "^2.3.0",
26
26
  "@types/aws-lambda": "^8.10.163",
27
27
  "@types/debug": "^4.1.13",
@@ -51,7 +51,7 @@
51
51
  "jsii-pacmak": "^1.140.0",
52
52
  "jsii-rosetta": "~5.9.67",
53
53
  "mime-types": "^2.1.35",
54
- "next": "^16.3.8",
54
+ "next": "^16.4.0",
55
55
  "prettier": "^3.9.9",
56
56
  "projen": "^0.101.6",
57
57
  "ts-jest": "^29.4.14",
@@ -84,7 +84,7 @@
84
84
  "publishConfig": {
85
85
  "access": "public"
86
86
  },
87
- "version": "0.7.6",
87
+ "version": "0.7.8",
88
88
  "jest": {
89
89
  "coverageProvider": "v8",
90
90
  "testPathIgnorePatterns": [
@@ -74,8 +74,13 @@ PM="$(node -e 'const f=require("path").join(process.argv[1],"package.json");let
74
74
  case "$PM" in
75
75
  pnpm)
76
76
  if command -v corepack >/dev/null 2>&1; then PM_CMD=(corepack pnpm); else PM_CMD=(pnpm); fi
77
- # Without it pnpm walks up out of /tmp looking for a workspace root.
78
- INSTALL_ARGS=(--ignore-workspace --prefer-offline)
77
+ INSTALL_ARGS=(--prefer-offline)
78
+ # Without it pnpm walks up out of /tmp looking for a workspace root. But a
79
+ # fixture with its own pnpm-workspace.yaml is that root, and the flag would
80
+ # also drop the file's settings: test/e2e/app-dir/turbopack-reports approves
81
+ # its native addon's node-gyp build there (`allowBuilds`), and with the flag
82
+ # pnpm skips the build, so `next build` can't load the binary.
83
+ [ -f "$APP_DIR/pnpm-workspace.yaml" ] || INSTALL_ARGS+=(--ignore-workspace)
79
84
  ;;
80
85
  *)
81
86
  PM_CMD=("$PM")