@wular/pnext 0.0.4 → 0.0.6

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 (392) hide show
  1. package/README.md +11 -11
  2. package/bin/pnext +1 -1
  3. package/config/lint/base.js +7 -7
  4. package/config/ts/base.json +2 -4
  5. package/config/ts/react.json +2 -6
  6. package/package.json +23 -2
  7. package/reference/compat.md +1 -1
  8. package/reference/config.md +2 -2
  9. package/reference/css.md +13 -9
  10. package/reference/dev.md +1 -1
  11. package/reference/metadata.md +7 -7
  12. package/reference/navigation.md +35 -28
  13. package/reference/performance.md +70 -70
  14. package/reference/rendering.md +17 -17
  15. package/reference/routing.md +17 -17
  16. package/reference/typegen.md +12 -8
  17. package/src/api/cache.ts +36 -37
  18. package/src/api/client-cache.ts +2 -2
  19. package/src/api/client-navigation.ts +113 -109
  20. package/src/api/dynamic.tsx +58 -55
  21. package/src/api/link.tsx +49 -52
  22. package/src/api/navigation.ts +59 -58
  23. package/src/api/server.ts +152 -144
  24. package/src/api/suspense.ts +4 -4
  25. package/src/cli/adapters/vercel-warm.ts +126 -121
  26. package/src/cli/adapters/vercel.ts +437 -443
  27. package/src/cli/analyze.ts +333 -144
  28. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  29. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  30. package/src/cli/build.ts +976 -978
  31. package/src/cli/create.ts +71 -63
  32. package/src/cli/dev.ts +116 -116
  33. package/src/cli/index.ts +88 -85
  34. package/src/cli/migrate/package-json.ts +73 -71
  35. package/src/cli/migrate/report.ts +32 -33
  36. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  37. package/src/cli/migrate/scan.ts +46 -46
  38. package/src/cli/migrate/spinner.ts +9 -9
  39. package/src/cli/migrate/tsconfig.ts +35 -35
  40. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  41. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  42. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  43. package/src/cli/start.ts +65 -66
  44. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  45. package/src/client/build.ts +794 -768
  46. package/src/client/chunk-fold.ts +245 -240
  47. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  48. package/src/client/entry.ts +162 -147
  49. package/src/client/prebuilt.ts +231 -223
  50. package/src/client/profile.ts +29 -29
  51. package/src/client/react-compiler.ts +20 -15
  52. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  53. package/src/client/reference-stub.ts +51 -51
  54. package/src/client/reference.ts +19 -19
  55. package/src/{api → client}/router/events.ts +17 -17
  56. package/src/{api → client}/router/history.ts +16 -16
  57. package/src/{api → client}/router/hub.ts +52 -53
  58. package/src/{api/router.ts → client/router/index.ts} +61 -60
  59. package/src/{api → client}/router/policies.ts +24 -24
  60. package/src/{api → client}/router/runtime.ts +1988 -1992
  61. package/src/{api → client}/router/types.ts +93 -98
  62. package/src/compat/actions/client-plugin.ts +42 -43
  63. package/src/compat/actions/client-stub.ts +14 -14
  64. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  65. package/src/compat/actions/config.ts +63 -64
  66. package/src/compat/actions/detect.ts +68 -68
  67. package/src/compat/actions/discovery.ts +105 -105
  68. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  69. package/src/compat/actions/early-submit.ts +1 -1
  70. package/src/compat/actions/endpoint.ts +198 -198
  71. package/src/compat/actions/extensions.ts +811 -0
  72. package/src/compat/actions/flight.ts +23 -23
  73. package/src/compat/actions/form-state.ts +34 -34
  74. package/src/compat/actions/hoist.ts +382 -236
  75. package/src/compat/actions/ids.ts +7 -12
  76. package/src/compat/actions/index.ts +8 -8
  77. package/src/compat/actions/instances.ts +46 -46
  78. package/src/compat/actions/origin.ts +47 -48
  79. package/src/compat/actions/protocol.ts +22 -22
  80. package/src/compat/actions/registry.ts +19 -19
  81. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  82. package/src/compat/actions/rewrite.ts +125 -125
  83. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  84. package/src/compat/actions/serve.ts +132 -136
  85. package/src/compat/actions/server-tag.ts +4 -4
  86. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  87. package/src/compat/actions/unrecognized-error.ts +4 -4
  88. package/src/compat/{index.ts → aliases.ts} +112 -109
  89. package/src/compat/bundler/bun-externals.ts +18 -18
  90. package/src/compat/bundler/cjs-exports.ts +271 -223
  91. package/src/compat/bundler/config.ts +116 -111
  92. package/src/compat/bundler/externals.ts +12 -12
  93. package/src/compat/bundler/import-meta-url.ts +19 -19
  94. package/src/compat/bundler/modularize-imports.ts +36 -33
  95. package/src/compat/bundler/new-url-asset.ts +22 -24
  96. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  97. package/src/compat/bundler/polyfill.ts +28 -28
  98. package/src/compat/bundler/react-compiler.ts +35 -29
  99. package/src/compat/bundler/react-profiler.tsx +11 -11
  100. package/src/compat/bundler/relay-transform.ts +48 -47
  101. package/src/compat/bundler/require-context.ts +119 -113
  102. package/src/compat/bundler/resolve-extensions.ts +19 -19
  103. package/src/compat/bundler/source-cache.ts +25 -25
  104. package/src/compat/bundler/static-imports.ts +7 -7
  105. package/src/compat/bundler/symlink-imports.ts +46 -46
  106. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  107. package/src/compat/bundler/wasm.ts +58 -60
  108. package/src/compat/bundler/webpack-loaders.ts +254 -241
  109. package/src/compat/bundler/worker.ts +101 -104
  110. package/src/compat/cache/build-flags.ts +29 -29
  111. package/src/compat/cache/build-prerender-errors.ts +40 -44
  112. package/src/compat/cache/custom-handler.ts +60 -53
  113. package/src/compat/cache/fetch-patch.ts +240 -240
  114. package/src/compat/cache/handler.ts +27 -31
  115. package/src/compat/cache/modern-handler.ts +148 -126
  116. package/src/compat/cache/resume-data-cache.ts +47 -45
  117. package/src/compat/cache/revalidate.ts +233 -232
  118. package/src/compat/cache/runtime-error.ts +35 -35
  119. package/src/compat/cache/use-cache-transform.ts +442 -417
  120. package/src/compat/cache/use-cache.ts +650 -614
  121. package/src/compat/cache-control.ts +140 -142
  122. package/src/compat/client/base-path.ts +21 -20
  123. package/src/compat/client/css-order.ts +18 -18
  124. package/src/compat/client/errors/bare-boundary.ts +11 -11
  125. package/src/compat/client/errors/control-flow.ts +23 -23
  126. package/src/compat/client/errors/error-boundary.ts +61 -61
  127. package/src/compat/client/errors/global-error.ts +101 -91
  128. package/src/compat/client/errors/install.ts +71 -72
  129. package/src/compat/client/errors/lazy.ts +23 -23
  130. package/src/compat/client/errors/primitive-throw.ts +47 -45
  131. package/src/compat/client/errors/soft-refresh.ts +4 -4
  132. package/src/compat/client/link-status.ts +33 -33
  133. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  134. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  135. package/src/compat/client/navigation-scroll.ts +63 -63
  136. package/src/compat/client/optimistic-routing.ts +93 -88
  137. package/src/compat/client/prefetch-cache.ts +23 -24
  138. package/src/compat/client/route-announcer.ts +35 -35
  139. package/src/compat/client/segment-cache-policy.ts +20 -20
  140. package/src/compat/client/segment-cache.ts +309 -315
  141. package/src/compat/client/segment-prefetch.ts +127 -132
  142. package/src/compat/client/trailing-slash.ts +5 -4
  143. package/src/compat/css/chunking.ts +113 -116
  144. package/src/compat/css/inline-css.ts +21 -21
  145. package/src/compat/css/lightningcss.ts +37 -38
  146. package/src/compat/css/modules.ts +161 -175
  147. package/src/compat/css/nonce.ts +7 -7
  148. package/src/compat/css/sass-plugin.ts +18 -21
  149. package/src/compat/css/sass.ts +150 -152
  150. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  151. package/src/compat/css/styled-jsx.ts +21 -21
  152. package/src/compat/edge-runtime.ts +27 -27
  153. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  154. package/src/compat/export/client.ts +29 -31
  155. package/src/compat/export/{index.ts → emit.ts} +111 -110
  156. package/src/compat/export/standalone.ts +62 -54
  157. package/src/compat/image-optimizer/cache.ts +51 -49
  158. package/src/compat/image-optimizer/detect.ts +52 -52
  159. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  160. package/src/compat/image-optimizer/source.ts +77 -80
  161. package/src/compat/lifecycle/after-scope.ts +26 -26
  162. package/src/compat/lifecycle/after.ts +48 -45
  163. package/src/compat/lifecycle/error-funnel.ts +98 -102
  164. package/src/compat/lifecycle/error-serialize.ts +30 -26
  165. package/src/compat/lifecycle/error-ui.ts +67 -32
  166. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  167. package/src/compat/lifecycle/instrumentation.ts +85 -85
  168. package/src/compat/lifecycle/node-console.ts +11 -11
  169. package/src/compat/lifecycle/testmode.ts +160 -132
  170. package/src/compat/mdx/compile.ts +60 -57
  171. package/src/compat/mdx/plugin.ts +11 -11
  172. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  173. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  174. package/src/compat/metadata.ts +75 -81
  175. package/src/compat/next/cache.ts +68 -69
  176. package/src/compat/next/canonical-url.ts +9 -9
  177. package/src/compat/next/client-cache.ts +19 -19
  178. package/src/compat/next/client-navigation.ts +112 -116
  179. package/src/compat/next/client-only.ts +1 -1
  180. package/src/compat/next/client-script.tsx +99 -93
  181. package/src/compat/next/client-server.ts +10 -10
  182. package/src/compat/next/config-loader.ts +176 -173
  183. package/src/compat/next/config.ts +7 -7
  184. package/src/compat/next/constants.cjs +6 -6
  185. package/src/compat/next/constants.ts +6 -6
  186. package/src/compat/next/custom-server.ts +26 -24
  187. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  188. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  189. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  190. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  191. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  192. package/src/compat/next/dynamic.tsx +21 -18
  193. package/src/compat/next/error.tsx +52 -52
  194. package/src/compat/next/font/cache.ts +74 -74
  195. package/src/compat/next/font/google.ts +2 -2
  196. package/src/compat/next/font/index.ts +1 -1
  197. package/src/compat/next/font/local.ts +3 -3
  198. package/src/compat/next/font/runtime-client.ts +17 -15
  199. package/src/compat/next/font/runtime.ts +443 -408
  200. package/src/compat/next/font/shared.ts +120 -108
  201. package/src/compat/next/form.tsx +63 -63
  202. package/src/compat/next/head.tsx +2 -2
  203. package/src/compat/next/headers.ts +103 -95
  204. package/src/compat/next/image/client.tsx +220 -0
  205. package/src/compat/next/image/config.ts +56 -58
  206. package/src/compat/next/image/optimizer.ts +40 -36
  207. package/src/compat/next/image/patterns.ts +37 -40
  208. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  209. package/src/compat/next/image/shared.ts +65 -57
  210. package/src/compat/next/image/static-metadata.ts +98 -107
  211. package/src/compat/next/image/validate.ts +79 -88
  212. package/src/compat/next/image.tsx +19 -23
  213. package/src/compat/next/index.ts +1 -1
  214. package/src/compat/next/legacy-image.tsx +59 -60
  215. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  216. package/src/compat/next/link.tsx +158 -158
  217. package/src/compat/next/navigation.cjs +12 -3
  218. package/src/compat/next/navigation.ts +48 -50
  219. package/src/compat/next/offline.ts +27 -27
  220. package/src/compat/next/og.ts +121 -124
  221. package/src/compat/next/preferred-region.ts +13 -14
  222. package/src/compat/next/redirects.ts +58 -56
  223. package/src/compat/next/resource-hints.ts +73 -76
  224. package/src/compat/next/rewrites.ts +130 -133
  225. package/src/compat/next/root-params.ts +45 -45
  226. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  227. package/src/compat/next/router.cjs +4 -2
  228. package/src/compat/next/router.ts +58 -61
  229. package/src/compat/next/script.tsx +108 -108
  230. package/src/compat/next/server-only.ts +1 -1
  231. package/src/compat/next/server.ts +19 -19
  232. package/src/compat/next/svgr.ts +18 -17
  233. package/src/compat/next/telemetry.ts +24 -24
  234. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  235. package/src/compat/next/user-agent.ts +53 -49
  236. package/src/compat/next/web-vitals.ts +22 -24
  237. package/src/compat/otel/api.ts +41 -41
  238. package/src/compat/otel/client-trace-metadata.ts +25 -27
  239. package/src/compat/otel/fetch-span.ts +29 -29
  240. package/src/compat/otel/tracer.ts +331 -331
  241. package/src/compat/pages/api.ts +456 -0
  242. package/src/compat/pages/client-plugin.ts +36 -36
  243. package/src/compat/pages/router-state.ts +34 -34
  244. package/src/compat/pages/{index.ts → router.ts} +130 -135
  245. package/src/compat/ppr/io.ts +12 -12
  246. package/src/compat/ppr/missing-root-params.ts +34 -38
  247. package/src/compat/ppr/root-params-scan.ts +66 -66
  248. package/src/compat/ppr/root-params-transform.ts +24 -26
  249. package/src/compat/ppr/root-params.ts +30 -30
  250. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  251. package/src/compat/protocol.ts +71 -70
  252. package/src/compat/react/action-state.ts +47 -48
  253. package/src/compat/react/client-lite.ts +15 -15
  254. package/src/compat/react/client.ts +4 -4
  255. package/src/compat/react/compiler-runtime.ts +11 -11
  256. package/src/compat/react/dom-client.ts +44 -44
  257. package/src/compat/react/dom-react-server.ts +10 -16
  258. package/src/compat/react/dom-server.ts +10 -10
  259. package/src/compat/react/dom.ts +52 -52
  260. package/src/compat/react/hooks-extra.ts +34 -35
  261. package/src/compat/react/parity.ts +64 -61
  262. package/src/compat/react/preact.ts +81 -82
  263. package/src/compat/react/react-server.ts +28 -28
  264. package/src/compat/react/router-shim.ts +1 -1
  265. package/src/compat/react/server-component-use.ts +8 -8
  266. package/src/compat/react/server-inserted-html.ts +30 -31
  267. package/src/compat/react/server.ts +53 -55
  268. package/src/compat/react/use.ts +32 -32
  269. package/src/compat/react/view-transition.ts +20 -20
  270. package/src/compat/register/actions.ts +35 -824
  271. package/src/compat/register/boot.ts +41 -41
  272. package/src/compat/register/build-tier.ts +5 -5
  273. package/src/compat/register/build.ts +74 -70
  274. package/src/compat/register/bundler.ts +161 -156
  275. package/src/compat/register/cache.ts +20 -20
  276. package/src/compat/register/client-errors.ts +3 -3
  277. package/src/compat/register/config.ts +6 -6
  278. package/src/compat/register/css-extras.ts +30 -34
  279. package/src/compat/register/edge-runtime.ts +3 -3
  280. package/src/compat/register/errors.ts +10 -12
  281. package/src/compat/register/export.ts +16 -16
  282. package/src/compat/register/font.ts +11 -11
  283. package/src/compat/register/hooks.ts +2 -2
  284. package/src/compat/register/image.ts +40 -40
  285. package/src/compat/register/index.ts +59 -62
  286. package/src/compat/register/instrumentation-client.ts +10 -10
  287. package/src/compat/register/lifecycle.ts +25 -28
  288. package/src/compat/register/mdx.ts +10 -10
  289. package/src/compat/register/middleware.ts +226 -16
  290. package/src/compat/register/otel.ts +80 -88
  291. package/src/compat/register/pages-api.ts +10 -463
  292. package/src/compat/register/ppr.ts +16 -16
  293. package/src/compat/register/protocol.ts +17 -18
  294. package/src/compat/register/proxy.ts +49 -51
  295. package/src/compat/register/render.ts +79 -76
  296. package/src/compat/register/routing.ts +162 -159
  297. package/src/compat/register/segment.ts +24 -1897
  298. package/src/compat/register/static-image.ts +3 -3
  299. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  300. package/src/compat/register/typed-routes.ts +14 -14
  301. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  302. package/src/compat/register/validation.ts +18 -18
  303. package/src/compat/segment/loading-boundary.ts +43 -45
  304. package/src/compat/segment/page-slot.ts +69 -69
  305. package/src/compat/segment/serve.ts +1884 -0
  306. package/src/compat/segment/tree.ts +113 -112
  307. package/src/compat/segment/vary-key.ts +38 -38
  308. package/src/compat/segment/vary-params.ts +138 -142
  309. package/src/compat/static-params.ts +14 -12
  310. package/src/compat/tsconfig-defaults.ts +87 -91
  311. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  312. package/src/compat/typecheck/worker.ts +15 -12
  313. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  314. package/src/compat/typed-routes/manifest.ts +174 -170
  315. package/src/compat/typed-routes/typegen.ts +127 -110
  316. package/src/compat/validation/errors.ts +16 -19
  317. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  318. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  319. package/src/compat-bootstrap.ts +16 -16
  320. package/src/config.ts +69 -69
  321. package/src/css/build.ts +230 -227
  322. package/src/css/postcss.ts +79 -80
  323. package/src/css/worker.ts +14 -15
  324. package/src/dev/client-actions.ts +10 -10
  325. package/src/dev/client-chunk-store.ts +27 -27
  326. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  327. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  328. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  329. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  330. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  331. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  332. package/src/dev/server.ts +804 -820
  333. package/src/env.ts +46 -43
  334. package/src/extensions.ts +491 -478
  335. package/src/index.ts +8 -8
  336. package/src/internal.ts +20 -23
  337. package/src/{islands → render}/boundary-error.ts +3 -3
  338. package/src/render/hooks.ts +71 -71
  339. package/src/render/island-context.ts +14 -14
  340. package/src/render/metadata.ts +310 -310
  341. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  342. package/src/{ppr.ts → render/ppr.ts} +244 -245
  343. package/src/render/renderer.ts +2076 -2082
  344. package/src/render/resource-hints.ts +16 -17
  345. package/src/render/slots.tsx +224 -235
  346. package/src/{islands → render}/static-children.ts +9 -12
  347. package/src/{islands → render}/static-slots.ts +37 -37
  348. package/src/{cache/context.ts → request/cache.ts} +20 -20
  349. package/src/request/context.ts +107 -107
  350. package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +318 -296
  354. package/src/resolve/source-text.ts +37 -37
  355. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  356. package/src/routing/forwarded.ts +19 -19
  357. package/src/routing/handler.ts +84 -91
  358. package/src/routing/href.ts +69 -70
  359. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  360. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  361. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  362. package/src/routing/routes.ts +827 -815
  363. package/src/routing/slots.ts +164 -160
  364. package/src/runtime/loader.ts +952 -0
  365. package/src/{dev → runtime}/module-cache.ts +309 -287
  366. package/src/{dev → runtime}/module-generations.ts +9 -9
  367. package/src/{dev → runtime}/module-transform.ts +81 -72
  368. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  369. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  370. package/src/runtime/vendor.ts +425 -404
  371. package/src/styles.d.ts +9 -0
  372. package/src/types.ts +320 -335
  373. package/src/utils/ansi.ts +5 -5
  374. package/src/utils/{source.ts → code.ts} +15 -12
  375. package/src/utils/content-type.ts +3 -3
  376. package/src/utils/decode.ts +2 -2
  377. package/src/utils/dev-profile.ts +13 -13
  378. package/src/utils/error-log.ts +6 -6
  379. package/src/utils/esbuild.ts +18 -18
  380. package/src/utils/fs-cache.ts +13 -13
  381. package/src/utils/fs.ts +57 -49
  382. package/src/utils/html.ts +20 -24
  383. package/src/utils/native-require.ts +8 -8
  384. package/src/utils/serialize.ts +139 -146
  385. package/src/utils/verbose.ts +18 -18
  386. package/src/cli/analyze-print.ts +0 -181
  387. package/src/compat/middleware/manifest.ts +0 -210
  388. package/src/compat/next/image-client.tsx +0 -215
  389. package/src/compat/next/link-usage.ts +0 -29
  390. package/src/css/index.ts +0 -2
  391. package/src/render/index.ts +0 -1
  392. package/src/style-modules.d.ts +0 -9
@@ -7,15 +7,15 @@
7
7
  * Installed once per process by `pnext build` / `pnext start` when Next
8
8
  * compat is enabled; plain fetches outside a render scope pass through.
9
9
  */
10
- import { currentCacheScope } from '../../cache/context';
10
+ import { currentCacheScope } from '../../request/cache'
11
11
  import {
12
12
  cacheComponents,
13
13
  hangingPromise,
14
14
  isPrerendering,
15
15
  realNow,
16
16
  trackPrerenderCacheFill,
17
- } from '../../ppr';
18
- import { cacheHandlerGet, cacheHandlerSet, hasCacheHandler } from './handler';
17
+ } from '../../render/ppr'
18
+ import { cacheHandlerGet, cacheHandlerSet, hasCacheHandler } from './handler'
19
19
  import {
20
20
  currentRenderCacheMeta,
21
21
  currentRenderIsStaticGeneration,
@@ -31,116 +31,116 @@ import {
31
31
  pathScopeRevalidated,
32
32
  tagsRevalidatedAfterSeq,
33
33
  tagsStaleSince,
34
- } from './revalidate';
35
- import { insideUseCacheProducer } from './use-cache';
34
+ } from './revalidate'
35
+ import { insideUseCacheProducer } from './use-cache'
36
36
 
37
- const MAX_TAGS = 128;
37
+ const MAX_TAGS = 128
38
38
 
39
39
  interface NextFetchOptions {
40
- revalidate?: number | false;
41
- tags?: string[];
40
+ revalidate?: number | false
41
+ tags?: string[]
42
42
  }
43
43
 
44
44
  interface FetchSnapshot {
45
- status: number;
46
- statusText: string;
47
- headers: [string, string][];
48
- body: Uint8Array;
49
- url: string;
45
+ status: number
46
+ statusText: string
47
+ headers: [string, string][]
48
+ body: Uint8Array
49
+ url: string
50
50
  }
51
51
 
52
52
  interface FetchCacheEntry {
53
- value: Promise<FetchSnapshot>;
54
- storedAt: number;
55
- tags: readonly string[];
56
- revalidateSeconds?: number;
53
+ value: Promise<FetchSnapshot>
54
+ storedAt: number
55
+ tags: readonly string[]
56
+ revalidateSeconds?: number
57
57
  /** A background stale-while-revalidate refresh is already in flight. */
58
- refreshing?: boolean;
58
+ refreshing?: boolean
59
59
  /** Pathname of the render that produced this entry (path-revalidation scope). */
60
- route?: string;
60
+ route?: string
61
61
  /**
62
62
  * Other routes that have SERVED this entry. One fetch cache entry is shared by every route issuing the
63
63
  * same request, and Next widens its implicit `_N_T_/<route>` soft tag on each read - so
64
64
  * revalidatePath('/b') expires an entry that /a produced and /b reused.
65
65
  */
66
- readRoutes?: string[];
66
+ readRoutes?: string[]
67
67
  /** Hard-tag-revalidation sequence sampled when this entry was produced. */
68
- tagSeq: number;
68
+ tagSeq: number
69
69
  /**
70
70
  * The render cache-meta this entry was produced under: an on-demand
71
71
  * regeneration (refreshFetches) refetches each entry once per render, then
72
72
  * repeated reads dedupe against it.
73
73
  */
74
- refreshedIn?: object;
74
+ refreshedIn?: object
75
75
  }
76
76
 
77
77
  export interface FetchRdcRecord {
78
- key: string;
78
+ key: string
79
79
  snapshot: {
80
- status: number;
81
- statusText: string;
82
- headers: [string, string][];
83
- body: string;
84
- url: string;
85
- };
86
- tags: string[];
87
- storedAt: number;
88
- tagSeq: number;
80
+ status: number
81
+ statusText: string
82
+ headers: [string, string][]
83
+ body: string
84
+ url: string
85
+ }
86
+ tags: string[]
87
+ storedAt: number
88
+ tagSeq: number
89
89
  /** Process that produced this record — `tagSeq` only means anything there. */
90
- pid?: string;
91
- revalidateSeconds?: number;
92
- route?: string;
90
+ pid?: string
91
+ revalidateSeconds?: number
92
+ route?: string
93
93
  }
94
94
 
95
- const FETCH_CACHE = Symbol.for('pnext.compat.fetchCache');
96
- const FETCH_CACHE_INSTALLED = Symbol.for('pnext.compat.fetchCacheInstalled');
95
+ const FETCH_CACHE = Symbol.for('pnext.compat.fetchCache')
96
+ const FETCH_CACHE_INSTALLED = Symbol.for('pnext.compat.fetchCacheInstalled')
97
97
 
98
98
  function fetchCacheStore(): Map<string, FetchCacheEntry> {
99
- const state = globalThis as Record<PropertyKey, unknown>;
100
- return (state[FETCH_CACHE] ??= new Map<string, FetchCacheEntry>()) as Map<string, FetchCacheEntry>;
99
+ const state = globalThis as Record<PropertyKey, unknown>
100
+ return (state[FETCH_CACHE] ??= new Map<string, FetchCacheEntry>()) as Map<string, FetchCacheEntry>
101
101
  }
102
102
 
103
103
  function fetchCacheInstalled(): boolean {
104
- return (globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] === true;
104
+ return (globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] === true
105
105
  }
106
106
 
107
107
  function markFetchCacheInstalled(): void {
108
- (globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] = true;
108
+ ;(globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] = true
109
109
  }
110
110
 
111
- const fetchCache = fetchCacheStore();
112
- const fetchCacheLimit = 2048;
113
- const FETCH_RDC_CAPTURE = Symbol.for('pnext.compat.fetchRdcCapture');
114
- const FETCH_RDC_RECORDS = Symbol.for('pnext.compat.fetchRdcRecords');
111
+ const fetchCache = fetchCacheStore()
112
+ const fetchCacheLimit = 2048
113
+ const FETCH_RDC_CAPTURE = Symbol.for('pnext.compat.fetchRdcCapture')
114
+ const FETCH_RDC_RECORDS = Symbol.for('pnext.compat.fetchRdcRecords')
115
115
 
116
116
  function fetchRdcRecords(): Map<string, FetchCacheEntry> {
117
- const state = globalThis as Record<PropertyKey, unknown>;
117
+ const state = globalThis as Record<PropertyKey, unknown>
118
118
  return (state[FETCH_RDC_RECORDS] ??= new Map<string, FetchCacheEntry>()) as Map<
119
119
  string,
120
120
  FetchCacheEntry
121
- >;
121
+ >
122
122
  }
123
123
 
124
124
  function fetchRdcCapture(): Set<string> | undefined {
125
- return (globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] as Set<string> | undefined;
125
+ return (globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] as Set<string> | undefined
126
126
  }
127
127
 
128
128
  function captureFetchRdcEntry(key: string) {
129
- fetchRdcCapture()?.add(key);
129
+ fetchRdcCapture()?.add(key)
130
130
  }
131
131
 
132
132
  export function beginFetchRdcCapture() {
133
- (globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] = new Set<string>();
133
+ ;(globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] = new Set<string>()
134
134
  }
135
135
 
136
136
  export async function collectFetchRdcRecords(): Promise<FetchRdcRecord[]> {
137
- const capture = fetchRdcCapture();
138
- if (!capture) return [];
139
- const records: FetchRdcRecord[] = [];
137
+ const capture = fetchRdcCapture()
138
+ if (!capture) return []
139
+ const records: FetchRdcRecord[] = []
140
140
  for (const key of capture) {
141
- const entry = fetchCache.get(key);
142
- if (!entry) continue;
143
- const snapshot = await entry.value;
141
+ const entry = fetchCache.get(key)
142
+ if (!entry) continue
143
+ const snapshot = await entry.value
144
144
  records.push({
145
145
  key,
146
146
  snapshot: {
@@ -154,11 +154,13 @@ export async function collectFetchRdcRecords(): Promise<FetchRdcRecord[]> {
154
154
  storedAt: entry.storedAt,
155
155
  tagSeq: entry.tagSeq,
156
156
  pid: rdcProcessId(),
157
- ...(entry.revalidateSeconds !== undefined ? { revalidateSeconds: entry.revalidateSeconds } : {}),
157
+ ...(entry.revalidateSeconds !== undefined
158
+ ? { revalidateSeconds: entry.revalidateSeconds }
159
+ : {}),
158
160
  ...(entry.route !== undefined ? { route: entry.route } : {}),
159
- });
161
+ })
160
162
  }
161
- return records;
163
+ return records
162
164
  }
163
165
 
164
166
  export function seedFetchRdcRecords(
@@ -167,11 +169,11 @@ export function seedFetchRdcRecords(
167
169
  routeTags: readonly string[] = [],
168
170
  ) {
169
171
  for (const record of records) {
170
- if (!isFetchRdcRecord(record)) continue;
172
+ if (!isFetchRdcRecord(record)) continue
171
173
  // An RDC artifact is a snapshot: seeding it must never regress a live
172
174
  // entry filled more recently (each regen seeds the stale .rdc first).
173
- const live = fetchCache.get(record.key);
174
- if (live !== undefined && live.storedAt > record.storedAt) continue;
175
+ const live = fetchCache.get(record.key)
176
+ if (live !== undefined && live.storedAt > record.storedAt) continue
175
177
  const entry: FetchCacheEntry = {
176
178
  value: Promise.resolve({
177
179
  status: record.snapshot.status,
@@ -191,33 +193,37 @@ export function seedFetchRdcRecords(
191
193
  ...(record.revalidateSeconds !== undefined
192
194
  ? { revalidateSeconds: record.revalidateSeconds }
193
195
  : {}),
194
- ...(route !== undefined ? { route } : record.route !== undefined ? { route: record.route } : {}),
195
- };
196
- fetchRdcRecords().set(record.key, entry);
197
- fetchCache.set(record.key, entry);
196
+ ...(route !== undefined
197
+ ? { route }
198
+ : record.route !== undefined
199
+ ? { route: record.route }
200
+ : {}),
201
+ }
202
+ fetchRdcRecords().set(record.key, entry)
203
+ fetchCache.set(record.key, entry)
198
204
  }
199
205
  }
200
206
 
201
207
  /** Widen an entry's path-revalidation scope with the route now reading it. */
202
208
  function noteFetchEntryRoute(entry: FetchCacheEntry, route: string | undefined): void {
203
- if (route === undefined || route === entry.route) return;
204
- const routes = (entry.readRoutes ??= []);
205
- if (routes.includes(route)) return;
206
- routes.push(route);
209
+ if (route === undefined || route === entry.route) return
210
+ const routes = (entry.readRoutes ??= [])
211
+ if (routes.includes(route)) return
212
+ routes.push(route)
207
213
  // A single entry read from an unbounded set of routes (dynamic pathnames)
208
214
  // must not grow without limit; the oldest reader's scope is dropped first.
209
- if (routes.length > 32) routes.shift();
215
+ if (routes.length > 32) routes.shift()
210
216
  }
211
217
 
212
218
  /** True when this entry's producing OR any reading route was revalidated. */
213
219
  function fetchEntryPathRevalidated(entry: FetchCacheEntry): boolean {
214
- if (pathScopeRevalidated(entry.route, entry.storedAt)) return true;
215
- return (entry.readRoutes ?? []).some(route => pathScopeRevalidated(route, entry.storedAt));
220
+ if (pathScopeRevalidated(entry.route, entry.storedAt)) return true
221
+ return (entry.readRoutes ?? []).some(route => pathScopeRevalidated(route, entry.storedAt))
216
222
  }
217
223
 
218
224
  function isFetchRdcRecord(value: unknown): value is FetchRdcRecord {
219
- if (!value || typeof value !== 'object') return false;
220
- const record = value as Partial<FetchRdcRecord>;
225
+ if (!value || typeof value !== 'object') return false
226
+ const record = value as Partial<FetchRdcRecord>
221
227
  return (
222
228
  typeof record.key === 'string' &&
223
229
  !!record.snapshot &&
@@ -225,7 +231,10 @@ function isFetchRdcRecord(value: unknown): value is FetchRdcRecord {
225
231
  typeof record.snapshot.statusText === 'string' &&
226
232
  Array.isArray(record.snapshot.headers) &&
227
233
  record.snapshot.headers.every(
228
- header => Array.isArray(header) && header.length === 2 && header.every(part => typeof part === 'string'),
234
+ header =>
235
+ Array.isArray(header) &&
236
+ header.length === 2 &&
237
+ header.every(part => typeof part === 'string'),
229
238
  ) &&
230
239
  typeof record.snapshot.body === 'string' &&
231
240
  typeof record.snapshot.url === 'string' &&
@@ -235,36 +244,36 @@ function isFetchRdcRecord(value: unknown): value is FetchRdcRecord {
235
244
  Number.isFinite(record.storedAt) &&
236
245
  typeof record.tagSeq === 'number' &&
237
246
  Number.isInteger(record.tagSeq)
238
- );
247
+ )
239
248
  }
240
249
 
241
250
  export function installCompatFetchCache() {
242
- if (fetchCacheInstalled()) return;
243
- markFetchCacheInstalled();
244
- registerDataCacheInvalidator(clearFetchCache);
245
- const original = globalThis.fetch.bind(globalThis);
251
+ if (fetchCacheInstalled()) return
252
+ markFetchCacheInstalled()
253
+ registerDataCacheInvalidator(clearFetchCache)
254
+ const original = globalThis.fetch.bind(globalThis)
246
255
 
247
256
  const patched = async function fetch(
248
257
  input: Parameters<typeof globalThis.fetch>[0],
249
258
  init?: RequestInit & { next?: NextFetchOptions },
250
259
  ): Promise<Response> {
251
- const normalized = await normalizeFetchArgs(input, init);
252
- if (!normalized) return original(input, init);
253
- const { request } = normalized;
260
+ const normalized = await normalizeFetchArgs(input, init)
261
+ if (!normalized) return original(input, init)
262
+ const { request } = normalized
254
263
  // A consumed stream body was buffered for the cache key; forward the bytes.
255
- if (normalized.replacementInit) init = { ...init, ...normalized.replacementInit };
264
+ if (normalized.replacementInit) init = { ...init, ...normalized.replacementInit }
256
265
 
257
- const nextOptions = init?.next ?? requestNextOptions(input);
258
- let tags = nextOptions?.tags ?? [];
266
+ const nextOptions = init?.next ?? requestNextOptions(input)
267
+ let tags = nextOptions?.tags ?? []
259
268
  if (tags.length > MAX_TAGS) {
260
269
  console.warn(
261
270
  `Warning: exceeded max tag count for ${request.url}, dropped tags: ${tags
262
271
  .slice(MAX_TAGS)
263
272
  .join(', ')}`,
264
- );
265
- tags = tags.slice(0, MAX_TAGS);
273
+ )
274
+ tags = tags.slice(0, MAX_TAGS)
266
275
  }
267
- const revalidate = nextOptions?.revalidate;
276
+ const revalidate = nextOptions?.revalidate
268
277
  if (
269
278
  revalidate !== undefined &&
270
279
  revalidate !== false &&
@@ -274,12 +283,12 @@ export function installCompatFetchCache() {
274
283
  `Invalid revalidate value "${String(revalidate)}" on "${
275
284
  currentRenderCacheMeta()?.route ?? request.url
276
285
  }", must be a non-negative number or false`,
277
- );
286
+ )
278
287
  }
279
- recordCacheTags(tags);
280
- if (typeof revalidate === 'number' && revalidate > 0) recordCacheRevalidate(revalidate);
288
+ recordCacheTags(tags)
289
+ if (typeof revalidate === 'number' && revalidate > 0) recordCacheRevalidate(revalidate)
281
290
 
282
- const cacheOption = init?.cache ?? requestCacheOption(input);
291
+ const cacheOption = init?.cache ?? requestCacheOption(input)
283
292
  if (
284
293
  insideDataCacheProducer() &&
285
294
  cacheOption === undefined &&
@@ -292,12 +301,12 @@ export function installCompatFetchCache() {
292
301
  // across entries whose keys differ.
293
302
  (!currentRenderIsStaticGeneration() || insideUseCacheProducer())
294
303
  ) {
295
- return original(input, init);
304
+ return original(input, init)
296
305
  }
297
306
 
298
- const segmentFetchCache = currentRenderCacheMeta()?.fetchCache;
307
+ const segmentFetchCache = currentRenderCacheMeta()?.fetchCache
299
308
  const segmentForcesCache =
300
- segmentFetchCache === 'force-cache' || segmentFetchCache === 'only-cache';
309
+ segmentFetchCache === 'force-cache' || segmentFetchCache === 'only-cache'
301
310
  // Explicit no-store signals opt the surrounding route out of prebuilt
302
311
  // static output (Next renders it dynamically per request) — unless the
303
312
  // segment's fetchCache forces caching, which supersedes them.
@@ -305,7 +314,7 @@ export function installCompatFetchCache() {
305
314
  !segmentForcesCache &&
306
315
  (cacheOption === 'no-store' || cacheOption === 'no-cache' || revalidate === 0)
307
316
  ) {
308
- recordCacheNoStore();
317
+ recordCacheNoStore()
309
318
  }
310
319
  // Route handlers never auto-cache an implicit/default fetch (Next treats
311
320
  // both forms as uncached), and it keeps the handler out of prebuilt static
@@ -313,8 +322,8 @@ export function installCompatFetchCache() {
313
322
  // prerender time.
314
323
  const handlerDefaultFetch =
315
324
  (cacheOption === undefined || cacheOption === 'default') &&
316
- currentRenderCacheMeta()?.handler === true;
317
- if (handlerDefaultFetch && !segmentForcesCache) recordCacheNoStore();
325
+ currentRenderCacheMeta()?.handler === true
326
+ if (handlerDefaultFetch && !segmentForcesCache) recordCacheNoStore()
318
327
 
319
328
  const mode = cacheModeFor(
320
329
  cacheOption,
@@ -322,34 +331,26 @@ export function installCompatFetchCache() {
322
331
  segmentFetchCache,
323
332
  request.method,
324
333
  currentRenderIsStaticGeneration() && !handlerDefaultFetch,
325
- );
326
- if (
327
- mode !== 'cache' &&
328
- cacheComponents() &&
329
- isPrerendering() &&
330
- !insideDataCacheProducer()
331
- ) {
332
- return hangingPromise<Response>('fetch()');
334
+ )
335
+ if (mode !== 'cache' && cacheComponents() && isPrerendering() && !insideDataCacheProducer()) {
336
+ return hangingPromise<Response>('fetch()')
333
337
  }
334
- if (mode === 'bypass') return original(input, init);
338
+ if (mode === 'bypass') return original(input, init)
335
339
 
336
- const key = fetchCacheKey(request);
340
+ const key = fetchCacheKey(request)
337
341
 
338
342
  if (mode === 'cache' && !draftModeBypassActive()) {
339
- const meta = currentRenderCacheMeta();
340
- const resumeEntry = fetchRdcRecords().get(key);
343
+ const meta = currentRenderCacheMeta()
344
+ const resumeEntry = fetchRdcRecords().get(key)
341
345
  if (
342
346
  resumeEntry &&
343
- !tagsRevalidatedAfterSeq(
344
- [...resumeEntry.tags, ...tags],
345
- resumeEntry.tagSeq,
346
- ) &&
347
+ !tagsRevalidatedAfterSeq([...resumeEntry.tags, ...tags], resumeEntry.tagSeq) &&
347
348
  !fetchEntryPathRevalidated(resumeEntry) &&
348
349
  (fetchCache.get(key)?.storedAt ?? -1) <= resumeEntry.storedAt
349
350
  ) {
350
- fetchCache.set(key, resumeEntry);
351
+ fetchCache.set(key, resumeEntry)
351
352
  }
352
- const preRefreshEntry = fetchCache.get(key);
353
+ const preRefreshEntry = fetchCache.get(key)
353
354
  // On-demand revalidation refetches each entry ONCE per render (Next skips the cache read entirely
354
355
  // under isOnDemandRevalidate), then dedupes via refreshedIn - but only entries the revalidation
355
356
  // actually reached. See the matching gate in use-cache.ts: a still-marked route re-renders many
@@ -358,23 +359,20 @@ export function installCompatFetchCache() {
358
359
  meta?.refreshFetches === true &&
359
360
  preRefreshEntry?.refreshedIn !== meta &&
360
361
  (preRefreshEntry === undefined ||
361
- tagsRevalidatedAfterSeq(
362
- [...preRefreshEntry.tags, ...tags],
363
- preRefreshEntry.tagSeq,
364
- ) ||
362
+ tagsRevalidatedAfterSeq([...preRefreshEntry.tags, ...tags], preRefreshEntry.tagSeq) ||
365
363
  fetchEntryPathRevalidated(preRefreshEntry) ||
366
364
  tagsStaleSince(preRefreshEntry.tags, preRefreshEntry.storedAt) ||
367
- fetchEntryExpired(preRefreshEntry));
365
+ fetchEntryExpired(preRefreshEntry))
368
366
  const revalidateSeconds =
369
- typeof revalidate === 'number' && revalidate > 0 ? revalidate : undefined;
370
- const blockingStale = currentRenderCacheMeta()?.blockingStaleFetches === true;
367
+ typeof revalidate === 'number' && revalidate > 0 ? revalidate : undefined
368
+ const blockingStale = currentRenderCacheMeta()?.blockingStaleFetches === true
371
369
  // Seed the in-memory entry from the configured cache handler on a miss,
372
370
  // so the handler observes every read (its get() logs are asserted) and
373
371
  // persists entries across the SWR window / restarts.
374
- let entry = fetchCache.get(key);
372
+ let entry = fetchCache.get(key)
375
373
  if (!entry && !refresh && hasCacheHandler()) {
376
- const persisted = await cacheHandlerGet(key, { tags });
377
- const snapshot = persistedSnapshot(persisted?.value);
374
+ const persisted = await cacheHandlerGet(key, { tags })
375
+ const snapshot = persistedSnapshot(persisted?.value)
378
376
  if (snapshot) {
379
377
  entry = {
380
378
  value: Promise.resolve(snapshot),
@@ -385,21 +383,21 @@ export function installCompatFetchCache() {
385
383
  ...(currentRenderCacheMeta()?.route !== undefined
386
384
  ? { route: currentRenderCacheMeta()?.route }
387
385
  : {}),
388
- };
389
- fetchCache.set(key, entry);
386
+ }
387
+ fetchCache.set(key, entry)
390
388
  }
391
389
  }
392
390
  // This render's route joins the entry's path-revalidation scope before
393
391
  // the freshness check, so revalidatePath() of a route that only REUSES a
394
392
  // shared entry expires it too.
395
- if (entry) noteFetchEntryRoute(entry, meta?.route);
393
+ if (entry) noteFetchEntryRoute(entry, meta?.route)
396
394
  if (
397
395
  entry &&
398
396
  !refresh &&
399
397
  !tagsRevalidatedAfterSeq([...entry.tags, ...tags], entry.tagSeq) &&
400
398
  !fetchEntryPathRevalidated(entry)
401
399
  ) {
402
- const tagStale = tagsStaleSince(entry.tags, entry.storedAt);
400
+ const tagStale = tagsStaleSince(entry.tags, entry.storedAt)
403
401
  // Staleness honours THIS call's revalidate, not only the value baked
404
402
  // into the stored entry. The data cache is shared by URL across routes,
405
403
  // so a shorter-lived reader (e.g. a `revalidate: 9` fetch) can find an
@@ -408,52 +406,56 @@ export function installCompatFetchCache() {
408
406
  // expires). Without folding the current revalidate into the check, that
409
407
  // reader's window would be silently ignored and its page would never
410
408
  // refresh (app-static variable-config-revalidate under a full suite).
411
- if (!tagStale && !fetchEntryExpired(entry) && !currentRequestExpired(entry, revalidateSeconds)) {
412
- captureFetchRdcEntry(key);
413
- return snapshotResponse(await entry.value);
409
+ if (
410
+ !tagStale &&
411
+ !fetchEntryExpired(entry) &&
412
+ !currentRequestExpired(entry, revalidateSeconds)
413
+ ) {
414
+ captureFetchRdcEntry(key)
415
+ return snapshotResponse(await entry.value)
414
416
  }
415
417
  // TTL expiry: serve stale, refresh in the background (Next's SWR
416
418
  // data-cache semantics) — except inside an ISR regeneration render,
417
419
  // which refetches inline. On-demand invalidation above blocks too.
418
420
  if (!blockingStale) {
419
421
  if (!entry.refreshing) {
420
- entry.refreshing = true;
421
- void storeFetchEntry(key, original, input, init, tags, revalidateSeconds, entry);
422
+ entry.refreshing = true
423
+ void storeFetchEntry(key, original, input, init, tags, revalidateSeconds, entry)
422
424
  }
423
- captureFetchRdcEntry(key);
424
- return snapshotResponse(await entry.value);
425
+ captureFetchRdcEntry(key)
426
+ return snapshotResponse(await entry.value)
425
427
  }
426
428
  }
427
- const value = storeFetchEntry(key, original, input, init, tags, revalidateSeconds);
428
- return snapshotResponse(await value);
429
+ const value = storeFetchEntry(key, original, input, init, tags, revalidateSeconds)
430
+ return snapshotResponse(await value)
429
431
  }
430
432
 
431
433
  // Uncached, but dedupe identical GETs within the render pass.
432
- const scope = currentCacheScope();
433
- if (!scope) return original(input, init);
434
- scope.fetches ??= new Map();
435
- let pending = scope.fetches.get(key) as Promise<FetchSnapshot> | undefined;
434
+ const scope = currentCacheScope()
435
+ if (!scope) return original(input, init)
436
+ scope.fetches ??= new Map()
437
+ let pending = scope.fetches.get(key) as Promise<FetchSnapshot> | undefined
436
438
  if (!pending) {
437
- pending = snapshotFetch(original, input, init);
438
- scope.fetches.set(key, pending);
439
+ pending = snapshotFetch(original, input, init)
440
+ scope.fetches.set(key, pending)
439
441
  }
440
- return snapshotResponse(await pending);
441
- };
442
+ return snapshotResponse(await pending)
443
+ }
442
444
 
443
- globalThis.fetch = patched as typeof globalThis.fetch;
445
+ globalThis.fetch = patched as typeof globalThis.fetch
444
446
  }
445
447
 
446
448
  interface NormalizedFetchRequest {
447
- url: string;
448
- method: string;
449
- headers: [string, string][];
450
- body?: string;
449
+ url: string
450
+ method: string
451
+ headers: [string, string][]
452
+ body?: string
451
453
  }
452
454
 
453
455
  interface NormalizedFetchArgs {
454
- request: NormalizedFetchRequest;
456
+ request: NormalizedFetchRequest
455
457
  /** Set when a one-shot body (stream) was buffered and must be re-sent as bytes. */
456
- replacementInit?: { body: BodyInit };
458
+ replacementInit?: { body: BodyInit }
457
459
  }
458
460
 
459
461
  async function normalizeFetchArgs(
@@ -461,34 +463,34 @@ async function normalizeFetchArgs(
461
463
  init?: RequestInit,
462
464
  ): Promise<NormalizedFetchArgs | null> {
463
465
  try {
464
- let url: string;
465
- let method = 'GET';
466
- let headers: Headers;
466
+ let url: string
467
+ let method = 'GET'
468
+ let headers: Headers
467
469
 
468
470
  if (typeof input === 'string' || input instanceof URL) {
469
- url = String(input);
470
- method = (init?.method ?? 'GET').toUpperCase();
471
- headers = new Headers(init?.headers);
471
+ url = String(input)
472
+ method = (init?.method ?? 'GET').toUpperCase()
473
+ headers = new Headers(init?.headers)
472
474
  } else if (input instanceof Request) {
473
- if (input.body != null) return null;
474
- url = input.url;
475
- method = (init?.method ?? input.method).toUpperCase();
476
- headers = new Headers(init?.headers ?? input.headers);
475
+ if (input.body != null) return null
476
+ url = input.url
477
+ method = (init?.method ?? input.method).toUpperCase()
478
+ headers = new Headers(init?.headers ?? input.headers)
477
479
  } else {
478
- return null;
480
+ return null
479
481
  }
480
- if (!/^https?:/.test(url)) return null;
482
+ if (!/^https?:/.test(url)) return null
481
483
 
482
- const normalizedBody = await normalizeFetchBody(init?.body);
483
- if (normalizedBody === null) return null;
484
+ const normalizedBody = await normalizeFetchBody(init?.body)
485
+ if (normalizedBody === null) return null
484
486
  return {
485
487
  request: { url, method, headers: [...headers.entries()], body: normalizedBody?.key },
486
488
  ...(normalizedBody?.replacement !== undefined
487
489
  ? { replacementInit: { body: normalizedBody.replacement } }
488
490
  : {}),
489
- };
491
+ }
490
492
  } catch {
491
- return null;
493
+ return null
492
494
  }
493
495
  }
494
496
 
@@ -500,42 +502,42 @@ async function normalizeFetchArgs(
500
502
  async function normalizeFetchBody(
501
503
  body: BodyInit | null | undefined,
502
504
  ): Promise<{ key: string; replacement?: BodyInit } | undefined | null> {
503
- if (body == null) return undefined;
504
- if (typeof body === 'string') return { key: body };
505
- if (body instanceof URLSearchParams) return { key: body.toString() };
506
- if (body instanceof ArrayBuffer) return { key: bytesKey(new Uint8Array(body)) };
505
+ if (body == null) return undefined
506
+ if (typeof body === 'string') return { key: body }
507
+ if (body instanceof URLSearchParams) return { key: body.toString() }
508
+ if (body instanceof ArrayBuffer) return { key: bytesKey(new Uint8Array(body)) }
507
509
  if (ArrayBuffer.isView(body)) {
508
- return { key: bytesKey(new Uint8Array(body.buffer, body.byteOffset, body.byteLength)) };
510
+ return { key: bytesKey(new Uint8Array(body.buffer, body.byteOffset, body.byteLength)) }
509
511
  }
510
512
  if (body instanceof ReadableStream) {
511
- const bytes = new Uint8Array(await new Response(body).arrayBuffer());
512
- return { key: bytesKey(bytes), replacement: bytes as BodyInit };
513
+ const bytes = new Uint8Array(await new Response(body).arrayBuffer())
514
+ return { key: bytesKey(bytes), replacement: bytes as BodyInit }
513
515
  }
514
516
  if (body instanceof FormData) {
515
517
  // Reading entries does not consume the body; fetch re-serializes it.
516
- const parts: string[] = [];
518
+ const parts: string[] = []
517
519
  for (const [name, value] of body.entries()) {
518
- parts.push(name, typeof value === 'string' ? value : await (value as Blob).text());
520
+ parts.push(name, typeof value === 'string' ? value : await (value as Blob).text())
519
521
  }
520
- return { key: parts.join(' ') };
522
+ return { key: parts.join(' ') }
521
523
  }
522
- return null;
524
+ return null
523
525
  }
524
526
 
525
527
  function bytesKey(bytes: Uint8Array) {
526
- return Buffer.from(bytes).toString('base64');
528
+ return Buffer.from(bytes).toString('base64')
527
529
  }
528
530
 
529
531
  function requestNextOptions(input: unknown): NextFetchOptions | undefined {
530
- return (input as { next?: NextFetchOptions } | null | undefined)?.next;
532
+ return (input as { next?: NextFetchOptions } | null | undefined)?.next
531
533
  }
532
534
 
533
535
  function requestCacheOption(input: unknown): RequestCache | undefined {
534
- if (input instanceof Request) return input.cache;
535
- return undefined;
536
+ if (input instanceof Request) return input.cache
537
+ return undefined
536
538
  }
537
539
 
538
- type CacheMode = 'cache' | 'dedupe' | 'bypass';
540
+ type CacheMode = 'cache' | 'dedupe' | 'bypass'
539
541
 
540
542
  function cacheModeFor(
541
543
  cacheOption: RequestCache | undefined,
@@ -545,21 +547,21 @@ function cacheModeFor(
545
547
  staticGeneration: boolean,
546
548
  ): CacheMode {
547
549
  if (segmentFetchCache === 'force-no-store' || segmentFetchCache === 'only-no-store') {
548
- return 'dedupe';
550
+ return 'dedupe'
549
551
  }
550
552
  // Segment-level force-cache supersedes even explicit no-store fetch options.
551
553
  if (segmentFetchCache === 'force-cache' || segmentFetchCache === 'only-cache') {
552
- return revalidate === 0 ? 'dedupe' : 'cache';
554
+ return revalidate === 0 ? 'dedupe' : 'cache'
553
555
  }
554
556
  if (cacheOption === 'no-store' || cacheOption === 'no-cache' || revalidate === 0) {
555
- return 'dedupe';
557
+ return 'dedupe'
556
558
  }
557
559
  if (
558
560
  cacheOption === 'force-cache' ||
559
561
  revalidate === false ||
560
562
  (typeof revalidate === 'number' && revalidate > 0)
561
563
  ) {
562
- return 'cache';
564
+ return 'cache'
563
565
  }
564
566
  // Auto (no explicit option): uncached per-request at runtime, but during
565
567
  // static generation a plain GET defaults to force-cache (Next semantics).
@@ -569,22 +571,22 @@ function cacheModeFor(
569
571
  // data, so a prerender postpones the boundary around it instead of baking the
570
572
  // response in (cache-components-errors dynamic-boundary expects the prerender
571
573
  // to keep its `<Suspense>` fallbacks).
572
- if (staticGeneration && method === 'GET' && !cacheComponents()) return 'cache';
573
- return 'dedupe';
574
+ if (staticGeneration && method === 'GET' && !cacheComponents()) return 'cache'
575
+ return 'dedupe'
574
576
  }
575
577
 
576
578
  function fetchCacheKey(request: NormalizedFetchRequest): string {
577
579
  const headers = request.headers
578
580
  .filter(([name]) => name !== 'traceparent' && name !== 'tracestate')
579
- .sort((a, b) => a[0].localeCompare(b[0]));
580
- return JSON.stringify([request.method, request.url, headers, request.body ?? null]);
581
+ .sort((a, b) => a[0].localeCompare(b[0]))
582
+ return JSON.stringify([request.method, request.url, headers, request.body ?? null])
581
583
  }
582
584
 
583
585
  function fetchEntryExpired(entry: FetchCacheEntry) {
584
586
  return (
585
587
  entry.revalidateSeconds !== undefined &&
586
588
  realNow() - entry.storedAt >= entry.revalidateSeconds * 1000
587
- );
589
+ )
588
590
  }
589
591
 
590
592
  // Staleness as seen by the CURRENT fetch call: its own `revalidate` window,
@@ -592,9 +594,7 @@ function fetchEntryExpired(entry: FetchCacheEntry) {
592
594
  // which only knows the window baked in when the entry was stored — a later
593
595
  // reader with a shorter revalidate must still see its own expiry.
594
596
  function currentRequestExpired(entry: FetchCacheEntry, revalidateSeconds: number | undefined) {
595
- return (
596
- revalidateSeconds !== undefined && realNow() - entry.storedAt >= revalidateSeconds * 1000
597
- );
597
+ return revalidateSeconds !== undefined && realNow() - entry.storedAt >= revalidateSeconds * 1000
598
598
  }
599
599
 
600
600
  function storeFetchEntry(
@@ -606,13 +606,13 @@ function storeFetchEntry(
606
606
  revalidateSeconds: number | undefined,
607
607
  serveStale?: FetchCacheEntry,
608
608
  ): Promise<FetchSnapshot> {
609
- const value = snapshotFetch(original, input, init);
609
+ const value = snapshotFetch(original, input, init)
610
610
  // Same contract as the 'use cache' / data-cache fills: a build prerender's
611
611
  // task boundary waits for an in-flight CACHED fetch rather than cutting it
612
612
  // short, so its result still lands in the static shell (core ppr).
613
- void trackPrerenderCacheFill(value);
614
- const producingMeta = currentRenderCacheMeta();
615
- const route = serveStale?.route ?? producingMeta?.route;
613
+ void trackPrerenderCacheFill(value)
614
+ const producingMeta = currentRenderCacheMeta()
615
+ const route = serveStale?.route ?? producingMeta?.route
616
616
  const stored: FetchCacheEntry = {
617
617
  value,
618
618
  // realNow: a build prerender freezes Date.now() to 0 (prerender
@@ -627,60 +627,60 @@ function storeFetchEntry(
627
627
  // A background refresh replaces the entry: the routes that had joined its
628
628
  // revalidation scope keep it (they still read this key).
629
629
  ...(serveStale?.readRoutes?.length ? { readRoutes: [...serveStale.readRoutes] } : {}),
630
- };
630
+ }
631
631
  if (serveStale) {
632
632
  value.then(
633
633
  snapshot => {
634
634
  if (snapshot.status === 200) {
635
- fetchCache.set(key, stored);
636
- void persistFetchEntry(key, snapshot, tags, revalidateSeconds);
637
- } else serveStale.refreshing = false;
635
+ fetchCache.set(key, stored)
636
+ void persistFetchEntry(key, snapshot, tags, revalidateSeconds)
637
+ } else serveStale.refreshing = false
638
638
  },
639
639
  () => {
640
- serveStale.refreshing = false;
640
+ serveStale.refreshing = false
641
641
  },
642
- );
643
- return value;
642
+ )
643
+ return value
644
644
  }
645
645
  if (fetchCache.size >= fetchCacheLimit) {
646
- const oldest = fetchCache.keys().next().value;
647
- if (oldest !== undefined) fetchCache.delete(oldest);
646
+ const oldest = fetchCache.keys().next().value
647
+ if (oldest !== undefined) fetchCache.delete(oldest)
648
648
  }
649
- fetchCache.set(key, stored);
650
- captureFetchRdcEntry(key);
649
+ fetchCache.set(key, stored)
650
+ captureFetchRdcEntry(key)
651
651
  value.then(
652
652
  snapshot => {
653
653
  // Only 200s are cached (Next does not cache error statuses).
654
- if (snapshot.status !== 200 && fetchCache.get(key) === stored) fetchCache.delete(key);
655
- else void persistFetchEntry(key, snapshot, tags, revalidateSeconds);
654
+ if (snapshot.status !== 200 && fetchCache.get(key) === stored) fetchCache.delete(key)
655
+ else void persistFetchEntry(key, snapshot, tags, revalidateSeconds)
656
656
  },
657
657
  () => {
658
- if (fetchCache.get(key) === stored) fetchCache.delete(key);
658
+ if (fetchCache.get(key) === stored) fetchCache.delete(key)
659
659
  },
660
- );
661
- return value;
660
+ )
661
+ return value
662
662
  }
663
663
 
664
664
  /** Snapshot <-> serializable value stored through the custom cache handler. */
665
665
  interface PersistedFetch {
666
- status: number;
667
- statusText: string;
668
- headers: [string, string][];
669
- body: string;
670
- url: string;
666
+ status: number
667
+ statusText: string
668
+ headers: [string, string][]
669
+ body: string
670
+ url: string
671
671
  }
672
672
 
673
673
  function persistedSnapshot(value: unknown): FetchSnapshot | undefined {
674
- if (!value || typeof value !== 'object') return undefined;
675
- const v = value as Partial<PersistedFetch>;
676
- if (typeof v.status !== 'number' || typeof v.body !== 'string') return undefined;
674
+ if (!value || typeof value !== 'object') return undefined
675
+ const v = value as Partial<PersistedFetch>
676
+ if (typeof v.status !== 'number' || typeof v.body !== 'string') return undefined
677
677
  return {
678
678
  status: v.status,
679
679
  statusText: v.statusText ?? '',
680
680
  headers: v.headers ?? [],
681
681
  body: new Uint8Array(Buffer.from(v.body, 'base64')),
682
682
  url: v.url ?? '',
683
- };
683
+ }
684
684
  }
685
685
 
686
686
  async function persistFetchEntry(
@@ -689,14 +689,14 @@ async function persistFetchEntry(
689
689
  tags: readonly string[],
690
690
  revalidateSeconds: number | undefined,
691
691
  ): Promise<void> {
692
- if (!hasCacheHandler()) return;
692
+ if (!hasCacheHandler()) return
693
693
  const value: PersistedFetch = {
694
694
  status: snapshot.status,
695
695
  statusText: snapshot.statusText,
696
696
  headers: snapshot.headers,
697
697
  body: Buffer.from(snapshot.body).toString('base64'),
698
698
  url: snapshot.url,
699
- };
699
+ }
700
700
  // fetchCache/fetchUrl mirror Next's incremental-cache ctx for fetch writes;
701
701
  // custom handlers key their logging/persistence off them.
702
702
  await cacheHandlerSet(key, value, {
@@ -704,7 +704,7 @@ async function persistFetchEntry(
704
704
  revalidate: revalidateSeconds ?? false,
705
705
  fetchCache: true,
706
706
  fetchUrl: snapshot.url || undefined,
707
- });
707
+ })
708
708
  }
709
709
 
710
710
  async function snapshotFetch(
@@ -712,18 +712,18 @@ async function snapshotFetch(
712
712
  input: Parameters<typeof globalThis.fetch>[0],
713
713
  init?: RequestInit,
714
714
  ): Promise<FetchSnapshot> {
715
- const response = await original(input, init);
716
- const body = new Uint8Array(await response.arrayBuffer());
715
+ const response = await original(input, init)
716
+ const body = new Uint8Array(await response.arrayBuffer())
717
717
  const headers = [...response.headers.entries()].filter(
718
718
  ([name]) => !['content-encoding', 'content-length', 'transfer-encoding'].includes(name),
719
- );
719
+ )
720
720
  return {
721
721
  status: response.status,
722
722
  statusText: response.statusText,
723
723
  headers,
724
724
  body,
725
725
  url: response.url,
726
- };
726
+ }
727
727
  }
728
728
 
729
729
  function snapshotResponse(snapshot: FetchSnapshot): Response {
@@ -731,15 +731,15 @@ function snapshotResponse(snapshot: FetchSnapshot): Response {
731
731
  status: snapshot.status,
732
732
  statusText: snapshot.statusText,
733
733
  headers: snapshot.headers,
734
- });
734
+ })
735
735
  // Response.url is read-only and lost through the constructor; restore it.
736
736
  if (snapshot.url) {
737
- Object.defineProperty(response, 'url', { value: snapshot.url, configurable: true });
737
+ Object.defineProperty(response, 'url', { value: snapshot.url, configurable: true })
738
738
  }
739
- return response;
739
+ return response
740
740
  }
741
741
 
742
742
  /** Test hook: drop all cached fetch entries. */
743
743
  export function clearFetchCache() {
744
- fetchCache.clear();
744
+ fetchCache.clear()
745
745
  }