@nifrajs/cli 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 (425) 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 +7 -15
  22. package/dist/check-diagnostics.d.ts.map +1 -1
  23. package/dist/check-diagnostics.js +162 -713
  24. package/dist/check-diagnostics.js.map +1 -1
  25. package/dist/check-scan.d.ts +58 -7
  26. package/dist/check-scan.d.ts.map +1 -1
  27. package/dist/check-scan.js +323 -62
  28. package/dist/check-scan.js.map +1 -1
  29. package/dist/check.d.ts +1 -0
  30. package/dist/check.d.ts.map +1 -1
  31. package/dist/check.js +145 -54
  32. package/dist/check.js.map +1 -1
  33. package/dist/cli.d.ts +42 -16
  34. package/dist/cli.d.ts.map +1 -1
  35. package/dist/cli.js +306 -87
  36. package/dist/cli.js.map +1 -1
  37. package/dist/command-catalog.d.ts +60 -5
  38. package/dist/command-catalog.d.ts.map +1 -1
  39. package/dist/command-catalog.js +298 -33
  40. package/dist/command-catalog.js.map +1 -1
  41. package/dist/config-target.d.ts +8 -0
  42. package/dist/config-target.d.ts.map +1 -0
  43. package/dist/config-target.js +45 -0
  44. package/dist/config-target.js.map +1 -0
  45. package/dist/contracts.d.ts +3 -2
  46. package/dist/contracts.d.ts.map +1 -1
  47. package/dist/contracts.js +56 -16
  48. package/dist/contracts.js.map +1 -1
  49. package/dist/db-audit.d.ts +37 -0
  50. package/dist/db-audit.d.ts.map +1 -0
  51. package/dist/db-audit.js +99 -0
  52. package/dist/db-audit.js.map +1 -0
  53. package/dist/db-child.d.ts +64 -0
  54. package/dist/db-child.d.ts.map +1 -0
  55. package/dist/db-child.js +213 -0
  56. package/dist/db-child.js.map +1 -0
  57. package/dist/db-config.d.ts +60 -0
  58. package/dist/db-config.d.ts.map +1 -0
  59. package/dist/db-config.js +176 -0
  60. package/dist/db-config.js.map +1 -0
  61. package/dist/db-tool.d.ts +84 -0
  62. package/dist/db-tool.d.ts.map +1 -0
  63. package/dist/db-tool.js +537 -0
  64. package/dist/db-tool.js.map +1 -0
  65. package/dist/dev-bun-config.d.ts +20 -13
  66. package/dist/dev-bun-config.d.ts.map +1 -1
  67. package/dist/dev-bun-config.js +98 -41
  68. package/dist/dev-bun-config.js.map +1 -1
  69. package/dist/dev-feed-tool.d.ts +106 -0
  70. package/dist/dev-feed-tool.d.ts.map +1 -0
  71. package/dist/dev-feed-tool.js +713 -0
  72. package/dist/dev-feed-tool.js.map +1 -0
  73. package/dist/dev-server-client.d.ts +67 -0
  74. package/dist/dev-server-client.d.ts.map +1 -0
  75. package/dist/dev-server-client.js +195 -0
  76. package/dist/dev-server-client.js.map +1 -0
  77. package/dist/diagnostics.d.ts +86 -0
  78. package/dist/diagnostics.d.ts.map +1 -1
  79. package/dist/diagnostics.js +85 -0
  80. package/dist/diagnostics.js.map +1 -1
  81. package/dist/diff-tool.d.ts +3 -3
  82. package/dist/diff-tool.d.ts.map +1 -1
  83. package/dist/diff-tool.js +6 -5
  84. package/dist/diff-tool.js.map +1 -1
  85. package/dist/docs-search.d.ts.map +1 -1
  86. package/dist/docs-search.js +12 -4
  87. package/dist/docs-search.js.map +1 -1
  88. package/dist/doctor.d.ts +17 -0
  89. package/dist/doctor.d.ts.map +1 -1
  90. package/dist/doctor.js +76 -15
  91. package/dist/doctor.js.map +1 -1
  92. package/dist/env-file.d.ts +15 -0
  93. package/dist/env-file.d.ts.map +1 -1
  94. package/dist/env-file.js +73 -1
  95. package/dist/env-file.js.map +1 -1
  96. package/dist/fix-recipes.d.ts.map +1 -1
  97. package/dist/fix-recipes.js +41 -21
  98. package/dist/fix-recipes.js.map +1 -1
  99. package/dist/frontend-guidance.js +5 -5
  100. package/dist/frontend-guidance.js.map +1 -1
  101. package/dist/i18n-check.d.ts +16 -0
  102. package/dist/i18n-check.d.ts.map +1 -0
  103. package/dist/i18n-check.js +154 -0
  104. package/dist/i18n-check.js.map +1 -0
  105. package/dist/init-agents.d.ts +49 -13
  106. package/dist/init-agents.d.ts.map +1 -1
  107. package/dist/init-agents.js +239 -34
  108. package/dist/init-agents.js.map +1 -1
  109. package/dist/internal/code-unit-order.d.ts +4 -0
  110. package/dist/internal/code-unit-order.d.ts.map +1 -0
  111. package/dist/internal/code-unit-order.js +6 -0
  112. package/dist/internal/code-unit-order.js.map +1 -0
  113. package/dist/internal/script-kind.d.ts +7 -0
  114. package/dist/internal/script-kind.d.ts.map +1 -0
  115. package/dist/internal/script-kind.js +12 -0
  116. package/dist/internal/script-kind.js.map +1 -0
  117. package/dist/internal/source-facts.d.ts +5 -0
  118. package/dist/internal/source-facts.d.ts.map +1 -1
  119. package/dist/internal/source-facts.js +61 -5
  120. package/dist/internal/source-facts.js.map +1 -1
  121. package/dist/internal/typescript-import.d.ts +49 -24
  122. package/dist/internal/typescript-import.d.ts.map +1 -1
  123. package/dist/internal/typescript-import.js +507 -67
  124. package/dist/internal/typescript-import.js.map +1 -1
  125. package/dist/introspect.d.ts +6 -4
  126. package/dist/introspect.d.ts.map +1 -1
  127. package/dist/introspect.js +93 -74
  128. package/dist/introspect.js.map +1 -1
  129. package/dist/learn.js +3 -3
  130. package/dist/learn.js.map +1 -1
  131. package/dist/levels-tool.d.ts +10 -0
  132. package/dist/levels-tool.d.ts.map +1 -1
  133. package/dist/levels-tool.js +33 -3
  134. package/dist/levels-tool.js.map +1 -1
  135. package/dist/load.d.ts +71 -16
  136. package/dist/load.d.ts.map +1 -1
  137. package/dist/load.js +78 -18
  138. package/dist/load.js.map +1 -1
  139. package/dist/manifest-tool.d.ts.map +1 -1
  140. package/dist/manifest-tool.js +3 -2
  141. package/dist/manifest-tool.js.map +1 -1
  142. package/dist/mcp-app-tool.d.ts.map +1 -1
  143. package/dist/mcp-app-tool.js +2 -0
  144. package/dist/mcp-app-tool.js.map +1 -1
  145. package/dist/mcp-context.d.ts.map +1 -1
  146. package/dist/mcp-context.js +5 -6
  147. package/dist/mcp-context.js.map +1 -1
  148. package/dist/mcp-delegate.d.ts +57 -0
  149. package/dist/mcp-delegate.d.ts.map +1 -0
  150. package/dist/mcp-delegate.js +130 -0
  151. package/dist/mcp-delegate.js.map +1 -0
  152. package/dist/mcp-docs-tools.d.ts.map +1 -1
  153. package/dist/mcp-docs-tools.js +23 -5
  154. package/dist/mcp-docs-tools.js.map +1 -1
  155. package/dist/mcp-exec.d.ts +3 -0
  156. package/dist/mcp-exec.d.ts.map +1 -1
  157. package/dist/mcp-exec.js +263 -131
  158. package/dist/mcp-exec.js.map +1 -1
  159. package/dist/mcp-http.d.ts.map +1 -1
  160. package/dist/mcp-http.js +20 -5
  161. package/dist/mcp-http.js.map +1 -1
  162. package/dist/mcp-io.d.ts +26 -0
  163. package/dist/mcp-io.d.ts.map +1 -1
  164. package/dist/mcp-io.js +113 -0
  165. package/dist/mcp-io.js.map +1 -1
  166. package/dist/mcp-isolate.d.ts +48 -0
  167. package/dist/mcp-isolate.d.ts.map +1 -0
  168. package/dist/mcp-isolate.js +222 -0
  169. package/dist/mcp-isolate.js.map +1 -0
  170. package/dist/mcp-path.d.ts +10 -0
  171. package/dist/mcp-path.d.ts.map +1 -0
  172. package/dist/mcp-path.js +51 -0
  173. package/dist/mcp-path.js.map +1 -0
  174. package/dist/mcp-project-child.d.ts +74 -0
  175. package/dist/mcp-project-child.d.ts.map +1 -0
  176. package/dist/mcp-project-child.js +130 -0
  177. package/dist/mcp-project-child.js.map +1 -0
  178. package/dist/mcp-reflect.d.ts.map +1 -1
  179. package/dist/mcp-reflect.js +2 -2
  180. package/dist/mcp-reflect.js.map +1 -1
  181. package/dist/mcp-render.d.ts.map +1 -1
  182. package/dist/mcp-render.js +64 -45
  183. package/dist/mcp-render.js.map +1 -1
  184. package/dist/mcp-root.d.ts +37 -9
  185. package/dist/mcp-root.d.ts.map +1 -1
  186. package/dist/mcp-root.js +124 -25
  187. package/dist/mcp-root.js.map +1 -1
  188. package/dist/mcp-run.d.ts +18 -1
  189. package/dist/mcp-run.d.ts.map +1 -1
  190. package/dist/mcp-run.js +159 -55
  191. package/dist/mcp-run.js.map +1 -1
  192. package/dist/mcp-ws.js +4 -1
  193. package/dist/mcp-ws.js.map +1 -1
  194. package/dist/mcp.d.ts +18 -5
  195. package/dist/mcp.d.ts.map +1 -1
  196. package/dist/mcp.js +165 -82
  197. package/dist/mcp.js.map +1 -1
  198. package/dist/migrate-layout.d.ts +44 -0
  199. package/dist/migrate-layout.d.ts.map +1 -0
  200. package/dist/migrate-layout.js +982 -0
  201. package/dist/migrate-layout.js.map +1 -0
  202. package/dist/openapi-tool.d.ts +2 -2
  203. package/dist/openapi-tool.d.ts.map +1 -1
  204. package/dist/openapi-tool.js.map +1 -1
  205. package/dist/openapi-types.d.ts +2 -1
  206. package/dist/openapi-types.d.ts.map +1 -1
  207. package/dist/openapi-types.js +240 -12
  208. package/dist/openapi-types.js.map +1 -1
  209. package/dist/pipeline-report.d.ts +3 -2
  210. package/dist/pipeline-report.d.ts.map +1 -1
  211. package/dist/pipeline-report.js +19 -16
  212. package/dist/pipeline-report.js.map +1 -1
  213. package/dist/port.d.ts +5 -4
  214. package/dist/port.d.ts.map +1 -1
  215. package/dist/port.js +46 -29
  216. package/dist/port.js.map +1 -1
  217. package/dist/project-facts.d.ts +28 -4
  218. package/dist/project-facts.d.ts.map +1 -1
  219. package/dist/project-facts.js +12 -2
  220. package/dist/project-facts.js.map +1 -1
  221. package/dist/recipes/4.0.0.d.ts +9 -0
  222. package/dist/recipes/4.0.0.d.ts.map +1 -0
  223. package/dist/recipes/4.0.0.js +34 -0
  224. package/dist/recipes/4.0.0.js.map +1 -0
  225. package/dist/recipes/index.d.ts.map +1 -1
  226. package/dist/recipes/index.js +2 -0
  227. package/dist/recipes/index.js.map +1 -1
  228. package/dist/release-verification.d.ts +11 -1
  229. package/dist/release-verification.d.ts.map +1 -1
  230. package/dist/release-verification.js +47 -4
  231. package/dist/release-verification.js.map +1 -1
  232. package/dist/review.d.ts +21 -0
  233. package/dist/review.d.ts.map +1 -0
  234. package/dist/review.js +823 -0
  235. package/dist/review.js.map +1 -0
  236. package/dist/route-types.d.ts +28 -0
  237. package/dist/route-types.d.ts.map +1 -0
  238. package/dist/route-types.js +106 -0
  239. package/dist/route-types.js.map +1 -0
  240. package/dist/rules/codes.d.ts +9 -0
  241. package/dist/rules/codes.d.ts.map +1 -1
  242. package/dist/rules/codes.js +9 -0
  243. package/dist/rules/codes.js.map +1 -1
  244. package/dist/rules/data-guard.d.ts +12 -0
  245. package/dist/rules/data-guard.d.ts.map +1 -0
  246. package/dist/rules/data-guard.js +213 -0
  247. package/dist/rules/data-guard.js.map +1 -0
  248. package/dist/rules/index.d.ts +3 -0
  249. package/dist/rules/index.d.ts.map +1 -1
  250. package/dist/rules/index.js +17 -5
  251. package/dist/rules/index.js.map +1 -1
  252. package/dist/rules/islands.d.ts.map +1 -1
  253. package/dist/rules/islands.js +7 -4
  254. package/dist/rules/islands.js.map +1 -1
  255. package/dist/rules/legacy.d.ts +3 -1
  256. package/dist/rules/legacy.d.ts.map +1 -1
  257. package/dist/rules/legacy.js +829 -34
  258. package/dist/rules/legacy.js.map +1 -1
  259. package/dist/rules/nano.d.ts.map +1 -1
  260. package/dist/rules/nano.js +15 -6
  261. package/dist/rules/nano.js.map +1 -1
  262. package/dist/rules/pages.d.ts +15 -0
  263. package/dist/rules/pages.d.ts.map +1 -0
  264. package/dist/rules/pages.js +88 -0
  265. package/dist/rules/pages.js.map +1 -0
  266. package/dist/rules/routes.d.ts +11 -0
  267. package/dist/rules/routes.d.ts.map +1 -1
  268. package/dist/rules/routes.js +180 -2
  269. package/dist/rules/routes.js.map +1 -1
  270. package/dist/rules/secrets.d.ts +10 -0
  271. package/dist/rules/secrets.d.ts.map +1 -0
  272. package/dist/rules/secrets.js +169 -0
  273. package/dist/rules/secrets.js.map +1 -0
  274. package/dist/rules/security.d.ts +7 -0
  275. package/dist/rules/security.d.ts.map +1 -1
  276. package/dist/rules/security.js +171 -65
  277. package/dist/rules/security.js.map +1 -1
  278. package/dist/rules/typescript.d.ts +16 -0
  279. package/dist/rules/typescript.d.ts.map +1 -0
  280. package/dist/rules/typescript.js +59 -0
  281. package/dist/rules/typescript.js.map +1 -0
  282. package/dist/rules/zones.d.ts +17 -0
  283. package/dist/rules/zones.d.ts.map +1 -0
  284. package/dist/rules/zones.js +174 -0
  285. package/dist/rules/zones.js.map +1 -0
  286. package/dist/scaffold.d.ts +25 -12
  287. package/dist/scaffold.d.ts.map +1 -1
  288. package/dist/scaffold.js +154 -90
  289. package/dist/scaffold.js.map +1 -1
  290. package/dist/sdk.d.ts +17 -3
  291. package/dist/sdk.d.ts.map +1 -1
  292. package/dist/sdk.js +941 -153
  293. package/dist/sdk.js.map +1 -1
  294. package/dist/search-terms.d.ts +2 -0
  295. package/dist/search-terms.d.ts.map +1 -1
  296. package/dist/search-terms.js +23 -8
  297. package/dist/search-terms.js.map +1 -1
  298. package/dist/smoke.d.ts +79 -0
  299. package/dist/smoke.d.ts.map +1 -0
  300. package/dist/smoke.js +494 -0
  301. package/dist/smoke.js.map +1 -0
  302. package/dist/sync-manifest.d.ts.map +1 -1
  303. package/dist/sync-manifest.js +2 -1
  304. package/dist/sync-manifest.js.map +1 -1
  305. package/dist/sync-routes.d.ts +4 -3
  306. package/dist/sync-routes.d.ts.map +1 -1
  307. package/dist/sync-routes.js +4 -3
  308. package/dist/sync-routes.js.map +1 -1
  309. package/dist/test-tool.d.ts.map +1 -1
  310. package/dist/test-tool.js +30 -11
  311. package/dist/test-tool.js.map +1 -1
  312. package/dist/types-search.d.ts.map +1 -1
  313. package/dist/types-search.js +11 -5
  314. package/dist/types-search.js.map +1 -1
  315. package/dist/upgrade.d.ts +36 -6
  316. package/dist/upgrade.d.ts.map +1 -1
  317. package/dist/upgrade.js +167 -29
  318. package/dist/upgrade.js.map +1 -1
  319. package/dist/verification-plan.d.ts.map +1 -1
  320. package/dist/verification-plan.js +8 -0
  321. package/dist/verification-plan.js.map +1 -1
  322. package/dist/verification.d.ts.map +1 -1
  323. package/dist/verification.js +45 -12
  324. package/dist/verification.js.map +1 -1
  325. package/dist/web-app-options.d.ts +19 -0
  326. package/dist/web-app-options.d.ts.map +1 -0
  327. package/dist/web-app-options.js +49 -0
  328. package/dist/web-app-options.js.map +1 -0
  329. package/dist/work-graph.d.ts +3 -0
  330. package/dist/work-graph.d.ts.map +1 -1
  331. package/dist/work-graph.js +33 -16
  332. package/dist/work-graph.js.map +1 -1
  333. package/docs/examples.json +185 -29
  334. package/docs/llms-full.txt +4123 -548
  335. package/docs/types.json +14391 -10060
  336. package/package.json +19 -11
  337. package/src/app-files.ts +40 -0
  338. package/src/assure-hydration.ts +139 -46
  339. package/src/assure.ts +17 -2
  340. package/src/capabilities-tool.ts +35 -9
  341. package/src/cdn-check.ts +268 -0
  342. package/src/check-diagnostics.ts +199 -797
  343. package/src/check-scan.ts +394 -63
  344. package/src/check.ts +146 -58
  345. package/src/cli.ts +347 -92
  346. package/src/command-catalog.ts +407 -45
  347. package/src/config-target.ts +47 -0
  348. package/src/contracts.ts +66 -15
  349. package/src/db-audit.ts +128 -0
  350. package/src/db-child.ts +285 -0
  351. package/src/db-config.ts +224 -0
  352. package/src/db-tool.ts +690 -0
  353. package/src/dev-bun-config.ts +116 -40
  354. package/src/dev-feed-tool.ts +912 -0
  355. package/src/dev-server-client.ts +267 -0
  356. package/src/diagnostics.ts +179 -0
  357. package/src/diff-tool.ts +6 -5
  358. package/src/docs-search.ts +10 -3
  359. package/src/doctor.ts +98 -15
  360. package/src/env-file.ts +78 -1
  361. package/src/fix-recipes.ts +44 -31
  362. package/src/frontend-guidance.ts +5 -5
  363. package/src/i18n-check.ts +179 -0
  364. package/src/init-agents.ts +301 -38
  365. package/src/internal/code-unit-order.ts +5 -0
  366. package/src/internal/script-kind.ts +11 -0
  367. package/src/internal/source-facts.ts +96 -22
  368. package/src/internal/typescript-import.ts +663 -68
  369. package/src/introspect.ts +93 -82
  370. package/src/learn.ts +3 -3
  371. package/src/levels-tool.ts +47 -2
  372. package/src/load.ts +144 -32
  373. package/src/manifest-tool.ts +3 -2
  374. package/src/mcp-app-tool.ts +2 -0
  375. package/src/mcp-context.ts +5 -7
  376. package/src/mcp-delegate.ts +162 -0
  377. package/src/mcp-docs-tools.ts +23 -5
  378. package/src/mcp-exec.ts +301 -161
  379. package/src/mcp-http.ts +22 -5
  380. package/src/mcp-io.ts +130 -0
  381. package/src/mcp-isolate.ts +287 -0
  382. package/src/mcp-path.ts +50 -0
  383. package/src/mcp-project-child.ts +182 -0
  384. package/src/mcp-reflect.ts +3 -2
  385. package/src/mcp-render.ts +72 -42
  386. package/src/mcp-root.ts +130 -24
  387. package/src/mcp-run.ts +190 -56
  388. package/src/mcp-ws.ts +4 -1
  389. package/src/mcp.ts +193 -91
  390. package/src/migrate-layout.ts +1121 -0
  391. package/src/openapi-tool.ts +7 -3
  392. package/src/openapi-types.ts +315 -13
  393. package/src/pipeline-report.ts +22 -18
  394. package/src/port.ts +53 -30
  395. package/src/project-facts.ts +42 -8
  396. package/src/recipes/4.0.0.ts +35 -0
  397. package/src/recipes/index.ts +2 -0
  398. package/src/release-verification.ts +74 -5
  399. package/src/review.ts +988 -0
  400. package/src/route-types.ts +133 -0
  401. package/src/rules/codes.ts +9 -0
  402. package/src/rules/data-guard.ts +230 -0
  403. package/src/rules/index.ts +18 -5
  404. package/src/rules/islands.ts +12 -4
  405. package/src/rules/legacy.ts +947 -35
  406. package/src/rules/nano.ts +18 -6
  407. package/src/rules/pages.ts +99 -0
  408. package/src/rules/routes.ts +181 -2
  409. package/src/rules/secrets.ts +174 -0
  410. package/src/rules/security.ts +198 -70
  411. package/src/rules/typescript.ts +77 -0
  412. package/src/rules/zones.ts +195 -0
  413. package/src/scaffold.ts +175 -98
  414. package/src/sdk.ts +1215 -158
  415. package/src/search-terms.ts +24 -7
  416. package/src/smoke.ts +607 -0
  417. package/src/sync-manifest.ts +2 -1
  418. package/src/sync-routes.ts +4 -3
  419. package/src/test-tool.ts +32 -11
  420. package/src/types-search.ts +11 -4
  421. package/src/upgrade.ts +205 -25
  422. package/src/verification-plan.ts +27 -0
  423. package/src/verification.ts +50 -12
  424. package/src/web-app-options.ts +57 -0
  425. package/src/work-graph.ts +40 -16
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The `createWebApp` options a CLI-run app takes from its framework config and `backend/app.ts`,
3
+ * built in one place. `nifra dev`, the static prerender, `nifra mcp`'s render tool and the
4
+ * hydration gate each construct the app themselves, and the generated server entry constructs it in
5
+ * production; when each call site picked its own subset, the app they served drifted from the one
6
+ * that ships.
7
+ */
8
+ import { inProcessClient } from "@nifrajs/client"
9
+ import type { CreateWebAppOptions } from "@nifrajs/web"
10
+ import { FRAMEWORK_WEB_OPTIONS, type FrameworkWebOption, type NifraFramework } from "./load.ts"
11
+
12
+ type FrameworkWebAppOptions = Pick<
13
+ CreateWebAppOptions,
14
+ "use" | "api" | "apiPrefix" | "apiStrip" | "mounts" | "csp" | "nonce"
15
+ >
16
+
17
+ /** `use`, the backend as `api`, and every forwarded framework field the config sets. */
18
+ export function frameworkWebAppOptions(
19
+ fw: NifraFramework,
20
+ backend: unknown,
21
+ ): FrameworkWebAppOptions {
22
+ const options: Record<string, unknown> = {}
23
+ if (fw.use !== undefined) options.use = fw.use
24
+ if (backend !== undefined) options.api = inProcessClient(backend as never)
25
+ for (const name of FRAMEWORK_WEB_OPTIONS) {
26
+ if (fw[name] !== undefined) options[name] = fw[name]
27
+ }
28
+ return options as FrameworkWebAppOptions
29
+ }
30
+
31
+ /**
32
+ * The mount paths the app will serve ahead of page routing, read from the config alone (no app is
33
+ * built): each `mounts` entry, plus the backend at `apiPrefix` when `backend/app.ts` exports one. A
34
+ * mount added inside `use` is not visible here; `createWebApp` checks its own mount table at
35
+ * startup.
36
+ */
37
+ export function frameworkMountPaths(fw: NifraFramework, hasBackend: boolean): string[] {
38
+ const paths: string[] = []
39
+ for (const mount of fw.mounts ?? []) {
40
+ if (typeof mount?.path === "string") paths.push(mount.path)
41
+ }
42
+ const apiPrefix = fw.apiPrefix ?? "/api"
43
+ if (hasBackend && apiPrefix !== "") paths.push(apiPrefix)
44
+ return paths
45
+ }
46
+
47
+ /** The generated server entry's imports for the forwarded fields the config sets, all from the
48
+ * edge-safe framework module. */
49
+ export function frameworkOptionImports(
50
+ fw: NifraFramework,
51
+ frameworkFile: string,
52
+ ): { optionImports?: Partial<Record<FrameworkWebOption, string>> } {
53
+ const imports: Partial<Record<FrameworkWebOption, string>> = {}
54
+ for (const name of FRAMEWORK_WEB_OPTIONS)
55
+ if (fw[name] !== undefined) imports[name] = frameworkFile
56
+ return Object.keys(imports).length === 0 ? {} : { optionImports: imports }
57
+ }
package/src/work-graph.ts CHANGED
@@ -9,9 +9,16 @@
9
9
  import { existsSync } from "node:fs"
10
10
  import { readFile, stat } from "node:fs/promises"
11
11
  import { basename, resolve } from "node:path"
12
- import { type ReflectedRoute, reflectRoutes } from "@nifrajs/core/reflection"
12
+ import {
13
+ type ProjectEvidenceSnapshot,
14
+ reflectedRoutesFromEvidence,
15
+ snapshotProjectEvidence,
16
+ } from "@nifrajs/core/evidence"
17
+ import type { ReflectedRoute } from "@nifrajs/core/reflection"
13
18
  import { Glob } from "bun"
19
+ import { BACKEND_APP_FILE, CONFIG_FILE, FRAMEWORK_FILE } from "./app-files.ts"
14
20
  import { digestRoute } from "./contracts.ts"
21
+ import { codeUnitOrder } from "./internal/code-unit-order.ts"
15
22
 
16
23
  export type WorkGraphNodeKind =
17
24
  | "route"
@@ -52,6 +59,8 @@ export interface WorkGraphSourceFile {
52
59
 
53
60
  export interface WorkGraphBuildInput {
54
61
  readonly source: unknown
62
+ /** Reuse a canonical route-evidence pass when the caller already has one. */
63
+ readonly evidence?: ProjectEvidenceSnapshot
55
64
  readonly files?: readonly WorkGraphSourceFile[]
56
65
  readonly freshness?: BuildFreshness
57
66
  }
@@ -126,8 +135,11 @@ export interface ProjectWorkGraphResult {
126
135
  readonly evidence: EvidenceBundle
127
136
  }
128
137
 
129
- const SOURCE_GLOB = new Glob("**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json}")
138
+ // Framework component, content, and style files are app source too: an edit to one makes a build stale.
139
+ const SOURCE_GLOB = new Glob("**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json,svelte,vue,mdx,css}")
130
140
  const IGNORED = /(^|\/)(node_modules|dist|build|\.nifra|\.git|\.wrangler|coverage)\//
141
+ const APP_SOURCE_DIR = /^(?:routes|frontend|backend|shared)\//
142
+ const BACKEND_SOURCE_DIR = /^(?:backend|shared)\//
131
143
  const MANIFEST_NAMES = new Set([
132
144
  "server-manifest.ts",
133
145
  "nifra-manifest.json",
@@ -169,13 +181,13 @@ export function evaluateBuildFreshness(input: {
169
181
 
170
182
  export async function inspectBuildFreshness(cwd: string): Promise<BuildFreshness> {
171
183
  const sourcePaths: string[] = []
172
- for (const name of ["backend.ts", "framework.ts", "nifra.config.ts"]) {
184
+ for (const name of [BACKEND_APP_FILE, FRAMEWORK_FILE, CONFIG_FILE]) {
173
185
  const path = resolve(cwd, name)
174
186
  if (existsSync(path)) sourcePaths.push(path)
175
187
  }
176
188
  for await (const rawPath of SOURCE_GLOB.scan({ cwd, dot: false })) {
177
189
  const path = rawPath.replaceAll("\\", "/")
178
- if (!IGNORED.test(path) && path.startsWith("routes/")) sourcePaths.push(resolve(cwd, path))
190
+ if (!IGNORED.test(path) && APP_SOURCE_DIR.test(path)) sourcePaths.push(resolve(cwd, path))
179
191
  }
180
192
  const sourceTimes = await fileTimes(sourcePaths)
181
193
  for (const buildDirName of ["dist", "build"]) {
@@ -208,8 +220,8 @@ export async function collectProjectWorkGraph(
208
220
  ): Promise<ProjectWorkGraphResult> {
209
221
  const freshness = await inspectBuildFreshness(cwd)
210
222
  if (!freshness.ok) throw new StaleBuildError(freshness)
211
- const backendPath = resolve(cwd, "backend.ts")
212
- if (!existsSync(backendPath)) throw new Error(`[nifra] no backend.ts in ${cwd}`)
223
+ const backendPath = resolve(cwd, BACKEND_APP_FILE)
224
+ if (!existsSync(backendPath)) throw new Error(`[nifra] no ${BACKEND_APP_FILE} in ${cwd}`)
213
225
  const loadedValue: unknown = await import(`${backendPath}?nifra-work-graph=${Date.now()}`)
214
226
  const loaded = recordOf(loadedValue)
215
227
  if (loaded?.backend === undefined)
@@ -224,7 +236,8 @@ export async function buildProjectWorkGraph(
224
236
  ): Promise<ProjectWorkGraphResult> {
225
237
  const freshness = input.freshness ?? { ok: true }
226
238
  if (!freshness.ok) throw new StaleBuildError(freshness)
227
- const graph = await buildWorkGraph(input)
239
+ const projectEvidence = input.evidence ?? snapshotProjectEvidence(input.source)
240
+ const graph = await buildWorkGraph({ ...input, evidence: projectEvidence })
228
241
  const impact = queryImpact(graph, options.changedFiles ?? [])
229
242
  const plan = planProofs(graph, impact, options.minLevel ?? 1)
230
243
  const evidence = createEvidenceBundle(graph, impact, plan)
@@ -232,7 +245,9 @@ export async function buildProjectWorkGraph(
232
245
  }
233
246
 
234
247
  export async function buildWorkGraph(input: WorkGraphBuildInput): Promise<WorkGraph> {
235
- const routes = reflectRoutes(input.source)
248
+ const routes = reflectedRoutesFromEvidence(
249
+ input.evidence ?? snapshotProjectEvidence(input.source),
250
+ )
236
251
  const files = input.files ?? []
237
252
  const nodes = new Map<string, WorkGraphNode>()
238
253
  const edges: WorkGraphEdge[] = []
@@ -280,8 +295,8 @@ export async function buildWorkGraph(input: WorkGraphBuildInput): Promise<WorkGr
280
295
  })
281
296
  for (const file of routeFiles)
282
297
  addEdge({ from: `file:${file}`, to: routeId, relation: "implements" })
283
- if (routeFiles.length === 0 && sourceFiles.some((file) => file.path === "backend.ts"))
284
- addEdge({ from: "file:backend.ts", to: routeId, relation: "implements" })
298
+ if (routeFiles.length === 0 && sourceFiles.some((file) => file.path === BACKEND_APP_FILE))
299
+ addEdge({ from: `file:${BACKEND_APP_FILE}`, to: routeId, relation: "implements" })
285
300
  for (const [name, schema] of Object.entries(route.schema ?? {})) {
286
301
  if (schema === undefined || name === "errors") continue
287
302
  const schemaId = `schema:${routeKey}:${name}`
@@ -324,9 +339,9 @@ export async function buildWorkGraph(input: WorkGraphBuildInput): Promise<WorkGr
324
339
  for (const file of manifestFiles)
325
340
  addEdge({ from: `manifest:${file.path}`, to: routeId, relation: "describes" })
326
341
  }
327
- const sortedNodes = [...nodes.values()].sort((a, b) => a.id.localeCompare(b.id))
342
+ const sortedNodes = [...nodes.values()].sort((a, b) => codeUnitOrder(a.id, b.id))
328
343
  const sortedEdges = edges.sort((a, b) =>
329
- `${a.from}\n${a.to}\n${a.relation}`.localeCompare(`${b.from}\n${b.to}\n${b.relation}`),
344
+ codeUnitOrder(`${a.from}\n${a.to}\n${a.relation}`, `${b.from}\n${b.to}\n${b.relation}`),
330
345
  )
331
346
  const digest = await digestJson({ nodes: sortedNodes, edges: sortedEdges })
332
347
  return Object.freeze({
@@ -343,7 +358,9 @@ export function queryImpact(graph: WorkGraph, changedFiles: readonly string[]):
343
358
  ...new Set(changedFiles.map((file) => file.replace(/^\.\//, "").replaceAll("\\", "/"))),
344
359
  ]
345
360
  const seeds = new Set<string>()
361
+ const unmodeled: string[] = []
346
362
  for (const file of normalized) {
363
+ let seeded = false
347
364
  for (const node of graph.nodes) {
348
365
  if (
349
366
  (node.kind === "file" || node.kind === "test" || node.kind === "manifest") &&
@@ -351,11 +368,18 @@ export function queryImpact(graph: WorkGraph, changedFiles: readonly string[]):
351
368
  node.id === `test:${file}` ||
352
369
  node.id === `manifest:${file}` ||
353
370
  node.files.includes(file))
354
- )
371
+ ) {
355
372
  seeds.add(node.id)
373
+ seeded = true
374
+ }
356
375
  }
376
+ // An app file the graph does not model (deleted, or a type it does not read) has an unknown
377
+ // reach, so it stands for itself and impacts every route rather than proving nothing.
378
+ if (!seeded && APP_SOURCE_DIR.test(file)) unmodeled.push(file)
357
379
  }
358
- if (normalized.includes("backend.ts"))
380
+ for (const file of unmodeled) seeds.add(`file:${file}`)
381
+ // Any backend or shared module can reach every handler through backend/app.ts.
382
+ if (unmodeled.length > 0 || normalized.some((file) => BACKEND_SOURCE_DIR.test(file)))
359
383
  for (const node of graph.nodes) if (node.kind === "route") seeds.add(node.id)
360
384
  const impacted = new Set(seeds)
361
385
  const queue = [...seeds]
@@ -434,7 +458,7 @@ export function createEvidenceBundle(
434
458
  plan: ProofPlan,
435
459
  proofs: readonly ProofEvidence[] = [],
436
460
  ): EvidenceBundle {
437
- const evidence = [...proofs].sort((a, b) => a.id.localeCompare(b.id))
461
+ const evidence = [...proofs].sort((a, b) => codeUnitOrder(a.id, b.id))
438
462
  // Levels are not cumulative (assure does not typecheck), so every planned step needs its own
439
463
  // passing proof; a higher-level pass never subsumes a lower one.
440
464
  const done =
@@ -571,7 +595,7 @@ function filesForRoute(
571
595
  const matches = files
572
596
  .filter(
573
597
  (file) =>
574
- file.path === "backend.ts" ||
598
+ file.path === BACKEND_APP_FILE ||
575
599
  (file.path.startsWith("routes/") && file.content.includes(route.path)),
576
600
  )
577
601
  .map((file) => file.path)