@nifrajs/web 3.3.0 → 4.0.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 (407) hide show
  1. package/dist/backend-only.d.ts +15 -0
  2. package/dist/backend-only.d.ts.map +1 -0
  3. package/dist/backend-only.js +16 -0
  4. package/dist/backend-only.js.map +1 -0
  5. package/dist/boundary.d.ts +5 -0
  6. package/dist/boundary.d.ts.map +1 -1
  7. package/dist/boundary.js +11 -2
  8. package/dist/boundary.js.map +1 -1
  9. package/dist/build-plan.d.ts +35 -6
  10. package/dist/build-plan.d.ts.map +1 -1
  11. package/dist/build-plan.js +89 -35
  12. package/dist/build-plan.js.map +1 -1
  13. package/dist/build-vite.d.ts +18 -0
  14. package/dist/build-vite.d.ts.map +1 -1
  15. package/dist/build-vite.js +97 -17
  16. package/dist/build-vite.js.map +1 -1
  17. package/dist/build.d.ts +72 -23
  18. package/dist/build.d.ts.map +1 -1
  19. package/dist/build.js +411 -98
  20. package/dist/build.js.map +1 -1
  21. package/dist/bun-dev-entry.d.ts +1 -1
  22. package/dist/bun-dev-entry.js +1 -1
  23. package/dist/cdn.d.ts +74 -0
  24. package/dist/cdn.d.ts.map +1 -0
  25. package/dist/cdn.js +132 -0
  26. package/dist/cdn.js.map +1 -0
  27. package/dist/client.d.ts +21 -1
  28. package/dist/client.d.ts.map +1 -1
  29. package/dist/client.js +226 -15
  30. package/dist/client.js.map +1 -1
  31. package/dist/conformance.d.ts +4 -3
  32. package/dist/conformance.d.ts.map +1 -1
  33. package/dist/conformance.js +12 -3
  34. package/dist/conformance.js.map +1 -1
  35. package/dist/csp.d.ts +93 -0
  36. package/dist/csp.d.ts.map +1 -0
  37. package/dist/csp.js +122 -0
  38. package/dist/csp.js.map +1 -0
  39. package/dist/css-contract.d.ts +21 -0
  40. package/dist/css-contract.d.ts.map +1 -0
  41. package/dist/css-contract.js +28 -0
  42. package/dist/css-contract.js.map +1 -0
  43. package/dist/dev-client.d.ts +76 -0
  44. package/dist/dev-client.d.ts.map +1 -0
  45. package/dist/dev-client.js +280 -0
  46. package/dist/dev-client.js.map +1 -0
  47. package/dist/dev-diagnostics.d.ts +26 -2
  48. package/dist/dev-diagnostics.d.ts.map +1 -1
  49. package/dist/dev-diagnostics.js +38 -7
  50. package/dist/dev-diagnostics.js.map +1 -1
  51. package/dist/dev-error.d.ts +4 -13
  52. package/dist/dev-error.d.ts.map +1 -1
  53. package/dist/dev-error.js +46 -4
  54. package/dist/dev-error.js.map +1 -1
  55. package/dist/dev-feed.d.ts +298 -0
  56. package/dist/dev-feed.d.ts.map +1 -0
  57. package/dist/dev-feed.js +797 -0
  58. package/dist/dev-feed.js.map +1 -0
  59. package/dist/dev-indicator.d.ts +38 -0
  60. package/dist/dev-indicator.d.ts.map +1 -0
  61. package/dist/dev-indicator.js +93 -0
  62. package/dist/dev-indicator.js.map +1 -0
  63. package/dist/dev-session.d.ts +77 -0
  64. package/dist/dev-session.d.ts.map +1 -0
  65. package/dist/dev-session.js +580 -0
  66. package/dist/dev-session.js.map +1 -0
  67. package/dist/dev-sourcemap.d.ts +27 -0
  68. package/dist/dev-sourcemap.d.ts.map +1 -0
  69. package/dist/dev-sourcemap.js +235 -0
  70. package/dist/dev-sourcemap.js.map +1 -0
  71. package/dist/dev-ssr-graph.d.ts.map +1 -1
  72. package/dist/dev-ssr-graph.js +13 -5
  73. package/dist/dev-ssr-graph.js.map +1 -1
  74. package/dist/dev.d.ts +15 -2
  75. package/dist/dev.d.ts.map +1 -1
  76. package/dist/dev.js +69 -44
  77. package/dist/dev.js.map +1 -1
  78. package/dist/diagnostic-catalog.d.ts +35 -0
  79. package/dist/diagnostic-catalog.d.ts.map +1 -0
  80. package/dist/diagnostic-catalog.js +203 -0
  81. package/dist/diagnostic-catalog.js.map +1 -0
  82. package/dist/diagnostic-prompt.d.ts +49 -0
  83. package/dist/diagnostic-prompt.d.ts.map +1 -0
  84. package/dist/diagnostic-prompt.js +303 -0
  85. package/dist/diagnostic-prompt.js.map +1 -0
  86. package/dist/diagnostic.d.ts +17 -23
  87. package/dist/diagnostic.d.ts.map +1 -1
  88. package/dist/diagnostic.js +31 -39
  89. package/dist/diagnostic.js.map +1 -1
  90. package/dist/draft.d.ts.map +1 -1
  91. package/dist/draft.js +4 -1
  92. package/dist/draft.js.map +1 -1
  93. package/dist/fn.d.ts +5 -0
  94. package/dist/fn.d.ts.map +1 -1
  95. package/dist/fn.js +13 -3
  96. package/dist/fn.js.map +1 -1
  97. package/dist/fs.d.ts.map +1 -1
  98. package/dist/fs.js +4 -2
  99. package/dist/fs.js.map +1 -1
  100. package/dist/index.d.ts +15 -15
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +13 -12
  103. package/dist/index.js.map +1 -1
  104. package/dist/internal/cdn/cloudflare.d.ts +48 -0
  105. package/dist/internal/cdn/cloudflare.d.ts.map +1 -0
  106. package/dist/internal/cdn/cloudflare.js +94 -0
  107. package/dist/internal/cdn/cloudflare.js.map +1 -0
  108. package/dist/internal/cdn/core.d.ts +91 -0
  109. package/dist/internal/cdn/core.d.ts.map +1 -0
  110. package/dist/internal/cdn/core.js +220 -0
  111. package/dist/internal/cdn/core.js.map +1 -0
  112. package/dist/internal/cdn/fastly.d.ts +17 -0
  113. package/dist/internal/cdn/fastly.d.ts.map +1 -0
  114. package/dist/internal/cdn/fastly.js +43 -0
  115. package/dist/internal/cdn/fastly.js.map +1 -0
  116. package/dist/internal/cdn/vercel.d.ts +31 -0
  117. package/dist/internal/cdn/vercel.d.ts.map +1 -0
  118. package/dist/internal/cdn/vercel.js +56 -0
  119. package/dist/internal/cdn/vercel.js.map +1 -0
  120. package/dist/internal/code-unit-order.d.ts +4 -0
  121. package/dist/internal/code-unit-order.d.ts.map +1 -0
  122. package/dist/internal/code-unit-order.js +6 -0
  123. package/dist/internal/code-unit-order.js.map +1 -0
  124. package/dist/internal/codegen.d.ts +3 -0
  125. package/dist/internal/codegen.d.ts.map +1 -1
  126. package/dist/internal/codegen.js +151 -30
  127. package/dist/internal/codegen.js.map +1 -1
  128. package/dist/internal/dev-csp.d.ts +24 -0
  129. package/dist/internal/dev-csp.d.ts.map +1 -0
  130. package/dist/internal/dev-csp.js +160 -0
  131. package/dist/internal/dev-csp.js.map +1 -0
  132. package/dist/internal/dev-reserved.d.ts +25 -0
  133. package/dist/internal/dev-reserved.d.ts.map +1 -0
  134. package/dist/internal/dev-reserved.js +39 -0
  135. package/dist/internal/dev-reserved.js.map +1 -0
  136. package/dist/internal/html-spans.d.ts +10 -0
  137. package/dist/internal/html-spans.d.ts.map +1 -0
  138. package/dist/internal/html-spans.js +46 -0
  139. package/dist/internal/html-spans.js.map +1 -0
  140. package/dist/internal/loading-runtime.d.ts +44 -0
  141. package/dist/internal/loading-runtime.d.ts.map +1 -0
  142. package/dist/internal/loading-runtime.js +206 -0
  143. package/dist/internal/loading-runtime.js.map +1 -0
  144. package/dist/internal/matches-runtime.d.ts +8 -0
  145. package/dist/internal/matches-runtime.d.ts.map +1 -0
  146. package/dist/internal/matches-runtime.js +61 -0
  147. package/dist/internal/matches-runtime.js.map +1 -0
  148. package/dist/internal/mount-shadow.d.ts +36 -0
  149. package/dist/internal/mount-shadow.d.ts.map +1 -0
  150. package/dist/internal/mount-shadow.js +65 -0
  151. package/dist/internal/mount-shadow.js.map +1 -0
  152. package/dist/internal/node-builtins.d.ts +3 -0
  153. package/dist/internal/node-builtins.d.ts.map +1 -0
  154. package/dist/internal/node-builtins.js +79 -0
  155. package/dist/internal/node-builtins.js.map +1 -0
  156. package/dist/internal/output-guard.d.ts +65 -0
  157. package/dist/internal/output-guard.d.ts.map +1 -0
  158. package/dist/internal/output-guard.js +630 -0
  159. package/dist/internal/output-guard.js.map +1 -0
  160. package/dist/internal/page-execution.d.ts +69 -0
  161. package/dist/internal/page-execution.d.ts.map +1 -0
  162. package/dist/internal/page-execution.js +1021 -0
  163. package/dist/internal/page-execution.js.map +1 -0
  164. package/dist/internal/parity.d.ts +21 -0
  165. package/dist/internal/parity.d.ts.map +1 -1
  166. package/dist/internal/parity.js +104 -22
  167. package/dist/internal/parity.js.map +1 -1
  168. package/dist/internal/private-env.d.ts +12 -0
  169. package/dist/internal/private-env.d.ts.map +1 -0
  170. package/dist/internal/private-env.js +335 -0
  171. package/dist/internal/private-env.js.map +1 -0
  172. package/dist/internal/public-url.d.ts +3 -0
  173. package/dist/internal/public-url.d.ts.map +1 -0
  174. package/dist/internal/public-url.js +18 -0
  175. package/dist/internal/public-url.js.map +1 -0
  176. package/dist/internal/render-document.d.ts +37 -21
  177. package/dist/internal/render-document.d.ts.map +1 -1
  178. package/dist/internal/render-document.js +104 -65
  179. package/dist/internal/render-document.js.map +1 -1
  180. package/dist/internal/request-url.d.ts +3 -0
  181. package/dist/internal/request-url.d.ts.map +1 -0
  182. package/dist/internal/request-url.js +14 -0
  183. package/dist/internal/request-url.js.map +1 -0
  184. package/dist/internal/response-controls.d.ts +75 -0
  185. package/dist/internal/response-controls.d.ts.map +1 -0
  186. package/dist/internal/response-controls.js +256 -0
  187. package/dist/internal/response-controls.js.map +1 -0
  188. package/dist/internal/runtime-contract.d.ts +11 -16
  189. package/dist/internal/runtime-contract.d.ts.map +1 -1
  190. package/dist/internal/runtime-contract.js.map +1 -1
  191. package/dist/internal/secret-scan.d.ts +104 -0
  192. package/dist/internal/secret-scan.d.ts.map +1 -0
  193. package/dist/internal/secret-scan.js +485 -0
  194. package/dist/internal/secret-scan.js.map +1 -0
  195. package/dist/internal/server-boundary.d.ts +6 -29
  196. package/dist/internal/server-boundary.d.ts.map +1 -1
  197. package/dist/internal/server-boundary.js +6 -66
  198. package/dist/internal/server-boundary.js.map +1 -1
  199. package/dist/internal/source-map.d.ts +47 -0
  200. package/dist/internal/source-map.d.ts.map +1 -0
  201. package/dist/internal/source-map.js +225 -0
  202. package/dist/internal/source-map.js.map +1 -0
  203. package/dist/internal/target-compat.d.ts +27 -0
  204. package/dist/internal/target-compat.d.ts.map +1 -0
  205. package/dist/internal/target-compat.js +77 -0
  206. package/dist/internal/target-compat.js.map +1 -0
  207. package/dist/internal/timing-safe-equal.d.ts +6 -0
  208. package/dist/internal/timing-safe-equal.d.ts.map +1 -1
  209. package/dist/internal/timing-safe-equal.js +10 -0
  210. package/dist/internal/timing-safe-equal.js.map +1 -1
  211. package/dist/internal/vitals-runtime.d.ts +18 -0
  212. package/dist/internal/vitals-runtime.d.ts.map +1 -0
  213. package/dist/internal/vitals-runtime.js +38 -0
  214. package/dist/internal/vitals-runtime.js.map +1 -0
  215. package/dist/internal/web-app.d.ts +56 -8
  216. package/dist/internal/web-app.d.ts.map +1 -1
  217. package/dist/internal/web-app.js +215 -772
  218. package/dist/internal/web-app.js.map +1 -1
  219. package/dist/internal/zone-graph.d.ts +89 -0
  220. package/dist/internal/zone-graph.d.ts.map +1 -0
  221. package/dist/internal/zone-graph.js +492 -0
  222. package/dist/internal/zone-graph.js.map +1 -0
  223. package/dist/isr.d.ts +83 -6
  224. package/dist/isr.d.ts.map +1 -1
  225. package/dist/isr.js +301 -39
  226. package/dist/isr.js.map +1 -1
  227. package/dist/llms-txt.d.ts +3 -0
  228. package/dist/llms-txt.d.ts.map +1 -1
  229. package/dist/llms-txt.js +37 -9
  230. package/dist/llms-txt.js.map +1 -1
  231. package/dist/manifest.d.ts +221 -14
  232. package/dist/manifest.d.ts.map +1 -1
  233. package/dist/manifest.js +386 -9
  234. package/dist/manifest.js.map +1 -1
  235. package/dist/module-graph.d.ts +26 -5
  236. package/dist/module-graph.d.ts.map +1 -1
  237. package/dist/module-graph.js +17 -7
  238. package/dist/module-graph.js.map +1 -1
  239. package/dist/navigation.d.ts +17 -3
  240. package/dist/navigation.d.ts.map +1 -1
  241. package/dist/navigation.js +11 -5
  242. package/dist/navigation.js.map +1 -1
  243. package/dist/nonce.d.ts +47 -0
  244. package/dist/nonce.d.ts.map +1 -0
  245. package/dist/nonce.js +63 -0
  246. package/dist/nonce.js.map +1 -0
  247. package/dist/plugins/css-modules.d.ts.map +1 -1
  248. package/dist/plugins/css-modules.js +4 -3
  249. package/dist/plugins/css-modules.js.map +1 -1
  250. package/dist/plugins/kit.d.ts +9 -0
  251. package/dist/plugins/kit.d.ts.map +1 -1
  252. package/dist/plugins/kit.js +18 -0
  253. package/dist/plugins/kit.js.map +1 -1
  254. package/dist/plugins/svg.d.ts +22 -3
  255. package/dist/plugins/svg.d.ts.map +1 -1
  256. package/dist/plugins/svg.js +112 -1
  257. package/dist/plugins/svg.js.map +1 -1
  258. package/dist/plugins/vite-leak-guard.d.ts +107 -3
  259. package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
  260. package/dist/plugins/vite-leak-guard.js +378 -17
  261. package/dist/plugins/vite-leak-guard.js.map +1 -1
  262. package/dist/plugins/vite-zone-guard.d.ts +61 -0
  263. package/dist/plugins/vite-zone-guard.d.ts.map +1 -0
  264. package/dist/plugins/vite-zone-guard.js +208 -0
  265. package/dist/plugins/vite-zone-guard.js.map +1 -0
  266. package/dist/plugins/zone-guard.d.ts +27 -0
  267. package/dist/plugins/zone-guard.d.ts.map +1 -0
  268. package/dist/plugins/zone-guard.js +72 -0
  269. package/dist/plugins/zone-guard.js.map +1 -0
  270. package/dist/prerender.d.ts +10 -0
  271. package/dist/prerender.d.ts.map +1 -1
  272. package/dist/prerender.js +35 -3
  273. package/dist/prerender.js.map +1 -1
  274. package/dist/public-dir.d.ts +9 -0
  275. package/dist/public-dir.d.ts.map +1 -1
  276. package/dist/public-dir.js +131 -48
  277. package/dist/public-dir.js.map +1 -1
  278. package/dist/pwa-manifest.d.ts +68 -0
  279. package/dist/pwa-manifest.d.ts.map +1 -0
  280. package/dist/pwa-manifest.js +178 -0
  281. package/dist/pwa-manifest.js.map +1 -0
  282. package/dist/query.js +4 -4
  283. package/dist/query.js.map +1 -1
  284. package/dist/render-seam.d.ts +42 -2
  285. package/dist/render-seam.d.ts.map +1 -1
  286. package/dist/render-seam.js +6 -0
  287. package/dist/render-seam.js.map +1 -1
  288. package/dist/route-manifest.d.ts +3 -0
  289. package/dist/route-manifest.d.ts.map +1 -1
  290. package/dist/route-manifest.js +26 -3
  291. package/dist/route-manifest.js.map +1 -1
  292. package/dist/route-types.d.ts +24 -0
  293. package/dist/route-types.d.ts.map +1 -0
  294. package/dist/route-types.js +195 -0
  295. package/dist/route-types.js.map +1 -0
  296. package/dist/router.d.ts +28 -6
  297. package/dist/router.d.ts.map +1 -1
  298. package/dist/router.js +129 -40
  299. package/dist/router.js.map +1 -1
  300. package/dist/trusted-html.d.ts +34 -0
  301. package/dist/trusted-html.d.ts.map +1 -0
  302. package/dist/trusted-html.js +35 -0
  303. package/dist/trusted-html.js.map +1 -0
  304. package/dist/vitals.d.ts +33 -0
  305. package/dist/vitals.d.ts.map +1 -0
  306. package/dist/vitals.js +16 -0
  307. package/dist/vitals.js.map +1 -0
  308. package/dist/vite.d.ts +16 -1
  309. package/dist/vite.d.ts.map +1 -1
  310. package/dist/vite.js +187 -36
  311. package/dist/vite.js.map +1 -1
  312. package/dist/zones.d.ts +70 -0
  313. package/dist/zones.d.ts.map +1 -0
  314. package/dist/zones.js +365 -0
  315. package/dist/zones.js.map +1 -0
  316. package/package.json +67 -14
  317. package/src/backend-only.ts +16 -0
  318. package/src/boundary.ts +18 -5
  319. package/src/build-plan.ts +113 -36
  320. package/src/build-vite.ts +124 -15
  321. package/src/build.ts +535 -102
  322. package/src/bun-dev-entry.ts +1 -1
  323. package/src/cdn.ts +216 -0
  324. package/src/client.ts +251 -18
  325. package/src/conformance.ts +16 -3
  326. package/src/csp.ts +194 -0
  327. package/src/css-contract.ts +44 -0
  328. package/src/dev-client.ts +349 -0
  329. package/src/dev-diagnostics.ts +60 -7
  330. package/src/dev-error.ts +49 -5
  331. package/src/dev-feed.ts +1140 -0
  332. package/src/dev-indicator.ts +113 -0
  333. package/src/dev-session.ts +729 -0
  334. package/src/dev-sourcemap.ts +281 -0
  335. package/src/dev-ssr-graph.ts +16 -5
  336. package/src/dev.ts +86 -43
  337. package/src/diagnostic-catalog.ts +243 -0
  338. package/src/diagnostic-prompt.ts +355 -0
  339. package/src/diagnostic.ts +63 -66
  340. package/src/draft.ts +4 -1
  341. package/src/fn.ts +19 -3
  342. package/src/fs.ts +13 -2
  343. package/src/index.ts +57 -10
  344. package/src/internal/cdn/cloudflare.ts +146 -0
  345. package/src/internal/cdn/core.ts +316 -0
  346. package/src/internal/cdn/fastly.ts +62 -0
  347. package/src/internal/cdn/vercel.ts +95 -0
  348. package/src/internal/code-unit-order.ts +5 -0
  349. package/src/internal/codegen.ts +180 -29
  350. package/src/internal/dev-csp.ts +176 -0
  351. package/src/internal/dev-reserved.ts +52 -0
  352. package/src/internal/html-spans.ts +50 -0
  353. package/src/internal/loading-runtime.ts +244 -0
  354. package/src/internal/matches-runtime.ts +62 -0
  355. package/src/internal/mount-shadow.ts +88 -0
  356. package/src/internal/node-builtins.ts +79 -0
  357. package/src/internal/output-guard.ts +701 -0
  358. package/src/internal/page-execution.ts +1371 -0
  359. package/src/internal/parity.ts +150 -36
  360. package/src/internal/private-env.ts +334 -0
  361. package/src/internal/public-url.ts +22 -0
  362. package/src/internal/render-document.ts +153 -73
  363. package/src/internal/request-url.ts +14 -0
  364. package/src/internal/response-controls.ts +284 -0
  365. package/src/internal/runtime-contract.ts +10 -15
  366. package/src/internal/secret-scan.ts +623 -0
  367. package/src/internal/server-boundary.ts +6 -69
  368. package/src/internal/source-map.ts +256 -0
  369. package/src/internal/target-compat.ts +92 -0
  370. package/src/internal/timing-safe-equal.ts +13 -0
  371. package/src/internal/vitals-runtime.ts +53 -0
  372. package/src/internal/web-app.ts +290 -879
  373. package/src/internal/zone-graph.ts +593 -0
  374. package/src/isr.ts +366 -39
  375. package/src/llms-txt.ts +44 -8
  376. package/src/manifest.ts +671 -17
  377. package/src/module-graph.ts +53 -9
  378. package/src/navigation.ts +29 -6
  379. package/src/nonce.ts +104 -0
  380. package/src/plugins/css-modules.ts +5 -3
  381. package/src/plugins/kit.ts +24 -0
  382. package/src/plugins/svg.ts +135 -4
  383. package/src/plugins/vite-leak-guard.ts +529 -16
  384. package/src/plugins/vite-zone-guard.ts +263 -0
  385. package/src/plugins/zone-guard.ts +110 -0
  386. package/src/prerender.ts +49 -3
  387. package/src/public-dir.ts +135 -49
  388. package/src/pwa-manifest.ts +226 -0
  389. package/src/query.ts +4 -4
  390. package/src/render-seam.ts +46 -1
  391. package/src/route-manifest.ts +15 -3
  392. package/src/route-types.ts +264 -0
  393. package/src/router.ts +163 -63
  394. package/src/trusted-html.ts +44 -0
  395. package/src/vitals.ts +44 -0
  396. package/src/vite.ts +207 -36
  397. package/src/zones.ts +430 -0
  398. package/dist/plugins/vite-server-only.d.ts +0 -49
  399. package/dist/plugins/vite-server-only.d.ts.map +0 -1
  400. package/dist/plugins/vite-server-only.js +0 -57
  401. package/dist/plugins/vite-server-only.js.map +0 -1
  402. package/dist/server-only.d.ts +0 -21
  403. package/dist/server-only.d.ts.map +0 -1
  404. package/dist/server-only.js +0 -25
  405. package/dist/server-only.js.map +0 -1
  406. package/src/plugins/vite-server-only.ts +0 -75
  407. package/src/server-only.ts +0 -25
package/src/zones.ts ADDED
@@ -0,0 +1,430 @@
1
+ /**
2
+ * `@nifrajs/web/zones` - which side of the app a source file belongs to.
3
+ *
4
+ * One classifier, used by both client builds, both dev servers and `nifra check`, so they cannot
5
+ * disagree about what may reach a browser. It classifies a RESOLVED file by its real path: the
6
+ * bundler has already applied tsconfig `paths`, aliases and package `exports`, and a workspace
7
+ * package linked through `node_modules` resolves to a path outside any `node_modules` directory, so
8
+ * it is first-party and must say which side it is on.
9
+ *
10
+ * Default-deny: a first-party file that no rule places is an error, never "probably fine".
11
+ */
12
+ import { closeSync, existsSync, openSync, readFileSync, readSync, realpathSync } from "node:fs"
13
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path"
14
+ import { SERVER_FN_MODULE } from "./internal/server-boundary.ts"
15
+
16
+ export type Zone =
17
+ /** A page or special file under `routes/` - the frontend half of a route. */
18
+ | "route-frontend"
19
+ /** A route's `x.backend.ts` twin. */
20
+ | "route-backend"
21
+ | "frontend"
22
+ | "backend"
23
+ | "shared"
24
+ /** A server-function module (`*.fn.ts`); the browser only ever receives its generated RPC stub. */
25
+ | "fn"
26
+ /** Framework output (the client entry, the server composition, generated types). */
27
+ | "generated"
28
+ /** A third-party package, or a workspace package declaring `"nifra": { "environment": "library" }`. */
29
+ | "library"
30
+
31
+ export type Classification =
32
+ | {
33
+ readonly zone: Zone
34
+ /** The package a `library` file belongs to. */
35
+ readonly packageName?: string
36
+ /** A `library` package's own declaration, when it made one. */
37
+ readonly declared?: PackageEnvironment
38
+ /** A third-party file's path inside `node_modules`: `drizzle-orm/node-postgres/index.js`. */
39
+ readonly modulePath?: string
40
+ }
41
+ | { readonly zone: "error"; readonly reason: string }
42
+
43
+ export type PackageEnvironment = "frontend" | "backend" | "shared" | "library"
44
+ const PACKAGE_ENVIRONMENTS: ReadonlySet<string> = new Set([
45
+ "frontend",
46
+ "backend",
47
+ "shared",
48
+ "library",
49
+ ])
50
+
51
+ /** Zones whose code may ship to a browser. `fn` is listed because its stub is what ships. */
52
+ export const BROWSER_ZONES: ReadonlySet<Zone> = new Set([
53
+ "route-frontend",
54
+ "frontend",
55
+ "shared",
56
+ "fn",
57
+ "generated",
58
+ "library",
59
+ ])
60
+
61
+ const SERVER_ZONES: ReadonlySet<Zone> = new Set(["route-backend", "backend", "fn"])
62
+ const FRONTEND_ZONES: ReadonlySet<Zone> = new Set(["route-frontend", "frontend"])
63
+
64
+ /**
65
+ * Third-party packages that never belong in a browser bundle: database drivers, ORMs' server
66
+ * entries, mailers and server SDKs. A package reaching a `node:` builtin is caught separately; this
67
+ * list covers the ones that bundle "fine" and leak credentials or query code instead.
68
+ */
69
+ export const SERVER_PACKAGES: readonly string[] = [
70
+ "@libsql/client",
71
+ "@neondatabase/serverless",
72
+ "@planetscale/database",
73
+ "@prisma/client",
74
+ "@sendgrid/mail",
75
+ "@vercel/postgres",
76
+ "argon2",
77
+ "bcrypt",
78
+ "bcryptjs",
79
+ "better-sqlite3",
80
+ "drizzle-kit",
81
+ "firebase-admin",
82
+ "ioredis",
83
+ "jsonwebtoken",
84
+ "knex",
85
+ "mongodb",
86
+ "mongoose",
87
+ "mysql",
88
+ "mysql2",
89
+ "nodemailer",
90
+ "pg",
91
+ "pg-pool",
92
+ "postgres",
93
+ "prisma",
94
+ "redis",
95
+ "resend",
96
+ "sequelize",
97
+ "server-only",
98
+ "sqlite3",
99
+ "stripe",
100
+ "twilio",
101
+ "typeorm",
102
+ ]
103
+
104
+ /** `drizzle-orm` is a browser-safe query builder until one of its driver entries is imported. */
105
+ const SERVER_SUBPATHS =
106
+ /^drizzle-orm\/(?:node-postgres|postgres-js|mysql2|better-sqlite3|libsql|bun-sqlite|neon-serverless|neon-http|vercel-postgres|planetscale-serverless|d1|pglite)(?:\/|$)/
107
+
108
+ /** The nifra marker a module imports to refuse the browser outright. */
109
+ export const BACKEND_ONLY_MARKER = "@nifrajs/web/backend-only"
110
+
111
+ const SOURCE = "(?:[cm]?[jt]sx?|svelte|vue|mdx)"
112
+ /** A route's backend half: `x.backend.ts`. Script extensions only; JSX belongs to the frontend half. */
113
+ export const ROUTE_BACKEND_FILE = /\.backend\.(?:[cm]?[jt]s)$/
114
+ const ZONE_SUFFIX = new RegExp(`\\.(frontend|backend|shared|fn)\\.${SOURCE}$`)
115
+ const LEGACY_SERVER_SUFFIX = new RegExp(`\\.server\\.${SOURCE}$`)
116
+
117
+ const ZONE_FOLDERS: Readonly<Record<string, Zone>> = {
118
+ frontend: "frontend",
119
+ backend: "backend",
120
+ shared: "shared",
121
+ public: "frontend",
122
+ }
123
+
124
+ export interface ZoneClassifierOptions {
125
+ /** The app root: the directory holding `routes/`, `frontend/`, `backend/` and `shared/`. */
126
+ readonly appRoot: string
127
+ /** The routes directory (default `<appRoot>/routes`). */
128
+ readonly routesDir?: string
129
+ /** Extra absolute files treated as `generated` - a build's own entry modules. */
130
+ readonly generatedFiles?: readonly string[]
131
+ }
132
+
133
+ export interface ZoneClassifier {
134
+ readonly appRoot: string
135
+ /** Classify a file by its absolute (or appRoot-relative) path. Results are cached per path. */
136
+ classify(file: string): Classification
137
+ }
138
+
139
+ const toPosix = (path: string): string => path.replaceAll("\\", "/")
140
+
141
+ // `generateServerManifest`'s first line. The manifest composes both halves of every route, so it
142
+ // imports frontend code from wherever the build wrote it - next to the server entry, often backend/.
143
+ const GENERATED_SERVER_MANIFEST = "// GENERATED by @nifrajs/web generateServerManifest"
144
+ const SERVER_MANIFEST_FILE = /^server-manifest\.[cm]?[jt]s$/
145
+
146
+ function isGeneratedServerManifest(file: string): boolean {
147
+ let fd: number | undefined
148
+ try {
149
+ fd = openSync(file, "r")
150
+ const head = Buffer.alloc(GENERATED_SERVER_MANIFEST.length)
151
+ const read = readSync(fd, head, 0, head.length, 0)
152
+ return head.toString("utf8", 0, read) === GENERATED_SERVER_MANIFEST
153
+ } catch {
154
+ return false
155
+ } finally {
156
+ if (fd !== undefined) closeSync(fd)
157
+ }
158
+ }
159
+
160
+ /** The real path of a file, or the normalized input when it does not exist on disk. */
161
+ function realFile(path: string): string {
162
+ try {
163
+ return toPosix(realpathSync.native(path))
164
+ } catch {
165
+ // A path that does not exist yet keeps its directory's real spelling, so it still compares with
166
+ // the paths around it: a Windows short name or a symlinked temp dir spells one directory two ways.
167
+ const parent = dirname(path)
168
+ if (parent === path) return toPosix(path)
169
+ const real = realFile(parent)
170
+ return `${real.endsWith("/") ? real : `${real}/`}${basename(path)}`
171
+ }
172
+ }
173
+
174
+ const isInside = (child: string, parent: string): boolean =>
175
+ child === parent || child.startsWith(parent.endsWith("/") ? parent : `${parent}/`)
176
+
177
+ /** `@scope/name` or `name` from the LAST `node_modules/` segment of a path. */
178
+ function nodeModulesPackage(path: string): string | undefined {
179
+ const at = path.lastIndexOf("/node_modules/")
180
+ if (at === -1) return undefined
181
+ const parts = path.slice(at + "/node_modules/".length).split("/")
182
+ const first = parts[0]
183
+ if (first === undefined || first === "") return undefined
184
+ return first.startsWith("@") && parts[1] !== undefined ? `${first}/${parts[1]}` : first
185
+ }
186
+
187
+ interface PackageInfo {
188
+ readonly dir: string
189
+ readonly name: string | undefined
190
+ readonly environment: string | undefined
191
+ }
192
+
193
+ /**
194
+ * Create a classifier for one app. Cheap to create; it caches per file and per package directory,
195
+ * so build plugins and dev servers keep one for the life of a build or a session.
196
+ */
197
+ export function createZoneClassifier(options: ZoneClassifierOptions): ZoneClassifier {
198
+ const appRoot = realFile(resolve(options.appRoot))
199
+ const routesDir = realFile(resolve(options.routesDir ?? join(options.appRoot, "routes")))
200
+ const generated = new Set((options.generatedFiles ?? []).map((file) => realFile(resolve(file))))
201
+ const cache = new Map<string, Classification>()
202
+ const packages = new Map<string, PackageInfo | null>()
203
+
204
+ /** The nearest `package.json` at or above `dir`, cached by directory. */
205
+ const packageFor = (dir: string): PackageInfo | undefined => {
206
+ const seen: string[] = []
207
+ let current = dir
208
+ for (;;) {
209
+ const cached = packages.get(current)
210
+ if (cached !== undefined) {
211
+ for (const visited of seen) packages.set(visited, cached)
212
+ return cached ?? undefined
213
+ }
214
+ seen.push(current)
215
+ const manifest = join(current, "package.json")
216
+ if (existsSync(manifest)) {
217
+ let parsed: { name?: unknown; nifra?: { environment?: unknown } } = {}
218
+ try {
219
+ parsed = JSON.parse(readFileSync(manifest, "utf8")) as typeof parsed
220
+ } catch {
221
+ // An unreadable manifest declares nothing; the caller reports the missing declaration.
222
+ }
223
+ const info: PackageInfo = {
224
+ dir: current,
225
+ name: typeof parsed.name === "string" ? parsed.name : undefined,
226
+ environment:
227
+ typeof parsed.nifra?.environment === "string" ? parsed.nifra.environment : undefined,
228
+ }
229
+ for (const visited of seen) packages.set(visited, info)
230
+ return info
231
+ }
232
+ const parent = toPosix(dirname(current))
233
+ if (parent === current) {
234
+ for (const visited of seen) packages.set(visited, null)
235
+ return undefined
236
+ }
237
+ current = parent
238
+ }
239
+ }
240
+
241
+ const classifyUncached = (file: string): Classification => {
242
+ if (generated.has(file)) return { zone: "generated" }
243
+ const thirdParty = nodeModulesPackage(file)
244
+ if (thirdParty !== undefined) {
245
+ const info = packageFor(toPosix(dirname(file)))
246
+ const declared =
247
+ info?.environment !== undefined && PACKAGE_ENVIRONMENTS.has(info.environment)
248
+ ? (info.environment as PackageEnvironment)
249
+ : undefined
250
+ return {
251
+ zone: "library",
252
+ packageName: thirdParty,
253
+ modulePath: file.slice(file.lastIndexOf("/node_modules/") + "/node_modules/".length),
254
+ ...(declared ? { declared } : {}),
255
+ }
256
+ }
257
+ const base = file.slice(file.lastIndexOf("/") + 1)
258
+ if (isInside(file, appRoot)) {
259
+ if (SERVER_MANIFEST_FILE.test(base) && isGeneratedServerManifest(file)) {
260
+ return { zone: "generated" }
261
+ }
262
+ if (LEGACY_SERVER_SUFFIX.test(base)) {
263
+ return {
264
+ zone: "error",
265
+ reason: `"${relativeTo(appRoot, file)}" uses the retired ".server" suffix. Rename it to ".backend" (or move it under backend/); nifra no longer empties .server modules in the browser build`,
266
+ }
267
+ }
268
+ const rel = relativeTo(appRoot, file)
269
+ const top = rel.split("/")[0] ?? ""
270
+ if (top.startsWith(".nifra")) return { zone: "generated" }
271
+ const suffix = ZONE_SUFFIX.exec(base)?.[1] as
272
+ | "frontend"
273
+ | "backend"
274
+ | "shared"
275
+ | "fn"
276
+ | undefined
277
+ // Only a script module is replaced by the calls a browser makes; any other ".fn" file would
278
+ // ship to the browser exactly as written.
279
+ if (suffix === "fn" && !SERVER_FN_MODULE.test(base)) {
280
+ return {
281
+ zone: "error",
282
+ reason: `"${rel}" is named as a server function, but only a script module (.ts, .js) can be one - the browser build would ship this file as it is. Rename it`,
283
+ }
284
+ }
285
+ if (isInside(file, routesDir)) {
286
+ if (ROUTE_BACKEND_FILE.test(base)) return { zone: "route-backend" }
287
+ if (suffix === "fn") return { zone: "fn" }
288
+ if (suffix === "backend") return { zone: "route-backend" }
289
+ if (suffix === "shared") return { zone: "shared" }
290
+ return { zone: "route-frontend" }
291
+ }
292
+ const folder = ZONE_FOLDERS[top]
293
+ if (folder !== undefined) {
294
+ if (suffix === undefined || suffix === folder) return { zone: folder }
295
+ if (suffix === "fn" && folder === "backend") return { zone: "fn" }
296
+ return {
297
+ zone: "error",
298
+ reason: `"${rel}" sits in ${top}/ but its ".${suffix}" suffix says otherwise. A file belongs to one side: move it, or drop the suffix`,
299
+ }
300
+ }
301
+ if (suffix !== undefined) return { zone: suffix === "fn" ? "fn" : suffix }
302
+ return { zone: "error", reason: unzonedReason(rel) }
303
+ }
304
+ // First-party code outside the app: a workspace package, or a relative import out of the app.
305
+ const info = packageFor(toPosix(dirname(file)))
306
+ const environment = info?.environment
307
+ if (environment !== undefined && PACKAGE_ENVIRONMENTS.has(environment)) {
308
+ return environment === "library"
309
+ ? {
310
+ zone: "library",
311
+ ...(info?.name ? { packageName: info.name } : {}),
312
+ declared: "library",
313
+ }
314
+ : { zone: environment as Zone }
315
+ }
316
+ const where = info?.name ?? info?.dir ?? dirname(file)
317
+ return {
318
+ zone: "error",
319
+ reason: `"${file}" is first-party code outside the app (${where}) and declares no side. Add "nifra": { "environment": "frontend" | "backend" | "shared" | "library" } to ${info === undefined ? "its package.json" : `${info.dir}/package.json`}`,
320
+ }
321
+ }
322
+
323
+ return {
324
+ appRoot,
325
+ classify(input: string): Classification {
326
+ const absolute = isAbsolute(input) ? input : resolve(appRoot, input)
327
+ const file = realFile(absolute)
328
+ const cached = cache.get(file)
329
+ if (cached !== undefined) return cached
330
+ const result = classifyUncached(file)
331
+ cache.set(file, result)
332
+ return result
333
+ },
334
+ }
335
+ }
336
+
337
+ function relativeTo(root: string, file: string): string {
338
+ return toPosix(relative(root, file)).split(sep).join("/")
339
+ }
340
+
341
+ const RETIRED_ROOT_FILES: Readonly<Record<string, string>> = {
342
+ "backend.ts": "backend/app.ts",
343
+ "framework.ts": "backend/framework.ts",
344
+ }
345
+
346
+ function unzonedReason(rel: string): string {
347
+ const moved = RETIRED_ROOT_FILES[rel]
348
+ if (moved !== undefined) {
349
+ return `"${rel}" moved: it lives at ${moved} now (run \`nifra migrate layout\`)`
350
+ }
351
+ return `"${rel}" is in no zone. Every file a build loads lives under routes/, frontend/, backend/ or shared/, or carries a .frontend/.backend/.shared suffix`
352
+ }
353
+
354
+ /** The package name a bare specifier names, or `undefined` for a relative path, a builtin, a
355
+ * subpath import (`#x`) or a bundler-virtual id. */
356
+ export function specifierPackage(specifier: string): string | undefined {
357
+ if (/^(?:\.|\/|#|\0|[a-z]+:)/i.test(specifier)) return undefined
358
+ if (specifier.startsWith("@") && !/^@[^/]+\/[^/]/.test(specifier)) return undefined
359
+ const parts = specifier.split("/")
360
+ return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0]
361
+ }
362
+
363
+ /**
364
+ * Why a classified file may not ship to a browser, or `undefined` when it may. A `drizzle-orm` driver
365
+ * entry is recognized by the import as written (`specifier`) or by the file's path in the package.
366
+ */
367
+ export function browserDenial(
368
+ classification: Classification,
369
+ specifier?: string,
370
+ ): string | undefined {
371
+ if (classification.zone === "error") return classification.reason
372
+ if (!BROWSER_ZONES.has(classification.zone)) {
373
+ return classification.zone === "route-backend"
374
+ ? "it is a route's backend half, which runs on the server only"
375
+ : "it is backend code"
376
+ }
377
+ if (classification.zone !== "library") return undefined
378
+ const name = classification.packageName
379
+ if (classification.declared === "backend") return `package "${name}" declares itself backend-only`
380
+ if (name !== undefined && SERVER_PACKAGES.includes(name)) {
381
+ return `package "${name}" is server code (a driver, server SDK or credential helper)`
382
+ }
383
+ if (specifier !== undefined && SERVER_SUBPATHS.test(specifier)) {
384
+ return `"${specifier}" is a database driver entry`
385
+ }
386
+ const driver = classification.modulePath?.match(SERVER_SUBPATHS)?.[0]
387
+ if (driver !== undefined) return `"${driver.replace(/\/$/, "")}" is a database driver entry`
388
+ return undefined
389
+ }
390
+
391
+ /** Whether a module in `from` may import (with a value import) a module in `to`. */
392
+ export function importAllowed(from: Zone, to: Zone): boolean {
393
+ if (from === "generated" || from === "library") return true
394
+ if (to === "generated" || to === "library") return true
395
+ if (FRONTEND_ZONES.has(from)) return FRONTEND_ZONES.has(to) || to === "shared" || to === "fn"
396
+ if (SERVER_ZONES.has(from)) return !FRONTEND_ZONES.has(to)
397
+ // shared
398
+ return to === "shared"
399
+ }
400
+
401
+ /** The message for an import {@link importAllowed} refuses. */
402
+ export function importRuleMessage(fromFile: string, from: Zone, toFile: string, to: Zone): string {
403
+ const side = (zone: Zone): string =>
404
+ zone === "route-frontend"
405
+ ? "a route's frontend half"
406
+ : zone === "route-backend"
407
+ ? "a route's backend half"
408
+ : zone === "fn"
409
+ ? "a server-function module"
410
+ : `${zone} code`
411
+ const hint =
412
+ from === "shared"
413
+ ? "shared code runs on both sides, so it may import only shared code and third-party packages"
414
+ : SERVER_ZONES.has(from)
415
+ ? "backend code may not import frontend code; move what both need into shared/"
416
+ : "frontend code may not import backend code; reach it through a loader, an action or a *.fn.ts server function"
417
+ return `${fromFile} (${side(from)}) imports ${toFile} (${side(to)}): ${hint}. A type-only import (\`import type\`) is allowed`
418
+ }
419
+
420
+ export { isSensitiveFieldName } from "./internal/output-guard.ts"
421
+ export { privateEnvReads, privateEnvReason } from "./internal/private-env.ts"
422
+ export {
423
+ publicScanFiles,
424
+ type SecretExemption,
425
+ type SecretFinding,
426
+ type SecretRule,
427
+ type SecretScanFile,
428
+ type SecretScanInput,
429
+ scanForSecrets,
430
+ } from "./internal/secret-scan.ts"
@@ -1,49 +0,0 @@
1
- /**
2
- * `@nifrajs/web/plugins/vite-server-only` - the Vite half of the `.server` convention.
3
- *
4
- * A module named `*.server.ts(x)` is server-only: the Bun client build empties it so its import
5
- * subtree - `node:` builtins, native modules, secrets - never reaches a browser. This does the same
6
- * for Vite, in both the dev server and the production build.
7
- *
8
- * ## Why this exists separately
9
- *
10
- * The convention was implemented once, as a `Bun.build` plugin, which meant it held in exactly one of
11
- * the four pipelines. `nifra build` emptied the module; `nifra dev` (Vite), a Vite production build,
12
- * and `nifra dev --bun` all shipped it whole. A guard that holds in one pipeline and not the others is
13
- * worse than none, because the file name reads as protection everywhere.
14
- *
15
- * `*.fn` already had this shape - a Bun plugin, a Vite plugin, and a refusal in the one pipeline that
16
- * cannot transform. `.server` now matches it.
17
- *
18
- * ## Why `transform` and not `load`
19
- *
20
- * Vite resolves and reads the file itself; taking `load` would mean re-implementing its resolution.
21
- * `transform` receives the source Vite already read, and returning replacement code discards the
22
- * original along with its imports - so the server subtree is never followed. `enforce: "pre"` puts
23
- * this ahead of framework transforms, which have no business seeing server code either.
24
- */
25
- import { SERVER_ONLY_MODULE, SERVER_ONLY_REPLACEMENT, viteServerOnlyReplacement } from "../internal/server-boundary.js";
26
- export { SERVER_ONLY_MODULE, SERVER_ONLY_REPLACEMENT, viteServerOnlyReplacement };
27
- /** The slice of a Vite/Rollup plugin this returns. Structural, so `vite` stays an optional peer. */
28
- export interface ServerOnlyEmptyPlugin {
29
- readonly name: string;
30
- readonly enforce: "pre";
31
- /** Applied only to the CLIENT build; the server build keeps the real module. */
32
- readonly applyToEnvironment?: (environment: {
33
- readonly name: string;
34
- }) => boolean;
35
- transform(code: string, id: string, options?: {
36
- readonly ssr?: boolean;
37
- }): {
38
- code: string;
39
- map: null;
40
- } | null;
41
- }
42
- /**
43
- * Empty every `*.server` module in the client build.
44
- *
45
- * Client-only by construction: nifra passes this to the client build and the dev server, never to the
46
- * SSR build, where the real module is what runs.
47
- */
48
- export declare function viteServerOnlyEmpty(): ServerOnlyEmptyPlugin;
49
- //# sourceMappingURL=vite-server-only.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite-server-only.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-server-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EAC1B,MAAM,gCAAgC,CAAA;AAIvC,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,CAAA;AAEjF,oGAAoG;AACpG,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAA;IACvB,gFAAgF;IAChF,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IACjF,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CACtC;AAKD;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,qBAAqB,CAiB3D"}
@@ -1,57 +0,0 @@
1
- /**
2
- * `@nifrajs/web/plugins/vite-server-only` - the Vite half of the `.server` convention.
3
- *
4
- * A module named `*.server.ts(x)` is server-only: the Bun client build empties it so its import
5
- * subtree - `node:` builtins, native modules, secrets - never reaches a browser. This does the same
6
- * for Vite, in both the dev server and the production build.
7
- *
8
- * ## Why this exists separately
9
- *
10
- * The convention was implemented once, as a `Bun.build` plugin, which meant it held in exactly one of
11
- * the four pipelines. `nifra build` emptied the module; `nifra dev` (Vite), a Vite production build,
12
- * and `nifra dev --bun` all shipped it whole. A guard that holds in one pipeline and not the others is
13
- * worse than none, because the file name reads as protection everywhere.
14
- *
15
- * `*.fn` already had this shape - a Bun plugin, a Vite plugin, and a refusal in the one pipeline that
16
- * cannot transform. `.server` now matches it.
17
- *
18
- * ## Why `transform` and not `load`
19
- *
20
- * Vite resolves and reads the file itself; taking `load` would mean re-implementing its resolution.
21
- * `transform` receives the source Vite already read, and returning replacement code discards the
22
- * original along with its imports - so the server subtree is never followed. `enforce: "pre"` puts
23
- * this ahead of framework transforms, which have no business seeing server code either.
24
- */
25
- import { SERVER_ONLY_MODULE, SERVER_ONLY_REPLACEMENT, viteServerOnlyReplacement, } from "../internal/server-boundary.js";
26
- // Re-exported so a caller wiring its own bundler gets the matcher from the same owner the pipelines
27
- // use, rather than writing a fifth copy of the regex.
28
- export { SERVER_ONLY_MODULE, SERVER_ONLY_REPLACEMENT, viteServerOnlyReplacement };
29
- /** Strips a Vite id's `?query` and `#hash` so the suffix test sees a plain path. */
30
- const bare = (id) => id.split("?")[0]?.split("#")[0] ?? id;
31
- /**
32
- * Empty every `*.server` module in the client build.
33
- *
34
- * Client-only by construction: nifra passes this to the client build and the dev server, never to the
35
- * SSR build, where the real module is what runs.
36
- */
37
- export function viteServerOnlyEmpty() {
38
- return {
39
- name: "nifra:server-only-empty",
40
- enforce: "pre",
41
- // Vite 6+ environments: the SSR environment must keep the real module. Older Vite ignores this and
42
- // relies on nifra only registering the plugin on the client side.
43
- applyToEnvironment: (environment) => environment.name === "client",
44
- transform(code, id, options) {
45
- // Vite 5 ignores `applyToEnvironment` but supplies this transform context for SSR.
46
- if (options?.ssr === true)
47
- return null;
48
- const path = bare(id);
49
- if (!SERVER_ONLY_MODULE.test(path))
50
- return null;
51
- // `map: null` is honest rather than lazy: the replacement shares no lines with the source, so any
52
- // mapping would point a debugger at unrelated code.
53
- return { code: viteServerOnlyReplacement(code), map: null };
54
- },
55
- };
56
- }
57
- //# sourceMappingURL=vite-server-only.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite-server-only.js","sourceRoot":"","sources":["../../src/plugins/vite-server-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,gCAAgC,CAAA;AAEvC,oGAAoG;AACpG,sDAAsD;AACtD,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,CAAA;AAejF,oFAAoF;AACpF,MAAM,IAAI,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AAE1E;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,IAAI,EAAE,yBAAyB;QAC/B,OAAO,EAAE,KAAK;QACd,mGAAmG;QACnG,kEAAkE;QAClE,kBAAkB,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,KAAK,QAAQ;QAClE,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO;YACzB,mFAAmF;YACnF,IAAI,OAAO,EAAE,GAAG,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAA;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;YACrB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAA;YAC/C,kGAAkG;YAClG,oDAAoD;YACpD,OAAO,EAAE,IAAI,EAAE,yBAAyB,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;QAC7D,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -1,21 +0,0 @@
1
- /**
2
- * `@nifrajs/web/server-only` - the **explicit, opt-in poison-import marker** (Next's `import
3
- * "server-only"`). A module of PURE server logic that carries no `node:` import - a secret-bearing
4
- * constant, a server-only API call - can't be caught by nifra's other two client-leak guards: the
5
- * `.server` convention (which empties `*.server` modules in the client build) needs the file to be
6
- * NAMED `*.server`, and the node-builtin guard only fires when a `node:` import actually reaches a
7
- * client chunk. This marker closes that gap: drop a side-effect import at the top of the module -
8
- *
9
- * import "@nifrajs/web/server-only"
10
- *
11
- * - and the CLIENT build ({@link buildClient}) FAILS LOUD, naming the import chain, if that module
12
- * ever lands in a browser chunk. On the SERVER build/runtime it's a harmless no-op (this empty
13
- * module), so the same file runs untouched server-side.
14
- *
15
- * Pair it with the type-level {@link ServerOnly} brand (from `@nifrajs/web`) on the module's exports
16
- * to signal intent to readers + the compiler; this runtime import is what actually fails the build.
17
- *
18
- * @see ServerOnly - the type-level intent marker that complements this runtime import.
19
- */
20
- export {};
21
- //# sourceMappingURL=server-only.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-only.d.ts","sourceRoot":"","sources":["../src/server-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,OAAO,EAAE,CAAA"}
@@ -1,25 +0,0 @@
1
- /**
2
- * `@nifrajs/web/server-only` - the **explicit, opt-in poison-import marker** (Next's `import
3
- * "server-only"`). A module of PURE server logic that carries no `node:` import - a secret-bearing
4
- * constant, a server-only API call - can't be caught by nifra's other two client-leak guards: the
5
- * `.server` convention (which empties `*.server` modules in the client build) needs the file to be
6
- * NAMED `*.server`, and the node-builtin guard only fires when a `node:` import actually reaches a
7
- * client chunk. This marker closes that gap: drop a side-effect import at the top of the module -
8
- *
9
- * import "@nifrajs/web/server-only"
10
- *
11
- * - and the CLIENT build ({@link buildClient}) FAILS LOUD, naming the import chain, if that module
12
- * ever lands in a browser chunk. On the SERVER build/runtime it's a harmless no-op (this empty
13
- * module), so the same file runs untouched server-side.
14
- *
15
- * Pair it with the type-level {@link ServerOnly} brand (from `@nifrajs/web`) on the module's exports
16
- * to signal intent to readers + the compiler; this runtime import is what actually fails the build.
17
- *
18
- * @see ServerOnly - the type-level intent marker that complements this runtime import.
19
- */
20
- // Intentionally empty. The marker is the IMPORT itself: `buildClient` detects any module that imports
21
- // this specifier and lands in a client chunk (via the same Bun metafile graph the node-builtin guard
22
- // walks) and fails the build. There is no value to export and nothing to run - on the server it's a
23
- // no-op so the marked module behaves normally; on the client the build never completes.
24
- export {};
25
- //# sourceMappingURL=server-only.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-only.js","sourceRoot":"","sources":["../src/server-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,sGAAsG;AACtG,qGAAqG;AACrG,oGAAoG;AACpG,wFAAwF;AACxF,OAAO,EAAE,CAAA"}