vinext 1.0.0-beta.2 → 1.0.0-beta.3

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 (126) hide show
  1. package/README.md +6 -9
  2. package/dist/build/client-build-config.js +7 -1
  3. package/dist/check.js +4 -0
  4. package/dist/config/config-matchers.js +4 -1
  5. package/dist/config/next-config.d.ts +12 -3
  6. package/dist/config/next-config.js +4 -0
  7. package/dist/entries/app-browser-entry.d.ts +4 -10
  8. package/dist/entries/app-browser-entry.js +20 -4
  9. package/dist/entries/app-rsc-entry.js +3 -0
  10. package/dist/entries/app-rsc-manifest.js +19 -0
  11. package/dist/entries/pages-client-entry.js +0 -1
  12. package/dist/entries/pages-server-entry.js +10 -3
  13. package/dist/index.js +112 -43
  14. package/dist/init-cloudflare.d.ts +3 -1
  15. package/dist/init-cloudflare.js +59 -5
  16. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  17. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  18. package/dist/plugins/import-meta-url.js +17 -6
  19. package/dist/plugins/require-context.js +20 -15
  20. package/dist/plugins/transform-cache.d.ts +19 -0
  21. package/dist/plugins/transform-cache.js +36 -0
  22. package/dist/routing/app-route-graph.d.ts +14 -6
  23. package/dist/routing/app-route-graph.js +106 -16
  24. package/dist/server/api-handler.d.ts +2 -0
  25. package/dist/server/api-handler.js +3 -3
  26. package/dist/server/app-browser-entry.js +103 -31
  27. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  28. package/dist/server/app-browser-navigation-controller.js +1 -1
  29. package/dist/server/app-page-cache-finalizer.js +1 -1
  30. package/dist/server/app-page-cache.d.ts +1 -1
  31. package/dist/server/app-page-cache.js +16 -2
  32. package/dist/server/app-page-dispatch.d.ts +8 -0
  33. package/dist/server/app-page-dispatch.js +31 -6
  34. package/dist/server/app-page-element-builder.d.ts +2 -0
  35. package/dist/server/app-page-element-builder.js +33 -7
  36. package/dist/server/app-page-head.d.ts +3 -3
  37. package/dist/server/app-page-head.js +58 -13
  38. package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
  39. package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
  40. package/dist/server/app-page-probe.d.ts +4 -0
  41. package/dist/server/app-page-probe.js +6 -2
  42. package/dist/server/app-page-request.d.ts +3 -0
  43. package/dist/server/app-page-request.js +1 -1
  44. package/dist/server/app-page-response.js +1 -1
  45. package/dist/server/app-page-route-wiring.d.ts +7 -0
  46. package/dist/server/app-page-route-wiring.js +211 -49
  47. package/dist/server/app-pages-bridge.d.ts +1 -1
  48. package/dist/server/app-pages-bridge.js +2 -1
  49. package/dist/server/app-route-handler-cache.js +4 -0
  50. package/dist/server/app-route-handler-dispatch.js +9 -3
  51. package/dist/server/app-route-handler-response.js +1 -1
  52. package/dist/server/app-route-module-loader.d.ts +6 -0
  53. package/dist/server/app-route-module-loader.js +3 -0
  54. package/dist/server/app-router-entry.js +6 -3
  55. package/dist/server/app-rsc-errors.js +10 -0
  56. package/dist/server/app-rsc-handler.js +21 -9
  57. package/dist/server/app-rsc-route-matching.d.ts +9 -0
  58. package/dist/server/app-rsc-route-matching.js +6 -0
  59. package/dist/server/app-ssr-entry.js +4 -4
  60. package/dist/server/cache-control.d.ts +2 -2
  61. package/dist/server/cache-control.js +2 -1
  62. package/dist/server/dev-server.d.ts +3 -1
  63. package/dist/server/dev-server.js +145 -312
  64. package/dist/server/headers.d.ts +2 -2
  65. package/dist/server/headers.js +4 -3
  66. package/dist/server/isr-cache.d.ts +10 -33
  67. package/dist/server/isr-cache.js +33 -43
  68. package/dist/server/isr-decision.d.ts +2 -2
  69. package/dist/server/pages-api-route.d.ts +2 -0
  70. package/dist/server/pages-api-route.js +4 -1
  71. package/dist/server/pages-dev-hydration.js +0 -1
  72. package/dist/server/pages-get-initial-props.d.ts +1 -1
  73. package/dist/server/pages-get-initial-props.js +1 -4
  74. package/dist/server/pages-i18n.js +64 -16
  75. package/dist/server/pages-node-compat.d.ts +2 -0
  76. package/dist/server/pages-node-compat.js +7 -3
  77. package/dist/server/pages-page-data.d.ts +61 -9
  78. package/dist/server/pages-page-data.js +334 -74
  79. package/dist/server/pages-page-handler.d.ts +5 -1
  80. package/dist/server/pages-page-handler.js +115 -19
  81. package/dist/server/pages-page-response.d.ts +5 -3
  82. package/dist/server/pages-page-response.js +23 -26
  83. package/dist/server/pages-request-pipeline.d.ts +7 -0
  84. package/dist/server/pages-request-pipeline.js +5 -1
  85. package/dist/server/pages-revalidate.d.ts +1 -1
  86. package/dist/server/pages-revalidate.js +54 -8
  87. package/dist/server/pages-router-entry.d.ts +1 -0
  88. package/dist/server/pages-router-entry.js +10 -4
  89. package/dist/server/prod-server.d.ts +2 -1
  90. package/dist/server/prod-server.js +37 -13
  91. package/dist/server/revalidation-host.d.ts +11 -0
  92. package/dist/server/revalidation-host.js +19 -0
  93. package/dist/server/worker-revalidation-context.d.ts +13 -0
  94. package/dist/server/worker-revalidation-context.js +29 -0
  95. package/dist/shims/cache-handler.d.ts +1 -1
  96. package/dist/shims/cache-handler.js +10 -7
  97. package/dist/shims/cache-runtime.d.ts +6 -0
  98. package/dist/shims/cache-runtime.js +4 -1
  99. package/dist/shims/cache.js +1 -1
  100. package/dist/shims/error.js +1 -1
  101. package/dist/shims/fetch-cache.js +1 -1
  102. package/dist/shims/font-google-base.js +17 -8
  103. package/dist/shims/font-local.js +41 -10
  104. package/dist/shims/headers.d.ts +10 -13
  105. package/dist/shims/headers.js +85 -36
  106. package/dist/shims/internal/cookie-serialize.d.ts +10 -9
  107. package/dist/shims/internal/cookie-serialize.js +9 -8
  108. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  109. package/dist/shims/internal/interpolate-as.js +27 -2
  110. package/dist/shims/link.js +18 -6
  111. package/dist/shims/metadata.d.ts +7 -17
  112. package/dist/shims/metadata.js +74 -24
  113. package/dist/shims/navigation.js +1 -1
  114. package/dist/shims/request-context.d.ts +4 -1
  115. package/dist/shims/router.js +18 -7
  116. package/dist/shims/script.js +1 -1
  117. package/dist/shims/server.d.ts +7 -6
  118. package/dist/shims/server.js +156 -57
  119. package/dist/shims/unified-request-context.d.ts +21 -2
  120. package/dist/shims/unified-request-context.js +82 -1
  121. package/dist/utils/cache-control-metadata.d.ts +2 -1
  122. package/dist/utils/cache-control-metadata.js +5 -1
  123. package/dist/utils/html-limited-bots.js +1 -1
  124. package/dist/utils/protocol-headers.d.ts +7 -1
  125. package/dist/utils/protocol-headers.js +7 -1
  126. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
1
+ import { MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
2
2
 
3
3
  //#region src/server/headers.d.ts
4
4
  /**
@@ -107,4 +107,4 @@ declare const INTERNAL_HEADERS: string[];
107
107
  /** Vinext-only internal headers stripped alongside Next.js protocol internals. */
108
108
  declare const VINEXT_INTERNAL_HEADERS: string[];
109
109
  //#endregion
110
- export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_REVALIDATE_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
110
+ export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_REVALIDATE_HEADER, VINEXT_REVALIDATE_HOST_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
@@ -1,4 +1,4 @@
1
- import { MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_OVERRIDE_HEADERS, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
1
+ import { MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_OVERRIDE_HEADERS, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
2
2
  //#region src/server/headers.ts
3
3
  /**
4
4
  * Internal HTTP header name constants used throughout vinext.
@@ -127,7 +127,8 @@ const INTERNAL_HEADERS = [
127
127
  const VINEXT_INTERNAL_HEADERS = [
128
128
  VINEXT_PRERENDER_ROUTE_PARAMS_HEADER,
129
129
  VINEXT_PRERENDER_SPECULATIVE_HEADER,
130
- VINEXT_PRERENDER_CACHE_LIFE_HEADER
130
+ VINEXT_PRERENDER_CACHE_LIFE_HEADER,
131
+ VINEXT_REVALIDATE_HOST_HEADER
131
132
  ];
132
133
  //#endregion
133
- export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_REVALIDATE_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
134
+ export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_REVALIDATE_HEADER, VINEXT_REVALIDATE_HOST_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
@@ -1,38 +1,11 @@
1
1
  import { OnRequestErrorContext } from "./instrumentation.js";
2
2
  import { RenderObservation } from "./cache-proof.js";
3
3
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
4
+ import { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER } from "../utils/protocol-headers.js";
4
5
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
5
6
  import { CacheHandlerValue, CachedAppPageValue, CachedPagesValue, IncrementalCacheValue } from "../shims/cache-handler.js";
6
7
 
7
8
  //#region src/server/isr-cache.d.ts
8
- /**
9
- * Header set on the internal request that `res.revalidate()` issues to
10
- * trigger on-demand ISR regeneration of a Pages Router route. Mirrors Next.js's
11
- * `PRERENDER_REVALIDATE_HEADER` (`x-prerender-revalidate`) — see
12
- * `.nextjs-ref/packages/next/src/lib/constants.ts`.
13
- *
14
- * SECURITY: in Next.js this header is NOT a presence flag — it carries the
15
- * secret `previewModeId`, and `checkIsOnDemandRevalidate`
16
- * (`.nextjs-ref/packages/next/src/server/api-utils/index.ts`) only treats a
17
- * request as on-demand revalidation when the value *equals* that secret. If we
18
- * gated on presence alone, any external client could send
19
- * `x-prerender-revalidate: <anything>` to force synchronous regeneration of any
20
- * ISR page, bypassing the fresh/stale cache short-circuits — a
21
- * cache-stampede/DoS vector. We therefore validate the value against
22
- * {@link getRevalidateSecret} (a build-time secret shared across all Workers
23
- * isolates) with a constant-time comparison, and only the matching value (sent
24
- * by our own `res.revalidate()`) is honored.
25
- */
26
- declare const PRERENDER_REVALIDATE_HEADER = "x-prerender-revalidate";
27
- /**
28
- * Companion header to {@link PRERENDER_REVALIDATE_HEADER}. When set,
29
- * `res.revalidate(path, { unstable_onlyGenerated: true })` only revalidates the
30
- * path if it was already generated, and a 404 response counts as a successful
31
- * no-op. Mirrors Next.js's `PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER`
32
- * (`x-prerender-revalidate-if-generated`) — see
33
- * `.nextjs-ref/packages/next/src/lib/constants.ts`.
34
- */
35
- declare const PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER = "x-prerender-revalidate-if-generated";
36
9
  declare function getRevalidateSecret(): string;
37
10
  declare function isRevalidateSecret(value: string | null | undefined): boolean;
38
11
  /**
@@ -44,20 +17,22 @@ declare function isRevalidateSecret(value: string | null | undefined): boolean;
44
17
  declare function isOnDemandRevalidateRequest(headerValue: string | string[] | null | undefined): boolean;
45
18
  type ISRCacheEntry = {
46
19
  value: CacheHandlerValue;
47
- isStale: boolean;
20
+ isStale: boolean; /** The entry crossed its hard expire boundary and must not be served. */
21
+ isExpired?: boolean;
48
22
  };
49
23
  /**
50
24
  * Get a cache entry with staleness information.
51
25
  *
52
26
  * Returns { value, isStale: false } for fresh entries,
53
- * { value, isStale: true } for expired-but-usable entries,
54
- * or null for cache misses.
27
+ * { value, isStale: true } for stale-but-usable entries,
28
+ * { value, isStale: true, isExpired: true } for entries that must be retained
29
+ * as regeneration input but not served, or null for cache misses.
55
30
  */
56
31
  declare function isrGet(key: string): Promise<ISRCacheEntry | null>;
57
32
  /**
58
33
  * Store a value in the ISR cache with a revalidation period.
59
34
  */
60
- declare function isrSet(key: string, data: IncrementalCacheValue, revalidateSeconds: number, tags?: string[], expireSeconds?: number): Promise<void>;
35
+ declare function isrSet(key: string, data: IncrementalCacheValue | null, revalidateSeconds: number | false, tags?: string[], expireSeconds?: number): Promise<void>;
61
36
  declare function isrSetPrerenderedAppPage(key: string, data: CachedAppPageValue, metadata: {
62
37
  expireSeconds?: number;
63
38
  revalidateSeconds?: number;
@@ -70,6 +45,8 @@ declare function isrSetPrerenderedAppPage(key: string, data: CachedAppPageValue,
70
45
  */
71
46
  tags?: string[];
72
47
  }): Promise<void>;
48
+ /** Coalesce same-key synchronous on-demand revalidations. */
49
+ declare function coalesceOnDemandRevalidation<T>(key: string, renderFn: () => Promise<T>): Promise<T>;
73
50
  /**
74
51
  * Trigger a background regeneration for a cache key.
75
52
  *
@@ -133,4 +110,4 @@ declare function setRevalidateDuration(key: string, seconds: number): void;
133
110
  */
134
111
  declare function getRevalidateDuration(key: string): number | undefined;
135
112
  //#endregion
136
- export { ISRCacheEntry, PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, appIsrCacheKey, appIsrHtmlKey, appIsrRouteKey, appIsrRscKey, buildAppPageCacheValue, buildPagesCacheValue, getRevalidateDuration, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, isrCacheKey, isrGet, isrSet, isrSetPrerenderedAppPage, normalizeMountedSlotsHeader, setRevalidateDuration, triggerBackgroundRegeneration };
113
+ export { ISRCacheEntry, PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, appIsrCacheKey, appIsrHtmlKey, appIsrRouteKey, appIsrRscKey, buildAppPageCacheValue, buildPagesCacheValue, coalesceOnDemandRevalidation, getRevalidateDuration, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, isrCacheKey, isrGet, isrSet, isrSetPrerenderedAppPage, normalizeMountedSlotsHeader, setRevalidateDuration, triggerBackgroundRegeneration };
@@ -1,4 +1,5 @@
1
1
  import { getRequestExecutionContext } from "../shims/request-context.js";
2
+ import { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER } from "../utils/protocol-headers.js";
2
3
  import { reportRequestError } from "./instrumentation.js";
3
4
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
4
5
  import { fnv1a64 } from "../utils/hash.js";
@@ -7,34 +8,6 @@ import { APP_RSC_RENDER_MODE_NAVIGATION, getRscRenderModeCacheVariant } from "./
7
8
  import { normalizeAppPageInterceptionProofPathname } from "./app-page-render-identity.js";
8
9
  //#region src/server/isr-cache.ts
9
10
  /**
10
- * Header set on the internal request that `res.revalidate()` issues to
11
- * trigger on-demand ISR regeneration of a Pages Router route. Mirrors Next.js's
12
- * `PRERENDER_REVALIDATE_HEADER` (`x-prerender-revalidate`) — see
13
- * `.nextjs-ref/packages/next/src/lib/constants.ts`.
14
- *
15
- * SECURITY: in Next.js this header is NOT a presence flag — it carries the
16
- * secret `previewModeId`, and `checkIsOnDemandRevalidate`
17
- * (`.nextjs-ref/packages/next/src/server/api-utils/index.ts`) only treats a
18
- * request as on-demand revalidation when the value *equals* that secret. If we
19
- * gated on presence alone, any external client could send
20
- * `x-prerender-revalidate: <anything>` to force synchronous regeneration of any
21
- * ISR page, bypassing the fresh/stale cache short-circuits — a
22
- * cache-stampede/DoS vector. We therefore validate the value against
23
- * {@link getRevalidateSecret} (a build-time secret shared across all Workers
24
- * isolates) with a constant-time comparison, and only the matching value (sent
25
- * by our own `res.revalidate()`) is honored.
26
- */
27
- const PRERENDER_REVALIDATE_HEADER = "x-prerender-revalidate";
28
- /**
29
- * Companion header to {@link PRERENDER_REVALIDATE_HEADER}. When set,
30
- * `res.revalidate(path, { unstable_onlyGenerated: true })` only revalidates the
31
- * path if it was already generated, and a 404 response counts as a successful
32
- * no-op. Mirrors Next.js's `PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER`
33
- * (`x-prerender-revalidate-if-generated`) — see
34
- * `.nextjs-ref/packages/next/src/lib/constants.ts`.
35
- */
36
- const PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER = "x-prerender-revalidate-if-generated";
37
- /**
38
11
  * Build-time secret that authenticates on-demand revalidation requests, the
39
12
  * vinext analog of Next.js's prerender-manifest `previewModeId`.
40
13
  *
@@ -54,19 +27,22 @@ const PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER = "x-prerender-revalidate-if-ge
54
27
  *
55
28
  * When the build-time define is absent — dev mode, and any path that doesn't
56
29
  * run through `vinext build` — we fall back to a lazily-generated random secret.
57
- * Those paths are single-process, so a module-scoped value is shared by sender
58
- * and receiver there no regression.
30
+ * Those paths are single-process, but Vite can evaluate this module separately
31
+ * in its RSC and SSR module graphs. Store the fallback on `globalThis` under a
32
+ * registry symbol so every module copy in the process reads the same value.
59
33
  */
60
- let devRevalidateSecret;
34
+ const _DEV_REVALIDATE_SECRET_KEY = Symbol.for("vinext.isrCache.devRevalidateSecret");
61
35
  function getRevalidateSecret() {
62
36
  const baked = process.env.__VINEXT_REVALIDATE_SECRET;
63
37
  if (baked) return baked;
64
- if (devRevalidateSecret === void 0) {
65
- const bytes = /* @__PURE__ */ new Uint8Array(32);
66
- crypto.getRandomValues(bytes);
67
- devRevalidateSecret = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
68
- }
69
- return devRevalidateSecret;
38
+ const globals = globalThis;
39
+ const existing = globals[_DEV_REVALIDATE_SECRET_KEY];
40
+ if (typeof existing === "string") return existing;
41
+ const bytes = /* @__PURE__ */ new Uint8Array(32);
42
+ crypto.getRandomValues(bytes);
43
+ const secret = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
44
+ globals[_DEV_REVALIDATE_SECRET_KEY] = secret;
45
+ return secret;
70
46
  }
71
47
  /**
72
48
  * Constant-time string equality. Avoids leaking secret length / prefix via
@@ -98,16 +74,18 @@ function isOnDemandRevalidateRequest(headerValue) {
98
74
  * Get a cache entry with staleness information.
99
75
  *
100
76
  * Returns { value, isStale: false } for fresh entries,
101
- * { value, isStale: true } for expired-but-usable entries,
102
- * or null for cache misses.
77
+ * { value, isStale: true } for stale-but-usable entries,
78
+ * { value, isStale: true, isExpired: true } for entries that must be retained
79
+ * as regeneration input but not served, or null for cache misses.
103
80
  */
104
81
  async function isrGet(key) {
105
82
  const result = await getCdnCacheAdapter().get(key);
106
- if (!result || !result.value) return null;
107
- if (result.cacheState === "expired") return null;
83
+ if (!result) return null;
84
+ const isExpired = result.cacheState === "expired";
108
85
  return {
109
86
  value: result,
110
- isStale: result.cacheState === "stale"
87
+ isStale: isExpired || result.cacheState === "stale",
88
+ ...isExpired ? { isExpired: true } : {}
111
89
  };
112
90
  }
113
91
  /**
@@ -142,6 +120,18 @@ async function isrSetPrerenderedAppPage(key, data, metadata) {
142
120
  const _PENDING_REGEN_KEY = Symbol.for("vinext.isrCache.pendingRegenerations");
143
121
  const _g = globalThis;
144
122
  const pendingRegenerations = _g[_PENDING_REGEN_KEY] ??= /* @__PURE__ */ new Map();
123
+ const _PENDING_ON_DEMAND_REGEN_KEY = Symbol.for("vinext.isrCache.pendingOnDemandRegenerations");
124
+ const pendingOnDemandRegenerations = _g[_PENDING_ON_DEMAND_REGEN_KEY] ??= /* @__PURE__ */ new Map();
125
+ /** Coalesce same-key synchronous on-demand revalidations. */
126
+ function coalesceOnDemandRevalidation(key, renderFn) {
127
+ const pending = pendingOnDemandRegenerations.get(key);
128
+ if (pending) return pending;
129
+ const promise = Promise.resolve().then(renderFn).finally(() => {
130
+ if (pendingOnDemandRegenerations.get(key) === promise) pendingOnDemandRegenerations.delete(key);
131
+ });
132
+ pendingOnDemandRegenerations.set(key, promise);
133
+ return promise;
134
+ }
145
135
  /**
146
136
  * Trigger a background regeneration for a cache key.
147
137
  *
@@ -283,4 +273,4 @@ function getRevalidateDuration(key) {
283
273
  return revalidateDurations.get(key);
284
274
  }
285
275
  //#endregion
286
- export { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, appIsrCacheKey, appIsrHtmlKey, appIsrRouteKey, appIsrRscKey, buildAppPageCacheValue, buildPagesCacheValue, getRevalidateDuration, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, isrCacheKey, isrGet, isrSet, isrSetPrerenderedAppPage, normalizeMountedSlotsHeader, setRevalidateDuration, triggerBackgroundRegeneration };
276
+ export { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, appIsrCacheKey, appIsrHtmlKey, appIsrRouteKey, appIsrRscKey, buildAppPageCacheValue, buildPagesCacheValue, coalesceOnDemandRevalidation, getRevalidateDuration, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, isrCacheKey, isrGet, isrSet, isrSetPrerenderedAppPage, normalizeMountedSlotsHeader, setRevalidateDuration, triggerBackgroundRegeneration };
@@ -33,7 +33,7 @@ type DecideIsrOptions = {
33
33
  * For `"dev"` call sites this is the only source of the revalidate value —
34
34
  * dev never has metadata attached to a cache entry.
35
35
  */
36
- revalidateSeconds: number;
36
+ revalidateSeconds: number | false;
37
37
  /**
38
38
  * The expire ceiling (seconds from epoch) read from the route config.
39
39
  * Absent when the route pre-dates expire metadata support.
@@ -63,7 +63,7 @@ declare function decideIsr(options: DecideIsrOptions): IsrDecision;
63
63
  * therefore never has `cacheControlMeta`. `expireSeconds` here is the route
64
64
  * config ceiling passed directly from the caller (not a per-entry fallback).
65
65
  */
66
- declare function buildMissIsrCacheControl(revalidateSeconds: number, expireSeconds?: number): string;
66
+ declare function buildMissIsrCacheControl(revalidateSeconds: number | false, expireSeconds?: number): string;
67
67
  /**
68
68
  * Build the `Cache-Control` string for a fresh (MISS) app-route response.
69
69
  *
@@ -74,9 +74,11 @@ type HandlePagesApiRouteOptions = {
74
74
  url: string;
75
75
  nextConfig?: {
76
76
  basePath?: string;
77
+ allowedRevalidateHeaderKeys?: readonly string[];
77
78
  i18n?: NextI18nConfig | null;
78
79
  trailingSlash?: boolean;
79
80
  };
81
+ trustedRevalidateOrigin?: string;
80
82
  };
81
83
  declare function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response>;
82
84
  //#endregion
@@ -48,10 +48,13 @@ async function _handlePagesApiRoute(options) {
48
48
  if (!isNodeApiRouteModule(route.module)) return new Response("API route does not export a default function", { status: 500 });
49
49
  const query = buildPagesApiQuery(options.url, params);
50
50
  const bodyParserConfig = resolveBodyParserConfig(route.module.config);
51
+ const body = bodyParserConfig.enabled ? await parsePagesApiBody(options.request, bodyParserConfig.sizeLimit) : void 0;
51
52
  const { req, res, responsePromise } = createPagesReqRes({
52
- body: bodyParserConfig.enabled ? await parsePagesApiBody(options.request, bodyParserConfig.sizeLimit) : void 0,
53
+ allowedRevalidateHeaderKeys: options.nextConfig?.allowedRevalidateHeaderKeys,
54
+ body,
53
55
  query,
54
56
  request: options.request,
57
+ trustedRevalidateOrigin: options.trustedRevalidateOrigin,
55
58
  url: options.url
56
59
  });
57
60
  let resWasPiped = false;
@@ -17,7 +17,6 @@ function createPagesDevHydrationScript(options) {
17
17
  element = React.createElement(AppComponent, {
18
18
  ...props,
19
19
  Component: PageComponent,
20
- pageProps: rawPageProps,
21
20
  router: appRouter,
22
21
  });
23
22
  ` : `
@@ -43,7 +43,7 @@ type DevAppInitialPropsResult = {
43
43
  kind: "render";
44
44
  pageProps: Record<string, unknown>;
45
45
  renderProps: Record<string, unknown> & {
46
- pageProps: unknown;
46
+ pageProps?: unknown;
47
47
  };
48
48
  };
49
49
  type DevAppInitialPropsContext = {
@@ -92,10 +92,7 @@ async function loadDevAppInitialProps(ctx) {
92
92
  return {
93
93
  kind: "render",
94
94
  pageProps: isPropsObject(initialPageProps) ? initialPageProps : {},
95
- renderProps: isPropsObject(initialProps) ? {
96
- ...initialProps,
97
- pageProps: initialPageProps
98
- } : { pageProps: initialPageProps }
95
+ renderProps: isPropsObject(initialProps) ? initialProps : {}
99
96
  };
100
97
  }
101
98
  //#endregion
@@ -93,23 +93,71 @@ function stripI18nLocaleForApiRoute(url, i18nConfig) {
93
93
  */
94
94
  function detectLocaleFromAcceptLanguage(acceptLang, i18nConfig) {
95
95
  if (!acceptLang) return null;
96
- const langs = acceptLang.split(",").map((part) => {
97
- const [lang, qPart] = part.trim().split(";");
98
- const q = qPart ? parseFloat(qPart.replace("q=", "")) : 1;
99
- return {
100
- lang: lang.trim().toLowerCase(),
101
- q
102
- };
103
- }).sort((a, b) => b.q - a.q);
104
- for (const { lang } of langs) {
105
- const exactMatch = i18nConfig.locales.find((locale) => locale.toLowerCase() === lang);
106
- if (exactMatch) return exactMatch;
107
- const prefix = lang.split("-")[0];
108
- const prefixMatch = i18nConfig.locales.find((locale) => {
109
- const lowered = locale.toLowerCase();
110
- return lowered === prefix || lowered.startsWith(prefix + "-");
96
+ const configured = /* @__PURE__ */ new Map();
97
+ let position = 0;
98
+ for (const locale of i18nConfig.locales) {
99
+ const lower = locale.toLowerCase();
100
+ configured.set(lower, {
101
+ locale,
102
+ position: position++
111
103
  });
112
- if (prefixMatch) return prefixMatch;
104
+ const parts = lower.split("-");
105
+ while (parts.length > 1) {
106
+ parts.pop();
107
+ const prefix = parts.join("-");
108
+ if (!configured.has(prefix)) configured.set(prefix, {
109
+ locale,
110
+ position: position++
111
+ });
112
+ }
113
+ }
114
+ const selections = [];
115
+ const listedTokens = /* @__PURE__ */ new Set();
116
+ try {
117
+ const parts = acceptLang.replace(/[ \t]/g, "").split(",");
118
+ for (let headerPosition = 0; headerPosition < parts.length; headerPosition++) {
119
+ const part = parts[headerPosition];
120
+ if (!part) continue;
121
+ const params = part.split(";");
122
+ if (params.length > 2) throw new Error("Invalid Accept-Language header");
123
+ const token = params[0].toLowerCase();
124
+ if (!token) throw new Error("Invalid Accept-Language header");
125
+ const selection = {
126
+ token,
127
+ headerPosition,
128
+ quality: 1
129
+ };
130
+ const configuredMatch = configured.get(token);
131
+ if (configuredMatch) selection.preference = configuredMatch.position;
132
+ listedTokens.add(token);
133
+ if (params.length === 2) {
134
+ const [key, value] = params[1].split("=");
135
+ if (!value || key !== "q" && key !== "Q") throw new Error("Invalid Accept-Language header");
136
+ const quality = parseFloat(value);
137
+ if (quality === 0) continue;
138
+ if (Number.isFinite(quality) && quality >= .001 && quality <= 1) selection.quality = quality;
139
+ }
140
+ selections.push(selection);
141
+ }
142
+ } catch {
143
+ return null;
144
+ }
145
+ selections.sort((a, b) => {
146
+ if (b.quality !== a.quality) return b.quality - a.quality;
147
+ if (a.preference !== b.preference) {
148
+ if (a.preference === void 0) return 1;
149
+ if (b.preference === void 0) return -1;
150
+ return a.preference - b.preference;
151
+ }
152
+ return a.headerPosition - b.headerPosition;
153
+ });
154
+ for (const { token } of selections) {
155
+ if (token === "*") {
156
+ for (const [preference, { locale }] of configured) if (!listedTokens.has(preference)) return locale;
157
+ continue;
158
+ }
159
+ const match = configured.get(token);
160
+ if (match) return match.locale;
113
161
  }
114
162
  return null;
115
163
  }
@@ -49,9 +49,11 @@ type PagesRequestCookiesCarrier = {
49
49
  cookies?: unknown;
50
50
  };
51
51
  type CreatePagesReqResOptions = {
52
+ allowedRevalidateHeaderKeys?: readonly string[];
52
53
  body: unknown;
53
54
  query: PagesRequestQuery;
54
55
  request: Request;
56
+ trustedRevalidateOrigin?: string;
55
57
  url: string;
56
58
  };
57
59
  type CreatePagesReqResResult = {
@@ -121,6 +121,8 @@ var PagesResponseStream = class extends Writable {
121
121
  resolveResponse;
122
122
  rejectResponse;
123
123
  requestHeaders;
124
+ trustedRevalidateOrigin;
125
+ allowedRevalidateHeaderKeys;
124
126
  resStatusCode = 200;
125
127
  resHeaders = {};
126
128
  setCookieHeaders = [];
@@ -128,11 +130,13 @@ var PagesResponseStream = class extends Writable {
128
130
  controller = null;
129
131
  bufferedChunks = [];
130
132
  streamEnded = false;
131
- constructor(resolveResponse, rejectResponse, requestHeaders) {
133
+ constructor(resolveResponse, rejectResponse, requestHeaders, trustedRevalidateOrigin, allowedRevalidateHeaderKeys = []) {
132
134
  super();
133
135
  this.resolveResponse = resolveResponse;
134
136
  this.rejectResponse = rejectResponse;
135
137
  this.requestHeaders = requestHeaders;
138
+ this.trustedRevalidateOrigin = trustedRevalidateOrigin;
139
+ this.allowedRevalidateHeaderKeys = allowedRevalidateHeaderKeys;
136
140
  this.once("error", (err) => {
137
141
  if (!this.resolved) {
138
142
  this.resolved = true;
@@ -202,7 +206,7 @@ var PagesResponseStream = class extends Writable {
202
206
  return headers;
203
207
  }
204
208
  async revalidate(urlPath, opts) {
205
- await performOnDemandRevalidate(this.requestHeaders, urlPath, opts);
209
+ await performOnDemandRevalidate(this.requestHeaders, urlPath, opts, this.trustedRevalidateOrigin, this.allowedRevalidateHeaderKeys);
206
210
  }
207
211
  setPreviewData(data, options = {}) {
208
212
  setPagesPreviewData(this, data, options);
@@ -299,7 +303,7 @@ function createPagesReqRes(options) {
299
303
  resolveResponse = resolve;
300
304
  rejectResponse = reject;
301
305
  });
302
- const res = new PagesResponseStream(resolveResponse, rejectResponse, options.request.headers);
306
+ const res = new PagesResponseStream(resolveResponse, rejectResponse, options.request.headers, options.trustedRevalidateOrigin ?? new URL(options.request.url).origin, options.allowedRevalidateHeaderKeys);
303
307
  attachPagesPreviewApi(req, res);
304
308
  return {
305
309
  req,
@@ -1,6 +1,6 @@
1
1
  import { Route } from "../routing/pages-router.js";
2
2
  import { VinextNextData } from "../client/vinext-next-data.js";
3
- import { CachedPagesValue } from "../shims/cache-handler.js";
3
+ import { CachedPagesValue, CachedRedirectValue } from "../shims/cache-handler.js";
4
4
  import { ISRCacheEntry } from "./isr-cache.js";
5
5
  import { PagesPreviewData } from "./pages-preview.js";
6
6
  import { PagesGetInitialPropsRouter } from "./pages-get-initial-props.js";
@@ -12,6 +12,12 @@ type PagesRedirectResult = {
12
12
  destination: string;
13
13
  permanent?: boolean;
14
14
  statusCode?: number;
15
+ basePath?: boolean;
16
+ };
17
+ type ResolvedPagesRedirect = {
18
+ destination: string;
19
+ statusCode: number;
20
+ basePath?: boolean;
15
21
  };
16
22
  type PagesStaticPathsEntry = string | {
17
23
  params?: Record<string, unknown>;
@@ -22,11 +28,23 @@ type PagesStaticPathsResult = {
22
28
  paths?: PagesStaticPathsEntry[];
23
29
  };
24
30
  type PagesPagePropsResult = {
25
- props?: Record<string, unknown>;
31
+ props?: Record<string, unknown> | Promise<Record<string, unknown>>;
26
32
  redirect?: PagesRedirectResult;
27
33
  notFound?: boolean;
28
- revalidate?: number;
34
+ revalidate?: unknown;
29
35
  };
36
+ declare function assertPages404DoesNotReturnNotFound(routePattern: string, result: Pick<PagesPagePropsResult, "notFound"> | null | undefined): void;
37
+ /**
38
+ * Next.js preserves an omitted/false Pages `revalidate` result as an indefinite
39
+ * cache lifetime. The one-year sentinel is only an HTTP Cache-Control detail;
40
+ * storing it as a revalidation deadline would incorrectly regenerate static
41
+ * pages after one year.
42
+ *
43
+ * Next.js source:
44
+ * - packages/next/src/server/render.tsx (`metadata.cacheControl`)
45
+ * - packages/next/src/server/route-modules/pages/pages-handler.ts
46
+ */
47
+ declare function resolvePagesRevalidateSeconds(result: PagesPagePropsResult, routeUrl?: string): number | false;
30
48
  type PagesMutableGsspResponse = {
31
49
  headersSent: boolean;
32
50
  } & PagesGsspResponse;
@@ -36,8 +54,16 @@ type PagesGsspContextResponse = {
36
54
  responsePromise: Promise<Response>;
37
55
  };
38
56
  type PagesRenderProps = Record<string, unknown> & {
39
- pageProps: unknown;
57
+ pageProps?: unknown;
40
58
  };
59
+ /**
60
+ * Merge gSP/gSSP data into the custom App's raw pageProps value.
61
+ *
62
+ * Next.js deliberately uses Object.assign rather than object spread, so
63
+ * enumerable keys from arrays and primitive wrapper objects are retained.
64
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/render.tsx
65
+ */
66
+ declare function mergePagesDataProps(appPageProps: unknown, dataProps: unknown): Record<string, unknown>;
41
67
  type PagesPageModule = {
42
68
  default?: unknown;
43
69
  getStaticPaths?: (context: {
@@ -106,6 +132,7 @@ type RenderPagesIsrHtmlOptions = {
106
132
  };
107
133
  type ResolvePagesPageDataOptions = {
108
134
  applyRequestContexts: () => void;
135
+ basePath?: string;
109
136
  buildId: string | null;
110
137
  /**
111
138
  * When true, this is a `/_next/data/<buildId>/<page>.json` request. Callers
@@ -124,7 +151,7 @@ type ResolvePagesPageDataOptions = {
124
151
  i18n: PagesI18nRenderContext;
125
152
  isrCacheKey: (router: string, pathname: string) => string;
126
153
  isrGet: (key: string) => Promise<ISRCacheEntry | null>;
127
- isrSet: (key: string, data: CachedPagesValue, revalidateSeconds: number, tags?: string[], expireSeconds?: number) => Promise<void>;
154
+ isrSet: (key: string, data: CachedPagesValue | CachedRedirectValue | null, revalidateSeconds: number | false, tags?: string[], expireSeconds?: number) => Promise<void>;
128
155
  expireSeconds?: number;
129
156
  /**
130
157
  * When true, this dispatch corresponds to a build-time prerender (the
@@ -152,6 +179,12 @@ type ResolvePagesPageDataOptions = {
152
179
  * presence — see the security note in `isr-cache.ts`.
153
180
  */
154
181
  isOnDemandRevalidate?: boolean;
182
+ /**
183
+ * When true alongside an authenticated on-demand request, return a
184
+ * successful 404 no-op if no cache entry exists instead of generating a new
185
+ * fallback path. Mirrors Next.js `unstable_onlyGenerated`.
186
+ */
187
+ revalidateOnlyGenerated?: boolean;
155
188
  previewData?: PagesPreviewData | false;
156
189
  /**
157
190
  * The deployment ID used for deployment-skew protection. When set, it is
@@ -171,6 +204,12 @@ type ResolvePagesPageDataOptions = {
171
204
  route: Pick<Route, "isDynamic">;
172
205
  routePattern: string;
173
206
  routeUrl: string;
207
+ /**
208
+ * Filesystem-route identity used for Pages ISR reads and writes. Error pages
209
+ * render against the original request URL but cache under /404, /500, or
210
+ * /_error, matching Next.js's error-page cache-key override.
211
+ */
212
+ isrCachePathname?: string;
174
213
  runInFreshUnifiedContext: <T>(callback: () => Promise<T>) => Promise<T>;
175
214
  safeJsonStringify: (value: unknown) => string;
176
215
  sanitizeDestination: (destination: string) => string;
@@ -210,7 +249,8 @@ type ResolvePagesPageDataRenderResult = {
210
249
  kind: "render";
211
250
  documentReqRes: PagesGsspContextResponse | null;
212
251
  gsspRes: PagesGsspResponse | null;
213
- isrRevalidateSeconds: number | null;
252
+ isrRevalidateSeconds: number | false | null;
253
+ isrExpireSeconds?: number;
214
254
  pageProps: Record<string, unknown>;
215
255
  props: PagesRenderProps;
216
256
  /**
@@ -223,12 +263,24 @@ type ResolvePagesPageDataRenderResult = {
223
263
  };
224
264
  type ResolvePagesPageDataResponseResult = {
225
265
  kind: "response";
226
- response: Response;
266
+ response: Response; /** False when an on-demand request must be reported as a failed revalidation. */
267
+ onDemandRevalidateSuccess?: boolean;
227
268
  };
228
269
  type ResolvePagesPageDataNotFoundResult = {
229
- kind: "notFound";
270
+ kind: "notFound"; /** Current getStaticProps cache lifetime, when this is an SSG result. */
271
+ revalidateSeconds?: number | false;
272
+ expireSeconds?: number;
273
+ cacheState?: "MISS" | "HIT" | "STALE";
230
274
  };
231
275
  type ResolvePagesPageDataResult = ResolvePagesPageDataRenderResult | ResolvePagesPageDataResponseResult | ResolvePagesPageDataNotFoundResult;
276
+ /** Validate and normalize the redirect metadata returned by gSP/gSSP. */
277
+ declare function resolvePagesRedirect(redirect: PagesRedirectResult, options: {
278
+ method: "getStaticProps" | "getServerSideProps";
279
+ routeUrl: string;
280
+ sanitizeDestination: (destination: string) => string;
281
+ }): ResolvedPagesRedirect;
282
+ declare function resolvePagesRedirectLocation(redirect: ResolvedPagesRedirect, configuredBasePath?: string): string;
283
+ declare function buildPagesRedirectProps(redirect: ResolvedPagesRedirect, props: PagesRenderProps): PagesRenderProps;
232
284
  /**
233
285
  * Compare a `getStaticPaths` entry against the actual request params.
234
286
  *
@@ -254,4 +306,4 @@ declare function matchesPagesStaticPath(pathEntry: PagesStaticPathsEntry, params
254
306
  declare function renderPagesIsrHtml(options: RenderPagesIsrHtmlOptions): Promise<string>;
255
307
  declare function resolvePagesPageData(options: ResolvePagesPageDataOptions): Promise<ResolvePagesPageDataResult>;
256
308
  //#endregion
257
- export { PagesPageModule, PagesRouteParam, PagesStaticPathsEntry, ResolvePagesPageDataOptions, getPagesRouteParams, matchesPagesStaticPath, renderPagesIsrHtml, resolvePagesPageData };
309
+ export { PagesPageModule, PagesRedirectResult, PagesRouteParam, PagesStaticPathsEntry, ResolvePagesPageDataOptions, ResolvedPagesRedirect, assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, renderPagesIsrHtml, resolvePagesPageData, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds };