@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
@@ -1,14 +1,14 @@
1
- import { existsSync, readFileSync, statSync } from 'node:fs';
2
- import path from 'node:path';
1
+ import { existsSync, readFileSync, statSync } from 'node:fs'
2
+ import path from 'node:path'
3
3
  // Lazy: the oxc-parser native binding costs ~12.6 MB RSS; load it only when a parse happens.
4
4
  const parseSync: typeof import('oxc-parser').parseSync = (...args) =>
5
5
  // eslint-disable-next-line @typescript-eslint/no-require-imports
6
- loadNative(() => require('oxc-parser') as typeof import('oxc-parser')).parseSync(...args);
7
- import { loadNative } from './utils/native-require';
8
- import { registerServerRuntime } from './runtime/server';
9
- import { pathToFileHref, type ResolvedConfig } from './config';
10
- import { devServerModuleHref } from './dev/imports';
11
- import { runWithRequest } from './request/context';
6
+ loadNative(() => require('oxc-parser') as typeof import('oxc-parser')).parseSync(...args)
7
+ import { loadNative } from '../utils/native-require'
8
+ import { registerServerRuntime } from '../runtime/loader'
9
+ import { pathToFileHref, type ResolvedConfig } from '../config'
10
+ import { devServerModuleHref } from '../runtime/modules'
11
+ import { runWithRequest } from '../request/context'
12
12
  import {
13
13
  copyMiddlewareHeaders,
14
14
  forwardMiddlewareRequestHeaders,
@@ -18,107 +18,106 @@ import {
18
18
  parseCookies,
19
19
  requestCookieHeader,
20
20
  toNextRequest,
21
- } from './api/server';
22
- import type { ExternalLoadTarget } from './resolve/imports';
23
- import { getProxyExtensions, withRouteRuntime } from './extensions';
24
- import { canonicalTrailingSlashPath } from './routing/href';
21
+ } from '../api/server'
22
+ import type { ExternalLoadTarget } from '../resolve/imports'
23
+ import { getProxyExtensions, withRouteRuntime } from '../extensions'
24
+ import { canonicalTrailingSlashPath } from './href'
25
25
 
26
26
  export interface ProxyModule {
27
- default?: ProxyHandler;
28
- proxy?: ProxyHandler;
29
- config?: ProxyConfig;
27
+ default?: ProxyHandler
28
+ proxy?: ProxyHandler
29
+ config?: ProxyConfig
30
30
  }
31
31
 
32
32
  export type ProxyHandler = (
33
- request: import('./types').NextRequest,
34
- event: import('./types').NextFetchEvent,
35
- ) => Response | undefined | void | Promise<Response | undefined | void>;
33
+ request: import('../types').NextRequest,
34
+ event: import('../types').NextFetchEvent,
35
+ ) => Response | undefined | void | Promise<Response | undefined | void>
36
36
 
37
37
  export interface ProxyConfig {
38
- matcher?: ProxyMatcher | ProxyMatcher[];
38
+ matcher?: ProxyMatcher | ProxyMatcher[]
39
39
  }
40
40
 
41
41
  export interface ProxyRouteCondition {
42
- type: 'header' | 'query' | 'cookie' | 'host';
43
- key?: string;
44
- value?: string;
42
+ type: 'header' | 'query' | 'cookie' | 'host'
43
+ key?: string
44
+ value?: string
45
45
  }
46
46
 
47
47
  type ProxyMatcher =
48
- | string
49
- | { source: string; has?: ProxyRouteCondition[]; missing?: ProxyRouteCondition[] };
48
+ string | { source: string; has?: ProxyRouteCondition[]; missing?: ProxyRouteCondition[] }
50
49
 
51
50
  interface CompiledMatcher {
52
- regex: RegExp;
53
- has?: ProxyRouteCondition[];
54
- missing?: ProxyRouteCondition[];
51
+ regex: RegExp
52
+ has?: ProxyRouteCondition[]
53
+ missing?: ProxyRouteCondition[]
55
54
  }
56
55
 
57
56
  export interface ProxyRunOptions {
58
- dev?: boolean;
59
- devImportVersion?: string;
57
+ dev?: boolean
58
+ devImportVersion?: string
60
59
  }
61
60
 
62
- export type ProxyRewriteObserver = (from: URL, to: URL) => void;
61
+ export type ProxyRewriteObserver = (from: URL, to: URL) => void
63
62
 
64
- let proxyRewriteObserver: ProxyRewriteObserver | undefined;
63
+ let proxyRewriteObserver: ProxyRewriteObserver | undefined
65
64
 
66
65
  export function setProxyRewriteObserver(observer: ProxyRewriteObserver | undefined): void {
67
- proxyRewriteObserver = observer;
66
+ proxyRewriteObserver = observer
68
67
  }
69
68
 
70
- export type ProxyRunObserver = <T>(request: Request, fn: () => T) => T;
69
+ export type ProxyRunObserver = <T>(request: Request, fn: () => T) => T
71
70
 
72
- let proxyRunObserver: ProxyRunObserver | undefined;
71
+ let proxyRunObserver: ProxyRunObserver | undefined
73
72
 
74
73
  export function setProxyRunObserver(observer: ProxyRunObserver | undefined): void {
75
- proxyRunObserver = observer;
74
+ proxyRunObserver = observer
76
75
  }
77
76
 
78
77
  function wrapMiddleware<T>(request: Request, fn: () => T): T {
79
- return proxyRunObserver ? proxyRunObserver(request, fn) : fn();
78
+ return proxyRunObserver ? proxyRunObserver(request, fn) : fn()
80
79
  }
81
80
 
82
81
  export interface ProxyNextResult {
83
- request: Request;
84
- response?: Response;
82
+ request: Request
83
+ response?: Response
85
84
  }
86
85
 
87
86
  export interface ProxyRunner {
88
- (request: Request, options?: ProxyRunOptions): Promise<ProxyNextResult | Response | undefined>;
87
+ (request: Request, options?: ProxyRunOptions): Promise<ProxyNextResult | Response | undefined>
89
88
  /**
90
89
  * Start compiling and importing the proxy module now. The proxy runs serially in front of every
91
90
  * request, so leaving its first import to the first request puts the whole compile on the critical
92
91
  * path of the first page; dev calls this at boot so it overlaps route scanning and the warmup.
93
92
  */
94
- warm(options?: ProxyRunOptions): void;
93
+ warm(options?: ProxyRunOptions): void
95
94
  }
96
95
 
97
- const proxyExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mts'];
96
+ const proxyExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mts']
98
97
 
99
98
  export function findProxyFile(config: ResolvedConfig) {
100
- return findProxyFiles(config)[0];
99
+ return findProxyFiles(config)[0]
101
100
  }
102
101
 
103
102
  export function proxyExternalLoadTarget(file: string): ExternalLoadTarget {
104
- return path.basename(file).startsWith('proxy.') ? 'client-ssr' : 'edge';
103
+ return path.basename(file).startsWith('proxy.') ? 'client-ssr' : 'edge'
105
104
  }
106
105
 
107
106
  export function findProxyFiles(config: ResolvedConfig, names = getProxyExtensions().names) {
108
- const files: string[] = [];
107
+ const files: string[] = []
109
108
  for (const base of proxyBases(config)) {
110
109
  for (const name of names) {
111
110
  for (const extension of proxyExtensions) {
112
- const file = path.join(base, `${name}${extension}`);
113
- if (existsSync(file)) files.push(file);
111
+ const file = path.join(base, `${name}${extension}`)
112
+ if (existsSync(file)) files.push(file)
114
113
  }
115
114
  }
116
115
  }
117
- return files;
116
+ return files
118
117
  }
119
118
 
120
119
  export async function validateProxyFiles(config: ResolvedConfig) {
121
- await getProxyExtensions().validateFiles(config);
120
+ await getProxyExtensions().validateFiles(config)
122
121
  }
123
122
 
124
123
  export async function runProxy(
@@ -126,12 +125,12 @@ export async function runProxy(
126
125
  request: Request,
127
126
  options: ProxyRunOptions = {},
128
127
  ): Promise<ProxyNextResult | Response | undefined> {
129
- const url = new URL(request.url);
128
+ const url = new URL(request.url)
130
129
  if (url.pathname.startsWith('/__pnext/') || url.pathname.startsWith('/assets/')) {
131
- return undefined;
130
+ return undefined
132
131
  }
133
132
 
134
- return createProxyRunner(config)(request, options);
133
+ return createProxyRunner(config)(request, options)
135
134
  }
136
135
 
137
136
  export interface ProxyRunnerOptions {
@@ -140,70 +139,69 @@ export interface ProxyRunnerOptions {
140
139
  * cannot resolve bare compat specifiers (next/server etc.), so prod must
141
140
  * load the build-time bundle that has aliases baked in.
142
141
  */
143
- compiledModuleHref?: string;
142
+ compiledModuleHref?: string
144
143
  }
145
144
 
146
145
  export function createProxyRunner(
147
146
  config: ResolvedConfig,
148
147
  runnerOptions: ProxyRunnerOptions = {},
149
148
  ): ProxyRunner {
150
- const file = findProxyFile(config);
151
- registerServerRuntime(config, file ? [file] : []);
152
- let moduleKey: string | undefined;
153
- let modulePromise: Promise<ProxyModule> | undefined;
154
- let matchers: CompiledMatcher[] | undefined;
149
+ const file = findProxyFile(config)
150
+ registerServerRuntime(config, file ? [file] : [])
151
+ let moduleKey: string | undefined
152
+ let modulePromise: Promise<ProxyModule> | undefined
153
+ let matchers: CompiledMatcher[] | undefined
155
154
 
156
155
  /** The module for `options`, started at most once per import version. */
157
156
  function proxyModule(options: ProxyRunOptions) {
158
- const key = proxyModuleKey(options);
157
+ const key = proxyModuleKey(options)
159
158
  if (key !== moduleKey) {
160
- moduleKey = key;
161
- modulePromise = importProxyModule(config, file!, options, runnerOptions);
162
- matchers = undefined;
159
+ moduleKey = key
160
+ modulePromise = importProxyModule(config, file!, options, runnerOptions)
161
+ matchers = undefined
163
162
  }
164
- return (modulePromise ??= importProxyModule(config, file!, options, runnerOptions));
163
+ return (modulePromise ??= importProxyModule(config, file!, options, runnerOptions))
165
164
  }
166
165
 
167
166
  const runner: ProxyRunner = async (request, options = {}) => {
168
- const url = new URL(request.url);
167
+ const url = new URL(request.url)
169
168
  if (url.pathname.startsWith('/__pnext/') || url.pathname.startsWith('/assets/')) {
170
- return undefined;
169
+ return undefined
171
170
  }
172
- if (!file) return undefined;
171
+ if (!file) return undefined
173
172
 
174
173
  // Matcher first, straight off the source: a request no matcher selects must not wait on the
175
174
  // proxy's compile+import, which is otherwise the first serial link of a cold page.
176
175
  if (!matchers && proxyMatcherGateEnabled()) {
177
- const staticMatchers = staticProxyMatchers(file);
178
- if (staticMatchers && !matchesProxy(staticMatchers, url, request)) return undefined;
176
+ const staticMatchers = staticProxyMatchers(file)
177
+ if (staticMatchers && !matchesProxy(staticMatchers, url, request)) return undefined
179
178
  }
180
179
 
181
- const module = await proxyModule(options);
182
- matchers ??= proxyMatchers(module.config);
183
- if (!matchesProxy(matchers, url, request)) return undefined;
180
+ const module = await proxyModule(options)
181
+ matchers ??= proxyMatchers(module.config)
182
+ if (!matchesProxy(matchers, url, request)) return undefined
184
183
 
185
184
  // A proxied request's body is buffered so both the proxy and the matched
186
185
  // route can read it; buffering is capped at clientMaxBodySize (compat maps
187
186
  // experimental.proxyClientMaxBodySize, default 10MB) — the excess is
188
187
  // dropped with a warning, matching Next's router-server behavior.
189
- request = await bufferProxyRequestBody(request, url.pathname);
188
+ request = await bufferProxyRequestBody(request, url.pathname)
190
189
 
191
- const handlerExport = getProxyExtensions().handlerExport(module as Record<string, unknown>);
192
- if (typeof handlerExport !== 'function')
193
- throw new Error(`${file} must export proxy or default`);
194
- const handler = handlerExport as ProxyHandler;
190
+ const handlerExport = getProxyExtensions().handlerExport(module as Record<string, unknown>)
191
+ if (typeof handlerExport !== 'function') throw new Error(`${file} must export proxy or default`)
192
+ const handler = handlerExport as ProxyHandler
195
193
 
196
194
  // Next normally hides the RSC cache key and Flight headers from proxy;
197
195
  // skipProxyUrlNormalize exposes the original request for advanced routing.
198
196
  const handlerRequest = getProxyExtensions().skipUrlNormalize()
199
197
  ? request
200
- : stripFlightHeaders(stripRscUnionQuery(request));
201
- const nextRequest = toNextRequest(handlerRequest);
198
+ : stripFlightHeaders(stripRscUnionQuery(request))
199
+ const nextRequest = toNextRequest(handlerRequest)
202
200
  // Response-headers channel so request-scoped APIs invoked inside the proxy
203
201
  // (notably draftMode().enable()/disable() from next/headers) can emit
204
202
  // Set-Cookie even when the handler returns NextResponse.next() — otherwise
205
203
  // the cookie would be dropped since it is not written onto that response.
206
- const proxyResponseHeaders = new Headers();
204
+ const proxyResponseHeaders = new Headers()
207
205
  let response = await runWithRequest(
208
206
  nextRequest,
209
207
  () =>
@@ -211,39 +209,39 @@ export function createProxyRunner(
211
209
  wrapMiddleware(nextRequest, () =>
212
210
  handler(nextRequest, {
213
211
  waitUntil(promise) {
214
- void promise;
212
+ void promise
215
213
  },
216
214
  }),
217
215
  ),
218
216
  ),
219
217
  {},
220
218
  { responseHeaders: proxyResponseHeaders },
221
- );
219
+ )
222
220
 
223
- const scopedCookies = getSetCookie(proxyResponseHeaders);
221
+ const scopedCookies = getSetCookie(proxyResponseHeaders)
224
222
  if (scopedCookies.length > 0) {
225
223
  // No explicit return means an implicit NextResponse.next(): synthesize one
226
224
  // so the emitted Set-Cookie survives while the request still continues.
227
- if (!response) response = NextResponse.next();
228
- for (const cookie of scopedCookies) response.headers.append('set-cookie', cookie);
225
+ if (!response) response = NextResponse.next()
226
+ for (const cookie of scopedCookies) response.headers.append('set-cookie', cookie)
229
227
  }
230
228
 
231
- if (!response) return { request };
229
+ if (!response) return { request }
232
230
 
233
231
  // Same-origin middleware redirects follow the app's trailing-slash rule,
234
232
  // exactly like a direct navigation would (Next normalizes the Location).
235
233
  // skipTrailingSlashRedirect and cross-origin targets are left untouched.
236
- response = normalizeRedirectLocation(response, url, config);
234
+ response = normalizeRedirectLocation(response, url, config)
237
235
 
238
- const meta = nextResponseMeta(response);
239
- if (!meta) return response;
236
+ const meta = nextResponseMeta(response)
237
+ if (!meta) return response
240
238
  const forwardedRequest = forwardMiddlewareRequestHeaders(
241
239
  response,
242
240
  applyProxyCookies(applyRequestOverride(request, meta.requestHeaders), response),
243
- );
241
+ )
244
242
  if (meta.kind === 'rewrite' && meta.url) {
245
- let rewritten = rewriteRequest(forwardedRequest, meta.url);
246
- const rewrittenUrl = new URL(rewritten.url);
243
+ let rewritten = rewriteRequest(forwardedRequest, meta.url)
244
+ const rewrittenUrl = new URL(rewritten.url)
247
245
  // A rewrite to another origin is proxied: the response for THIS request
248
246
  // comes from the external server (Next's router-server does the same for
249
247
  // any middleware rewrite whose destination carries a protocol).
@@ -251,51 +249,51 @@ export function createProxyRunner(
251
249
  // An RSC fetch's `_rsc` cache-buster must ride along: the external
252
250
  // server cannot recover it from the original URL, and the router keys
253
251
  // its response on it. Only added when the destination lacks its own.
254
- const rscHash = url.searchParams.get('_rsc');
252
+ const rscHash = url.searchParams.get('_rsc')
255
253
  if (rscHash !== null && !rewrittenUrl.searchParams.has('_rsc')) {
256
- rewrittenUrl.searchParams.set('_rsc', rscHash);
257
- rewritten = new Request(rewrittenUrl, rewritten);
254
+ rewrittenUrl.searchParams.set('_rsc', rscHash)
255
+ rewritten = new Request(rewrittenUrl, rewritten)
258
256
  }
259
- getProxyExtensions().onExternalRewrite(rewritten);
257
+ getProxyExtensions().onExternalRewrite(rewritten)
260
258
  // The forwarded request still carries the ORIGINAL Host header (the
261
259
  // local server); Bun uses it for SNI/verification, so an https target
262
260
  // fails certificate checks. Drop it and let fetch derive Host from the
263
261
  // target URL, like Next's external-rewrite proxying.
264
- const externalHeaders = new Headers(rewritten.headers);
265
- externalHeaders.delete('host');
266
- const external = await fetch(new Request(rewritten, { headers: externalHeaders }));
267
- const headers = new Headers(external.headers);
268
- headers.delete('content-encoding');
269
- headers.delete('content-length');
270
- headers.delete('transfer-encoding');
262
+ const externalHeaders = new Headers(rewritten.headers)
263
+ externalHeaders.delete('host')
264
+ const external = await fetch(new Request(rewritten, { headers: externalHeaders }))
265
+ const headers = new Headers(external.headers)
266
+ headers.delete('content-encoding')
267
+ headers.delete('content-length')
268
+ headers.delete('transfer-encoding')
271
269
  const proxied = new Response(external.body, {
272
270
  status: external.status,
273
271
  statusText: external.statusText,
274
272
  headers,
275
- });
276
- copyMiddlewareHeaders(response, proxied);
277
- return proxied;
273
+ })
274
+ copyMiddlewareHeaders(response, proxied)
275
+ return proxied
278
276
  }
279
277
  if (rewrittenUrl.origin === url.origin) {
280
- proxyRewriteObserver?.(url, rewrittenUrl);
278
+ proxyRewriteObserver?.(url, rewrittenUrl)
281
279
  if (request.headers.get('x-nextjs-data') === '1') {
282
- response.headers.set('x-nextjs-rewrite', rewrittenUrl.href);
280
+ response.headers.set('x-nextjs-rewrite', rewrittenUrl.href)
283
281
  }
284
282
  }
285
- return { request: rewritten, response };
283
+ return { request: rewritten, response }
286
284
  }
287
285
 
288
- return { request: forwardedRequest, response };
289
- };
286
+ return { request: forwardedRequest, response }
287
+ }
290
288
 
291
289
  runner.warm = (options = {}) => {
292
- if (!file) return;
290
+ if (!file) return
293
291
  // A failure surfaces on the first request, which awaits this same promise;
294
292
  // the swallow here only keeps the unawaited warm call from going unhandled.
295
- void proxyModule(options).catch(() => undefined);
296
- };
293
+ void proxyModule(options).catch(() => undefined)
294
+ }
297
295
 
298
- return runner;
296
+ return runner
299
297
  }
300
298
 
301
299
  // Apply the app's trailing-slash rule to a same-origin redirect emitted by the
@@ -303,96 +301,96 @@ export function createProxyRunner(
303
301
  // `trailingSlash: true` must land on `/somewhere/`). Cross-origin targets, the
304
302
  // skipTrailingSlashRedirect opt-out, and non-redirect responses pass through.
305
303
  function normalizeRedirectLocation(response: Response, requestUrl: URL, config: ResolvedConfig) {
306
- if (config.skipTrailingSlashRedirect || !config.trailingSlash) return response;
307
- if (response.status < 300 || response.status >= 400) return response;
308
- const location = response.headers.get('location');
309
- if (!location) return response;
310
- let target: URL;
304
+ if (config.skipTrailingSlashRedirect || !config.trailingSlash) return response
305
+ if (response.status < 300 || response.status >= 400) return response
306
+ const location = response.headers.get('location')
307
+ if (!location) return response
308
+ let target: URL
311
309
  try {
312
- target = new URL(location, requestUrl);
310
+ target = new URL(location, requestUrl)
313
311
  } catch {
314
- return response;
312
+ return response
315
313
  }
316
- if (target.origin !== requestUrl.origin) return response;
317
- const normalized = canonicalTrailingSlashPath(target.pathname, true);
318
- if (normalized === target.pathname) return response;
319
- target.pathname = normalized;
314
+ if (target.origin !== requestUrl.origin) return response
315
+ const normalized = canonicalTrailingSlashPath(target.pathname, true)
316
+ if (normalized === target.pathname) return response
317
+ target.pathname = normalized
320
318
  try {
321
- response.headers.set('location', target.href);
322
- return response;
319
+ response.headers.set('location', target.href)
320
+ return response
323
321
  } catch {
324
- const headers = new Headers(response.headers);
325
- headers.set('location', target.href);
322
+ const headers = new Headers(response.headers)
323
+ headers.set('location', target.href)
326
324
  return new Response(response.body, {
327
325
  status: response.status,
328
326
  statusText: response.statusText,
329
327
  headers,
330
- });
328
+ })
331
329
  }
332
330
  }
333
331
 
334
332
  // Human label for the truncation warning ("10MB", "500KB") — whole units only,
335
333
  // mirroring Next's log line ("Request body exceeded 10MB for /api/echo").
336
334
  function formatBodyLimit(bytes: number): string {
337
- if (bytes >= 1024 * 1024 && bytes % (1024 * 1024) === 0) return `${bytes / (1024 * 1024)}MB`;
338
- if (bytes >= 1024 && bytes % 1024 === 0) return `${bytes / 1024}KB`;
339
- return `${bytes}B`;
335
+ if (bytes >= 1024 * 1024 && bytes % (1024 * 1024) === 0) return `${bytes / (1024 * 1024)}MB`
336
+ if (bytes >= 1024 && bytes % 1024 === 0) return `${bytes / 1024}KB`
337
+ return `${bytes}B`
340
338
  }
341
339
 
342
340
  async function bufferProxyRequestBody(request: Request, pathname: string): Promise<Request> {
343
- if (request.method === 'GET' || request.method === 'HEAD' || !request.body) return request;
344
- const limit = getProxyExtensions().clientMaxBodySize();
345
- const chunks: Uint8Array[] = [];
346
- let total = 0;
347
- let truncated = false;
348
- const reader = request.body.getReader();
341
+ if (request.method === 'GET' || request.method === 'HEAD' || !request.body) return request
342
+ const limit = getProxyExtensions().clientMaxBodySize()
343
+ const chunks: Uint8Array[] = []
344
+ let total = 0
345
+ let truncated = false
346
+ const reader = request.body.getReader()
349
347
  for (;;) {
350
- const { done, value } = await reader.read();
351
- if (done) break;
348
+ const { done, value } = await reader.read()
349
+ if (done) break
352
350
  if (!truncated && total + value.byteLength > limit) {
353
- const keep = limit - total;
354
- if (keep > 0) chunks.push(value.subarray(0, keep));
355
- total = limit;
356
- truncated = true;
351
+ const keep = limit - total
352
+ if (keep > 0) chunks.push(value.subarray(0, keep))
353
+ total = limit
354
+ truncated = true
357
355
  // Keep draining (and discarding) the rest of the upload — cancelling the
358
356
  // stream mid-upload stalls the connection and the response never flushes.
359
- continue;
357
+ continue
360
358
  }
361
359
  if (!truncated) {
362
- chunks.push(value);
363
- total += value.byteLength;
360
+ chunks.push(value)
361
+ total += value.byteLength
364
362
  }
365
363
  }
366
364
  if (truncated) {
367
- console.warn(`Request body exceeded ${formatBodyLimit(limit)} for ${pathname}`);
365
+ console.warn(`Request body exceeded ${formatBodyLimit(limit)} for ${pathname}`)
368
366
  }
369
- const body = new Uint8Array(total);
370
- let offset = 0;
367
+ const body = new Uint8Array(total)
368
+ let offset = 0
371
369
  for (const chunk of chunks) {
372
- body.set(chunk, offset);
373
- offset += chunk.byteLength;
370
+ body.set(chunk, offset)
371
+ offset += chunk.byteLength
374
372
  }
375
- const headers = new Headers(request.headers);
376
- headers.set('content-length', String(total));
373
+ const headers = new Headers(request.headers)
374
+ headers.set('content-length', String(total))
377
375
  return new Request(request.url, {
378
376
  method: request.method,
379
377
  headers,
380
378
  body,
381
379
  // @ts-expect-error Bun/Node fetch option for streaming request bodies.
382
380
  duplex: 'half',
383
- });
381
+ })
384
382
  }
385
383
 
386
384
  export function applyProxyResponse(response: Response, proxyResponse?: Response) {
387
- if (proxyResponse) copyMiddlewareHeaders(proxyResponse, response);
388
- return response;
385
+ if (proxyResponse) copyMiddlewareHeaders(proxyResponse, response)
386
+ return response
389
387
  }
390
388
 
391
389
  export function proxyRoutePatterns(config: ProxyConfig | undefined) {
392
- const matcher = config?.matcher;
393
- if (!matcher) return ['^/(.*)$'];
394
- const matchers = Array.isArray(matcher) ? matcher : [matcher];
395
- return matchers.map(item => `^${matcherPattern(matcherSource(item))}$`);
390
+ const matcher = config?.matcher
391
+ if (!matcher) return ['^/(.*)$']
392
+ const matchers = Array.isArray(matcher) ? matcher : [matcher]
393
+ return matchers.map(item => `^${matcherPattern(matcherSource(item))}$`)
396
394
  }
397
395
 
398
396
  async function importProxyModule(
@@ -407,14 +405,14 @@ async function importProxyModule(
407
405
  externalLoadTarget: proxyExternalLoadTarget(file),
408
406
  reactServerLayer: true,
409
407
  })
410
- : (runnerOptions.compiledModuleHref ?? pathToFileHref(file));
411
- return import(href) as Promise<ProxyModule>;
408
+ : (runnerOptions.compiledModuleHref ?? pathToFileHref(file))
409
+ return import(href) as Promise<ProxyModule>
412
410
  }
413
411
 
414
412
  function proxyBases(config: ResolvedConfig) {
415
413
  return config.appPath === path.join(config.root, 'src', 'app')
416
414
  ? [path.join(config.root, 'src'), config.root]
417
- : [config.root];
415
+ : [config.root]
418
416
  }
419
417
 
420
418
  /**
@@ -423,11 +421,11 @@ function proxyBases(config: ResolvedConfig) {
423
421
  */
424
422
  function proxyMatcherGateEnabled() {
425
423
  // eslint-disable-next-line turbo/no-undeclared-env-vars
426
- return process.env.PNEXT_PROXY_MATCHER_GATE !== '0';
424
+ return process.env.PNEXT_PROXY_MATCHER_GATE !== '0'
427
425
  }
428
426
 
429
427
  /** Parsed matchers per proxy file, keyed on the source's size+mtime. */
430
- const staticMatcherCache = new Map<string, { key: string; matchers?: CompiledMatcher[] }>();
428
+ const staticMatcherCache = new Map<string, { key: string; matchers?: CompiledMatcher[] }>()
431
429
 
432
430
  /**
433
431
  * Compile the matchers of `export const config` off the proxy source itself. Only a wholly literal config
@@ -436,159 +434,159 @@ const staticMatcherCache = new Map<string, { key: string; matchers?: CompiledMat
436
434
  * literal `config` yields undefined, and the caller falls back to the imported module's config.
437
435
  */
438
436
  function staticProxyMatchers(file: string): CompiledMatcher[] | undefined {
439
- let key: string;
437
+ let key: string
440
438
  try {
441
- const stats = statSync(file);
442
- key = `${stats.size}:${stats.mtimeMs}`;
439
+ const stats = statSync(file)
440
+ key = `${stats.size}:${stats.mtimeMs}`
443
441
  } catch {
444
- return undefined;
442
+ return undefined
445
443
  }
446
- const cached = staticMatcherCache.get(file);
447
- if (cached?.key === key) return cached.matchers;
448
- let matchers: CompiledMatcher[] | undefined;
444
+ const cached = staticMatcherCache.get(file)
445
+ if (cached?.key === key) return cached.matchers
446
+ let matchers: CompiledMatcher[] | undefined
449
447
  try {
450
- const config = staticProxyConfig(file, readFileSync(file, 'utf8'));
451
- if (config) matchers = proxyMatchers(config);
448
+ const config = staticProxyConfig(file, readFileSync(file, 'utf8'))
449
+ if (config) matchers = proxyMatchers(config)
452
450
  } catch {
453
- matchers = undefined;
451
+ matchers = undefined
454
452
  }
455
- staticMatcherCache.set(file, { key, matchers });
456
- return matchers;
453
+ staticMatcherCache.set(file, { key, matchers })
454
+ return matchers
457
455
  }
458
456
 
459
457
  function staticProxyConfig(file: string, source: string): ProxyConfig | undefined {
460
- const result = parseSync(file, source, { lang: parserLang(file) });
458
+ const result = parseSync(file, source, { lang: parserLang(file) })
461
459
  // A recovered parse may have dropped the very declaration we are reading.
462
- if (result.errors.length > 0) return undefined;
460
+ if (result.errors.length > 0) return undefined
463
461
  for (const statement of result.program.body as StaticNode[]) {
464
- if (statement.type !== 'ExportNamedDeclaration') continue;
465
- const declaration = statement.declaration;
466
- if (declaration?.type !== 'VariableDeclaration') continue;
462
+ if (statement.type !== 'ExportNamedDeclaration') continue
463
+ const declaration = statement.declaration
464
+ if (declaration?.type !== 'VariableDeclaration') continue
467
465
  for (const declarator of declaration.declarations ?? []) {
468
- if (declarator.id?.type !== 'Identifier' || declarator.id.name !== 'config') continue;
469
- const value = staticValue(declarator.init);
470
- return isProxyConfigShape(value) ? (value as ProxyConfig) : undefined;
466
+ if (declarator.id?.type !== 'Identifier' || declarator.id.name !== 'config') continue
467
+ const value = staticValue(declarator.init)
468
+ return isProxyConfigShape(value) ? (value as ProxyConfig) : undefined
471
469
  }
472
470
  }
473
- return undefined;
471
+ return undefined
474
472
  }
475
473
 
476
474
  function parserLang(file: string) {
477
- const ext = path.extname(file);
478
- if (ext === '.tsx') return 'tsx';
479
- if (ext === '.jsx') return 'jsx';
480
- return ext === '.js' || ext === '.mjs' ? 'js' : 'ts';
475
+ const ext = path.extname(file)
476
+ if (ext === '.tsx') return 'tsx'
477
+ if (ext === '.jsx') return 'jsx'
478
+ return ext === '.js' || ext === '.mjs' ? 'js' : 'ts'
481
479
  }
482
480
 
483
481
  /** Structural view of the oxc AST nodes this file reads — no full type import. */
484
482
  interface StaticNode {
485
- type: string;
486
- name?: string;
487
- value?: unknown;
488
- computed?: boolean;
489
- shorthand?: boolean;
490
- key?: StaticNode;
491
- init?: StaticNode;
492
- id?: StaticNode;
493
- declaration?: StaticNode;
494
- declarations?: StaticNode[];
495
- expression?: StaticNode;
496
- properties?: StaticNode[];
497
- elements?: (StaticNode | null)[];
498
- expressions?: StaticNode[];
499
- quasis?: { value?: { cooked?: string } }[];
483
+ type: string
484
+ name?: string
485
+ value?: unknown
486
+ computed?: boolean
487
+ shorthand?: boolean
488
+ key?: StaticNode
489
+ init?: StaticNode
490
+ id?: StaticNode
491
+ declaration?: StaticNode
492
+ declarations?: StaticNode[]
493
+ expression?: StaticNode
494
+ properties?: StaticNode[]
495
+ elements?: (StaticNode | null)[]
496
+ expressions?: StaticNode[]
497
+ quasis?: { value?: { cooked?: string } }[]
500
498
  }
501
499
 
502
500
  /** Literal-only evaluation; `undefined` marks "not statically known". */
503
501
  function staticValue(node: StaticNode | undefined | null): unknown {
504
- if (!node) return undefined;
502
+ if (!node) return undefined
505
503
  switch (node.type) {
506
504
  // `… as const` / `… satisfies ProxyConfig` wrap the literal, they never change it.
507
505
  case 'TSAsExpression':
508
506
  case 'TSSatisfiesExpression':
509
507
  case 'TSNonNullExpression':
510
- return staticValue(node.expression);
508
+ return staticValue(node.expression)
511
509
  case 'Literal':
512
510
  case 'StringLiteral':
513
511
  case 'NumericLiteral':
514
512
  case 'BooleanLiteral':
515
513
  // A regex literal reports `value: null` here; it is not a matcher shape.
516
- return node.value === null ? undefined : node.value;
514
+ return node.value === null ? undefined : node.value
517
515
  case 'TemplateLiteral':
518
516
  return node.expressions?.length === 0
519
517
  ? (node.quasis?.[0]?.value?.cooked ?? undefined)
520
- : undefined;
518
+ : undefined
521
519
  case 'ArrayExpression': {
522
- const items: unknown[] = [];
520
+ const items: unknown[] = []
523
521
  for (const element of node.elements ?? []) {
524
- const value = staticValue(element);
525
- if (value === undefined) return undefined;
526
- items.push(value);
522
+ const value = staticValue(element)
523
+ if (value === undefined) return undefined
524
+ items.push(value)
527
525
  }
528
- return items;
526
+ return items
529
527
  }
530
528
  case 'ObjectExpression': {
531
- const object: Record<string, unknown> = {};
529
+ const object: Record<string, unknown> = {}
532
530
  for (const property of node.properties ?? []) {
533
- if (property.type !== 'Property' && property.type !== 'ObjectProperty') return undefined;
534
- if (property.computed) return undefined;
531
+ if (property.type !== 'Property' && property.type !== 'ObjectProperty') return undefined
532
+ if (property.computed) return undefined
535
533
  const key =
536
- property.key?.type === 'Identifier' ? property.key.name : (property.key?.value as string);
537
- if (typeof key !== 'string') return undefined;
538
- const value = staticValue(property.value as StaticNode | undefined);
539
- if (value === undefined) return undefined;
540
- object[key] = value;
534
+ property.key?.type === 'Identifier' ? property.key.name : (property.key?.value as string)
535
+ if (typeof key !== 'string') return undefined
536
+ const value = staticValue(property.value as StaticNode | undefined)
537
+ if (value === undefined) return undefined
538
+ object[key] = value
541
539
  }
542
- return object;
540
+ return object
543
541
  }
544
542
  default:
545
- return undefined;
543
+ return undefined
546
544
  }
547
545
  }
548
546
 
549
547
  /** Only a config whose `matcher` is exactly the documented shape may gate. */
550
548
  function isProxyConfigShape(value: unknown): boolean {
551
- if (typeof value !== 'object' || value === null) return false;
552
- const matcher = (value as { matcher?: unknown }).matcher;
553
- if (matcher === undefined) return true;
554
- const items = Array.isArray(matcher) ? matcher : [matcher];
549
+ if (typeof value !== 'object' || value === null) return false
550
+ const matcher = (value as { matcher?: unknown }).matcher
551
+ if (matcher === undefined) return true
552
+ const items = Array.isArray(matcher) ? matcher : [matcher]
555
553
  return items.every(item => {
556
- if (typeof item === 'string') return true;
557
- if (typeof item !== 'object' || item === null) return false;
558
- const { source, has, missing } = item as Record<string, unknown>;
559
- if (typeof source !== 'string') return false;
554
+ if (typeof item === 'string') return true
555
+ if (typeof item !== 'object' || item === null) return false
556
+ const { source, has, missing } = item as Record<string, unknown>
557
+ if (typeof source !== 'string') return false
560
558
  return [has, missing].every(
561
559
  list => list === undefined || (Array.isArray(list) && list.every(isConditionShape)),
562
- );
563
- });
560
+ )
561
+ })
564
562
  }
565
563
 
566
564
  function isConditionShape(value: unknown): boolean {
567
- if (typeof value !== 'object' || value === null) return false;
568
- const { type, key, value: expected } = value as Record<string, unknown>;
569
- if (type !== 'header' && type !== 'query' && type !== 'cookie' && type !== 'host') return false;
570
- if (key !== undefined && typeof key !== 'string') return false;
571
- return expected === undefined || typeof expected === 'string';
565
+ if (typeof value !== 'object' || value === null) return false
566
+ const { type, key, value: expected } = value as Record<string, unknown>
567
+ if (type !== 'header' && type !== 'query' && type !== 'cookie' && type !== 'host') return false
568
+ if (key !== undefined && typeof key !== 'string') return false
569
+ return expected === undefined || typeof expected === 'string'
572
570
  }
573
571
 
574
572
  function proxyMatchers(config: ProxyConfig | undefined): CompiledMatcher[] {
575
- const matcher = config?.matcher;
576
- if (!matcher) return [{ regex: /.*/ }];
577
- const matchers = Array.isArray(matcher) ? matcher : [matcher];
573
+ const matcher = config?.matcher
574
+ if (!matcher) return [{ regex: /.*/ }]
575
+ const matchers = Array.isArray(matcher) ? matcher : [matcher]
578
576
  return matchers.map(item => ({
579
577
  regex: matcherRegex(matcherSource(item)),
580
578
  ...(typeof item === 'object' && item.has ? { has: item.has } : {}),
581
579
  ...(typeof item === 'object' && item.missing ? { missing: item.missing } : {}),
582
- }));
580
+ }))
583
581
  }
584
582
 
585
583
  function matchesProxy(matchers: CompiledMatcher[], url: URL, request: Request) {
586
- const decoded = decodePathSeparators(url.pathname);
584
+ const decoded = decodePathSeparators(url.pathname)
587
585
  return matchers.some(
588
586
  matcher =>
589
587
  (matcher.regex.test(url.pathname) || matcher.regex.test(decoded)) &&
590
588
  matchesConditions(matcher, url, request),
591
- );
589
+ )
592
590
  }
593
591
 
594
592
  // A matcher applies only when every `has` condition is present and no `missing`
@@ -597,89 +595,85 @@ function matchesProxy(matchers: CompiledMatcher[], url: URL, request: Request) {
597
595
  // opts out of running for prefetch requests.
598
596
  function matchesConditions(matcher: CompiledMatcher, url: URL, request: Request) {
599
597
  if (matcher.has && !matcher.has.every(condition => hasCondition(condition, url, request))) {
600
- return false;
598
+ return false
601
599
  }
602
600
  if (matcher.missing?.some(condition => hasCondition(condition, url, request))) {
603
- return false;
601
+ return false
604
602
  }
605
- return true;
603
+ return true
606
604
  }
607
605
 
608
606
  function hasCondition(condition: ProxyRouteCondition, url: URL, request: Request): boolean {
609
- const actual = conditionValue(condition, url, request);
610
- if (actual === null) return false;
611
- if (condition.value === undefined) return true;
607
+ const actual = conditionValue(condition, url, request)
608
+ if (actual === null) return false
609
+ if (condition.value === undefined) return true
612
610
  try {
613
- return new RegExp(`^${condition.value}$`).test(actual);
611
+ return new RegExp(`^${condition.value}$`).test(actual)
614
612
  } catch {
615
- return condition.value === actual;
613
+ return condition.value === actual
616
614
  }
617
615
  }
618
616
 
619
- function conditionValue(
620
- condition: ProxyRouteCondition,
621
- url: URL,
622
- request: Request,
623
- ): string | null {
617
+ function conditionValue(condition: ProxyRouteCondition, url: URL, request: Request): string | null {
624
618
  switch (condition.type) {
625
619
  case 'header':
626
- return condition.key ? request.headers.get(condition.key) : null;
620
+ return condition.key ? request.headers.get(condition.key) : null
627
621
  case 'query':
628
- return condition.key ? url.searchParams.get(condition.key) : null;
622
+ return condition.key ? url.searchParams.get(condition.key) : null
629
623
  case 'cookie': {
630
- if (!condition.key) return null;
624
+ if (!condition.key) return null
631
625
  const cookie = parseCookies(request.headers.get('cookie') ?? '').find(
632
626
  item => item.name === condition.key,
633
- );
634
- return cookie ? cookie.value : null;
627
+ )
628
+ return cookie ? cookie.value : null
635
629
  }
636
630
  case 'host':
637
- return url.host;
631
+ return url.host
638
632
  default:
639
- return null;
633
+ return null
640
634
  }
641
635
  }
642
636
 
643
637
  function decodePathSeparators(pathname: string) {
644
- return pathname.replace(/%2f/gi, '/');
638
+ return pathname.replace(/%2f/gi, '/')
645
639
  }
646
640
 
647
641
  function matcherSource(matcher: ProxyMatcher) {
648
- return typeof matcher === 'string' ? matcher : matcher.source;
642
+ return typeof matcher === 'string' ? matcher : matcher.source
649
643
  }
650
644
 
651
645
  function matcherRegex(matcher: string) {
652
- return new RegExp(`^${matcherPattern(matcher)}$`);
646
+ return new RegExp(`^${matcherPattern(matcher)}$`)
653
647
  }
654
648
 
655
649
  function matcherPattern(matcher: string) {
656
- if (matcher.includes('(')) return matcher;
657
- if (matcher === '/') return '/';
650
+ if (matcher.includes('(')) return matcher
651
+ if (matcher === '/') return '/'
658
652
 
659
- let source = '';
653
+ let source = ''
660
654
  for (const segment of matcher.split('/').filter(Boolean)) {
661
655
  if (/^:[^/]+\*$/.test(segment)) {
662
- source += '(?:/.*)?';
656
+ source += '(?:/.*)?'
663
657
  } else if (/^:[^/]+$/.test(segment)) {
664
- source += '/[^/]+';
658
+ source += '/[^/]+'
665
659
  } else {
666
- source += `/${escapeRegex(segment)}`;
660
+ source += `/${escapeRegex(segment)}`
667
661
  }
668
662
  }
669
- return source || '/';
663
+ return source || '/'
670
664
  }
671
665
 
672
666
  function rewriteRequest(request: Request, url: string) {
673
- return new Request(new URL(url, request.url), request);
667
+ return new Request(new URL(url, request.url), request)
674
668
  }
675
669
 
676
670
  // Drop `?_rsc=<hash>` from the request the middleware handler sees. GET/HEAD
677
671
  // only ever carry it (router fetches), so re-wrapping the Request is body-safe.
678
672
  function stripRscUnionQuery(request: Request): Request {
679
- const url = new URL(request.url);
680
- if (!url.searchParams.has('_rsc')) return request;
681
- url.searchParams.delete('_rsc');
682
- return new Request(url, request);
673
+ const url = new URL(request.url)
674
+ if (!url.searchParams.has('_rsc')) return request
675
+ url.searchParams.delete('_rsc')
676
+ return new Request(url, request)
683
677
  }
684
678
 
685
679
  // The app-router flight headers Next removes from the request middleware sees
@@ -691,66 +685,66 @@ const FLIGHT_HEADERS = [
691
685
  'next-router-prefetch',
692
686
  'next-hmr-refresh',
693
687
  'next-router-segment-prefetch',
694
- ];
688
+ ]
695
689
 
696
690
  // Drop the flight headers from the request the middleware handler sees. GET/HEAD
697
691
  // router fetches carry them, so re-wrapping the Request is body-safe.
698
692
  function stripFlightHeaders(request: Request): Request {
699
- if (!FLIGHT_HEADERS.some(header => request.headers.has(header))) return request;
700
- const headers = new Headers(request.headers);
701
- for (const header of FLIGHT_HEADERS) headers.delete(header);
702
- return new Request(request, { headers });
693
+ if (!FLIGHT_HEADERS.some(header => request.headers.has(header))) return request
694
+ const headers = new Headers(request.headers)
695
+ for (const header of FLIGHT_HEADERS) headers.delete(header)
696
+ return new Request(request, { headers })
703
697
  }
704
698
 
705
699
  function applyRequestOverride(request: Request, headers: Headers | undefined) {
706
- if (!headers) return request;
707
- return new Request(request, { headers });
700
+ if (!headers) return request
701
+ return new Request(request, { headers })
708
702
  }
709
703
 
710
704
  function applyProxyCookies(request: Request, response: Response) {
711
- const setCookies = getSetCookie(response.headers);
712
- if (setCookies.length === 0) return request;
705
+ const setCookies = getSetCookie(response.headers)
706
+ if (setCookies.length === 0) return request
713
707
 
714
- const cookies = parseCookies(request.headers.get('cookie') ?? '');
708
+ const cookies = parseCookies(request.headers.get('cookie') ?? '')
715
709
  for (const header of setCookies) {
716
- const cookie = parseSetCookie(header);
717
- if (!cookie) continue;
718
- const index = cookies.findIndex(item => item.name === cookie.name);
710
+ const cookie = parseSetCookie(header)
711
+ if (!cookie) continue
712
+ const index = cookies.findIndex(item => item.name === cookie.name)
719
713
  if (cookie.deleted) {
720
- if (index !== -1) cookies.splice(index, 1);
721
- continue;
714
+ if (index !== -1) cookies.splice(index, 1)
715
+ continue
722
716
  }
723
- if (index === -1) cookies.push({ name: cookie.name, value: cookie.value });
724
- else cookies[index] = { name: cookie.name, value: cookie.value };
717
+ if (index === -1) cookies.push({ name: cookie.name, value: cookie.value })
718
+ else cookies[index] = { name: cookie.name, value: cookie.value }
725
719
  }
726
720
 
727
- const headers = new Headers(request.headers);
728
- const cookieHeader = requestCookieHeader(cookies);
729
- if (cookieHeader) headers.set('cookie', cookieHeader);
730
- else headers.delete('cookie');
731
- return new Request(request, { headers });
721
+ const headers = new Headers(request.headers)
722
+ const cookieHeader = requestCookieHeader(cookies)
723
+ if (cookieHeader) headers.set('cookie', cookieHeader)
724
+ else headers.delete('cookie')
725
+ return new Request(request, { headers })
732
726
  }
733
727
 
734
728
  function parseSetCookie(header: string) {
735
- const [pair = '', ...attributes] = header.split(';').map(part => part.trim());
736
- const [name = '', ...valueParts] = pair.split('=');
737
- if (!name) return undefined;
738
- const deleted = attributes.some(attribute => /^max-age=0$/i.test(attribute));
739
- return { name: decodeCookiePart(name), value: decodeCookiePart(valueParts.join('=')), deleted };
729
+ const [pair = '', ...attributes] = header.split(';').map(part => part.trim())
730
+ const [name = '', ...valueParts] = pair.split('=')
731
+ if (!name) return undefined
732
+ const deleted = attributes.some(attribute => /^max-age=0$/i.test(attribute))
733
+ return { name: decodeCookiePart(name), value: decodeCookiePart(valueParts.join('=')), deleted }
740
734
  }
741
735
 
742
736
  function decodeCookiePart(value: string) {
743
737
  try {
744
- return decodeURIComponent(value);
738
+ return decodeURIComponent(value)
745
739
  } catch {
746
- return value;
740
+ return value
747
741
  }
748
742
  }
749
743
 
750
744
  function escapeRegex(value: string) {
751
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
745
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
752
746
  }
753
747
 
754
748
  function proxyModuleKey(options: ProxyRunOptions) {
755
- return options.dev ? `dev:${options.devImportVersion ?? 'dev'}` : 'prod';
749
+ return options.dev ? `dev:${options.devImportVersion ?? 'dev'}` : 'prod'
756
750
  }