@wular/pnext 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/README.md +11 -11
  2. package/bin/pnext +1 -1
  3. package/config/lint/base.js +7 -7
  4. package/config/ts/base.json +2 -4
  5. package/config/ts/react.json +2 -6
  6. package/package.json +23 -2
  7. package/reference/compat.md +1 -1
  8. package/reference/config.md +2 -2
  9. package/reference/css.md +13 -9
  10. package/reference/dev.md +1 -1
  11. package/reference/metadata.md +7 -7
  12. package/reference/navigation.md +35 -28
  13. package/reference/performance.md +70 -70
  14. package/reference/rendering.md +17 -17
  15. package/reference/routing.md +17 -17
  16. package/reference/typegen.md +12 -8
  17. package/src/api/cache.ts +36 -37
  18. package/src/api/client-cache.ts +2 -2
  19. package/src/api/client-navigation.ts +113 -109
  20. package/src/api/dynamic.tsx +58 -55
  21. package/src/api/link.tsx +49 -52
  22. package/src/api/navigation.ts +59 -58
  23. package/src/api/server.ts +152 -144
  24. package/src/api/suspense.ts +4 -4
  25. package/src/cli/adapters/vercel-warm.ts +126 -121
  26. package/src/cli/adapters/vercel.ts +437 -443
  27. package/src/cli/analyze.ts +333 -144
  28. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  29. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  30. package/src/cli/build.ts +976 -978
  31. package/src/cli/create.ts +71 -63
  32. package/src/cli/dev.ts +116 -116
  33. package/src/cli/index.ts +88 -85
  34. package/src/cli/migrate/package-json.ts +73 -71
  35. package/src/cli/migrate/report.ts +32 -33
  36. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  37. package/src/cli/migrate/scan.ts +46 -46
  38. package/src/cli/migrate/spinner.ts +9 -9
  39. package/src/cli/migrate/tsconfig.ts +35 -35
  40. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  41. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  42. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  43. package/src/cli/start.ts +65 -66
  44. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  45. package/src/client/build.ts +794 -768
  46. package/src/client/chunk-fold.ts +245 -240
  47. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  48. package/src/client/entry.ts +162 -147
  49. package/src/client/prebuilt.ts +231 -223
  50. package/src/client/profile.ts +29 -29
  51. package/src/client/react-compiler.ts +20 -15
  52. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  53. package/src/client/reference-stub.ts +51 -51
  54. package/src/client/reference.ts +19 -19
  55. package/src/{api → client}/router/events.ts +17 -17
  56. package/src/{api → client}/router/history.ts +16 -16
  57. package/src/{api → client}/router/hub.ts +52 -53
  58. package/src/{api/router.ts → client/router/index.ts} +61 -60
  59. package/src/{api → client}/router/policies.ts +24 -24
  60. package/src/{api → client}/router/runtime.ts +1988 -1992
  61. package/src/{api → client}/router/types.ts +93 -98
  62. package/src/compat/actions/client-plugin.ts +42 -43
  63. package/src/compat/actions/client-stub.ts +14 -14
  64. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  65. package/src/compat/actions/config.ts +63 -64
  66. package/src/compat/actions/detect.ts +68 -68
  67. package/src/compat/actions/discovery.ts +105 -105
  68. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  69. package/src/compat/actions/early-submit.ts +1 -1
  70. package/src/compat/actions/endpoint.ts +198 -198
  71. package/src/compat/actions/extensions.ts +811 -0
  72. package/src/compat/actions/flight.ts +23 -23
  73. package/src/compat/actions/form-state.ts +34 -34
  74. package/src/compat/actions/hoist.ts +382 -236
  75. package/src/compat/actions/ids.ts +7 -12
  76. package/src/compat/actions/index.ts +8 -8
  77. package/src/compat/actions/instances.ts +46 -46
  78. package/src/compat/actions/origin.ts +47 -48
  79. package/src/compat/actions/protocol.ts +22 -22
  80. package/src/compat/actions/registry.ts +19 -19
  81. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  82. package/src/compat/actions/rewrite.ts +125 -125
  83. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  84. package/src/compat/actions/serve.ts +132 -136
  85. package/src/compat/actions/server-tag.ts +4 -4
  86. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  87. package/src/compat/actions/unrecognized-error.ts +4 -4
  88. package/src/compat/{index.ts → aliases.ts} +112 -109
  89. package/src/compat/bundler/bun-externals.ts +18 -18
  90. package/src/compat/bundler/cjs-exports.ts +271 -223
  91. package/src/compat/bundler/config.ts +116 -111
  92. package/src/compat/bundler/externals.ts +12 -12
  93. package/src/compat/bundler/import-meta-url.ts +19 -19
  94. package/src/compat/bundler/modularize-imports.ts +36 -33
  95. package/src/compat/bundler/new-url-asset.ts +22 -24
  96. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  97. package/src/compat/bundler/polyfill.ts +28 -28
  98. package/src/compat/bundler/react-compiler.ts +35 -29
  99. package/src/compat/bundler/react-profiler.tsx +11 -11
  100. package/src/compat/bundler/relay-transform.ts +48 -47
  101. package/src/compat/bundler/require-context.ts +119 -113
  102. package/src/compat/bundler/resolve-extensions.ts +19 -19
  103. package/src/compat/bundler/source-cache.ts +25 -25
  104. package/src/compat/bundler/static-imports.ts +7 -7
  105. package/src/compat/bundler/symlink-imports.ts +46 -46
  106. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  107. package/src/compat/bundler/wasm.ts +58 -60
  108. package/src/compat/bundler/webpack-loaders.ts +254 -241
  109. package/src/compat/bundler/worker.ts +101 -104
  110. package/src/compat/cache/build-flags.ts +29 -29
  111. package/src/compat/cache/build-prerender-errors.ts +40 -44
  112. package/src/compat/cache/custom-handler.ts +60 -53
  113. package/src/compat/cache/fetch-patch.ts +240 -240
  114. package/src/compat/cache/handler.ts +27 -31
  115. package/src/compat/cache/modern-handler.ts +148 -126
  116. package/src/compat/cache/resume-data-cache.ts +47 -45
  117. package/src/compat/cache/revalidate.ts +233 -232
  118. package/src/compat/cache/runtime-error.ts +35 -35
  119. package/src/compat/cache/use-cache-transform.ts +442 -417
  120. package/src/compat/cache/use-cache.ts +650 -614
  121. package/src/compat/cache-control.ts +140 -142
  122. package/src/compat/client/base-path.ts +21 -20
  123. package/src/compat/client/css-order.ts +18 -18
  124. package/src/compat/client/errors/bare-boundary.ts +11 -11
  125. package/src/compat/client/errors/control-flow.ts +23 -23
  126. package/src/compat/client/errors/error-boundary.ts +61 -61
  127. package/src/compat/client/errors/global-error.ts +101 -91
  128. package/src/compat/client/errors/install.ts +71 -72
  129. package/src/compat/client/errors/lazy.ts +23 -23
  130. package/src/compat/client/errors/primitive-throw.ts +47 -45
  131. package/src/compat/client/errors/soft-refresh.ts +4 -4
  132. package/src/compat/client/link-status.ts +33 -33
  133. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  134. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  135. package/src/compat/client/navigation-scroll.ts +63 -63
  136. package/src/compat/client/optimistic-routing.ts +93 -88
  137. package/src/compat/client/prefetch-cache.ts +23 -24
  138. package/src/compat/client/route-announcer.ts +35 -35
  139. package/src/compat/client/segment-cache-policy.ts +20 -20
  140. package/src/compat/client/segment-cache.ts +309 -315
  141. package/src/compat/client/segment-prefetch.ts +127 -132
  142. package/src/compat/client/trailing-slash.ts +5 -4
  143. package/src/compat/css/chunking.ts +113 -116
  144. package/src/compat/css/inline-css.ts +21 -21
  145. package/src/compat/css/lightningcss.ts +37 -38
  146. package/src/compat/css/modules.ts +161 -175
  147. package/src/compat/css/nonce.ts +7 -7
  148. package/src/compat/css/sass-plugin.ts +18 -21
  149. package/src/compat/css/sass.ts +150 -152
  150. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  151. package/src/compat/css/styled-jsx.ts +21 -21
  152. package/src/compat/edge-runtime.ts +27 -27
  153. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  154. package/src/compat/export/client.ts +29 -31
  155. package/src/compat/export/{index.ts → emit.ts} +111 -110
  156. package/src/compat/export/standalone.ts +62 -54
  157. package/src/compat/image-optimizer/cache.ts +51 -49
  158. package/src/compat/image-optimizer/detect.ts +52 -52
  159. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  160. package/src/compat/image-optimizer/source.ts +77 -80
  161. package/src/compat/lifecycle/after-scope.ts +26 -26
  162. package/src/compat/lifecycle/after.ts +48 -45
  163. package/src/compat/lifecycle/error-funnel.ts +98 -102
  164. package/src/compat/lifecycle/error-serialize.ts +30 -26
  165. package/src/compat/lifecycle/error-ui.ts +67 -32
  166. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  167. package/src/compat/lifecycle/instrumentation.ts +85 -85
  168. package/src/compat/lifecycle/node-console.ts +11 -11
  169. package/src/compat/lifecycle/testmode.ts +160 -132
  170. package/src/compat/mdx/compile.ts +60 -57
  171. package/src/compat/mdx/plugin.ts +11 -11
  172. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  173. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  174. package/src/compat/metadata.ts +75 -81
  175. package/src/compat/next/cache.ts +68 -69
  176. package/src/compat/next/canonical-url.ts +9 -9
  177. package/src/compat/next/client-cache.ts +19 -19
  178. package/src/compat/next/client-navigation.ts +112 -116
  179. package/src/compat/next/client-only.ts +1 -1
  180. package/src/compat/next/client-script.tsx +99 -93
  181. package/src/compat/next/client-server.ts +10 -10
  182. package/src/compat/next/config-loader.ts +176 -173
  183. package/src/compat/next/config.ts +7 -7
  184. package/src/compat/next/constants.cjs +6 -6
  185. package/src/compat/next/constants.ts +6 -6
  186. package/src/compat/next/custom-server.ts +26 -24
  187. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  188. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  189. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  190. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  191. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  192. package/src/compat/next/dynamic.tsx +21 -18
  193. package/src/compat/next/error.tsx +52 -52
  194. package/src/compat/next/font/cache.ts +74 -74
  195. package/src/compat/next/font/google.ts +2 -2
  196. package/src/compat/next/font/index.ts +1 -1
  197. package/src/compat/next/font/local.ts +3 -3
  198. package/src/compat/next/font/runtime-client.ts +17 -15
  199. package/src/compat/next/font/runtime.ts +443 -408
  200. package/src/compat/next/font/shared.ts +120 -108
  201. package/src/compat/next/form.tsx +63 -63
  202. package/src/compat/next/head.tsx +2 -2
  203. package/src/compat/next/headers.ts +103 -95
  204. package/src/compat/next/image/client.tsx +220 -0
  205. package/src/compat/next/image/config.ts +56 -58
  206. package/src/compat/next/image/optimizer.ts +40 -36
  207. package/src/compat/next/image/patterns.ts +37 -40
  208. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  209. package/src/compat/next/image/shared.ts +65 -57
  210. package/src/compat/next/image/static-metadata.ts +98 -107
  211. package/src/compat/next/image/validate.ts +79 -88
  212. package/src/compat/next/image.tsx +19 -23
  213. package/src/compat/next/index.ts +1 -1
  214. package/src/compat/next/legacy-image.tsx +59 -60
  215. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  216. package/src/compat/next/link.tsx +158 -158
  217. package/src/compat/next/navigation.cjs +12 -3
  218. package/src/compat/next/navigation.ts +48 -50
  219. package/src/compat/next/offline.ts +27 -27
  220. package/src/compat/next/og.ts +121 -124
  221. package/src/compat/next/preferred-region.ts +13 -14
  222. package/src/compat/next/redirects.ts +58 -56
  223. package/src/compat/next/resource-hints.ts +73 -76
  224. package/src/compat/next/rewrites.ts +130 -133
  225. package/src/compat/next/root-params.ts +45 -45
  226. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  227. package/src/compat/next/router.cjs +4 -2
  228. package/src/compat/next/router.ts +58 -61
  229. package/src/compat/next/script.tsx +108 -108
  230. package/src/compat/next/server-only.ts +1 -1
  231. package/src/compat/next/server.ts +19 -19
  232. package/src/compat/next/svgr.ts +18 -17
  233. package/src/compat/next/telemetry.ts +24 -24
  234. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  235. package/src/compat/next/user-agent.ts +53 -49
  236. package/src/compat/next/web-vitals.ts +22 -24
  237. package/src/compat/otel/api.ts +41 -41
  238. package/src/compat/otel/client-trace-metadata.ts +25 -27
  239. package/src/compat/otel/fetch-span.ts +29 -29
  240. package/src/compat/otel/tracer.ts +331 -331
  241. package/src/compat/pages/api.ts +456 -0
  242. package/src/compat/pages/client-plugin.ts +36 -36
  243. package/src/compat/pages/router-state.ts +34 -34
  244. package/src/compat/pages/{index.ts → router.ts} +130 -135
  245. package/src/compat/ppr/io.ts +12 -12
  246. package/src/compat/ppr/missing-root-params.ts +34 -38
  247. package/src/compat/ppr/root-params-scan.ts +66 -66
  248. package/src/compat/ppr/root-params-transform.ts +24 -26
  249. package/src/compat/ppr/root-params.ts +30 -30
  250. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  251. package/src/compat/protocol.ts +71 -70
  252. package/src/compat/react/action-state.ts +47 -48
  253. package/src/compat/react/client-lite.ts +15 -15
  254. package/src/compat/react/client.ts +4 -4
  255. package/src/compat/react/compiler-runtime.ts +11 -11
  256. package/src/compat/react/dom-client.ts +44 -44
  257. package/src/compat/react/dom-react-server.ts +10 -16
  258. package/src/compat/react/dom-server.ts +10 -10
  259. package/src/compat/react/dom.ts +52 -52
  260. package/src/compat/react/hooks-extra.ts +34 -35
  261. package/src/compat/react/parity.ts +64 -61
  262. package/src/compat/react/preact.ts +81 -82
  263. package/src/compat/react/react-server.ts +28 -28
  264. package/src/compat/react/router-shim.ts +1 -1
  265. package/src/compat/react/server-component-use.ts +8 -8
  266. package/src/compat/react/server-inserted-html.ts +30 -31
  267. package/src/compat/react/server.ts +53 -55
  268. package/src/compat/react/use.ts +32 -32
  269. package/src/compat/react/view-transition.ts +20 -20
  270. package/src/compat/register/actions.ts +35 -824
  271. package/src/compat/register/boot.ts +41 -41
  272. package/src/compat/register/build-tier.ts +5 -5
  273. package/src/compat/register/build.ts +74 -70
  274. package/src/compat/register/bundler.ts +161 -156
  275. package/src/compat/register/cache.ts +20 -20
  276. package/src/compat/register/client-errors.ts +3 -3
  277. package/src/compat/register/config.ts +6 -6
  278. package/src/compat/register/css-extras.ts +30 -34
  279. package/src/compat/register/edge-runtime.ts +3 -3
  280. package/src/compat/register/errors.ts +10 -12
  281. package/src/compat/register/export.ts +16 -16
  282. package/src/compat/register/font.ts +11 -11
  283. package/src/compat/register/hooks.ts +2 -2
  284. package/src/compat/register/image.ts +40 -40
  285. package/src/compat/register/index.ts +59 -62
  286. package/src/compat/register/instrumentation-client.ts +10 -10
  287. package/src/compat/register/lifecycle.ts +25 -28
  288. package/src/compat/register/mdx.ts +10 -10
  289. package/src/compat/register/middleware.ts +226 -16
  290. package/src/compat/register/otel.ts +80 -88
  291. package/src/compat/register/pages-api.ts +10 -463
  292. package/src/compat/register/ppr.ts +16 -16
  293. package/src/compat/register/protocol.ts +17 -18
  294. package/src/compat/register/proxy.ts +49 -51
  295. package/src/compat/register/render.ts +79 -76
  296. package/src/compat/register/routing.ts +162 -159
  297. package/src/compat/register/segment.ts +24 -1897
  298. package/src/compat/register/static-image.ts +3 -3
  299. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  300. package/src/compat/register/typed-routes.ts +14 -14
  301. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  302. package/src/compat/register/validation.ts +18 -18
  303. package/src/compat/segment/loading-boundary.ts +43 -45
  304. package/src/compat/segment/page-slot.ts +69 -69
  305. package/src/compat/segment/serve.ts +1884 -0
  306. package/src/compat/segment/tree.ts +113 -112
  307. package/src/compat/segment/vary-key.ts +38 -38
  308. package/src/compat/segment/vary-params.ts +138 -142
  309. package/src/compat/static-params.ts +14 -12
  310. package/src/compat/tsconfig-defaults.ts +87 -91
  311. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  312. package/src/compat/typecheck/worker.ts +15 -12
  313. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  314. package/src/compat/typed-routes/manifest.ts +174 -170
  315. package/src/compat/typed-routes/typegen.ts +127 -110
  316. package/src/compat/validation/errors.ts +16 -19
  317. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  318. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  319. package/src/compat-bootstrap.ts +16 -16
  320. package/src/config.ts +69 -69
  321. package/src/css/build.ts +230 -227
  322. package/src/css/postcss.ts +79 -80
  323. package/src/css/worker.ts +14 -15
  324. package/src/dev/client-actions.ts +10 -10
  325. package/src/dev/client-chunk-store.ts +27 -27
  326. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  327. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  328. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  329. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  330. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  331. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  332. package/src/dev/server.ts +804 -820
  333. package/src/env.ts +46 -43
  334. package/src/extensions.ts +491 -478
  335. package/src/index.ts +8 -8
  336. package/src/internal.ts +20 -23
  337. package/src/{islands → render}/boundary-error.ts +3 -3
  338. package/src/render/hooks.ts +71 -71
  339. package/src/render/island-context.ts +14 -14
  340. package/src/render/metadata.ts +310 -310
  341. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  342. package/src/{ppr.ts → render/ppr.ts} +244 -245
  343. package/src/render/renderer.ts +2076 -2082
  344. package/src/render/resource-hints.ts +16 -17
  345. package/src/render/slots.tsx +224 -235
  346. package/src/{islands → render}/static-children.ts +9 -12
  347. package/src/{islands → render}/static-slots.ts +37 -37
  348. package/src/{cache/context.ts → request/cache.ts} +20 -20
  349. package/src/request/context.ts +107 -107
  350. package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +318 -296
  354. package/src/resolve/source-text.ts +37 -37
  355. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  356. package/src/routing/forwarded.ts +19 -19
  357. package/src/routing/handler.ts +84 -91
  358. package/src/routing/href.ts +69 -70
  359. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  360. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  361. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  362. package/src/routing/routes.ts +827 -815
  363. package/src/routing/slots.ts +164 -160
  364. package/src/runtime/loader.ts +952 -0
  365. package/src/{dev → runtime}/module-cache.ts +309 -287
  366. package/src/{dev → runtime}/module-generations.ts +9 -9
  367. package/src/{dev → runtime}/module-transform.ts +81 -72
  368. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  369. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  370. package/src/runtime/vendor.ts +425 -404
  371. package/src/styles.d.ts +9 -0
  372. package/src/types.ts +320 -335
  373. package/src/utils/ansi.ts +5 -5
  374. package/src/utils/{source.ts → code.ts} +15 -12
  375. package/src/utils/content-type.ts +3 -3
  376. package/src/utils/decode.ts +2 -2
  377. package/src/utils/dev-profile.ts +13 -13
  378. package/src/utils/error-log.ts +6 -6
  379. package/src/utils/esbuild.ts +18 -18
  380. package/src/utils/fs-cache.ts +13 -13
  381. package/src/utils/fs.ts +57 -49
  382. package/src/utils/html.ts +20 -24
  383. package/src/utils/native-require.ts +8 -8
  384. package/src/utils/serialize.ts +139 -146
  385. package/src/utils/verbose.ts +18 -18
  386. package/src/cli/analyze-print.ts +0 -181
  387. package/src/compat/middleware/manifest.ts +0 -210
  388. package/src/compat/next/image-client.tsx +0 -215
  389. package/src/compat/next/link-usage.ts +0 -29
  390. package/src/css/index.ts +0 -2
  391. package/src/render/index.ts +0 -1
  392. package/src/style-modules.d.ts +0 -9
@@ -0,0 +1,456 @@
1
+ // Pages-router API/data serving implementation (COMPAT - may import core freely): Node req/res
2
+ // shims plus the API-route and data-fetch (`/_next/data`) dispatch. Registered by
3
+ // ../register/pages-api.ts, which wires the exports below into the extension registries.
4
+
5
+ import { existsSync, readFileSync } from 'node:fs'
6
+ import { Writable } from 'node:stream'
7
+ import path from 'node:path'
8
+ import { devServerModuleHref } from '../../runtime/modules'
9
+ import { pagesApiBundleTargetForRuntime } from '../../runtime/loader'
10
+ import { getRequestExtensions, type RequestInterceptor } from '../../extensions'
11
+ import { getRequestRuntime } from '../../routing/request-environment'
12
+ import { selectRouteForRequest } from '../../routing/routes'
13
+ import { serverBundleTargetForRuntime } from '../../runtime/loader'
14
+ import { setWorkUnitRoute } from '../../request/context'
15
+ import { canonicalUrlHref } from '../next/canonical-url'
16
+ import { markPathRevalidated, normalizeRevalidatePath } from '../cache/revalidate'
17
+ import { withPagesApiHandlerSpan } from '../otel/tracer'
18
+ import { toNextRequest } from '../../api/server'
19
+
20
+ type PagesApiHandler = (req: unknown, res: PagesApiResponse) => Promise<unknown>
21
+
22
+ interface PagesApiModule {
23
+ default?: PagesApiHandler
24
+ }
25
+
26
+ interface PagesApiResponse {
27
+ statusCode: number
28
+ on(event: 'close' | 'error', listener: (...args: unknown[]) => void): PagesApiResponse
29
+ write(chunk: unknown, encoding?: BufferEncoding, callback?: () => void): boolean
30
+ setHeader(name: string, value: string | number | readonly string[]): PagesApiResponse
31
+ getHeader(name: string): string | null
32
+ status(code: number): PagesApiResponse
33
+ json(value: unknown): PagesApiResponse
34
+ send(value?: unknown): PagesApiResponse
35
+ end(value?: unknown): PagesApiResponse
36
+ revalidate(path: string): Promise<void>
37
+ }
38
+
39
+ const pageExtensions = ['ts', 'tsx', 'js', 'jsx', 'mjs', 'mts']
40
+
41
+ /** The preview-mode id written into prerender-manifest.json (see register/pages-api.ts). */
42
+ export const PREVIEW_MODE_ID = 'pnext-preview-id'
43
+
44
+ /**
45
+ * Pages-router data protocol (`/_next/data/<id>/<page>.json`, normalized to the page path by cli/start.ts
46
+ * with the `x-nextjs-data` marker): serve the page's data-fetch result as Next's data JSON -
47
+ * `{ pageProps }` from getServerSideProps/getStaticProps of the materialized pages route - instead of
48
+ * rendering HTML. When the request was rewritten, `x-nextjs-matched-path` reports the destination the
49
+ * data was served from, which the pages client router uses to resolve the rewrite.
50
+ */
51
+ export const pagesDataInterceptor: RequestInterceptor = async request => {
52
+ if (request.headers.get('x-nextjs-data') !== '1') return undefined
53
+ const method = request.method.toUpperCase()
54
+ if (method !== 'GET' && method !== 'HEAD') return undefined
55
+ const runtime = getRequestRuntime()
56
+ if (!runtime) return undefined
57
+ const url = new URL(request.url)
58
+ // Un-normalized data URLs (skipMiddlewareUrlNormalize without a middleware
59
+ // rewrite) never match a route here; header-only marker requests for
60
+ // document paths fall through to the HTML render.
61
+ if (url.pathname.startsWith('/_next/')) return undefined
62
+
63
+ const selection = selectRouteForRequest(runtime.routes, url.pathname)
64
+ if (selection?.route.kind !== 'page') {
65
+ return dataResponse({ notFound: true }, 404, url)
66
+ }
67
+ const route = selection.route
68
+ if (!isMaterializedPagesRoute(route.file)) return undefined
69
+
70
+ const module = (await import(
71
+ await devServerModuleHref(
72
+ runtime.config,
73
+ route.file,
74
+ runtime.dev ? (runtime.devImportVersion ?? 'dev') : 'build',
75
+ {
76
+ conditionTarget: serverBundleTargetForRuntime(route.segmentConfig?.runtime),
77
+ },
78
+ )
79
+ )) as PagesDataModule
80
+
81
+ setWorkUnitRoute('data', 'dynamic')
82
+ const params = selection.params ?? {}
83
+ const query = { ...Object.fromEntries(url.searchParams), ...params }
84
+ if (typeof module.getServerSideProps === 'function') {
85
+ const result = await module.getServerSideProps({
86
+ params,
87
+ query,
88
+ req: pagesDataRequestShim(request, url),
89
+ res: pagesDataResponseShim(),
90
+ resolvedUrl: `${url.pathname}${url.search}`,
91
+ preview: false,
92
+ previewData: undefined,
93
+ })
94
+ return pagesDataResult(result, url)
95
+ }
96
+ if (typeof module.getStaticProps === 'function') {
97
+ const result = await module.getStaticProps({ params })
98
+ return pagesDataResult(result, url, true)
99
+ }
100
+ return dataResponse({ pageProps: {} }, 200, url)
101
+ }
102
+
103
+ interface PagesDataFnResult {
104
+ props?: Record<string, unknown>
105
+ notFound?: boolean
106
+ redirect?: { destination: string; permanent?: boolean; statusCode?: number }
107
+ }
108
+
109
+ interface PagesDataModule {
110
+ getServerSideProps?: (
111
+ context: Record<string, unknown>,
112
+ ) => Promise<PagesDataFnResult> | PagesDataFnResult
113
+ getStaticProps?: (
114
+ context: Record<string, unknown>,
115
+ ) => Promise<PagesDataFnResult> | PagesDataFnResult
116
+ }
117
+
118
+ function pagesDataResult(result: PagesDataFnResult | undefined, url: URL, ssg = false): Response {
119
+ if (result?.notFound) return dataResponse({ notFound: true }, 404, url)
120
+ if (result?.redirect) {
121
+ const status = result.redirect.statusCode ?? (result.redirect.permanent ? 308 : 307)
122
+ return dataResponse(
123
+ {
124
+ pageProps: {
125
+ __N_REDIRECT: result.redirect.destination,
126
+ __N_REDIRECT_STATUS: status,
127
+ },
128
+ },
129
+ 200,
130
+ url,
131
+ )
132
+ }
133
+ return dataResponse(
134
+ { pageProps: result?.props ?? {}, ...(ssg ? { __N_SSG: true } : { __N_SSP: true }) },
135
+ 200,
136
+ url,
137
+ )
138
+ }
139
+
140
+ function dataResponse(body: Record<string, unknown>, status: number, url: URL): Response {
141
+ const headers = new Headers({ 'content-type': 'application/json; charset=utf-8' })
142
+ // A rewrite happened when the canonical (as-requested, post-normalization)
143
+ // pathname differs from the URL the route was matched on.
144
+ const canonical = canonicalUrlHref()
145
+ if (canonical && new URL(canonical).pathname !== url.pathname) {
146
+ headers.set('x-nextjs-matched-path', url.pathname)
147
+ }
148
+ return new Response(JSON.stringify(body), { status, headers })
149
+ }
150
+
151
+ // The materialized hybrid app hosts BOTH routers; only pages wrappers
152
+ // re-export from source-pages/, so sniff the (tiny, generated) wrapper body —
153
+ // app routes must never serve _next/data.
154
+ function isMaterializedPagesRoute(file: string): boolean {
155
+ if (!file.split(path.sep).join('/').includes('pnext-pages-compat/')) return false
156
+ try {
157
+ return readFileSync(file, 'utf8').includes('source-pages/')
158
+ } catch {
159
+ return false
160
+ }
161
+ }
162
+
163
+ function pagesDataRequestShim(request: Request, url: URL) {
164
+ return {
165
+ method: request.method,
166
+ url: `${url.pathname}${url.search}`,
167
+ headers: Object.fromEntries(request.headers),
168
+ cookies: cookiesFromHeader(request.headers.get('cookie')),
169
+ }
170
+ }
171
+
172
+ function pagesDataResponseShim() {
173
+ const headers = new Headers()
174
+ let statusCode = 200
175
+ return {
176
+ get statusCode() {
177
+ return statusCode
178
+ },
179
+ set statusCode(value: number) {
180
+ statusCode = value
181
+ },
182
+ setHeader(name: string, value: string | number | readonly string[]) {
183
+ headers.set(name, Array.isArray(value) ? value.join(', ') : String(value))
184
+ return this
185
+ },
186
+ getHeader(name: string) {
187
+ return headers.get(name)
188
+ },
189
+ removeHeader(name: string) {
190
+ headers.delete(name)
191
+ },
192
+ }
193
+ }
194
+
195
+ export const pagesApiInterceptor: RequestInterceptor = async (request, { config }) => {
196
+ const url = new URL(request.url)
197
+ const file = pagesApiFile(config.root, url.pathname)
198
+ if (!file) return undefined
199
+ const imported = (await import(
200
+ await devServerModuleHref(config, file, 'build', {
201
+ conditionTarget: pagesApiBundleTargetForRuntime(apiRuntime(file)),
202
+ })
203
+ )) as PagesApiModule
204
+ if (typeof imported.default !== 'function') return undefined
205
+
206
+ const responder = createPagesApiResponse(request)
207
+ // Edge-runtime pages API handlers receive the real NextRequest (signal,
208
+ // nextUrl, text() — Request prototype getters a spread would lose); node
209
+ // handlers get the IncomingMessage-shaped shim.
210
+ const handlerRequest =
211
+ apiRuntime(file) === 'edge' ? toNextRequest(request) : createPagesApiRequest(request, url)
212
+ const finished = withPagesApiHandlerSpan(url.pathname, () =>
213
+ Promise.resolve(imported.default!(handlerRequest, responder.res)),
214
+ ).catch(error => responder.fail(error))
215
+ // A handler that starts writing (res.write / pipeline) streams: the response returns at the first write
216
+ // and the body flows through until end or disconnect - a client disconnect destroys `res`, surfacing as
217
+ // its 'close' event, which is Node pages-API cancellation semantics. A handler that only buffers
218
+ // resolves on completion exactly as before.
219
+ const outcome = await Promise.race([responder.started.then(() => STREAM_STARTED), finished])
220
+ if (outcome !== STREAM_STARTED) {
221
+ if (outcome instanceof Response) return outcome
222
+ return responder.response(outcome)
223
+ }
224
+ return responder.streamResponse()
225
+ }
226
+
227
+ const STREAM_STARTED = Symbol('pnext.pagesApiStreamStarted')
228
+
229
+ function pagesApiFile(root: string, pathname: string): string | undefined {
230
+ if (pathname !== '/api' && !pathname.startsWith('/api/')) return undefined
231
+ let relative: string
232
+ try {
233
+ relative = decodeURIComponent(pathname === '/api' ? 'index' : pathname.slice('/api/'.length))
234
+ } catch {
235
+ return undefined
236
+ }
237
+ const baseDir = path.join(root, 'pages', 'api')
238
+ const base = path.resolve(baseDir, relative)
239
+ if (base !== baseDir && !base.startsWith(`${baseDir}${path.sep}`)) return undefined
240
+ for (const ext of pageExtensions) {
241
+ const file = `${base}.${ext}`
242
+ if (existsSync(file)) return file
243
+ const index = path.join(base, `index.${ext}`)
244
+ if (existsSync(index)) return index
245
+ }
246
+ return undefined
247
+ }
248
+
249
+ function apiRuntime(file: string): string | undefined {
250
+ return /\bruntime\b\s*[:=]\s*(['"`])(?:edge|experimental-edge)\1/.test(readFileSync(file, 'utf8'))
251
+ ? 'edge'
252
+ : undefined
253
+ }
254
+
255
+ function createPagesApiRequest(request: Request, url: URL) {
256
+ const nextRequest = toNextRequest(request)
257
+ return {
258
+ ...nextRequest,
259
+ method: request.method,
260
+ url: `${url.pathname}${url.search}`,
261
+ headers: Object.fromEntries(request.headers),
262
+ query: Object.fromEntries(url.searchParams),
263
+ cookies: cookiesFromHeader(request.headers.get('cookie')),
264
+ nextUrl: nextRequest.nextUrl,
265
+ text() {
266
+ return request.text()
267
+ },
268
+ json() {
269
+ return request.json()
270
+ },
271
+ }
272
+ }
273
+
274
+ function createPagesApiResponse(request: Request) {
275
+ const headers = new Headers()
276
+ let statusCode = 200
277
+ let sent = false
278
+ let body: BodyInit | null = null
279
+ let started = false
280
+ let notifyStarted: () => void = () => undefined
281
+ const startedPromise = new Promise<void>(resolve => {
282
+ notifyStarted = resolve
283
+ })
284
+
285
+ let controller: ReadableStreamDefaultController<Uint8Array> | undefined
286
+ const streamBody = new ReadableStream<Uint8Array>({
287
+ start(c) {
288
+ controller = c
289
+ },
290
+ // The client disconnected mid-stream: destroy the res so the handler
291
+ // observes it as the response closing (Node pages-API semantics —
292
+ // `res.on('close', ...)` aborts its inner stream).
293
+ cancel() {
294
+ writable.destroy()
295
+ },
296
+ })
297
+ const start = () => {
298
+ if (!started) {
299
+ started = true
300
+ notifyStarted()
301
+ }
302
+ }
303
+ const enqueue = (chunk: unknown) => {
304
+ const value = normalizeWriteChunk(chunk)
305
+ if (value === '') return
306
+ try {
307
+ controller?.enqueue(
308
+ typeof value === 'string' ? new TextEncoder().encode(value) : new Uint8Array(value),
309
+ )
310
+ } catch {
311
+ // Stream already closed/cancelled — drop the late chunk.
312
+ }
313
+ }
314
+ // A REAL Writable: `stream.pipeline(source, res)` and event listeners need a
315
+ // genuine EventEmitter/stream destination, not a duck-typed object.
316
+ const writable = new Writable({
317
+ write(chunk, _encoding, callback) {
318
+ start()
319
+ enqueue(chunk)
320
+ callback()
321
+ },
322
+ final(callback) {
323
+ // Only a stream that actually wrote flags the streaming path: a plain
324
+ // res.end(value) is a BUFFERED response (its body rides `body`, not the
325
+ // stream) and must resolve through the handler-completion race.
326
+ try {
327
+ controller?.close()
328
+ } catch {
329
+ // Already closed.
330
+ }
331
+ callback()
332
+ },
333
+ destroy(error, callback) {
334
+ try {
335
+ controller?.close()
336
+ } catch {
337
+ // Already closed.
338
+ }
339
+ callback(error ?? null)
340
+ },
341
+ })
342
+ request.signal?.addEventListener?.('abort', () => writable.destroy(), { once: true })
343
+
344
+ const api = {
345
+ setHeader(name: string, value: string | number | readonly string[]) {
346
+ headers.set(name, Array.isArray(value) ? value.join(', ') : String(value))
347
+ return res
348
+ },
349
+ getHeader(name: string) {
350
+ return headers.get(name)
351
+ },
352
+ removeHeader(name: string) {
353
+ headers.delete(name)
354
+ },
355
+ status(code: number) {
356
+ statusCode = code
357
+ return res
358
+ },
359
+ json(value: unknown) {
360
+ if (!headers.has('content-type'))
361
+ headers.set('content-type', 'application/json; charset=utf-8')
362
+ body = JSON.stringify(value)
363
+ sent = true
364
+ return res
365
+ },
366
+ send(value?: unknown) {
367
+ body = bodyFromValue(value, headers)
368
+ sent = true
369
+ return res
370
+ },
371
+ end(value?: unknown) {
372
+ if (!sent) {
373
+ body = bodyFromValue(value, headers)
374
+ sent = true
375
+ }
376
+ if (value !== undefined && value !== null && started) {
377
+ // Mid-stream end(chunk): flush the tail through the stream.
378
+ enqueue(value)
379
+ }
380
+ ;(Writable.prototype.end as (this: Writable) => Writable).call(writable)
381
+ return res
382
+ },
383
+ async revalidate(pathname: string) {
384
+ markPathRevalidated(pathname)
385
+ await getRequestExtensions().onDemandRevalidatePath(normalizeRevalidatePath(pathname))
386
+ },
387
+ }
388
+ const res = Object.assign(writable, api) as unknown as PagesApiResponse
389
+ Object.defineProperty(res, 'statusCode', {
390
+ get: () => statusCode,
391
+ set: (value: number) => {
392
+ statusCode = value
393
+ },
394
+ })
395
+
396
+ return {
397
+ res,
398
+ started: startedPromise,
399
+ fail(error: unknown): never | undefined {
400
+ if (!started) throw error
401
+ try {
402
+ controller?.error(error)
403
+ } catch {
404
+ // Stream already settled.
405
+ }
406
+ return undefined
407
+ },
408
+ streamResponse() {
409
+ // Null-body statuses (204/304) must not carry a body stream.
410
+ if (statusCode === 204 || statusCode === 304) {
411
+ return new Response(null, { status: statusCode, headers })
412
+ }
413
+ return new Response(streamBody, { status: statusCode, headers })
414
+ },
415
+ response(result: unknown) {
416
+ if (result !== undefined && !sent) body = bodyFromValue(result, headers)
417
+ return new Response(statusCode === 204 || statusCode === 304 ? null : body, {
418
+ status: statusCode,
419
+ headers,
420
+ })
421
+ },
422
+ }
423
+ }
424
+
425
+ function normalizeWriteChunk(chunk: unknown) {
426
+ if (chunk === null || chunk === undefined) return ''
427
+ if (typeof chunk === 'string') return chunk
428
+ if (chunk instanceof ArrayBuffer) return Buffer.from(chunk)
429
+ if (ArrayBuffer.isView(chunk))
430
+ return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)
431
+ if (typeof chunk === 'number' || typeof chunk === 'boolean' || typeof chunk === 'bigint') {
432
+ return String(chunk)
433
+ }
434
+ return JSON.stringify(chunk) ?? ''
435
+ }
436
+
437
+ function bodyFromValue(value: unknown, headers: Headers): BodyInit | null {
438
+ if (value === undefined || value === null) return null
439
+ if (typeof value === 'string' || value instanceof Blob || value instanceof ArrayBuffer)
440
+ return value
441
+ if (value instanceof Uint8Array && value.buffer instanceof ArrayBuffer) {
442
+ return value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength)
443
+ }
444
+ if (!headers.has('content-type')) headers.set('content-type', 'application/json; charset=utf-8')
445
+ return JSON.stringify(value)
446
+ }
447
+
448
+ function cookiesFromHeader(header: string | null): Record<string, string> {
449
+ if (!header) return {}
450
+ return Object.fromEntries(
451
+ header
452
+ .split(';')
453
+ .map(part => part.trim().split('='))
454
+ .filter((parts): parts is [string, string] => parts.length === 2 && parts[0] !== ''),
455
+ )
456
+ }
@@ -1,56 +1,56 @@
1
- import { existsSync } from 'node:fs';
2
- import { readFile } from 'node:fs/promises';
3
- import path from 'node:path';
4
- import type { Loader, OnLoadResult, Plugin } from 'esbuild';
5
- import { build as esbuild } from '../../utils/esbuild';
6
- import type { ResolvedConfig } from '../../config';
7
- import { applyClientSourceTransforms, getBundlerExtensions } from '../../extensions';
1
+ import { existsSync } from 'node:fs'
2
+ import { readFile } from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import type { Loader, OnLoadResult, Plugin } from 'esbuild'
5
+ import { build as esbuild } from '../../utils/esbuild'
6
+ import type { ResolvedConfig } from '../../config'
7
+ import { applyClientSourceTransforms, getBundlerExtensions } from '../../extensions'
8
8
 
9
- const pageClientFacade = 'pnext-page-client.js';
10
- const sideEffectImportPattern = /(?:^|\n)\s*import\s*(['"])([^'"]+)\1\s*;?/g;
11
- const styleImportPattern = /\.(?:css|scss|sass|less|styl)(?:\?|$)/;
9
+ const pageClientFacade = 'pnext-page-client.js'
10
+ const sideEffectImportPattern = /(?:^|\n)\s*import\s*(['"])([^'"]+)\1\s*;?/g
11
+ const styleImportPattern = /\.(?:css|scss|sass|less|styl)(?:\?|$)/
12
12
 
13
13
  /**
14
14
  * Compile generated Pages facades from only the page component export. The relative-import hook is
15
15
  * a catch-all that only ever fires from a facade, so an app with no `pages/` dir skips it.
16
16
  */
17
17
  export function pagesClientModulePlugin(config: ResolvedConfig): Plugin {
18
- const compiled = new Map<string, Promise<OnLoadResult>>();
19
- const hasPages = existsSync(path.join(config.root, 'pages'));
18
+ const compiled = new Map<string, Promise<OnLoadResult>>()
19
+ const hasPages = existsSync(path.join(config.root, 'pages'))
20
20
  return {
21
21
  name: 'pnext-pages-client-module',
22
22
  setup(build) {
23
- if (!hasPages) return;
23
+ if (!hasPages) return
24
24
  build.onResolve({ filter: /^\.{1,2}\// }, args => {
25
- if (path.basename(args.importer) !== pageClientFacade) return undefined;
25
+ if (path.basename(args.importer) !== pageClientFacade) return undefined
26
26
  return {
27
27
  path: path.resolve(args.resolveDir, args.path),
28
28
  namespace: 'pnext-pages-client-module',
29
- };
30
- });
29
+ }
30
+ })
31
31
  build.onLoad({ filter: /.*/, namespace: 'pnext-pages-client-module' }, args => {
32
- let output = compiled.get(args.path);
32
+ let output = compiled.get(args.path)
33
33
  if (!output) {
34
- output = compilePageClientModule(config, args.path);
35
- compiled.set(args.path, output);
34
+ output = compilePageClientModule(config, args.path)
35
+ compiled.set(args.path, output)
36
36
  }
37
- return output;
38
- });
37
+ return output
38
+ })
39
39
  },
40
- };
40
+ }
41
41
  }
42
42
 
43
43
  async function compilePageClientModule(
44
44
  config: ResolvedConfig,
45
45
  file: string,
46
46
  ): Promise<OnLoadResult> {
47
- const rawSource = await readFile(file, 'utf8');
48
- const source = applyClientSourceTransforms(rawSource, file, config.root);
47
+ const rawSource = await readFile(file, 'utf8')
48
+ const source = applyClientSourceTransforms(rawSource, file, config.root)
49
49
  const sideEffectImports = new Set(
50
50
  [...source.matchAll(sideEffectImportPattern)]
51
51
  .map(match => match[2])
52
52
  .filter((specifier): specifier is string => Boolean(specifier)),
53
- );
53
+ )
54
54
  const result = await esbuild({
55
55
  stdin: {
56
56
  contents: `export { default } from ${JSON.stringify(file)};`,
@@ -76,34 +76,34 @@ async function compilePageClientModule(
76
76
  setup(build) {
77
77
  build.onResolve({ filter: /.*/ }, args => {
78
78
  if (args.path === file) {
79
- return { path: file, namespace: 'pnext-pages-client-source' };
79
+ return { path: file, namespace: 'pnext-pages-client-source' }
80
80
  }
81
81
  return {
82
82
  path: args.path,
83
83
  external: true,
84
84
  sideEffects: sideEffectImports.has(args.path) || styleImportPattern.test(args.path),
85
- };
86
- });
85
+ }
86
+ })
87
87
  build.onLoad({ filter: /.*/, namespace: 'pnext-pages-client-source' }, () => ({
88
88
  contents: source,
89
89
  loader: pageLoader(file),
90
90
  resolveDir: path.dirname(file),
91
- }));
91
+ }))
92
92
  },
93
93
  },
94
94
  ],
95
- });
96
- const output = result.outputFiles[0];
97
- if (!output) throw new Error(`Failed to compile Pages client module ${file}`);
95
+ })
96
+ const output = result.outputFiles[0]
97
+ if (!output) throw new Error(`Failed to compile Pages client module ${file}`)
98
98
  return {
99
99
  contents: output.text,
100
100
  loader: 'js',
101
101
  resolveDir: path.dirname(file),
102
- };
102
+ }
103
103
  }
104
104
 
105
105
  function pageLoader(file: string): Loader {
106
- if (file.endsWith('.tsx')) return 'tsx';
107
- if (file.endsWith('.ts')) return 'ts';
108
- return 'jsx';
106
+ if (file.endsWith('.tsx')) return 'tsx'
107
+ if (file.endsWith('.ts')) return 'ts'
108
+ return 'jsx'
109
109
  }