@wular/pnext 0.1.5 → 0.1.7

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 (302) hide show
  1. package/bin/pnext +9 -2
  2. package/dist/server/_chunks/aliases-j47a10ce.js +44 -0
  3. package/dist/server/_chunks/analyze-arswqe6s.js +445 -0
  4. package/dist/server/_chunks/boot-af0mv3dy.js +36 -0
  5. package/dist/server/_chunks/build-spy3dxp4.js +84 -0
  6. package/dist/server/_chunks/build-t9h0hec3.js +3550 -0
  7. package/dist/server/_chunks/build-tier-m7yvqz61.js +2472 -0
  8. package/dist/server/_chunks/compile-53j02j27.js +22 -0
  9. package/dist/server/_chunks/config-1yzwexq6.js +27 -0
  10. package/dist/server/_chunks/config-n2z7yxps.js +22 -0
  11. package/dist/server/_chunks/create-meec9hs6.js +134 -0
  12. package/dist/server/_chunks/dev-fjmqg6en.js +220 -0
  13. package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
  14. package/dist/server/_chunks/generate-n9sh6hzt.js +21 -0
  15. package/dist/server/_chunks/index-0374j2b9.js +66 -0
  16. package/dist/server/_chunks/index-06nyqntx.js +213 -0
  17. package/dist/server/_chunks/index-1011cscr.js +5263 -0
  18. package/dist/server/_chunks/index-11sfk4hb.js +170 -0
  19. package/dist/server/_chunks/index-20ppawv7.js +297 -0
  20. package/dist/server/_chunks/index-2dv4y4wd.js +1065 -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-357na4a8.js +109 -0
  24. package/dist/server/_chunks/index-3b3at80h.js +109 -0
  25. package/dist/server/_chunks/index-3tf1xjsp.js +6166 -0
  26. package/dist/server/_chunks/index-3xbr4eyv.js +105 -0
  27. package/dist/server/_chunks/index-4399bvd2.js +18 -0
  28. package/dist/server/_chunks/index-4hgjrqh7.js +851 -0
  29. package/dist/server/_chunks/index-4q2gbfwk.js +2530 -0
  30. package/dist/server/_chunks/index-4t92hdxd.js +172 -0
  31. package/dist/server/_chunks/index-4zzebszd.js +10 -0
  32. package/dist/server/_chunks/index-5gyr4emz.js +107 -0
  33. package/dist/server/_chunks/index-5hr4062s.js +70 -0
  34. package/dist/server/_chunks/index-68m3mwbd.js +84 -0
  35. package/dist/server/_chunks/index-6b009mt0.js +56 -0
  36. package/dist/server/_chunks/index-6e4fqv30.js +588 -0
  37. package/dist/server/_chunks/index-6gex3pfa.js +15 -0
  38. package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
  39. package/dist/server/_chunks/index-6q7zvrap.js +134 -0
  40. package/dist/server/_chunks/index-73z4esab.js +38 -0
  41. package/dist/server/_chunks/index-79ngvam8.js +60 -0
  42. package/dist/server/_chunks/index-7wc9n8be.js +25 -0
  43. package/dist/server/_chunks/index-8k7pfejn.js +1599 -0
  44. package/dist/server/_chunks/index-8kcxdfya.js +206 -0
  45. package/dist/server/_chunks/index-91x12ykq.js +274 -0
  46. package/dist/server/_chunks/index-9ch50vtq.js +18 -0
  47. package/dist/server/_chunks/index-9hx2641q.js +28 -0
  48. package/dist/server/_chunks/index-9n2914ww.js +535 -0
  49. package/dist/server/_chunks/index-9ych9ma8.js +207 -0
  50. package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
  51. package/dist/server/_chunks/index-bcws5eh2.js +35 -0
  52. package/dist/server/_chunks/index-c0g2wf3z.js +92 -0
  53. package/dist/server/_chunks/index-cf4rvxv6.js +95 -0
  54. package/dist/server/_chunks/index-cjgqs13g.js +65 -0
  55. package/dist/server/_chunks/index-ckkdpht5.js +41 -0
  56. package/dist/server/_chunks/index-cyfednwb.js +87 -0
  57. package/dist/server/_chunks/index-danncfhy.js +311 -0
  58. package/dist/server/_chunks/index-dg0f05zs.js +199 -0
  59. package/dist/server/_chunks/index-e3a6yx84.js +18 -0
  60. package/dist/server/_chunks/index-e88tyv35.js +45 -0
  61. package/dist/server/_chunks/index-eajaspjk.js +1253 -0
  62. package/dist/server/_chunks/index-eeaanp2e.js +483 -0
  63. package/dist/server/_chunks/index-egykcqg3.js +101 -0
  64. package/dist/server/_chunks/index-en7n9f7m.js +22 -0
  65. package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
  66. package/dist/server/_chunks/index-fkp000p1.js +590 -0
  67. package/dist/server/_chunks/index-fn1chkkd.js +214 -0
  68. package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
  69. package/dist/server/_chunks/index-ggk2j965.js +9432 -0
  70. package/dist/server/_chunks/index-grta8ap3.js +238 -0
  71. package/dist/server/_chunks/index-h2a70tg4.js +7 -0
  72. package/dist/server/_chunks/index-h4xy648y.js +51 -0
  73. package/dist/server/_chunks/index-hkdfj58q.js +92 -0
  74. package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
  75. package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
  76. package/dist/server/_chunks/index-jepjvcrf.js +198 -0
  77. package/dist/server/_chunks/index-jks0x0a1.js +14 -0
  78. package/dist/server/_chunks/index-jx7bqvw1.js +57 -0
  79. package/dist/server/_chunks/index-k1g3epw0.js +1299 -0
  80. package/dist/server/_chunks/index-knp0s912.js +7 -0
  81. package/dist/server/_chunks/index-kq8kpzye.js +472 -0
  82. package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
  83. package/dist/server/_chunks/index-kresp2n8.js +445 -0
  84. package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
  85. package/dist/server/_chunks/index-n4hxpng2.js +11 -0
  86. package/dist/server/_chunks/index-ncnes8c6.js +17 -0
  87. package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
  88. package/dist/server/_chunks/index-nyrba2kr.js +4130 -0
  89. package/dist/server/_chunks/index-p77b4kcx.js +296 -0
  90. package/dist/server/_chunks/index-pym1cezq.js +39 -0
  91. package/dist/server/_chunks/index-q738kkhj.js +100 -0
  92. package/dist/server/_chunks/index-qjj6gddn.js +54 -0
  93. package/dist/server/_chunks/index-qm6kmhqs.js +110 -0
  94. package/dist/server/_chunks/index-qn4z5s3c.js +819 -0
  95. package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
  96. package/dist/server/_chunks/index-r97ptz1q.js +97 -0
  97. package/dist/server/_chunks/index-ras0sdab.js +26 -0
  98. package/dist/server/_chunks/index-rcs322t1.js +19 -0
  99. package/dist/server/_chunks/index-rn8dyr1f.js +126 -0
  100. package/dist/server/_chunks/index-rt9qq1va.js +4 -0
  101. package/dist/server/_chunks/index-rthrsed5.js +356 -0
  102. package/dist/server/_chunks/index-sctcgyvv.js +185 -0
  103. package/dist/server/_chunks/index-sjpckxqn.js +213 -0
  104. package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
  105. package/dist/server/_chunks/index-stbk3jhn.js +31 -0
  106. package/dist/server/_chunks/index-sv8m6789.js +266 -0
  107. package/dist/server/_chunks/index-tgcakdxc.js +125 -0
  108. package/dist/server/_chunks/index-tgsfjmep.js +74 -0
  109. package/dist/server/_chunks/index-tq0pc7eg.js +154 -0
  110. package/dist/server/_chunks/index-tq1f96v7.js +51 -0
  111. package/dist/server/_chunks/index-tqn2qnnn.js +241 -0
  112. package/dist/server/_chunks/index-tvqkq6e6.js +128 -0
  113. package/dist/server/_chunks/index-v1ags1na.js +132 -0
  114. package/dist/server/_chunks/index-vvmmknm1.js +1431 -0
  115. package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
  116. package/dist/server/_chunks/index-vz0km5qk.js +33 -0
  117. package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
  118. package/dist/server/_chunks/index-web361b8.js +138 -0
  119. package/dist/server/_chunks/index-wpfhfbs4.js +194 -0
  120. package/dist/server/_chunks/index-x0y005nh.js +283 -0
  121. package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
  122. package/dist/server/_chunks/index-x93hv0sc.js +271 -0
  123. package/dist/server/_chunks/index-xvj80c3a.js +30 -0
  124. package/dist/server/_chunks/index-xywjg2vc.js +100 -0
  125. package/dist/server/_chunks/index-y2jr2n72.js +152 -0
  126. package/dist/server/_chunks/index-y36a0ybw.js +57 -0
  127. package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
  128. package/dist/server/_chunks/index-yhxkxghe.js +56 -0
  129. package/dist/server/_chunks/index-ym67zqxp.js +130 -0
  130. package/dist/server/_chunks/index-ytjvpbm2.js +736 -0
  131. package/dist/server/_chunks/index-yz54pxrh.js +960 -0
  132. package/dist/server/_chunks/index-z4z9zv3b.js +733 -0
  133. package/dist/server/_chunks/index-z84ab1w0.js +1270 -0
  134. package/dist/server/_chunks/index-z88qv16t.js +11 -0
  135. package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
  136. package/dist/server/_chunks/loader-7yw0j98z.js +78 -0
  137. package/dist/server/_chunks/modules-jn8bmbn8.js +74 -0
  138. package/dist/server/_chunks/pipeline-yy9jhydf.js +832 -0
  139. package/dist/server/_chunks/production-jar9ztm3.js +44 -0
  140. package/dist/server/_chunks/proxy-config-j84dgksn.js +21 -0
  141. package/dist/server/_chunks/proxy-w1d0wmsn.js +33 -0
  142. package/dist/server/_chunks/router-k1reahfn.js +498 -0
  143. package/dist/server/_chunks/routes-2s277fc6.js +64 -0
  144. package/dist/server/_chunks/run-pvd8bs1t.js +696 -0
  145. package/dist/server/_chunks/server-mt4a994c.js +1835 -0
  146. package/dist/server/_chunks/tsconfig-defaults-1nb3308g.js +20 -0
  147. package/dist/server/_chunks/typegen-0qr0459b.js +35 -0
  148. package/dist/server/api/client-cache.js +14 -0
  149. package/dist/server/cli/index.js +378 -0
  150. package/dist/server/cli/start.js +137 -0
  151. package/dist/server/client/reference.js +16 -0
  152. package/dist/server/compat/next/cache.js +56 -0
  153. package/dist/server/compat/next/canonical-url.js +13 -0
  154. package/dist/server/compat/next/client-cache.js +57 -0
  155. package/dist/server/compat/next/client-navigation.js +232 -0
  156. package/dist/server/compat/next/client-only.js +1 -0
  157. package/dist/server/compat/next/client-script.js +178 -0
  158. package/dist/server/compat/next/client-server.js +34 -0
  159. package/dist/server/compat/next/config-headers.js +32 -0
  160. package/dist/server/compat/next/config-loader.js +25 -0
  161. package/dist/server/compat/next/config.js +10 -0
  162. package/dist/server/compat/next/constants.js +18 -0
  163. package/dist/server/compat/next/custom-server.js +10 -0
  164. package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
  165. package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
  166. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
  167. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
  168. package/dist/server/compat/next/dynamic.js +32 -0
  169. package/dist/server/compat/next/error.js +112 -0
  170. package/dist/server/compat/next/font/cache.js +14 -0
  171. package/dist/server/compat/next/font/google.js +3 -0
  172. package/dist/server/compat/next/font/index.js +1 -0
  173. package/dist/server/compat/next/font/local.js +22 -0
  174. package/dist/server/compat/next/font/runtime-client.js +33 -0
  175. package/dist/server/compat/next/font/runtime.js +41 -0
  176. package/dist/server/compat/next/font/shared.js +22 -0
  177. package/dist/server/compat/next/form.js +129 -0
  178. package/dist/server/compat/next/head.js +10 -0
  179. package/dist/server/compat/next/headers.js +30 -0
  180. package/dist/server/compat/next/image/client.js +11 -0
  181. package/dist/server/compat/next/image/config.js +18 -0
  182. package/dist/server/compat/next/image/optimizer.js +25 -0
  183. package/dist/server/compat/next/image/patterns.js +12 -0
  184. package/dist/server/compat/next/image/props.js +16 -0
  185. package/dist/server/compat/next/image/shared.js +86 -0
  186. package/dist/server/compat/next/image/static-metadata.js +32 -0
  187. package/dist/server/compat/next/image/validate.js +8 -0
  188. package/dist/server/compat/next/image.js +59 -0
  189. package/dist/server/compat/next/index.js +1 -0
  190. package/dist/server/compat/next/legacy-image.js +78 -0
  191. package/dist/server/compat/next/legacy-request-apis.js +24 -0
  192. package/dist/server/compat/next/link-transform.js +14 -0
  193. package/dist/server/compat/next/link.js +14 -0
  194. package/dist/server/compat/next/navigation.js +190 -0
  195. package/dist/server/compat/next/offline.js +45 -0
  196. package/dist/server/compat/next/og.js +8 -0
  197. package/dist/server/compat/next/preferred-region.js +8 -0
  198. package/dist/server/compat/next/redirects.js +30 -0
  199. package/dist/server/compat/next/resource-hints.js +30 -0
  200. package/dist/server/compat/next/rewrites.js +41 -0
  201. package/dist/server/compat/next/root-params.js +121 -0
  202. package/dist/server/compat/next/route-state.js +23 -0
  203. package/dist/server/compat/next/router.js +103 -0
  204. package/dist/server/compat/next/script.js +37 -0
  205. package/dist/server/compat/next/server-only.js +1 -0
  206. package/dist/server/compat/next/server.js +131 -0
  207. package/dist/server/compat/next/svgr.js +14 -0
  208. package/dist/server/compat/next/telemetry.js +10 -0
  209. package/dist/server/compat/next/usage.js +13 -0
  210. package/dist/server/compat/next/user-agent.js +12 -0
  211. package/dist/server/compat/next/web-vitals.js +35 -0
  212. package/dist/server/compat/react/action-state.js +11 -0
  213. package/dist/server/compat/react/client-lite.js +83 -0
  214. package/dist/server/compat/react/client.js +131 -0
  215. package/dist/server/compat/react/compiler-runtime.js +42 -0
  216. package/dist/server/compat/react/dom-client.js +106 -0
  217. package/dist/server/compat/react/dom-react-server.js +37 -0
  218. package/dist/server/compat/react/dom-server.js +40 -0
  219. package/dist/server/compat/react/dom.js +52 -0
  220. package/dist/server/compat/react/hooks-extra.js +12 -0
  221. package/dist/server/compat/react/internals.js +14 -0
  222. package/dist/server/compat/react/parity.js +11 -0
  223. package/dist/server/compat/react/preact.js +113 -0
  224. package/dist/server/compat/react/react-server.js +133 -0
  225. package/dist/server/compat/react/router-shim.js +8 -0
  226. package/dist/server/compat/react/server-component-use.js +14 -0
  227. package/dist/server/compat/react/server-inserted-html.js +14 -0
  228. package/dist/server/compat/react/server.js +194 -0
  229. package/dist/server/compat/react/style-values.js +10 -0
  230. package/dist/server/compat/react/use.js +10 -0
  231. package/dist/server/compat/react/view-transition.js +12 -0
  232. package/dist/server/generation.json +1 -0
  233. package/package.json +4 -1
  234. package/src/api/dynamic.tsx +2 -0
  235. package/src/api/server.ts +24 -6
  236. package/src/cli/adapters/vercel-warm.ts +315 -61
  237. package/src/cli/adapters/vercel.ts +348 -71
  238. package/src/cli/build.ts +58 -33
  239. package/src/cli/index.ts +23 -10
  240. package/src/cli/serve/entry.ts +21 -159
  241. package/src/cli/serve/immutable.ts +31 -0
  242. package/src/cli/serve/pipeline.ts +82 -84
  243. package/src/cli/start.ts +3 -1
  244. package/src/client/chunk-fold.ts +19 -6
  245. package/src/client/react-tier.ts +3 -2
  246. package/src/client/reference-stub.ts +21 -2
  247. package/src/compat/actions/client-plugin.ts +4 -2
  248. package/src/compat/actions/config.ts +6 -5
  249. package/src/compat/actions/extensions.ts +2 -3
  250. package/src/compat/aliases.ts +8 -1
  251. package/src/compat/bundler/config.ts +88 -0
  252. package/src/compat/bundler/optimize-package-imports.ts +86 -26
  253. package/src/compat/bundler/relay-transform.ts +15 -3
  254. package/src/compat/cache-control.ts +16 -8
  255. package/src/compat/css/modules.ts +18 -5
  256. package/src/compat/lifecycle/error-funnel.ts +1 -1
  257. package/src/compat/lifecycle/instrumentation.ts +117 -24
  258. package/src/compat/lifecycle/testmode.ts +3 -2
  259. package/src/compat/next/config-loader.ts +137 -13
  260. package/src/compat/next/font/runtime.ts +22 -2
  261. package/src/compat/next/og.ts +3 -3
  262. package/src/compat/next/usage.ts +3 -2
  263. package/src/compat/pages/api.ts +83 -14
  264. package/src/compat/pages/router.ts +30 -14
  265. package/src/compat/register/bundler.ts +3 -1
  266. package/src/compat/register/middleware.ts +1 -1
  267. package/src/compat/register/otel.ts +5 -9
  268. package/src/compat/register/render.ts +3 -1
  269. package/src/compat/register/use-cache.ts +3 -1
  270. package/src/compat/release.ts +46 -0
  271. package/src/compat/segment/serve.ts +1 -1
  272. package/src/compat/validation/validate.ts +10 -7
  273. package/src/config.ts +51 -7
  274. package/src/css/assets.ts +213 -0
  275. package/src/css/build.ts +174 -238
  276. package/src/dev/server.ts +27 -8
  277. package/src/extensions.ts +4 -0
  278. package/src/render/hooks.ts +13 -0
  279. package/src/render/renderer.ts +52 -32
  280. package/src/request/context.ts +9 -0
  281. package/src/resolve/dynamic.ts +3 -1
  282. package/src/resolve/imports.ts +12 -52
  283. package/src/resolve/package-json.ts +56 -0
  284. package/src/resolve/scan-facts.ts +65 -0
  285. package/src/routing/href.ts +10 -3
  286. package/src/routing/match.ts +287 -0
  287. package/src/routing/metadata-files.ts +19 -5
  288. package/src/routing/proxy-config.ts +137 -0
  289. package/src/routing/proxy.ts +35 -134
  290. package/src/routing/routes.ts +22 -281
  291. package/src/runtime/fingerprint.ts +23 -8
  292. package/src/runtime/load.ts +170 -0
  293. package/src/runtime/loader.ts +215 -43
  294. package/src/runtime/module-cache.ts +13 -0
  295. package/src/runtime/modules.ts +370 -81
  296. package/src/runtime/prebundle.ts +81 -0
  297. package/src/runtime/production.ts +391 -0
  298. package/src/runtime/release-graph.ts +334 -0
  299. package/src/runtime/vendor-build.ts +724 -13
  300. package/src/runtime/vendor.ts +16 -3
  301. package/src/types.ts +2 -0
  302. package/src/utils/fs.ts +89 -3
@@ -20,6 +20,89 @@ const PREDEFINED_SERVER_EXTERNAL_PACKAGES = [
20
20
  '@node-rs/bcrypt',
21
21
  ]
22
22
 
23
+ /** Next's `next/dist/lib/server-external-packages.jsonc`. */
24
+ const NEXT_SERVER_EXTERNAL_PACKAGES = new Set([
25
+ '@alinea/generated',
26
+ '@appsignal/nodejs',
27
+ '@aws-sdk/client-s3',
28
+ '@aws-sdk/s3-presigned-post',
29
+ '@blockfrost/blockfrost-js',
30
+ '@highlight-run/node',
31
+ '@huggingface/transformers',
32
+ '@jpg-store/lucid-cardano',
33
+ '@libsql/client',
34
+ '@mikro-orm/core',
35
+ '@mikro-orm/knex',
36
+ '@node-rs/argon2',
37
+ '@node-rs/bcrypt',
38
+ '@prisma/client',
39
+ '@react-pdf/renderer',
40
+ '@sentry/profiling-node',
41
+ '@sparticuz/chromium',
42
+ '@sparticuz/chromium-min',
43
+ '@statsig/statsig-node-core',
44
+ '@swc/core',
45
+ '@xenova/transformers',
46
+ '@zenstackhq/runtime',
47
+ 'argon2',
48
+ 'autoprefixer',
49
+ 'aws-crt',
50
+ 'bcrypt',
51
+ 'better-sqlite3',
52
+ 'canvas',
53
+ 'chromadb-default-embed',
54
+ 'config',
55
+ 'cpu-features',
56
+ 'cypress',
57
+ 'dd-trace',
58
+ 'eslint',
59
+ 'express',
60
+ 'firebase-admin',
61
+ 'htmlrewriter',
62
+ 'import-in-the-middle',
63
+ 'isolated-vm',
64
+ 'jest',
65
+ 'jsdom',
66
+ 'keyv',
67
+ 'libsql',
68
+ 'mdx-bundler',
69
+ 'mongodb',
70
+ 'mongoose',
71
+ 'newrelic',
72
+ 'next-mdx-remote',
73
+ 'next-seo',
74
+ 'node-cron',
75
+ 'node-pty',
76
+ 'node-web-audio-api',
77
+ 'onnxruntime-node',
78
+ 'oslo',
79
+ 'pg',
80
+ 'pino',
81
+ 'pino-pretty',
82
+ 'pino-roll',
83
+ 'playwright',
84
+ 'playwright-core',
85
+ 'postcss',
86
+ 'prettier',
87
+ 'prisma',
88
+ 'puppeteer',
89
+ 'puppeteer-core',
90
+ 'ravendb',
91
+ 'require-in-the-middle',
92
+ 'rimraf',
93
+ 'sharp',
94
+ 'shiki',
95
+ 'sqlite3',
96
+ 'thread-stream',
97
+ 'ts-morph',
98
+ 'ts-node',
99
+ 'typescript',
100
+ 'vscode-oniguruma',
101
+ 'webpack',
102
+ 'websocket',
103
+ 'zeromq',
104
+ ])
105
+
23
106
  function stringArray(value: unknown): string[] {
24
107
  return Array.isArray(value)
25
108
  ? value.filter((item): item is string => typeof item === 'string')
@@ -51,6 +134,11 @@ export function deploymentId(): string | undefined {
51
134
  return fromEnv && fromEnv.length > 0 ? fromEnv : undefined
52
135
  }
53
136
 
137
+ /** Next's built-in server externals, which a release keeps out of its dependency graph. */
138
+ export function builtInServerExternalPackages(): ReadonlySet<string> {
139
+ return NEXT_SERVER_EXTERNAL_PACKAGES
140
+ }
141
+
54
142
  /** `publicRuntimeConfig`: the subset of runtime config safe to inline into client bundles. */
55
143
  export function publicRuntimeConfig(): Record<string, unknown> {
56
144
  const config = getNextConfig().publicRuntimeConfig
@@ -181,9 +181,33 @@ function parseGeneratedBarrel(entry: string): BarrelMap | undefined {
181
181
  if (isGeneratedFontAwesomePackage(packageDir)) {
182
182
  return parseGeneratedFontAwesomeBarrel(entry, source)
183
183
  }
184
+ const plain = plainReExports(source)
185
+ const exported = plain
186
+ ? { exports: plain, count: plain.size, reExportsOnly: () => true }
187
+ : parsedReExports(entry, source)
188
+ if (!exported || exported.count < GENERATED_BARREL_MIN_EXPORTS) return undefined
189
+ const { exports, count: exportCount } = exported
190
+ const siblings = siblingFilesByStem(path.dirname(entry), entry)
191
+ const members = new Map<string, BarrelMember>()
192
+ for (const [name, member] of exports) {
193
+ const files = siblings.get(name)
194
+ const file = files?.[0]
195
+ if (
196
+ file &&
197
+ files.length === 1 &&
198
+ path.resolve(path.dirname(entry), member.source) === path.resolve(path.dirname(entry), file)
199
+ ) {
200
+ members.set(name, member)
201
+ }
202
+ }
203
+ if (members.size / exportCount >= GENERATED_BARREL_LEAF_RATIO) return members
204
+ return exported.reExportsOnly() ? manyToFewBarrelMembers(exports, entry) : undefined
205
+ }
206
+
207
+ /** The entry's re-export records off oxc's module record; the AST is read only if asked for. */
208
+ function parsedReExports(entry: string, source: string) {
184
209
  const parsed = parseSync(entry, source, { lang: 'js' })
185
210
  if (parsed.errors.length > 0) return undefined
186
- const siblings = siblingFilesByStem(path.dirname(entry), entry)
187
211
  const exports = new Map<string, BarrelMember>()
188
212
  const exportNames = new Set<string>()
189
213
  let exportCount = 0
@@ -206,22 +230,56 @@ function parseGeneratedBarrel(entry: string): BarrelMap | undefined {
206
230
  exports.set(name, { source: request, imported })
207
231
  }
208
232
  }
209
- if (exportCount < GENERATED_BARREL_MIN_EXPORTS) return undefined
233
+ return {
234
+ exports,
235
+ count: exportCount,
236
+ // Re-exports and nothing else: no statement runs code or declares a binding.
237
+ reExportsOnly: () =>
238
+ parsed.program.body.every(
239
+ node => node.type === 'ExportNamedDeclaration' && !node.declaration,
240
+ ),
241
+ }
242
+ }
210
243
 
211
- const members = new Map<string, BarrelMember>()
212
- for (const [name, member] of exports) {
213
- const files = siblings.get(name)
214
- const file = files?.[0]
215
- if (
216
- file &&
217
- files.length === 1 &&
218
- path.resolve(path.dirname(entry), member.source) === path.resolve(path.dirname(entry), file)
219
- ) {
220
- members.set(name, member)
244
+ const PLAIN_RE_EXPORT = /export\s*\{([^{}]*)\}\s*from\s*(['"])([^'"\\\n]*)\2[ \t]*;?/y
245
+ const PLAIN_GAP = /(?:\s+|\/\/[^\n]*|\/\*[\s\S]*?\*\/)*/y
246
+ const PLAIN_SPECIFIER = /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/
247
+
248
+ /**
249
+ * A generated catalogue is usually nothing but `export { a as b } from './x'` lines. Read that
250
+ * exact shape without building an AST (oxc's module record alone costs more than the parse on a
251
+ * 1 MB entry); anything else - or a repeated name - answers undefined and takes the oxc path.
252
+ */
253
+ function plainReExports(source: string): Map<string, BarrelMember> | undefined {
254
+ // The scan knows only LF as a line end; CR, U+2028 and U+2029 also end a `//` comment.
255
+ if (/[\r\u2028\u2029]/.test(source)) return undefined
256
+ const exports = new Map<string, BarrelMember>()
257
+ let at = 0
258
+ for (;;) {
259
+ PLAIN_GAP.lastIndex = at
260
+ PLAIN_GAP.exec(source)
261
+ if (PLAIN_GAP.lastIndex >= source.length) break
262
+ // Without a `;`, only a line break can end the statement before the next one.
263
+ if (at > 0 && source[at - 1] !== ';' && !source.slice(at, PLAIN_GAP.lastIndex).includes('\n'))
264
+ return undefined
265
+ PLAIN_RE_EXPORT.lastIndex = PLAIN_GAP.lastIndex
266
+ const statement = PLAIN_RE_EXPORT.exec(source)
267
+ if (!statement) return undefined
268
+ at = PLAIN_RE_EXPORT.lastIndex
269
+ const parts = statement[1]!.split(',')
270
+ for (const [index, part] of parts.entries()) {
271
+ const specifier = PLAIN_SPECIFIER.exec(part.trim())
272
+ if (!specifier) {
273
+ if (part.trim() === '' && index === parts.length - 1 && index > 0) continue
274
+ return undefined
275
+ }
276
+ const imported = specifier[1]!
277
+ const name = specifier[2] ?? imported
278
+ if (exports.has(name)) return undefined
279
+ exports.set(name, { source: statement[3]!, imported })
221
280
  }
222
281
  }
223
- if (members.size / exportCount >= GENERATED_BARREL_LEAF_RATIO) return members
224
- return manyToFewBarrelMembers(parsed.program.body, exports, entry)
282
+ return exports
225
283
  }
226
284
 
227
285
  /**
@@ -234,26 +292,28 @@ function parseGeneratedBarrel(entry: string): BarrelMap | undefined {
234
292
  * read for demanded members.
235
293
  */
236
294
  function manyToFewBarrelMembers(
237
- body: readonly { type: string; declaration?: unknown }[],
238
295
  exports: ReadonlyMap<string, BarrelMember>,
239
296
  entry: string,
240
297
  ): BarrelMap | undefined {
241
- for (const node of body) {
242
- if (node.type !== 'ExportNamedDeclaration' || node.declaration) return undefined
243
- }
244
298
  const byDirectory = new Map<string, Map<string, string[]>>()
299
+ // Thousands of names share a handful of leaves: judge each leaf once.
300
+ const unambiguous = new Map<string, boolean>()
245
301
  const members = new Map<string, BarrelMember>()
246
302
  for (const [name, member] of exports) {
247
303
  if (!member.source.startsWith('.')) continue
248
- const file = path.resolve(path.dirname(entry), member.source)
249
- const directory = path.dirname(file)
250
- let siblings = byDirectory.get(directory)
251
- if (!siblings) {
252
- siblings = siblingFilesByStem(directory, entry)
253
- byDirectory.set(directory, siblings)
304
+ let leaf = unambiguous.get(member.source)
305
+ if (leaf === undefined) {
306
+ const file = path.resolve(path.dirname(entry), member.source)
307
+ const directory = path.dirname(file)
308
+ let siblings = byDirectory.get(directory)
309
+ if (!siblings) {
310
+ siblings = siblingFilesByStem(directory, entry)
311
+ byDirectory.set(directory, siblings)
312
+ }
313
+ leaf = siblings.get(path.basename(file).replace(/\.(?:c|m)?js$/, ''))?.length === 1
314
+ unambiguous.set(member.source, leaf)
254
315
  }
255
- if (siblings.get(path.basename(file).replace(/\.(?:c|m)?js$/, ''))?.length !== 1) continue
256
- members.set(name, member)
316
+ if (leaf) members.set(name, member)
257
317
  }
258
318
  return members.size > 0 ? members : undefined
259
319
  }
@@ -14,7 +14,7 @@
14
14
  // Everything is resolved relative to `process.cwd()`, matching the SWC transform's root. That is what
15
15
  // makes the multi-project fixture work: each sub-project is built with its own cwd.
16
16
 
17
- import { existsSync } from 'node:fs'
17
+ import { existsSync, realpathSync } from 'node:fs'
18
18
  import path from 'node:path'
19
19
  import { withSniff, type ServerSourceTransform } from '../../extensions'
20
20
  import type { RelayCompilerConfig } from './config'
@@ -35,6 +35,14 @@ function relayTagPattern(): RegExp {
35
35
 
36
36
  const OPERATION_NAME = /\b(?:query|mutation|subscription|fragment)\s+([A-Za-z_][\w]*)/
37
37
 
38
+ function realFile(file: string): string {
39
+ try {
40
+ return realpathSync(file)
41
+ } catch {
42
+ return file
43
+ }
44
+ }
45
+
38
46
  function isUnder(dir: string, file: string): boolean {
39
47
  const relative = path.relative(dir, file)
40
48
  return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative)
@@ -61,6 +69,7 @@ export function createRelayTransform(
61
69
 
62
70
  const cwd = path.resolve(process.cwd())
63
71
  const srcDir = path.resolve(cwd, relay.src)
72
+ const realSrcDir = realFile(srcDir)
64
73
  const artifactDir = relay.artifactDirectory
65
74
  ? path.resolve(cwd, relay.artifactDirectory)
66
75
  : undefined
@@ -88,11 +97,14 @@ export function createRelayTransform(
88
97
 
89
98
  return withSniff(['graphql'], (source, file) => {
90
99
  if (!source.includes('graphql`') && !/graphql\s*`/.test(source)) return source
91
- const absolute = path.resolve(file)
100
+ const resolved = path.resolve(file)
101
+ // A build materializes pages under its out dir; its links lead back to the source file.
102
+ const absolute = isUnder(cwd, resolved) ? realFile(resolved) : resolved
92
103
  // Next scopes the transform to `src`. Files outside the build cwd entirely
93
104
  // (materialized copies) are not covered by that check, so only skip a file
94
105
  // that lives under the cwd but outside the configured source root.
95
- if (isUnder(cwd, absolute) && !isUnder(srcDir, absolute)) return source
106
+ const inSrc = isUnder(srcDir, resolved) || isUnder(realSrcDir, absolute)
107
+ if (isUnder(cwd, absolute) && !inSrc) return source
96
108
 
97
109
  const bindings = new Map<string, string>()
98
110
  const replaced = source.replace(relayTagPattern(), (match, body: string) => {
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readdirSync, readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { nextCompatEnabled } from '../compat/aliases'
4
+ import { productionRelease } from '../runtime/production'
4
5
  import type { ResolvedConfig } from '../config'
5
6
  import type { ResponseFinalizer, ResponseFinalizerContext } from '../extensions'
6
7
  import { getNextConfig } from './next/config-loader'
@@ -31,7 +32,7 @@ export function cacheControlFinalizers(config: ResolvedConfig): ResponseFinalize
31
32
  rules ??= loadCompatHeaders(config.root)
32
33
  applyConfigHeaders(ctx, await rules, config.basePath)
33
34
  applyPoweredByHeader(ctx)
34
- pagesRevalidateRules ??= loadPagesRevalidateRules(config.root)
35
+ pagesRevalidateRules ??= loadPagesRevalidateRules(config)
35
36
  applyDefaultIsrHeader(ctx, pagesRevalidateRules)
36
37
  }
37
38
  return [finalizer]
@@ -139,20 +140,27 @@ function isBrowserCacheable(value: string): boolean {
139
140
  return !/\bno-store\b|\bno-cache\b/i.test(value)
140
141
  }
141
142
 
142
- function loadPagesRevalidateRules(root: string): RevalidateRule[] {
143
+ function loadPagesRevalidateRules(config: ResolvedConfig): RevalidateRule[] {
144
+ const facts =
145
+ productionRelease(config)?.compat?.pagesRevalidate ?? pagesRevalidateFacts(config.root)
146
+ return facts.flatMap(([relative, revalidateSeconds]) => {
147
+ const regex = pagesRouteRegex(relative)
148
+ return regex ? [{ regex, revalidateSeconds }] : []
149
+ })
150
+ }
151
+
152
+ /** Pages with a `getStaticProps` revalidate window: `[pages-relative file, seconds]`. */
153
+ export function pagesRevalidateFacts(root: string): [string, number][] {
143
154
  const pagesDir = path.join(root, 'pages')
144
155
  if (!existsSync(pagesDir)) return []
145
- const rules: RevalidateRule[] = []
156
+ const facts: [string, number][] = []
146
157
  for (const file of walkFiles(pagesDir)) {
147
158
  const source = readFileSync(file, 'utf8')
148
159
  if (!/\bgetStaticProps\b/.test(source)) continue
149
160
  const match = /\brevalidate\s*:\s*(\d+)/.exec(source)
150
- if (!match?.[1]) continue
151
- const regex = pagesRouteRegex(path.relative(pagesDir, file))
152
- if (!regex) continue
153
- rules.push({ regex, revalidateSeconds: Number(match[1]) })
161
+ if (match?.[1]) facts.push([path.relative(pagesDir, file), Number(match[1])])
154
162
  }
155
- return rules
163
+ return facts
156
164
  }
157
165
 
158
166
  function walkFiles(dir: string): string[] {
@@ -4,10 +4,10 @@ import path from 'node:path'
4
4
  import type { Plugin } from 'esbuild'
5
5
  import type { ResolvedConfig } from '../../config'
6
6
  import { resolveImport } from '../../resolve/imports'
7
- import { hoistCssImports } from '../../css/build'
8
7
  import { maybeLightningcssTransform } from './lightningcss'
9
8
  import { escapeRegex } from '../../utils/code'
10
9
  import { cssModuleScopePath } from '../../utils/fs'
10
+ import { productionRelease } from '../../runtime/production'
11
11
 
12
12
  interface ComposeRef {
13
13
  names: string[]
@@ -23,31 +23,44 @@ interface CssModuleInfo {
23
23
  const pagesCompatIgnoredSourceEntries = new Set(['.next', '.pnext', 'app', 'node_modules', 'pages'])
24
24
 
25
25
  export function materializeNextCssSources(config: ResolvedConfig) {
26
+ // A production release already compiled everything these links would let resolve.
27
+ if (productionRelease(config)) return
26
28
  const generatedRoot = path.dirname(config.appPath)
27
29
  if (path.basename(path.dirname(generatedRoot)) !== 'pnext-pages-compat') return
28
30
 
31
+ const outTop = path.relative(config.root, config.outRootPath).split(path.sep)[0]
32
+ // Inside the app (a build's output) links stay relative, naming no build-machine path.
33
+ const inApp = !path.relative(config.root, generatedRoot).startsWith('..')
29
34
  for (const entry of readdirSync(config.root)) {
30
- if (pagesCompatIgnoredSourceEntries.has(entry)) continue
35
+ if (pagesCompatIgnoredSourceEntries.has(entry) || entry === outTop) continue
31
36
  const source = path.join(config.root, entry)
32
37
  const target = path.join(generatedRoot, entry)
33
38
  if (existsSync(target)) continue
34
39
  try {
35
- symlinkSync(source, target, lstatSync(source).isDirectory() ? 'dir' : 'file')
40
+ symlinkSync(
41
+ inApp ? path.relative(generatedRoot, source) : source,
42
+ target,
43
+ lstatSync(source).isDirectory() ? 'dir' : 'file',
44
+ )
36
45
  } catch {
37
46
  // A concurrent materialization may have linked the same source already.
38
47
  }
39
48
  }
40
49
  }
41
50
 
51
+ let cssBuild: Promise<typeof import('../../css/build')> | undefined
52
+
42
53
  export function nextCssModuleChunkPlugin(config: ResolvedConfig): Plugin {
43
54
  return {
44
55
  name: 'pnext-compat-css-modules',
45
56
  setup(build) {
46
- build.onLoad({ filter: /\.css$/ }, ({ path: file }) => {
57
+ build.onLoad({ filter: /\.css$/ }, async ({ path: file }) => {
47
58
  const source = nextCssSource(file, config.root)
48
59
  // This onLoad claims every `.css`, so core's directive-order plugin
49
60
  // (registered after it) never sees a compat app's stylesheet — hoist here.
50
- const raw = hoistCssImports(readFileSync(source, 'utf8'))
61
+ const raw = (await (cssBuild ??= import('../../css/build'))).hoistCssImports(
62
+ readFileSync(source, 'utf8'),
63
+ )
51
64
  const contents = file.endsWith('.module.css')
52
65
  ? transformCssModule(raw, source, config.root)
53
66
  : rewriteTransparentBodyChildren(raw)
@@ -10,7 +10,7 @@
10
10
 
11
11
  import { getWorkUnit } from '../../request/context'
12
12
  import { getRequestRuntime } from '../../routing/request-environment'
13
- import { selectRouteForRequest } from '../../routing/routes'
13
+ import { selectRouteForRequest } from '../../routing/match'
14
14
  import path from 'node:path'
15
15
  import type { RouteManifestEntry } from '../../types'
16
16
  import type { RequestErrorContext, RequestErrorInfo } from '../../extensions'
@@ -12,7 +12,15 @@
12
12
  // separate module state) and calling its register() with NEXT_RUNTIME='edge' set for the duration.
13
13
  // Apps without edge entities never get the pass.
14
14
 
15
- import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from 'node:fs'
15
+ import {
16
+ existsSync,
17
+ mkdirSync,
18
+ readFileSync,
19
+ readdirSync,
20
+ rmSync,
21
+ statSync,
22
+ writeFileSync,
23
+ } from 'node:fs'
16
24
  import path from 'node:path'
17
25
  import { pathToFileURL } from 'node:url'
18
26
  import { createRequire } from 'node:module'
@@ -21,6 +29,7 @@ import { build } from '../../utils/esbuild'
21
29
  import type { ResolvedConfig } from '../../config'
22
30
  import { resolveExternalLoadTarget } from '../../resolve/imports'
23
31
  import { compatAliases, reactServerLayerAliases } from '../aliases'
32
+ import { productionRelease } from '../../runtime/production'
24
33
 
25
34
  const INSTRUMENTATION_BASENAMES = [
26
35
  'instrumentation.ts',
@@ -136,38 +145,89 @@ async function importInstrumentation(
136
145
  config: ResolvedConfig,
137
146
  suffix = '',
138
147
  ): Promise<InstrumentationModule> {
139
- const root = config.root
140
148
  // Under config.outPath, so a dev server's scratch bundle lives in its own
141
149
  // subtree and a concurrent build never removes it mid-import.
142
150
  const outDir = path.join(config.outPath, 'instrumentation')
143
151
  mkdirSync(outDir, { recursive: true })
144
152
  const outfile = path.join(outDir, `instrumentation.${Date.now()}${suffix}.mjs`)
145
- const tsconfig = path.join(root, 'tsconfig.json')
146
153
  try {
147
- await build({
148
- entryPoints: [file],
149
- outfile,
150
- bundle: true,
151
- platform: 'node',
152
- format: 'esm',
153
- target: 'esnext',
154
- packages: 'external',
155
- plugins: [instrumentationPlugin(root, config)],
156
- ...(existsSync(tsconfig) ? { tsconfig } : {}),
157
- define: {
158
- __dirname: JSON.stringify(path.dirname(file)),
159
- __filename: JSON.stringify(file),
160
- 'import.meta.url': JSON.stringify(pathToFileURL(file).href),
161
- },
162
- logLevel: 'silent',
163
- sourcemap: false,
164
- })
154
+ await bundleInstrumentation(file, config, outfile)
165
155
  return (await import(pathToFileURL(outfile).href)) as InstrumentationModule
166
156
  } finally {
167
157
  rmSync(outfile, { force: true })
168
158
  }
169
159
  }
170
160
 
161
+ /**
162
+ * Bundle instrumentation for a production release: the node instance, plus a separate edge instance
163
+ * file when the app has edge entities. Out-relative paths, or undefined when the app has none.
164
+ */
165
+ export async function emitReleaseInstrumentation(config: ResolvedConfig, outDir: string) {
166
+ const file = findInstrumentation(config)
167
+ if (!file) return undefined
168
+ const node = await releaseInstrumentation(file, config, outDir, 'instrumentation')
169
+ if (!appHasEdgeEntities(config)) return { file: path.relative(config.outPath, node) }
170
+ const edge = await releaseInstrumentation(file, config, outDir, 'instrumentation.edge')
171
+ return { file: path.relative(config.outPath, node), edge: path.relative(config.outPath, edge) }
172
+ }
173
+
174
+ /** One release instance: located relative to itself, named by its content (a new generation never reuses a module). */
175
+ async function releaseInstrumentation(
176
+ file: string,
177
+ config: ResolvedConfig,
178
+ outDir: string,
179
+ name: string,
180
+ ) {
181
+ const temporary = path.join(outDir, `${name}.${process.pid}.tmp.mjs`)
182
+ await bundleInstrumentation(file, config, temporary, outDir)
183
+ const { relocateReleaseBundle } = await import('../../runtime/modules')
184
+ const contents = relocateReleaseBundle(config, temporary, readFileSync(temporary, 'utf8'))
185
+ rmSync(temporary, { force: true })
186
+ const outfile = path.join(outDir, `${name}.${Bun.hash(contents).toString(36)}.mjs`)
187
+ writeFileSync(outfile, contents)
188
+ return outfile
189
+ }
190
+
191
+ async function bundleInstrumentation(
192
+ file: string,
193
+ config: ResolvedConfig,
194
+ outfile: string,
195
+ releaseDir?: string,
196
+ ) {
197
+ const root = config.root
198
+ const tsconfig = path.join(root, 'tsconfig.json')
199
+ // A release instance finds its source relative to itself, never at the build machine's path.
200
+ const sourceUrl = releaseDir
201
+ ? `new URL(${JSON.stringify(path.relative(releaseDir, file).split(path.sep).join('/'))}, import.meta.url).href`
202
+ : JSON.stringify(pathToFileURL(file).href)
203
+ await build({
204
+ entryPoints: [file],
205
+ outfile,
206
+ bundle: true,
207
+ platform: 'node',
208
+ format: 'esm',
209
+ target: 'esnext',
210
+ packages: 'external',
211
+ plugins: [instrumentationPlugin(root, config)],
212
+ ...(existsSync(tsconfig) ? { tsconfig } : {}),
213
+ banner: {
214
+ js:
215
+ 'import { fileURLToPath as __pnextFileURLToPath } from "node:url";\n' +
216
+ 'import { dirname as __pnextDirname } from "node:path";\n' +
217
+ `const __pnextSourceUrl = ${sourceUrl};\n` +
218
+ 'const __pnextSourceFile = __pnextFileURLToPath(__pnextSourceUrl);\n' +
219
+ 'const __pnextSourceDir = __pnextDirname(__pnextSourceFile);',
220
+ },
221
+ define: {
222
+ __dirname: '__pnextSourceDir',
223
+ __filename: '__pnextSourceFile',
224
+ 'import.meta.url': '__pnextSourceUrl',
225
+ },
226
+ logLevel: 'silent',
227
+ sourcemap: false,
228
+ })
229
+ }
230
+
171
231
  /**
172
232
  * Load instrumentation and run register() once. Idempotent: repeated calls
173
233
  * (build + start both run init hooks) reuse the first load. Returns immediately;
@@ -175,6 +235,11 @@ async function importInstrumentation(
175
235
  */
176
236
  export function loadInstrumentation(config: ResolvedConfig): void {
177
237
  if (readyGate) return
238
+ const released = productionRelease(config)
239
+ if (released) {
240
+ readyGate = registerReleased(released.instrumentation)
241
+ return
242
+ }
178
243
  const file = findInstrumentation(config)
179
244
  if (!file) {
180
245
  readyGate = Promise.resolve()
@@ -197,21 +262,49 @@ export function loadInstrumentation(config: ResolvedConfig): void {
197
262
  })()
198
263
  }
199
264
 
265
+ /** A release's prebuilt instrumentation: register() on the node instance, then the edge instance. */
266
+ async function registerReleased(instrumentation: { file?: string; edge?: string } | undefined) {
267
+ if (!instrumentation?.file) return
268
+ try {
269
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
270
+ if (!process.env.NEXT_RUNTIME) process.env.NEXT_RUNTIME = 'nodejs'
271
+ loaded = (await import(pathToFileURL(instrumentation.file).href)) as InstrumentationModule
272
+ await loaded.register?.()
273
+ if (instrumentation.edge) {
274
+ await withEdgeRuntime(async () => {
275
+ const edgeInstance = (await import(
276
+ pathToFileURL(instrumentation.edge!).href
277
+ )) as InstrumentationModule
278
+ await edgeInstance.register?.()
279
+ }, 'instrumentation register() (edge pass) failed:')
280
+ }
281
+ } catch (error) {
282
+ console.error('instrumentation register() failed:', error)
283
+ }
284
+ }
285
+
200
286
  /**
201
287
  * The edge boot pass: a fresh instrumentation instance registered with NEXT_RUNTIME='edge' for the
202
288
  * duration of the call. A double provider registration is harmless - @opentelemetry/api rejects a second
203
289
  * global registration and keeps the first.
204
290
  */
205
291
  async function runEdgeRegisterPass(file: string, config: ResolvedConfig): Promise<void> {
292
+ await withEdgeRuntime(async () => {
293
+ const edgeInstance = await importInstrumentation(file, config, '.edge')
294
+ await edgeInstance.register?.()
295
+ }, 'instrumentation register() (edge pass) failed:')
296
+ }
297
+
298
+ /** Run `task` with NEXT_RUNTIME='edge', restoring the previous value. */
299
+ async function withEdgeRuntime(task: () => Promise<void>, failure: string): Promise<void> {
206
300
  // eslint-disable-next-line turbo/no-undeclared-env-vars
207
301
  const previous = process.env.NEXT_RUNTIME
208
302
  // eslint-disable-next-line turbo/no-undeclared-env-vars
209
303
  process.env.NEXT_RUNTIME = 'edge'
210
304
  try {
211
- const edgeInstance = await importInstrumentation(file, config, '.edge')
212
- await edgeInstance.register?.()
305
+ await task()
213
306
  } catch (error) {
214
- console.error('instrumentation register() (edge pass) failed:', error)
307
+ console.error(failure, error)
215
308
  } finally {
216
309
  if (previous === undefined) {
217
310
  // eslint-disable-next-line turbo/no-undeclared-env-vars
@@ -18,9 +18,8 @@ import { currentRequest, getWorkUnit } from '../../request/context'
18
18
  // readonly property." `require()` returns the real, mutable CJS exports
19
19
  // object that node/http/https resolve `.get` calls through at runtime, so
20
20
  // patch that instead of the namespace binding.
21
+ // Required on install, not at import: loading node:http/https costs every build ~10 ms.
21
22
  const requireNode = createRequire(import.meta.url)
22
- const httpModule = requireNode('node:http') as typeof http
23
- const httpsModule = requireNode('node:https') as typeof https
24
23
 
25
24
  interface TestProxyInfo {
26
25
  proxyPort: number
@@ -284,6 +283,8 @@ export function installTestProxyFetch(): void {
284
283
  ;(testFetch as typeof fetch).preconnect = originalFetch.preconnect?.bind(originalFetch)
285
284
  globalThis.fetch = testFetch as typeof fetch
286
285
 
286
+ const httpModule = requireNode('node:http') as typeof http
287
+ const httpsModule = requireNode('node:https') as typeof https
287
288
  const originalHttpGet = httpModule.get
288
289
  const originalHttpsGet = httpsModule.get
289
290
  httpModule.get = patchableGet(originalHttpGet, originalFetch)