vinext 0.0.47 → 0.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +1 -1
  2. package/dist/build/layout-classification.js +3 -1
  3. package/dist/build/layout-classification.js.map +1 -1
  4. package/dist/build/prerender.js +10 -10
  5. package/dist/build/prerender.js.map +1 -1
  6. package/dist/build/report.d.ts +8 -4
  7. package/dist/build/report.js +17 -7
  8. package/dist/build/report.js.map +1 -1
  9. package/dist/build/run-prerender.d.ts +5 -0
  10. package/dist/build/run-prerender.js +4 -1
  11. package/dist/build/run-prerender.js.map +1 -1
  12. package/dist/build/server-manifest.js +2 -7
  13. package/dist/build/server-manifest.js.map +1 -1
  14. package/dist/build/standalone.js +3 -5
  15. package/dist/build/standalone.js.map +1 -1
  16. package/dist/check.js +45 -29
  17. package/dist/check.js.map +1 -1
  18. package/dist/cli-args.d.ts +3 -1
  19. package/dist/cli-args.js +18 -1
  20. package/dist/cli-args.js.map +1 -1
  21. package/dist/cli.js +9 -1
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config/config-matchers.js +46 -37
  24. package/dist/config/config-matchers.js.map +1 -1
  25. package/dist/deploy.d.ts +18 -2
  26. package/dist/deploy.js +47 -4
  27. package/dist/deploy.js.map +1 -1
  28. package/dist/entries/app-rsc-entry.js +11 -9
  29. package/dist/entries/app-rsc-entry.js.map +1 -1
  30. package/dist/entries/app-rsc-manifest.js +4 -1
  31. package/dist/entries/app-rsc-manifest.js.map +1 -1
  32. package/dist/entries/pages-client-entry.js +3 -2
  33. package/dist/entries/pages-client-entry.js.map +1 -1
  34. package/dist/entries/pages-server-entry.js +14 -59
  35. package/dist/entries/pages-server-entry.js.map +1 -1
  36. package/dist/entries/runtime-entry-module.d.ts +12 -3
  37. package/dist/entries/runtime-entry-module.js +15 -4
  38. package/dist/entries/runtime-entry-module.js.map +1 -1
  39. package/dist/index.js +12 -7
  40. package/dist/index.js.map +1 -1
  41. package/dist/plugins/og-assets.js +15 -16
  42. package/dist/plugins/og-assets.js.map +1 -1
  43. package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
  44. package/dist/plugins/rsc-client-shim-excludes.js +10 -1
  45. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  46. package/dist/routing/app-route-graph.d.ts +90 -4
  47. package/dist/routing/app-route-graph.js +210 -7
  48. package/dist/routing/app-route-graph.js.map +1 -1
  49. package/dist/routing/app-router.d.ts +15 -3
  50. package/dist/routing/app-router.js +20 -23
  51. package/dist/routing/app-router.js.map +1 -1
  52. package/dist/routing/file-matcher.d.ts +3 -1
  53. package/dist/routing/file-matcher.js +6 -1
  54. package/dist/routing/file-matcher.js.map +1 -1
  55. package/dist/routing/pages-router.js +10 -19
  56. package/dist/routing/pages-router.js.map +1 -1
  57. package/dist/routing/route-matching.d.ts +28 -0
  58. package/dist/routing/route-matching.js +44 -0
  59. package/dist/routing/route-matching.js.map +1 -0
  60. package/dist/routing/route-pattern.js +4 -1
  61. package/dist/routing/route-pattern.js.map +1 -1
  62. package/dist/routing/route-trie.d.ts +8 -0
  63. package/dist/routing/route-trie.js +12 -1
  64. package/dist/routing/route-trie.js.map +1 -1
  65. package/dist/routing/route-validation.js +3 -4
  66. package/dist/routing/route-validation.js.map +1 -1
  67. package/dist/routing/utils.d.ts +8 -1
  68. package/dist/routing/utils.js +25 -2
  69. package/dist/routing/utils.js.map +1 -1
  70. package/dist/server/app-browser-entry.js +66 -49
  71. package/dist/server/app-browser-entry.js.map +1 -1
  72. package/dist/server/app-browser-navigation-controller.d.ts +7 -5
  73. package/dist/server/app-browser-navigation-controller.js +43 -35
  74. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  75. package/dist/server/app-browser-state.d.ts +33 -15
  76. package/dist/server/app-browser-state.js +52 -59
  77. package/dist/server/app-browser-state.js.map +1 -1
  78. package/dist/server/app-browser-visible-commit.d.ts +68 -0
  79. package/dist/server/app-browser-visible-commit.js +182 -0
  80. package/dist/server/app-browser-visible-commit.js.map +1 -0
  81. package/dist/server/app-client-reference-preloader.d.ts +15 -0
  82. package/dist/server/app-client-reference-preloader.js +46 -0
  83. package/dist/server/app-client-reference-preloader.js.map +1 -0
  84. package/dist/server/app-elements-wire.d.ts +130 -0
  85. package/dist/server/app-elements-wire.js +205 -0
  86. package/dist/server/app-elements-wire.js.map +1 -0
  87. package/dist/server/app-elements.d.ts +2 -84
  88. package/dist/server/app-elements.js +3 -102
  89. package/dist/server/app-elements.js.map +1 -1
  90. package/dist/server/app-fallback-renderer.d.ts +1 -1
  91. package/dist/server/app-middleware.d.ts +2 -1
  92. package/dist/server/app-middleware.js +34 -11
  93. package/dist/server/app-middleware.js.map +1 -1
  94. package/dist/server/app-page-boundary-render.d.ts +1 -1
  95. package/dist/server/app-page-boundary-render.js +8 -5
  96. package/dist/server/app-page-boundary-render.js.map +1 -1
  97. package/dist/server/app-page-boundary.js +2 -1
  98. package/dist/server/app-page-boundary.js.map +1 -1
  99. package/dist/server/app-page-cache.d.ts +1 -0
  100. package/dist/server/app-page-cache.js +8 -13
  101. package/dist/server/app-page-cache.js.map +1 -1
  102. package/dist/server/app-page-dispatch.d.ts +2 -1
  103. package/dist/server/app-page-dispatch.js +18 -10
  104. package/dist/server/app-page-dispatch.js.map +1 -1
  105. package/dist/server/app-page-element-builder.d.ts +1 -1
  106. package/dist/server/app-page-element-builder.js +8 -5
  107. package/dist/server/app-page-element-builder.js.map +1 -1
  108. package/dist/server/app-page-execution.d.ts +23 -5
  109. package/dist/server/app-page-execution.js +39 -24
  110. package/dist/server/app-page-execution.js.map +1 -1
  111. package/dist/server/app-page-head.js +2 -1
  112. package/dist/server/app-page-head.js.map +1 -1
  113. package/dist/server/app-page-method.js +2 -5
  114. package/dist/server/app-page-method.js.map +1 -1
  115. package/dist/server/app-page-probe.d.ts +1 -1
  116. package/dist/server/app-page-probe.js +5 -1
  117. package/dist/server/app-page-probe.js.map +1 -1
  118. package/dist/server/app-page-render.d.ts +1 -1
  119. package/dist/server/app-page-render.js +38 -3
  120. package/dist/server/app-page-render.js.map +1 -1
  121. package/dist/server/app-page-request.d.ts +0 -1
  122. package/dist/server/app-page-request.js +7 -10
  123. package/dist/server/app-page-request.js.map +1 -1
  124. package/dist/server/app-page-response.js +3 -2
  125. package/dist/server/app-page-response.js.map +1 -1
  126. package/dist/server/app-page-route-wiring.d.ts +5 -2
  127. package/dist/server/app-page-route-wiring.js +15 -12
  128. package/dist/server/app-page-route-wiring.js.map +1 -1
  129. package/dist/server/app-page-stream.d.ts +7 -0
  130. package/dist/server/app-page-stream.js +9 -2
  131. package/dist/server/app-page-stream.js.map +1 -1
  132. package/dist/server/app-prerender-endpoints.js +3 -2
  133. package/dist/server/app-prerender-endpoints.js.map +1 -1
  134. package/dist/server/app-route-handler-cache.js +2 -1
  135. package/dist/server/app-route-handler-cache.js.map +1 -1
  136. package/dist/server/app-route-handler-dispatch.js +6 -5
  137. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  138. package/dist/server/app-route-handler-policy.js +13 -13
  139. package/dist/server/app-route-handler-policy.js.map +1 -1
  140. package/dist/server/app-route-handler-response.js +2 -1
  141. package/dist/server/app-route-handler-response.js.map +1 -1
  142. package/dist/server/app-route-handler-runtime.d.ts +9 -1
  143. package/dist/server/app-route-handler-runtime.js +11 -1
  144. package/dist/server/app-route-handler-runtime.js.map +1 -1
  145. package/dist/server/app-router-entry.js +9 -4
  146. package/dist/server/app-router-entry.js.map +1 -1
  147. package/dist/server/app-rsc-cache-busting.d.ts +34 -0
  148. package/dist/server/app-rsc-cache-busting.js +137 -0
  149. package/dist/server/app-rsc-cache-busting.js.map +1 -0
  150. package/dist/server/app-rsc-handler.js +22 -11
  151. package/dist/server/app-rsc-handler.js.map +1 -1
  152. package/dist/server/app-rsc-request-normalization.d.ts +4 -2
  153. package/dist/server/app-rsc-request-normalization.js +10 -6
  154. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  155. package/dist/server/app-rsc-response-finalizer.js +1 -1
  156. package/dist/server/app-rsc-route-matching.js +8 -4
  157. package/dist/server/app-rsc-route-matching.js.map +1 -1
  158. package/dist/server/app-segment-config.js +4 -0
  159. package/dist/server/app-segment-config.js.map +1 -1
  160. package/dist/server/app-server-action-execution.js +43 -51
  161. package/dist/server/app-server-action-execution.js.map +1 -1
  162. package/dist/server/app-ssr-entry.js +21 -20
  163. package/dist/server/app-ssr-entry.js.map +1 -1
  164. package/dist/server/artifact-compatibility.d.ts +44 -0
  165. package/dist/server/artifact-compatibility.js +82 -0
  166. package/dist/server/artifact-compatibility.js.map +1 -0
  167. package/dist/server/cache-proof.d.ts +200 -0
  168. package/dist/server/cache-proof.js +342 -0
  169. package/dist/server/cache-proof.js.map +1 -0
  170. package/dist/server/dev-origin-check.js +8 -4
  171. package/dist/server/dev-origin-check.js.map +1 -1
  172. package/dist/server/dev-server.js +1 -6
  173. package/dist/server/dev-server.js.map +1 -1
  174. package/dist/server/http-error-responses.d.ts +67 -0
  175. package/dist/server/http-error-responses.js +77 -0
  176. package/dist/server/http-error-responses.js.map +1 -0
  177. package/dist/server/image-optimization.js +2 -1
  178. package/dist/server/image-optimization.js.map +1 -1
  179. package/dist/server/metadata-route-response.js +6 -5
  180. package/dist/server/metadata-route-response.js.map +1 -1
  181. package/dist/server/metadata-routes.d.ts +1 -0
  182. package/dist/server/metadata-routes.js +6 -0
  183. package/dist/server/metadata-routes.js.map +1 -1
  184. package/dist/server/middleware-matcher.js +2 -2
  185. package/dist/server/middleware-matcher.js.map +1 -1
  186. package/dist/server/middleware-response-headers.js +21 -0
  187. package/dist/server/middleware-response-headers.js.map +1 -1
  188. package/dist/server/middleware-runtime.js +3 -3
  189. package/dist/server/middleware-runtime.js.map +1 -1
  190. package/dist/server/navigation-trace.d.ts +33 -0
  191. package/dist/server/navigation-trace.js +35 -0
  192. package/dist/server/navigation-trace.js.map +1 -0
  193. package/dist/server/next-error-digest.d.ts +44 -0
  194. package/dist/server/next-error-digest.js +40 -0
  195. package/dist/server/next-error-digest.js.map +1 -0
  196. package/dist/server/pages-api-route.js +2 -1
  197. package/dist/server/pages-api-route.js.map +1 -1
  198. package/dist/server/pages-node-compat.js +4 -16
  199. package/dist/server/pages-node-compat.js.map +1 -1
  200. package/dist/server/pages-page-response.d.ts +2 -8
  201. package/dist/server/pages-page-response.js +44 -14
  202. package/dist/server/pages-page-response.js.map +1 -1
  203. package/dist/server/prod-server.d.ts +6 -0
  204. package/dist/server/prod-server.js +28 -21
  205. package/dist/server/prod-server.js.map +1 -1
  206. package/dist/server/request-pipeline.d.ts +42 -1
  207. package/dist/server/request-pipeline.js +97 -17
  208. package/dist/server/request-pipeline.js.map +1 -1
  209. package/dist/shims/cache-runtime.d.ts +2 -2
  210. package/dist/shims/cache-runtime.js +3 -6
  211. package/dist/shims/cache-runtime.js.map +1 -1
  212. package/dist/shims/cache.js +3 -5
  213. package/dist/shims/cache.js.map +1 -1
  214. package/dist/shims/fetch-cache.js +2 -3
  215. package/dist/shims/fetch-cache.js.map +1 -1
  216. package/dist/shims/head-state.js +2 -3
  217. package/dist/shims/head-state.js.map +1 -1
  218. package/dist/shims/headers.js +4 -44
  219. package/dist/shims/headers.js.map +1 -1
  220. package/dist/shims/i18n-state.js +2 -3
  221. package/dist/shims/i18n-state.js.map +1 -1
  222. package/dist/shims/internal/als-registry.d.ts +15 -0
  223. package/dist/shims/internal/als-registry.js +55 -0
  224. package/dist/shims/internal/als-registry.js.map +1 -0
  225. package/dist/shims/internal/cookie-serialize.d.ts +46 -0
  226. package/dist/shims/internal/cookie-serialize.js +51 -0
  227. package/dist/shims/internal/cookie-serialize.js.map +1 -0
  228. package/dist/shims/link.js +31 -26
  229. package/dist/shims/link.js.map +1 -1
  230. package/dist/shims/metadata.d.ts +26 -1
  231. package/dist/shims/metadata.js +94 -4
  232. package/dist/shims/metadata.js.map +1 -1
  233. package/dist/shims/navigation-state.js +2 -3
  234. package/dist/shims/navigation-state.js.map +1 -1
  235. package/dist/shims/navigation.d.ts +2 -7
  236. package/dist/shims/navigation.js +44 -36
  237. package/dist/shims/navigation.js.map +1 -1
  238. package/dist/shims/request-context.js +2 -4
  239. package/dist/shims/request-context.js.map +1 -1
  240. package/dist/shims/router-state.js +2 -3
  241. package/dist/shims/router-state.js.map +1 -1
  242. package/dist/shims/router.js +2 -2
  243. package/dist/shims/router.js.map +1 -1
  244. package/dist/shims/server.js +5 -30
  245. package/dist/shims/server.js.map +1 -1
  246. package/dist/shims/slot.d.ts +1 -1
  247. package/dist/shims/slot.js +5 -4
  248. package/dist/shims/slot.js.map +1 -1
  249. package/dist/shims/thenable-params.d.ts +5 -2
  250. package/dist/shims/thenable-params.js +26 -6
  251. package/dist/shims/thenable-params.js.map +1 -1
  252. package/dist/shims/unified-request-context.js +2 -14
  253. package/dist/shims/unified-request-context.js.map +1 -1
  254. package/dist/utils/base-path.d.ts +7 -1
  255. package/dist/utils/base-path.js +12 -1
  256. package/dist/utils/base-path.js.map +1 -1
  257. package/dist/utils/safe-json-file.d.ts +18 -0
  258. package/dist/utils/safe-json-file.js +25 -0
  259. package/dist/utils/safe-json-file.js.map +1 -0
  260. package/dist/utils/text-stream.d.ts +29 -0
  261. package/dist/utils/text-stream.js +66 -0
  262. package/dist/utils/text-stream.js.map +1 -0
  263. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"slot.js","names":["React"],"sources":["../../src/shims/slot.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { UNMATCHED_SLOT, type AppElementValue, type AppElements } from \"../server/app-elements.js\";\nimport { notFound } from \"./navigation.js\";\n\nconst EMPTY_ELEMENTS: AppElements = Object.freeze({});\nconst warnedMissingEntryIds = new Set<string>();\n\nexport { UNMATCHED_SLOT };\n\n/**\n * Holds resolved AppElements (not a Promise). React 19's use(Promise) during\n * hydration triggers \"async Client Component\" for native Promises that lack\n * React's internal .status property. Storing resolved values sidesteps this.\n */\nexport const ElementsContext = React.createContext<AppElements>(EMPTY_ELEMENTS);\n\nexport const ChildrenContext = React.createContext<React.ReactNode>(null);\n\nexport const ParallelSlotsContext = React.createContext<Readonly<\n Record<string, React.ReactNode>\n> | null>(null);\n\nexport function mergeElements(\n prev: AppElements,\n next: AppElements,\n clearAbsentSlots = false,\n): AppElements {\n const merged: Record<string, AppElementValue> = { ...prev, ...next };\n // On soft navigation, unmatched parallel slots preserve their previous subtree\n // instead of firing notFound(). Only hard navigation (full page load) should 404.\n // This matches Next.js behavior for parallel route persistence.\n for (const key of Object.keys(merged)) {\n if (key.startsWith(\"slot:\") && merged[key] === UNMATCHED_SLOT && Object.hasOwn(prev, key)) {\n merged[key] = prev[key];\n }\n }\n // On traversal (browser back/forward), the server renders the full destination\n // route tree. A slot absent from next means the destination route tree does not\n // include it, so clear it rather than keeping the stale prev value. This only\n // runs for traversals because soft forward navigations may omit parent layout\n // slots that should be preserved.\n if (clearAbsentSlots) {\n for (const key of Object.keys(merged)) {\n if (key.startsWith(\"slot:\") && !Object.hasOwn(next, key)) {\n delete merged[key];\n }\n }\n }\n return merged;\n}\n\nexport function Slot({\n id,\n children,\n parallelSlots,\n}: {\n id: string;\n children?: React.ReactNode;\n parallelSlots?: Readonly<Record<string, React.ReactNode>>;\n}) {\n const elements = React.useContext(ElementsContext);\n\n if (!Object.hasOwn(elements, id)) {\n if (process.env.NODE_ENV !== \"production\" && !id.startsWith(\"slot:\")) {\n if (!warnedMissingEntryIds.has(id)) {\n warnedMissingEntryIds.add(id);\n console.warn(\"[vinext] Missing App Router element entry during render: \" + id);\n }\n }\n return null;\n }\n\n const element = elements[id];\n if (element === UNMATCHED_SLOT) {\n notFound();\n }\n\n return (\n <ParallelSlotsContext.Provider value={parallelSlots ?? null}>\n <ChildrenContext.Provider value={children ?? null}>{element}</ChildrenContext.Provider>\n </ParallelSlotsContext.Provider>\n );\n}\n\nexport function Children() {\n return React.useContext(ChildrenContext);\n}\n\nexport function ParallelSlot({ name }: { name: string }) {\n const slots = React.useContext(ParallelSlotsContext);\n return slots?.[name] ?? null;\n}\n"],"mappings":";;;;;;AAMA,MAAM,iBAA8B,OAAO,OAAO,EAAE,CAAC;AACrD,MAAM,wCAAwB,IAAI,KAAa;;;;;;AAS/C,MAAa,kBAAkBA,QAAM,cAA2B,eAAe;AAE/E,MAAa,kBAAkBA,QAAM,cAA+B,KAAK;AAEzE,MAAa,uBAAuBA,QAAM,cAEhC,KAAK;AAEf,SAAgB,cACd,MACA,MACA,mBAAmB,OACN;CACb,MAAM,SAA0C;EAAE,GAAG;EAAM,GAAG;EAAM;AAIpE,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,IAAI,WAAW,QAAQ,IAAI,OAAO,SAAS,kBAAkB,OAAO,OAAO,MAAM,IAAI,CACvF,QAAO,OAAO,KAAK;AAQvB,KAAI;OACG,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,IAAI,WAAW,QAAQ,IAAI,CAAC,OAAO,OAAO,MAAM,IAAI,CACtD,QAAO,OAAO;;AAIpB,QAAO;;AAGT,SAAgB,KAAK,EACnB,IACA,UACA,iBAKC;CACD,MAAM,WAAWA,QAAM,WAAW,gBAAgB;AAElD,KAAI,CAAC,OAAO,OAAO,UAAU,GAAG,EAAE;AAChC,MAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,GAAG,WAAW,QAAQ;OAC9D,CAAC,sBAAsB,IAAI,GAAG,EAAE;AAClC,0BAAsB,IAAI,GAAG;AAC7B,YAAQ,KAAK,8DAA8D,GAAG;;;AAGlF,SAAO;;CAGT,MAAM,UAAU,SAAS;AACzB,KAAI,YAAY,eACd,WAAU;AAGZ,QACE,oBAAC,qBAAqB,UAAtB;EAA+B,OAAO,iBAAiB;YACrD,oBAAC,gBAAgB,UAAjB;GAA0B,OAAO,YAAY;aAAO;GAAmC,CAAA;EACzD,CAAA;;AAIpC,SAAgB,WAAW;AACzB,QAAOA,QAAM,WAAW,gBAAgB;;AAG1C,SAAgB,aAAa,EAAE,QAA0B;AAEvD,QADcA,QAAM,WAAW,qBAAqB,GACrC,SAAS"}
1
+ {"version":3,"file":"slot.js","names":["React"],"sources":["../../src/shims/slot.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n AppElementsWire,\n UNMATCHED_SLOT,\n type AppElementValue,\n type AppElements,\n} from \"../server/app-elements.js\";\nimport { notFound } from \"./navigation.js\";\n\nconst EMPTY_ELEMENTS: AppElements = Object.freeze({});\nconst warnedMissingEntryIds = new Set<string>();\n\nexport { UNMATCHED_SLOT };\n\n/**\n * Holds resolved AppElements (not a Promise). React 19's use(Promise) during\n * hydration triggers \"async Client Component\" for native Promises that lack\n * React's internal .status property. Storing resolved values sidesteps this.\n */\nexport const ElementsContext = React.createContext<AppElements>(EMPTY_ELEMENTS);\n\nexport const ChildrenContext = React.createContext<React.ReactNode>(null);\n\nexport const ParallelSlotsContext = React.createContext<Readonly<\n Record<string, React.ReactNode>\n> | null>(null);\n\nexport function mergeElements(\n prev: AppElements,\n next: AppElements,\n clearAbsentSlots = false,\n): AppElements {\n const merged: Record<string, AppElementValue> = { ...prev, ...next };\n // On soft navigation, unmatched parallel slots preserve their previous subtree\n // instead of firing notFound(). Only hard navigation (full page load) should 404.\n // This matches Next.js behavior for parallel route persistence.\n for (const key of Object.keys(merged)) {\n if (\n AppElementsWire.isSlotId(key) &&\n merged[key] === UNMATCHED_SLOT &&\n Object.hasOwn(prev, key)\n ) {\n merged[key] = prev[key];\n }\n }\n // On traversal (browser back/forward), the server renders the full destination\n // route tree. A slot absent from next means the destination route tree does not\n // include it, so clear it rather than keeping the stale prev value. This only\n // runs for traversals because soft forward navigations may omit parent layout\n // slots that should be preserved.\n if (clearAbsentSlots) {\n for (const key of Object.keys(merged)) {\n if (AppElementsWire.isSlotId(key) && !Object.hasOwn(next, key)) {\n delete merged[key];\n }\n }\n }\n return merged;\n}\n\nexport function Slot({\n id,\n children,\n parallelSlots,\n}: {\n id: string;\n children?: React.ReactNode;\n parallelSlots?: Readonly<Record<string, React.ReactNode>>;\n}) {\n const elements = React.useContext(ElementsContext);\n\n if (!Object.hasOwn(elements, id)) {\n if (process.env.NODE_ENV !== \"production\" && !AppElementsWire.isSlotId(id)) {\n if (!warnedMissingEntryIds.has(id)) {\n warnedMissingEntryIds.add(id);\n console.warn(\"[vinext] Missing App Router element entry during render: \" + id);\n }\n }\n return null;\n }\n\n const element = elements[id];\n if (element === UNMATCHED_SLOT) {\n notFound();\n }\n\n return (\n <ParallelSlotsContext.Provider value={parallelSlots ?? null}>\n <ChildrenContext.Provider value={children ?? null}>{element}</ChildrenContext.Provider>\n </ParallelSlotsContext.Provider>\n );\n}\n\nexport function Children() {\n return React.useContext(ChildrenContext);\n}\n\nexport function ParallelSlot({ name }: { name: string }) {\n const slots = React.useContext(ParallelSlotsContext);\n return slots?.[name] ?? null;\n}\n"],"mappings":";;;;;;;AAWA,MAAM,iBAA8B,OAAO,OAAO,EAAE,CAAC;AACrD,MAAM,wCAAwB,IAAI,KAAa;;;;;;AAS/C,MAAa,kBAAkBA,QAAM,cAA2B,eAAe;AAE/E,MAAa,kBAAkBA,QAAM,cAA+B,KAAK;AAEzE,MAAa,uBAAuBA,QAAM,cAEhC,KAAK;AAEf,SAAgB,cACd,MACA,MACA,mBAAmB,OACN;CACb,MAAM,SAA0C;EAAE,GAAG;EAAM,GAAG;EAAM;AAIpE,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KACE,gBAAgB,SAAS,IAAI,IAC7B,OAAO,SAAS,kBAChB,OAAO,OAAO,MAAM,IAAI,CAExB,QAAO,OAAO,KAAK;AAQvB,KAAI;OACG,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,gBAAgB,SAAS,IAAI,IAAI,CAAC,OAAO,OAAO,MAAM,IAAI,CAC5D,QAAO,OAAO;;AAIpB,QAAO;;AAGT,SAAgB,KAAK,EACnB,IACA,UACA,iBAKC;CACD,MAAM,WAAWA,QAAM,WAAW,gBAAgB;AAElD,KAAI,CAAC,OAAO,OAAO,UAAU,GAAG,EAAE;AAChC,MAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,gBAAgB,SAAS,GAAG;OACpE,CAAC,sBAAsB,IAAI,GAAG,EAAE;AAClC,0BAAsB,IAAI,GAAG;AAC7B,YAAQ,KAAK,8DAA8D,GAAG;;;AAGlF,SAAO;;CAGT,MAAM,UAAU,SAAS;AACzB,KAAI,YAAY,eACd,WAAU;AAGZ,QACE,oBAAC,qBAAqB,UAAtB;EAA+B,OAAO,iBAAiB;YACrD,oBAAC,gBAAgB,UAAjB;GAA0B,OAAO,YAAY;aAAO;GAAmC,CAAA;EACzD,CAAA;;AAIpC,SAAgB,WAAW;AACzB,QAAOA,QAAM,WAAW,gBAAgB;;AAG1C,SAAgB,aAAa,EAAE,QAA0B;AAEvD,QADcA,QAAM,WAAW,qBAAqB,GACrC,SAAS"}
@@ -1,5 +1,8 @@
1
1
  //#region src/shims/thenable-params.d.ts
2
- declare function makeThenableParams<T extends Record<string, unknown>>(obj: T): Promise<Awaited<T>>;
2
+ declare const WELL_KNOWN_PROPERTIES: readonly ["hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "toLocaleString", "then", "catch", "finally", "status", "value", "error", "displayName", "_debugInfo", "toJSON", "$$typeof", "__esModule", "@@iterator"];
3
+ type WellKnownProperty = (typeof WELL_KNOWN_PROPERTIES)[number];
4
+ type ThenableParams<T extends Record<string, unknown>> = Promise<T> & Omit<T, WellKnownProperty>;
5
+ declare function makeThenableParams<T extends Record<string, unknown>>(obj: T): ThenableParams<T>;
3
6
  //#endregion
4
- export { makeThenableParams };
7
+ export { ThenableParams, makeThenableParams };
5
8
  //# sourceMappingURL=thenable-params.d.ts.map
@@ -2,20 +2,40 @@
2
2
  function hasParamProperty(obj, prop) {
3
3
  return Object.prototype.hasOwnProperty.call(obj, prop);
4
4
  }
5
- function isPromiseMethod(prop) {
6
- return prop === "then" || prop === "catch" || prop === "finally";
5
+ const wellKnownProperties = new Set([
6
+ "hasOwnProperty",
7
+ "isPrototypeOf",
8
+ "propertyIsEnumerable",
9
+ "toString",
10
+ "valueOf",
11
+ "toLocaleString",
12
+ "then",
13
+ "catch",
14
+ "finally",
15
+ "status",
16
+ "value",
17
+ "error",
18
+ "displayName",
19
+ "_debugInfo",
20
+ "toJSON",
21
+ "$$typeof",
22
+ "__esModule",
23
+ "@@iterator"
24
+ ]);
25
+ function isWellKnownProperty(prop) {
26
+ return wellKnownProperties.has(prop);
7
27
  }
8
28
  function makeThenableParams(obj) {
9
29
  const plain = { ...obj };
10
30
  const promise = Promise.resolve(plain);
11
31
  return new Proxy(promise, {
12
32
  get(target, prop, receiver) {
13
- if (!isPromiseMethod(prop) && hasParamProperty(plain, prop)) return Reflect.get(plain, prop);
33
+ if (!isWellKnownProperty(prop) && hasParamProperty(plain, prop)) return Reflect.get(plain, prop);
14
34
  const value = Reflect.get(target, prop, receiver);
15
35
  return typeof value === "function" ? value.bind(target) : value;
16
36
  },
17
37
  getOwnPropertyDescriptor(target, prop) {
18
- if (!isPromiseMethod(prop) && hasParamProperty(plain, prop)) return {
38
+ if (!isWellKnownProperty(prop) && hasParamProperty(plain, prop)) return {
19
39
  configurable: true,
20
40
  enumerable: true,
21
41
  value: Reflect.get(plain, prop),
@@ -24,10 +44,10 @@ function makeThenableParams(obj) {
24
44
  return Reflect.getOwnPropertyDescriptor(target, prop);
25
45
  },
26
46
  has(target, prop) {
27
- return Reflect.has(target, prop) || hasParamProperty(plain, prop);
47
+ return Reflect.has(target, prop) || !isWellKnownProperty(prop) && hasParamProperty(plain, prop);
28
48
  },
29
49
  ownKeys() {
30
- return Reflect.ownKeys(plain).filter((prop) => !isPromiseMethod(prop));
50
+ return Reflect.ownKeys(plain).filter((prop) => !isWellKnownProperty(prop));
31
51
  }
32
52
  });
33
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"thenable-params.js","names":[],"sources":["../../src/shims/thenable-params.ts"],"sourcesContent":["function hasParamProperty<T extends Record<string, unknown>>(obj: T, prop: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n}\n\nfunction isPromiseMethod(prop: PropertyKey): boolean {\n return prop === \"then\" || prop === \"catch\" || prop === \"finally\";\n}\n\nexport function makeThenableParams<T extends Record<string, unknown>>(obj: T) {\n const plain = { ...obj };\n const promise = Promise.resolve(plain);\n\n return new Proxy(promise, {\n get(target, prop, receiver) {\n if (!isPromiseMethod(prop) && hasParamProperty(plain, prop)) {\n return Reflect.get(plain, prop);\n }\n\n const value = Reflect.get(target, prop, receiver);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n getOwnPropertyDescriptor(target, prop) {\n if (!isPromiseMethod(prop) && hasParamProperty(plain, prop)) {\n return {\n configurable: true,\n enumerable: true,\n value: Reflect.get(plain, prop),\n writable: true,\n };\n }\n\n return Reflect.getOwnPropertyDescriptor(target, prop);\n },\n has(target, prop) {\n return Reflect.has(target, prop) || hasParamProperty(plain, prop);\n },\n ownKeys() {\n return Reflect.ownKeys(plain).filter((prop) => !isPromiseMethod(prop));\n },\n });\n}\n"],"mappings":";AAAA,SAAS,iBAAoD,KAAQ,MAA4B;AAC/F,QAAO,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK;;AAGxD,SAAS,gBAAgB,MAA4B;AACnD,QAAO,SAAS,UAAU,SAAS,WAAW,SAAS;;AAGzD,SAAgB,mBAAsD,KAAQ;CAC5E,MAAM,QAAQ,EAAE,GAAG,KAAK;CACxB,MAAM,UAAU,QAAQ,QAAQ,MAAM;AAEtC,QAAO,IAAI,MAAM,SAAS;EACxB,IAAI,QAAQ,MAAM,UAAU;AAC1B,OAAI,CAAC,gBAAgB,KAAK,IAAI,iBAAiB,OAAO,KAAK,CACzD,QAAO,QAAQ,IAAI,OAAO,KAAK;GAGjC,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AACjD,UAAO,OAAO,UAAU,aAAa,MAAM,KAAK,OAAO,GAAG;;EAE5D,yBAAyB,QAAQ,MAAM;AACrC,OAAI,CAAC,gBAAgB,KAAK,IAAI,iBAAiB,OAAO,KAAK,CACzD,QAAO;IACL,cAAc;IACd,YAAY;IACZ,OAAO,QAAQ,IAAI,OAAO,KAAK;IAC/B,UAAU;IACX;AAGH,UAAO,QAAQ,yBAAyB,QAAQ,KAAK;;EAEvD,IAAI,QAAQ,MAAM;AAChB,UAAO,QAAQ,IAAI,QAAQ,KAAK,IAAI,iBAAiB,OAAO,KAAK;;EAEnE,UAAU;AACR,UAAO,QAAQ,QAAQ,MAAM,CAAC,QAAQ,SAAS,CAAC,gBAAgB,KAAK,CAAC;;EAEzE,CAAC"}
1
+ {"version":3,"file":"thenable-params.js","names":[],"sources":["../../src/shims/thenable-params.ts"],"sourcesContent":["function hasParamProperty<T extends Record<string, unknown>>(obj: T, prop: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n}\n\n// Properties that cannot be shadowed by param names because they need to\n// remain the true underlying value for Promises / React to work correctly.\n//\n// Next.js comments out `value` and `error` in reflect-utils.ts because they\n// use `Promise.resolve(underlyingParams)` directly in production, so React\n// mutations on the promise object are never shadowed. vinext uses a Proxy\n// that intercepts sync reads through a separate `plain` object, which means\n// a param named `value` or `error` would shadow React's `.status`/`.value`\n// attachments that React adds to resolved promises for `use()` caching.\n// https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/utils/reflect-utils.ts\nconst WELL_KNOWN_PROPERTIES = [\n // Object prototype\n \"hasOwnProperty\",\n \"isPrototypeOf\",\n \"propertyIsEnumerable\",\n \"toString\",\n \"valueOf\",\n \"toLocaleString\",\n\n // Promise prototype\n \"then\",\n \"catch\",\n \"finally\",\n\n // React Promise extension (status is explicitly reserved by Next.js;\n // value/error are reserved here because our Proxy-based approach creates\n // a shadowing risk that native Promise does not have)\n \"status\",\n \"value\",\n \"error\",\n\n // React introspection\n \"displayName\",\n \"_debugInfo\",\n\n // Common tested properties\n \"toJSON\",\n \"$$typeof\",\n \"__esModule\",\n\n // Tested by flight when checking for iterables\n \"@@iterator\",\n] as const;\n\n// The type-level set of well-known properties is derived directly from the\n// runtime array above, so they can never drift out of sync. These properties\n// are omitted from the synchronous intersection because the Proxy returns\n// Promise/React internals for them, not the param value. After awaiting, the\n// resolved object contains the actual param values for all keys.\ntype WellKnownProperty = (typeof WELL_KNOWN_PROPERTIES)[number];\n\nconst wellKnownProperties = new Set<PropertyKey>(WELL_KNOWN_PROPERTIES);\n\nfunction isWellKnownProperty(prop: PropertyKey): boolean {\n return wellKnownProperties.has(prop);\n}\n\nexport type ThenableParams<T extends Record<string, unknown>> = Promise<T> &\n Omit<T, WellKnownProperty>;\n\nexport function makeThenableParams<T extends Record<string, unknown>>(obj: T): ThenableParams<T> {\n const plain = { ...obj };\n const promise = Promise.resolve(plain);\n\n // The Proxy implements both Promise and plain-object behaviour so that\n // `await params` and `params.id` both work. TypeScript's Proxy type\n // cannot express this intersection precisely — the cast is isolated to\n // the boundary so the handler above stays fully type-checked.\n return new Proxy(promise, {\n get(target, prop, receiver) {\n if (!isWellKnownProperty(prop) && hasParamProperty(plain, prop)) {\n return Reflect.get(plain, prop);\n }\n\n const value = Reflect.get(target, prop, receiver);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n getOwnPropertyDescriptor(target, prop) {\n if (!isWellKnownProperty(prop) && hasParamProperty(plain, prop)) {\n return {\n configurable: true,\n enumerable: true,\n value: Reflect.get(plain, prop),\n writable: true,\n };\n }\n\n return Reflect.getOwnPropertyDescriptor(target, prop);\n },\n has(target, prop) {\n return (\n Reflect.has(target, prop) || (!isWellKnownProperty(prop) && hasParamProperty(plain, prop))\n );\n },\n ownKeys() {\n return Reflect.ownKeys(plain).filter((prop) => !isWellKnownProperty(prop));\n },\n }) as unknown as ThenableParams<T>;\n}\n"],"mappings":";AAAA,SAAS,iBAAoD,KAAQ,MAA4B;AAC/F,QAAO,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK;;AAsDxD,MAAM,sBAAsB,IAAI,IAzCF;CAE5B;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAKA;CACA;CACA;CAGA;CACA;CAGA;CACA;CACA;CAGA;CACD,CASsE;AAEvE,SAAS,oBAAoB,MAA4B;AACvD,QAAO,oBAAoB,IAAI,KAAK;;AAMtC,SAAgB,mBAAsD,KAA2B;CAC/F,MAAM,QAAQ,EAAE,GAAG,KAAK;CACxB,MAAM,UAAU,QAAQ,QAAQ,MAAM;AAMtC,QAAO,IAAI,MAAM,SAAS;EACxB,IAAI,QAAQ,MAAM,UAAU;AAC1B,OAAI,CAAC,oBAAoB,KAAK,IAAI,iBAAiB,OAAO,KAAK,CAC7D,QAAO,QAAQ,IAAI,OAAO,KAAK;GAGjC,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AACjD,UAAO,OAAO,UAAU,aAAa,MAAM,KAAK,OAAO,GAAG;;EAE5D,yBAAyB,QAAQ,MAAM;AACrC,OAAI,CAAC,oBAAoB,KAAK,IAAI,iBAAiB,OAAO,KAAK,CAC7D,QAAO;IACL,cAAc;IACd,YAAY;IACZ,OAAO,QAAQ,IAAI,OAAO,KAAK;IAC/B,UAAU;IACX;AAGH,UAAO,QAAQ,yBAAyB,QAAQ,KAAK;;EAEvD,IAAI,QAAQ,MAAM;AAChB,UACE,QAAQ,IAAI,QAAQ,KAAK,IAAK,CAAC,oBAAoB,KAAK,IAAI,iBAAiB,OAAO,KAAK;;EAG7F,UAAU;AACR,UAAO,QAAQ,QAAQ,MAAM,CAAC,QAAQ,SAAS,CAAC,oBAAoB,KAAK,CAAC;;EAE7E,CAAC"}
@@ -1,20 +1,8 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
1
+ import { getOrCreateAls } from "./internal/als-registry.js";
2
2
  //#region src/shims/unified-request-context.ts
3
- /**
4
- * Unified per-request context backed by a single AsyncLocalStorage.
5
- *
6
- * Consolidates the 5–6 nested ALS scopes that previously wrapped every
7
- * App Router request (headers, navigation, cache-state, private-cache,
8
- * fetch-cache, execution-context) into one flat store.
9
- *
10
- * Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields
11
- * from the unified store, falling back to its own standalone ALS when
12
- * outside (SSR environment, Pages Router, tests).
13
- */
14
- const _ALS_KEY = Symbol.for("vinext.unifiedRequestContext.als");
15
3
  const _REQUEST_CONTEXT_ALS_KEY = Symbol.for("vinext.requestContext.als");
16
4
  const _g = globalThis;
17
- const _als = _g[_ALS_KEY] ??= new AsyncLocalStorage();
5
+ const _als = getOrCreateAls("vinext.unifiedRequestContext.als");
18
6
  function _getInheritedExecutionContext() {
19
7
  const unifiedStore = _als.getStore();
20
8
  if (unifiedStore) return unifiedStore.executionContext;
@@ -1 +1 @@
1
- {"version":3,"file":"unified-request-context.js","names":[],"sources":["../../src/shims/unified-request-context.ts"],"sourcesContent":["/**\n * Unified per-request context backed by a single AsyncLocalStorage.\n *\n * Consolidates the 5–6 nested ALS scopes that previously wrapped every\n * App Router request (headers, navigation, cache-state, private-cache,\n * fetch-cache, execution-context) into one flat store.\n *\n * Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields\n * from the unified store, falling back to its own standalone ALS when\n * outside (SSR environment, Pages Router, tests).\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n CacheState,\n ExecutionContextLike,\n FetchCacheState,\n HeadState,\n I18nState,\n NavigationState,\n PrivateCacheState,\n RouterState,\n RootParamsState,\n VinextHeadersShimState,\n} from \"./request-state-types.js\";\n\n// ---------------------------------------------------------------------------\n// Unified context shape\n// ---------------------------------------------------------------------------\n\n/**\n * Flat union of all per-request state previously spread across\n * VinextHeadersShimState, NavigationState, CacheState, PrivateCacheState,\n * FetchCacheState, and ExecutionContextLike.\n *\n * Each field group is documented with its source shim module.\n */\nexport type UnifiedRequestContext = {\n // ── request-context.ts ─────────────────────────────────────────────\n /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */\n executionContext: ExecutionContextLike | null;\n\n // ── cache-for-request.ts ──────────────────────────────────────────\n /** Per-request cache for cacheForRequest(). Keyed by factory function reference. */\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n requestCache: WeakMap<(...args: any[]) => any, unknown>;\n} & VinextHeadersShimState &\n I18nState &\n NavigationState &\n CacheState &\n PrivateCacheState &\n FetchCacheState &\n RouterState &\n HeadState &\n RootParamsState;\n\n// ---------------------------------------------------------------------------\n// ALS setup — stored on globalThis via Symbol.for so all Vite environments\n// (RSC/SSR/client) share the same instance.\n// ---------------------------------------------------------------------------\n\nconst _ALS_KEY = Symbol.for(\"vinext.unifiedRequestContext.als\");\nconst _REQUEST_CONTEXT_ALS_KEY = Symbol.for(\"vinext.requestContext.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\nconst _als = (_g[_ALS_KEY] ??=\n new AsyncLocalStorage<UnifiedRequestContext>()) as AsyncLocalStorage<UnifiedRequestContext>;\n\nfunction _getInheritedExecutionContext(): ExecutionContextLike | null {\n const unifiedStore = _als.getStore();\n if (unifiedStore) return unifiedStore.executionContext;\n\n const executionContextAls = _g[_REQUEST_CONTEXT_ALS_KEY] as\n | AsyncLocalStorage<ExecutionContextLike | null>\n | undefined;\n return executionContextAls?.getStore() ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a fresh `UnifiedRequestContext` with defaults for all fields.\n * Pass partial overrides for the fields you need to pre-populate.\n */\nexport function createRequestContext(opts?: Partial<UnifiedRequestContext>): UnifiedRequestContext {\n return {\n headersContext: null,\n dynamicUsageDetected: false,\n invalidDynamicUsageError: null,\n pendingSetCookies: [],\n draftModeCookieHeader: null,\n phase: \"render\",\n i18nContext: null,\n serverContext: null,\n serverInsertedHTMLCallbacks: [],\n requestScopedCacheLife: null,\n unstableCacheRevalidation: \"foreground\",\n _privateCache: null,\n currentRequestTags: [],\n currentFetchSoftTags: [],\n currentFetchCacheMode: null,\n executionContext: _getInheritedExecutionContext(), // inherits from standalone ALS if present\n requestCache: new WeakMap(),\n ssrContext: null,\n ssrHeadChildren: [],\n rootParams: null,\n ...opts,\n };\n}\n\n/**\n * Run `fn` within a unified request context scope.\n * All shim modules will read/write their state from `ctx` for the\n * duration of the call, including async continuations.\n */\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => Promise<T>,\n): Promise<T>;\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T>;\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return _als.run(ctx, fn);\n}\n\n/**\n * Run `fn` in a nested unified scope derived from the current request context.\n * Used by legacy runWith* wrappers to reset or override one sub-state while\n * preserving proper async isolation for continuations created inside `fn`.\n * The child scope is a shallow clone of the parent store, so untouched fields\n * keep sharing their existing references while overridden slices can be reset.\n *\n * @internal\n */\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => Promise<T>,\n): Promise<T>;\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T>;\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n const parentCtx = _als.getStore();\n if (!parentCtx) return fn();\n\n const childCtx = { ...parentCtx };\n // NOTE: This is a shallow clone. Array fields (pendingSetCookies,\n // serverInsertedHTMLCallbacks, currentRequestTags, ssrHeadChildren), the\n // _privateCache Map, requestCache WeakMap, and object fields (headersContext,\n // i18nContext, serverContext, ssrContext, executionContext,\n // requestScopedCacheLife) still share references with the parent until\n // replaced. requestCache is intentionally shared — nested scopes within\n // the same request should see the same cached values. The mutate\n // callback must replace those reference-typed slices (for example\n // `ctx.currentRequestTags = []`) rather than mutating them in-place (for\n // example `ctx.currentRequestTags.push(...)`) or the parent scope will\n // observe those changes too. Keep this enumeration in sync with\n // UnifiedRequestContext: when adding a new reference-typed field, add it\n // here too and verify callers still follow the replace-not-mutate rule.\n mutate(childCtx);\n return _als.run(childCtx, fn);\n}\n\n/**\n * Get the current unified request context.\n * Returns the ALS store when inside a `runWithRequestContext()` scope,\n * or a fresh detached context otherwise. Unlike the legacy per-shim fallback\n * singletons, this detached value is ephemeral — mutations do not persist\n * across calls. This is intentional to prevent state leakage outside request\n * scopes.\n *\n * Only direct callers observe this detached fallback. Shim `_getState()`\n * helpers should continue to gate on `isInsideUnifiedScope()` and fall back\n * to their standalone ALS/fallback singletons outside the unified scope.\n * If called inside a standalone `runWithExecutionContext()` scope, the\n * detached context still reflects that inherited `executionContext`.\n */\nexport function getRequestContext(): UnifiedRequestContext {\n return _als.getStore() ?? createRequestContext();\n}\n\n/**\n * Check whether the current execution is inside a `runWithRequestContext()` scope.\n * Shim modules use this to decide whether to read from the unified store\n * or fall back to their own standalone ALS.\n */\nexport function isInsideUnifiedScope(): boolean {\n return _als.getStore() != null;\n}\n"],"mappings":";;;;;;;;;;;;;AA6DA,MAAM,WAAW,OAAO,IAAI,mCAAmC;AAC/D,MAAM,2BAA2B,OAAO,IAAI,4BAA4B;AACxE,MAAM,KAAK;AACX,MAAM,OAAQ,GAAG,cACf,IAAI,mBAA0C;AAEhD,SAAS,gCAA6D;CACpE,MAAM,eAAe,KAAK,UAAU;AACpC,KAAI,aAAc,QAAO,aAAa;AAKtC,QAH4B,GAAG,2BAGH,UAAU,IAAI;;;;;;AAW5C,SAAgB,qBAAqB,MAA8D;AACjG,QAAO;EACL,gBAAgB;EAChB,sBAAsB;EACtB,0BAA0B;EAC1B,mBAAmB,EAAE;EACrB,uBAAuB;EACvB,OAAO;EACP,aAAa;EACb,eAAe;EACf,6BAA6B,EAAE;EAC/B,wBAAwB;EACxB,2BAA2B;EAC3B,eAAe;EACf,oBAAoB,EAAE;EACtB,sBAAsB,EAAE;EACxB,uBAAuB;EACvB,kBAAkB,+BAA+B;EACjD,8BAAc,IAAI,SAAS;EAC3B,YAAY;EACZ,iBAAiB,EAAE;EACnB,YAAY;EACZ,GAAG;EACJ;;AAgBH,SAAgB,sBACd,KACA,IACgB;AAChB,QAAO,KAAK,IAAI,KAAK,GAAG;;AAoB1B,SAAgB,4BACd,QACA,IACgB;CAChB,MAAM,YAAY,KAAK,UAAU;AACjC,KAAI,CAAC,UAAW,QAAO,IAAI;CAE3B,MAAM,WAAW,EAAE,GAAG,WAAW;AAcjC,QAAO,SAAS;AAChB,QAAO,KAAK,IAAI,UAAU,GAAG;;;;;;;;;;;;;;;;AAiB/B,SAAgB,oBAA2C;AACzD,QAAO,KAAK,UAAU,IAAI,sBAAsB;;;;;;;AAQlD,SAAgB,uBAAgC;AAC9C,QAAO,KAAK,UAAU,IAAI"}
1
+ {"version":3,"file":"unified-request-context.js","names":[],"sources":["../../src/shims/unified-request-context.ts"],"sourcesContent":["/**\n * Unified per-request context backed by a single AsyncLocalStorage.\n *\n * Consolidates the 5–6 nested ALS scopes that previously wrapped every\n * App Router request (headers, navigation, cache-state, private-cache,\n * fetch-cache, execution-context) into one flat store.\n *\n * Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields\n * from the unified store, falling back to its own standalone ALS when\n * outside (SSR environment, Pages Router, tests).\n */\n\nimport type { AsyncLocalStorage } from \"node:async_hooks\";\nimport { getOrCreateAls } from \"./internal/als-registry.js\";\nimport type {\n CacheState,\n ExecutionContextLike,\n FetchCacheState,\n HeadState,\n I18nState,\n NavigationState,\n PrivateCacheState,\n RouterState,\n RootParamsState,\n VinextHeadersShimState,\n} from \"./request-state-types.js\";\n\n// ---------------------------------------------------------------------------\n// Unified context shape\n// ---------------------------------------------------------------------------\n\n/**\n * Flat union of all per-request state previously spread across\n * VinextHeadersShimState, NavigationState, CacheState, PrivateCacheState,\n * FetchCacheState, and ExecutionContextLike.\n *\n * Each field group is documented with its source shim module.\n */\nexport type UnifiedRequestContext = {\n // ── request-context.ts ─────────────────────────────────────────────\n /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */\n executionContext: ExecutionContextLike | null;\n\n // ── cache-for-request.ts ──────────────────────────────────────────\n /** Per-request cache for cacheForRequest(). Keyed by factory function reference. */\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n requestCache: WeakMap<(...args: any[]) => any, unknown>;\n} & VinextHeadersShimState &\n I18nState &\n NavigationState &\n CacheState &\n PrivateCacheState &\n FetchCacheState &\n RouterState &\n HeadState &\n RootParamsState;\n\n// ---------------------------------------------------------------------------\n// ALS setup — stored on globalThis via Symbol.for so all Vite environments\n// (RSC/SSR/client) share the same instance.\n// ---------------------------------------------------------------------------\n\nconst _REQUEST_CONTEXT_ALS_KEY = Symbol.for(\"vinext.requestContext.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\nconst _als = getOrCreateAls<UnifiedRequestContext>(\"vinext.unifiedRequestContext.als\");\n\nfunction _getInheritedExecutionContext(): ExecutionContextLike | null {\n const unifiedStore = _als.getStore();\n if (unifiedStore) return unifiedStore.executionContext;\n\n const executionContextAls = _g[_REQUEST_CONTEXT_ALS_KEY] as\n | AsyncLocalStorage<ExecutionContextLike | null>\n | undefined;\n return executionContextAls?.getStore() ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a fresh `UnifiedRequestContext` with defaults for all fields.\n * Pass partial overrides for the fields you need to pre-populate.\n */\nexport function createRequestContext(opts?: Partial<UnifiedRequestContext>): UnifiedRequestContext {\n return {\n headersContext: null,\n dynamicUsageDetected: false,\n invalidDynamicUsageError: null,\n pendingSetCookies: [],\n draftModeCookieHeader: null,\n phase: \"render\",\n i18nContext: null,\n serverContext: null,\n serverInsertedHTMLCallbacks: [],\n requestScopedCacheLife: null,\n unstableCacheRevalidation: \"foreground\",\n _privateCache: null,\n currentRequestTags: [],\n currentFetchSoftTags: [],\n currentFetchCacheMode: null,\n executionContext: _getInheritedExecutionContext(), // inherits from standalone ALS if present\n requestCache: new WeakMap(),\n ssrContext: null,\n ssrHeadChildren: [],\n rootParams: null,\n ...opts,\n };\n}\n\n/**\n * Run `fn` within a unified request context scope.\n * All shim modules will read/write their state from `ctx` for the\n * duration of the call, including async continuations.\n */\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => Promise<T>,\n): Promise<T>;\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T>;\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return _als.run(ctx, fn);\n}\n\n/**\n * Run `fn` in a nested unified scope derived from the current request context.\n * Used by legacy runWith* wrappers to reset or override one sub-state while\n * preserving proper async isolation for continuations created inside `fn`.\n * The child scope is a shallow clone of the parent store, so untouched fields\n * keep sharing their existing references while overridden slices can be reset.\n *\n * @internal\n */\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => Promise<T>,\n): Promise<T>;\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T>;\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n const parentCtx = _als.getStore();\n if (!parentCtx) return fn();\n\n const childCtx = { ...parentCtx };\n // NOTE: This is a shallow clone. Array fields (pendingSetCookies,\n // serverInsertedHTMLCallbacks, currentRequestTags, ssrHeadChildren), the\n // _privateCache Map, requestCache WeakMap, and object fields (headersContext,\n // i18nContext, serverContext, ssrContext, executionContext,\n // requestScopedCacheLife) still share references with the parent until\n // replaced. requestCache is intentionally shared — nested scopes within\n // the same request should see the same cached values. The mutate\n // callback must replace those reference-typed slices (for example\n // `ctx.currentRequestTags = []`) rather than mutating them in-place (for\n // example `ctx.currentRequestTags.push(...)`) or the parent scope will\n // observe those changes too. Keep this enumeration in sync with\n // UnifiedRequestContext: when adding a new reference-typed field, add it\n // here too and verify callers still follow the replace-not-mutate rule.\n mutate(childCtx);\n return _als.run(childCtx, fn);\n}\n\n/**\n * Get the current unified request context.\n * Returns the ALS store when inside a `runWithRequestContext()` scope,\n * or a fresh detached context otherwise. Unlike the legacy per-shim fallback\n * singletons, this detached value is ephemeral — mutations do not persist\n * across calls. This is intentional to prevent state leakage outside request\n * scopes.\n *\n * Only direct callers observe this detached fallback. Shim `_getState()`\n * helpers should continue to gate on `isInsideUnifiedScope()` and fall back\n * to their standalone ALS/fallback singletons outside the unified scope.\n * If called inside a standalone `runWithExecutionContext()` scope, the\n * detached context still reflects that inherited `executionContext`.\n */\nexport function getRequestContext(): UnifiedRequestContext {\n return _als.getStore() ?? createRequestContext();\n}\n\n/**\n * Check whether the current execution is inside a `runWithRequestContext()` scope.\n * Shim modules use this to decide whether to read from the unified store\n * or fall back to their own standalone ALS.\n */\nexport function isInsideUnifiedScope(): boolean {\n return _als.getStore() != null;\n}\n"],"mappings":";;AA8DA,MAAM,2BAA2B,OAAO,IAAI,4BAA4B;AACxE,MAAM,KAAK;AACX,MAAM,OAAO,eAAsC,mCAAmC;AAEtF,SAAS,gCAA6D;CACpE,MAAM,eAAe,KAAK,UAAU;AACpC,KAAI,aAAc,QAAO,aAAa;AAKtC,QAH4B,GAAG,2BAGH,UAAU,IAAI;;;;;;AAW5C,SAAgB,qBAAqB,MAA8D;AACjG,QAAO;EACL,gBAAgB;EAChB,sBAAsB;EACtB,0BAA0B;EAC1B,mBAAmB,EAAE;EACrB,uBAAuB;EACvB,OAAO;EACP,aAAa;EACb,eAAe;EACf,6BAA6B,EAAE;EAC/B,wBAAwB;EACxB,2BAA2B;EAC3B,eAAe;EACf,oBAAoB,EAAE;EACtB,sBAAsB,EAAE;EACxB,uBAAuB;EACvB,kBAAkB,+BAA+B;EACjD,8BAAc,IAAI,SAAS;EAC3B,YAAY;EACZ,iBAAiB,EAAE;EACnB,YAAY;EACZ,GAAG;EACJ;;AAgBH,SAAgB,sBACd,KACA,IACgB;AAChB,QAAO,KAAK,IAAI,KAAK,GAAG;;AAoB1B,SAAgB,4BACd,QACA,IACgB;CAChB,MAAM,YAAY,KAAK,UAAU;AACjC,KAAI,CAAC,UAAW,QAAO,IAAI;CAE3B,MAAM,WAAW,EAAE,GAAG,WAAW;AAcjC,QAAO,SAAS;AAChB,QAAO,KAAK,IAAI,UAAU,GAAG;;;;;;;;;;;;;;;;AAiB/B,SAAgB,oBAA2C;AACzD,QAAO,KAAK,UAAU,IAAI,sBAAsB;;;;;;;AAQlD,SAAgB,uBAAgC;AAC9C,QAAO,KAAK,UAAU,IAAI"}
@@ -15,6 +15,12 @@ declare function hasBasePath(pathname: string, basePath: string): boolean;
15
15
  * boundary. Returns the original pathname when it is outside the basePath.
16
16
  */
17
17
  declare function stripBasePath(pathname: string, basePath: string): string;
18
+ /**
19
+ * Remove trailing slashes from a pathname while preserving the root "/".
20
+ * Collapses any number of trailing slashes ("/a//" → "/a"). Used by the
21
+ * trailing-slash redirect path and route pattern normalization.
22
+ */
23
+ declare function removeTrailingSlash(pathname: string): string;
18
24
  //#endregion
19
- export { hasBasePath, stripBasePath };
25
+ export { hasBasePath, removeTrailingSlash, stripBasePath };
20
26
  //# sourceMappingURL=base-path.d.ts.map
@@ -21,7 +21,18 @@ function stripBasePath(pathname, basePath) {
21
21
  if (!hasBasePath(pathname, basePath)) return pathname;
22
22
  return pathname.slice(basePath.length) || "/";
23
23
  }
24
+ /**
25
+ * Remove trailing slashes from a pathname while preserving the root "/".
26
+ * Collapses any number of trailing slashes ("/a//" → "/a"). Used by the
27
+ * trailing-slash redirect path and route pattern normalization.
28
+ */
29
+ function removeTrailingSlash(pathname) {
30
+ if (pathname === "/") return "/";
31
+ let end = pathname.length;
32
+ while (end > 0 && pathname.charCodeAt(end - 1) === 47) end--;
33
+ return end === 0 ? "/" : pathname.slice(0, end);
34
+ }
24
35
  //#endregion
25
- export { hasBasePath, stripBasePath };
36
+ export { hasBasePath, removeTrailingSlash, stripBasePath };
26
37
 
27
38
  //# sourceMappingURL=base-path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-path.js","names":[],"sources":["../../src/utils/base-path.ts"],"sourcesContent":["/**\n * Shared basePath helpers.\n *\n * Next.js only treats a pathname as being under basePath when it is an exact\n * match (\"/app\") or starts with the basePath followed by a path separator\n * (\"/app/...\"). Prefix-only matches like \"/application\" must be left intact.\n */\n\n/**\n * Check whether a pathname is inside the configured basePath.\n */\nexport function hasBasePath(pathname: string, basePath: string): boolean {\n if (!basePath) return false;\n return pathname === basePath || pathname.startsWith(basePath + \"/\");\n}\n\n/**\n * Strip the basePath prefix from a pathname when it matches on a segment\n * boundary. Returns the original pathname when it is outside the basePath.\n */\nexport function stripBasePath(pathname: string, basePath: string): string {\n if (!hasBasePath(pathname, basePath)) return pathname;\n return pathname.slice(basePath.length) || \"/\";\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,YAAY,UAAkB,UAA2B;AACvE,KAAI,CAAC,SAAU,QAAO;AACtB,QAAO,aAAa,YAAY,SAAS,WAAW,WAAW,IAAI;;;;;;AAOrE,SAAgB,cAAc,UAAkB,UAA0B;AACxE,KAAI,CAAC,YAAY,UAAU,SAAS,CAAE,QAAO;AAC7C,QAAO,SAAS,MAAM,SAAS,OAAO,IAAI"}
1
+ {"version":3,"file":"base-path.js","names":[],"sources":["../../src/utils/base-path.ts"],"sourcesContent":["/**\n * Shared basePath helpers.\n *\n * Next.js only treats a pathname as being under basePath when it is an exact\n * match (\"/app\") or starts with the basePath followed by a path separator\n * (\"/app/...\"). Prefix-only matches like \"/application\" must be left intact.\n */\n\n/**\n * Check whether a pathname is inside the configured basePath.\n */\nexport function hasBasePath(pathname: string, basePath: string): boolean {\n if (!basePath) return false;\n return pathname === basePath || pathname.startsWith(basePath + \"/\");\n}\n\n/**\n * Strip the basePath prefix from a pathname when it matches on a segment\n * boundary. Returns the original pathname when it is outside the basePath.\n */\nexport function stripBasePath(pathname: string, basePath: string): string {\n if (!hasBasePath(pathname, basePath)) return pathname;\n return pathname.slice(basePath.length) || \"/\";\n}\n\n/**\n * Remove trailing slashes from a pathname while preserving the root \"/\".\n * Collapses any number of trailing slashes (\"/a//\" → \"/a\"). Used by the\n * trailing-slash redirect path and route pattern normalization.\n */\nexport function removeTrailingSlash(pathname: string): string {\n if (pathname === \"/\") return \"/\";\n let end = pathname.length;\n while (end > 0 && pathname.charCodeAt(end - 1) === 47 /* \"/\" */) end--;\n return end === 0 ? \"/\" : pathname.slice(0, end);\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,YAAY,UAAkB,UAA2B;AACvE,KAAI,CAAC,SAAU,QAAO;AACtB,QAAO,aAAa,YAAY,SAAS,WAAW,WAAW,IAAI;;;;;;AAOrE,SAAgB,cAAc,UAAkB,UAA0B;AACxE,KAAI,CAAC,YAAY,UAAU,SAAS,CAAE,QAAO;AAC7C,QAAO,SAAS,MAAM,SAAS,OAAO,IAAI;;;;;;;AAQ5C,SAAgB,oBAAoB,UAA0B;AAC5D,KAAI,aAAa,IAAK,QAAO;CAC7B,IAAI,MAAM,SAAS;AACnB,QAAO,MAAM,KAAK,SAAS,WAAW,MAAM,EAAE,KAAK,GAAc;AACjE,QAAO,QAAQ,IAAI,MAAM,SAAS,MAAM,GAAG,IAAI"}
@@ -0,0 +1,18 @@
1
+ //#region src/utils/safe-json-file.d.ts
2
+ /**
3
+ * Read and parse a JSON file, returning `null` if the file is missing,
4
+ * unreadable, or contains invalid JSON.
5
+ *
6
+ * Pass `onError` to log/observe failures while still receiving `null`. The
7
+ * callback is invoked for any thrown error from `readFileSync` or
8
+ * `JSON.parse` (e.g. `ENOENT`, syntax errors).
9
+ *
10
+ * Callers that need a default value other than `null` should map the result:
11
+ * `readJsonFile<string[]>(p) ?? []`
12
+ */
13
+ declare function readJsonFile<T>(filePath: string, options?: {
14
+ onError?: (err: unknown) => void;
15
+ }): T | null;
16
+ //#endregion
17
+ export { readJsonFile };
18
+ //# sourceMappingURL=safe-json-file.d.ts.map
@@ -0,0 +1,25 @@
1
+ import fs from "node:fs";
2
+ //#region src/utils/safe-json-file.ts
3
+ /**
4
+ * Read and parse a JSON file, returning `null` if the file is missing,
5
+ * unreadable, or contains invalid JSON.
6
+ *
7
+ * Pass `onError` to log/observe failures while still receiving `null`. The
8
+ * callback is invoked for any thrown error from `readFileSync` or
9
+ * `JSON.parse` (e.g. `ENOENT`, syntax errors).
10
+ *
11
+ * Callers that need a default value other than `null` should map the result:
12
+ * `readJsonFile<string[]>(p) ?? []`
13
+ */
14
+ function readJsonFile(filePath, options) {
15
+ try {
16
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
17
+ } catch (err) {
18
+ options?.onError?.(err);
19
+ return null;
20
+ }
21
+ }
22
+ //#endregion
23
+ export { readJsonFile };
24
+
25
+ //# sourceMappingURL=safe-json-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-json-file.js","names":[],"sources":["../../src/utils/safe-json-file.ts"],"sourcesContent":["import fs from \"node:fs\";\n\n/**\n * Read and parse a JSON file, returning `null` if the file is missing,\n * unreadable, or contains invalid JSON.\n *\n * Pass `onError` to log/observe failures while still receiving `null`. The\n * callback is invoked for any thrown error from `readFileSync` or\n * `JSON.parse` (e.g. `ENOENT`, syntax errors).\n *\n * Callers that need a default value other than `null` should map the result:\n * `readJsonFile<string[]>(p) ?? []`\n */\nexport function readJsonFile<T>(\n filePath: string,\n options?: { onError?: (err: unknown) => void },\n): T | null {\n try {\n return JSON.parse(fs.readFileSync(filePath, \"utf-8\")) as T;\n } catch (err) {\n options?.onError?.(err);\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,aACd,UACA,SACU;AACV,KAAI;AACF,SAAO,KAAK,MAAM,GAAG,aAAa,UAAU,QAAQ,CAAC;UAC9C,KAAK;AACZ,WAAS,UAAU,IAAI;AACvB,SAAO"}
@@ -0,0 +1,29 @@
1
+ //#region src/utils/text-stream.d.ts
2
+ /**
3
+ * Helpers for the repeated `new TextDecoder()` + `ReadableStream` chunk-loop
4
+ * pattern used across the server. Each helper handles the streaming-decode
5
+ * boundary correctly (final empty `decoder.decode()` flush so any incomplete
6
+ * trailing UTF-8 sequence is reported).
7
+ *
8
+ * Sites with additional load-bearing behaviour (line-buffered transforms,
9
+ * raw-byte accumulators, mixed string/Uint8Array streams, cache-key body
10
+ * canonicalisation) intentionally still inline their own decoder.
11
+ */
12
+ /**
13
+ * Drain a UTF-8 byte stream and return the full decoded text. The stream
14
+ * reader is released on both success and failure.
15
+ */
16
+ declare function readStreamAsText(stream: ReadableStream<Uint8Array>): Promise<string>;
17
+ /**
18
+ * Drain a UTF-8 byte stream up to `maxBytes` of *raw* input, returning the
19
+ * decoded text. If the raw size limit is exceeded, the reader is cancelled
20
+ * and `onLimitExceeded` is invoked; it MUST throw — its return type is
21
+ * `never` to enforce that. Each caller passes its own error type.
22
+ *
23
+ * The size check is on raw bytes (pre-decode) to bound memory before
24
+ * paying the decoder cost.
25
+ */
26
+ declare function readStreamAsTextWithLimit(stream: ReadableStream<Uint8Array>, maxBytes: number, onLimitExceeded: () => never): Promise<string>;
27
+ //#endregion
28
+ export { readStreamAsText, readStreamAsTextWithLimit };
29
+ //# sourceMappingURL=text-stream.d.ts.map
@@ -0,0 +1,66 @@
1
+ //#region src/utils/text-stream.ts
2
+ /**
3
+ * Helpers for the repeated `new TextDecoder()` + `ReadableStream` chunk-loop
4
+ * pattern used across the server. Each helper handles the streaming-decode
5
+ * boundary correctly (final empty `decoder.decode()` flush so any incomplete
6
+ * trailing UTF-8 sequence is reported).
7
+ *
8
+ * Sites with additional load-bearing behaviour (line-buffered transforms,
9
+ * raw-byte accumulators, mixed string/Uint8Array streams, cache-key body
10
+ * canonicalisation) intentionally still inline their own decoder.
11
+ */
12
+ /**
13
+ * Drain a UTF-8 byte stream and return the full decoded text. The stream
14
+ * reader is released on both success and failure.
15
+ */
16
+ async function readStreamAsText(stream) {
17
+ const reader = stream.getReader();
18
+ const decoder = new TextDecoder();
19
+ const chunks = [];
20
+ try {
21
+ for (;;) {
22
+ const { done, value } = await reader.read();
23
+ if (done) break;
24
+ chunks.push(decoder.decode(value, { stream: true }));
25
+ }
26
+ chunks.push(decoder.decode());
27
+ return chunks.join("");
28
+ } finally {
29
+ reader.releaseLock();
30
+ }
31
+ }
32
+ /**
33
+ * Drain a UTF-8 byte stream up to `maxBytes` of *raw* input, returning the
34
+ * decoded text. If the raw size limit is exceeded, the reader is cancelled
35
+ * and `onLimitExceeded` is invoked; it MUST throw — its return type is
36
+ * `never` to enforce that. Each caller passes its own error type.
37
+ *
38
+ * The size check is on raw bytes (pre-decode) to bound memory before
39
+ * paying the decoder cost.
40
+ */
41
+ async function readStreamAsTextWithLimit(stream, maxBytes, onLimitExceeded) {
42
+ const reader = stream.getReader();
43
+ const decoder = new TextDecoder();
44
+ const chunks = [];
45
+ let totalSize = 0;
46
+ try {
47
+ for (;;) {
48
+ const result = await reader.read();
49
+ if (result.done) break;
50
+ totalSize += result.value.byteLength;
51
+ if (totalSize > maxBytes) {
52
+ await reader.cancel();
53
+ onLimitExceeded();
54
+ }
55
+ chunks.push(decoder.decode(result.value, { stream: true }));
56
+ }
57
+ chunks.push(decoder.decode());
58
+ return chunks.join("");
59
+ } finally {
60
+ reader.releaseLock();
61
+ }
62
+ }
63
+ //#endregion
64
+ export { readStreamAsText, readStreamAsTextWithLimit };
65
+
66
+ //# sourceMappingURL=text-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-stream.js","names":[],"sources":["../../src/utils/text-stream.ts"],"sourcesContent":["/**\n * Helpers for the repeated `new TextDecoder()` + `ReadableStream` chunk-loop\n * pattern used across the server. Each helper handles the streaming-decode\n * boundary correctly (final empty `decoder.decode()` flush so any incomplete\n * trailing UTF-8 sequence is reported).\n *\n * Sites with additional load-bearing behaviour (line-buffered transforms,\n * raw-byte accumulators, mixed string/Uint8Array streams, cache-key body\n * canonicalisation) intentionally still inline their own decoder.\n */\n\n/**\n * Drain a UTF-8 byte stream and return the full decoded text. The stream\n * reader is released on both success and failure.\n */\nexport async function readStreamAsText(stream: ReadableStream<Uint8Array>): Promise<string> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Drain a UTF-8 byte stream up to `maxBytes` of *raw* input, returning the\n * decoded text. If the raw size limit is exceeded, the reader is cancelled\n * and `onLimitExceeded` is invoked; it MUST throw — its return type is\n * `never` to enforce that. Each caller passes its own error type.\n *\n * The size check is on raw bytes (pre-decode) to bound memory before\n * paying the decoder cost.\n */\nexport async function readStreamAsTextWithLimit(\n stream: ReadableStream<Uint8Array>,\n maxBytes: number,\n onLimitExceeded: () => never,\n): Promise<string> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n let totalSize = 0;\n\n try {\n for (;;) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n\n totalSize += result.value.byteLength;\n if (totalSize > maxBytes) {\n await reader.cancel();\n onLimitExceeded();\n }\n\n chunks.push(decoder.decode(result.value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n } finally {\n reader.releaseLock();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,eAAsB,iBAAiB,QAAqD;CAC1F,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,SAAmB,EAAE;AAE3B,KAAI;AACF,WAAS;GACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,OAAI,KACF;AAEF,UAAO,KAAK,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC;;AAEtD,SAAO,KAAK,QAAQ,QAAQ,CAAC;AAC7B,SAAO,OAAO,KAAK,GAAG;WACd;AACR,SAAO,aAAa;;;;;;;;;;;;AAaxB,eAAsB,0BACpB,QACA,UACA,iBACiB;CACjB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,SAAmB,EAAE;CAC3B,IAAI,YAAY;AAEhB,KAAI;AACF,WAAS;GACP,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,OAAI,OAAO,KACT;AAGF,gBAAa,OAAO,MAAM;AAC1B,OAAI,YAAY,UAAU;AACxB,UAAM,OAAO,QAAQ;AACrB,qBAAiB;;AAGnB,UAAO,KAAK,QAAQ,OAAO,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC;;AAG7D,SAAO,KAAK,QAAQ,QAAQ,CAAC;AAC7B,SAAO,OAAO,KAAK,GAAG;WACd;AACR,SAAO,aAAa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vinext",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "description": "Run Next.js apps on Vite. Drop-in replacement for the next CLI.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -72,7 +72,7 @@
72
72
  "@types/react-dom": "^19.2.3",
73
73
  "@vitejs/plugin-react": "^6.0.1",
74
74
  "@vitejs/plugin-rsc": "^0.5.23",
75
- "react-server-dom-webpack": "^19.2.5",
75
+ "react-server-dom-webpack": "^19.2.6",
76
76
  "vite": "npm:@voidzero-dev/vite-plus-core@0.1.17",
77
77
  "vite-plus": "0.1.17"
78
78
  },
@@ -80,9 +80,9 @@
80
80
  "@mdx-js/rollup": "^3.0.0",
81
81
  "@vitejs/plugin-react": "^5.1.4 || ^6.0.0",
82
82
  "@vitejs/plugin-rsc": "^0.5.23",
83
- "react": "^19.2.5",
84
- "react-dom": "^19.2.5",
85
- "react-server-dom-webpack": "^19.2.5",
83
+ "react": "^19.2.6",
84
+ "react-dom": "^19.2.6",
85
+ "react-server-dom-webpack": "^19.2.6",
86
86
  "vite": "^7.0.0 || ^8.0.0"
87
87
  },
88
88
  "peerDependenciesMeta": {