@wular/pnext 0.0.3 → 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 -1961
  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 -1887
  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} +152 -143
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +442 -186
  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 +833 -848
  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
@@ -1,9 +1,9 @@
1
- import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { basename, join, relative, sep } from 'node:path';
3
- import { h, type ComponentChildren, type ComponentType } from 'preact';
4
- import type { RouteParamsSnapshot } from './island-context';
5
- import { Suspense } from '../api/suspense';
6
- import type { ClientReference } from '../client/reference';
1
+ import { AsyncLocalStorage } from 'node:async_hooks'
2
+ import { basename, join, relative, sep } from 'node:path'
3
+ import { h, type ComponentChildren, type ComponentType } from 'preact'
4
+ import type { RouteParamsSnapshot } from './island-context'
5
+ import { Suspense } from '../api/suspense'
6
+ import type { ClientReference } from '../client/reference'
7
7
  import {
8
8
  consumedSegments,
9
9
  isGroupSegment,
@@ -14,92 +14,87 @@ import {
14
14
  slotConventionFile,
15
15
  slotDirectoriesIn,
16
16
  type SegmentMatch,
17
- } from '../routing/slots';
18
- import { toPosixPath } from '../utils/fs';
19
- import type {
20
- PageProps,
21
- RouteManifestEntry,
22
- RouteParamValue,
23
- ServerComponent,
24
- } from '../types';
17
+ } from '../routing/slots'
18
+ import { toPosixPath } from '../utils/fs'
19
+ import type { PageProps, RouteManifestEntry, RouteParamValue, ServerComponent } from '../types'
25
20
 
26
21
  interface SlotRenderOptions {
27
- config: { appPath: string };
28
- url: URL;
22
+ config: { appPath: string }
23
+ url: URL
29
24
  nav?: {
30
- soft?: boolean;
31
- childrenPath?: string;
32
- targetPath?: string;
33
- state?: { childrenSearch?: string; slots?: Record<string, string> };
34
- };
35
- route: Pick<RouteManifestEntry, 'clientReferences' | 'slotDirs'>;
36
- params?: Record<string, RouteParamValue>;
37
- clientComponents?: Map<string, ComponentType<Record<string, unknown>>>;
38
- slotStateOut?: Record<string, string>;
39
- moduleLoader?: (file: string) => Promise<Record<string, unknown>> | Record<string, unknown>;
25
+ soft?: boolean
26
+ childrenPath?: string
27
+ targetPath?: string
28
+ state?: { childrenSearch?: string; slots?: Record<string, string> }
29
+ }
30
+ route: Pick<RouteManifestEntry, 'clientReferences' | 'slotDirs'>
31
+ params?: Record<string, RouteParamValue>
32
+ clientComponents?: Map<string, ComponentType<Record<string, unknown>>>
33
+ slotStateOut?: Record<string, string>
34
+ moduleLoader?: (file: string) => Promise<Record<string, unknown>> | Record<string, unknown>
40
35
  }
41
36
 
42
37
  interface ServerVNodeProps extends Record<string, unknown> {
43
- children?: ComponentChildren;
38
+ children?: ComponentChildren
44
39
  }
45
40
 
46
41
  interface PageModule {
47
- default?: ServerComponent<PageProps>;
42
+ default?: ServerComponent<PageProps>
48
43
  }
49
44
 
50
45
  interface LayoutModule {
51
- default?: ServerComponent<{ children: ComponentChildren }>;
46
+ default?: ServerComponent<{ children: ComponentChildren }>
52
47
  }
53
48
 
54
49
  interface LoadingModule {
55
- default?: ServerComponent<Record<string, never>>;
50
+ default?: ServerComponent<Record<string, never>>
56
51
  }
57
52
 
58
53
  interface SlotRenderDeps<Options extends SlotRenderOptions> {
59
- importModule: (file: string, options: Options) => Promise<Record<string, unknown>>;
60
- markServerReference: <T>(component: T) => T;
61
- clientReferenceStub: (reference: ClientReference) => ComponentType<Record<string, unknown>>;
62
- createPageProps: (options: Options) => PageProps;
54
+ importModule: (file: string, options: Options) => Promise<Record<string, unknown>>
55
+ markServerReference: <T>(component: T) => T
56
+ clientReferenceStub: (reference: ClientReference) => ComponentType<Record<string, unknown>>
57
+ createPageProps: (options: Options) => PageProps
63
58
  }
64
59
 
65
60
  export interface SlotContext<Options extends SlotRenderOptions = SlotRenderOptions> {
66
- options: Options;
67
- deps: SlotRenderDeps<Options>;
68
- appPath: string;
69
- urlPath: string;
70
- urlSegments: string[];
61
+ options: Options
62
+ deps: SlotRenderDeps<Options>
63
+ appPath: string
64
+ urlPath: string
65
+ urlSegments: string[]
71
66
  /** The request's search string (`?a=b` or ''), `_rsc` union query stripped. */
72
- urlSearch: string;
73
- childrenPath: string;
74
- childrenSegments: string[];
67
+ urlSearch: string
68
+ childrenPath: string
69
+ childrenSegments: string[]
75
70
  /** Search string the children tree renders with (host renders inherit it). */
76
- childrenSearch: string;
77
- soft: boolean;
78
- statePaths: Record<string, string>;
79
- stateOut: Record<string, string>;
80
- matches: ResolvedSlotMatch[];
71
+ childrenSearch: string
72
+ soft: boolean
73
+ statePaths: Record<string, string>
74
+ stateOut: Record<string, string>
75
+ matches: ResolvedSlotMatch[]
81
76
  }
82
77
 
83
78
  export interface ResolvedSlotMatch {
84
- slotDir: string;
85
- pageFile?: string;
86
- layoutFiles: string[];
87
- params: Record<string, RouteParamValue>;
79
+ slotDir: string
80
+ pageFile?: string
81
+ layoutFiles: string[]
82
+ params: Record<string, RouteParamValue>
88
83
  }
89
84
 
90
85
  export function createSlotContext<Options extends SlotRenderOptions>(
91
86
  options: Options,
92
87
  deps: SlotRenderDeps<Options>,
93
88
  ): SlotContext<Options> {
94
- const urlPath = trimPathname(options.nav?.targetPath ?? options.url.pathname);
95
- const childrenPath = trimPathname(options.nav?.childrenPath ?? options.url.pathname);
96
- const urlSearch = stripRscSearch(options.url.search);
89
+ const urlPath = trimPathname(options.nav?.targetPath ?? options.url.pathname)
90
+ const childrenPath = trimPathname(options.nav?.childrenPath ?? options.url.pathname)
91
+ const urlSearch = stripRscSearch(options.url.search)
97
92
  // A host render (children anchored away from the URL) keeps the children
98
93
  // tree's own recorded query; a direct render's children query IS the URL's.
99
94
  const childrenSearch =
100
95
  options.nav?.soft && childrenPath !== trimPathname(options.url.pathname)
101
96
  ? (options.nav?.state?.childrenSearch ?? '')
102
- : urlSearch;
97
+ : urlSearch
103
98
  return {
104
99
  options,
105
100
  deps,
@@ -114,30 +109,30 @@ export function createSlotContext<Options extends SlotRenderOptions>(
114
109
  statePaths: options.nav?.state?.slots ?? {},
115
110
  stateOut: options.slotStateOut ?? {},
116
111
  matches: [],
117
- };
112
+ }
118
113
  }
119
114
 
120
115
  function trimPathname(pathname: string) {
121
- return pathname.length > 1 ? pathname.replace(/\/+$/, '') || '/' : pathname;
116
+ return pathname.length > 1 ? pathname.replace(/\/+$/, '') || '/' : pathname
122
117
  }
123
118
 
124
119
  /** Split a recorded slot source (`pathname` or `pathname?query`) into parts. */
125
120
  function sourceParts(source: string): { path: string; search: string } {
126
- const queryIndex = source.indexOf('?');
127
- if (queryIndex === -1) return { path: trimPathname(source), search: '' };
121
+ const queryIndex = source.indexOf('?')
122
+ if (queryIndex === -1) return { path: trimPathname(source), search: '' }
128
123
  return {
129
124
  path: trimPathname(source.slice(0, queryIndex)),
130
125
  search: source.slice(queryIndex),
131
- };
126
+ }
132
127
  }
133
128
 
134
129
  /** The router's `_rsc` union query is a CDN cache key, never an app param. */
135
130
  function stripRscSearch(search: string): string {
136
- if (!search.includes('_rsc')) return search;
137
- const params = new URLSearchParams(search);
138
- params.delete('_rsc');
139
- const stripped = params.toString();
140
- return stripped ? `?${stripped}` : '';
131
+ if (!search.includes('_rsc')) return search
132
+ const params = new URLSearchParams(search)
133
+ params.delete('_rsc')
134
+ const stripped = params.toString()
135
+ return stripped ? `?${stripped}` : ''
141
136
  }
142
137
 
143
138
  /** Render every `@slot` in `dir` into layout props. */
@@ -145,26 +140,24 @@ export async function renderDirSlots<Options extends SlotRenderOptions>(
145
140
  context: SlotContext<Options>,
146
141
  dir: string,
147
142
  ): Promise<Record<string, ComponentChildren>> {
148
- const slotDirs = slotDirectoriesIn(dir);
149
- if (slotDirs.length === 0) return {};
150
- const consumed = consumedSegments(context.appPath, dir);
143
+ const slotDirs = slotDirectoriesIn(dir)
144
+ if (slotDirs.length === 0) return {}
145
+ const consumed = consumedSegments(context.appPath, dir)
151
146
  // A `[...catchAll]` layout greedily consumes every remaining URL segment (a catch-all is always the last
152
147
  // route segment), so any `@slot` it hosts matches at the index - the empty remaining path. Treat Infinity
153
148
  // as "all segments consumed" rather than skipping slot rendering, which would drop the slot entirely on a
154
149
  // catch-all route.
155
- const effectiveConsumed = Number.isFinite(consumed)
156
- ? consumed
157
- : context.childrenSegments.length;
158
- const props: Record<string, ComponentChildren> = {};
150
+ const effectiveConsumed = Number.isFinite(consumed) ? consumed : context.childrenSegments.length
151
+ const props: Record<string, ComponentChildren> = {}
159
152
  for (const slotDir of slotDirs) {
160
- const content = await resolveSlotContent(context, slotDir, effectiveConsumed);
153
+ const content = await resolveSlotContent(context, slotDir, effectiveConsumed)
161
154
  // An unmatched slot with no `default.*` stays a bare null: wrapping it in
162
155
  // the boundary marker would make it a truthy VNode, and an unmatched
163
156
  // `@children` slot must stay falsy so childrenFromSlots can fall back to
164
157
  // the segment-matched children tree.
165
- props[basename(slotDir).slice(1)] = content == null ? null : wrapSlotBoundary(content);
158
+ props[basename(slotDir).slice(1)] = content == null ? null : wrapSlotBoundary(content)
166
159
  }
167
- return props;
160
+ return props
168
161
  }
169
162
 
170
163
  async function resolveSlotContent<Options extends SlotRenderOptions>(
@@ -172,7 +165,7 @@ async function resolveSlotContent<Options extends SlotRenderOptions>(
172
165
  slotDir: string,
173
166
  consumed: number,
174
167
  ): Promise<ComponentChildren> {
175
- const key = toPosixPath(relative(context.appPath, slotDir));
168
+ const key = toPosixPath(relative(context.appPath, slotDir))
176
169
 
177
170
  // Interceptor targets are absolute paths, so the navigated URL applies to
178
171
  // them regardless of the chain's consumed prefix (that mismatch is exactly
@@ -182,67 +175,67 @@ async function resolveSlotContent<Options extends SlotRenderOptions>(
182
175
  // not intercept it. Interceptors go before direct matching: an interception
183
176
  // route beats a catch-all inside the same slot.
184
177
  if (context.soft && context.urlPath !== context.childrenPath) {
185
- const intercepted = matchSlotInterceptor(context.appPath, slotDir, context.urlPath);
178
+ const intercepted = matchSlotInterceptor(context.appPath, slotDir, context.urlPath)
186
179
  if (intercepted) {
187
- context.stateOut[key] = context.urlPath + context.urlSearch;
188
- return renderSlotMatch(context, slotDir, intercepted, context.urlSearch);
180
+ context.stateOut[key] = context.urlPath + context.urlSearch
181
+ return renderSlotMatch(context, slotDir, intercepted, context.urlSearch)
189
182
  }
190
183
  }
191
184
 
192
185
  // Each candidate source carries the search string its render uses: a slot
193
186
  // re-rendered from a RECORDED source keeps the query it was fetched with
194
187
  // (Next's per-segment refetch URL), not the current request's.
195
- const sources: { path: string; search: string }[] = [];
188
+ const sources: { path: string; search: string }[] = []
196
189
  const pushSource = (path: string, search: string) => {
197
- if (!sources.some(source => source.path === path)) sources.push({ path, search });
198
- };
199
- const rawStateSource = context.statePaths[key];
200
- const stateSource = rawStateSource ? sourceParts(rawStateSource) : undefined;
190
+ if (!sources.some(source => source.path === path)) sources.push({ path, search })
191
+ }
192
+ const rawStateSource = context.statePaths[key]
193
+ const stateSource = rawStateSource ? sourceParts(rawStateSource) : undefined
201
194
  const preserveForInterception =
202
195
  context.soft &&
203
196
  context.urlPath !== context.childrenPath &&
204
197
  context.options.route.slotDirs?.some(dir =>
205
198
  Boolean(matchSlotInterceptor(context.appPath, dir, context.urlPath)),
206
- );
199
+ )
207
200
  if (
208
201
  preserveForInterception &&
209
202
  stateSource &&
210
203
  segmentsSharePrefix(pathnameSegments(stateSource.path), context.childrenSegments, consumed)
211
204
  ) {
212
- pushSource(stateSource.path, stateSource.search);
205
+ pushSource(stateSource.path, stateSource.search)
213
206
  }
214
207
  if (segmentsSharePrefix(context.urlSegments, context.childrenSegments, consumed)) {
215
- pushSource(context.urlPath, context.urlSearch);
208
+ pushSource(context.urlPath, context.urlSearch)
216
209
  }
217
210
  if (
218
211
  context.soft &&
219
212
  stateSource &&
220
213
  segmentsSharePrefix(pathnameSegments(stateSource.path), context.childrenSegments, consumed)
221
214
  ) {
222
- pushSource(stateSource.path, stateSource.search);
215
+ pushSource(stateSource.path, stateSource.search)
223
216
  }
224
217
  // Host renders (children anchored away from the URL) fall back to the
225
218
  // children path itself, so sibling slots keep matching the visible page even
226
219
  // without an explicit state entry.
227
220
  if (context.childrenPath !== context.urlPath) {
228
- pushSource(context.childrenPath, context.childrenSearch);
221
+ pushSource(context.childrenPath, context.childrenSearch)
229
222
  }
230
223
 
231
224
  for (const source of sources) {
232
225
  const intercepted =
233
226
  context.soft && source.path !== context.urlPath
234
227
  ? matchSlotInterceptor(context.appPath, slotDir, source.path)
235
- : null;
228
+ : null
236
229
  const match =
237
- intercepted ?? matchSegments(slotDir, pathnameSegments(source.path).slice(consumed));
238
- if (!match) continue;
239
- context.stateOut[key] = source.path + source.search;
240
- return renderSlotMatch(context, slotDir, match, source.search);
230
+ intercepted ?? matchSegments(slotDir, pathnameSegments(source.path).slice(consumed))
231
+ if (!match) continue
232
+ context.stateOut[key] = source.path + source.search
233
+ return renderSlotMatch(context, slotDir, match, source.search)
241
234
  }
242
235
 
243
- const defaultFile = slotConventionFile(slotDir, 'default');
244
- if (!defaultFile) return null;
245
- return renderSlotComponent(context, defaultFile, {});
236
+ const defaultFile = slotConventionFile(slotDir, 'default')
237
+ if (!defaultFile) return null
238
+ return renderSlotComponent(context, defaultFile, {})
246
239
  }
247
240
 
248
241
  /** Render a matched slot page inside its slot-internal layout chain. */
@@ -255,55 +248,52 @@ async function renderSlotMatch<Options extends SlotRenderOptions>(
255
248
  // A pageless match renders null children under the matched layout chain.
256
249
  let tree: ComponentChildren = match.file
257
250
  ? await renderSlotComponent(context, match.file, match.params, sourceSearch)
258
- : null;
251
+ : null
259
252
 
260
253
  // Wrap innermost-out: loading.* at the page's own dir suspends the page;
261
254
  // each dir's layout receives its own nested slots as props.
262
- const chain: string[] = [slotDir];
263
- for (const name of match.dirs) chain.push(join(chain[chain.length - 1]!, name));
255
+ const chain: string[] = [slotDir]
256
+ for (const name of match.dirs) chain.push(join(chain[chain.length - 1]!, name))
264
257
  context.matches.push({
265
258
  slotDir,
266
259
  ...(match.file ? { pageFile: match.file } : {}),
267
260
  layoutFiles: chain.flatMap(dir => slotConventionFile(dir, 'layout') ?? []),
268
261
  params: match.params,
269
- });
262
+ })
270
263
  for (const dir of [...chain].reverse()) {
271
- const loadingFile = slotConventionFile(dir, 'loading');
264
+ const loadingFile = slotConventionFile(dir, 'loading')
272
265
  if (loadingFile) {
273
266
  const module = (await context.deps.importModule(
274
267
  loadingFile,
275
268
  context.options,
276
- )) as LoadingModule;
277
- const Loading = context.deps.markServerReference(module.default);
269
+ )) as LoadingModule
270
+ const Loading = context.deps.markServerReference(module.default)
278
271
  if (Loading) {
279
272
  tree = h(
280
273
  Suspense,
281
274
  { fallback: h(Loading as ComponentType<Record<string, never>>, {}) },
282
275
  tree,
283
- );
276
+ )
284
277
  }
285
278
  }
286
- const layoutFile = slotConventionFile(dir, 'layout');
287
- if (!layoutFile) continue;
288
- const module = (await context.deps.importModule(layoutFile, context.options)) as LayoutModule;
289
- const Layout = context.deps.markServerReference(module.default);
290
- if (!Layout) continue;
291
- const nestedSlots = await renderDirSlots(context, dir);
279
+ const layoutFile = slotConventionFile(dir, 'layout')
280
+ if (!layoutFile) continue
281
+ const module = (await context.deps.importModule(layoutFile, context.options)) as LayoutModule
282
+ const Layout = context.deps.markServerReference(module.default)
283
+ if (!Layout) continue
284
+ const nestedSlots = await renderDirSlots(context, dir)
292
285
  tree = h(Layout as ComponentType<ServerVNodeProps>, {
293
286
  ...slotPageProps(context, match.params, sourceSearch),
294
287
  ...nestedSlots,
295
288
  children: tree,
296
- });
289
+ })
297
290
  }
298
291
  // Any `'use client'` island rendered anywhere inside this slot subtree must
299
292
  // see the slot's own params (its dynamic / catch-all captures) from useParams,
300
293
  // not just the global route params. Wrap the subtree in a params scope so the
301
294
  // renderer stamps each island it resolves within it (see resolveServerTree's
302
295
  // paramsScopeSymbol handling + render/island-context.ts RouteParamsContext).
303
- return wrapSlotParamsScope(
304
- { ...(context.options.params ?? {}), ...match.params },
305
- tree,
306
- );
296
+ return wrapSlotParamsScope({ ...(context.options.params ?? {}), ...match.params }, tree)
307
297
  }
308
298
 
309
299
  // ---------------------------------------------------------------------------
@@ -315,18 +305,18 @@ async function renderSlotMatch<Options extends SlotRenderOptions>(
315
305
  // slot's resolved params. Mirrors the layout-segment scope above.
316
306
  // ---------------------------------------------------------------------------
317
307
 
318
- export const paramsScopeSymbol = Symbol.for('pnext.paramsScope');
308
+ export const paramsScopeSymbol = Symbol.for('pnext.paramsScope')
319
309
 
320
- const PARAMS_SCOPE_PROP = '__pnextParams';
310
+ const PARAMS_SCOPE_PROP = '__pnextParams'
321
311
 
322
- const paramsSnapshotStorage = new AsyncLocalStorage<RouteParamsSnapshot>();
312
+ const paramsSnapshotStorage = new AsyncLocalStorage<RouteParamsSnapshot>()
323
313
 
324
314
  type ParamsScopeMarker = ((props: ServerVNodeProps) => ComponentChildren) & {
325
- [paramsScopeSymbol]?: true;
326
- };
315
+ [paramsScopeSymbol]?: true
316
+ }
327
317
 
328
- const ParamsScopeMarker: ParamsScopeMarker = props => props.children;
329
- ParamsScopeMarker[paramsScopeSymbol] = true;
318
+ const ParamsScopeMarker: ParamsScopeMarker = props => props.children
319
+ ParamsScopeMarker[paramsScopeSymbol] = true
330
320
 
331
321
  // Parallel-route slot marker (task-boundary scoping). A named `@slot` subtree is wrapped in this marker so
332
322
  // the server-tree resolver can arm the build prerender's task boundary ONLY while resolving slot content.
@@ -334,33 +324,33 @@ ParamsScopeMarker[paramsScopeSymbol] = true;
334
324
  // to parallel-route slots, the shape it was designed for, and leaves every other <Suspense> baking its task
335
325
  // work as before.
336
326
 
337
- export const slotBoundarySymbol = Symbol.for('pnext.slotBoundary');
327
+ export const slotBoundarySymbol = Symbol.for('pnext.slotBoundary')
338
328
 
339
329
  type SlotBoundaryMarker = ((props: ServerVNodeProps) => ComponentChildren) & {
340
- [slotBoundarySymbol]?: true;
341
- };
330
+ [slotBoundarySymbol]?: true
331
+ }
342
332
 
343
- const SlotBoundaryMarker: SlotBoundaryMarker = props => props.children;
344
- SlotBoundaryMarker[slotBoundarySymbol] = true;
333
+ const SlotBoundaryMarker: SlotBoundaryMarker = props => props.children
334
+ SlotBoundaryMarker[slotBoundarySymbol] = true
345
335
 
346
336
  /** Wrap a named parallel-route slot subtree in the task-boundary marker. */
347
337
  export function wrapSlotBoundary(content: ComponentChildren): ComponentChildren {
348
- return h(SlotBoundaryMarker as ComponentType<ServerVNodeProps>, null, content);
338
+ return h(SlotBoundaryMarker as ComponentType<ServerVNodeProps>, null, content)
349
339
  }
350
340
 
351
341
  /** Read the params for the slot scope active in the current async resolution. */
352
342
  export function currentParamsSnapshot(): RouteParamsSnapshot | undefined {
353
- return paramsSnapshotStorage.getStore();
343
+ return paramsSnapshotStorage.getStore()
354
344
  }
355
345
 
356
346
  /** Run `fn` with the given slot params installed as the active params scope. */
357
347
  export function runInParamsScope<T>(params: RouteParamsSnapshot, fn: () => T): T {
358
- return paramsSnapshotStorage.run(params, fn);
348
+ return paramsSnapshotStorage.run(params, fn)
359
349
  }
360
350
 
361
351
  /** Read the params a params-scope marker VNode carries. */
362
352
  export function paramsScopeParams(props: Record<string, unknown>): RouteParamsSnapshot {
363
- return (props[PARAMS_SCOPE_PROP] as RouteParamsSnapshot | undefined) ?? {};
353
+ return (props[PARAMS_SCOPE_PROP] as RouteParamsSnapshot | undefined) ?? {}
364
354
  }
365
355
 
366
356
  function wrapSlotParamsScope(
@@ -371,7 +361,7 @@ function wrapSlotParamsScope(
371
361
  ParamsScopeMarker as ComponentType<ServerVNodeProps>,
372
362
  { [PARAMS_SCOPE_PROP]: params },
373
363
  tree,
374
- );
364
+ )
375
365
  }
376
366
 
377
367
  async function renderSlotComponent<Options extends SlotRenderOptions>(
@@ -380,38 +370,38 @@ async function renderSlotComponent<Options extends SlotRenderOptions>(
380
370
  params: Record<string, RouteParamValue>,
381
371
  sourceSearch?: string,
382
372
  ): Promise<ComponentChildren> {
383
- const props = slotPageProps(context, params, sourceSearch);
373
+ const props = slotPageProps(context, params, sourceSearch)
384
374
 
385
375
  // A 'use client' page inside a slot renders as an island: the reference
386
376
  // stub becomes a hydrated boundary in resolveServerTree. Its promise props
387
377
  // (params/searchParams) travel as plain markers the island runtime revives.
388
378
  const reference = context.options.route.clientReferences.find(
389
379
  item => item.file === file && item.exportName === 'default',
390
- );
380
+ )
391
381
  if (reference) {
392
382
  const Component =
393
383
  context.options.clientComponents?.get(reference.id) ??
394
- context.deps.clientReferenceStub(reference);
384
+ context.deps.clientReferenceStub(reference)
395
385
  return h(Component, {
396
386
  params: promiseMarker(await props.params),
397
387
  searchParams: promiseMarker(await props.searchParams),
398
- });
388
+ })
399
389
  }
400
390
 
401
- const module = (await context.deps.importModule(file, context.options)) as PageModule;
402
- const Component = context.deps.markServerReference(module.default);
403
- if (!Component) return null;
404
- return h(Component as ComponentType<PageProps>, props);
391
+ const module = (await context.deps.importModule(file, context.options)) as PageModule
392
+ const Component = context.deps.markServerReference(module.default)
393
+ if (!Component) return null
394
+ return h(Component as ComponentType<PageProps>, props)
405
395
  }
406
396
 
407
- const PROMISE_MARKER_KEY = '__pnextPromise';
397
+ const PROMISE_MARKER_KEY = '__pnextPromise'
408
398
 
409
399
  export function promiseMarker(value: unknown) {
410
- return { [PROMISE_MARKER_KEY]: value ?? null };
400
+ return { [PROMISE_MARKER_KEY]: value ?? null }
411
401
  }
412
402
 
413
403
  /** The discriminator that makes a placeholder marker rewritable at serve time. */
414
- const PROMISE_PLACEHOLDER_KEY = '__pnextParams';
404
+ const PROMISE_PLACEHOLDER_KEY = '__pnextParams'
415
405
 
416
406
  /**
417
407
  * The wire placeholder for a request-API promise prop that a partial prerender must NOT await (see ppr.ts
@@ -420,25 +410,25 @@ const PROMISE_PLACEHOLDER_KEY = '__pnextParams';
420
410
  * `window.__PNEXT_ROUTE__` and `data-pnext-params`, and all three must agree.
421
411
  */
422
412
  export function promisePlaceholderMarker(kind: 'params' | 'searchParams') {
423
- return { [PROMISE_MARKER_KEY]: null, [PROMISE_PLACEHOLDER_KEY]: kind };
413
+ return { [PROMISE_MARKER_KEY]: null, [PROMISE_PLACEHOLDER_KEY]: kind }
424
414
  }
425
415
 
426
416
  /** The serialized placeholder the serve-time re-stamp searches for. */
427
417
  export function promisePlaceholderJson(kind: 'params' | 'searchParams'): string {
428
- return `{"${PROMISE_MARKER_KEY}":null,"${PROMISE_PLACEHOLDER_KEY}":"${kind}"}`;
418
+ return `{"${PROMISE_MARKER_KEY}":null,"${PROMISE_PLACEHOLDER_KEY}":"${kind}"}`
429
419
  }
430
420
 
431
421
  /** Revive promise markers into thenables for the SSR pass of an island. */
432
422
  export function revivePromiseProps(props: Record<string, unknown>) {
433
- const out: Record<string, unknown> = {};
423
+ const out: Record<string, unknown> = {}
434
424
  for (const [key, value] of Object.entries(props)) {
435
425
  if (value && typeof value === 'object' && PROMISE_MARKER_KEY in value) {
436
- out[key] = Promise.resolve((value as Record<string, unknown>)[PROMISE_MARKER_KEY]);
426
+ out[key] = Promise.resolve((value as Record<string, unknown>)[PROMISE_MARKER_KEY])
437
427
  } else {
438
- out[key] = value;
428
+ out[key] = value
439
429
  }
440
430
  }
441
- return out;
431
+ return out
442
432
  }
443
433
 
444
434
  function slotPageProps<Options extends SlotRenderOptions>(
@@ -446,14 +436,14 @@ function slotPageProps<Options extends SlotRenderOptions>(
446
436
  params: Record<string, RouteParamValue>,
447
437
  sourceSearch?: string,
448
438
  ): PageProps {
449
- const base = context.deps.createPageProps(context.options);
439
+ const base = context.deps.createPageProps(context.options)
450
440
  // What createPageProps already resolves searchParams from: the children
451
441
  // tree's recorded query on a host render, the request's otherwise (see
452
442
  // childrenSourceSearchParams in renderer.ts).
453
443
  const baseSearch =
454
444
  context.soft && context.childrenPath !== trimPathname(context.options.url.pathname)
455
445
  ? context.childrenSearch
456
- : context.urlSearch;
446
+ : context.urlSearch
457
447
  return {
458
448
  ...base,
459
449
  params: Promise.resolve({ ...(context.options.params ?? {}), ...params }),
@@ -463,37 +453,37 @@ function slotPageProps<Options extends SlotRenderOptions>(
463
453
  ...(sourceSearch !== undefined && sourceSearch !== baseSearch
464
454
  ? { searchParams: fulfilledPromise(searchParamsObject(sourceSearch)) }
465
455
  : {}),
466
- };
456
+ }
467
457
  }
468
458
 
469
459
  // Repeated keys collect into arrays (Next's searchParams page-prop shape).
470
460
  function searchParamsObject(search: string): Record<string, string | string[]> {
471
- const result: Record<string, string | string[]> = {};
461
+ const result: Record<string, string | string[]> = {}
472
462
  new URLSearchParams(search).forEach((value, key) => {
473
- if (key === '_rsc') return;
474
- const current = result[key];
475
- if (current === undefined) result[key] = value;
476
- else if (Array.isArray(current)) current.push(value);
477
- else result[key] = [current, value];
478
- });
479
- return result;
463
+ if (key === '_rsc') return
464
+ const current = result[key]
465
+ if (current === undefined) result[key] = value
466
+ else if (Array.isArray(current)) current.push(value)
467
+ else result[key] = [current, value]
468
+ })
469
+ return result
480
470
  }
481
471
 
482
472
  // Pre-settled promise (status/value readable synchronously) so preact's use()
483
473
  // does not suspend during streaming SSR — mirrors renderer.ts settledPromise
484
474
  // (not imported: renderer.ts imports from this module).
485
475
  function fulfilledPromise<T>(value: T): Promise<T> {
486
- const promise = Promise.resolve(value) as Promise<T> & { status?: string; value?: T };
487
- promise.status = 'fulfilled';
488
- promise.value = value;
489
- return promise;
476
+ const promise = Promise.resolve(value) as Promise<T> & { status?: string; value?: T }
477
+ promise.status = 'fulfilled'
478
+ promise.value = value
479
+ return promise
490
480
  }
491
481
 
492
482
  function segmentsSharePrefix(a: string[], b: string[], length: number) {
493
483
  for (let index = 0; index < length; index += 1) {
494
- if (a[index] !== b[index]) return false;
484
+ if (a[index] !== b[index]) return false
495
485
  }
496
- return true;
486
+ return true
497
487
  }
498
488
 
499
489
  // ---------------------------------------------------------------------------
@@ -508,13 +498,13 @@ function segmentsSharePrefix(a: string[], b: string[], length: number) {
508
498
  // ---------------------------------------------------------------------------
509
499
 
510
500
  export interface LayoutSegmentScope {
511
- segments: string[];
512
- appPath?: string;
513
- layoutDir?: string;
514
- slots?: Record<string, string>;
501
+ segments: string[]
502
+ appPath?: string
503
+ layoutDir?: string
504
+ slots?: Record<string, string>
515
505
  }
516
506
 
517
- const layoutSegmentStorage = new AsyncLocalStorage<LayoutSegmentScope>();
507
+ const layoutSegmentStorage = new AsyncLocalStorage<LayoutSegmentScope>()
518
508
 
519
509
  /**
520
510
  * Run `fn` inside a layout-segment scope. The synchronous portion of a layout's
@@ -527,7 +517,7 @@ export function runInLayoutSegmentScope<T>(
527
517
  fn: () => T,
528
518
  scope: Omit<LayoutSegmentScope, 'segments'> = {},
529
519
  ): T {
530
- return layoutSegmentStorage.run({ segments, ...scope }, fn);
520
+ return layoutSegmentStorage.run({ segments, ...scope }, fn)
531
521
  }
532
522
 
533
523
  /**
@@ -538,24 +528,23 @@ export function runInLayoutSegmentScope<T>(
538
528
  * Returns undefined outside any layout scope (e.g. a leaf page island).
539
529
  */
540
530
  export function currentLayoutSegmentSnapshot():
541
- | { depth: number; segments: string[]; slots: Record<string, string[]> }
542
- | undefined {
543
- const scope = layoutSegmentStorage.getStore();
544
- if (!scope) return undefined;
545
- const slots: Record<string, string[]> = {};
546
- let depth = 0;
531
+ { depth: number; segments: string[]; slots: Record<string, string[]> } | undefined {
532
+ const scope = layoutSegmentStorage.getStore()
533
+ if (!scope) return undefined
534
+ const slots: Record<string, string[]> = {}
535
+ let depth = 0
547
536
  if (scope.appPath && scope.layoutDir) {
548
- depth = layoutSegmentDepth(scope.appPath, scope.layoutDir);
549
- const owner = toPosixPath(relative(scope.appPath, scope.layoutDir));
550
- const prefix = owner ? `${owner}/@` : '@';
537
+ depth = layoutSegmentDepth(scope.appPath, scope.layoutDir)
538
+ const owner = toPosixPath(relative(scope.appPath, scope.layoutDir))
539
+ const prefix = owner ? `${owner}/@` : '@'
551
540
  for (const [dir, path] of Object.entries(scope.slots ?? {})) {
552
- if (!dir.startsWith(prefix)) continue;
553
- const key = dir.slice(prefix.length);
554
- if (key.includes('/')) continue;
555
- slots[key] = pathnameSegments(path);
541
+ if (!dir.startsWith(prefix)) continue
542
+ const key = dir.slice(prefix.length)
543
+ if (key.includes('/')) continue
544
+ slots[key] = pathnameSegments(path)
556
545
  }
557
546
  }
558
- return { depth, segments: scope.segments, slots };
547
+ return { depth, segments: scope.segments, slots }
559
548
  }
560
549
 
561
550
  /**
@@ -565,18 +554,18 @@ export function currentLayoutSegmentSnapshot():
565
554
  * hook falls back to the island context instead. Distinguishes the two callers.
566
555
  */
567
556
  export function hasLayoutSegmentScope(): boolean {
568
- return layoutSegmentStorage.getStore() !== undefined;
557
+ return layoutSegmentStorage.getStore() !== undefined
569
558
  }
570
559
 
571
560
  /** The active layout's "segments below me", or `[]` outside any layout scope. */
572
561
  export function currentLayoutSegments(slotKey?: string): string[] {
573
- const scope = layoutSegmentStorage.getStore();
574
- if (!scope) return [];
575
- if (!slotKey) return scope.segments;
576
- if (!scope.appPath || !scope.layoutDir) return [];
577
- const owner = toPosixPath(relative(scope.appPath, scope.layoutDir));
578
- const slotPath = scope.slots?.[owner ? `${owner}/@${slotKey}` : `@${slotKey}`];
579
- return slotPath ? pathnameSegments(slotPath) : [];
562
+ const scope = layoutSegmentStorage.getStore()
563
+ if (!scope) return []
564
+ if (!slotKey) return scope.segments
565
+ if (!scope.appPath || !scope.layoutDir) return []
566
+ const owner = toPosixPath(relative(scope.appPath, scope.layoutDir))
567
+ const slotPath = scope.slots?.[owner ? `${owner}/@${slotKey}` : `@${slotKey}`]
568
+ return slotPath ? pathnameSegments(slotPath) : []
580
569
  }
581
570
 
582
571
  /**
@@ -591,33 +580,33 @@ export function fullLayoutSegments(
591
580
  leafDir: string,
592
581
  params: Record<string, RouteParamValue>,
593
582
  ): string[] {
594
- const relativeDir = relative(appPath, leafDir);
595
- if (relativeDir.startsWith('..')) return [];
596
- const segments: string[] = [];
583
+ const relativeDir = relative(appPath, leafDir)
584
+ if (relativeDir.startsWith('..')) return []
585
+ const segments: string[] = []
597
586
  for (const name of relativeDir.split(sep).filter(Boolean)) {
598
- if (isSlotSegment(name)) continue;
587
+ if (isSlotSegment(name)) continue
599
588
  if (isGroupSegment(name)) {
600
- segments.push(name);
601
- continue;
589
+ segments.push(name)
590
+ continue
602
591
  }
603
- const optional = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(name);
604
- const catchAll = optional ?? /^\[\.\.\.([^\]]+)\]$/.exec(name);
592
+ const optional = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(name)
593
+ const catchAll = optional ?? /^\[\.\.\.([^\]]+)\]$/.exec(name)
605
594
  if (catchAll?.[1]) {
606
- const value = params[catchAll[1]];
607
- const joined = Array.isArray(value) ? value.join('/') : (value ?? '');
595
+ const value = params[catchAll[1]]
596
+ const joined = Array.isArray(value) ? value.join('/') : (value ?? '')
608
597
  // An empty optional catch-all contributes no segment at all.
609
- if (joined) segments.push(joined);
610
- continue;
598
+ if (joined) segments.push(joined)
599
+ continue
611
600
  }
612
- const dynamic = /^\[([^\].]+)\]$/.exec(name);
601
+ const dynamic = /^\[([^\].]+)\]$/.exec(name)
613
602
  if (dynamic?.[1]) {
614
- const value = params[dynamic[1]];
615
- segments.push(Array.isArray(value) ? value.join('/') : String(value ?? ''));
616
- continue;
603
+ const value = params[dynamic[1]]
604
+ segments.push(Array.isArray(value) ? value.join('/') : String(value ?? ''))
605
+ continue
617
606
  }
618
- segments.push(name);
607
+ segments.push(name)
619
608
  }
620
- return segments;
609
+ return segments
621
610
  }
622
611
 
623
612
  /**
@@ -632,33 +621,33 @@ export function layoutParamsForDir(
632
621
  layoutDir: string,
633
622
  params: Record<string, RouteParamValue>,
634
623
  ): Record<string, RouteParamValue> {
635
- const relativeDir = relative(appPath, layoutDir);
636
- if (relativeDir.startsWith('..')) return {};
637
- const scoped: Record<string, RouteParamValue> = {};
624
+ const relativeDir = relative(appPath, layoutDir)
625
+ if (relativeDir.startsWith('..')) return {}
626
+ const scoped: Record<string, RouteParamValue> = {}
638
627
  for (const name of relativeDir.split(sep).filter(Boolean)) {
639
- if (isSlotSegment(name) || isGroupSegment(name)) continue;
640
- const optional = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(name);
628
+ if (isSlotSegment(name) || isGroupSegment(name)) continue
629
+ const optional = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(name)
641
630
  if (optional?.[1]) {
642
- const value = params[optional[1]];
631
+ const value = params[optional[1]]
643
632
  // Empty optional catch-all: omit entirely (no params object for the layout).
644
633
  if (value !== undefined && (Array.isArray(value) ? value.length > 0 : value != null)) {
645
- scoped[optional[1]] = value;
634
+ scoped[optional[1]] = value
646
635
  }
647
- continue;
636
+ continue
648
637
  }
649
- const catchAll = /^\[\.\.\.([^\]]+)\]$/.exec(name);
638
+ const catchAll = /^\[\.\.\.([^\]]+)\]$/.exec(name)
650
639
  if (catchAll?.[1]) {
651
- const value = params[catchAll[1]];
652
- if (value !== undefined) scoped[catchAll[1]] = value;
653
- continue;
640
+ const value = params[catchAll[1]]
641
+ if (value !== undefined) scoped[catchAll[1]] = value
642
+ continue
654
643
  }
655
- const dynamic = /^\[([^\].]+)\]$/.exec(name);
644
+ const dynamic = /^\[([^\].]+)\]$/.exec(name)
656
645
  if (dynamic?.[1]) {
657
- const value = params[dynamic[1]];
658
- if (value !== undefined) scoped[dynamic[1]] = value;
646
+ const value = params[dynamic[1]]
647
+ if (value !== undefined) scoped[dynamic[1]] = value
659
648
  }
660
649
  }
661
- return scoped;
650
+ return scoped
662
651
  }
663
652
 
664
653
  /**
@@ -668,12 +657,12 @@ export function layoutParamsForDir(
668
657
  * present in the full list); slots count as zero.
669
658
  */
670
659
  export function layoutSegmentDepth(appPath: string, layoutDir: string): number {
671
- const relativeDir = relative(appPath, layoutDir);
672
- if (relativeDir.startsWith('..') || relativeDir === '') return 0;
673
- let depth = 0;
660
+ const relativeDir = relative(appPath, layoutDir)
661
+ if (relativeDir.startsWith('..') || relativeDir === '') return 0
662
+ let depth = 0
674
663
  for (const name of relativeDir.split(sep).filter(Boolean)) {
675
- if (isSlotSegment(name)) continue;
676
- depth += 1;
664
+ if (isSlotSegment(name)) continue
665
+ depth += 1
677
666
  }
678
- return depth;
667
+ return depth
679
668
  }