@nifrajs/cli 3.5.0 → 4.0.2

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 (404) hide show
  1. package/README.md +42 -3
  2. package/dist/app-files.d.ts +11 -0
  3. package/dist/app-files.d.ts.map +1 -0
  4. package/dist/app-files.js +34 -0
  5. package/dist/app-files.js.map +1 -0
  6. package/dist/assure-hydration.d.ts +7 -1
  7. package/dist/assure-hydration.d.ts.map +1 -1
  8. package/dist/assure-hydration.js +128 -43
  9. package/dist/assure-hydration.js.map +1 -1
  10. package/dist/assure.d.ts.map +1 -1
  11. package/dist/assure.js +16 -2
  12. package/dist/assure.js.map +1 -1
  13. package/dist/capabilities-tool.d.ts +5 -1
  14. package/dist/capabilities-tool.d.ts.map +1 -1
  15. package/dist/capabilities-tool.js +32 -10
  16. package/dist/capabilities-tool.js.map +1 -1
  17. package/dist/cdn-check.d.ts +41 -0
  18. package/dist/cdn-check.d.ts.map +1 -0
  19. package/dist/cdn-check.js +207 -0
  20. package/dist/cdn-check.js.map +1 -0
  21. package/dist/check-diagnostics.d.ts +4 -0
  22. package/dist/check-diagnostics.d.ts.map +1 -1
  23. package/dist/check-diagnostics.js +13 -0
  24. package/dist/check-diagnostics.js.map +1 -1
  25. package/dist/check-scan.d.ts +49 -7
  26. package/dist/check-scan.d.ts.map +1 -1
  27. package/dist/check-scan.js +291 -62
  28. package/dist/check-scan.js.map +1 -1
  29. package/dist/check.d.ts.map +1 -1
  30. package/dist/check.js +99 -63
  31. package/dist/check.js.map +1 -1
  32. package/dist/cli.d.ts +42 -16
  33. package/dist/cli.d.ts.map +1 -1
  34. package/dist/cli.js +262 -82
  35. package/dist/cli.js.map +1 -1
  36. package/dist/command-catalog.d.ts +62 -5
  37. package/dist/command-catalog.d.ts.map +1 -1
  38. package/dist/command-catalog.js +275 -35
  39. package/dist/command-catalog.js.map +1 -1
  40. package/dist/config-target.d.ts +8 -0
  41. package/dist/config-target.d.ts.map +1 -0
  42. package/dist/config-target.js +45 -0
  43. package/dist/config-target.js.map +1 -0
  44. package/dist/contracts.d.ts.map +1 -1
  45. package/dist/contracts.js +52 -13
  46. package/dist/contracts.js.map +1 -1
  47. package/dist/db-audit.d.ts +37 -0
  48. package/dist/db-audit.d.ts.map +1 -0
  49. package/dist/db-audit.js +99 -0
  50. package/dist/db-audit.js.map +1 -0
  51. package/dist/db-child.d.ts +64 -0
  52. package/dist/db-child.d.ts.map +1 -0
  53. package/dist/db-child.js +213 -0
  54. package/dist/db-child.js.map +1 -0
  55. package/dist/db-config.d.ts +60 -0
  56. package/dist/db-config.d.ts.map +1 -0
  57. package/dist/db-config.js +176 -0
  58. package/dist/db-config.js.map +1 -0
  59. package/dist/db-tool.d.ts +84 -0
  60. package/dist/db-tool.d.ts.map +1 -0
  61. package/dist/db-tool.js +537 -0
  62. package/dist/db-tool.js.map +1 -0
  63. package/dist/dev-bun-config.d.ts +20 -13
  64. package/dist/dev-bun-config.d.ts.map +1 -1
  65. package/dist/dev-bun-config.js +98 -41
  66. package/dist/dev-bun-config.js.map +1 -1
  67. package/dist/dev-feed-tool.d.ts +106 -0
  68. package/dist/dev-feed-tool.d.ts.map +1 -0
  69. package/dist/dev-feed-tool.js +713 -0
  70. package/dist/dev-feed-tool.js.map +1 -0
  71. package/dist/dev-server-client.d.ts +67 -0
  72. package/dist/dev-server-client.d.ts.map +1 -0
  73. package/dist/dev-server-client.js +195 -0
  74. package/dist/dev-server-client.js.map +1 -0
  75. package/dist/diff-tool.d.ts +3 -3
  76. package/dist/diff-tool.d.ts.map +1 -1
  77. package/dist/diff-tool.js +6 -5
  78. package/dist/diff-tool.js.map +1 -1
  79. package/dist/docs-search.d.ts.map +1 -1
  80. package/dist/docs-search.js +12 -4
  81. package/dist/docs-search.js.map +1 -1
  82. package/dist/doctor.d.ts +17 -0
  83. package/dist/doctor.d.ts.map +1 -1
  84. package/dist/doctor.js +76 -15
  85. package/dist/doctor.js.map +1 -1
  86. package/dist/env-file.d.ts +15 -0
  87. package/dist/env-file.d.ts.map +1 -1
  88. package/dist/env-file.js +73 -1
  89. package/dist/env-file.js.map +1 -1
  90. package/dist/fix-recipes.d.ts.map +1 -1
  91. package/dist/fix-recipes.js +48 -22
  92. package/dist/fix-recipes.js.map +1 -1
  93. package/dist/frontend-guidance.js +5 -5
  94. package/dist/frontend-guidance.js.map +1 -1
  95. package/dist/i18n-check.d.ts +16 -0
  96. package/dist/i18n-check.d.ts.map +1 -0
  97. package/dist/i18n-check.js +154 -0
  98. package/dist/i18n-check.js.map +1 -0
  99. package/dist/init-agents.d.ts +49 -13
  100. package/dist/init-agents.d.ts.map +1 -1
  101. package/dist/init-agents.js +239 -34
  102. package/dist/init-agents.js.map +1 -1
  103. package/dist/internal/code-unit-order.d.ts +4 -0
  104. package/dist/internal/code-unit-order.d.ts.map +1 -0
  105. package/dist/internal/code-unit-order.js +6 -0
  106. package/dist/internal/code-unit-order.js.map +1 -0
  107. package/dist/internal/script-kind.d.ts +7 -0
  108. package/dist/internal/script-kind.d.ts.map +1 -0
  109. package/dist/internal/script-kind.js +12 -0
  110. package/dist/internal/script-kind.js.map +1 -0
  111. package/dist/internal/source-facts.d.ts +5 -0
  112. package/dist/internal/source-facts.d.ts.map +1 -1
  113. package/dist/internal/source-facts.js +61 -5
  114. package/dist/internal/source-facts.js.map +1 -1
  115. package/dist/internal/typescript-import.d.ts +49 -24
  116. package/dist/internal/typescript-import.d.ts.map +1 -1
  117. package/dist/internal/typescript-import.js +507 -67
  118. package/dist/internal/typescript-import.js.map +1 -1
  119. package/dist/introspect.d.ts +5 -1
  120. package/dist/introspect.d.ts.map +1 -1
  121. package/dist/introspect.js +92 -27
  122. package/dist/introspect.js.map +1 -1
  123. package/dist/learn.js +3 -3
  124. package/dist/learn.js.map +1 -1
  125. package/dist/levels-tool.d.ts +10 -0
  126. package/dist/levels-tool.d.ts.map +1 -1
  127. package/dist/levels-tool.js +33 -3
  128. package/dist/levels-tool.js.map +1 -1
  129. package/dist/load.d.ts +67 -17
  130. package/dist/load.d.ts.map +1 -1
  131. package/dist/load.js +78 -18
  132. package/dist/load.js.map +1 -1
  133. package/dist/manifest-tool.d.ts.map +1 -1
  134. package/dist/manifest-tool.js +3 -2
  135. package/dist/manifest-tool.js.map +1 -1
  136. package/dist/mcp-app-tool.d.ts.map +1 -1
  137. package/dist/mcp-app-tool.js +2 -0
  138. package/dist/mcp-app-tool.js.map +1 -1
  139. package/dist/mcp-context.js +1 -1
  140. package/dist/mcp-context.js.map +1 -1
  141. package/dist/mcp-delegate.d.ts +57 -0
  142. package/dist/mcp-delegate.d.ts.map +1 -0
  143. package/dist/mcp-delegate.js +130 -0
  144. package/dist/mcp-delegate.js.map +1 -0
  145. package/dist/mcp-docs-tools.d.ts.map +1 -1
  146. package/dist/mcp-docs-tools.js +23 -5
  147. package/dist/mcp-docs-tools.js.map +1 -1
  148. package/dist/mcp-exec.d.ts +2 -0
  149. package/dist/mcp-exec.d.ts.map +1 -1
  150. package/dist/mcp-exec.js +132 -108
  151. package/dist/mcp-exec.js.map +1 -1
  152. package/dist/mcp-http.d.ts.map +1 -1
  153. package/dist/mcp-http.js +17 -5
  154. package/dist/mcp-http.js.map +1 -1
  155. package/dist/mcp-io.d.ts +14 -0
  156. package/dist/mcp-io.d.ts.map +1 -1
  157. package/dist/mcp-io.js +45 -0
  158. package/dist/mcp-io.js.map +1 -1
  159. package/dist/mcp-isolate.d.ts +48 -0
  160. package/dist/mcp-isolate.d.ts.map +1 -0
  161. package/dist/mcp-isolate.js +222 -0
  162. package/dist/mcp-isolate.js.map +1 -0
  163. package/dist/mcp-project-child.d.ts +74 -0
  164. package/dist/mcp-project-child.d.ts.map +1 -0
  165. package/dist/mcp-project-child.js +130 -0
  166. package/dist/mcp-project-child.js.map +1 -0
  167. package/dist/mcp-render.js +2 -2
  168. package/dist/mcp-render.js.map +1 -1
  169. package/dist/mcp-root.d.ts +37 -9
  170. package/dist/mcp-root.d.ts.map +1 -1
  171. package/dist/mcp-root.js +110 -23
  172. package/dist/mcp-root.js.map +1 -1
  173. package/dist/mcp-run.d.ts +18 -1
  174. package/dist/mcp-run.d.ts.map +1 -1
  175. package/dist/mcp-run.js +82 -9
  176. package/dist/mcp-run.js.map +1 -1
  177. package/dist/mcp-ws.js +4 -1
  178. package/dist/mcp-ws.js.map +1 -1
  179. package/dist/mcp.d.ts +16 -3
  180. package/dist/mcp.d.ts.map +1 -1
  181. package/dist/mcp.js +81 -53
  182. package/dist/mcp.js.map +1 -1
  183. package/dist/migrate-layout.d.ts +44 -0
  184. package/dist/migrate-layout.d.ts.map +1 -0
  185. package/dist/migrate-layout.js +1155 -0
  186. package/dist/migrate-layout.js.map +1 -0
  187. package/dist/openapi-tool.d.ts +2 -2
  188. package/dist/openapi-tool.d.ts.map +1 -1
  189. package/dist/openapi-tool.js.map +1 -1
  190. package/dist/openapi-types.d.ts +2 -1
  191. package/dist/openapi-types.d.ts.map +1 -1
  192. package/dist/openapi-types.js +240 -12
  193. package/dist/openapi-types.js.map +1 -1
  194. package/dist/pipeline-report.d.ts +3 -2
  195. package/dist/pipeline-report.d.ts.map +1 -1
  196. package/dist/pipeline-report.js +19 -16
  197. package/dist/pipeline-report.js.map +1 -1
  198. package/dist/port.d.ts +5 -4
  199. package/dist/port.d.ts.map +1 -1
  200. package/dist/port.js +46 -29
  201. package/dist/port.js.map +1 -1
  202. package/dist/project-facts.d.ts +5 -0
  203. package/dist/project-facts.d.ts.map +1 -1
  204. package/dist/project-facts.js.map +1 -1
  205. package/dist/recipes/4.0.0.d.ts +9 -0
  206. package/dist/recipes/4.0.0.d.ts.map +1 -0
  207. package/dist/recipes/4.0.0.js +36 -0
  208. package/dist/recipes/4.0.0.js.map +1 -0
  209. package/dist/recipes/index.d.ts.map +1 -1
  210. package/dist/recipes/index.js +2 -0
  211. package/dist/recipes/index.js.map +1 -1
  212. package/dist/release-verification.d.ts +11 -1
  213. package/dist/release-verification.d.ts.map +1 -1
  214. package/dist/release-verification.js +47 -4
  215. package/dist/release-verification.js.map +1 -1
  216. package/dist/review.d.ts.map +1 -1
  217. package/dist/review.js +12 -8
  218. package/dist/review.js.map +1 -1
  219. package/dist/route-types.d.ts +28 -0
  220. package/dist/route-types.d.ts.map +1 -0
  221. package/dist/route-types.js +106 -0
  222. package/dist/route-types.js.map +1 -0
  223. package/dist/rules/codes.d.ts +9 -0
  224. package/dist/rules/codes.d.ts.map +1 -1
  225. package/dist/rules/codes.js +9 -0
  226. package/dist/rules/codes.js.map +1 -1
  227. package/dist/rules/data-guard.d.ts +12 -0
  228. package/dist/rules/data-guard.d.ts.map +1 -0
  229. package/dist/rules/data-guard.js +213 -0
  230. package/dist/rules/data-guard.js.map +1 -0
  231. package/dist/rules/index.d.ts +3 -0
  232. package/dist/rules/index.d.ts.map +1 -1
  233. package/dist/rules/index.js +17 -5
  234. package/dist/rules/index.js.map +1 -1
  235. package/dist/rules/islands.d.ts.map +1 -1
  236. package/dist/rules/islands.js +7 -4
  237. package/dist/rules/islands.js.map +1 -1
  238. package/dist/rules/legacy.d.ts.map +1 -1
  239. package/dist/rules/legacy.js +71 -38
  240. package/dist/rules/legacy.js.map +1 -1
  241. package/dist/rules/nano.d.ts.map +1 -1
  242. package/dist/rules/nano.js +15 -6
  243. package/dist/rules/nano.js.map +1 -1
  244. package/dist/rules/pages.d.ts +15 -0
  245. package/dist/rules/pages.d.ts.map +1 -0
  246. package/dist/rules/pages.js +88 -0
  247. package/dist/rules/pages.js.map +1 -0
  248. package/dist/rules/routes.d.ts +11 -0
  249. package/dist/rules/routes.d.ts.map +1 -1
  250. package/dist/rules/routes.js +180 -2
  251. package/dist/rules/routes.js.map +1 -1
  252. package/dist/rules/secrets.d.ts +10 -0
  253. package/dist/rules/secrets.d.ts.map +1 -0
  254. package/dist/rules/secrets.js +169 -0
  255. package/dist/rules/secrets.js.map +1 -0
  256. package/dist/rules/security.d.ts +7 -0
  257. package/dist/rules/security.d.ts.map +1 -1
  258. package/dist/rules/security.js +171 -65
  259. package/dist/rules/security.js.map +1 -1
  260. package/dist/rules/typescript.d.ts +16 -0
  261. package/dist/rules/typescript.d.ts.map +1 -0
  262. package/dist/rules/typescript.js +59 -0
  263. package/dist/rules/typescript.js.map +1 -0
  264. package/dist/rules/zones.d.ts +17 -0
  265. package/dist/rules/zones.d.ts.map +1 -0
  266. package/dist/rules/zones.js +174 -0
  267. package/dist/rules/zones.js.map +1 -0
  268. package/dist/scaffold.d.ts +25 -12
  269. package/dist/scaffold.d.ts.map +1 -1
  270. package/dist/scaffold.js +132 -87
  271. package/dist/scaffold.js.map +1 -1
  272. package/dist/sdk.d.ts +17 -3
  273. package/dist/sdk.d.ts.map +1 -1
  274. package/dist/sdk.js +941 -153
  275. package/dist/sdk.js.map +1 -1
  276. package/dist/search-terms.d.ts +2 -0
  277. package/dist/search-terms.d.ts.map +1 -1
  278. package/dist/search-terms.js +23 -8
  279. package/dist/search-terms.js.map +1 -1
  280. package/dist/smoke.d.ts +79 -0
  281. package/dist/smoke.d.ts.map +1 -0
  282. package/dist/smoke.js +494 -0
  283. package/dist/smoke.js.map +1 -0
  284. package/dist/sync-manifest.d.ts +10 -2
  285. package/dist/sync-manifest.d.ts.map +1 -1
  286. package/dist/sync-manifest.js +44 -19
  287. package/dist/sync-manifest.js.map +1 -1
  288. package/dist/sync-routes.d.ts +4 -3
  289. package/dist/sync-routes.d.ts.map +1 -1
  290. package/dist/sync-routes.js +4 -3
  291. package/dist/sync-routes.js.map +1 -1
  292. package/dist/test-tool.d.ts.map +1 -1
  293. package/dist/test-tool.js +30 -11
  294. package/dist/test-tool.js.map +1 -1
  295. package/dist/types-search.d.ts.map +1 -1
  296. package/dist/types-search.js +11 -5
  297. package/dist/types-search.js.map +1 -1
  298. package/dist/upgrade.d.ts +36 -6
  299. package/dist/upgrade.d.ts.map +1 -1
  300. package/dist/upgrade.js +167 -29
  301. package/dist/upgrade.js.map +1 -1
  302. package/dist/verification-plan.d.ts.map +1 -1
  303. package/dist/verification-plan.js +4 -0
  304. package/dist/verification-plan.js.map +1 -1
  305. package/dist/verification.d.ts.map +1 -1
  306. package/dist/verification.js +45 -12
  307. package/dist/verification.js.map +1 -1
  308. package/dist/web-app-options.d.ts +19 -0
  309. package/dist/web-app-options.d.ts.map +1 -0
  310. package/dist/web-app-options.js +49 -0
  311. package/dist/web-app-options.js.map +1 -0
  312. package/dist/work-graph.d.ts.map +1 -1
  313. package/dist/work-graph.js +29 -13
  314. package/dist/work-graph.js.map +1 -1
  315. package/docs/examples.json +185 -29
  316. package/docs/llms-full.txt +3807 -580
  317. package/docs/types.json +14229 -10939
  318. package/package.json +19 -12
  319. package/src/app-files.ts +40 -0
  320. package/src/assure-hydration.ts +139 -46
  321. package/src/assure.ts +17 -2
  322. package/src/capabilities-tool.ts +35 -9
  323. package/src/cdn-check.ts +268 -0
  324. package/src/check-diagnostics.ts +17 -0
  325. package/src/check-scan.ts +358 -63
  326. package/src/check.ts +97 -62
  327. package/src/cli.ts +296 -87
  328. package/src/command-catalog.ts +389 -48
  329. package/src/config-target.ts +47 -0
  330. package/src/contracts.ts +54 -12
  331. package/src/db-audit.ts +128 -0
  332. package/src/db-child.ts +285 -0
  333. package/src/db-config.ts +224 -0
  334. package/src/db-tool.ts +690 -0
  335. package/src/dev-bun-config.ts +116 -40
  336. package/src/dev-feed-tool.ts +912 -0
  337. package/src/dev-server-client.ts +267 -0
  338. package/src/diff-tool.ts +6 -5
  339. package/src/docs-search.ts +10 -3
  340. package/src/doctor.ts +98 -15
  341. package/src/env-file.ts +78 -1
  342. package/src/fix-recipes.ts +53 -32
  343. package/src/frontend-guidance.ts +5 -5
  344. package/src/i18n-check.ts +179 -0
  345. package/src/init-agents.ts +301 -38
  346. package/src/internal/code-unit-order.ts +5 -0
  347. package/src/internal/script-kind.ts +11 -0
  348. package/src/internal/source-facts.ts +96 -22
  349. package/src/internal/typescript-import.ts +663 -68
  350. package/src/introspect.ts +90 -27
  351. package/src/learn.ts +3 -3
  352. package/src/levels-tool.ts +47 -2
  353. package/src/load.ts +140 -33
  354. package/src/manifest-tool.ts +3 -2
  355. package/src/mcp-app-tool.ts +2 -0
  356. package/src/mcp-context.ts +1 -1
  357. package/src/mcp-delegate.ts +162 -0
  358. package/src/mcp-docs-tools.ts +23 -5
  359. package/src/mcp-exec.ts +160 -132
  360. package/src/mcp-http.ts +19 -5
  361. package/src/mcp-io.ts +57 -0
  362. package/src/mcp-isolate.ts +287 -0
  363. package/src/mcp-project-child.ts +182 -0
  364. package/src/mcp-render.ts +2 -2
  365. package/src/mcp-root.ts +117 -22
  366. package/src/mcp-run.ts +104 -10
  367. package/src/mcp-ws.ts +4 -1
  368. package/src/mcp.ts +106 -64
  369. package/src/migrate-layout.ts +1338 -0
  370. package/src/openapi-tool.ts +7 -3
  371. package/src/openapi-types.ts +315 -13
  372. package/src/pipeline-report.ts +22 -18
  373. package/src/port.ts +53 -30
  374. package/src/project-facts.ts +5 -0
  375. package/src/recipes/4.0.0.ts +37 -0
  376. package/src/recipes/index.ts +2 -0
  377. package/src/release-verification.ts +74 -5
  378. package/src/review.ts +13 -8
  379. package/src/route-types.ts +133 -0
  380. package/src/rules/codes.ts +9 -0
  381. package/src/rules/data-guard.ts +230 -0
  382. package/src/rules/index.ts +18 -5
  383. package/src/rules/islands.ts +12 -4
  384. package/src/rules/legacy.ts +71 -39
  385. package/src/rules/nano.ts +18 -6
  386. package/src/rules/pages.ts +99 -0
  387. package/src/rules/routes.ts +181 -2
  388. package/src/rules/secrets.ts +174 -0
  389. package/src/rules/security.ts +198 -70
  390. package/src/rules/typescript.ts +77 -0
  391. package/src/rules/zones.ts +195 -0
  392. package/src/scaffold.ts +147 -95
  393. package/src/sdk.ts +1215 -158
  394. package/src/search-terms.ts +24 -7
  395. package/src/smoke.ts +607 -0
  396. package/src/sync-manifest.ts +50 -19
  397. package/src/sync-routes.ts +4 -3
  398. package/src/test-tool.ts +32 -11
  399. package/src/types-search.ts +11 -4
  400. package/src/upgrade.ts +205 -25
  401. package/src/verification-plan.ts +13 -0
  402. package/src/verification.ts +50 -12
  403. package/src/web-app-options.ts +57 -0
  404. package/src/work-graph.ts +27 -13
@@ -3,24 +3,26 @@
3
3
  *
4
4
  * Bun's dev-server bundling (`Bun.serve` HTML imports) accepts plugins ONLY through bunfig's
5
5
  * `[serve.static] plugins` - there is no programmatic option (upstream ask: oven-sh/bun#36830), and
6
- * a runtime `Bun.plugin()` never reaches it. Without a plugin there, a `*.fn` server-function module
7
- * would ship to the browser WHOLE (body, DB handles, secrets) instead of as the RPC stub the
8
- * production client build emits, and a `*.server` module would ship instead of being emptied.
6
+ * a runtime `Bun.plugin()` never reaches it. Without a plugin there, a `*.fn` server-function
7
+ * module would ship to the browser WHOLE (body, DB handles, secrets) instead of as the RPC stub the
8
+ * production client build emits, and backend code a browser module imports would be served instead
9
+ * of refused.
9
10
  *
10
11
  * The same channel is the only way an app's OWN `clientPlugins` (SFC compilers and the like) can reach
11
12
  * that bundler: the CLI holds them as plugin OBJECTS, and bunfig accepts only module paths - so the
12
13
  * generated module re-imports the app's config and composes them in.
13
14
  *
14
15
  * So the CLI generates, under `.nifra/dev-bun/`:
15
- * - `boundary-plugin.ts` - default-exports one plugin composing the SAME `serverFnStubPlugin` +
16
- * `serverOnlyEmptyPlugin` + CSS Modules transform the production build uses (imported from
17
- * `@nifrajs/web`, resolved from the app - identical transforms, not re-implementations), plus the
18
- * app's own `clientPlugins`;
16
+ * - `boundary-plugin.ts` - default-exports one plugin composing the SAME `zoneGuardPlugin` +
17
+ * `serverFnStubPlugin` + CSS Modules transform the production build uses (imported from
18
+ * `@nifrajs/web`, resolved from the app - identical transforms, not re-implementations), plus
19
+ * the app's own `clientPlugins`;
19
20
  * - `bunfig.toml` - the app's ENTIRE bunfig carried over verbatim (jsx, loaders, defines, install
20
- * settings - dropping any of them would give dev a different Bun than the app configured), with
21
- * `[serve.static] plugins` merged to put the boundary plugin first and path-bearing entries
22
- * (`preload`, plugin paths) re-rooted at the app, because bunfig resolves relative entries
23
- * against the CONFIG file's directory;
21
+ * settings - dropping any of them would give dev a different Bun than the app configured), except
22
+ * that `[serve.static] plugins` names only the boundary plugin, which composes the app's own
23
+ * entries last, in their order; path-bearing entries (`preload`, plugin paths) are re-rooted at
24
+ * the app, because bunfig resolves relative entries against the CONFIG file's directory; and
25
+ * the config's `define` is layered over both `[define]` and `[serve.static] define`;
24
26
  * - `launch-token` - a per-launch random value (see below).
25
27
  *
26
28
  * `dev --bun` then re-execs itself once with `--config=<generated>` (bunfig is read at process
@@ -106,33 +108,68 @@ export function serializeBunfig(data: BunfigData): string {
106
108
  return `${lines.join("\n")}\n`
107
109
  }
108
110
 
109
- /** Render the generated bunfig: the user's config carried whole, with the boundary plugin prepended
110
- * to `[serve.static] plugins` and path-bearing entries (`preload`, plugin paths) re-rooted at the
111
- * APP - bunfig resolves relative entries against the config file's own directory, which is
112
- * `.nifra/dev-bun/`. */
111
+ /** A bunfig entry that names a file, re-rooted at the APP: bunfig resolves a relative entry against
112
+ * the config file's own directory, which for the generated config is `.nifra/dev-bun/`. */
113
+ const resolveEntry = (entry: unknown, appRoot: string): unknown =>
114
+ typeof entry === "string" && entry.startsWith(".") ? resolve(appRoot, entry) : entry
115
+
116
+ /** The app's own `[serve.static] plugins`, re-rooted at the app, for the boundary module to compose. */
117
+ export function userServePlugins(user: BunfigData, appRoot: string): string[] {
118
+ const serve = isTable(user.serve) ? user.serve : {}
119
+ const serveStatic = isTable(serve.static) ? serve.static : {}
120
+ const plugins = Array.isArray(serveStatic.plugins) ? serveStatic.plugins : []
121
+ return plugins.map((entry, i) => {
122
+ const resolved = resolveEntry(entry, appRoot)
123
+ if (typeof resolved !== "string") {
124
+ throw new Error(`[nifra] bunfig field \`serve.static.plugins[${i}]\` must be a module path`)
125
+ }
126
+ return resolved
127
+ })
128
+ }
129
+
130
+ /** Render the generated bunfig: the user's config carried whole, with `[serve.static] plugins` naming
131
+ * only the boundary plugin (it composes the app's own entries, see {@link userServePlugins}),
132
+ * `preload` re-rooted at the APP, and the config's `define` added to both halves. */
113
133
  export function renderDevBunfig(
114
134
  boundaryPluginPath: string,
115
135
  user: BunfigData,
116
136
  appRoot: string,
137
+ define: Readonly<Record<string, string>> = {},
117
138
  ): string {
118
- const resolveEntry = (entry: unknown): unknown =>
119
- typeof entry === "string" && entry.startsWith(".") ? resolve(appRoot, entry) : entry
120
139
  const data: BunfigData = structuredClone(user)
121
140
  if (data.preload !== undefined) {
122
141
  const entries = Array.isArray(data.preload) ? data.preload : [data.preload]
123
- data.preload = entries.map(resolveEntry)
142
+ data.preload = entries.map((entry) => resolveEntry(entry, appRoot))
124
143
  }
125
144
  const serve = isTable(data.serve) ? data.serve : {}
126
145
  data.serve = serve
127
146
  const serveStatic = isTable(serve.static) ? serve.static : {}
128
147
  serve.static = serveStatic
129
- const existing = Array.isArray(serveStatic.plugins) ? serveStatic.plugins : []
130
- serveStatic.plugins = [boundaryPluginPath, ...existing.map(resolveEntry)]
148
+ serveStatic.plugins = [boundaryPluginPath]
149
+ if (Object.keys(define).length > 0) {
150
+ for (const [key, value] of Object.entries(define)) {
151
+ if (typeof value !== "string") {
152
+ throw new Error(
153
+ `[nifra] \`define\` entry \`${key}\` must be a string of source code, such as "true" or ` +
154
+ `'"text"' - it replaces the name in the bundle as written.`,
155
+ )
156
+ }
157
+ }
158
+ // `nifra build` applies `define` to the client and the server bundle. In dev the two halves read
159
+ // different keys: the runtime SSR runs in honours only top-level `[define]`, Bun's dev-server
160
+ // bundler only `[serve.static] define`. Layered last, so a clash resolves the way production does.
161
+ data.define = Object.assign(isTable(data.define) ? data.define : {}, define)
162
+ serveStatic.define = Object.assign(
163
+ isTable(serveStatic.define) ? serveStatic.define : {},
164
+ define,
165
+ )
166
+ }
131
167
  return (
132
168
  "# Generated by `nifra dev --bun` - do not edit. Regenerated on every dev start.\n" +
133
169
  "# The app's own bunfig is carried over verbatim; [serve.static] plugins additionally deliver\n" +
134
- "# the client-boundary plugins (server-fn stubs, server-only emptying) to Bun's dev-server\n" +
135
- "# bundler, which only accepts plugins via this channel (oven-sh/bun#36830).\n" +
170
+ "# the client-boundary plugins (zone guard, server-fn stubs) to Bun's dev-server\n" +
171
+ "# bundler, which only accepts plugins via this channel (oven-sh/bun#36830). The app's\n" +
172
+ "# config `define` is added to [define] (SSR) and [serve.static] define (client).\n" +
136
173
  serializeBunfig(data)
137
174
  )
138
175
  }
@@ -151,13 +188,22 @@ function relativeSpecifier(fromDir: string, target: string): string {
151
188
  * The `@nifrajs/*` specifiers are bare so they resolve from the APP's install (the module lives under
152
189
  * the app's `.nifra/`), keeping dev transforms byte-identical to production's.
153
190
  *
154
- * `configPath` is the app's `nifra.config.ts` (or `framework.ts`). Importing it here is the only way an
155
- * app's `clientPlugins` can reach Bun's dev-server bundler at all: that bundler takes plugins as module
156
- * PATHS via bunfig, never as the plugin objects the CLI already holds in memory. Without this an app
157
- * whose transforms live in `clientPlugins` had no working Bun dev loop - its client would be bundled
158
- * with the transform silently missing. `setup` is async because `clientPlugins` may be a thunk.
191
+ * `configPath` is the app's `nifra.config.ts` (or `backend/framework.ts`). Importing it here is the
192
+ * only way an app's `clientPlugins` can reach Bun's dev-server bundler at all: that bundler takes
193
+ * plugins as module PATHS via bunfig, never as the plugin objects the CLI already holds in memory.
194
+ * Without this an app whose transforms live in `clientPlugins` had no working Bun dev loop - its
195
+ * client would be bundled with the transform silently missing. `setup` is async because
196
+ * `clientPlugins` may be a thunk.
197
+ *
198
+ * `servePlugins` are the app's own bunfig `[serve.static] plugins`, composed last and in order rather
199
+ * than listed beside this module, so that every plugin reaching the bundler registers through
200
+ * `reserveDevSpecifiers` (see `@nifrajs/web/internal/dev-reserved`).
159
201
  */
160
- export function renderBoundaryPluginModule(configPath?: string, pluginDir?: string): string {
202
+ export function renderBoundaryPluginModule(
203
+ configPath?: string,
204
+ pluginDir?: string,
205
+ servePlugins: readonly string[] = [],
206
+ ): string {
161
207
  const appImport =
162
208
  configPath !== undefined && pluginDir !== undefined
163
209
  ? `import * as appConfig from ${tomlString(relativeSpecifier(pluginDir, configPath))}\n`
@@ -168,25 +214,49 @@ export function renderBoundaryPluginModule(configPath?: string, pluginDir?: stri
168
214
  : ` // The app's OWN client transforms (SFC compilers etc.). \`clientPlugins\` may be a thunk.
169
215
  const field = appConfig.clientPlugins
170
216
  const appPlugins = (typeof field === "function" ? await field() : field) ?? []
171
- for (const p of appPlugins) await p.setup(build)
217
+ for (const p of appPlugins) await p.setup(guarded)
218
+ `
219
+ const serveSetup =
220
+ servePlugins.length === 0
221
+ ? ""
222
+ : ` // The app's own bunfig [serve.static] plugins, as Bun would load them, in their order.
223
+ for (const specifier of ${JSON.stringify(servePlugins)}) {
224
+ const plugin = (await import(specifier)).default
225
+ if (typeof plugin?.setup !== "function") {
226
+ throw new TypeError(\`[nifra] bunfig.toml [serve.static] plugin "\${specifier}" does not default-export a bundler plugin\`)
227
+ }
228
+ await plugin.setup(guarded)
229
+ }
172
230
  `
173
231
  return `// Generated by \`nifra dev\` (Bun pipeline) - do not edit. Regenerated on every dev start.
174
- import { serverFnStubPlugin, serverOnlyEmptyPlugin } from "@nifrajs/web/build"
232
+ import { serverFnStubPlugin, zoneGuardPlugin } from "@nifrajs/web/build"
233
+ import { reserveDevSpecifiers } from "@nifrajs/web/internal/dev-reserved"
175
234
  import { cssModulesBunPlugin } from "@nifrajs/web/plugins/css-modules"
176
235
  ${appImport}
236
+ // This module lives at <app>/.nifra/dev-bun/, so the app root is two directories up.
237
+ const zones = zoneGuardPlugin({
238
+ appRoot: Bun.fileURLToPath(new URL("../../", import.meta.url)),${
239
+ appImport === ""
240
+ ? ""
241
+ : `
242
+ ...(typeof appConfig.publicEnvPrefix === "string" ? { publicEnvPrefix: appConfig.publicEnvPrefix } : {}),`
243
+ }
244
+ })
177
245
  const fn = serverFnStubPlugin()
178
- const serverOnly = serverOnlyEmptyPlugin()
179
246
  const cssModules = cssModulesBunPlugin("dom")
180
247
 
181
248
  export default {
182
249
  name: "nifra-dev-boundary",
183
250
  async setup(build) {
184
- // Boundary first: an app plugin must never get to transform a module that the boundary is about to
185
- // empty or stub, or the transform decides what ships instead of the boundary.
186
- serverOnly.setup(build)
187
- fn.setup(build)
188
- cssModules.setup(build)
189
- ${appSetup} },
251
+ // Every plugin below registers through this view: a resolve filter matching the dev entry script
252
+ // or Bun's built-in React refresh runtime breaks the page even when its handler declines.
253
+ const guarded = reserveDevSpecifiers(build)
254
+ // Boundary first: an app plugin must never get to transform a module that the boundary is about
255
+ // to refuse or stub, or the transform decides what ships instead of the boundary.
256
+ zones.setup(guarded)
257
+ fn.setup(guarded)
258
+ cssModules.setup(guarded)
259
+ ${appSetup}${serveSetup} },
190
260
  }
191
261
  `
192
262
  }
@@ -201,20 +271,26 @@ const TOKEN_FILE = "launch-token"
201
271
 
202
272
  /** Write the generated config for an app; returns the bunfig path to re-exec with and the fresh
203
273
  * launch token to pass in the child's environment. `configPath` (the app's `nifra.config.ts` /
204
- * `framework.ts`) is what lets the app's own `clientPlugins` reach Bun's dev-server bundler. */
274
+ * `backend/framework.ts`) is what lets the app's own `clientPlugins` reach Bun's dev-server
275
+ * bundler; `define` is the config's own. */
205
276
  export async function writeBunDevConfig(
206
277
  appRoot: string,
207
278
  configPath?: string,
279
+ define?: Readonly<Record<string, string>>,
208
280
  ): Promise<BunDevConfig> {
209
281
  const dir = resolve(appRoot, ".nifra", "dev-bun")
210
282
  mkdirSync(dir, { recursive: true })
211
283
  const pluginPath = resolve(dir, "boundary-plugin.ts")
212
- writeFileSync(pluginPath, renderBoundaryPluginModule(configPath, dir))
213
284
  const userToml = await Bun.file(resolve(appRoot, "bunfig.toml"))
214
285
  .text()
215
286
  .catch(() => undefined)
287
+ const user = parseUserBunfig(userToml)
288
+ writeFileSync(
289
+ pluginPath,
290
+ renderBoundaryPluginModule(configPath, dir, userServePlugins(user, appRoot)),
291
+ )
216
292
  const bunfigPath = resolve(dir, "bunfig.toml")
217
- writeFileSync(bunfigPath, renderDevBunfig(pluginPath, parseUserBunfig(userToml), appRoot))
293
+ writeFileSync(bunfigPath, renderDevBunfig(pluginPath, user, appRoot, define))
218
294
  const launchToken = crypto.randomUUID()
219
295
  writeFileSync(resolve(dir, TOKEN_FILE), launchToken)
220
296
  return { bunfigPath, launchToken }