@wular/pnext 0.0.1

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 (371) hide show
  1. package/README.md +153 -0
  2. package/bin/pnext +67 -0
  3. package/config/lint/base.js +48 -0
  4. package/config/ts/base.json +26 -0
  5. package/config/ts/react.json +13 -0
  6. package/package.json +70 -0
  7. package/reference/compat.md +63 -0
  8. package/reference/config.md +120 -0
  9. package/reference/css.md +58 -0
  10. package/reference/dev.md +69 -0
  11. package/reference/env.md +40 -0
  12. package/reference/metadata.md +86 -0
  13. package/reference/navigation.md +149 -0
  14. package/reference/overview.md +35 -0
  15. package/reference/performance.md +97 -0
  16. package/reference/rendering.md +127 -0
  17. package/reference/routing.md +167 -0
  18. package/reference/typegen.md +64 -0
  19. package/src/api/cache.ts +80 -0
  20. package/src/api/client-cache.ts +9 -0
  21. package/src/api/client-navigation.ts +279 -0
  22. package/src/api/dynamic.tsx +102 -0
  23. package/src/api/link.tsx +119 -0
  24. package/src/api/navigation.ts +198 -0
  25. package/src/api/router/events.ts +53 -0
  26. package/src/api/router/history.ts +70 -0
  27. package/src/api/router/hub.ts +194 -0
  28. package/src/api/router/policies.ts +107 -0
  29. package/src/api/router/runtime.ts +5238 -0
  30. package/src/api/router/types.ts +299 -0
  31. package/src/api/router.ts +167 -0
  32. package/src/api/server.ts +323 -0
  33. package/src/api/suspense.ts +16 -0
  34. package/src/cache/context.ts +61 -0
  35. package/src/cli/adapters/vercel-warm.ts +375 -0
  36. package/src/cli/adapters/vercel.ts +1310 -0
  37. package/src/cli/analyze-print.ts +181 -0
  38. package/src/cli/analyze.ts +328 -0
  39. package/src/cli/boot-trace.ts +29 -0
  40. package/src/cli/build.ts +3114 -0
  41. package/src/cli/dev.ts +276 -0
  42. package/src/cli/index.ts +196 -0
  43. package/src/cli/named-bin.ts +119 -0
  44. package/src/cli/serve-ui.ts +160 -0
  45. package/src/cli/start.ts +1425 -0
  46. package/src/client/build.ts +2136 -0
  47. package/src/client/chunk-fold.ts +526 -0
  48. package/src/client/entry.ts +1525 -0
  49. package/src/client/paths.ts +22 -0
  50. package/src/client/prebuilt.ts +621 -0
  51. package/src/client/profile.ts +75 -0
  52. package/src/client/react-compiler.ts +94 -0
  53. package/src/client/reference-stub.ts +145 -0
  54. package/src/client/reference.ts +47 -0
  55. package/src/compat/actions/action-client.ts +531 -0
  56. package/src/compat/actions/action-dispatch.ts +676 -0
  57. package/src/compat/actions/action-router.ts +40 -0
  58. package/src/compat/actions/action-shared.ts +95 -0
  59. package/src/compat/actions/client-plugin.ts +135 -0
  60. package/src/compat/actions/client-stub.ts +65 -0
  61. package/src/compat/actions/config.ts +164 -0
  62. package/src/compat/actions/detect.ts +208 -0
  63. package/src/compat/actions/discovery.ts +244 -0
  64. package/src/compat/actions/early-submit.ts +40 -0
  65. package/src/compat/actions/endpoint.ts +602 -0
  66. package/src/compat/actions/flight.ts +52 -0
  67. package/src/compat/actions/form-state.ts +73 -0
  68. package/src/compat/actions/hoist.ts +485 -0
  69. package/src/compat/actions/ids.ts +39 -0
  70. package/src/compat/actions/index.ts +41 -0
  71. package/src/compat/actions/instances.ts +144 -0
  72. package/src/compat/actions/origin.ts +109 -0
  73. package/src/compat/actions/protocol.ts +125 -0
  74. package/src/compat/actions/registry.ts +74 -0
  75. package/src/compat/actions/rewrite.ts +282 -0
  76. package/src/compat/actions/serve.ts +414 -0
  77. package/src/compat/actions/server-tag.ts +21 -0
  78. package/src/compat/actions/unrecognized-error.ts +30 -0
  79. package/src/compat/adapter/build-complete.ts +257 -0
  80. package/src/compat/bundler/bun-externals.ts +53 -0
  81. package/src/compat/bundler/cjs-exports.ts +542 -0
  82. package/src/compat/bundler/config.ts +363 -0
  83. package/src/compat/bundler/externals.ts +34 -0
  84. package/src/compat/bundler/import-meta-url.ts +60 -0
  85. package/src/compat/bundler/modularize-imports.ts +119 -0
  86. package/src/compat/bundler/new-url-asset.ts +87 -0
  87. package/src/compat/bundler/optimize-package-imports.ts +273 -0
  88. package/src/compat/bundler/polyfill.ts +88 -0
  89. package/src/compat/bundler/react-compiler.ts +61 -0
  90. package/src/compat/bundler/react-profiler.tsx +25 -0
  91. package/src/compat/bundler/relay-transform.ts +116 -0
  92. package/src/compat/bundler/require-context.ts +281 -0
  93. package/src/compat/bundler/resolve-extensions.ts +75 -0
  94. package/src/compat/bundler/source-cache.ts +61 -0
  95. package/src/compat/bundler/static-imports.ts +25 -0
  96. package/src/compat/bundler/symlink-imports.ts +119 -0
  97. package/src/compat/bundler/tsconfig-paths.ts +50 -0
  98. package/src/compat/bundler/wasm.ts +153 -0
  99. package/src/compat/bundler/webpack-loaders.ts +685 -0
  100. package/src/compat/bundler/worker.ts +278 -0
  101. package/src/compat/cache/build-flags.ts +81 -0
  102. package/src/compat/cache/build-prerender-errors.ts +163 -0
  103. package/src/compat/cache/custom-handler.ts +159 -0
  104. package/src/compat/cache/fetch-patch.ts +745 -0
  105. package/src/compat/cache/handler.ts +100 -0
  106. package/src/compat/cache/modern-handler.ts +275 -0
  107. package/src/compat/cache/resume-data-cache.ts +143 -0
  108. package/src/compat/cache/revalidate.ts +759 -0
  109. package/src/compat/cache/runtime-error.ts +124 -0
  110. package/src/compat/cache/use-cache-transform.ts +961 -0
  111. package/src/compat/cache/use-cache.ts +1695 -0
  112. package/src/compat/cache-control.ts +269 -0
  113. package/src/compat/client/base-path.ts +64 -0
  114. package/src/compat/client/css-order.ts +36 -0
  115. package/src/compat/client/errors/control-flow.ts +92 -0
  116. package/src/compat/client/errors/error-boundary.ts +222 -0
  117. package/src/compat/client/errors/global-error.ts +238 -0
  118. package/src/compat/client/errors/install.ts +217 -0
  119. package/src/compat/client/errors/lazy.ts +53 -0
  120. package/src/compat/client/errors/primitive-throw.ts +126 -0
  121. package/src/compat/client/errors/soft-refresh.ts +14 -0
  122. package/src/compat/client/link-status.ts +86 -0
  123. package/src/compat/client/nav-compat-runtime.ts +57 -0
  124. package/src/compat/client/nav-compat.ts +42 -0
  125. package/src/compat/client/navigation-scroll.ts +154 -0
  126. package/src/compat/client/optimistic-routing.ts +206 -0
  127. package/src/compat/client/prefetch-cache.ts +111 -0
  128. package/src/compat/client/route-announcer.ts +72 -0
  129. package/src/compat/client/segment-cache-policy.ts +159 -0
  130. package/src/compat/client/segment-cache.ts +1077 -0
  131. package/src/compat/client/segment-prefetch.ts +375 -0
  132. package/src/compat/client/trailing-slash.ts +24 -0
  133. package/src/compat/css/chunking.ts +254 -0
  134. package/src/compat/css/inline-css.ts +73 -0
  135. package/src/compat/css/lightningcss.ts +90 -0
  136. package/src/compat/css/modules.ts +373 -0
  137. package/src/compat/css/nonce.ts +30 -0
  138. package/src/compat/css/sass-plugin.ts +65 -0
  139. package/src/compat/css/sass.ts +392 -0
  140. package/src/compat/css/styled-jsx-runtime.ts +80 -0
  141. package/src/compat/css/styled-jsx.ts +49 -0
  142. package/src/compat/edge-runtime.ts +71 -0
  143. package/src/compat/export/client.ts +112 -0
  144. package/src/compat/export/index.ts +272 -0
  145. package/src/compat/export/standalone.ts +207 -0
  146. package/src/compat/image-optimizer/cache.ts +119 -0
  147. package/src/compat/image-optimizer/detect.ts +143 -0
  148. package/src/compat/image-optimizer/index.ts +601 -0
  149. package/src/compat/image-optimizer/source.ts +243 -0
  150. package/src/compat/index.ts +458 -0
  151. package/src/compat/lifecycle/after-scope.ts +86 -0
  152. package/src/compat/lifecycle/after.ts +173 -0
  153. package/src/compat/lifecycle/error-funnel.ts +306 -0
  154. package/src/compat/lifecycle/error-serialize.ts +87 -0
  155. package/src/compat/lifecycle/error-ui.ts +167 -0
  156. package/src/compat/lifecycle/instrumentation-client.ts +138 -0
  157. package/src/compat/lifecycle/instrumentation.ts +277 -0
  158. package/src/compat/lifecycle/node-console.ts +19 -0
  159. package/src/compat/lifecycle/testmode.ts +263 -0
  160. package/src/compat/mdx/compile.ts +219 -0
  161. package/src/compat/mdx/next-mdx-stub.ts +46 -0
  162. package/src/compat/mdx/plugin.ts +37 -0
  163. package/src/compat/metadata-route-artifacts.ts +458 -0
  164. package/src/compat/metadata.ts +295 -0
  165. package/src/compat/middleware/manifest.ts +210 -0
  166. package/src/compat/misc/action-return.ts +173 -0
  167. package/src/compat/next/cache.ts +211 -0
  168. package/src/compat/next/canonical-url.ts +35 -0
  169. package/src/compat/next/client-cache.ts +57 -0
  170. package/src/compat/next/client-navigation.ts +313 -0
  171. package/src/compat/next/client-only.ts +3 -0
  172. package/src/compat/next/client-script.tsx +215 -0
  173. package/src/compat/next/client-server.ts +39 -0
  174. package/src/compat/next/config-loader.ts +569 -0
  175. package/src/compat/next/config.ts +29 -0
  176. package/src/compat/next/constants.cjs +6 -0
  177. package/src/compat/next/constants.ts +6 -0
  178. package/src/compat/next/custom-server.ts +236 -0
  179. package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
  180. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
  181. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
  182. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
  183. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
  184. package/src/compat/next/dynamic.tsx +46 -0
  185. package/src/compat/next/error.tsx +148 -0
  186. package/src/compat/next/font/cache.ts +171 -0
  187. package/src/compat/next/font/google.ts +2 -0
  188. package/src/compat/next/font/index.ts +8 -0
  189. package/src/compat/next/font/local.ts +5 -0
  190. package/src/compat/next/font/runtime-client.ts +71 -0
  191. package/src/compat/next/font/runtime.ts +974 -0
  192. package/src/compat/next/font/shared.ts +281 -0
  193. package/src/compat/next/form.tsx +156 -0
  194. package/src/compat/next/head.tsx +10 -0
  195. package/src/compat/next/headers.ts +247 -0
  196. package/src/compat/next/image/config.ts +196 -0
  197. package/src/compat/next/image/optimizer.ts +96 -0
  198. package/src/compat/next/image/patterns.ts +103 -0
  199. package/src/compat/next/image/shared.ts +141 -0
  200. package/src/compat/next/image/static-metadata.ts +283 -0
  201. package/src/compat/next/image/validate.ts +269 -0
  202. package/src/compat/next/image-client.tsx +215 -0
  203. package/src/compat/next/image-props.ts +575 -0
  204. package/src/compat/next/image-usage.ts +102 -0
  205. package/src/compat/next/image.tsx +56 -0
  206. package/src/compat/next/index.ts +1 -0
  207. package/src/compat/next/legacy-image.tsx +97 -0
  208. package/src/compat/next/link-usage.ts +29 -0
  209. package/src/compat/next/link-validation-transform.ts +200 -0
  210. package/src/compat/next/link.tsx +466 -0
  211. package/src/compat/next/navigation.cjs +21 -0
  212. package/src/compat/next/navigation.ts +188 -0
  213. package/src/compat/next/offline.ts +51 -0
  214. package/src/compat/next/og.ts +324 -0
  215. package/src/compat/next/optimistic-route-state.ts +188 -0
  216. package/src/compat/next/preferred-region.ts +39 -0
  217. package/src/compat/next/redirects.ts +131 -0
  218. package/src/compat/next/resource-hints.ts +136 -0
  219. package/src/compat/next/rewrites.ts +350 -0
  220. package/src/compat/next/root-params.ts +142 -0
  221. package/src/compat/next/router.cjs +49 -0
  222. package/src/compat/next/router.ts +143 -0
  223. package/src/compat/next/script.tsx +355 -0
  224. package/src/compat/next/server-only.ts +3 -0
  225. package/src/compat/next/server.ts +28 -0
  226. package/src/compat/next/svgr.ts +58 -0
  227. package/src/compat/next/telemetry.ts +77 -0
  228. package/src/compat/next/user-agent.ts +100 -0
  229. package/src/compat/next/web-vitals.ts +56 -0
  230. package/src/compat/otel/api.ts +95 -0
  231. package/src/compat/otel/client-trace-metadata.ts +71 -0
  232. package/src/compat/otel/fetch-span.ts +77 -0
  233. package/src/compat/otel/tracer.ts +944 -0
  234. package/src/compat/pages/client-plugin.ts +108 -0
  235. package/src/compat/pages/index.ts +527 -0
  236. package/src/compat/pages/router-state.ts +94 -0
  237. package/src/compat/ppr/io.ts +38 -0
  238. package/src/compat/ppr/missing-root-params.ts +105 -0
  239. package/src/compat/ppr/root-params-scan.ts +164 -0
  240. package/src/compat/ppr/root-params-transform.ts +75 -0
  241. package/src/compat/ppr/root-params.ts +129 -0
  242. package/src/compat/ppr/segment-config-incompat.ts +34 -0
  243. package/src/compat/protocol.ts +202 -0
  244. package/src/compat/react/client.ts +59 -0
  245. package/src/compat/react/compiler-runtime.ts +60 -0
  246. package/src/compat/react/dom-client.ts +115 -0
  247. package/src/compat/react/dom-react-server.ts +20 -0
  248. package/src/compat/react/dom-server.ts +40 -0
  249. package/src/compat/react/dom.ts +154 -0
  250. package/src/compat/react/preact.ts +522 -0
  251. package/src/compat/react/react-server.ts +84 -0
  252. package/src/compat/react/router-shim.ts +26 -0
  253. package/src/compat/react/server-component-use.ts +48 -0
  254. package/src/compat/react/server-inserted-html.ts +87 -0
  255. package/src/compat/react/server.ts +156 -0
  256. package/src/compat/react/view-transition.ts +60 -0
  257. package/src/compat/register/actions.ts +875 -0
  258. package/src/compat/register/boot.ts +141 -0
  259. package/src/compat/register/build-tier.ts +11 -0
  260. package/src/compat/register/build.ts +182 -0
  261. package/src/compat/register/bundler.ts +587 -0
  262. package/src/compat/register/cache.ts +85 -0
  263. package/src/compat/register/client-errors.ts +18 -0
  264. package/src/compat/register/config.ts +17 -0
  265. package/src/compat/register/css-extras.ts +120 -0
  266. package/src/compat/register/edge-runtime.ts +6 -0
  267. package/src/compat/register/errors.ts +46 -0
  268. package/src/compat/register/export.ts +23 -0
  269. package/src/compat/register/font.ts +36 -0
  270. package/src/compat/register/hooks.ts +34 -0
  271. package/src/compat/register/image.ts +133 -0
  272. package/src/compat/register/index.ts +111 -0
  273. package/src/compat/register/instrumentation-client.ts +35 -0
  274. package/src/compat/register/lifecycle.ts +86 -0
  275. package/src/compat/register/mdx.ts +48 -0
  276. package/src/compat/register/middleware.ts +36 -0
  277. package/src/compat/register/misc.ts +44 -0
  278. package/src/compat/register/otel.ts +288 -0
  279. package/src/compat/register/pages-api.ts +473 -0
  280. package/src/compat/register/ppr.ts +56 -0
  281. package/src/compat/register/protocol.ts +57 -0
  282. package/src/compat/register/proxy.ts +127 -0
  283. package/src/compat/register/render.ts +268 -0
  284. package/src/compat/register/routing.ts +410 -0
  285. package/src/compat/register/segment.ts +1903 -0
  286. package/src/compat/register/static-image.ts +21 -0
  287. package/src/compat/register/typed-routes.ts +35 -0
  288. package/src/compat/register/usecache.ts +131 -0
  289. package/src/compat/register/validation.ts +56 -0
  290. package/src/compat/segment/loading-boundary.ts +113 -0
  291. package/src/compat/segment/page-slot.ts +200 -0
  292. package/src/compat/segment/tree.ts +481 -0
  293. package/src/compat/segment/vary-key.ts +102 -0
  294. package/src/compat/segment/vary-params.ts +551 -0
  295. package/src/compat/static-params.ts +33 -0
  296. package/src/compat/tsconfig-defaults.ts +301 -0
  297. package/src/compat/typecheck/index.ts +1481 -0
  298. package/src/compat/typecheck/worker.ts +26 -0
  299. package/src/compat/typed-routes/index.ts +92 -0
  300. package/src/compat/typed-routes/manifest.ts +356 -0
  301. package/src/compat/typed-routes/typegen.ts +566 -0
  302. package/src/compat/validation/errors.ts +159 -0
  303. package/src/compat/validation/index.ts +1770 -0
  304. package/src/compat/validation/prerender-diagnostics.ts +1508 -0
  305. package/src/compat-bootstrap.ts +67 -0
  306. package/src/config.ts +218 -0
  307. package/src/css/build.ts +697 -0
  308. package/src/css/index.ts +2 -0
  309. package/src/css/postcss.ts +236 -0
  310. package/src/css/worker.ts +34 -0
  311. package/src/dev/client-actions.ts +35 -0
  312. package/src/dev/client-chunk-store.ts +92 -0
  313. package/src/dev/client-key-cache.ts +178 -0
  314. package/src/dev/global-css-cache.ts +212 -0
  315. package/src/dev/imports.ts +2430 -0
  316. package/src/dev/module-cache.ts +721 -0
  317. package/src/dev/module-generations.ts +38 -0
  318. package/src/dev/module-transform.ts +188 -0
  319. package/src/dev/node-module-bundle-cache.ts +63 -0
  320. package/src/dev/restart-cache.ts +10 -0
  321. package/src/dev/route-bundle-key-cache.ts +154 -0
  322. package/src/dev/route-facts-cache.ts +223 -0
  323. package/src/dev/server.ts +1710 -0
  324. package/src/dynamic/source.ts +307 -0
  325. package/src/dynamic/tree-shake.ts +262 -0
  326. package/src/env.ts +92 -0
  327. package/src/extensions.ts +1898 -0
  328. package/src/index.ts +34 -0
  329. package/src/internal.ts +43 -0
  330. package/src/islands/boundary-error.ts +8 -0
  331. package/src/islands/static-children.ts +37 -0
  332. package/src/islands/static-slots.ts +106 -0
  333. package/src/ppr-postpone.ts +24 -0
  334. package/src/ppr.ts +784 -0
  335. package/src/proxy.ts +752 -0
  336. package/src/render/hooks.ts +384 -0
  337. package/src/render/index.ts +1 -0
  338. package/src/render/island-context.ts +47 -0
  339. package/src/render/metadata.ts +857 -0
  340. package/src/render/renderer.ts +7391 -0
  341. package/src/render/resource-hints.ts +44 -0
  342. package/src/render/slots.tsx +679 -0
  343. package/src/request/context.ts +396 -0
  344. package/src/resolve/engine.ts +219 -0
  345. package/src/resolve/imports.ts +1104 -0
  346. package/src/resolve/scan-facts.ts +474 -0
  347. package/src/resolve/source-text.ts +86 -0
  348. package/src/routing/forwarded.ts +41 -0
  349. package/src/routing/handler.ts +271 -0
  350. package/src/routing/href.ts +203 -0
  351. package/src/routing/metadata.ts +1018 -0
  352. package/src/routing/request-runtime.ts +43 -0
  353. package/src/routing/routes.ts +2560 -0
  354. package/src/routing/slots.ts +432 -0
  355. package/src/runtime/server.ts +3453 -0
  356. package/src/runtime/vendor.ts +1160 -0
  357. package/src/style-modules.d.ts +9 -0
  358. package/src/typegen.ts +151 -0
  359. package/src/types.ts +725 -0
  360. package/src/utils/ansi.ts +9 -0
  361. package/src/utils/content-type.ts +31 -0
  362. package/src/utils/decode.ts +7 -0
  363. package/src/utils/dev-profile.ts +31 -0
  364. package/src/utils/error-log.ts +29 -0
  365. package/src/utils/fs-cache.ts +31 -0
  366. package/src/utils/fs.ts +119 -0
  367. package/src/utils/html.ts +46 -0
  368. package/src/utils/serialize.ts +378 -0
  369. package/src/utils/source.ts +35 -0
  370. package/src/utils/verbose.ts +39 -0
  371. package/tsconfig.json +10 -0
@@ -0,0 +1,236 @@
1
+ // Custom-server `next()` entry (COMPAT).
2
+ //
3
+ // Next apps can drive the framework through their own HTTP server, requiring 'next' and calling
4
+ // `app.prepare()` / `app.getRequestHandler()`. pnext has no `next` package to require, so `pnext build`
5
+ // materializes a minimal one into the app's `node_modules/next` when the app root ships a custom server
6
+ // entry importing 'next'.
7
+ //
8
+ // The shim's factory boots the real pnext server as a child process on an ephemeral internal port and
9
+ // proxies node req/res pairs to it, so the custom server observes Next's contract while pnext serves
10
+ // every request - basePath, server actions, after(), graceful stop included. close() SIGTERMs the child
11
+ // and awaits its exit, which lets pending after() callbacks drain.
12
+ //
13
+ // Only a missing, symlinked, or previously shimmed `node_modules/next` is replaced: the e2e harness
14
+ // links the real Next checkout for tsc typechecks, and fixtures with a genuinely installed `next` are
15
+ // left alone.
16
+ import { existsSync, lstatSync, readFileSync } from 'node:fs';
17
+ import { mkdir, rm, writeFile } from 'node:fs/promises';
18
+ import path from 'node:path';
19
+ import type { ResolvedConfig } from '../../config';
20
+
21
+ const SERVER_ENTRY_NAMES = ['server.js', 'server.mjs', 'server.cjs', 'server.ts'];
22
+ const SHIM_VERSION = '0.0.0-pnext-custom-server';
23
+
24
+ /** Whether the app root ships a custom server entry that imports 'next'. */
25
+ export function hasCustomServerEntry(root: string): boolean {
26
+ for (const name of SERVER_ENTRY_NAMES) {
27
+ const file = path.join(root, name);
28
+ if (!existsSync(file)) continue;
29
+ try {
30
+ const source = readFileSync(file, 'utf8');
31
+ if (/(?:require\(\s*['"]next['"]\s*\)|from\s+['"]next['"])/.test(source)) return true;
32
+ } catch {
33
+ // Unreadable entry — skip.
34
+ }
35
+ }
36
+ return false;
37
+ }
38
+
39
+ /**
40
+ * Materialize the `next` custom-server shim into the app's node_modules when a
41
+ * custom server entry exists. No-op when `node_modules/next` is a real
42
+ * third-party install (absent, symlinked, or an earlier shim is replaced).
43
+ */
44
+ export async function emitCustomServerShim(config: ResolvedConfig): Promise<void> {
45
+ if (!hasCustomServerEntry(config.root)) return;
46
+ const target = path.join(config.root, 'node_modules', 'next');
47
+ try {
48
+ const stat = lstatSync(target);
49
+ // A previously emitted shim is a real directory too — refresh it, so a
50
+ // rebuild in an existing test dir never keeps a stale copy.
51
+ if (!stat.isSymbolicLink() && !isEmittedShim(target)) return; // real install — leave it alone
52
+ await rm(target, { recursive: true, force: true });
53
+ } catch {
54
+ // Missing — create fresh below.
55
+ }
56
+ await mkdir(target, { recursive: true });
57
+ await writeFile(
58
+ path.join(target, 'package.json'),
59
+ `${JSON.stringify({ name: 'next', version: SHIM_VERSION, main: 'index.cjs' }, null, 2)}\n`,
60
+ );
61
+ await writeFile(path.join(target, 'index.cjs'), customServerShimSource());
62
+ }
63
+
64
+ /** Whether `node_modules/next` is a shim this build emitted earlier. */
65
+ function isEmittedShim(target: string): boolean {
66
+ try {
67
+ const pkg = JSON.parse(readFileSync(path.join(target, 'package.json'), 'utf8')) as { version?: string };
68
+ return pkg.version === SHIM_VERSION;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * The shim source. Bakes the absolute pnext CLI path so the child boots the
76
+ * same runtime the harness/build used, from any app directory.
77
+ */
78
+ function customServerShimSource(): string {
79
+ const cliPath = path.resolve(import.meta.dirname, '..', '..', 'cli', 'index.ts');
80
+ return `'use strict';
81
+ // pnext custom-server shim for require('next') / import next from 'next'.
82
+ // Generated by pnext build; see src/compat/next/custom-server.ts.
83
+ const { spawn } = require('node:child_process');
84
+
85
+ const PNEXT_CLI = ${JSON.stringify(cliPath)};
86
+ const HOP_BY_HOP = new Set([
87
+ 'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',
88
+ 'te', 'trailer', 'transfer-encoding', 'upgrade', 'host', 'accept-encoding',
89
+ ]);
90
+
91
+ function createServer(options = {}) {
92
+ const dev = Boolean(options.dev);
93
+ const hostname = options.hostname || 'localhost';
94
+ const port = options.port || 3000;
95
+ let child;
96
+ let childExited;
97
+ let internalPort;
98
+
99
+ async function prepare() {
100
+ if (internalPort) return;
101
+ child = spawn(
102
+ 'bun',
103
+ ['--conditions=react-server', PNEXT_CLI, dev ? 'dev' : 'start', '--port', '0', '--hostname', '127.0.0.1'],
104
+ {
105
+ cwd: process.cwd(),
106
+ env: { ...process.env, BROWSER: 'none', NODE_ENV: dev ? 'development' : 'production' },
107
+ stdio: ['ignore', 'pipe', 'pipe'],
108
+ }
109
+ );
110
+ childExited = new Promise((resolve) => child.once('exit', resolve));
111
+ internalPort = await new Promise((resolve, reject) => {
112
+ const timer = setTimeout(
113
+ () => reject(new Error('pnext custom-server: timed out waiting for the pnext server to start')),
114
+ 60000
115
+ );
116
+ let buffer = '';
117
+ // Echo the child's logs line by line, relabelling its "- Local: <internal>"
118
+ // ready banner: log scanners on THIS process's stdout (the Next e2e harness
119
+ // parses that exact line for the app URL) must not pick up the internal
120
+ // port, or every request would bypass the custom server. Line buffering
121
+ // keeps a coalesced/split chunk from slipping the raw banner through.
122
+ const echoLines = (out) => {
123
+ let tail = '';
124
+ const write = (text) => {
125
+ const merged = tail + text;
126
+ const cut = merged.lastIndexOf('\\n') + 1;
127
+ tail = merged.slice(cut);
128
+ if (cut === 0) return;
129
+ out.write(merged.slice(0, cut).replace(/-(\\s*)(Local|Network):/g, '[pnext internal]$1$2:'));
130
+ };
131
+ child.once('exit', () => { if (tail) { const rest = tail; tail = ''; out.write(rest); } });
132
+ return write;
133
+ };
134
+ const echoOut = echoLines(process.stdout);
135
+ const echoErr = echoLines(process.stderr);
136
+ const scan = (chunk, echo) => {
137
+ const text = chunk.toString('utf8');
138
+ echo(text);
139
+ if (internalPort) return;
140
+ buffer = (buffer + text).slice(-4096);
141
+ const match = /-\\s*Local:\\s+https?:\\/\\/[^:\\s]+:(\\d+)/.exec(buffer);
142
+ if (match) {
143
+ clearTimeout(timer);
144
+ resolve(Number(match[1]));
145
+ }
146
+ };
147
+ child.stdout.on('data', (chunk) => scan(chunk, echoOut));
148
+ child.stderr.on('data', (chunk) => scan(chunk, echoErr));
149
+ child.once('exit', (code) => {
150
+ clearTimeout(timer);
151
+ reject(new Error('pnext custom-server: the pnext server exited during startup (code ' + code + ')'));
152
+ });
153
+ });
154
+ }
155
+
156
+ async function handleRequest(req, res) {
157
+ if (!internalPort) throw new Error('pnext custom-server: prepare() must complete before handling requests');
158
+ const target = new URL(req.url || '/', 'http://127.0.0.1:' + internalPort);
159
+ const headers = {};
160
+ for (const [name, value] of Object.entries(req.headers)) {
161
+ if (value === undefined || HOP_BY_HOP.has(name)) continue;
162
+ headers[name] = Array.isArray(value) ? value.join(', ') : value;
163
+ }
164
+ if (req.headers.host) headers['x-forwarded-host'] = req.headers.host;
165
+ headers['x-forwarded-proto'] = 'http';
166
+ const method = (req.method || 'GET').toUpperCase();
167
+ const hasBody = method !== 'GET' && method !== 'HEAD';
168
+ const response = await fetch(target, {
169
+ method,
170
+ headers,
171
+ body: hasBody ? req : undefined,
172
+ duplex: hasBody ? 'half' : undefined,
173
+ redirect: 'manual',
174
+ });
175
+ res.statusCode = response.status;
176
+ for (const [name, value] of response.headers) {
177
+ if (['content-encoding', 'content-length', 'transfer-encoding', 'set-cookie'].includes(name)) continue;
178
+ if (name === 'location') {
179
+ // Rewrite child-origin absolute redirects back to a relative target so
180
+ // the browser stays on the custom server's host/port.
181
+ try {
182
+ const url = new URL(value);
183
+ if (url.hostname === '127.0.0.1' && Number(url.port) === internalPort) {
184
+ res.setHeader(name, url.pathname + url.search + url.hash);
185
+ continue;
186
+ }
187
+ } catch {}
188
+ }
189
+ res.setHeader(name, value);
190
+ }
191
+ const setCookies = typeof response.headers.getSetCookie === 'function' ? response.headers.getSetCookie() : [];
192
+ if (setCookies.length > 0) {
193
+ const existing = res.getHeader('set-cookie');
194
+ const merged = existing === undefined ? setCookies : [].concat(existing, setCookies);
195
+ res.setHeader('set-cookie', merged);
196
+ }
197
+ if (response.body) {
198
+ for await (const chunk of response.body) res.write(chunk);
199
+ }
200
+ res.end();
201
+ }
202
+
203
+ async function close() {
204
+ if (!child || child.exitCode !== null) return;
205
+ // Graceful: the pnext server stops accepting connections, drains pending
206
+ // after() callbacks, then exits 0. Escalate to SIGKILL only on a hang.
207
+ child.kill('SIGTERM');
208
+ await Promise.race([
209
+ childExited,
210
+ new Promise((resolve) => setTimeout(resolve, 15000).unref()),
211
+ ]);
212
+ if (child.exitCode === null) child.kill('SIGKILL');
213
+ }
214
+
215
+ return {
216
+ hostname,
217
+ port,
218
+ prepare,
219
+ close,
220
+ getRequestHandler: () => (req, res) => handleRequest(req, res).catch((error) => {
221
+ console.error('pnext custom-server: request failed:', error);
222
+ if (!res.headersSent) res.statusCode = 500;
223
+ res.end('Internal Server Error');
224
+ }),
225
+ getUpgradeHandler: () => (_req, socket) => { socket.destroy(); },
226
+ setAssetPrefix: () => {},
227
+ logError: (...args) => console.error(...args),
228
+ render: async (req, res) => { await handleRequest(req, res); },
229
+ renderToHTML: async () => { throw new Error('renderToHTML is not supported by the pnext custom server'); },
230
+ };
231
+ }
232
+
233
+ module.exports = createServer;
234
+ module.exports.default = createServer;
235
+ `;
236
+ }
@@ -0,0 +1,32 @@
1
+ // Header-name constants matching
2
+ // next/src/client/components/app-router-headers.ts exactly.
3
+ export const RSC_HEADER = 'rsc' as const;
4
+ export const ACTION_HEADER = 'next-action' as const;
5
+ export const NEXT_ROUTER_STATE_TREE_HEADER = 'next-router-state-tree' as const;
6
+ export const NEXT_ROUTER_PREFETCH_HEADER = 'next-router-prefetch' as const;
7
+ export const NEXT_ROUTER_SEGMENT_PREFETCH_HEADER = 'next-router-segment-prefetch' as const;
8
+ export const NEXT_HMR_REFRESH_HEADER = 'next-hmr-refresh' as const;
9
+ export const NEXT_HMR_REFRESH_HASH_COOKIE = '__next_hmr_refresh_hash__' as const;
10
+ export const NEXT_URL = 'next-url' as const;
11
+ export const RSC_CONTENT_TYPE_HEADER = 'text/x-component' as const;
12
+
13
+ export const NEXT_INSTANT_TEST_COOKIE = 'next-instant-navigation-testing' as const;
14
+
15
+ export const FLIGHT_HEADERS = [
16
+ RSC_HEADER,
17
+ NEXT_ROUTER_STATE_TREE_HEADER,
18
+ NEXT_ROUTER_PREFETCH_HEADER,
19
+ NEXT_HMR_REFRESH_HEADER,
20
+ NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,
21
+ ] as const;
22
+
23
+ export const NEXT_RSC_UNION_QUERY = '_rsc' as const;
24
+ export const NEXT_ROUTER_STALE_TIME_HEADER = 'x-nextjs-stale-time' as const;
25
+ export const NEXT_DID_POSTPONE_HEADER = 'x-nextjs-postponed' as const;
26
+ export const NEXT_REWRITTEN_PATH_HEADER = 'x-nextjs-rewritten-path' as const;
27
+ export const NEXT_REWRITTEN_QUERY_HEADER = 'x-nextjs-rewritten-query' as const;
28
+ export const NEXT_IS_PRERENDER_HEADER = 'x-nextjs-prerender' as const;
29
+ export const NEXT_ACTION_NOT_FOUND_HEADER = 'x-nextjs-action-not-found' as const;
30
+ export const NEXT_REQUEST_ID_HEADER = 'x-nextjs-request-id' as const;
31
+ export const NEXT_HTML_REQUEST_ID_HEADER = 'x-nextjs-html-request-id' as const;
32
+ export const NEXT_ACTION_REVALIDATED_HEADER = 'x-action-revalidated' as const;
@@ -0,0 +1,38 @@
1
+ // Compat shim for the deep Next internal
2
+ // `next/dist/server/app-render/work-unit-async-storage.external`.
3
+ //
4
+ // Some libraries (and app code, e.g. the app-external / segment-cache e2e
5
+ // fixtures) import this module directly to reach the SAME work-unit store the
6
+ // framework populates during a render. Next backs that with an
7
+ // AsyncLocalStorage whose store carries `type` ('request' | 'prerender' |
8
+ // 'prerender-runtime') plus, for a request work unit, `cookies`/`headers`.
9
+ // pnext keeps that state in core (src/request/context.ts, src/ppr.ts) and
10
+ // publishes a getter onto globalThis, which this module reflects — so a direct
11
+ // import observes the live store rather than a separate, empty instance.
12
+ //
13
+ // CommonJS on purpose: apps `require()` this specifier, and the server
14
+ // runtime's onLoad transform only intercepts `[jt]sx?` (see rootFilter), so a
15
+ // `.cjs` external is left to Bun's native loader and stays synchronously
16
+ // requirable. The same module as a `.ts` external is forced through that
17
+ // transform, becomes an async module, and `require()` throws
18
+ // "require() async module ... is unsupported". Same rule as constants.cjs /
19
+ // navigation.cjs — see the note in src/compat/index.ts.
20
+ const WORK_UNIT_EXTERNAL = Symbol.for('pnext.workUnitExternal')
21
+ /** @type {Record<PropertyKey, unknown>} */
22
+ const root = globalThis
23
+
24
+ const workUnitAsyncStorage = {
25
+ // Never undefined: fixtures do `getStore().type` during build prerenders as
26
+ // well as live requests. Core's getter always answers with a store.
27
+ getStore: () =>
28
+ /** @type {(() => unknown) | undefined} */ (root[WORK_UNIT_EXTERNAL])?.(),
29
+ /**
30
+ * @param {unknown} _store
31
+ * @param {(...args: unknown[]) => unknown} callback
32
+ * @param {unknown[]} args
33
+ */
34
+ run: (_store, callback, ...args) => callback(...args),
35
+ }
36
+
37
+ exports.workUnitAsyncStorage = workUnitAsyncStorage
38
+ exports.default = workUnitAsyncStorage
@@ -0,0 +1 @@
1
+ export { revalidatePath, revalidateTag } from '../../../../cache';
@@ -0,0 +1 @@
1
+ export { unstable_cache } from '../../../../cache';
@@ -0,0 +1 @@
1
+ export { unstable_noStore } from '../../../../cache';
@@ -0,0 +1,46 @@
1
+ import { h, type ComponentType } from 'preact';
2
+ import { lazy, Suspense } from 'preact/compat';
3
+ import {
4
+ dynamic as pnextDynamic,
5
+ dynamicReferenceSymbol,
6
+ type DynamicLoader,
7
+ type DynamicModule,
8
+ type DynamicOptions,
9
+ type DynamicReference,
10
+ type DynamicTarget,
11
+ } from '../../api/dynamic';
12
+
13
+ export type { DynamicLoader, DynamicModule, DynamicOptions };
14
+
15
+ export default function dynamic<Props extends object = object>(
16
+ loader: DynamicLoader<Props>,
17
+ options: DynamicOptions<Props> = {},
18
+ // Injected by the server compile; see rewriteDynamicCallTargets.
19
+ target?: DynamicTarget,
20
+ ) {
21
+ if (typeof loader === 'string') return pnextDynamic(loader, options, target);
22
+
23
+ const coreDynamic = pnextDynamic(loader, options, target) as DynamicWithReference<Props>;
24
+ const Lazy = lazy(() => loader().then(module => ({ default: componentFromModule(module) })));
25
+ const DynamicComponent = ((props: Props) => {
26
+ const Loading = options.loading;
27
+ const content = h(Suspense, { fallback: Loading ? h(Loading, props) : null }, h(Lazy, props));
28
+ return options.ssr === false
29
+ ? h('pnext-dynamic', { style: { display: 'contents' } },
30
+ (!process.browser && typeof window === 'undefined') ? null : content)
31
+ : content;
32
+ }) as DynamicWithReference<Props>;
33
+
34
+ DynamicComponent[dynamicReferenceSymbol] = coreDynamic[dynamicReferenceSymbol];
35
+ return DynamicComponent;
36
+ }
37
+
38
+ export { dynamic };
39
+
40
+ type DynamicWithReference<Props extends object> = ComponentType<Props> & {
41
+ [dynamicReferenceSymbol]?: DynamicReference<Props>;
42
+ };
43
+
44
+ function componentFromModule<Props>(module: DynamicModule<Props>) {
45
+ return typeof module === 'function' ? module : module.default;
46
+ }
@@ -0,0 +1,148 @@
1
+ 'use client';
2
+
3
+ import { Component, Fragment, h, type ComponentChildren, type ComponentType } from 'preact';
4
+ import { isControlFlowError } from '../client/errors/control-flow';
5
+ import { untagPrimitiveThrow } from '../client/errors/primitive-throw';
6
+
7
+ export interface ErrorInfo {
8
+ error: unknown;
9
+ reset: () => void;
10
+ unstable_retry: () => void;
11
+ }
12
+
13
+ // Island error-boundary protocol (see render/renderer.ts): when a Server Component inside this
14
+ // boundary's children throws during the SSR resolve walk, the renderer serializes the error into this
15
+ // prop on the island - used twice. On SSR the initial state is the caught state, so the fallback renders
16
+ // inline; on hydration the prop rides `data-pnext-props`, so the client mount re-creates the SAME caught
17
+ // state and the server-rendered fallback hydrates interactive. Without this handoff the client would
18
+ // remount with "no error" and blank out the fallback. The renderer only performs the handoff for
19
+ // components carrying `Symbol.for('pnext.islandErrorBoundary')`, stamped below.
20
+ const ISLAND_BOUNDARY_ERROR_PROP = '__pnextBoundaryError';
21
+ const islandErrorBoundarySymbol = Symbol.for('pnext.islandErrorBoundary');
22
+
23
+ interface IslandBoundaryErrorMarker {
24
+ name?: string;
25
+ message?: string;
26
+ digest?: string;
27
+ }
28
+
29
+ interface CatchErrorProps {
30
+ children?: ComponentChildren;
31
+ clearError?: () => void;
32
+ [ISLAND_BOUNDARY_ERROR_PROP]?: IslandBoundaryErrorMarker;
33
+ }
34
+
35
+ interface CatchErrorState {
36
+ error: unknown;
37
+ hasError: boolean;
38
+ version: number;
39
+ }
40
+
41
+ function reviveBoundaryError(marker: IslandBoundaryErrorMarker): Error & { digest?: string } {
42
+ const error = new Error(String(marker.message ?? '')) as Error & { digest?: string };
43
+ if (marker.name) error.name = String(marker.name);
44
+ if (typeof marker.digest === 'string') error.digest = marker.digest;
45
+ return error;
46
+ }
47
+
48
+ function initialCatchErrorState(props: CatchErrorProps): CatchErrorState {
49
+ const marker = props[ISLAND_BOUNDARY_ERROR_PROP];
50
+ if (marker && typeof marker === 'object') {
51
+ return { error: reviveBoundaryError(marker), hasError: true, version: 0 };
52
+ }
53
+ return { error: undefined, hasError: false, version: 0 };
54
+ }
55
+
56
+ export function unstable_catchError<Props extends Record<string, unknown>>(
57
+ Fallback: (props: Props, info: ErrorInfo) => ComponentChildren,
58
+ ): ComponentType<Props & CatchErrorProps> {
59
+ class CatchError extends Component<Props & CatchErrorProps, CatchErrorState> {
60
+ state: CatchErrorState = initialCatchErrorState(this.props);
61
+
62
+ static getDerivedStateFromError(error: unknown): Partial<CatchErrorState> {
63
+ // Router signals belong to their owning route boundary. Capturing one
64
+ // here turns a redirect/notFound into a stale local fallback instead of
65
+ // letting the client control-flow handler complete the navigation.
66
+ if (isControlFlowError(error)) throw error;
67
+ return { error: normalizeBoundaryError(error), hasError: true };
68
+ }
69
+
70
+ reset = () => {
71
+ this.props.clearError?.();
72
+ this.setState(state => ({
73
+ error: undefined,
74
+ hasError: false,
75
+ version: state.version + 1,
76
+ }));
77
+ };
78
+
79
+ unstable_retry = () => {
80
+ // App-Router only: `unstable_retry` re-runs the server render, which the Pages Router has no
81
+ // equivalent of. The discriminator is the rendering context, NOT the user-supplied `clearError`
82
+ // prop (the Pages fixture passes it too) - App-Router documents always render the segment tree as
83
+ // <pnext-layout>/[data-pnext-root] elements; Pages ones never do.
84
+ if (!isAppRouterDocument()) {
85
+ throw new Error(
86
+ '`unstable_retry()` can only be used in the App Router. Use `reset()` in the Pages Router.',
87
+ );
88
+ }
89
+ if (!process.browser && typeof window === 'undefined') {
90
+ this.reset();
91
+ return;
92
+ }
93
+ // Refresh FIRST, reset when it settles. Resetting immediately re-renders the children while the
94
+ // refresh response is still in flight; anything the user does in that window is wiped when the
95
+ // body swap lands, so a rapid retry-then-interact cycle loses the new state. Deferring the reset
96
+ // closes that window (if the swap remounted this boundary the setState is a no-op on an unmounted
97
+ // instance, which preact ignores). A failed refresh still resets.
98
+ const refreshed = routerRefresh();
99
+ void Promise.resolve(refreshed)
100
+ .catch(() => undefined)
101
+ .then(() => this.reset());
102
+ };
103
+
104
+ render(props: Props & CatchErrorProps, state: CatchErrorState) {
105
+ if (state.hasError) {
106
+ // Strip the internal handoff marker; the user's fallback gets the
107
+ // component's own props (title, clearError, ...), matching Next.
108
+ const { [ISLAND_BOUNDARY_ERROR_PROP]: _marker, ...rest } = props;
109
+ return Fallback(rest as unknown as Props, {
110
+ error: state.error,
111
+ reset: this.reset,
112
+ unstable_retry: this.unstable_retry,
113
+ });
114
+ }
115
+ return h(Fragment, { key: state.version }, props.children);
116
+ }
117
+ }
118
+ // Opt in to the renderer's island error-boundary handoff (see above).
119
+ (CatchError as unknown as Record<symbol, boolean>)[islandErrorBoundarySymbol] = true;
120
+ return CatchError;
121
+ }
122
+
123
+ function isAppRouterDocument(): boolean {
124
+ if (typeof document === 'undefined') return false;
125
+ return Boolean(document.querySelector('pnext-layout, [data-pnext-root]'));
126
+ }
127
+
128
+ function routerRefresh() {
129
+ const global = window as unknown as {
130
+ __PNEXT_ROUTER__?: { refresh?: () => Promise<void> | void };
131
+ };
132
+ return global.__PNEXT_ROUTER__?.refresh?.();
133
+ }
134
+
135
+ function normalizeBoundaryError(error: unknown): unknown {
136
+ // Preact-core interop tag (see client/errors/primitive-throw.ts): a client
137
+ // `throw undefined`/`null` arrives here re-thrown as a tagged Error so it
138
+ // survived preact's own `e.then` suspense check without crashing. Unwrap
139
+ // back to the raw value Next passes to error UIs.
140
+ const untagged = untagPrimitiveThrow(error);
141
+ if (untagged !== error) return untagged;
142
+ if (error instanceof Error) {
143
+ // Fallback for any crash that slips through un-tagged (defense in depth).
144
+ if (error.message === "Cannot read properties of undefined (reading 'then')") return undefined;
145
+ if (error.message === "Cannot read properties of null (reading 'then')") return null;
146
+ }
147
+ return error;
148
+ }