@nifrajs/web 4.0.2 → 5.1.0

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 (426) hide show
  1. package/README.md +19 -0
  2. package/dist/build-vite.d.ts +19 -0
  3. package/dist/build-vite.d.ts.map +1 -1
  4. package/dist/build-vite.js +31 -10
  5. package/dist/build-vite.js.map +1 -1
  6. package/dist/build.d.ts +8 -10
  7. package/dist/build.d.ts.map +1 -1
  8. package/dist/build.js +90 -31
  9. package/dist/build.js.map +1 -1
  10. package/dist/cdn.d.ts +8 -0
  11. package/dist/cdn.d.ts.map +1 -1
  12. package/dist/cdn.js +14 -15
  13. package/dist/cdn.js.map +1 -1
  14. package/dist/client.d.ts +6 -6
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +46 -18
  17. package/dist/client.js.map +1 -1
  18. package/dist/deferred.d.ts +2 -2
  19. package/dist/deferred.d.ts.map +1 -1
  20. package/dist/deferred.js +28 -7
  21. package/dist/deferred.js.map +1 -1
  22. package/dist/dev-feed.d.ts.map +1 -1
  23. package/dist/dev-feed.js +24 -5
  24. package/dist/dev-feed.js.map +1 -1
  25. package/dist/dev-port.d.ts +3 -2
  26. package/dist/dev-port.d.ts.map +1 -1
  27. package/dist/dev-port.js +2 -6
  28. package/dist/dev-port.js.map +1 -1
  29. package/dist/dev-session.d.ts.map +1 -1
  30. package/dist/dev-session.js +4 -14
  31. package/dist/dev-session.js.map +1 -1
  32. package/dist/dev.d.ts +7 -17
  33. package/dist/dev.d.ts.map +1 -1
  34. package/dist/dev.js +13 -1
  35. package/dist/dev.js.map +1 -1
  36. package/dist/draft.d.ts +8 -5
  37. package/dist/draft.d.ts.map +1 -1
  38. package/dist/draft.js +30 -13
  39. package/dist/draft.js.map +1 -1
  40. package/dist/fonts-google.d.ts.map +1 -1
  41. package/dist/fonts-google.js +7 -0
  42. package/dist/fonts-google.js.map +1 -1
  43. package/dist/index.d.ts +5 -4
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -3
  46. package/dist/index.js.map +1 -1
  47. package/dist/internal/codegen.d.ts +1 -0
  48. package/dist/internal/codegen.d.ts.map +1 -1
  49. package/dist/internal/codegen.js +56 -29
  50. package/dist/internal/codegen.js.map +1 -1
  51. package/dist/internal/disposable-dir.d.ts +8 -0
  52. package/dist/internal/disposable-dir.d.ts.map +1 -0
  53. package/dist/internal/disposable-dir.js +25 -0
  54. package/dist/internal/disposable-dir.js.map +1 -0
  55. package/dist/internal/entry-chunks.d.ts +9 -0
  56. package/dist/internal/entry-chunks.d.ts.map +1 -0
  57. package/dist/internal/entry-chunks.js +15 -0
  58. package/dist/internal/entry-chunks.js.map +1 -0
  59. package/dist/internal/evidence-traversal.d.ts +12 -0
  60. package/dist/internal/evidence-traversal.d.ts.map +1 -0
  61. package/dist/internal/evidence-traversal.js +48 -0
  62. package/dist/internal/evidence-traversal.js.map +1 -0
  63. package/dist/internal/head-merge.d.ts +6 -0
  64. package/dist/internal/head-merge.d.ts.map +1 -1
  65. package/dist/internal/head-merge.js +9 -0
  66. package/dist/internal/head-merge.js.map +1 -1
  67. package/dist/internal/js-string.d.ts +2 -0
  68. package/dist/internal/js-string.d.ts.map +1 -1
  69. package/dist/internal/js-string.js +5 -1
  70. package/dist/internal/js-string.js.map +1 -1
  71. package/dist/internal/mount-shadow.js +1 -1
  72. package/dist/internal/mount-shadow.js.map +1 -1
  73. package/dist/internal/output-guard.d.ts +7 -0
  74. package/dist/internal/output-guard.d.ts.map +1 -1
  75. package/dist/internal/output-guard.js +80 -8
  76. package/dist/internal/output-guard.js.map +1 -1
  77. package/dist/internal/package-entries.d.ts +34 -0
  78. package/dist/internal/package-entries.d.ts.map +1 -0
  79. package/dist/internal/package-entries.js +324 -0
  80. package/dist/internal/package-entries.js.map +1 -0
  81. package/dist/internal/page-execution.d.ts +6 -0
  82. package/dist/internal/page-execution.d.ts.map +1 -1
  83. package/dist/internal/page-execution.js +437 -114
  84. package/dist/internal/page-execution.js.map +1 -1
  85. package/dist/internal/parity.d.ts.map +1 -1
  86. package/dist/internal/parity.js +15 -2
  87. package/dist/internal/parity.js.map +1 -1
  88. package/dist/internal/private-env.d.ts +8 -0
  89. package/dist/internal/private-env.d.ts.map +1 -1
  90. package/dist/internal/private-env.js +25 -10
  91. package/dist/internal/private-env.js.map +1 -1
  92. package/dist/internal/progressive-cookies.d.ts +14 -0
  93. package/dist/internal/progressive-cookies.d.ts.map +1 -0
  94. package/dist/internal/progressive-cookies.js +43 -0
  95. package/dist/internal/progressive-cookies.js.map +1 -0
  96. package/dist/internal/public-env.d.ts +2 -0
  97. package/dist/internal/public-env.d.ts.map +1 -0
  98. package/dist/internal/public-env.js +13 -0
  99. package/dist/internal/public-env.js.map +1 -0
  100. package/dist/internal/render-document.d.ts +5 -44
  101. package/dist/internal/render-document.d.ts.map +1 -1
  102. package/dist/internal/render-document.js +51 -63
  103. package/dist/internal/render-document.js.map +1 -1
  104. package/dist/internal/response-controls.d.ts +2 -0
  105. package/dist/internal/response-controls.d.ts.map +1 -1
  106. package/dist/internal/response-controls.js +26 -16
  107. package/dist/internal/response-controls.js.map +1 -1
  108. package/dist/internal/revive-dates.d.ts +16 -0
  109. package/dist/internal/revive-dates.d.ts.map +1 -0
  110. package/dist/internal/revive-dates.js +32 -0
  111. package/dist/internal/revive-dates.js.map +1 -0
  112. package/dist/internal/route-path.d.ts +14 -0
  113. package/dist/internal/route-path.d.ts.map +1 -0
  114. package/dist/internal/route-path.js +19 -0
  115. package/dist/internal/route-path.js.map +1 -0
  116. package/dist/internal/secret-scan.d.ts.map +1 -1
  117. package/dist/internal/secret-scan.js +190 -20
  118. package/dist/internal/secret-scan.js.map +1 -1
  119. package/dist/internal/server-boundary.d.ts.map +1 -1
  120. package/dist/internal/server-boundary.js +33 -5
  121. package/dist/internal/server-boundary.js.map +1 -1
  122. package/dist/internal/web-app.d.ts +25 -18
  123. package/dist/internal/web-app.d.ts.map +1 -1
  124. package/dist/internal/web-app.js +81 -24
  125. package/dist/internal/web-app.js.map +1 -1
  126. package/dist/internal/wire-date.d.ts +3 -0
  127. package/dist/internal/wire-date.d.ts.map +1 -0
  128. package/dist/internal/wire-date.js +14 -0
  129. package/dist/internal/wire-date.js.map +1 -0
  130. package/dist/internal/without-query.d.ts +4 -0
  131. package/dist/internal/without-query.d.ts.map +1 -0
  132. package/dist/internal/without-query.js +9 -0
  133. package/dist/internal/without-query.js.map +1 -0
  134. package/dist/internal/zone-graph.d.ts +4 -0
  135. package/dist/internal/zone-graph.d.ts.map +1 -1
  136. package/dist/internal/zone-graph.js +71 -20
  137. package/dist/internal/zone-graph.js.map +1 -1
  138. package/dist/isr.d.ts +59 -3
  139. package/dist/isr.d.ts.map +1 -1
  140. package/dist/isr.js +311 -41
  141. package/dist/isr.js.map +1 -1
  142. package/dist/llms-txt.d.ts +2 -0
  143. package/dist/llms-txt.d.ts.map +1 -1
  144. package/dist/llms-txt.js +29 -3
  145. package/dist/llms-txt.js.map +1 -1
  146. package/dist/manifest.d.ts +37 -4
  147. package/dist/manifest.d.ts.map +1 -1
  148. package/dist/manifest.js +4 -0
  149. package/dist/manifest.js.map +1 -1
  150. package/dist/open-resolved.d.ts +18 -0
  151. package/dist/open-resolved.d.ts.map +1 -0
  152. package/dist/open-resolved.js +62 -0
  153. package/dist/open-resolved.js.map +1 -0
  154. package/dist/plugins/kit.d.ts +1 -0
  155. package/dist/plugins/kit.d.ts.map +1 -1
  156. package/dist/plugins/kit.js +26 -11
  157. package/dist/plugins/kit.js.map +1 -1
  158. package/dist/plugins/vite-leak-guard.d.ts +9 -1
  159. package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
  160. package/dist/plugins/vite-leak-guard.js +84 -7
  161. package/dist/plugins/vite-leak-guard.js.map +1 -1
  162. package/dist/plugins/vite-zone-guard.d.ts.map +1 -1
  163. package/dist/plugins/vite-zone-guard.js +17 -21
  164. package/dist/plugins/vite-zone-guard.js.map +1 -1
  165. package/dist/plugins/zone-guard.d.ts.map +1 -1
  166. package/dist/plugins/zone-guard.js +44 -3
  167. package/dist/plugins/zone-guard.js.map +1 -1
  168. package/dist/prerender.d.ts +5 -1
  169. package/dist/prerender.d.ts.map +1 -1
  170. package/dist/prerender.js +41 -19
  171. package/dist/prerender.js.map +1 -1
  172. package/dist/public-dir.d.ts +8 -1
  173. package/dist/public-dir.d.ts.map +1 -1
  174. package/dist/public-dir.js +17 -6
  175. package/dist/public-dir.js.map +1 -1
  176. package/dist/query.d.ts +13 -4
  177. package/dist/query.d.ts.map +1 -1
  178. package/dist/query.js +89 -26
  179. package/dist/query.js.map +1 -1
  180. package/dist/render-seam.d.ts +25 -2
  181. package/dist/render-seam.d.ts.map +1 -1
  182. package/dist/render-seam.js +1 -0
  183. package/dist/render-seam.js.map +1 -1
  184. package/dist/route-types.d.ts.map +1 -1
  185. package/dist/route-types.js +20 -9
  186. package/dist/route-types.js.map +1 -1
  187. package/dist/router.d.ts +9 -2
  188. package/dist/router.d.ts.map +1 -1
  189. package/dist/router.js +47 -50
  190. package/dist/router.js.map +1 -1
  191. package/dist/seo.d.ts +49 -0
  192. package/dist/seo.d.ts.map +1 -0
  193. package/dist/seo.js +48 -0
  194. package/dist/seo.js.map +1 -0
  195. package/dist/server-components/build-info.d.ts +3 -0
  196. package/dist/server-components/build-info.d.ts.map +1 -0
  197. package/dist/server-components/build-info.js +7 -0
  198. package/dist/server-components/build-info.js.map +1 -0
  199. package/dist/server-components/build-target.d.ts +12 -0
  200. package/dist/server-components/build-target.d.ts.map +1 -0
  201. package/dist/server-components/build-target.js +153 -0
  202. package/dist/server-components/build-target.js.map +1 -0
  203. package/dist/server-components/build.d.ts +24 -0
  204. package/dist/server-components/build.d.ts.map +1 -0
  205. package/dist/server-components/build.js +366 -0
  206. package/dist/server-components/build.js.map +1 -0
  207. package/dist/server-components/bundle-proof.d.ts +3 -0
  208. package/dist/server-components/bundle-proof.d.ts.map +1 -0
  209. package/dist/server-components/bundle-proof.js +23 -0
  210. package/dist/server-components/bundle-proof.js.map +1 -0
  211. package/dist/server-components/client.d.ts +46 -0
  212. package/dist/server-components/client.d.ts.map +1 -0
  213. package/dist/server-components/client.js +594 -0
  214. package/dist/server-components/client.js.map +1 -0
  215. package/dist/server-components/definition.d.ts +11 -0
  216. package/dist/server-components/definition.d.ts.map +1 -0
  217. package/dist/server-components/definition.js +94 -0
  218. package/dist/server-components/definition.js.map +1 -0
  219. package/dist/server-components/dev-http.d.ts +5 -0
  220. package/dist/server-components/dev-http.d.ts.map +1 -0
  221. package/dist/server-components/dev-http.js +71 -0
  222. package/dist/server-components/dev-http.js.map +1 -0
  223. package/dist/server-components/error.d.ts +9 -0
  224. package/dist/server-components/error.d.ts.map +1 -0
  225. package/dist/server-components/error.js +24 -0
  226. package/dist/server-components/error.js.map +1 -0
  227. package/dist/server-components/frames.d.ts +7 -0
  228. package/dist/server-components/frames.d.ts.map +1 -0
  229. package/dist/server-components/frames.js +169 -0
  230. package/dist/server-components/frames.js.map +1 -0
  231. package/dist/server-components/html-policy.d.ts +6 -0
  232. package/dist/server-components/html-policy.d.ts.map +1 -0
  233. package/dist/server-components/html-policy.js +75 -0
  234. package/dist/server-components/html-policy.js.map +1 -0
  235. package/dist/server-components/html.d.ts +4 -0
  236. package/dist/server-components/html.d.ts.map +1 -0
  237. package/dist/server-components/html.js +67 -0
  238. package/dist/server-components/html.js.map +1 -0
  239. package/dist/server-components/islands.d.ts +44 -0
  240. package/dist/server-components/islands.d.ts.map +1 -0
  241. package/dist/server-components/islands.js +42 -0
  242. package/dist/server-components/islands.js.map +1 -0
  243. package/dist/server-components/native.d.ts +4 -0
  244. package/dist/server-components/native.d.ts.map +1 -0
  245. package/dist/server-components/native.js +81 -0
  246. package/dist/server-components/native.js.map +1 -0
  247. package/dist/server-components/portal.d.ts +6 -0
  248. package/dist/server-components/portal.d.ts.map +1 -0
  249. package/dist/server-components/portal.js +35 -0
  250. package/dist/server-components/portal.js.map +1 -0
  251. package/dist/server-components/props.d.ts +3 -0
  252. package/dist/server-components/props.d.ts.map +1 -0
  253. package/dist/server-components/props.js +14 -0
  254. package/dist/server-components/props.js.map +1 -0
  255. package/dist/server-components/protocol.d.ts +44 -0
  256. package/dist/server-components/protocol.d.ts.map +1 -0
  257. package/dist/server-components/protocol.js +139 -0
  258. package/dist/server-components/protocol.js.map +1 -0
  259. package/dist/server-components/range.d.ts +24 -0
  260. package/dist/server-components/range.d.ts.map +1 -0
  261. package/dist/server-components/range.js +263 -0
  262. package/dist/server-components/range.js.map +1 -0
  263. package/dist/server-components/registry.d.ts +6 -0
  264. package/dist/server-components/registry.d.ts.map +1 -0
  265. package/dist/server-components/registry.js +30 -0
  266. package/dist/server-components/registry.js.map +1 -0
  267. package/dist/server-components/response.d.ts +4 -0
  268. package/dist/server-components/response.d.ts.map +1 -0
  269. package/dist/server-components/response.js +32 -0
  270. package/dist/server-components/response.js.map +1 -0
  271. package/dist/server-components/router-integration.d.ts +9 -0
  272. package/dist/server-components/router-integration.d.ts.map +1 -0
  273. package/dist/server-components/router-integration.js +29 -0
  274. package/dist/server-components/router-integration.js.map +1 -0
  275. package/dist/server-components/runtime.d.ts +14 -0
  276. package/dist/server-components/runtime.d.ts.map +1 -0
  277. package/dist/server-components/runtime.js +276 -0
  278. package/dist/server-components/runtime.js.map +1 -0
  279. package/dist/server-components/scheduler.d.ts +14 -0
  280. package/dist/server-components/scheduler.d.ts.map +1 -0
  281. package/dist/server-components/scheduler.js +74 -0
  282. package/dist/server-components/scheduler.js.map +1 -0
  283. package/dist/server-components/schema.d.ts +4 -0
  284. package/dist/server-components/schema.d.ts.map +1 -0
  285. package/dist/server-components/schema.js +77 -0
  286. package/dist/server-components/schema.js.map +1 -0
  287. package/dist/server-components/server-entry.d.ts +12 -0
  288. package/dist/server-components/server-entry.d.ts.map +1 -0
  289. package/dist/server-components/server-entry.js +90 -0
  290. package/dist/server-components/server-entry.js.map +1 -0
  291. package/dist/server-components/source.d.ts +15 -0
  292. package/dist/server-components/source.d.ts.map +1 -0
  293. package/dist/server-components/source.js +269 -0
  294. package/dist/server-components/source.js.map +1 -0
  295. package/dist/server-components/state.d.ts +4 -0
  296. package/dist/server-components/state.d.ts.map +1 -0
  297. package/dist/server-components/state.js +123 -0
  298. package/dist/server-components/state.js.map +1 -0
  299. package/dist/server-components/stream.d.ts +6 -0
  300. package/dist/server-components/stream.d.ts.map +1 -0
  301. package/dist/server-components/stream.js +70 -0
  302. package/dist/server-components/stream.js.map +1 -0
  303. package/dist/server-components/trusted-html.d.ts +3 -0
  304. package/dist/server-components/trusted-html.d.ts.map +1 -0
  305. package/dist/server-components/trusted-html.js +14 -0
  306. package/dist/server-components/trusted-html.js.map +1 -0
  307. package/dist/server-components/types.d.ts +107 -0
  308. package/dist/server-components/types.d.ts.map +1 -0
  309. package/dist/server-components/types.js +2 -0
  310. package/dist/server-components/types.js.map +1 -0
  311. package/dist/server-components/typescript.d.ts +11 -0
  312. package/dist/server-components/typescript.d.ts.map +1 -0
  313. package/dist/server-components/typescript.js +28 -0
  314. package/dist/server-components/typescript.js.map +1 -0
  315. package/dist/server-components/value.d.ts +5 -0
  316. package/dist/server-components/value.d.ts.map +1 -0
  317. package/dist/server-components/value.js +77 -0
  318. package/dist/server-components/value.js.map +1 -0
  319. package/dist/server-components/vite.d.ts +12 -0
  320. package/dist/server-components/vite.d.ts.map +1 -0
  321. package/dist/server-components/vite.js +197 -0
  322. package/dist/server-components/vite.js.map +1 -0
  323. package/dist/server-components.d.ts +5 -0
  324. package/dist/server-components.d.ts.map +1 -0
  325. package/dist/server-components.js +4 -0
  326. package/dist/server-components.js.map +1 -0
  327. package/dist/service-worker.d.ts +8 -1
  328. package/dist/service-worker.d.ts.map +1 -1
  329. package/dist/service-worker.js +20 -6
  330. package/dist/service-worker.js.map +1 -1
  331. package/dist/vite.d.ts +12 -0
  332. package/dist/vite.d.ts.map +1 -1
  333. package/dist/vite.js +7 -1
  334. package/dist/vite.js.map +1 -1
  335. package/dist/zones.d.ts +64 -2
  336. package/dist/zones.d.ts.map +1 -1
  337. package/dist/zones.js +331 -28
  338. package/dist/zones.js.map +1 -1
  339. package/package.json +102 -4
  340. package/src/build-vite.ts +31 -9
  341. package/src/build.ts +109 -31
  342. package/src/cdn.ts +18 -12
  343. package/src/client.ts +48 -17
  344. package/src/deferred.ts +27 -9
  345. package/src/dev-feed.ts +24 -5
  346. package/src/dev-port.ts +4 -10
  347. package/src/dev-session.ts +4 -13
  348. package/src/dev.ts +29 -1
  349. package/src/draft.ts +35 -14
  350. package/src/fonts-google.ts +10 -0
  351. package/src/index.ts +5 -6
  352. package/src/internal/codegen.ts +60 -29
  353. package/src/internal/disposable-dir.ts +24 -0
  354. package/src/internal/entry-chunks.ts +18 -0
  355. package/src/internal/evidence-traversal.ts +57 -0
  356. package/src/internal/head-merge.ts +16 -0
  357. package/src/internal/js-string.ts +6 -1
  358. package/src/internal/mount-shadow.ts +1 -1
  359. package/src/internal/output-guard.ts +88 -7
  360. package/src/internal/package-entries.ts +331 -0
  361. package/src/internal/page-execution.ts +573 -114
  362. package/src/internal/parity.ts +15 -2
  363. package/src/internal/private-env.ts +27 -13
  364. package/src/internal/progressive-cookies.ts +60 -0
  365. package/src/internal/public-env.ts +14 -0
  366. package/src/internal/render-document.ts +66 -89
  367. package/src/internal/response-controls.ts +31 -14
  368. package/src/internal/revive-dates.ts +35 -0
  369. package/src/internal/route-path.ts +24 -0
  370. package/src/internal/secret-scan.ts +190 -18
  371. package/src/internal/server-boundary.ts +29 -5
  372. package/src/internal/web-app.ts +126 -42
  373. package/src/internal/wire-date.ts +16 -0
  374. package/src/internal/without-query.ts +8 -0
  375. package/src/internal/zone-graph.ts +78 -25
  376. package/src/isr.ts +364 -45
  377. package/src/llms-txt.ts +32 -3
  378. package/src/manifest.ts +38 -4
  379. package/src/open-resolved.ts +64 -0
  380. package/src/plugins/kit.ts +31 -11
  381. package/src/plugins/vite-leak-guard.ts +104 -8
  382. package/src/plugins/vite-zone-guard.ts +21 -19
  383. package/src/plugins/zone-guard.ts +41 -2
  384. package/src/prerender.ts +39 -18
  385. package/src/public-dir.ts +27 -8
  386. package/src/query.ts +107 -26
  387. package/src/render-seam.ts +30 -2
  388. package/src/route-types.ts +34 -7
  389. package/src/router.ts +66 -59
  390. package/src/seo.ts +68 -0
  391. package/src/server-components/build-info.ts +11 -0
  392. package/src/server-components/build-target.ts +194 -0
  393. package/src/server-components/build.ts +419 -0
  394. package/src/server-components/bundle-proof.ts +33 -0
  395. package/src/server-components/client.ts +663 -0
  396. package/src/server-components/definition.ts +125 -0
  397. package/src/server-components/dev-http.ts +75 -0
  398. package/src/server-components/error.ts +24 -0
  399. package/src/server-components/frames.ts +181 -0
  400. package/src/server-components/html-policy.ts +94 -0
  401. package/src/server-components/html.ts +81 -0
  402. package/src/server-components/islands.ts +111 -0
  403. package/src/server-components/native.ts +101 -0
  404. package/src/server-components/portal.ts +42 -0
  405. package/src/server-components/props.ts +19 -0
  406. package/src/server-components/protocol.ts +167 -0
  407. package/src/server-components/range.ts +313 -0
  408. package/src/server-components/registry.ts +34 -0
  409. package/src/server-components/response.ts +44 -0
  410. package/src/server-components/router-integration.ts +40 -0
  411. package/src/server-components/runtime.ts +376 -0
  412. package/src/server-components/scheduler.ts +84 -0
  413. package/src/server-components/schema.ts +69 -0
  414. package/src/server-components/server-entry.ts +98 -0
  415. package/src/server-components/source.ts +324 -0
  416. package/src/server-components/state.ts +143 -0
  417. package/src/server-components/stream.ts +71 -0
  418. package/src/server-components/trusted-html.ts +21 -0
  419. package/src/server-components/types.ts +138 -0
  420. package/src/server-components/typescript.ts +39 -0
  421. package/src/server-components/value.ts +82 -0
  422. package/src/server-components/vite.ts +242 -0
  423. package/src/server-components.ts +32 -0
  424. package/src/service-worker.ts +24 -7
  425. package/src/vite.ts +8 -1
  426. package/src/zones.ts +418 -32
@@ -0,0 +1,39 @@
1
+ import { createRequire } from "node:module"
2
+ import type * as TS from "typescript"
3
+
4
+ /** The code of the error a TypeScript without the in-process compiler API raises here. */
5
+ export const UNSUPPORTED_TYPESCRIPT = "NIFRA_TS_UNSUPPORTED"
6
+
7
+ function isCompiler(value: unknown): value is typeof TS {
8
+ return (
9
+ typeof value === "object" &&
10
+ value !== null &&
11
+ "createSourceFile" in value &&
12
+ typeof value.createSourceFile === "function"
13
+ )
14
+ }
15
+
16
+ /**
17
+ * The TypeScript compiler API, resolved from `from` the way `import "typescript"` there would be.
18
+ * TypeScript 7's package ships no in-process compiler API (its root export is only `version`), so
19
+ * it raises an error that names the fix instead of a TypeError on first use.
20
+ */
21
+ export function loadTypeScript(from: string = import.meta.url): typeof TS {
22
+ const loaded: unknown = createRequire(from)("typescript")
23
+ if (isCompiler(loaded)) return loaded
24
+ const version =
25
+ typeof loaded === "object" &&
26
+ loaded !== null &&
27
+ "version" in loaded &&
28
+ typeof loaded.version === "string"
29
+ ? loaded.version
30
+ : "unknown"
31
+ throw Object.assign(
32
+ new Error(
33
+ `${UNSUPPORTED_TYPESCRIPT}: server components read component modules with the TypeScript compiler API, which TypeScript ${version} does not ship. Pin the project to TypeScript 6 (for example, \`bun add -d typescript@^6\`).`,
34
+ ),
35
+ { code: UNSUPPORTED_TYPESCRIPT, version },
36
+ )
37
+ }
38
+
39
+ export const ts: typeof TS = loadTypeScript()
@@ -0,0 +1,82 @@
1
+ import { ServerComponentError } from "./error.ts"
2
+ import type { ComponentValue } from "./types.ts"
3
+
4
+ /** Property order does not identify a resource; callers supply already-validated DTO inputs. */
5
+ export function componentInputKey(value: ComponentValue): string {
6
+ if (Array.isArray(value)) return `[${value.map(componentInputKey).join(",")}]`
7
+ if (typeof value === "object" && value !== null)
8
+ return `{${Object.keys(value)
9
+ .sort()
10
+ .map((key) => `${JSON.stringify(key)}:${componentInputKey(Reflect.get(value, key))}`)
11
+ .join(",")}}`
12
+ return JSON.stringify(value)
13
+ }
14
+
15
+ const encoder = new TextEncoder()
16
+ const forbidden = new Set(["__proto__", "prototype", "constructor"])
17
+
18
+ export function componentValue(value: unknown, maxBytes: number = 65536): ComponentValue {
19
+ const seen = new Set<object>()
20
+ let nodes = 0
21
+ let bytes = 0
22
+ const charge = (text: string): void => {
23
+ bytes += encoder.encode(text).byteLength
24
+ if (bytes > maxBytes) throw new ServerComponentError("component_limit", 413)
25
+ }
26
+ const visit = (item: unknown, depth: number): ComponentValue => {
27
+ if (++nodes > 8192 || depth > 16) throw new ServerComponentError("component_limit", 413)
28
+ if (
29
+ item === null ||
30
+ typeof item === "string" ||
31
+ typeof item === "boolean" ||
32
+ (typeof item === "number" && Number.isFinite(item))
33
+ ) {
34
+ charge(JSON.stringify(item))
35
+ return item
36
+ }
37
+ if (typeof item !== "object" || item === null || seen.has(item))
38
+ throw new ServerComponentError("component_contract")
39
+ const array = Array.isArray(item)
40
+ const prototype = Object.getPrototypeOf(item)
41
+ if (
42
+ array ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null
43
+ ) {
44
+ throw new ServerComponentError("component_contract")
45
+ }
46
+ // Reject custom serializers without invoking them, including inherited serializers.
47
+ if ("toJSON" in item || Object.getOwnPropertySymbols(item).length > 0)
48
+ throw new ServerComponentError("component_contract")
49
+ const descriptors = Object.getOwnPropertyDescriptors(item)
50
+ const names = Object.keys(descriptors)
51
+ if (array && (item.length > 8192 || names.length !== item.length + 1))
52
+ throw new ServerComponentError("component_contract")
53
+ const result: ComponentValue[] | Record<string, ComponentValue> = array
54
+ ? []
55
+ : Object.create(null)
56
+ seen.add(item)
57
+ charge(array ? "[]" : "{}")
58
+ let count = 0
59
+ for (const name of names) {
60
+ if (array && name === "length") continue
61
+ const property = descriptors[name]!
62
+ if (
63
+ forbidden.has(name) ||
64
+ !property.enumerable ||
65
+ !Object.hasOwn(property, "value") ||
66
+ (array && (!/^(0|[1-9][0-9]*)$/.test(name) || Number(name) >= item.length))
67
+ ) {
68
+ throw new ServerComponentError("component_contract")
69
+ }
70
+ charge((count++ === 0 ? "" : ",") + (array ? "" : `${JSON.stringify(name)}:`))
71
+ Object.defineProperty(result, name, {
72
+ value: visit(property.value, depth + 1),
73
+ enumerable: true,
74
+ writable: true,
75
+ configurable: true,
76
+ })
77
+ }
78
+ seen.delete(item)
79
+ return result
80
+ }
81
+ return visit(value, 0)
82
+ }
@@ -0,0 +1,242 @@
1
+ import { existsSync, readFileSync } from "node:fs"
2
+ import { createRequire } from "node:module"
3
+ import { resolve } from "node:path"
4
+ import type * as TS from "typescript"
5
+ import { type Plugin, version as viteVersion } from "vite"
6
+ import {
7
+ compileComponentModule,
8
+ componentReference,
9
+ directive,
10
+ exportedValues,
11
+ guardCreateElementCalls,
12
+ sourceFile,
13
+ } from "./source.ts"
14
+ import { ts } from "./typescript.ts"
15
+
16
+ const componentFile = /\.component\.server\.[cm]?[jt]sx?$/
17
+ const islandFile = /\.island\.[cm]?[jt]sx?$/
18
+ const referencePrefix = "\0nifra-component-reference:"
19
+ const nativeQuery = "nifra-native-client-reference"
20
+ const reactRuntime = "\0nifra-component-react-runtime"
21
+ // Vite uses forward slashes for module IDs even when the filesystem uses backslashes.
22
+ const bare = (id: string): string => (id.split("?")[0] ?? id).replaceAll("\\", "/")
23
+
24
+ export interface ServerComponentsPluginOptions {
25
+ readonly root: string
26
+ readonly adapter: "react" | "vue" | "svelte" | "solid" | "preact"
27
+ }
28
+
29
+ function nativeFacade(source: string, file: string): string {
30
+ const prefix = file.replace(/\.[cm]?[jt]sx?$/, ".props.")
31
+ const extensions = /\.[cm]?jsx?$/.test(file)
32
+ ? ["js", "mjs", "cjs", "ts"]
33
+ : ["ts", "mts", "cts", "js"]
34
+ const companion =
35
+ extensions.map((extension) => prefix + extension).find(existsSync) ?? prefix + extensions[0]
36
+ if (!existsSync(companion))
37
+ throw new Error(
38
+ `[nifra/components] ${file} requires ${companion}: export a closed props schema for every native client component`,
39
+ )
40
+ const schemas = sourceFile(readFileSync(companion, "utf8"), companion)
41
+ const registered = new Set(exportedValues(schemas))
42
+ const slots = new Map<string, readonly string[]>()
43
+ for (const statement of schemas.statements) {
44
+ if (!ts.isVariableStatement(statement)) continue
45
+ for (const declaration of statement.declarationList.declarations) {
46
+ if (!ts.isIdentifier(declaration.name) || !declaration.name.text.endsWith("Slots")) continue
47
+ let value = declaration.initializer
48
+ if (value !== undefined && ts.isAsExpression(value)) value = value.expression
49
+ if (
50
+ value === undefined ||
51
+ !ts.isArrayLiteralExpression(value) ||
52
+ !value.elements.every(ts.isStringLiteral)
53
+ )
54
+ throw new Error("[nifra/components] Managed slot names must be a literal array")
55
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The compiler inspects trusted AST/package metadata and its own populated stub map; application data never supplies these values.
56
+ const names = value.elements.map((node) => (node as TS.StringLiteral).text)
57
+ if (
58
+ names.some(
59
+ (name) =>
60
+ !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(name) ||
61
+ name === "ref" ||
62
+ name === "key" ||
63
+ name === "constructor",
64
+ )
65
+ )
66
+ throw new Error("[nifra/components] Invalid managed slot name")
67
+ slots.set(declaration.name.text.slice(0, -5), names)
68
+ }
69
+ }
70
+ const names = exportedValues(sourceFile(source, file))
71
+ const exports = names.map((name, index) => {
72
+ if (!registered.has(name))
73
+ throw new Error(
74
+ `[nifra/components] Native client export ${name} in ${file} has no registered props schema`,
75
+ )
76
+ if (name !== "default" && !/^[$A-Z_a-z][$\w]*$/.test(name))
77
+ throw new Error("[nifra/components] Native client export names must be identifiers")
78
+ const local = `__nifra_client_${index}`
79
+ const value = `__guard(__native[${JSON.stringify(name)}], __schemas[${JSON.stringify(name)}], ${JSON.stringify(slots.get(name) ?? [])})`
80
+ return name === "default"
81
+ ? `const ${local} = ${value}; export default ${local};`
82
+ : `export const ${name} = ${value};`
83
+ })
84
+ return [
85
+ 'import { guardedClientReference as __guard } from "@nifrajs/web-react/server-components/guard";',
86
+ `import * as __native from ${JSON.stringify(`${file}?${nativeQuery}`)};`,
87
+ `import * as __schemas from ${JSON.stringify(companion)};`,
88
+ ...exports,
89
+ ].join("\n")
90
+ }
91
+
92
+ /** Compiler bridge. The ordinary build must continue rejecting arbitrary server imports. */
93
+ export function serverComponentsPlugin(
94
+ options: ServerComponentsPluginOptions,
95
+ ): Plugin & { readonly api: { readonly componentModules: ReadonlySet<string> } } {
96
+ const stubs = new Map<string, string>()
97
+ const internal = new Set<string>()
98
+ const nativeReferences = new Set<string>()
99
+ const componentModules = new Set<string>()
100
+ return {
101
+ api: { componentModules },
102
+ name: "nifra:server-components",
103
+ enforce: "pre",
104
+ configResolved(config) {
105
+ if (viteVersion !== "8.2.1")
106
+ throw new Error(
107
+ "[nifra/components] Use the certified Vite 8.2.1 component pipeline; Bun remains a supported server runtime",
108
+ )
109
+ if (options.adapter === "react") {
110
+ const require = createRequire(resolve(config.root, "package.json"))
111
+ const versions = ["react", "react-dom", "react-server-dom-webpack"].map((name) => {
112
+ try {
113
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The compiler inspects trusted AST/package metadata and its own populated stub map; application data never supplies these values.
114
+ return (require(`${name}/package.json`) as { version: string }).version
115
+ } catch {
116
+ throw new Error(
117
+ `[nifra/components] Install ${name}@19.2.8 for the React component pipeline`,
118
+ )
119
+ }
120
+ })
121
+ if (versions.some((version) => version !== "19.2.8"))
122
+ throw new Error(
123
+ "[nifra/components] React, React DOM, and Flight must all use the matching 19.2.8 version",
124
+ )
125
+ }
126
+ },
127
+ async resolveId(source, importer) {
128
+ const environment = this.environment.name
129
+ if (source === "react" && environment === "rsc" && !internal.has(bare(importer ?? ""))) {
130
+ internal.add(reactRuntime)
131
+ const guard = await this.resolve("@nifrajs/web-react/server-components/guard", importer, {
132
+ skipSelf: true,
133
+ })
134
+ if (guard !== null) internal.add(bare(guard.id))
135
+ return reactRuntime
136
+ }
137
+ if (source.startsWith("\0virtual:vite-rsc/") && environment !== "rsc") return null
138
+ if (source.startsWith("@nifrajs/web-react/server-components/")) {
139
+ const resolved = await this.resolve(source, importer, { skipSelf: true })
140
+ if (resolved !== null) internal.add(bare(resolved.id))
141
+ return resolved
142
+ }
143
+ if (source.includes(nativeQuery)) {
144
+ const file = source.startsWith("/@fs/")
145
+ ? source.slice("/@fs".length).replace(/^\/(?=[A-Za-z]:[\\/])/, "")
146
+ : existsSync(bare(source))
147
+ ? source
148
+ : resolve(options.root, `.${source}`)
149
+ if (
150
+ !nativeReferences.has(bare(file)) ||
151
+ (environment === "rsc" && (importer === undefined || bare(importer) !== bare(file)))
152
+ )
153
+ throw new Error(
154
+ "[nifra/components] Raw native client references are compiler-owned; import the registered client component",
155
+ )
156
+ return file
157
+ }
158
+ if (source.startsWith(referencePrefix) || source.startsWith("\0")) return null
159
+ if (
160
+ environment === "rsc" &&
161
+ options.adapter === "react" &&
162
+ (source === "react/jsx-runtime" || source === "react/jsx-dev-runtime") &&
163
+ !internal.has(bare(importer ?? ""))
164
+ ) {
165
+ const resolved = await this.resolve(
166
+ `@nifrajs/web-react/server-components/${source.endsWith("dev-runtime") ? "jsx-dev-runtime" : "jsx-runtime"}`,
167
+ importer,
168
+ { skipSelf: true },
169
+ )
170
+ if (resolved === null)
171
+ throw new Error("[nifra/components] Install the matching @nifrajs/web-react adapter")
172
+ internal.add(bare(resolved.id))
173
+ const guard = await this.resolve("@nifrajs/web-react/server-components/guard", importer, {
174
+ skipSelf: true,
175
+ })
176
+ if (guard !== null) internal.add(bare(guard.id))
177
+ return resolved
178
+ }
179
+ if (environment !== "client") return null
180
+ const resolved = await this.resolve(source, importer, { skipSelf: true })
181
+ if (resolved === null || !componentFile.test(bare(resolved.id))) return null
182
+ if (resolved.id !== bare(resolved.id))
183
+ throw new Error("[nifra/components] Server component source cannot be imported as an asset")
184
+ const compiled = compileComponentModule(
185
+ readFileSync(resolved.id, "utf8"),
186
+ resolved.id,
187
+ options.root,
188
+ "client",
189
+ )
190
+ const id = referencePrefix + componentReference(resolved.id, options.root, "module")
191
+ stubs.set(id, compiled.code)
192
+ return id
193
+ },
194
+ load(id) {
195
+ if (id === reactRuntime)
196
+ return {
197
+ code: 'import * as Native from "react"; import { guardedCreateElement as createElement, guardedCloneElement as cloneElement } from "@nifrajs/web-react/server-components/guard"; export { Children, Fragment, Profiler, StrictMode, Suspense, __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, cache, cacheSignal, captureOwnerStack, createRef, forwardRef, isValidElement, lazy, memo, use, useCallback, useDebugValue, useId, useMemo, version } from "react"; export { createElement, cloneElement }; export default { ...Native, createElement, cloneElement };',
198
+ map: null,
199
+ }
200
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The compiler inspects trusted AST/package metadata and its own populated stub map; application data never supplies these values.
201
+ if (stubs.has(id)) return { code: stubs.get(id) as string, map: null }
202
+ const path = bare(id)
203
+ if (id.endsWith(`?${nativeQuery}`)) return { code: readFileSync(path, "utf8"), map: null }
204
+ if (!/\.[cm]?[jt]sx?$/.test(path) || !existsSync(path)) return null
205
+ const source = readFileSync(path, "utf8")
206
+ const ast = sourceFile(source, path)
207
+ if (directive(ast, "use server"))
208
+ throw new Error(
209
+ `[nifra/components] Native use-server actions in ${path} are unsupported; use a validated serverFn in a *.fn.ts module`,
210
+ )
211
+ if (
212
+ this.environment.name === "rsc" &&
213
+ options.adapter === "react" &&
214
+ directive(ast, "use client")
215
+ ) {
216
+ nativeReferences.add(path)
217
+ return { code: nativeFacade(source, path), map: null }
218
+ }
219
+ return null
220
+ },
221
+ transform(source, id) {
222
+ if (id.includes(nativeQuery) || internal.has(bare(id))) return null
223
+ const path = bare(id)
224
+ let code = source
225
+ if (componentFile.test(path)) {
226
+ code = compileComponentModule(source, path, options.root, this.environment.name).code
227
+ componentModules.add(path)
228
+ }
229
+ if (islandFile.test(path))
230
+ code = compileComponentModule(
231
+ source,
232
+ path,
233
+ options.root,
234
+ this.environment.name,
235
+ "island",
236
+ ).code
237
+ if (this.environment.name === "rsc" && options.adapter === "react")
238
+ code = guardCreateElementCalls(code, path)
239
+ return code === source ? null : { code, map: null }
240
+ },
241
+ }
242
+ }
@@ -0,0 +1,32 @@
1
+ export {
2
+ defineServerComponent,
3
+ inheritOwnerAuthorization,
4
+ isServerComponent,
5
+ prepareServerComponent,
6
+ } from "./server-components/definition.ts"
7
+ export { type ComponentErrorCode, ServerComponentError } from "./server-components/error.ts"
8
+ export {
9
+ createServerComponents,
10
+ defineComponentOwner,
11
+ type ServerComponentsOptions,
12
+ serverComponentIdentity,
13
+ serverComponentInstance,
14
+ } from "./server-components/runtime.ts"
15
+ export type {
16
+ ComponentInstance,
17
+ ComponentIsland,
18
+ ComponentKey,
19
+ ComponentOwner,
20
+ ComponentRecord,
21
+ ComponentRender,
22
+ ComponentRenderContext,
23
+ ComponentState,
24
+ ComponentValue,
25
+ PreparedServerComponent,
26
+ ServerComponent,
27
+ ServerComponentContext,
28
+ ServerComponentDefinition,
29
+ ServerComponentHandle,
30
+ ServerComponentRenderAdapter,
31
+ ServerComponentRuntime,
32
+ } from "./server-components/types.ts"
@@ -13,6 +13,10 @@
13
13
  * - **GET, same-origin, `ok`, and not `no-store`.** Anything else goes straight to the network.
14
14
  * - **The cache name carries the build id.** A deploy that changed the assets gets a new cache, and
15
15
  * activation deletes every older one, so a stale worker cannot pin an old build indefinitely.
16
+ * Only caches named `<cacheName>:<buildId>` are the worker's: the origin's other caches - another
17
+ * app's, or data the page stored itself - are never read, written or deleted.
18
+ * - **Only this build's precached URLs are answered.** Every other request, an API call included,
19
+ * goes to the network untouched.
16
20
  *
17
21
  * It is opt-in and generated at build time; an app that does not call this ships nothing.
18
22
  */
@@ -36,7 +40,10 @@ export interface ServiceWorkerOptions {
36
40
  * bytes. Omit it and failed navigations simply fail, which is the honest default.
37
41
  */
38
42
  readonly offlineUrl?: string
39
- /** Cache name prefix. Default `nifra`. */
43
+ /**
44
+ * Cache name prefix, and the namespace activation cleans: every cache named `<cacheName>:<id>` other
45
+ * than this build's is deleted. Give each worker sharing an origin its own. Default `nifra`.
46
+ */
40
47
  readonly cacheName?: string
41
48
  /** Extra same-origin URLs to precache. Only pass immutable ones. */
42
49
  readonly additionalPrecache?: readonly string[]
@@ -101,8 +108,11 @@ export function generateServiceWorker(
101
108
  const urls = [...new Set(offline === undefined ? precache : [...precache, offline])].sort()
102
109
 
103
110
  return `// Generated by @nifrajs/web/service-worker. Do not edit.
104
- const CACHE = ${JSON.stringify(`${prefix}-${options.buildId}`)}
111
+ const OWNED = ${JSON.stringify(`${prefix}:`)}
112
+ const CACHE = OWNED + ${JSON.stringify(options.buildId)}
105
113
  const PRECACHE = ${JSON.stringify(urls)}
114
+ const OWN_URLS = new Set(PRECACHE)
115
+ const OWN = { cacheName: CACHE }
106
116
  const OFFLINE = ${offline === undefined ? "null" : JSON.stringify(offline)}
107
117
 
108
118
  self.addEventListener("install", (event) => {
@@ -115,7 +125,9 @@ self.addEventListener("activate", (event) => {
115
125
  event.waitUntil(
116
126
  caches
117
127
  .keys()
118
- .then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
128
+ // Neither the prefix nor a build id can hold a colon, so the first one ends the namespace.
129
+ .then((keys) => keys.filter((k) => k !== CACHE && k.startsWith(OWNED)))
130
+ .then((old) => Promise.all(old.map((k) => caches.delete(k))))
119
131
  .then(() => self.clients.claim()),
120
132
  )
121
133
  })
@@ -130,20 +142,25 @@ self.addEventListener("fetch", (event) => {
130
142
  // how one user gets served the page rendered for another, so nothing is stored here.
131
143
  if (request.mode === "navigate") {
132
144
  if (OFFLINE === null) return
133
- event.respondWith(fetch(request).catch(() => caches.match(OFFLINE).then((r) => r ?? Response.error())))
145
+ event.respondWith(
146
+ fetch(request).catch(() => caches.match(OFFLINE, OWN).then((r) => r ?? Response.error())),
147
+ )
134
148
  return
135
149
  }
136
150
 
137
- // Assets: cache first, because every precached URL is content-hashed and therefore immutable.
151
+ // Assets: cache first, because every precached URL is content-hashed and therefore immutable. Only
152
+ // this build's URLs are answered, and only from this build's cache: every other request, an API
153
+ // call included, goes to the network, and another cache on the origin is never read.
154
+ if (!OWN_URLS.has(url.pathname)) return
138
155
  event.respondWith(
139
- caches.match(request).then((hit) => {
156
+ caches.match(request, OWN).then((hit) => {
140
157
  if (hit !== undefined) return hit
141
158
  return fetch(request).then((response) => {
142
159
  const cacheable =
143
160
  response.ok &&
144
161
  response.type === "basic" &&
145
162
  !(response.headers.get("cache-control") ?? "").includes("no-store")
146
- if (cacheable && PRECACHE.includes(url.pathname)) {
163
+ if (cacheable) {
147
164
  const copy = response.clone()
148
165
  void caches.open(CACHE).then((c) => c.put(request, copy))
149
166
  }
package/src/vite.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  * injects its HMR client + the framework's refresh preamble. Node `http` (not `Bun.serve`) because
11
11
  * Vite's `middlewares` are Connect-style - it runs fine under Bun.
12
12
  */
13
+
13
14
  import { type Dirent, readdirSync, writeFileSync } from "node:fs"
14
15
  import {
15
16
  createServer as createHttpServer,
@@ -17,6 +18,7 @@ import {
17
18
  type ServerResponse,
18
19
  } from "node:http"
19
20
  import { dirname, isAbsolute, join, relative, resolve as resolvePath, sep } from "node:path"
21
+ import { singleCopyPackageNames } from "@nifrajs/core/single-copy"
20
22
  import { CLIENT_BATCH_MAX_BYTES } from "./dev-client.ts"
21
23
  import { DEV_REQUEST_ID_HEADER, DEV_SERVER_FILES } from "./dev-feed.ts"
22
24
  import { listenOrExplain } from "./dev-port.ts"
@@ -632,6 +634,10 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
632
634
  // Ahead of the user's plugins: the zone guard refuses backend code before anything serves or
633
635
  // transforms it, and a `*.fn` module must be replaced before anything else reads it.
634
636
  plugins: [zoneGuard, viteServerFnStub(), ...plugins],
637
+ // Vite pre-bundles what it finds by crawling `index.html`, and this app has none: every dependency
638
+ // would be found mid-session instead, each one re-optimizing and reloading the page. The client
639
+ // entry imports every route's frontend module, so crawling it covers the whole route graph.
640
+ optimizeDeps: { entries: [DEV_ENTRY] },
635
641
  resolve: {
636
642
  conditions: resolveConditions,
637
643
  // Dedupe each framework runtime to ONE copy. In a multi-root workspace a shared package can pull
@@ -640,7 +646,8 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
640
646
  // on any hook-using route (the error points at the component, not the resolution - brutal to
641
647
  // diagnose). Same policy table the production builds read, so dev matches prod. No-op per
642
648
  // framework the app does not use (the package simply isn't present to dedupe).
643
- dedupe: [...viteDedupePackages()],
649
+ // The app's single-copy declaration pins its packages the same way.
650
+ dedupe: [...viteDedupePackages(), ...singleCopyPackageNames(root)],
644
651
  },
645
652
  ssr: {
646
653
  // Explicit listing forces external even for workspace-LINKED packages (Vite's default keeps