@fougere/core 0.6.0-alpha.0 → 0.8.0-alpha.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 (510) hide show
  1. package/README.md +1 -1
  2. package/dist/boot/AppLifecycle.d.ts +1 -1
  3. package/dist/boot/AppLifecycle.d.ts.map +1 -1
  4. package/dist/boot/AppLifecycle.js +13 -2
  5. package/dist/boot/AppLifecycle.js.map +1 -1
  6. package/dist/boot/Emissions.d.ts +13 -90
  7. package/dist/boot/Emissions.d.ts.map +1 -1
  8. package/dist/boot/Emissions.js +21 -118
  9. package/dist/boot/Emissions.js.map +1 -1
  10. package/dist/boot/ambient-port.d.ts +3 -24
  11. package/dist/boot/ambient-port.d.ts.map +1 -1
  12. package/dist/boot/ambient.als.d.ts.map +1 -1
  13. package/dist/boot/ambient.als.js +7 -12
  14. package/dist/boot/ambient.als.js.map +1 -1
  15. package/dist/boot/ambient.queue.d.ts +2 -5
  16. package/dist/boot/ambient.queue.d.ts.map +1 -1
  17. package/dist/boot/ambient.queue.js.map +1 -1
  18. package/dist/boot/apply.d.ts +1 -13
  19. package/dist/boot/apply.d.ts.map +1 -1
  20. package/dist/boot/apply.js +9 -16
  21. package/dist/boot/apply.js.map +1 -1
  22. package/dist/boot/auth.d.ts +2 -12
  23. package/dist/boot/auth.d.ts.map +1 -1
  24. package/dist/boot/boot.d.ts +3 -16
  25. package/dist/boot/boot.d.ts.map +1 -1
  26. package/dist/boot/boot.js +4 -11
  27. package/dist/boot/boot.js.map +1 -1
  28. package/dist/boot/bootstrap.d.ts.map +1 -1
  29. package/dist/boot/bootstrap.js +84 -130
  30. package/dist/boot/bootstrap.js.map +1 -1
  31. package/dist/boot/card.d.ts +1 -17
  32. package/dist/boot/card.d.ts.map +1 -1
  33. package/dist/boot/card.js +3 -32
  34. package/dist/boot/card.js.map +1 -1
  35. package/dist/boot/frame.d.ts +8 -32
  36. package/dist/boot/frame.d.ts.map +1 -1
  37. package/dist/boot/frame.js +17 -56
  38. package/dist/boot/frame.js.map +1 -1
  39. package/dist/boot/hosted.d.ts +2 -24
  40. package/dist/boot/hosted.d.ts.map +1 -1
  41. package/dist/boot/hosted.js +10 -15
  42. package/dist/boot/hosted.js.map +1 -1
  43. package/dist/boot/ownership.d.ts +3 -36
  44. package/dist/boot/ownership.d.ts.map +1 -1
  45. package/dist/boot/ownership.js +5 -40
  46. package/dist/boot/ownership.js.map +1 -1
  47. package/dist/boot/ports.d.ts +1 -14
  48. package/dist/boot/ports.d.ts.map +1 -1
  49. package/dist/boot/ports.js +1 -14
  50. package/dist/boot/ports.js.map +1 -1
  51. package/dist/boot/remote.d.ts +5 -38
  52. package/dist/boot/remote.d.ts.map +1 -1
  53. package/dist/boot/remote.js +8 -41
  54. package/dist/boot/remote.js.map +1 -1
  55. package/dist/boot/runner.d.ts +4 -21
  56. package/dist/boot/runner.d.ts.map +1 -1
  57. package/dist/boot/runner.js +4 -17
  58. package/dist/boot/runner.js.map +1 -1
  59. package/dist/boot/seed.d.ts +4 -31
  60. package/dist/boot/seed.d.ts.map +1 -1
  61. package/dist/boot/seed.js +6 -37
  62. package/dist/boot/seed.js.map +1 -1
  63. package/dist/boot/statement-drift.d.ts +2 -21
  64. package/dist/boot/statement-drift.d.ts.map +1 -1
  65. package/dist/boot/statement-drift.js +4 -9
  66. package/dist/boot/statement-drift.js.map +1 -1
  67. package/dist/boot/together.d.ts +4 -8
  68. package/dist/boot/together.d.ts.map +1 -1
  69. package/dist/boot/together.js +15 -50
  70. package/dist/boot/together.js.map +1 -1
  71. package/dist/boot/types.d.ts +31 -173
  72. package/dist/boot/types.d.ts.map +1 -1
  73. package/dist/builtin/config.d.ts +7 -0
  74. package/dist/builtin/config.d.ts.map +1 -0
  75. package/dist/builtin/config.js +15 -0
  76. package/dist/builtin/config.js.map +1 -0
  77. package/dist/{builtins → builtin}/logger.d.ts +4 -25
  78. package/dist/builtin/logger.d.ts.map +1 -0
  79. package/dist/{builtins → builtin}/logger.js +5 -32
  80. package/dist/builtin/logger.js.map +1 -0
  81. package/dist/config-loader.d.ts +9 -67
  82. package/dist/config-loader.d.ts.map +1 -1
  83. package/dist/config-loader.js +5 -18
  84. package/dist/config-loader.js.map +1 -1
  85. package/dist/contract.d.ts +15 -31
  86. package/dist/contract.d.ts.map +1 -1
  87. package/dist/contract.js +13 -26
  88. package/dist/contract.js.map +1 -1
  89. package/dist/criterion.d.ts +37 -0
  90. package/dist/criterion.d.ts.map +1 -0
  91. package/dist/criterion.js +28 -0
  92. package/dist/criterion.js.map +1 -0
  93. package/dist/crypto/encoding.d.ts +2 -15
  94. package/dist/crypto/encoding.d.ts.map +1 -1
  95. package/dist/crypto/encoding.js +2 -15
  96. package/dist/crypto/encoding.js.map +1 -1
  97. package/dist/crypto/node.d.ts.map +1 -1
  98. package/dist/crypto/node.js +1 -7
  99. package/dist/crypto/node.js.map +1 -1
  100. package/dist/crypto/port.d.ts +2 -18
  101. package/dist/crypto/port.d.ts.map +1 -1
  102. package/dist/crypto/port.js +1 -17
  103. package/dist/crypto/port.js.map +1 -1
  104. package/dist/crypto/webcrypto.d.ts.map +1 -1
  105. package/dist/crypto/webcrypto.js +1 -12
  106. package/dist/crypto/webcrypto.js.map +1 -1
  107. package/dist/declare.d.ts +19 -37
  108. package/dist/declare.d.ts.map +1 -1
  109. package/dist/declare.js +23 -30
  110. package/dist/declare.js.map +1 -1
  111. package/dist/define.d.ts +2 -3
  112. package/dist/define.d.ts.map +1 -1
  113. package/dist/define.js +2 -3
  114. package/dist/define.js.map +1 -1
  115. package/dist/descriptor/Fronds.d.ts +3 -28
  116. package/dist/descriptor/Fronds.d.ts.map +1 -1
  117. package/dist/descriptor/Fronds.js +6 -31
  118. package/dist/descriptor/Fronds.js.map +1 -1
  119. package/dist/descriptor/frond.d.ts +25 -60
  120. package/dist/descriptor/frond.d.ts.map +1 -1
  121. package/dist/descriptor/frond.js +5 -1
  122. package/dist/descriptor/frond.js.map +1 -1
  123. package/dist/dispatch/ArgumentResolver.d.ts +1 -1
  124. package/dist/dispatch/ArgumentResolver.d.ts.map +1 -1
  125. package/dist/dispatch/ArgumentResolver.js +5 -5
  126. package/dist/dispatch/ArgumentResolver.js.map +1 -1
  127. package/dist/dispatch/DispatchEvent.d.ts +2 -2
  128. package/dist/dispatch/DispatchEvent.d.ts.map +1 -1
  129. package/dist/dispatch/DispatchLifecycle.d.ts +1 -7
  130. package/dist/dispatch/DispatchLifecycle.d.ts.map +1 -1
  131. package/dist/dispatch/DispatchLifecycle.js +1 -7
  132. package/dist/dispatch/DispatchLifecycle.js.map +1 -1
  133. package/dist/dispatch/DispatchPort.d.ts +1 -1
  134. package/dist/dispatch/DispatchPort.d.ts.map +1 -1
  135. package/dist/dispatch/Dispatcher.d.ts +1 -1
  136. package/dist/dispatch/Dispatcher.d.ts.map +1 -1
  137. package/dist/dispatch/Dispatcher.js +2 -2
  138. package/dist/dispatch/Dispatcher.js.map +1 -1
  139. package/dist/{boot → dispatch}/HandlerFacade.d.ts +25 -38
  140. package/dist/dispatch/HandlerFacade.d.ts.map +1 -0
  141. package/dist/{boot → dispatch}/HandlerFacade.js +65 -74
  142. package/dist/dispatch/HandlerFacade.js.map +1 -0
  143. package/dist/dispatch/LocalRoutePolicy.d.ts +1 -1
  144. package/dist/dispatch/LocalRoutePolicy.d.ts.map +1 -1
  145. package/dist/dispatch/LocalRoutePolicy.js +4 -4
  146. package/dist/dispatch/LocalRoutePolicy.js.map +1 -1
  147. package/dist/dispatch/OperationRoute.d.ts +2 -2
  148. package/dist/dispatch/OperationRoute.d.ts.map +1 -1
  149. package/dist/dispatch/OutputView.d.ts +3 -2
  150. package/dist/dispatch/OutputView.d.ts.map +1 -1
  151. package/dist/dispatch/OutputView.js +19 -1
  152. package/dist/dispatch/OutputView.js.map +1 -1
  153. package/dist/dispatch/Route.d.ts +2 -2
  154. package/dist/dispatch/Route.d.ts.map +1 -1
  155. package/dist/dispatch/RoutePolicy.d.ts +1 -1
  156. package/dist/dispatch/RoutePolicy.d.ts.map +1 -1
  157. package/dist/dispatch/RouteRegistry.d.ts +1 -1
  158. package/dist/dispatch/RouteRegistry.d.ts.map +1 -1
  159. package/dist/dispatch/RouteRegistry.js +2 -2
  160. package/dist/dispatch/RouteRegistry.js.map +1 -1
  161. package/dist/dispatch/RouteResolver.d.ts +2 -4
  162. package/dist/dispatch/RouteResolver.d.ts.map +1 -1
  163. package/dist/dispatch/StorageGuard.d.ts +40 -8
  164. package/dist/dispatch/StorageGuard.d.ts.map +1 -1
  165. package/dist/dispatch/StorageGuard.js +151 -20
  166. package/dist/dispatch/StorageGuard.js.map +1 -1
  167. package/dist/dispatch/presenterArguments.d.ts +7 -0
  168. package/dist/dispatch/presenterArguments.d.ts.map +1 -0
  169. package/dist/dispatch/presenterArguments.js +12 -0
  170. package/dist/dispatch/presenterArguments.js.map +1 -0
  171. package/dist/dispatch/remoteRoutes.d.ts +7 -0
  172. package/dist/dispatch/remoteRoutes.d.ts.map +1 -0
  173. package/dist/dispatch/{RemoteRouteResolver.js → remoteRoutes.js} +6 -10
  174. package/dist/dispatch/remoteRoutes.js.map +1 -0
  175. package/dist/dispatch/routeNotFound.d.ts +9 -0
  176. package/dist/dispatch/routeNotFound.d.ts.map +1 -0
  177. package/dist/dispatch/routeNotFound.js +21 -0
  178. package/dist/dispatch/routeNotFound.js.map +1 -0
  179. package/dist/dispatch/validateInput.d.ts +5 -0
  180. package/dist/dispatch/validateInput.d.ts.map +1 -0
  181. package/dist/dispatch/validateInput.js +20 -0
  182. package/dist/dispatch/validateInput.js.map +1 -0
  183. package/dist/effective-operation.d.ts +1 -24
  184. package/dist/effective-operation.d.ts.map +1 -1
  185. package/dist/effective-operation.js +21 -50
  186. package/dist/effective-operation.js.map +1 -1
  187. package/dist/emit.d.ts +4 -42
  188. package/dist/emit.d.ts.map +1 -1
  189. package/dist/emit.js +3 -39
  190. package/dist/emit.js.map +1 -1
  191. package/dist/entry/facade.d.ts +8 -0
  192. package/dist/entry/facade.d.ts.map +1 -0
  193. package/dist/entry/facade.js +28 -0
  194. package/dist/entry/facade.js.map +1 -0
  195. package/dist/entry/transport.d.ts +5 -0
  196. package/dist/entry/transport.d.ts.map +1 -0
  197. package/dist/entry/transport.js +11 -0
  198. package/dist/entry/transport.js.map +1 -0
  199. package/dist/frond-config.d.ts +7 -70
  200. package/dist/frond-config.d.ts.map +1 -1
  201. package/dist/frond-config.js +1 -9
  202. package/dist/frond-config.js.map +1 -1
  203. package/dist/identity-keys.d.ts +2 -5
  204. package/dist/identity-keys.d.ts.map +1 -1
  205. package/dist/identity-keys.js +3 -16
  206. package/dist/identity-keys.js.map +1 -1
  207. package/dist/identity.d.ts +4 -30
  208. package/dist/identity.d.ts.map +1 -1
  209. package/dist/identity.js +11 -73
  210. package/dist/identity.js.map +1 -1
  211. package/dist/imports.d.ts +1 -7
  212. package/dist/imports.d.ts.map +1 -1
  213. package/dist/imports.js +1 -7
  214. package/dist/imports.js.map +1 -1
  215. package/dist/index.d.ts +17 -24
  216. package/dist/index.d.ts.map +1 -1
  217. package/dist/index.js +10 -18
  218. package/dist/index.js.map +1 -1
  219. package/dist/loader.d.ts +1 -8
  220. package/dist/loader.d.ts.map +1 -1
  221. package/dist/loader.js +1 -8
  222. package/dist/loader.js.map +1 -1
  223. package/dist/node.d.ts +2 -11
  224. package/dist/node.d.ts.map +1 -1
  225. package/dist/node.js +2 -11
  226. package/dist/node.js.map +1 -1
  227. package/dist/prefab/collector.d.ts +1 -22
  228. package/dist/prefab/collector.d.ts.map +1 -1
  229. package/dist/prefab/collector.js +1 -22
  230. package/dist/prefab/collector.js.map +1 -1
  231. package/dist/prefab/crud.d.ts +16 -32
  232. package/dist/prefab/crud.d.ts.map +1 -1
  233. package/dist/prefab/crud.js +31 -58
  234. package/dist/prefab/crud.js.map +1 -1
  235. package/dist/prefab/mirror.d.ts +2 -24
  236. package/dist/prefab/mirror.d.ts.map +1 -1
  237. package/dist/prefab/mirror.js +2 -20
  238. package/dist/prefab/mirror.js.map +1 -1
  239. package/dist/prefab/prefab.d.ts +1 -7
  240. package/dist/prefab/prefab.d.ts.map +1 -1
  241. package/dist/prefab/prefab.js +1 -7
  242. package/dist/prefab/prefab.js.map +1 -1
  243. package/dist/prefab/presenter.d.ts +2 -36
  244. package/dist/prefab/presenter.d.ts.map +1 -1
  245. package/dist/prefab/presenter.js +2 -36
  246. package/dist/prefab/presenter.js.map +1 -1
  247. package/dist/prefab/repository.d.ts +5 -73
  248. package/dist/prefab/repository.d.ts.map +1 -1
  249. package/dist/prefab/repository.js +3 -16
  250. package/dist/prefab/repository.js.map +1 -1
  251. package/dist/scan/adapters.d.ts +3 -0
  252. package/dist/scan/adapters.d.ts.map +1 -0
  253. package/dist/scan/adapters.js +25 -0
  254. package/dist/scan/adapters.js.map +1 -0
  255. package/dist/scan/bundling.d.ts +1 -12
  256. package/dist/scan/bundling.d.ts.map +1 -1
  257. package/dist/scan/bundling.js +1 -12
  258. package/dist/scan/bundling.js.map +1 -1
  259. package/dist/scan/contract.d.ts +27 -0
  260. package/dist/scan/contract.d.ts.map +1 -0
  261. package/dist/scan/contract.js +46 -0
  262. package/dist/scan/contract.js.map +1 -0
  263. package/dist/scan/conventions.d.ts +6 -40
  264. package/dist/scan/conventions.d.ts.map +1 -1
  265. package/dist/scan/conventions.js +5 -34
  266. package/dist/scan/conventions.js.map +1 -1
  267. package/dist/scan/emit.d.ts +1 -5
  268. package/dist/scan/emit.d.ts.map +1 -1
  269. package/dist/scan/emit.js +10 -78
  270. package/dist/scan/emit.js.map +1 -1
  271. package/dist/scan/handler-parser.d.ts +4 -26
  272. package/dist/scan/handler-parser.d.ts.map +1 -1
  273. package/dist/scan/handler-parser.js +26 -83
  274. package/dist/scan/handler-parser.js.map +1 -1
  275. package/dist/scan/result.d.ts +3 -16
  276. package/dist/scan/result.d.ts.map +1 -1
  277. package/dist/scan/scanner.d.ts +2 -27
  278. package/dist/scan/scanner.d.ts.map +1 -1
  279. package/dist/scan/scanner.js +45 -133
  280. package/dist/scan/scanner.js.map +1 -1
  281. package/dist/scan/statement.d.ts.map +1 -1
  282. package/dist/scan/statement.js +60 -37
  283. package/dist/scan/statement.js.map +1 -1
  284. package/dist/source.d.ts +53 -0
  285. package/dist/source.d.ts.map +1 -0
  286. package/dist/source.js +18 -0
  287. package/dist/source.js.map +1 -0
  288. package/dist/storage.d.ts +13 -210
  289. package/dist/storage.d.ts.map +1 -1
  290. package/dist/storage.js +4 -68
  291. package/dist/storage.js.map +1 -1
  292. package/dist/store.d.ts +18 -0
  293. package/dist/store.d.ts.map +1 -0
  294. package/dist/store.js +179 -0
  295. package/dist/store.js.map +1 -0
  296. package/dist/verify.d.ts +5 -38
  297. package/dist/verify.d.ts.map +1 -1
  298. package/dist/verify.js +17 -37
  299. package/dist/verify.js.map +1 -1
  300. package/dist/wire/CallLog.d.ts +32 -0
  301. package/dist/wire/CallLog.d.ts.map +1 -0
  302. package/dist/{contract → wire}/CallLog.js.map +1 -1
  303. package/dist/wire/Invocation.d.ts +32 -0
  304. package/dist/wire/Invocation.d.ts.map +1 -0
  305. package/dist/wire/Invocation.js +66 -0
  306. package/dist/wire/Invocation.js.map +1 -0
  307. package/dist/{contract → wire}/RouteAddress.d.ts +5 -0
  308. package/dist/wire/RouteAddress.d.ts.map +1 -0
  309. package/dist/{contract → wire}/RouteAddress.js +7 -0
  310. package/dist/wire/RouteAddress.js.map +1 -0
  311. package/dist/wire/binding.d.ts +5 -21
  312. package/dist/wire/binding.d.ts.map +1 -1
  313. package/dist/wire/binding.js +5 -10
  314. package/dist/wire/binding.js.map +1 -1
  315. package/dist/wire/call.d.ts +24 -133
  316. package/dist/wire/call.d.ts.map +1 -1
  317. package/dist/wire/call.js +15 -41
  318. package/dist/wire/call.js.map +1 -1
  319. package/dist/wire/drift.d.ts +3 -28
  320. package/dist/wire/drift.d.ts.map +1 -1
  321. package/dist/wire/drift.js +4 -23
  322. package/dist/wire/drift.js.map +1 -1
  323. package/dist/wire/errors.d.ts +4 -24
  324. package/dist/wire/errors.d.ts.map +1 -1
  325. package/dist/wire/errors.js +4 -24
  326. package/dist/wire/errors.js.map +1 -1
  327. package/dist/wire/http-error.d.ts +2 -13
  328. package/dist/wire/http-error.d.ts.map +1 -1
  329. package/dist/wire/http-error.js +5 -19
  330. package/dist/wire/http-error.js.map +1 -1
  331. package/dist/wire/loggerMiddleware.d.ts +2 -8
  332. package/dist/wire/loggerMiddleware.d.ts.map +1 -1
  333. package/dist/wire/loggerMiddleware.js +1 -7
  334. package/dist/wire/loggerMiddleware.js.map +1 -1
  335. package/dist/wire/middleware.d.ts +3 -7
  336. package/dist/wire/middleware.d.ts.map +1 -1
  337. package/dist/wire/middleware.js +1 -5
  338. package/dist/wire/middleware.js.map +1 -1
  339. package/dist/wire/operation.d.ts +7 -43
  340. package/dist/wire/operation.d.ts.map +1 -1
  341. package/dist/wire/operation.js +4 -15
  342. package/dist/wire/operation.js.map +1 -1
  343. package/dist/wire/signature.d.ts +4 -25
  344. package/dist/wire/signature.d.ts.map +1 -1
  345. package/package.json +3 -3
  346. package/src/boot/AppLifecycle.ts +15 -2
  347. package/src/boot/Emissions.ts +21 -118
  348. package/src/boot/ambient-port.ts +3 -24
  349. package/src/boot/ambient.als.ts +7 -12
  350. package/src/boot/ambient.queue.ts +2 -5
  351. package/src/boot/apply.ts +9 -16
  352. package/src/boot/auth.ts +2 -12
  353. package/src/boot/boot.ts +6 -21
  354. package/src/boot/bootstrap.ts +95 -140
  355. package/src/boot/card.ts +4 -33
  356. package/src/boot/frame.ts +24 -64
  357. package/src/boot/hosted.ts +12 -34
  358. package/src/boot/ownership.ts +5 -39
  359. package/src/boot/ports.ts +1 -14
  360. package/src/boot/remote.ts +11 -58
  361. package/src/boot/runner.ts +5 -22
  362. package/src/boot/seed.ts +6 -37
  363. package/src/boot/statement-drift.ts +5 -24
  364. package/src/boot/together.ts +18 -51
  365. package/src/boot/types.ts +31 -173
  366. package/src/{builtins → builtin}/config.ts +1 -7
  367. package/src/{builtins → builtin}/logger.ts +6 -39
  368. package/src/config-loader.ts +12 -71
  369. package/src/contract.ts +19 -39
  370. package/src/criterion.ts +54 -0
  371. package/src/crypto/encoding.ts +2 -15
  372. package/src/crypto/node.ts +1 -7
  373. package/src/crypto/port.ts +2 -18
  374. package/src/crypto/webcrypto.ts +1 -12
  375. package/src/declare.ts +42 -41
  376. package/src/define.ts +2 -3
  377. package/src/descriptor/Fronds.ts +6 -31
  378. package/src/descriptor/frond.ts +26 -60
  379. package/src/dispatch/ArgumentResolver.ts +6 -6
  380. package/src/dispatch/DispatchEvent.ts +2 -2
  381. package/src/dispatch/DispatchLifecycle.ts +1 -7
  382. package/src/dispatch/DispatchPort.ts +1 -1
  383. package/src/dispatch/Dispatcher.ts +3 -3
  384. package/src/dispatch/HandlerFacade.ts +231 -0
  385. package/src/dispatch/LocalRoutePolicy.ts +4 -4
  386. package/src/dispatch/OperationRoute.ts +2 -2
  387. package/src/dispatch/OutputView.ts +24 -2
  388. package/src/dispatch/Route.ts +2 -2
  389. package/src/dispatch/RoutePolicy.ts +1 -1
  390. package/src/dispatch/RouteRegistry.ts +2 -2
  391. package/src/dispatch/RouteResolver.ts +2 -4
  392. package/src/dispatch/StorageGuard.ts +175 -19
  393. package/src/dispatch/presenterArguments.ts +25 -0
  394. package/src/dispatch/{RemoteRouteResolver.ts → remoteRoutes.ts} +7 -9
  395. package/src/dispatch/routeNotFound.ts +33 -0
  396. package/src/dispatch/validateInput.ts +28 -0
  397. package/src/effective-operation.ts +21 -50
  398. package/src/emit.ts +5 -63
  399. package/src/entry/facade.ts +44 -0
  400. package/src/entry/transport.ts +16 -0
  401. package/src/frond-config.ts +7 -70
  402. package/src/identity-keys.ts +3 -16
  403. package/src/identity.ts +12 -80
  404. package/src/imports.ts +2 -31
  405. package/src/index.ts +17 -24
  406. package/src/loader.ts +2 -16
  407. package/src/node.ts +2 -11
  408. package/src/prefab/collector.ts +1 -22
  409. package/src/prefab/crud.ts +37 -76
  410. package/src/prefab/mirror.ts +4 -44
  411. package/src/prefab/prefab.ts +2 -21
  412. package/src/prefab/presenter.ts +2 -36
  413. package/src/prefab/repository.ts +7 -83
  414. package/src/scan/adapters.ts +32 -0
  415. package/src/scan/bundling.ts +1 -12
  416. package/src/scan/contract.ts +80 -0
  417. package/src/scan/conventions.ts +6 -40
  418. package/src/scan/emit.ts +11 -80
  419. package/src/scan/handler-parser.ts +27 -96
  420. package/src/scan/result.ts +3 -16
  421. package/src/scan/scanner.ts +46 -132
  422. package/src/scan/statement.ts +73 -41
  423. package/src/source.ts +63 -0
  424. package/src/storage.ts +14 -234
  425. package/src/store.ts +191 -0
  426. package/src/verify.ts +16 -57
  427. package/src/wire/CallLog.ts +30 -0
  428. package/src/{contract → wire}/Invocation.ts +24 -17
  429. package/src/{contract → wire}/RouteAddress.ts +7 -0
  430. package/src/wire/binding.ts +9 -25
  431. package/src/wire/call.ts +30 -133
  432. package/src/wire/drift.ts +5 -30
  433. package/src/wire/errors.ts +4 -24
  434. package/src/wire/http-error.ts +5 -19
  435. package/src/wire/loggerMiddleware.ts +2 -8
  436. package/src/wire/middleware.ts +3 -7
  437. package/src/wire/operation.ts +8 -48
  438. package/src/wire/signature.ts +4 -25
  439. package/dist/boot/HandlerFacade.d.ts.map +0 -1
  440. package/dist/boot/HandlerFacade.js.map +0 -1
  441. package/dist/builtins/config.d.ts +0 -13
  442. package/dist/builtins/config.d.ts.map +0 -1
  443. package/dist/builtins/config.js +0 -21
  444. package/dist/builtins/config.js.map +0 -1
  445. package/dist/builtins/logger.d.ts.map +0 -1
  446. package/dist/builtins/logger.js.map +0 -1
  447. package/dist/contract/Call.d.ts +0 -10
  448. package/dist/contract/Call.d.ts.map +0 -1
  449. package/dist/contract/Call.js +0 -15
  450. package/dist/contract/Call.js.map +0 -1
  451. package/dist/contract/CallLog.d.ts +0 -57
  452. package/dist/contract/CallLog.d.ts.map +0 -1
  453. package/dist/contract/Invocation.d.ts +0 -27
  454. package/dist/contract/Invocation.d.ts.map +0 -1
  455. package/dist/contract/Invocation.js +0 -59
  456. package/dist/contract/Invocation.js.map +0 -1
  457. package/dist/contract/RouteAddress.d.ts.map +0 -1
  458. package/dist/contract/RouteAddress.js.map +0 -1
  459. package/dist/dispatch/InputValidator.d.ts +0 -7
  460. package/dist/dispatch/InputValidator.d.ts.map +0 -1
  461. package/dist/dispatch/InputValidator.js +0 -22
  462. package/dist/dispatch/InputValidator.js.map +0 -1
  463. package/dist/dispatch/OperationExecutor.d.ts +0 -25
  464. package/dist/dispatch/OperationExecutor.d.ts.map +0 -1
  465. package/dist/dispatch/OperationExecutor.js +0 -32
  466. package/dist/dispatch/OperationExecutor.js.map +0 -1
  467. package/dist/dispatch/OutputProjector.d.ts +0 -12
  468. package/dist/dispatch/OutputProjector.d.ts.map +0 -1
  469. package/dist/dispatch/OutputProjector.js +0 -30
  470. package/dist/dispatch/OutputProjector.js.map +0 -1
  471. package/dist/dispatch/PresenterArgumentResolver.d.ts +0 -12
  472. package/dist/dispatch/PresenterArgumentResolver.d.ts.map +0 -1
  473. package/dist/dispatch/PresenterArgumentResolver.js +0 -20
  474. package/dist/dispatch/PresenterArgumentResolver.js.map +0 -1
  475. package/dist/dispatch/RemoteRouteResolver.d.ts +0 -13
  476. package/dist/dispatch/RemoteRouteResolver.d.ts.map +0 -1
  477. package/dist/dispatch/RemoteRouteResolver.js.map +0 -1
  478. package/dist/dispatch/RouteNotFoundError.d.ts +0 -10
  479. package/dist/dispatch/RouteNotFoundError.d.ts.map +0 -1
  480. package/dist/dispatch/RouteNotFoundError.js +0 -24
  481. package/dist/dispatch/RouteNotFoundError.js.map +0 -1
  482. package/dist/entry/DynamicFacade.d.ts +0 -10
  483. package/dist/entry/DynamicFacade.d.ts.map +0 -1
  484. package/dist/entry/DynamicFacade.js +0 -27
  485. package/dist/entry/DynamicFacade.js.map +0 -1
  486. package/dist/entry/FacadeEntry.d.ts +0 -11
  487. package/dist/entry/FacadeEntry.d.ts.map +0 -1
  488. package/dist/entry/FacadeEntry.js +0 -26
  489. package/dist/entry/FacadeEntry.js.map +0 -1
  490. package/dist/entry/TransportEntry.d.ts +0 -13
  491. package/dist/entry/TransportEntry.d.ts.map +0 -1
  492. package/dist/entry/TransportEntry.js +0 -24
  493. package/dist/entry/TransportEntry.js.map +0 -1
  494. package/dist/rows.d.ts +0 -40
  495. package/dist/rows.d.ts.map +0 -1
  496. package/dist/rows.js +0 -146
  497. package/dist/rows.js.map +0 -1
  498. package/src/boot/HandlerFacade.ts +0 -242
  499. package/src/contract/Call.ts +0 -18
  500. package/src/contract/CallLog.ts +0 -55
  501. package/src/dispatch/InputValidator.ts +0 -28
  502. package/src/dispatch/OperationExecutor.ts +0 -60
  503. package/src/dispatch/OutputProjector.ts +0 -32
  504. package/src/dispatch/PresenterArgumentResolver.ts +0 -25
  505. package/src/dispatch/RouteNotFoundError.ts +0 -29
  506. package/src/entry/DynamicFacade.ts +0 -28
  507. package/src/entry/FacadeEntry.ts +0 -32
  508. package/src/entry/TransportEntry.ts +0 -30
  509. package/src/rows.ts +0 -155
  510. /package/dist/{contract → wire}/CallLog.js +0 -0
@@ -1,9 +1,4 @@
1
- /**
2
- * Handler signature parser — extracts method signatures from handler source files.
3
- *
4
- * The AST says what the author declared; TypeScript's checker says what those types mean.
5
- * TypeScript is lazy-loaded to avoid bundling the compiler in production builds.
6
- */
1
+ /** Handler signature parser — extracts method signatures from handler source files. */
7
2
  import type { TypeRef, Param, Signature } from '../wire/signature.js';
8
3
  import type ts from '@typescript/typescript6';
9
4
  import { readFileSync, existsSync, statSync } from 'node:fs';
@@ -26,26 +21,11 @@ interface TypeProject {
26
21
  program: ts.Program;
27
22
  }
28
23
 
29
- /**
30
- * One checked program per project/configuration during a scan.
31
- *
32
- * A checker is a project reader, not a file parser: creating one per handler would reopen
33
- * the standard library and every imported declaration for each method. `scanProject`
34
- * resets this map at the start of a run, so an edited source can never meet a program from
35
- * the previous run.
36
- */
24
+ /** One checked program per project/configuration during a scan. */
37
25
  const typeProjects = new Map<string, TypeProject>();
38
26
  const compilerProjects = new Map<string, { key: string; roots: string[]; options: ts.CompilerOptions }>();
39
27
 
40
- /**
41
- * What survives a run: the parsed declarations, and the program built over them.
42
- *
43
- * Rebuilding a program re-reads `lib.d.ts` and every imported `.d.ts`, and that is FIXED
44
- * work — measured, a second scan in one process cost the same at 16 frond files as at 406.
45
- * The mtime is the guard, so a run still cannot see a stale type: a file that moved is
46
- * re-read and TypeScript invalidates it and everything depending on it, which is a
47
- * narrower rule than discarding the program and not a weaker one.
48
- */
28
+ /** What survives a run. */
49
29
  const sourceFiles = new Map<string, { mtime: number; file: ts.SourceFile }>();
50
30
  const retained = new Map<string, { host: ts.CompilerHost; program: ts.Program }>();
51
31
 
@@ -61,8 +41,8 @@ export function forgetParsedSources(): void {
61
41
  }
62
42
 
63
43
  function keptHost(key: string, options: ts.CompilerOptions): ts.CompilerHost {
64
- const held = retained.get(key);
65
- if (held) return held.host;
44
+ const cached = retained.get(key);
45
+ if (cached) return cached.host;
66
46
  const typescript = getTS();
67
47
  const base = typescript.createCompilerHost(options);
68
48
  const host: ts.CompilerHost = {
@@ -138,13 +118,7 @@ function compilerProjectOf(filePath: string, projectRoot?: string): { key: strin
138
118
  return configured;
139
119
  }
140
120
 
141
- /**
142
- * Declare every file a run will read, so one program covers it.
143
- *
144
- * `checkedSourceOf` rebuilds whenever it meets a root it has not seen, and a frond lives
145
- * outside its project's tsconfig `include`, so every declaration was a new root: 44 files
146
- * cost 7.3 s that way against 0.34 s for one program.
147
- */
121
+ /** Declare every file a run will read, so one program covers it. */
148
122
  export async function seedTypeProgram(filePaths: readonly string[], projectRoot?: string): Promise<void> {
149
123
  const typescript = await loadTS();
150
124
  const grouped = new Map<string, { options: ts.CompilerOptions; paths: string[] }>();
@@ -152,9 +126,9 @@ export async function seedTypeProgram(filePaths: readonly string[], projectRoot?
152
126
  for (const filePath of filePaths) {
153
127
  const absolute = resolvePath(filePath);
154
128
  const configured = compilerProjectOf(absolute, projectRoot);
155
- const held = grouped.get(configured.key) ?? { options: configured.options, paths: [] };
156
- held.paths.push(absolute);
157
- grouped.set(configured.key, held);
129
+ const group = grouped.get(configured.key) ?? { options: configured.options, paths: [] };
130
+ group.paths.push(absolute);
131
+ grouped.set(configured.key, group);
158
132
  }
159
133
 
160
134
  for (const [key, { options, paths }] of grouped) {
@@ -168,25 +142,25 @@ function checkedSourceOf(filePath: string, projectRoot?: string): { source: ts.S
168
142
  const typescript = getTS();
169
143
  const absolute = resolvePath(filePath);
170
144
  const configured = compilerProjectOf(absolute, projectRoot);
171
- let held = typeProjects.get(configured.key);
145
+ let project = typeProjects.get(configured.key);
172
146
 
173
- if (!held) {
147
+ if (!project) {
174
148
  // `path.resolve` is variadic, so handing it directly to `map` also passed the
175
149
  // index and the whole roots array as path segments. A fixture without a warm scan
176
150
  // cache exposed that first-run-only failure.
177
151
  const roots = new Set(configured.roots.map((root) => resolvePath(root)));
178
152
  roots.add(absolute);
179
153
  const program = builtProgram(configured.key, [...roots], configured.options);
180
- held = { roots, options: configured.options, program };
181
- typeProjects.set(configured.key, held);
182
- } else if (!held.roots.has(absolute)) {
183
- held.roots.add(absolute);
184
- held.program = builtProgram(configured.key, [...held.roots], held.options);
154
+ project = { roots, options: configured.options, program };
155
+ typeProjects.set(configured.key, project);
156
+ } else if (!project.roots.has(absolute)) {
157
+ project.roots.add(absolute);
158
+ project.program = builtProgram(configured.key, [...project.roots], project.options);
185
159
  }
186
160
 
187
- const source = held.program.getSourceFile(absolute);
161
+ const source = project.program.getSourceFile(absolute);
188
162
  if (!source) throw new Error(`TypeScript did not include '${absolute}' in its program.`);
189
- return { source, checker: held.program.getTypeChecker() };
163
+ return { source, checker: project.program.getTypeChecker() };
190
164
  }
191
165
 
192
166
  /** A file, opened. Five places read and parsed one, each spelling the same two calls. */
@@ -428,20 +402,7 @@ function resolveSpecifier(specifier: string, fromFile: string, projectRoot: stri
428
402
 
429
403
  // ── Mixin / heritage parsing ─────────────────
430
404
 
431
- /**
432
- * The class a returned expression carries, however it is wrapped.
433
- *
434
- * A mixin does not always hand its class back bare. `Crud` returns
435
- * `asCrudConstructor(class CrudHandler { … })` — one assertion helper standing between
436
- * `return` and the class — and a parser accepting only a bare `return class` found
437
- * nothing there, silently: the five inherited CRUD ops stopped being derived, and a warm
438
- * scan cache kept answering the old parse for weeks (`scan-cache.ts` keys on source, not
439
- * on parser version).
440
- *
441
- * So unwrap rather than match one shape: descend through call arguments, `as` and
442
- * `satisfies` assertions, and parentheses. What is looked for is a class; where the
443
- * author put it is their business.
444
- */
405
+ /** The class a returned expression carries, however it is wrapped. */
445
406
  function classInExpression(expr: ts.Node, depth = 0): ts.ClassExpression | undefined {
446
407
  const ts = getTS();
447
408
  if (depth > 8) return undefined;
@@ -502,7 +463,7 @@ function extractClassMethods(
502
463
  // `private`/`protected` is a statement about the surface, and the AST carries it —
503
464
  // it was read past. Every helper a handler names by intent (`mustOwn`, `readMany`,
504
465
  // `refuse`) became a callable op: measured on the bench, `list.readMany` executed
505
- // and `list.mayPublish` judged its argument. A door is what the author declares
466
+ // and `list.mayPublish` validated its argument. A door is what the author declares
506
467
  // public, and TypeScript already has the word for it. `#name` is private too, but
507
468
  // it is not an identifier, so it never reached here in the first place.
508
469
  if (member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword)) continue;
@@ -521,14 +482,7 @@ function extractClassMethods(
521
482
  return results;
522
483
  }
523
484
 
524
- /**
525
- * The first sentence of a member's doc comment, or nothing.
526
- *
527
- * One sentence on purpose: what a caller needs to choose an operation is a claim,
528
- * not an essay, and the rest of the comment addresses whoever edits the method.
529
- * Reads the leading trivia rather than `ts.getJSDocTags` — the comment is what the
530
- * author wrote, tags are a schema they never agreed to.
531
- */
485
+ /** The first sentence of a member's doc comment, or nothing. */
532
486
  function docSentenceOf(member: ts.Node, source: ts.SourceFile): string | undefined {
533
487
  const ts = getTS();
534
488
  const ranges = ts.getLeadingCommentRanges(source.text, member.pos) ?? [];
@@ -551,11 +505,7 @@ function docSentenceOf(member: ts.Node, source: ts.SourceFile): string | undefin
551
505
  * Parse inherited methods from a class's heritage clause.
552
506
  * Handles both `extends Crud(Entity)` (mixin) and `extends BaseClass` patterns.
553
507
  */
554
- /**
555
- * Where a name used here is declared. The checker follows the import, the re-export chain
556
- * and an installed package's types — the three cases three hand-rolled functions treated
557
- * separately.
558
- */
508
+ /** Where a name used here is declared. */
559
509
  function declarationFileOf(node: ts.Node, checker: ts.TypeChecker): string | undefined {
560
510
  const typescript = getTS();
561
511
  let symbol = checker.getSymbolAtLocation(node);
@@ -564,13 +514,7 @@ function declarationFileOf(node: ts.Node, checker: ts.TypeChecker): string | und
564
514
  return symbol.declarations?.[0]?.getSourceFile().fileName;
565
515
  }
566
516
 
567
- /**
568
- * The methods a base class contributes, read from the INSTANTIATED type.
569
- *
570
- * `extends Crud(Post)` gives `create(input: Partial<Post>)` directly: the checker has
571
- * already substituted the mixin's type parameter. The three functions this replaces
572
- * detected the generic names and mapped them to the mixin's arguments by position.
573
- */
517
+ /** The methods a base class contributes, read from the INSTANTIATED type. */
574
518
  function inheritedFromBase(
575
519
  base: ts.ExpressionWithTypeArguments,
576
520
  checker: ts.TypeChecker,
@@ -617,10 +561,8 @@ function parseInheritedMethods(
617
561
  checker: ts.TypeChecker,
618
562
  skip: Set<string>,
619
563
  /**
620
- * Base classes this pass could not open — an INSTALLED one, typically, whose
621
- * source is not in the workspace. Reported rather than treated as "no inherited
622
- * method": the two used to be the same answer, so an op inherited from a
623
- * published base class was absent from the façade without a word.
564
+ * Base classes this pass could not open — an INSTALLED one, typically, whose source is not in
565
+ * the workspace.
624
566
  */
625
567
  unresolved: string[],
626
568
  ): Signature[] {
@@ -685,14 +627,7 @@ function findDefaultClass(source: ts.SourceFile): ts.ClassDeclaration | undefine
685
627
  return undefined;
686
628
  }
687
629
 
688
- /**
689
- * What a handler file yielded — its methods, AND what the pass could not open.
690
- *
691
- * The second half is why this is a pair rather than an array: an unresolvable base
692
- * class used to give the same answer as a base class with no method, so an op
693
- * inherited from an installed package was missing from the façade in silence. The
694
- * pair travels through the scan cache, which is why {@link PARSER_VERSION} moved.
695
- */
630
+ /** What a handler file yielded — its methods, AND what the pass could not open. */
696
631
  export interface HandlerParse {
697
632
  methods: Signature[];
698
633
  /** Base classes whose source this pass could not open. Empty is a claim. */
@@ -708,11 +643,7 @@ export async function parseAllHandlerMethods(filePath: string, projectRoot?: str
708
643
  return parseClassMethods(filePath, CONSTRUCTOR_ONLY, projectRoot);
709
644
  }
710
645
 
711
- /**
712
- * Parse a presenter source file and extract all method signatures.
713
- *
714
- * Returns all methods (no CRUD filtering) — each method is a computed field.
715
- */
646
+ /** Parse a presenter source file and extract all method signatures. */
716
647
  export async function parsePresenterMethods(filePath: string, projectRoot?: string): Promise<Signature[]> {
717
648
  await loadTS();
718
649
  // No `projectRoot`, so no heritage pass and nothing to report: a presenter's
@@ -1,24 +1,11 @@
1
1
  import type { Fronds } from '../descriptor/Fronds.js';
2
2
 
3
3
  /** Result of scanning a project directory. */
4
- /**
5
- * Something the scan could NOT do — recorded instead of swallowed.
6
- *
7
- * The scan answers with what it found. Until now it answered the same way whether
8
- * a directory held nothing or could not be read, and whether a handler declared no
9
- * operation or failed to parse: `catch → empty`. So every downstream reader — the
10
- * façade, the identity card, anything asking "what does this app serve?" — could
11
- * not tell **"there is nothing"** from **"I could not look"**.
12
- *
13
- * That distinction is what makes a rule about an ABSENCE sound. Without it, a check
14
- * derived from the scan reports "nothing wrong" precisely when it read nothing.
15
- */
4
+ /** Something the scan could NOT do — recorded instead of swallowed. */
16
5
  export interface ScanDiagnostic {
17
6
  /**
18
- * `blocking` — the app now serves less than its source declares, and no caller
19
- * can know it: a handler that failed to parse contributes zero operations.
20
- * `warning` — something may be missing and the scan cannot decide, e.g. a base
21
- * class it is not allowed to resolve. Statable in `frond.config.ts`.
7
+ * `blocking` — the app now serves less than its source declares, and no caller can know it: a
8
+ * handler that failed to parse contributes zero operations.
22
9
  */
23
10
  severity: 'blocking' | 'warning';
24
11
  /** Stable rule name — `handler-parse-failed`, `directory-unreadable`. */
@@ -31,13 +31,7 @@ import {
31
31
 
32
32
  // FS
33
33
 
34
- /**
35
- * What this scan run could not do. Reset by {@link scanProject}, which owns a run.
36
- *
37
- * Module-scoped like the loader and the cache root above: the scanner already has a
38
- * notion of "the current run". Three sites record — measured — so a per-run object
39
- * would carry twenty methods to spare one line of reset.
40
- */
34
+ /** What this scan run could not do. */
41
35
  let diagnostics: ScanDiagnostic[] = [];
42
36
 
43
37
  function record(d: ScanDiagnostic): void {
@@ -45,10 +39,8 @@ function record(d: ScanDiagnostic): void {
45
39
  }
46
40
 
47
41
  /**
48
- * An absent convention directory is the ordinary case — a frond without
49
- * `presenters/` is not a defect. Anything else (permissions, an I/O error, a path
50
- * that is not a directory) means the scan did not look, and answering `[]` says
51
- * it did. One `catch` used to conflate the two.
42
+ * An absent convention directory is the ordinary case — a frond without `presenters/` is not a
43
+ * defect.
52
44
  */
53
45
  async function readEntries(path: string): Promise<Dirent[]> {
54
46
  try {
@@ -94,8 +86,18 @@ async function loadDefault(filePath: string): Promise<unknown> {
94
86
 
95
87
  async function loadClass(filePath: string): Promise<ProviderEntry['ctor']> {
96
88
  const ctor = await loadDefault(filePath);
97
- if (typeof ctor !== 'function' || !ctor.prototype)
98
- throw new Error(`${filePath}: default export is not a class`);
89
+ // A convention directory holds classes, because a provider is registered under one and
90
+ // asked for by its type. What is NOT a class — a shared contract, a pure function, a
91
+ // table of constants — belongs beside them rather than among them, and saying where
92
+ // costs one line: measured twice on a real project, both times a file that had to move.
93
+ if (typeof ctor !== 'function' || !ctor.prototype) {
94
+ throw new Error(
95
+ `${filePath}: default export is not a class. This directory is scanned for providers, `
96
+ + 'which are registered under a class name — a contract or a pure function has no key '
97
+ + `to answer under. Move it beside the directory, at the frond's root, where the scan `
98
+ + 'reads nothing and an import still reaches it.',
99
+ );
100
+ }
99
101
  return ctor as ProviderEntry['ctor'];
100
102
  }
101
103
 
@@ -115,13 +117,7 @@ function findWorkspaceRoot(from: string): string {
115
117
  return resolvePath(from); // fallback: use project root itself
116
118
  }
117
119
 
118
- /**
119
- * Strip the 'Handler' suffix → the name the handler answers to. 'PostHandler' → 'post'.
120
- *
121
- * Nothing here checks that an entity carries the result, and nothing should: a handler
122
- * about no stored row is ordinary. The old name of this function — `toEntityName` — is
123
- * what let "one façade per entity" be repeated until it read as a rule.
124
- */
120
+ /** Strip the 'Handler' suffix → the name the handler answers to. */
125
121
  function toAddress(className: string): string {
126
122
  const base = className.endsWith('Handler') ? className.slice(0, -7) : className;
127
123
  return lowerFirst(base);
@@ -130,18 +126,8 @@ function toAddress(className: string): string {
130
126
  // Scan
131
127
 
132
128
  /**
133
- * The container key a constructor parameter asks for — derived from its TYPE, not from
134
- * how the type was spelled.
135
- *
136
- * `deps` used to be `p.type.name`, so the key WAS the alias's name: `type ListStorage =
137
- * Storage<List>` resolved only because someone had spelled it exactly like the
138
- * registration key (`ListStorage`), while `type ListRepo = Storage<List>` — the same type —
139
- * typechecked and died at boot on `'ListRepo' is not registered`. And `Storage<List>`
140
- * written out in full asked for `'Storage'`, which nothing registers.
141
- *
142
- * `Storage<X>` names X's storage, so that is the key. The generic argument was already
143
- * parsed (`TypeRef.generics`) and thrown away. Anything else keeps its own name: a
144
- * plain service IS designated by its class name.
129
+ * The container key a constructor parameter asks for — derived from its TYPE, not from how the
130
+ * type was spelled.
145
131
  */
146
132
  function depKeyOf(type: TypeRef): string {
147
133
  // `Facade<PostHandler>` — the second port, read exactly like the first. The type names
@@ -166,32 +152,25 @@ function depKeyOf(type: TypeRef): string {
166
152
  // `RepositoryOf<Post>` — what an author writes when no repository file exists. The dual
167
153
  // of the line below: one names the port, the other the holder, and both resolve to a key
168
154
  // rather than to a class the author would have to invent.
169
- const held = type.name === 'RepositoryOf' ? type.generics?.[0]?.name : undefined;
170
- if (held) return repositoryKeyOf(held);
155
+ const subject = type.name === 'RepositoryOf' ? type.generics?.[0]?.name : undefined;
156
+ if (subject) return repositoryKeyOf(subject);
171
157
 
172
- const target = type.name === 'Storage' ? type.generics?.[0]?.name : undefined;
158
+ // The GENERIC names the subject, so a prefix does not change the key — `MeiliStorage<Card>`
159
+ // is `Card`'s storage. A class named `FileStorage` is untouched: it carries no generic.
160
+ const target = type.name.endsWith('Storage') && type.generics?.length === 1
161
+ ? type.generics[0]?.name
162
+ : undefined;
173
163
  if (!target) return type.name;
174
164
 
175
165
  return storageKeyOf(target);
176
166
  }
177
167
 
178
- /**
179
- * `'[Account, Ledger]'` → `['Account', 'Ledger']`.
180
- *
181
- * The tuple was chosen over the variadic form the parser reads more cleanly, because the
182
- * variadic one costs arities-with-defaults and a `never` filter on the TypeScript side
183
- * while the tuple maps to `[Storage<Account>, Storage<Ledger>]` in one line. The
184
- * parser does not get to decide alone; this split is what that choice costs.
185
- */
168
+ /** `'[Account, Ledger]'` → `['Account', 'Ledger']`. */
186
169
  function tupleMembers(raw: string): string[] {
187
170
  return raw.replace(/^\[|\]$/g, '').split(',').map((member) => member.trim()).filter(Boolean);
188
171
  }
189
172
 
190
- /**
191
- * These readings are semantic: an unchanged file can mean something different after an
192
- * imported alias changes. The parser's TypeScript Program is the cache for one scan; a
193
- * cache keyed only by this file's bytes would be unsound.
194
- */
173
+ /** These readings are semantic. */
195
174
  const ctorParamsOf = (filePath: string) =>
196
175
  parseConstructorParams(filePath);
197
176
 
@@ -203,6 +182,9 @@ const handlerMethodsOf = (filePath: string, projectRoot?: string) =>
203
182
 
204
183
  async function toProvider(filePath: string): Promise<ProviderEntry> {
205
184
  const ctor = await loadClass(filePath);
185
+ // Read here, while the class is the one the source declared. What a bundler does to
186
+ // that name later is why it is carried rather than asked for again.
187
+ const name = ctor.name;
206
188
  const params = await ctorParamsOf(filePath);
207
189
  const deps = params.map((p) => depKeyOf(p.type));
208
190
 
@@ -222,10 +204,10 @@ async function toProvider(filePath: string): Promise<ProviderEntry> {
222
204
  deps.push(storageKeyOf(lowerFirst((target as { name: string }).name)));
223
205
  }
224
206
 
225
- // No `name` beside `ctor`: a provider registers under `ctor.name`, which is what
226
- // `depKeyOf` returns since it reads the type as written. The camelCase field that
227
- // used to sit here called itself the registration key and was one nowhere.
228
- return { ctor, deps, filePath };
207
+ // `name` beside `ctor`, and it IS the registration key what `depKeyOf` returns, since
208
+ // it reads the type as written. It used to be asked of `ctor.name` at boot, which held
209
+ // until a bundler lowered a static field and renamed the declaration doing it.
210
+ return { name, ctor, deps, filePath };
229
211
  }
230
212
 
231
213
  async function toEntityEntry(filePath: string): Promise<EntityEntry | null> {
@@ -272,12 +254,7 @@ function resolveSchema(type: TypeRef, moduleExports: Record<string, unknown>): S
272
254
  return undefined;
273
255
  }
274
256
 
275
- /**
276
- * Parse ALL method signatures for unified binding.
277
- *
278
- * Resolves schemas for all params (not just the first) and stores
279
- * full signatures for the binding algorithm.
280
- */
257
+ /** Parse ALL method signatures for unified binding. */
281
258
  async function inferOperations(
282
259
  filePath: string,
283
260
  handlerName: string,
@@ -308,15 +285,8 @@ async function inferOperations(
308
285
  }
309
286
 
310
287
  /**
311
- * A base class the parse could not open — an installed package, typically, whose
312
- * source is not in the workspace. Its operations are missing from this façade, and
313
- * the scan cannot tell whether there were any.
314
- *
315
- * A warning, not a refusal: an installed base class with no operation is perfectly
316
- * ordinary, and the boot has no way to decide between the two. So it names the
317
- * clause and stops there. Stating the contract in `frond.config.ts` is the answer
318
- * — the third producer, which creates an op neither other producer found — and it
319
- * silences this by making the op exist.
288
+ * A base class the parse could not open — an installed package, typically, whose source is not
289
+ * in the workspace.
320
290
  */
321
291
  for (const base of parsed.unresolvedHeritage) {
322
292
  record({
@@ -342,10 +312,10 @@ async function inferOperations(
342
312
  // caller supplies through the body are candidates: a schema-typed collector, fact or
343
313
  // context parameter is not input merely because it names an entity. The old loop
344
314
  // ignored provenance and assigned the first schema it met, so swapping two parameters
345
- // silently changed the contract the façade used to judge the request body.
315
+ // silently changed the contract the façade used to validate the request body.
346
316
  const binding = computeBindingPlan(method.params, collectorTypeNames);
347
317
  const candidates = method.params.flatMap((param, index) => {
348
- if (binding[index]?.source.kind !== 'body') return [];
318
+ if (binding[index]?.source.kind !== 'input') return [];
349
319
  const schema = resolveSchema(param.type, moduleExports);
350
320
  return schema ? [{ param, schema }] : [];
351
321
  });
@@ -522,13 +492,7 @@ async function scanFrond(frondPath: string, name: string, source: FrondDescripto
522
492
  entities: entitiesDir, handlers: handlersDir,
523
493
  presenters: presentersDir, collectors: collectorsDir, seeds: seedsDir,
524
494
  } = conventions.dirs;
525
- /**
526
- * A convention directory, read by whoever knows the shape it holds.
527
- *
528
- * The same three lines were written six times — list, read in parallel, drop what the
529
- * reader refused — which is what made `handlers/` quietly special: it grew a second
530
- * pass for its surfaces and nothing else could.
531
- */
495
+ /** A convention directory, read by whoever knows the shape it holds. */
532
496
  const collect = async <T extends object>(
533
497
  dir: string,
534
498
  read: (filePath: string) => Promise<T | null>,
@@ -615,15 +579,7 @@ async function scanFrond(frondPath: string, name: string, source: FrondDescripto
615
579
  };
616
580
  }
617
581
 
618
- /**
619
- * The frond's name — the directory, unless its `package.json` renames it. One rule for a
620
- * frond under `fronds/` and for the root frond alike, so the root needs no second spelling.
621
- *
622
- * Carrying the convention is what makes a frond; the key never marked anything and
623
- * nothing read it. It earns its keep as the one thing the directory cannot say: that
624
- * `fronds/blog-v2/` serves the frond still called `blog` — so a rename on disk does not
625
- * rename the entity keys, the `@fronds/*` import or a `remotes:` entry.
626
- */
582
+ /** The frond's name — the directory, unless its `package.json` renames it. */
627
583
  async function frondNameOf(frondPath: string, dirName: string): Promise<string> {
628
584
  try {
629
585
  const pkg = JSON.parse(await readFile(join(frondPath, 'package.json'), 'utf8')) as {
@@ -637,15 +593,8 @@ async function frondNameOf(frondPath: string, dirName: string): Promise<string>
637
593
  }
638
594
 
639
595
  /**
640
- * A frond is a directory carrying the convention, and the project root is one such
641
- * directory — so a single-domain app writes `entities/` next to `app/` and never names
642
- * anything. `fronds/` is not the definition, it is where the OTHERS live: the root frond
643
- * stays put when a second domain appears, which is what makes flattening free instead of
644
- * a deferred move.
645
- *
646
- * `entities/` is the test, not "any convention directory". `services/` and `repositories/`
647
- * are ordinary top-level names in projects that never heard of Fougere, and a domain
648
- * without a single entity is not a domain.
596
+ * A frond is a directory carrying the convention, and the project root is one such directory — so
597
+ * a single-domain app writes `entities/` next to `app/` and never names anything.
649
598
  */
650
599
  async function rootFrondOf(root: string, workspaceRoot: string, conventions: Conventions): Promise<FrondDescriptor | null> {
651
600
  if ((await files(join(root, conventions.dirs.entities))).length === 0) return null;
@@ -653,21 +602,7 @@ async function rootFrondOf(root: string, workspaceRoot: string, conventions: Con
653
602
  return scanFrond(root, name, { path: root, package: frondPackage(name, conventions) }, conventions, workspaceRoot);
654
603
  }
655
604
 
656
- /**
657
- * `@fronds/<name>` → the directory it names, for every frond of a project.
658
- *
659
- * The framework states this convention — `FrondSource.package` has always spelled it, and
660
- * `fougere sync` writes it into a consumer's tsconfig — and until now its own reader could
661
- * not resolve it. The Nuxt module registered a Vite alias, so a `.vue` page could import
662
- * `@fronds/blog/entities/Post`, while the SCAN loaded sources through a bare jiti: a frond
663
- * naming its neighbour got `Cannot find module '@fronds/user/entities/User.js'`. So the one
664
- * form that survives a split was the one form that did not run.
665
- *
666
- * Hand it to the module loader — `createJiti(url, { alias: await frondAliases(root) })` —
667
- * and the named form resolves everywhere the framework reads. A directory listing and a
668
- * `package.json` read, no parsing: it is deliberately callable BEFORE the loader exists,
669
- * which is what makes the chicken-and-egg go away.
670
- */
605
+ /** `@fronds/<name>` → the directory it names, for every frond of a project. */
671
606
  export async function frondAliases(root: string, conventions: Conventions = DEFAULT_CONVENTIONS): Promise<Record<string, string>> {
672
607
  const frondsDir = join(root, conventions.fronds);
673
608
  const aliases: Record<string, string> = {};
@@ -681,17 +616,7 @@ export async function frondAliases(root: string, conventions: Conventions = DEFA
681
616
  aliases[frondPackage(await frondNameOf(path, dir), conventions)] = resolvePath(path);
682
617
  }
683
618
 
684
- /**
685
- * A SYNCED frond answers to the same name.
686
- *
687
- * `fougere sync` writes `.fougere/remotes/<name>/` and registers it in `remotes.json`,
688
- * which the Nuxt module already reads to alias `@fronds/<name>`. Doing it here too is
689
- * what makes the convention mean ONE thing: a consumer writes `@fronds/blog/entities/Post`
690
- * and never learns whether that frond is on this disk or was fetched from a card.
691
- *
692
- * A local frond wins a name collision — its source is the truth, a synced copy is a
693
- * mirror of somebody else's.
694
- */
619
+ /** A SYNCED frond answers to the same name. */
695
620
  try {
696
621
  const registry = JSON.parse(
697
622
  await readFile(join(root, '.fougere', 'remotes.json'), 'utf8'),
@@ -757,18 +682,7 @@ export async function scanProject(
757
682
  return { fronds, diagnostics };
758
683
  }
759
684
 
760
- /**
761
- * What changes when a frond's domain changes — the paths a dev loop watches.
762
- *
763
- * It lives beside the scan rather than beside the conventions it reads, because it turns
764
- * names into DISK paths: `join` is `node:path`, and `conventions.ts` is reached from
765
- * `index` through `frond()`, which an edge bundle imports. Measured — esbuild refused the
766
- * Worker with `Could not resolve "node:path"`.
767
- *
768
- * The root frond IS the scan root, so watching its path would match every write in the
769
- * project: `.nuxt/`, `node_modules/`, the build output. Its convention directories are
770
- * the frond, and they are what a scan re-reads.
771
- */
685
+ /** What changes when a frond's domain changes — the paths a dev loop watches. */
772
686
  export function watchPathsOf(
773
687
  frond: { source: { path: string } },
774
688
  scanRoot: string,