@wular/pnext 0.1.6 → 0.1.8

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 (337) hide show
  1. package/bin/pnext +9 -2
  2. package/dist/server/_chunks/aliases-pycbtjt1.js +46 -0
  3. package/dist/server/_chunks/analyze-4d9e00g9.js +449 -0
  4. package/dist/server/_chunks/boot-bhemypxz.js +38 -0
  5. package/dist/server/_chunks/build-c991dv65.js +86 -0
  6. package/dist/server/_chunks/build-kh5e3x48.js +3341 -0
  7. package/dist/server/_chunks/build-tier-0a96kmx3.js +2456 -0
  8. package/dist/server/_chunks/compile-040r79gj.js +22 -0
  9. package/dist/server/_chunks/config-0tvz03a6.js +24 -0
  10. package/dist/server/_chunks/config-27rj7830.js +36 -0
  11. package/dist/server/_chunks/create-9rvwshsp.js +135 -0
  12. package/dist/server/_chunks/dev-ex9exynt.js +220 -0
  13. package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
  14. package/dist/server/_chunks/generate-myw9hef7.js +22 -0
  15. package/dist/server/_chunks/index-0r5eqfc7.js +279 -0
  16. package/dist/server/_chunks/index-0yjv5v47.js +105 -0
  17. package/dist/server/_chunks/index-11xpbfej.js +17 -0
  18. package/dist/server/_chunks/index-141vcwk6.js +109 -0
  19. package/dist/server/_chunks/index-1pzm1hdy.js +4130 -0
  20. package/dist/server/_chunks/index-29pq0kax.js +590 -0
  21. package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
  22. package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
  23. package/dist/server/_chunks/index-38xpdxwd.js +194 -0
  24. package/dist/server/_chunks/index-3e075kny.js +128 -0
  25. package/dist/server/_chunks/index-3ycf5ckv.js +472 -0
  26. package/dist/server/_chunks/index-4399bvd2.js +18 -0
  27. package/dist/server/_chunks/index-4da76t62.js +297 -0
  28. package/dist/server/_chunks/index-4t92hdxd.js +172 -0
  29. package/dist/server/_chunks/index-4zzebszd.js +10 -0
  30. package/dist/server/_chunks/index-52k54ykj.js +95 -0
  31. package/dist/server/_chunks/index-5hr4062s.js +70 -0
  32. package/dist/server/_chunks/index-68m3mwbd.js +84 -0
  33. package/dist/server/_chunks/index-6b009mt0.js +56 -0
  34. package/dist/server/_chunks/index-6gex3pfa.js +15 -0
  35. package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
  36. package/dist/server/_chunks/index-6q7zvrap.js +134 -0
  37. package/dist/server/_chunks/index-71885zaq.js +284 -0
  38. package/dist/server/_chunks/index-73z4esab.js +38 -0
  39. package/dist/server/_chunks/index-79ngvam8.js +60 -0
  40. package/dist/server/_chunks/index-7wc9n8be.js +25 -0
  41. package/dist/server/_chunks/index-8ct7rqy3.js +198 -0
  42. package/dist/server/_chunks/index-8kcxdfya.js +206 -0
  43. package/dist/server/_chunks/index-9ch50vtq.js +18 -0
  44. package/dist/server/_chunks/index-9f49w76j.js +213 -0
  45. package/dist/server/_chunks/index-9hz3s0m8.js +851 -0
  46. package/dist/server/_chunks/index-akkrvjn6.js +535 -0
  47. package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
  48. package/dist/server/_chunks/index-b7j671dj.js +207 -0
  49. package/dist/server/_chunks/index-bcws5eh2.js +35 -0
  50. package/dist/server/_chunks/index-bzd2ef7t.js +10 -0
  51. package/dist/server/_chunks/index-cjgqs13g.js +65 -0
  52. package/dist/server/_chunks/index-ckkdpht5.js +41 -0
  53. package/dist/server/_chunks/index-cn86z041.js +296 -0
  54. package/dist/server/_chunks/index-cvr4z22m.js +92 -0
  55. package/dist/server/_chunks/index-cyfednwb.js +87 -0
  56. package/dist/server/_chunks/index-d158y67j.js +152 -0
  57. package/dist/server/_chunks/index-d1jsmhhk.js +955 -0
  58. package/dist/server/_chunks/index-dg0f05zs.js +199 -0
  59. package/dist/server/_chunks/index-dgr390q7.js +9438 -0
  60. package/dist/server/_chunks/index-drwv61cc.js +185 -0
  61. package/dist/server/_chunks/index-e3a6yx84.js +18 -0
  62. package/dist/server/_chunks/index-e88tyv35.js +45 -0
  63. package/dist/server/_chunks/index-en7n9f7m.js +22 -0
  64. package/dist/server/_chunks/index-entm8bmz.js +28 -0
  65. package/dist/server/_chunks/index-evhd413j.js +57 -0
  66. package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
  67. package/dist/server/_chunks/index-fjv96re1.js +5295 -0
  68. package/dist/server/_chunks/index-fn1chkkd.js +214 -0
  69. package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
  70. package/dist/server/_chunks/index-gcmj16xy.js +92 -0
  71. package/dist/server/_chunks/index-gkndxkxf.js +736 -0
  72. package/dist/server/_chunks/index-grta8ap3.js +238 -0
  73. package/dist/server/_chunks/index-h2a70tg4.js +7 -0
  74. package/dist/server/_chunks/index-h4xy648y.js +51 -0
  75. package/dist/server/_chunks/index-hdbwtdv2.js +352 -0
  76. package/dist/server/_chunks/index-he6n2bvp.js +1270 -0
  77. package/dist/server/_chunks/index-j0m1jxqa.js +1253 -0
  78. package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
  79. package/dist/server/_chunks/index-j681c48a.js +2530 -0
  80. package/dist/server/_chunks/index-jbj7ehef.js +50 -0
  81. package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
  82. package/dist/server/_chunks/index-jks0x0a1.js +14 -0
  83. package/dist/server/_chunks/index-jn9rbhrx.js +1599 -0
  84. package/dist/server/_chunks/index-jt8e1pje.js +12 -0
  85. package/dist/server/_chunks/index-kdhxpwyq.js +483 -0
  86. package/dist/server/_chunks/index-knp0s912.js +7 -0
  87. package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
  88. package/dist/server/_chunks/index-kresp2n8.js +445 -0
  89. package/dist/server/_chunks/index-m63czgq5.js +590 -0
  90. package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
  91. package/dist/server/_chunks/index-n4hxpng2.js +11 -0
  92. package/dist/server/_chunks/index-n629dy38.js +1071 -0
  93. package/dist/server/_chunks/index-nf3df4jy.js +266 -0
  94. package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
  95. package/dist/server/_chunks/index-pym1cezq.js +39 -0
  96. package/dist/server/_chunks/index-q3r9z8mq.js +213 -0
  97. package/dist/server/_chunks/index-q738kkhj.js +100 -0
  98. package/dist/server/_chunks/index-qcrvt6er.js +112 -0
  99. package/dist/server/_chunks/index-qjj6gddn.js +54 -0
  100. package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
  101. package/dist/server/_chunks/index-r97ptz1q.js +97 -0
  102. package/dist/server/_chunks/index-ras0sdab.js +26 -0
  103. package/dist/server/_chunks/index-rcs322t1.js +19 -0
  104. package/dist/server/_chunks/index-rgj5mx84.js +101 -0
  105. package/dist/server/_chunks/index-rjegyfx4.js +1435 -0
  106. package/dist/server/_chunks/index-rt9qq1va.js +4 -0
  107. package/dist/server/_chunks/index-rthrsed5.js +356 -0
  108. package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
  109. package/dist/server/_chunks/index-stbk3jhn.js +31 -0
  110. package/dist/server/_chunks/index-tf4j19ge.js +130 -0
  111. package/dist/server/_chunks/index-tgcakdxc.js +125 -0
  112. package/dist/server/_chunks/index-tgsfjmep.js +74 -0
  113. package/dist/server/_chunks/index-tq1f96v7.js +51 -0
  114. package/dist/server/_chunks/index-tq3b39a5.js +107 -0
  115. package/dist/server/_chunks/index-typcbcsv.js +819 -0
  116. package/dist/server/_chunks/index-v1ags1na.js +132 -0
  117. package/dist/server/_chunks/index-vmr35jjw.js +170 -0
  118. package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
  119. package/dist/server/_chunks/index-vz0km5qk.js +33 -0
  120. package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
  121. package/dist/server/_chunks/index-web361b8.js +138 -0
  122. package/dist/server/_chunks/index-wm36rj4v.js +311 -0
  123. package/dist/server/_chunks/index-x0y005nh.js +283 -0
  124. package/dist/server/_chunks/index-x2m17v9c.js +6166 -0
  125. package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
  126. package/dist/server/_chunks/index-x9c55pzy.js +871 -0
  127. package/dist/server/_chunks/index-xh1nbk46.js +1299 -0
  128. package/dist/server/_chunks/index-xvj80c3a.js +30 -0
  129. package/dist/server/_chunks/index-xywjg2vc.js +100 -0
  130. package/dist/server/_chunks/index-y4d02znn.js +66 -0
  131. package/dist/server/_chunks/index-y7mzvq2q.js +110 -0
  132. package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
  133. package/dist/server/_chunks/index-yhxkxghe.js +56 -0
  134. package/dist/server/_chunks/index-yrjkqtfj.js +86 -0
  135. package/dist/server/_chunks/index-z88qv16t.js +11 -0
  136. package/dist/server/_chunks/index-zfrwq472.js +154 -0
  137. package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
  138. package/dist/server/_chunks/loader-5en7wpt5.js +80 -0
  139. package/dist/server/_chunks/modules-t92favpj.js +76 -0
  140. package/dist/server/_chunks/pipeline-4t9q43ht.js +836 -0
  141. package/dist/server/_chunks/production-385bw8df.js +55 -0
  142. package/dist/server/_chunks/proxy-config-60gprphe.js +23 -0
  143. package/dist/server/_chunks/proxy-gfhmktbk.js +35 -0
  144. package/dist/server/_chunks/router-xnrva921.js +501 -0
  145. package/dist/server/_chunks/routes-ht868pdc.js +66 -0
  146. package/dist/server/_chunks/run-d40d63ag.js +697 -0
  147. package/dist/server/_chunks/server-2p8fgqq2.js +1839 -0
  148. package/dist/server/_chunks/tsconfig-defaults-bcn34eqb.js +21 -0
  149. package/dist/server/_chunks/typegen-dvtcjtaw.js +37 -0
  150. package/dist/server/api/client-cache.js +14 -0
  151. package/dist/server/cli/index.js +375 -0
  152. package/dist/server/cli/start.js +158 -0
  153. package/dist/server/client/reference.js +16 -0
  154. package/dist/server/compat/next/cache.js +56 -0
  155. package/dist/server/compat/next/canonical-url.js +13 -0
  156. package/dist/server/compat/next/client-cache.js +57 -0
  157. package/dist/server/compat/next/client-navigation.js +232 -0
  158. package/dist/server/compat/next/client-only.js +1 -0
  159. package/dist/server/compat/next/client-script.js +178 -0
  160. package/dist/server/compat/next/client-server.js +34 -0
  161. package/dist/server/compat/next/config-headers.js +34 -0
  162. package/dist/server/compat/next/config-loader.js +25 -0
  163. package/dist/server/compat/next/config.js +10 -0
  164. package/dist/server/compat/next/constants.js +18 -0
  165. package/dist/server/compat/next/custom-server.js +10 -0
  166. package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
  167. package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
  168. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
  169. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
  170. package/dist/server/compat/next/dynamic.js +21 -0
  171. package/dist/server/compat/next/error.js +112 -0
  172. package/dist/server/compat/next/font/cache.js +16 -0
  173. package/dist/server/compat/next/font/google.js +3 -0
  174. package/dist/server/compat/next/font/index.js +1 -0
  175. package/dist/server/compat/next/font/local.js +24 -0
  176. package/dist/server/compat/next/font/runtime-client.js +33 -0
  177. package/dist/server/compat/next/font/runtime.js +43 -0
  178. package/dist/server/compat/next/font/shared.js +22 -0
  179. package/dist/server/compat/next/form.js +129 -0
  180. package/dist/server/compat/next/head.js +10 -0
  181. package/dist/server/compat/next/headers.js +30 -0
  182. package/dist/server/compat/next/image/client.js +11 -0
  183. package/dist/server/compat/next/image/config.js +18 -0
  184. package/dist/server/compat/next/image/optimizer.js +25 -0
  185. package/dist/server/compat/next/image/patterns.js +12 -0
  186. package/dist/server/compat/next/image/props.js +16 -0
  187. package/dist/server/compat/next/image/shared.js +86 -0
  188. package/dist/server/compat/next/image/static-metadata.js +32 -0
  189. package/dist/server/compat/next/image/validate.js +8 -0
  190. package/dist/server/compat/next/image.js +59 -0
  191. package/dist/server/compat/next/index.js +1 -0
  192. package/dist/server/compat/next/legacy-image.js +78 -0
  193. package/dist/server/compat/next/legacy-request-apis.js +24 -0
  194. package/dist/server/compat/next/link-transform.js +15 -0
  195. package/dist/server/compat/next/link.js +14 -0
  196. package/dist/server/compat/next/navigation.js +191 -0
  197. package/dist/server/compat/next/offline.js +45 -0
  198. package/dist/server/compat/next/og.js +8 -0
  199. package/dist/server/compat/next/preferred-region.js +8 -0
  200. package/dist/server/compat/next/redirects.js +32 -0
  201. package/dist/server/compat/next/resource-hints.js +30 -0
  202. package/dist/server/compat/next/rewrites.js +43 -0
  203. package/dist/server/compat/next/root-params.js +121 -0
  204. package/dist/server/compat/next/route-state.js +23 -0
  205. package/dist/server/compat/next/router.js +103 -0
  206. package/dist/server/compat/next/script.js +37 -0
  207. package/dist/server/compat/next/server-only.js +1 -0
  208. package/dist/server/compat/next/server.js +131 -0
  209. package/dist/server/compat/next/svgr.js +14 -0
  210. package/dist/server/compat/next/telemetry.js +10 -0
  211. package/dist/server/compat/next/usage.js +13 -0
  212. package/dist/server/compat/next/user-agent.js +12 -0
  213. package/dist/server/compat/next/web-vitals.js +35 -0
  214. package/dist/server/compat/react/action-state.js +11 -0
  215. package/dist/server/compat/react/client-lite.js +83 -0
  216. package/dist/server/compat/react/client.js +131 -0
  217. package/dist/server/compat/react/compiler-runtime.js +42 -0
  218. package/dist/server/compat/react/dom-client.js +106 -0
  219. package/dist/server/compat/react/dom-react-server.js +37 -0
  220. package/dist/server/compat/react/dom-server.js +40 -0
  221. package/dist/server/compat/react/dom.js +52 -0
  222. package/dist/server/compat/react/hooks-extra.js +12 -0
  223. package/dist/server/compat/react/internals.js +14 -0
  224. package/dist/server/compat/react/parity.js +11 -0
  225. package/dist/server/compat/react/preact.js +113 -0
  226. package/dist/server/compat/react/react-server.js +133 -0
  227. package/dist/server/compat/react/router-shim.js +8 -0
  228. package/dist/server/compat/react/server-component-use.js +14 -0
  229. package/dist/server/compat/react/server-inserted-html.js +14 -0
  230. package/dist/server/compat/react/server.js +194 -0
  231. package/dist/server/compat/react/style-values.js +10 -0
  232. package/dist/server/compat/react/use.js +10 -0
  233. package/dist/server/compat/react/view-transition.js +12 -0
  234. package/dist/server/generation.json +1 -0
  235. package/package.json +4 -1
  236. package/reference/compat.md +1 -1
  237. package/reference/config.md +2 -2
  238. package/reference/dev.md +1 -1
  239. package/reference/getting-started.md +1 -1
  240. package/reference/rendering.md +4 -4
  241. package/src/api/dynamic.tsx +86 -4
  242. package/src/api/server.ts +24 -6
  243. package/src/cli/adapters/vercel-warm.ts +327 -62
  244. package/src/cli/adapters/vercel.ts +164 -1054
  245. package/src/cli/analyze.ts +3 -2
  246. package/src/cli/build/cache.ts +6 -6
  247. package/src/cli/build.ts +78 -45
  248. package/src/cli/index.ts +21 -3
  249. package/src/cli/serve/immutable.ts +31 -0
  250. package/src/cli/serve/pipeline.ts +97 -93
  251. package/src/cli/serve/standalone-worker.ts +8 -0
  252. package/src/cli/serve/standalone.ts +703 -0
  253. package/src/cli/start.ts +31 -8
  254. package/src/client/build.ts +1 -1
  255. package/src/client/chunk-fold.ts +19 -6
  256. package/src/client/react-tier.ts +3 -2
  257. package/src/client/reference-stub.ts +23 -36
  258. package/src/compat/actions/client-plugin.ts +4 -2
  259. package/src/compat/actions/config.ts +6 -5
  260. package/src/compat/actions/extensions.ts +5 -5
  261. package/src/compat/aliases.ts +8 -1
  262. package/src/compat/bundler/config.ts +88 -0
  263. package/src/compat/bundler/optimize-package-imports.ts +86 -26
  264. package/src/compat/bundler/relay-transform.ts +15 -3
  265. package/src/compat/bundler/require-context.ts +2 -1
  266. package/src/compat/bundler/webpack-loaders.ts +3 -2
  267. package/src/compat/bundler/worker.ts +2 -2
  268. package/src/compat/cache-control.ts +16 -8
  269. package/src/compat/css/inline-css.ts +1 -1
  270. package/src/compat/css/modules.ts +18 -5
  271. package/src/compat/export/build-complete.ts +1 -1
  272. package/src/compat/export/emit.ts +4 -4
  273. package/src/compat/export/standalone.ts +30 -65
  274. package/src/compat/image-optimizer/optimize.ts +1 -1
  275. package/src/compat/lifecycle/error-funnel.ts +1 -1
  276. package/src/compat/lifecycle/instrumentation-client.ts +4 -3
  277. package/src/compat/lifecycle/instrumentation.ts +117 -24
  278. package/src/compat/lifecycle/testmode.ts +3 -2
  279. package/src/compat/metadata-artifacts.ts +1 -1
  280. package/src/compat/next/config-loader.ts +140 -13
  281. package/src/compat/next/dynamic.tsx +10 -23
  282. package/src/compat/next/font/cache.ts +2 -1
  283. package/src/compat/next/font/runtime.ts +23 -3
  284. package/src/compat/next/og.ts +3 -3
  285. package/src/compat/next/usage.ts +3 -2
  286. package/src/compat/pages/api.ts +83 -14
  287. package/src/compat/pages/router.ts +30 -14
  288. package/src/compat/register/bundler.ts +3 -1
  289. package/src/compat/register/image.ts +1 -1
  290. package/src/compat/register/middleware.ts +1 -1
  291. package/src/compat/register/otel.ts +5 -9
  292. package/src/compat/register/render.ts +3 -1
  293. package/src/compat/register/use-cache.ts +3 -1
  294. package/src/compat/release.ts +46 -0
  295. package/src/compat/segment/serve.ts +1 -1
  296. package/src/compat/typecheck/check.ts +6 -4
  297. package/src/compat/validation/validate.ts +10 -7
  298. package/src/config.ts +76 -9
  299. package/src/css/assets.ts +213 -0
  300. package/src/css/build.ts +190 -247
  301. package/src/dev/client-chunk-store.ts +2 -1
  302. package/src/dev/restart/client-key.ts +2 -1
  303. package/src/dev/restart/global-css.ts +2 -1
  304. package/src/dev/restart/route-bundle-key.ts +2 -1
  305. package/src/dev/restart/route-facts.ts +2 -1
  306. package/src/dev/server.ts +34 -14
  307. package/src/extensions.ts +4 -0
  308. package/src/out-paths.ts +10 -0
  309. package/src/render/hooks.ts +13 -0
  310. package/src/render/renderer.ts +53 -33
  311. package/src/request/context.ts +9 -0
  312. package/src/resolve/dynamic.ts +7 -1
  313. package/src/resolve/engine.ts +2 -12
  314. package/src/resolve/imports.ts +12 -52
  315. package/src/resolve/package-json.ts +56 -0
  316. package/src/resolve/scan-facts.ts +250 -1
  317. package/src/routing/href.ts +10 -3
  318. package/src/routing/match.ts +287 -0
  319. package/src/routing/metadata-files.ts +20 -6
  320. package/src/routing/proxy-config.ts +137 -0
  321. package/src/routing/proxy.ts +35 -134
  322. package/src/routing/routes.ts +22 -281
  323. package/src/runtime/fingerprint.ts +23 -8
  324. package/src/runtime/load.ts +170 -0
  325. package/src/runtime/loader.ts +218 -44
  326. package/src/runtime/module-cache.ts +15 -1
  327. package/src/runtime/modules.ts +405 -82
  328. package/src/runtime/prebundle.ts +101 -0
  329. package/src/runtime/production.ts +456 -0
  330. package/src/runtime/release-graph.ts +342 -0
  331. package/src/runtime/vendor-build.ts +750 -17
  332. package/src/runtime/vendor.ts +16 -3
  333. package/src/types.ts +4 -3
  334. package/src/utils/directive.ts +40 -0
  335. package/src/utils/fs.ts +95 -4
  336. package/src/utils/resource-query.ts +12 -0
  337. package/src/cli/serve/entry.ts +0 -45
@@ -10,6 +10,9 @@ import {
10
10
  tsConfigFileFor,
11
11
  } from './engine'
12
12
  import { onExtensionHostReset } from '../extensions'
13
+ import { findWorkspaceRoot, readPackageJson, type PackageJson } from './package-json'
14
+
15
+ export { findWorkspaceRoot }
13
16
 
14
17
  // `Bun` through globalThis: pnext ships TypeScript source, so app compilers without
15
18
  // bun-types typecheck this file and a bare `Bun` identifier would fail them.
@@ -45,6 +48,8 @@ export interface ExternalPackagePolicy {
45
48
  * transpile.
46
49
  */
47
50
  transpiled?: () => readonly string[]
51
+ /** Kept out of a release's server dependency graph beyond `external`: Next's built-in list. */
52
+ releaseExternal?: (packageName: string) => boolean
48
53
  /** ESM external mode for package exports interop. */
49
54
  esmExternals: () => boolean | 'loose'
50
55
  }
@@ -94,9 +99,14 @@ export function resolveExternalLoadTarget(context: ExternalLoadContext): string
94
99
  // `#imports` resolve from the importer's OWN package, so they are not
95
100
  // shareable across a resolution root; they stay uncached.
96
101
  if (context.specifier.startsWith('#')) return externalLoadResolver(context)
97
- const key = `${context.target}\0${resolutionRootForFile(context.root, context.fromFile)}\0${context.specifier}`
102
+ // A node_modules importer resolves from its own directory, as Node does: a version nested under
103
+ // its package wins over the hoisted one.
104
+ const resolveContext = context.fromFile.includes(`${path.sep}node_modules${path.sep}`)
105
+ ? { ...context, root: path.dirname(context.fromFile) }
106
+ : context
107
+ const key = `${context.target}\0${resolutionRootForFile(resolveContext.root, context.fromFile)}\0${context.specifier}`
98
108
  if (externalLoadTargets.has(key)) return externalLoadTargets.get(key)
99
- const target = externalLoadResolver(context)
109
+ const target = externalLoadResolver(resolveContext)
100
110
  externalLoadTargets.set(key, target)
101
111
  return target
102
112
  }
@@ -143,22 +153,6 @@ export function setTsConfigPath(file: string | undefined): void {
143
153
  clearVendorPackageResolutions()
144
154
  }
145
155
 
146
- interface PackageJson {
147
- name?: string
148
- type?: string
149
- browser?: string
150
- main?: string
151
- module?: string
152
- source?: string
153
- exports?: PackageExport
154
- imports?: Record<string, PackageExport>
155
- dependencies?: Record<string, string>
156
- devDependencies?: Record<string, string>
157
- optionalDependencies?: Record<string, string>
158
- peerDependencies?: Record<string, string>
159
- workspaces?: string[] | { packages?: string[] }
160
- }
161
-
162
156
  // Compat (or any bundler extension) registers its bare-specifier to file aliases here (e.g. `next/form` ->
163
157
  // `src/compat/next/form.tsx`). Core's own route scanner has no static knowledge of those aliases otherwise,
164
158
  // so a server component importing a 'use client' compat module would never be walked into and its client
@@ -886,25 +880,6 @@ export function commonJsModuleHasDefaultExport(source: string, file: string) {
886
880
  )
887
881
  }
888
882
 
889
- export function findWorkspaceRoot(root: string) {
890
- const key = path.resolve(root)
891
- if (workspaceRootCache.has(key)) return workspaceRootCache.get(key)
892
-
893
- let dir = key
894
- while (true) {
895
- if (readPackageJson(dir).workspaces || existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
896
- workspaceRootCache.set(key, dir)
897
- return dir
898
- }
899
- const parent = path.dirname(dir)
900
- if (parent === dir) {
901
- workspaceRootCache.set(key, undefined)
902
- return undefined
903
- }
904
- dir = parent
905
- }
906
- }
907
-
908
883
  function isInside(root: string, file: string) {
909
884
  const relative = path.relative(root, file)
910
885
  return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
@@ -962,8 +937,6 @@ function readPnpmWorkspacePatterns(root: string) {
962
937
  }
963
938
 
964
939
  const tsConfigCache = new Map<string, TsConfig>()
965
- const packageJsonCache = new Map<string, PackageJson>()
966
- const workspaceRootCache = new Map<string, string | undefined>()
967
940
  const workspacePackageCache = new Map<string, Map<string, string>>()
968
941
 
969
942
  function readTsConfig(root: string) {
@@ -975,14 +948,6 @@ function readTsConfig(root: string) {
975
948
  return config
976
949
  }
977
950
 
978
- function readPackageJson(root: string) {
979
- const existing = packageJsonCache.get(root)
980
- if (existing) return existing
981
- const config = readJson<PackageJson>(path.join(root, 'package.json')) ?? {}
982
- packageJsonCache.set(root, config)
983
- return config
984
- }
985
-
986
951
  function workspacePackages(root: string) {
987
952
  const existing = workspacePackageCache.get(root)
988
953
  if (existing) return existing
@@ -1027,11 +992,6 @@ export function workspacePackageRoots(root: string) {
1027
992
  return [...workspacePackages(path.resolve(root)).values()].sort()
1028
993
  }
1029
994
 
1030
- function readJson<T>(file: string) {
1031
- if (!existsSync(file)) return undefined
1032
- return JSON.parse(readFileSync(file, 'utf8')) as T
1033
- }
1034
-
1035
995
  function readJsonc<T>(file: string) {
1036
996
  if (!existsSync(file)) return undefined
1037
997
  return JSON.parse(stripTrailingCommas(stripJsonComments(readFileSync(file, 'utf8')))) as T
@@ -0,0 +1,56 @@
1
+ // package.json reads and workspace-root discovery, which config loading needs without the resolver.
2
+ import { existsSync, readFileSync } from 'node:fs'
3
+ import path from 'node:path'
4
+
5
+ type PackageExport = unknown
6
+
7
+ export interface PackageJson {
8
+ name?: string
9
+ type?: string
10
+ browser?: string
11
+ main?: string
12
+ module?: string
13
+ source?: string
14
+ exports?: PackageExport
15
+ imports?: Record<string, PackageExport>
16
+ dependencies?: Record<string, string>
17
+ devDependencies?: Record<string, string>
18
+ optionalDependencies?: Record<string, string>
19
+ peerDependencies?: Record<string, string>
20
+ workspaces?: string[] | { packages?: string[] }
21
+ }
22
+
23
+ const packageJsonCache = new Map<string, PackageJson>()
24
+ const workspaceRootCache = new Map<string, string | undefined>()
25
+
26
+ export function readPackageJson(root: string) {
27
+ const existing = packageJsonCache.get(root)
28
+ if (existing) return existing
29
+ const config = readJson<PackageJson>(path.join(root, 'package.json')) ?? {}
30
+ packageJsonCache.set(root, config)
31
+ return config
32
+ }
33
+
34
+ export function findWorkspaceRoot(root: string) {
35
+ const key = path.resolve(root)
36
+ if (workspaceRootCache.has(key)) return workspaceRootCache.get(key)
37
+
38
+ let dir = key
39
+ while (true) {
40
+ if (readPackageJson(dir).workspaces || existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
41
+ workspaceRootCache.set(key, dir)
42
+ return dir
43
+ }
44
+ const parent = path.dirname(dir)
45
+ if (parent === dir) {
46
+ workspaceRootCache.set(key, undefined)
47
+ return undefined
48
+ }
49
+ dir = parent
50
+ }
51
+ }
52
+
53
+ function readJson<T>(file: string) {
54
+ if (!existsSync(file)) return undefined
55
+ return JSON.parse(readFileSync(file, 'utf8')) as T
56
+ }
@@ -76,6 +76,8 @@ export interface RewriteFacts {
76
76
  edges: SpecifierEdge[]
77
77
  imports: ImportStatement[]
78
78
  importMetas: { start: number; end: number }[]
79
+ /** `import()` calls whose argument is not a plain string literal. */
80
+ computedImports: { start: number; end: number }[]
79
81
  /**
80
82
  * The parse recovered from errors, so the record may be incomplete — folded
81
83
  * passes fall back to their textual form rather than silently under-rewrite.
@@ -146,6 +148,7 @@ const emptyRewriteFacts: RewriteFacts = {
146
148
  edges: [],
147
149
  imports: [],
148
150
  importMetas: [],
151
+ computedImports: [],
149
152
  unreliable: false,
150
153
  }
151
154
 
@@ -373,10 +376,14 @@ function parseFacts(file: string, source: string, lang: ParserLang) {
373
376
  imports.sort((a, b) => a.index - b.index)
374
377
 
375
378
  const dynamicImports: { specifier: string; index: number }[] = []
379
+ const computedImports: { start: number; end: number }[] = []
376
380
  for (const entry of result.module.dynamicImports) {
377
381
  const raw = source.slice(entry.moduleRequest.start, entry.moduleRequest.end)
378
382
  const specifier = literalSpecifier(raw)
379
- if (specifier === undefined) continue
383
+ if (specifier === undefined) {
384
+ computedImports.push({ start: entry.start, end: entry.end })
385
+ continue
386
+ }
380
387
  dynamicImports.push({ specifier, index: entry.start })
381
388
  // The literal's own span, without the whitespace `moduleRequest` includes.
382
389
  const lead = raw.length - raw.trimStart().length
@@ -419,6 +426,7 @@ function parseFacts(file: string, source: string, lang: ParserLang) {
419
426
  edges,
420
427
  imports: importStatements,
421
428
  importMetas: result.module.importMetas.map(meta => ({ start: meta.start, end: meta.end })),
429
+ computedImports,
422
430
  unreliable: result.errors.length > 0,
423
431
  },
424
432
  }
@@ -581,6 +589,247 @@ function child(node: AstNode | undefined, key: string): AstNode | undefined {
581
589
  return isNode(value) ? value : undefined
582
590
  }
583
591
 
592
+ /** A string literal argument: its cooked value and the span of its quoted text. */
593
+ export interface LiteralSpan {
594
+ specifier: string
595
+ start: number
596
+ end: number
597
+ }
598
+
599
+ /** How a module refers to its own location (see `importMetaRefs`). */
600
+ export interface ImportMetaRefs {
601
+ /** `new URL('<literal>', import.meta.url)`. */
602
+ urls: LiteralSpan[]
603
+ /** `import.meta.resolve('<literal>')`. */
604
+ resolves: LiteralSpan[]
605
+ /** Reads `import.meta.url`/`dirname`/`filename`/`resolve`, or takes `import.meta` whole. */
606
+ readsLocation: boolean
607
+ /** Spans of each `import()` whose argument is not a string literal. */
608
+ computedImports: { start: number; end: number }[]
609
+ /** The parse recovered from errors: callers keep their conservative answer. */
610
+ unreliable: boolean
611
+ }
612
+
613
+ const noMetaRefs: ImportMetaRefs = {
614
+ urls: [],
615
+ resolves: [],
616
+ readsLocation: false,
617
+ computedImports: [],
618
+ unreliable: false,
619
+ }
620
+ const metaRefMemo = new Map<string, ImportMetaRefs>()
621
+ const locationMembers = new Set(['url', 'dirname', 'filename', 'resolve'])
622
+
623
+ /** Every reference a module makes to its own location, from the AST: never a comment or a string. */
624
+ export function importMetaRefs(file: string, source: string): ImportMetaRefs {
625
+ if (stylesheetOrData.test(file)) return noMetaRefs
626
+ if (!source.includes('import.meta') && !source.includes('import(')) return noMetaRefs
627
+ // The memoized module record answers computed imports and whether `import.meta` occurs at all;
628
+ // only a module that really uses it pays for the AST.
629
+ const record = rewriteFacts(file, source)
630
+ if (record.importMetas.length === 0)
631
+ return { ...noMetaRefs, computedImports: record.computedImports, unreliable: record.unreliable }
632
+ const lang = langForFile(file)
633
+ const key = `${lang}\0${source.length}\0${bun.hash(source).toString()}`
634
+ const cached = metaRefMemo.get(key)
635
+ if (cached) return cached
636
+ const result = parseSync(file, source, { lang })
637
+ const refs: ImportMetaRefs = {
638
+ ...noMetaRefs,
639
+ urls: [],
640
+ resolves: [],
641
+ computedImports: record.computedImports,
642
+ }
643
+ refs.unreliable = result.errors.length > 0
644
+ const isImportMeta = (node: AstNode | undefined) =>
645
+ node?.type === 'MetaProperty' &&
646
+ child(node, 'meta')?.name === 'import' &&
647
+ child(node, 'property')?.name === 'meta'
648
+ const memberName = (node: AstNode) =>
649
+ node.computed ? stringValue(child(node, 'property')) : (child(node, 'property')?.name as string)
650
+ const literal = (node: AstNode | undefined): LiteralSpan | undefined => {
651
+ if (!node) return undefined
652
+ const value =
653
+ stringValue(node) ??
654
+ (node.type === 'TemplateLiteral' && (node.expressions as unknown[]).length === 0
655
+ ? ((node.quasis as AstNode[])[0]?.value as { cooked?: string } | undefined)?.cooked
656
+ : undefined)
657
+ return value === undefined ? undefined : { specifier: value, start: node.start, end: node.end }
658
+ }
659
+ const visit = (value: unknown, parent: AstNode | undefined) => {
660
+ if (Array.isArray(value)) {
661
+ for (const item of value) visit(item, parent)
662
+ return
663
+ }
664
+ if (!isNode(value)) return
665
+ if (isImportMeta(value)) {
666
+ const member = parent?.type === 'MemberExpression' && parent.object === value
667
+ if (!member || locationMembers.has(memberName(parent) ?? '')) refs.readsLocation = true
668
+ } else if (value.type === 'NewExpression' && child(value, 'callee')?.name === 'URL') {
669
+ const [target, base] = value.arguments as AstNode[]
670
+ const span = literal(target)
671
+ if (span && base?.type === 'MemberExpression' && isImportMeta(child(base, 'object')))
672
+ if (memberName(base) === 'url') refs.urls.push(span)
673
+ } else if (value.type === 'CallExpression') {
674
+ const callee = child(value, 'callee')
675
+ if (callee?.type === 'MemberExpression' && isImportMeta(child(callee, 'object'))) {
676
+ const span = literal((value.arguments as AstNode[])[0])
677
+ if (span && memberName(callee) === 'resolve') refs.resolves.push(span)
678
+ }
679
+ }
680
+ for (const key in value) {
681
+ if (key !== 'start' && key !== 'end' && key !== 'type') visit(value[key], value)
682
+ }
683
+ }
684
+ visit(result.program, undefined)
685
+ metaRefMemo.set(key, refs)
686
+ return refs
687
+ }
688
+
689
+ /**
690
+ * Whether the module declares top-level state: a `const`/`let`/`var` initialized by `new`, or by a
691
+ * call through a plain name (not `require`, not `/* @__PURE__ *\/`), from the AST: never a line
692
+ * inside a string, and every declarator counts.
693
+ */
694
+ export function hasModuleState(file: string, source: string): boolean {
695
+ const result = parseSync(file, source, { lang: langForFile(file) })
696
+ const pureEnds = new Set(
697
+ result.comments
698
+ .filter(comment => /^\s*[#@]__PURE__\s*$/.test(comment.value))
699
+ .map(comment => comment.end),
700
+ )
701
+ const annotatedPure = (node: AstNode) => {
702
+ for (let index = node.start - 1; index >= 0; index -= 1) {
703
+ if (pureEnds.has(index + 1)) return true
704
+ if (!/\s/.test(source[index]!)) return false
705
+ }
706
+ return false
707
+ }
708
+ const plainCallee = (node: AstNode | undefined): boolean =>
709
+ node?.type === 'Identifier' ||
710
+ (node?.type === 'MemberExpression' && !node.computed && plainCallee(child(node, 'object')))
711
+ const declarations = (result.program.body as unknown as AstNode[]).flatMap(statement => {
712
+ const declaration =
713
+ statement.type === 'ExportNamedDeclaration' ? child(statement, 'declaration') : statement
714
+ return declaration?.type === 'VariableDeclaration'
715
+ ? (declaration.declarations as AstNode[])
716
+ : []
717
+ })
718
+ return declarations.some(declarator => {
719
+ const init = unwrapExpression(child(declarator, 'init'))
720
+ if (init?.type === 'NewExpression') return true
721
+ if (init?.type !== 'CallExpression') return false
722
+ const callee = child(init, 'callee')
723
+ return plainCallee(callee) && callee?.name !== 'require' && !annotatedPure(init)
724
+ })
725
+ }
726
+
727
+ /** A string literal holding an absolute path or `file:` URL, and whether it is an object key. */
728
+ export interface PathLiteral {
729
+ value: string
730
+ start: number
731
+ end: number
732
+ key: boolean
733
+ }
734
+
735
+ /** Absolute path literals in emitted code, from the AST; undefined when the parse recovered. */
736
+ export function absolutePathLiterals(file: string, source: string): PathLiteral[] | undefined {
737
+ const result = parseSync(file, source, { lang: langForFile(file) })
738
+ if (result.errors.length > 0) return undefined
739
+ const found: PathLiteral[] = []
740
+ const visit = (value: unknown, parent: AstNode | undefined) => {
741
+ if (Array.isArray(value)) {
742
+ for (const item of value) visit(item, parent)
743
+ return
744
+ }
745
+ if (!isNode(value)) return
746
+ const literal = stringValue(value)
747
+ if (literal !== undefined && (literal.startsWith('/') || literal.startsWith('file:///'))) {
748
+ const key = parent?.type === 'Property' && parent.key === value && !parent.computed
749
+ found.push({ value: literal, start: value.start, end: value.end, key })
750
+ }
751
+ for (const key in value) {
752
+ if (key !== 'start' && key !== 'end' && key !== 'type') visit(value[key], value)
753
+ }
754
+ }
755
+ visit(result.program, undefined)
756
+ return found
757
+ }
758
+
759
+ /** Line comments (`// …`), from the parse; undefined when it recovered. */
760
+ export function lineComments(file: string, source: string) {
761
+ const result = parseSync(file, source, { lang: langForFile(file) })
762
+ if (result.errors.length > 0) return undefined
763
+ return result.comments
764
+ .filter(comment => comment.type === 'Line')
765
+ .map(comment => ({ value: comment.value, start: comment.start, end: comment.end }))
766
+ }
767
+
768
+ /**
769
+ * Drop `type: "json"` attributes from the import declarations and `import()` calls whose target
770
+ * `compiled` claims: the target is JS, which a native load would parse as JSON.
771
+ */
772
+ export function stripJsonImportAttributes(
773
+ source: string,
774
+ file: string,
775
+ compiled: (specifier: string) => boolean,
776
+ ) {
777
+ const result = parseSync(file, source, { lang: 'js', sourceType: 'module' })
778
+ if (result.errors.length > 0) return source
779
+ const edits: { start: number; end: number; value: string }[] = []
780
+ const visit = (node: AstNode) => {
781
+ const target = child(node, 'source')
782
+ const specifier = stringValue(target)
783
+ if (target && specifier !== undefined && compiled(specifier)) {
784
+ const attributes = node.attributes as AstNode[] | undefined
785
+ const options = child(node, 'options')
786
+ if (attributes?.length && attributes.every(jsonTypeAttribute)) {
787
+ const end = source.indexOf('}', attributes.at(-1)!.end) + 1
788
+ edits.push({ start: target.end, end, value: '' })
789
+ } else if (node.type === 'ImportExpression' && options && jsonImportOptions(options)) {
790
+ edits.push({ start: target.end, end: options.end, value: '' })
791
+ }
792
+ }
793
+ for (const value of Object.values(node)) {
794
+ if (isNode(value)) visit(value)
795
+ else if (Array.isArray(value)) for (const item of value) if (isNode(item)) visit(item)
796
+ }
797
+ }
798
+ visit(result.program as unknown as AstNode)
799
+ return edits.length > 0 ? spliceSource(source, edits) : source
800
+ }
801
+
802
+ function propertyName(node: AstNode | undefined) {
803
+ if (!node) return undefined
804
+ return node.type === 'Identifier' ? (node.name as string) : stringValue(node)
805
+ }
806
+
807
+ function jsonTypeAttribute(node: AstNode) {
808
+ return (
809
+ !node.computed &&
810
+ propertyName(child(node, 'key')) === 'type' &&
811
+ stringValue(child(node, 'value')) === 'json'
812
+ )
813
+ }
814
+
815
+ /** `{ with: { type: 'json' } }` (or `assert`) and nothing else. */
816
+ function jsonImportOptions(options: AstNode) {
817
+ const [property, ...rest] = (options.properties as AstNode[] | undefined) ?? []
818
+ const attributes = child(property, 'value')
819
+ const entries = attributes?.properties as AstNode[] | undefined
820
+ return (
821
+ options.type === 'ObjectExpression' &&
822
+ !!property &&
823
+ rest.length === 0 &&
824
+ property.type === 'Property' &&
825
+ !property.computed &&
826
+ ['with', 'assert'].includes(propertyName(child(property, 'key')) ?? '') &&
827
+ attributes?.type === 'ObjectExpression' &&
828
+ !!entries?.length &&
829
+ entries.every(entry => entry.type === 'Property' && jsonTypeAttribute(entry))
830
+ )
831
+ }
832
+
584
833
  function collectDynamicCalls(program: AstNode): DynamicCallFact[] {
585
834
  const calls: DynamicCallFact[] = []
586
835
  const visit = (value: unknown) => {
@@ -198,7 +198,16 @@ export function canonicalTrailingSlashPath(pathname: string, trailingSlash: bool
198
198
  if (/\.[^/]+$/.test(pathname)) return pathname
199
199
  const slashed = pathname.endsWith('/')
200
200
  if (trailingSlash ? slashed : !slashed) return pathname
201
- return trailingSlash ? `${pathname.replace(/\/+$/, '')}/` : pathname.replace(/\/+$/, '') || '/'
201
+ // Collapsed, so a rewritten path can never read as protocol-relative (`//host`).
202
+ const bare = pathname.replace(/\/{2,}/g, '/').replace(/\/+$/, '')
203
+ return trailingSlash ? `${bare}/` : bare || '/'
204
+ }
205
+
206
+ /** Next 308s a path with repeated slashes to its collapsed form, for every method, before anything else. */
207
+ export function repeatedSlashRedirect(url: URL): Response | null {
208
+ if (!url.pathname.includes('//')) return null
209
+ const target = `${url.pathname.replace(/\/{2,}/g, '/')}${url.search}`
210
+ return new Response(target, { status: 308, headers: { location: target } })
202
211
  }
203
212
 
204
213
  /**
@@ -210,13 +219,11 @@ export function canonicalTrailingSlashPath(pathname: string, trailingSlash: bool
210
219
  export function trailingSlashRedirect(
211
220
  config: { trailingSlash?: boolean; skipTrailingSlashRedirect?: boolean },
212
221
  url: URL,
213
- method: string,
214
222
  ): Response | null {
215
223
  // skipTrailingSlashRedirect: the app serves both slashed and unslashed URLs
216
224
  // as-is, so no canonical redirect is ever emitted (route matching already
217
225
  // tolerates a trailing slash via normalizePathname).
218
226
  if (config.skipTrailingSlashRedirect) return null
219
- if (method !== 'GET' && method !== 'HEAD') return null
220
227
  const pathname = url.pathname
221
228
  if (pathname === '/' || pathname === '') return null
222
229
  if (pathname.startsWith('/__pnext') || isBuildAssetPathname(pathname)) return null