@fougere/core 0.5.0-alpha.1 → 0.7.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 (519) hide show
  1. package/README.md +1 -1
  2. package/dist/boot/Emissions.d.ts +14 -91
  3. package/dist/boot/Emissions.d.ts.map +1 -1
  4. package/dist/boot/Emissions.js +21 -118
  5. package/dist/boot/Emissions.js.map +1 -1
  6. package/dist/boot/ambient-port.d.ts +3 -24
  7. package/dist/boot/ambient-port.d.ts.map +1 -1
  8. package/dist/boot/ambient.als.d.ts.map +1 -1
  9. package/dist/boot/ambient.als.js +7 -12
  10. package/dist/boot/ambient.als.js.map +1 -1
  11. package/dist/boot/ambient.queue.d.ts +2 -5
  12. package/dist/boot/ambient.queue.d.ts.map +1 -1
  13. package/dist/boot/ambient.queue.js.map +1 -1
  14. package/dist/boot/apply.d.ts +1 -13
  15. package/dist/boot/apply.d.ts.map +1 -1
  16. package/dist/boot/apply.js +3 -15
  17. package/dist/boot/apply.js.map +1 -1
  18. package/dist/boot/auth.d.ts +6 -16
  19. package/dist/boot/auth.d.ts.map +1 -1
  20. package/dist/boot/boot.d.ts +5 -18
  21. package/dist/boot/boot.d.ts.map +1 -1
  22. package/dist/boot/boot.js +4 -11
  23. package/dist/boot/boot.js.map +1 -1
  24. package/dist/boot/bootstrap.d.ts.map +1 -1
  25. package/dist/boot/bootstrap.js +106 -163
  26. package/dist/boot/bootstrap.js.map +1 -1
  27. package/dist/boot/card.d.ts +5 -0
  28. package/dist/boot/card.d.ts.map +1 -0
  29. package/dist/boot/card.js +71 -0
  30. package/dist/boot/card.js.map +1 -0
  31. package/dist/boot/frame.d.ts +8 -32
  32. package/dist/boot/frame.d.ts.map +1 -1
  33. package/dist/boot/frame.js +23 -57
  34. package/dist/boot/frame.js.map +1 -1
  35. package/dist/boot/hosted.d.ts +3 -19
  36. package/dist/boot/hosted.d.ts.map +1 -1
  37. package/dist/boot/hosted.js +12 -17
  38. package/dist/boot/hosted.js.map +1 -1
  39. package/dist/boot/ownership.d.ts +5 -36
  40. package/dist/boot/ownership.d.ts.map +1 -1
  41. package/dist/boot/ownership.js +9 -49
  42. package/dist/boot/ownership.js.map +1 -1
  43. package/dist/boot/ports.d.ts +2 -15
  44. package/dist/boot/ports.d.ts.map +1 -1
  45. package/dist/boot/ports.js +1 -14
  46. package/dist/boot/ports.js.map +1 -1
  47. package/dist/boot/remote.d.ts +5 -38
  48. package/dist/boot/remote.d.ts.map +1 -1
  49. package/dist/boot/remote.js +8 -41
  50. package/dist/boot/remote.js.map +1 -1
  51. package/dist/boot/runner.d.ts +11 -0
  52. package/dist/boot/runner.d.ts.map +1 -0
  53. package/dist/boot/runner.js +13 -0
  54. package/dist/boot/runner.js.map +1 -0
  55. package/dist/boot/seed.d.ts +5 -32
  56. package/dist/boot/seed.d.ts.map +1 -1
  57. package/dist/boot/seed.js +10 -41
  58. package/dist/boot/seed.js.map +1 -1
  59. package/dist/boot/statement-drift.d.ts +4 -22
  60. package/dist/boot/statement-drift.d.ts.map +1 -1
  61. package/dist/boot/statement-drift.js +4 -9
  62. package/dist/boot/statement-drift.js.map +1 -1
  63. package/dist/boot/together.d.ts +8 -12
  64. package/dist/boot/together.d.ts.map +1 -1
  65. package/dist/boot/together.js +28 -65
  66. package/dist/boot/together.js.map +1 -1
  67. package/dist/boot/types.d.ts +36 -180
  68. package/dist/boot/types.d.ts.map +1 -1
  69. package/dist/builtin/config.d.ts +7 -0
  70. package/dist/builtin/config.d.ts.map +1 -0
  71. package/dist/builtin/config.js +15 -0
  72. package/dist/builtin/config.js.map +1 -0
  73. package/dist/{builtins → builtin}/logger.d.ts +4 -25
  74. package/dist/builtin/logger.d.ts.map +1 -0
  75. package/dist/{builtins → builtin}/logger.js +5 -32
  76. package/dist/builtin/logger.js.map +1 -0
  77. package/dist/config-loader.d.ts +9 -67
  78. package/dist/config-loader.d.ts.map +1 -1
  79. package/dist/config-loader.js +5 -18
  80. package/dist/config-loader.js.map +1 -1
  81. package/dist/contract.d.ts +13 -31
  82. package/dist/contract.d.ts.map +1 -1
  83. package/dist/contract.js +10 -26
  84. package/dist/contract.js.map +1 -1
  85. package/dist/crypto/encoding.d.ts +2 -15
  86. package/dist/crypto/encoding.d.ts.map +1 -1
  87. package/dist/crypto/encoding.js +2 -15
  88. package/dist/crypto/encoding.js.map +1 -1
  89. package/dist/crypto/node.d.ts.map +1 -1
  90. package/dist/crypto/node.js +1 -7
  91. package/dist/crypto/node.js.map +1 -1
  92. package/dist/crypto/port.d.ts +2 -18
  93. package/dist/crypto/port.d.ts.map +1 -1
  94. package/dist/crypto/port.js +1 -17
  95. package/dist/crypto/port.js.map +1 -1
  96. package/dist/crypto/webcrypto.d.ts.map +1 -1
  97. package/dist/crypto/webcrypto.js +1 -12
  98. package/dist/crypto/webcrypto.js.map +1 -1
  99. package/dist/declare.d.ts +41 -0
  100. package/dist/declare.d.ts.map +1 -0
  101. package/dist/{scan/declare.js → declare.js} +6 -31
  102. package/dist/declare.js.map +1 -0
  103. package/dist/define.d.ts +2 -3
  104. package/dist/define.d.ts.map +1 -1
  105. package/dist/define.js +2 -3
  106. package/dist/define.js.map +1 -1
  107. package/dist/descriptor/Fronds.d.ts +19 -0
  108. package/dist/descriptor/Fronds.d.ts.map +1 -0
  109. package/dist/descriptor/Fronds.js +40 -0
  110. package/dist/descriptor/Fronds.js.map +1 -0
  111. package/dist/descriptor/frond.d.ts +135 -0
  112. package/dist/descriptor/frond.d.ts.map +1 -0
  113. package/dist/{scan → descriptor}/frond.js.map +1 -1
  114. package/dist/dispatch/ArgumentResolver.d.ts +6 -3
  115. package/dist/dispatch/ArgumentResolver.d.ts.map +1 -1
  116. package/dist/dispatch/ArgumentResolver.js +48 -3
  117. package/dist/dispatch/ArgumentResolver.js.map +1 -1
  118. package/dist/dispatch/DispatchEvent.d.ts +2 -2
  119. package/dist/dispatch/DispatchEvent.d.ts.map +1 -1
  120. package/dist/dispatch/DispatchLifecycle.d.ts +1 -7
  121. package/dist/dispatch/DispatchLifecycle.d.ts.map +1 -1
  122. package/dist/dispatch/DispatchLifecycle.js +1 -7
  123. package/dist/dispatch/DispatchLifecycle.js.map +1 -1
  124. package/dist/dispatch/DispatchPort.d.ts +1 -1
  125. package/dist/dispatch/DispatchPort.d.ts.map +1 -1
  126. package/dist/dispatch/Dispatcher.d.ts +1 -1
  127. package/dist/dispatch/Dispatcher.d.ts.map +1 -1
  128. package/dist/dispatch/Dispatcher.js +2 -2
  129. package/dist/dispatch/Dispatcher.js.map +1 -1
  130. package/dist/{boot → dispatch}/HandlerFacade.d.ts +25 -38
  131. package/dist/dispatch/HandlerFacade.d.ts.map +1 -0
  132. package/dist/{boot → dispatch}/HandlerFacade.js +65 -74
  133. package/dist/dispatch/HandlerFacade.js.map +1 -0
  134. package/dist/dispatch/LocalRoutePolicy.d.ts +1 -1
  135. package/dist/dispatch/LocalRoutePolicy.d.ts.map +1 -1
  136. package/dist/dispatch/LocalRoutePolicy.js +4 -4
  137. package/dist/dispatch/LocalRoutePolicy.js.map +1 -1
  138. package/dist/dispatch/OperationRoute.d.ts +2 -2
  139. package/dist/dispatch/OperationRoute.d.ts.map +1 -1
  140. package/dist/dispatch/OutputView.d.ts +3 -2
  141. package/dist/dispatch/OutputView.d.ts.map +1 -1
  142. package/dist/dispatch/OutputView.js +19 -1
  143. package/dist/dispatch/OutputView.js.map +1 -1
  144. package/dist/dispatch/Route.d.ts +2 -3
  145. package/dist/dispatch/Route.d.ts.map +1 -1
  146. package/dist/dispatch/RoutePolicy.d.ts +1 -1
  147. package/dist/dispatch/RoutePolicy.d.ts.map +1 -1
  148. package/dist/dispatch/RouteRegistry.d.ts +1 -1
  149. package/dist/dispatch/RouteRegistry.d.ts.map +1 -1
  150. package/dist/dispatch/RouteRegistry.js +2 -2
  151. package/dist/dispatch/RouteRegistry.js.map +1 -1
  152. package/dist/dispatch/RouteResolver.d.ts +2 -4
  153. package/dist/dispatch/RouteResolver.d.ts.map +1 -1
  154. package/dist/dispatch/StorageGuard.d.ts +9 -8
  155. package/dist/dispatch/StorageGuard.d.ts.map +1 -1
  156. package/dist/dispatch/StorageGuard.js +66 -23
  157. package/dist/dispatch/StorageGuard.js.map +1 -1
  158. package/dist/dispatch/presenterArguments.d.ts +7 -0
  159. package/dist/dispatch/presenterArguments.d.ts.map +1 -0
  160. package/dist/dispatch/presenterArguments.js +12 -0
  161. package/dist/dispatch/presenterArguments.js.map +1 -0
  162. package/dist/dispatch/remoteRoutes.d.ts +7 -0
  163. package/dist/dispatch/remoteRoutes.d.ts.map +1 -0
  164. package/dist/dispatch/{RemoteRouteResolver.js → remoteRoutes.js} +6 -10
  165. package/dist/dispatch/remoteRoutes.js.map +1 -0
  166. package/dist/dispatch/routeNotFound.d.ts +9 -0
  167. package/dist/dispatch/routeNotFound.d.ts.map +1 -0
  168. package/dist/dispatch/routeNotFound.js +21 -0
  169. package/dist/dispatch/routeNotFound.js.map +1 -0
  170. package/dist/dispatch/validateInput.d.ts +5 -0
  171. package/dist/dispatch/validateInput.d.ts.map +1 -0
  172. package/dist/dispatch/validateInput.js +20 -0
  173. package/dist/dispatch/validateInput.js.map +1 -0
  174. package/dist/effective-operation.d.ts +6 -3
  175. package/dist/effective-operation.d.ts.map +1 -1
  176. package/dist/effective-operation.js +49 -27
  177. package/dist/effective-operation.js.map +1 -1
  178. package/dist/emit.d.ts +4 -42
  179. package/dist/emit.d.ts.map +1 -1
  180. package/dist/emit.js +3 -39
  181. package/dist/emit.js.map +1 -1
  182. package/dist/entry/facade.d.ts +8 -0
  183. package/dist/entry/facade.d.ts.map +1 -0
  184. package/dist/entry/facade.js +28 -0
  185. package/dist/entry/facade.js.map +1 -0
  186. package/dist/entry/transport.d.ts +5 -0
  187. package/dist/entry/transport.d.ts.map +1 -0
  188. package/dist/entry/transport.js +11 -0
  189. package/dist/entry/transport.js.map +1 -0
  190. package/dist/frond-config.d.ts +8 -71
  191. package/dist/frond-config.d.ts.map +1 -1
  192. package/dist/frond-config.js +1 -9
  193. package/dist/frond-config.js.map +1 -1
  194. package/dist/graph.d.ts +1 -1
  195. package/dist/graph.d.ts.map +1 -1
  196. package/dist/identity-keys.d.ts +2 -5
  197. package/dist/identity-keys.d.ts.map +1 -1
  198. package/dist/identity-keys.js +3 -16
  199. package/dist/identity-keys.js.map +1 -1
  200. package/dist/identity.d.ts +4 -30
  201. package/dist/identity.d.ts.map +1 -1
  202. package/dist/identity.js +11 -73
  203. package/dist/identity.js.map +1 -1
  204. package/dist/imports.d.ts +2 -8
  205. package/dist/imports.d.ts.map +1 -1
  206. package/dist/imports.js +1 -7
  207. package/dist/imports.js.map +1 -1
  208. package/dist/index.d.ts +28 -30
  209. package/dist/index.d.ts.map +1 -1
  210. package/dist/index.js +17 -22
  211. package/dist/index.js.map +1 -1
  212. package/dist/loader.d.ts +1 -8
  213. package/dist/loader.d.ts.map +1 -1
  214. package/dist/loader.js +1 -8
  215. package/dist/loader.js.map +1 -1
  216. package/dist/node.d.ts +2 -11
  217. package/dist/node.d.ts.map +1 -1
  218. package/dist/node.js +2 -11
  219. package/dist/node.js.map +1 -1
  220. package/dist/prefab/collector.d.ts +1 -22
  221. package/dist/prefab/collector.d.ts.map +1 -1
  222. package/dist/prefab/collector.js +1 -22
  223. package/dist/prefab/collector.js.map +1 -1
  224. package/dist/prefab/crud.d.ts +19 -35
  225. package/dist/prefab/crud.d.ts.map +1 -1
  226. package/dist/prefab/crud.js +39 -66
  227. package/dist/prefab/crud.js.map +1 -1
  228. package/dist/prefab/mirror.d.ts +5 -27
  229. package/dist/prefab/mirror.d.ts.map +1 -1
  230. package/dist/prefab/mirror.js +6 -24
  231. package/dist/prefab/mirror.js.map +1 -1
  232. package/dist/prefab/prefab.d.ts +1 -7
  233. package/dist/prefab/prefab.d.ts.map +1 -1
  234. package/dist/prefab/prefab.js +1 -7
  235. package/dist/prefab/prefab.js.map +1 -1
  236. package/dist/prefab/presenter.d.ts +2 -36
  237. package/dist/prefab/presenter.d.ts.map +1 -1
  238. package/dist/prefab/presenter.js +2 -36
  239. package/dist/prefab/presenter.js.map +1 -1
  240. package/dist/prefab/repository.d.ts +12 -80
  241. package/dist/prefab/repository.d.ts.map +1 -1
  242. package/dist/prefab/repository.js +22 -35
  243. package/dist/prefab/repository.js.map +1 -1
  244. package/dist/scan/adapters.d.ts +3 -0
  245. package/dist/scan/adapters.d.ts.map +1 -0
  246. package/dist/scan/adapters.js +25 -0
  247. package/dist/scan/adapters.js.map +1 -0
  248. package/dist/scan/bundling.d.ts +1 -12
  249. package/dist/scan/bundling.d.ts.map +1 -1
  250. package/dist/scan/bundling.js +1 -12
  251. package/dist/scan/bundling.js.map +1 -1
  252. package/dist/scan/conventions.d.ts +6 -40
  253. package/dist/scan/conventions.d.ts.map +1 -1
  254. package/dist/scan/conventions.js +5 -34
  255. package/dist/scan/conventions.js.map +1 -1
  256. package/dist/scan/emit.d.ts +2 -6
  257. package/dist/scan/emit.d.ts.map +1 -1
  258. package/dist/scan/emit.js +5 -39
  259. package/dist/scan/emit.js.map +1 -1
  260. package/dist/scan/handler-parser.d.ts +9 -76
  261. package/dist/scan/handler-parser.d.ts.map +1 -1
  262. package/dist/scan/handler-parser.js +28 -85
  263. package/dist/scan/handler-parser.js.map +1 -1
  264. package/dist/scan/result.d.ts +28 -0
  265. package/dist/scan/result.d.ts.map +1 -0
  266. package/dist/scan/result.js +2 -0
  267. package/dist/scan/result.js.map +1 -0
  268. package/dist/scan/scanner.d.ts +3 -28
  269. package/dist/scan/scanner.d.ts.map +1 -1
  270. package/dist/scan/scanner.js +36 -135
  271. package/dist/scan/scanner.js.map +1 -1
  272. package/dist/scan/statement.d.ts +1 -1
  273. package/dist/scan/statement.d.ts.map +1 -1
  274. package/dist/scan/statement.js +4 -30
  275. package/dist/scan/statement.js.map +1 -1
  276. package/dist/source.d.ts +41 -0
  277. package/dist/source.d.ts.map +1 -0
  278. package/dist/source.js +10 -0
  279. package/dist/source.js.map +1 -0
  280. package/dist/storage.d.ts +92 -0
  281. package/dist/storage.d.ts.map +1 -0
  282. package/dist/storage.js +50 -0
  283. package/dist/storage.js.map +1 -0
  284. package/dist/store.d.ts +18 -0
  285. package/dist/store.d.ts.map +1 -0
  286. package/dist/store.js +146 -0
  287. package/dist/store.js.map +1 -0
  288. package/dist/verify.d.ts +6 -39
  289. package/dist/verify.d.ts.map +1 -1
  290. package/dist/verify.js +19 -39
  291. package/dist/verify.js.map +1 -1
  292. package/dist/wire/CallLog.d.ts +32 -0
  293. package/dist/wire/CallLog.d.ts.map +1 -0
  294. package/dist/{contract → wire}/CallLog.js.map +1 -1
  295. package/dist/wire/Invocation.d.ts +32 -0
  296. package/dist/wire/Invocation.d.ts.map +1 -0
  297. package/dist/wire/Invocation.js +66 -0
  298. package/dist/wire/Invocation.js.map +1 -0
  299. package/dist/wire/RouteAddress.d.ts +24 -0
  300. package/dist/wire/RouteAddress.d.ts.map +1 -0
  301. package/dist/{contract → wire}/RouteAddress.js +7 -0
  302. package/dist/wire/RouteAddress.js.map +1 -0
  303. package/dist/wire/binding.d.ts +36 -0
  304. package/dist/wire/binding.d.ts.map +1 -0
  305. package/dist/{boot → wire}/binding.js +5 -62
  306. package/dist/wire/binding.js.map +1 -0
  307. package/dist/wire/call.d.ts +25 -172
  308. package/dist/wire/call.d.ts.map +1 -1
  309. package/dist/wire/call.js +15 -166
  310. package/dist/wire/call.js.map +1 -1
  311. package/dist/wire/drift.d.ts +3 -28
  312. package/dist/wire/drift.d.ts.map +1 -1
  313. package/dist/wire/drift.js +4 -23
  314. package/dist/wire/drift.js.map +1 -1
  315. package/dist/wire/errors.d.ts +4 -24
  316. package/dist/wire/errors.d.ts.map +1 -1
  317. package/dist/wire/errors.js +4 -24
  318. package/dist/wire/errors.js.map +1 -1
  319. package/dist/wire/http-error.d.ts +2 -13
  320. package/dist/wire/http-error.d.ts.map +1 -1
  321. package/dist/wire/http-error.js +5 -19
  322. package/dist/wire/http-error.js.map +1 -1
  323. package/dist/wire/loggerMiddleware.d.ts +2 -8
  324. package/dist/wire/loggerMiddleware.d.ts.map +1 -1
  325. package/dist/wire/loggerMiddleware.js +1 -7
  326. package/dist/wire/loggerMiddleware.js.map +1 -1
  327. package/dist/wire/middleware.d.ts +3 -7
  328. package/dist/wire/middleware.d.ts.map +1 -1
  329. package/dist/wire/middleware.js +1 -5
  330. package/dist/wire/middleware.js.map +1 -1
  331. package/dist/wire/operation.d.ts +12 -74
  332. package/dist/wire/operation.d.ts.map +1 -1
  333. package/dist/wire/operation.js +4 -66
  334. package/dist/wire/operation.js.map +1 -1
  335. package/dist/wire/signature.d.ts +37 -0
  336. package/dist/wire/signature.d.ts.map +1 -0
  337. package/dist/wire/signature.js +2 -0
  338. package/dist/wire/signature.js.map +1 -0
  339. package/package.json +3 -3
  340. package/src/boot/Emissions.ts +22 -119
  341. package/src/boot/ambient-port.ts +3 -24
  342. package/src/boot/ambient.als.ts +7 -12
  343. package/src/boot/ambient.queue.ts +2 -5
  344. package/src/boot/apply.ts +3 -15
  345. package/src/boot/auth.ts +6 -16
  346. package/src/boot/boot.ts +8 -23
  347. package/src/boot/bootstrap.ts +117 -173
  348. package/src/boot/card.ts +84 -0
  349. package/src/boot/frame.ts +31 -65
  350. package/src/boot/hosted.ts +15 -40
  351. package/src/boot/ownership.ts +14 -49
  352. package/src/boot/ports.ts +2 -15
  353. package/src/boot/remote.ts +11 -58
  354. package/src/boot/runner.ts +17 -0
  355. package/src/boot/seed.ts +11 -42
  356. package/src/boot/statement-drift.ts +10 -28
  357. package/src/boot/together.ts +38 -72
  358. package/src/boot/types.ts +36 -180
  359. package/src/{builtins → builtin}/config.ts +1 -7
  360. package/src/{builtins → builtin}/logger.ts +6 -39
  361. package/src/config-loader.ts +12 -71
  362. package/src/contract.ts +15 -39
  363. package/src/crypto/encoding.ts +2 -15
  364. package/src/crypto/node.ts +1 -7
  365. package/src/crypto/port.ts +2 -18
  366. package/src/crypto/webcrypto.ts +1 -12
  367. package/src/{scan/declare.ts → declare.ts} +11 -42
  368. package/src/define.ts +2 -3
  369. package/src/descriptor/Fronds.ts +47 -0
  370. package/src/descriptor/frond.ts +145 -0
  371. package/src/dispatch/ArgumentResolver.ts +54 -8
  372. package/src/dispatch/DispatchEvent.ts +2 -2
  373. package/src/dispatch/DispatchLifecycle.ts +1 -7
  374. package/src/dispatch/DispatchPort.ts +1 -1
  375. package/src/dispatch/Dispatcher.ts +3 -3
  376. package/src/dispatch/HandlerFacade.ts +231 -0
  377. package/src/dispatch/LocalRoutePolicy.ts +4 -4
  378. package/src/dispatch/OperationRoute.ts +2 -2
  379. package/src/dispatch/OutputView.ts +24 -2
  380. package/src/dispatch/Route.ts +2 -4
  381. package/src/dispatch/RoutePolicy.ts +1 -1
  382. package/src/dispatch/RouteRegistry.ts +2 -2
  383. package/src/dispatch/RouteResolver.ts +2 -4
  384. package/src/dispatch/StorageGuard.ts +75 -23
  385. package/src/dispatch/presenterArguments.ts +25 -0
  386. package/src/dispatch/{RemoteRouteResolver.ts → remoteRoutes.ts} +7 -9
  387. package/src/dispatch/routeNotFound.ts +33 -0
  388. package/src/dispatch/validateInput.ts +28 -0
  389. package/src/effective-operation.ts +60 -37
  390. package/src/emit.ts +5 -63
  391. package/src/entry/facade.ts +44 -0
  392. package/src/entry/transport.ts +16 -0
  393. package/src/frond-config.ts +8 -71
  394. package/src/graph.ts +1 -1
  395. package/src/identity-keys.ts +3 -16
  396. package/src/identity.ts +12 -80
  397. package/src/imports.ts +3 -32
  398. package/src/index.ts +28 -33
  399. package/src/loader.ts +2 -16
  400. package/src/node.ts +2 -11
  401. package/src/prefab/collector.ts +1 -22
  402. package/src/prefab/crud.ts +51 -90
  403. package/src/prefab/mirror.ts +9 -49
  404. package/src/prefab/prefab.ts +2 -21
  405. package/src/prefab/presenter.ts +2 -36
  406. package/src/prefab/repository.ts +32 -108
  407. package/src/scan/adapters.ts +32 -0
  408. package/src/scan/bundling.ts +1 -12
  409. package/src/scan/conventions.ts +6 -40
  410. package/src/scan/emit.ts +7 -43
  411. package/src/scan/handler-parser.ts +41 -163
  412. package/src/scan/result.ts +29 -0
  413. package/src/scan/scanner.ts +40 -138
  414. package/src/scan/statement.ts +6 -31
  415. package/src/source.ts +44 -0
  416. package/src/storage.ts +141 -0
  417. package/src/store.ts +152 -0
  418. package/src/verify.ts +19 -60
  419. package/src/wire/CallLog.ts +30 -0
  420. package/src/{contract → wire}/Invocation.ts +24 -17
  421. package/src/{contract → wire}/RouteAddress.ts +10 -0
  422. package/src/wire/binding.ts +102 -0
  423. package/src/wire/call.ts +30 -261
  424. package/src/wire/drift.ts +5 -30
  425. package/src/wire/errors.ts +4 -24
  426. package/src/wire/http-error.ts +5 -19
  427. package/src/wire/loggerMiddleware.ts +2 -8
  428. package/src/wire/middleware.ts +3 -7
  429. package/src/wire/operation.ts +13 -110
  430. package/src/wire/signature.ts +38 -0
  431. package/dist/boot/HandlerFacade.d.ts.map +0 -1
  432. package/dist/boot/HandlerFacade.js.map +0 -1
  433. package/dist/boot/binding.d.ts +0 -60
  434. package/dist/boot/binding.d.ts.map +0 -1
  435. package/dist/boot/binding.js.map +0 -1
  436. package/dist/builtins/config.d.ts +0 -13
  437. package/dist/builtins/config.d.ts.map +0 -1
  438. package/dist/builtins/config.js +0 -21
  439. package/dist/builtins/config.js.map +0 -1
  440. package/dist/builtins/logger.d.ts.map +0 -1
  441. package/dist/builtins/logger.js.map +0 -1
  442. package/dist/contract/Call.d.ts +0 -10
  443. package/dist/contract/Call.d.ts.map +0 -1
  444. package/dist/contract/Call.js +0 -15
  445. package/dist/contract/Call.js.map +0 -1
  446. package/dist/contract/CallLog.d.ts +0 -57
  447. package/dist/contract/CallLog.d.ts.map +0 -1
  448. package/dist/contract/Invocation.d.ts +0 -27
  449. package/dist/contract/Invocation.d.ts.map +0 -1
  450. package/dist/contract/Invocation.js +0 -59
  451. package/dist/contract/Invocation.js.map +0 -1
  452. package/dist/contract/RouteAddress.d.ts +0 -17
  453. package/dist/contract/RouteAddress.d.ts.map +0 -1
  454. package/dist/contract/RouteAddress.js.map +0 -1
  455. package/dist/dispatch/InputValidator.d.ts +0 -7
  456. package/dist/dispatch/InputValidator.d.ts.map +0 -1
  457. package/dist/dispatch/InputValidator.js +0 -22
  458. package/dist/dispatch/InputValidator.js.map +0 -1
  459. package/dist/dispatch/OperationExecutor.d.ts +0 -25
  460. package/dist/dispatch/OperationExecutor.d.ts.map +0 -1
  461. package/dist/dispatch/OperationExecutor.js +0 -32
  462. package/dist/dispatch/OperationExecutor.js.map +0 -1
  463. package/dist/dispatch/OutputProjector.d.ts +0 -12
  464. package/dist/dispatch/OutputProjector.d.ts.map +0 -1
  465. package/dist/dispatch/OutputProjector.js +0 -30
  466. package/dist/dispatch/OutputProjector.js.map +0 -1
  467. package/dist/dispatch/PresenterArgumentResolver.d.ts +0 -12
  468. package/dist/dispatch/PresenterArgumentResolver.d.ts.map +0 -1
  469. package/dist/dispatch/PresenterArgumentResolver.js +0 -20
  470. package/dist/dispatch/PresenterArgumentResolver.js.map +0 -1
  471. package/dist/dispatch/RemoteRouteResolver.d.ts +0 -13
  472. package/dist/dispatch/RemoteRouteResolver.d.ts.map +0 -1
  473. package/dist/dispatch/RemoteRouteResolver.js.map +0 -1
  474. package/dist/dispatch/RouteNotFoundError.d.ts +0 -10
  475. package/dist/dispatch/RouteNotFoundError.d.ts.map +0 -1
  476. package/dist/dispatch/RouteNotFoundError.js +0 -24
  477. package/dist/dispatch/RouteNotFoundError.js.map +0 -1
  478. package/dist/entry/DynamicFacade.d.ts +0 -10
  479. package/dist/entry/DynamicFacade.d.ts.map +0 -1
  480. package/dist/entry/DynamicFacade.js +0 -27
  481. package/dist/entry/DynamicFacade.js.map +0 -1
  482. package/dist/entry/FacadeEntry.d.ts +0 -11
  483. package/dist/entry/FacadeEntry.d.ts.map +0 -1
  484. package/dist/entry/FacadeEntry.js +0 -26
  485. package/dist/entry/FacadeEntry.js.map +0 -1
  486. package/dist/entry/TransportEntry.d.ts +0 -13
  487. package/dist/entry/TransportEntry.d.ts.map +0 -1
  488. package/dist/entry/TransportEntry.js +0 -24
  489. package/dist/entry/TransportEntry.js.map +0 -1
  490. package/dist/orm.d.ts +0 -207
  491. package/dist/orm.d.ts.map +0 -1
  492. package/dist/orm.js +0 -66
  493. package/dist/orm.js.map +0 -1
  494. package/dist/scan/Fronds.d.ts +0 -45
  495. package/dist/scan/Fronds.d.ts.map +0 -1
  496. package/dist/scan/Fronds.js +0 -66
  497. package/dist/scan/Fronds.js.map +0 -1
  498. package/dist/scan/declare.d.ts +0 -71
  499. package/dist/scan/declare.d.ts.map +0 -1
  500. package/dist/scan/declare.js.map +0 -1
  501. package/dist/scan/frond.d.ts +0 -224
  502. package/dist/scan/frond.d.ts.map +0 -1
  503. package/src/boot/HandlerFacade.ts +0 -242
  504. package/src/boot/binding.ts +0 -182
  505. package/src/contract/Call.ts +0 -18
  506. package/src/contract/CallLog.ts +0 -55
  507. package/src/dispatch/InputValidator.ts +0 -28
  508. package/src/dispatch/OperationExecutor.ts +0 -60
  509. package/src/dispatch/OutputProjector.ts +0 -32
  510. package/src/dispatch/PresenterArgumentResolver.ts +0 -25
  511. package/src/dispatch/RouteNotFoundError.ts +0 -29
  512. package/src/entry/DynamicFacade.ts +0 -28
  513. package/src/entry/FacadeEntry.ts +0 -32
  514. package/src/entry/TransportEntry.ts +0 -30
  515. package/src/orm.ts +0 -252
  516. package/src/scan/Fronds.ts +0 -73
  517. package/src/scan/frond.ts +0 -235
  518. /package/dist/{scan → descriptor}/frond.js +0 -0
  519. /package/dist/{contract → wire}/CallLog.js +0 -0
package/src/boot/frame.ts CHANGED
@@ -1,24 +1,10 @@
1
1
  /**
2
- * The compensated realization of a frame — what `Together` becomes when its members do
3
- * not share an engine.
4
- *
5
- * A transaction is the engine's own answer and costs nothing to use: the members are
6
- * rebuilt over it and the engine gives both the unwind and the isolation. Across engines
7
- * there is no such thing, so the unwind is built here: every write through the port is
8
- * recorded with the image that preceded it, and a failure replays the inverses in reverse
9
- * order.
10
- *
11
- * **It gives all-or-nothing, never isolation.** Between two writes a reader sees the half,
12
- * and nothing here can hide it — that is the whole difference between the two realizations
13
- * and the reason the boot says which one it built.
14
- *
15
- * The port is thirteen known gestures, which is what makes the inverse derivable rather
16
- * than declared: a saga asks its author for an `undo` per step because its steps are
17
- * arbitrary code. Here they are not.
2
+ * The compensated realization of a frame — what `Together` becomes when its members do not share
3
+ * an engine.
18
4
  */
19
- import { FieldGroup, FieldSet, Unique, type Fields } from '@fougere/schema';
5
+ import { FieldSet, Role, type SchemaView } from '@fougere/schema';
20
6
  import { dequal } from 'dequal';
21
- import type { Logger } from '../builtins/logger.js';
7
+ import type { Logger } from '../builtin/logger.js';
22
8
 
23
9
  /** One write that landed, and how to take it back. */
24
10
  export interface Undo {
@@ -28,11 +14,8 @@ export interface Undo {
28
14
  }
29
15
 
30
16
  /**
31
- * The subset of the port a frame has to watch: every gesture that writes, plus the reads
32
- * that take one back.
33
- *
34
- * Not `StorageGuard`'s `Writer`, which is `create` and `update` — all a judge needs. Undoing
35
- * needs more: the deletes, and the reads that fetch the image to put back.
17
+ * The subset of the port a frame has to watch: every gesture that writes, plus the reads that take
18
+ * one back.
36
19
  */
37
20
  interface Undoable {
38
21
  create(input: Record<string, unknown>, ...rest: unknown[]): Promise<Record<string, unknown>>;
@@ -47,25 +30,11 @@ interface Undoable {
47
30
  const pick = (row: Record<string, unknown>, keys: readonly string[]): Record<string, unknown> =>
48
31
  Object.fromEntries(keys.map((key) => [key, row[key]]));
49
32
 
50
- /**
51
- * Whether an upsert's conflict can be something other than the primary key.
52
- *
53
- * The inverse of an upsert is derivable exactly when the conflict is the primary key: read
54
- * the rows by key first, then restore the ones that were there and delete the ones that
55
- * were not. `SqlEntityOrm` spells `onConflict(pk)` on SQLite and Postgres, so that holds —
56
- * but MySQL's `onDuplicateKeyUpdate` fires on ANY unique constraint, and a row that
57
- * conflicts on a unique email while carrying a different key would be restored under a key
58
- * the write never touched.
59
- *
60
- * So the question is asked of the DECLARATION, not of the engine: an entity whose only
61
- * unique constraint is its key upserts unambiguously everywhere. This file knows no dialect
62
- * and should not learn one.
63
- */
64
- function mayConflictElsewhere(fields: Fields): boolean {
65
- const groups = FieldGroup.groupsOf(fields, Unique);
66
- if (groups.length > 0) return true;
67
- // A sole `unique()` carries a one-member group, which `groupsOf` filters out.
68
- return Object.values(fields).some((field) => FieldGroup.on(field, Unique).length > 0);
33
+ /** Whether an upsert's conflict can be something other than the primary key. */
34
+ function mayConflictElsewhere(schema: SchemaView): boolean {
35
+ if ((schema.getUnique() ?? []).length > 0) return true;
36
+
37
+ return Object.values(schema.getFields()).some((field) => Role.of(field).isUnique);
69
38
  }
70
39
 
71
40
  /** Refused where it is used, naming the group that makes the inverse ambiguous. */
@@ -79,17 +48,14 @@ function refuseAmbiguousUpsert(entity: string, gesture: string): never {
79
48
  }
80
49
 
81
50
  /**
82
- * The ORM a member is handed inside a compensated frame: the same port, writing the same
83
- * rows, leaving an inverse behind each time.
84
- *
85
- * `Object.create` for the same reason `StorageGuard` uses it — the ORM keeps every gesture
86
- * it had, including the ones this knows nothing about.
51
+ * The storage a member is handed inside a compensated frame: the same port, writing the same rows,
52
+ * leaving an inverse behind each time.
87
53
  */
88
- export function recording<T extends object>(orm: T, entity: string, fields: Fields, journal: Undo[]): T {
89
- const base = orm as unknown as Undoable;
90
- if (typeof base.create !== 'function' || typeof base.update !== 'function') return orm;
54
+ export function recording<T extends object>(storage: T, entity: string, schema: SchemaView, journal: Undo[]): T {
55
+ const base = storage as unknown as Undoable;
56
+ if (typeof base.create !== 'function' || typeof base.update !== 'function') return storage;
91
57
 
92
- const key = FieldSet.of(fields).primary;
58
+ const key = FieldSet.of(schema.getFields()).primary;
93
59
  if (!key) {
94
60
  throw new Error(
95
61
  `${entity} declares no primary field, so a write to it cannot be taken back by ` +
@@ -97,7 +63,7 @@ export function recording<T extends object>(orm: T, entity: string, fields: Fiel
97
63
  );
98
64
  }
99
65
 
100
- const recorded = Object.create(orm) as T & Undoable;
66
+ const recorded = Object.create(storage) as T & Undoable;
101
67
 
102
68
  recorded.create = async function (...args) {
103
69
  const row = await base.create.apply(this, args);
@@ -121,9 +87,16 @@ export function recording<T extends object>(orm: T, entity: string, fields: Fiel
121
87
  run: async () => {
122
88
  const current = await base.findById.call(this, id);
123
89
  if (!current) throw new Error(`${entity}#${id} is gone`);
90
+ // Reading and restoring are two statements, and there is no transaction here to make
91
+ // them one — a write landing between them is overwritten unseen. So this names what it
92
+ // FOUND, and claims nothing about what it did not: the frame was built because no
93
+ // engine could isolate it, and a check does not put the isolation back.
124
94
  const moved = touched.filter((field) => !dequal(current[field], wrote[field]));
125
95
  if (moved.length > 0) {
126
- throw new Error(`${entity}#${id} was changed by someone else since (${moved.join(', ')})`);
96
+ throw new Error(
97
+ `${entity}#${id} no longer holds what this frame wrote (${moved.join(', ')}), so ` +
98
+ `restoring the previous values would drop whatever replaced them`,
99
+ );
127
100
  }
128
101
  await base.update.call(this, id, pick(before, touched));
129
102
  },
@@ -159,8 +132,8 @@ export function recording<T extends object>(orm: T, entity: string, fields: Fiel
159
132
  };
160
133
 
161
134
  if (typeof base.upsert === 'function') {
162
- (recorded as unknown as Undoable).upsert = async function (input, ...rest) {
163
- if (mayConflictElsewhere(fields)) refuseAmbiguousUpsert(entity, 'upsert');
135
+ recorded.upsert = async function (input, ...rest) {
136
+ if (mayConflictElsewhere(schema)) refuseAmbiguousUpsert(entity, 'upsert');
164
137
  const undo = await undoUpsert.call(this, [input]);
165
138
  const row = await base.upsert!.call(this, input, ...rest);
166
139
  journal.push(undo);
@@ -169,8 +142,8 @@ export function recording<T extends object>(orm: T, entity: string, fields: Fiel
169
142
  }
170
143
 
171
144
  if (typeof base.upsertAll === 'function') {
172
- (recorded as unknown as Undoable).upsertAll = async function (inputs, ...rest) {
173
- if (mayConflictElsewhere(fields)) refuseAmbiguousUpsert(entity, 'upsertAll');
145
+ recorded.upsertAll = async function (inputs, ...rest) {
146
+ if (mayConflictElsewhere(schema)) refuseAmbiguousUpsert(entity, 'upsertAll');
174
147
  const undo = await undoUpsert.call(this, inputs);
175
148
  const written = await base.upsertAll!.call(this, inputs, ...rest);
176
149
  journal.push(undo);
@@ -181,14 +154,7 @@ export function recording<T extends object>(orm: T, entity: string, fields: Fiel
181
154
  return recorded;
182
155
  }
183
156
 
184
- /**
185
- * Replay the inverses, most recent first, and report rather than pretend.
186
- *
187
- * Every one is attempted even after one fails: stopping at the first would leave writes
188
- * standing that could have been taken back. What cannot be undone is named — the caller is
189
- * about to tell a user their transfer failed, and "it failed and here is what is still in
190
- * the database" is the only honest version of that sentence.
191
- */
157
+ /** Replay the inverses, most recent first, and report rather than pretend. */
192
158
  export async function unwind(journal: readonly Undo[], cause: unknown, log: Logger): Promise<never> {
193
159
  const stuck: string[] = [];
194
160
  for (const undo of [...journal].reverse()) {
@@ -1,23 +1,7 @@
1
- /**
2
- * What this app hosts — what it STATED, or what a scan FOUND.
3
- *
4
- * The PRESENCE of the key is the decision, the way `remotes:` states a topology: an app
5
- * that passes `fronds:` is saying "do not scan", and one that passes `scan:` is handing
6
- * over what a scanner read. There is no mode to configure because there is no third
7
- * behaviour to name.
8
- *
9
- * Both may arrive, and then they MERGE — but only where a scan costs nothing at runtime.
10
- * Under Nuxt the scan is a build artifact, so an app may state the frond it wants to own
11
- * and leave the rest to what the build found. Anywhere the scan would run at START, half a
12
- * statement buys nothing the whole one does: the disk is read either way.
13
- *
14
- * Merging is per frond NAME and per member. A stated frond wins outright on the members it
15
- * names — stating `entities: [Post]` where a scan found `[Post, Author]` yields `[Post]`,
16
- * because the point of stating is to decide. Empty is what "I named none" looks like, and
17
- * `frond()` builds every member, so an empty one is filled rather than enforced.
18
- */
19
- import type { FrondDescriptor, ScanResult } from '../scan/frond.js';
20
- import { Fronds } from '../scan/Fronds.js';
1
+ /** What this app hosts — what it STATED, or what a scan FOUND. */
2
+ import type { FrondDescriptor } from '../descriptor/frond.js';
3
+ import type { ScanResult } from '../scan/result.js';
4
+ import { Fronds } from '../descriptor/Fronds.js';
21
5
 
22
6
  /** Where an app's fronds come from — either, or both. */
23
7
  export interface HostedSources {
@@ -27,22 +11,22 @@ export interface HostedSources {
27
11
  scan?: ScanResult | (() => Promise<ScanResult> | ScanResult);
28
12
  }
29
13
 
30
- /** The members a stated frond takes from a scan when it named none of its own. */
14
+ /** The members a frond takes from a scan when it named none of its own. */
31
15
  type Fillable = 'providers' | 'entities' | 'handlers' | 'presenters' | 'collectors' | 'seeds';
32
16
 
33
- /** A stated frond, completed by what a scan found under the same name. */
34
- function completed(stated: FrondDescriptor, found: FrondDescriptor | undefined): FrondDescriptor {
35
- if (!found) return stated;
17
+ /** A frond the host passed, completed by what a scan found under the same name. */
18
+ function completed(given: FrondDescriptor, found: FrondDescriptor | undefined): FrondDescriptor {
19
+ if (!found) return given;
36
20
 
37
21
  // Written out rather than looped: a loop over the key union asks TypeScript to prove
38
- // `found[k]` fits `stated[k]` for every k at once, which it cannot — and the cast that
22
+ // `found[k]` fits `given[k]` for every k at once, which it cannot — and the cast that
39
23
  // silences it would also silence a member added to the descriptor and forgotten here.
40
24
  const fill = <K extends Fillable>(member: K): FrondDescriptor[K] =>
41
- (stated[member].length === 0 ? found[member] : stated[member]);
25
+ (given[member].length === 0 ? found[member] : given[member]);
42
26
 
43
27
  return {
44
28
  ...found,
45
- ...stated,
29
+ ...given,
46
30
  providers: fill('providers'),
47
31
  entities: fill('entities'),
48
32
  handlers: fill('handlers'),
@@ -58,20 +42,11 @@ export async function hostedBy(sources: HostedSources): Promise<ScanResult> {
58
42
  ? await (typeof sources.scan === 'function' ? sources.scan() : sources.scan)
59
43
  : undefined;
60
44
 
61
- if (!sources.fronds) {
62
- if (!scanned) {
63
- throw new Error(
64
- 'createApp needs `fronds:` (what this app states) or `scan:` (what a scanner found). '
65
- + 'Neither was given, so nothing is hosted.',
66
- );
67
- }
68
-
69
- return scanned;
70
- }
45
+ if (!sources.fronds) return scanned ?? { fronds: Fronds.hosting([]), diagnostics: [] };
71
46
 
72
47
  const found = scanned?.fronds ?? [];
73
- const stated = sources.fronds.map((f) => completed(f, found.find((s) => s.name === f.name)));
74
- const unstated = found.filter((f) => !sources.fronds!.some((s) => s.name === f.name));
48
+ const configured = sources.fronds.map((f) => completed(f, found.find((s) => s.name === f.name)));
49
+ const discovered = found.filter((f) => !sources.fronds!.some((s) => s.name === f.name));
75
50
 
76
- return { fronds: Fronds.scanned([...stated, ...unstated]), diagnostics: scanned?.diagnostics ?? [] };
51
+ return { fronds: Fronds.hosting([...configured, ...discovered]), diagnostics: scanned?.diagnostics ?? [] };
77
52
  }
@@ -1,17 +1,11 @@
1
1
  import { lowerFirst } from '@fougere/schema';
2
- import type { FrondDescriptor, ProviderEntry } from '../scan/frond.js';
2
+ import type { FrondDescriptor, ProviderEntry } from '../descriptor/frond.js';
3
+ import { inheritsCrud } from '../prefab/crud.js';
3
4
  import { targetOf } from '../prefab/prefab.js';
4
5
  import { ownedBy, repositoryKeyOf } from '../prefab/repository.js';
5
- import { ormKeyOf } from '../orm.js';
6
+ import { entityOfStorageKey } from '../storage.js';
6
7
 
7
- /**
8
- * Who owns an entity's storage.
9
- *
10
- * `Repository(Commande, Stock)` states it — an aggregate is the only thing that claims
11
- * entities it is not named after, and the arity is what says so. A repository of ONE owns
12
- * nothing: a boundary between one thing and nothing is not a boundary, and the judge is
13
- * already on that entity's rows.
14
- */
8
+ /** Who owns an entity's storage. */
15
9
  export function ownersOf(providers: readonly ProviderEntry[]): Map<string, string> {
16
10
  const owners = new Map<string, string>();
17
11
  for (const provider of providers) {
@@ -37,7 +31,7 @@ export function ownersOf(providers: readonly ProviderEntry[]): Map<string, strin
37
31
 
38
32
  /**
39
33
  * The entities a class was BUILT ON — what a prefab may legitimately be handed the storage
40
- * of. Empty for a plain service, which is why one cannot ask for an ORM at all.
34
+ * of. Empty for a plain service, which is why one cannot ask for a storage at all.
41
35
  */
42
36
  function builtOn(ctor: unknown): string[] {
43
37
  const owned = ownedBy(ctor);
@@ -46,20 +40,12 @@ function builtOn(ctor: unknown): string[] {
46
40
  return target?.name ? [lowerFirst(target.name)] : [];
47
41
  }
48
42
 
49
- /**
50
- * `EntityOrm<E>` is not a word of the user's vocabulary — `<E>Repository` is the one way in.
51
- *
52
- * A door judges and projects; a HOLDER keeps the storage. So the rule is not about which
53
- * directory a file sits in but about which of the two a class is: a handler, a presenter and
54
- * a collector may never name an ORM, and a provider may name only the ORM of what its prefab
55
- * was built on — which is `Repository` and `Mirror`, without either being named here.
56
- *
57
- * What it buys beyond one word instead of two: an entity that becomes owned later needs no
58
- * call site to move, because none of them ever spelled the storage.
59
- *
60
- * Refused at boot rather than reported by `verify`, which nothing calls at startup.
61
- */
62
- export function refuseOrmInUserCode(frond: FrondDescriptor, owners: Map<string, string>): void {
43
+ /** `Storage<E>` is not a word of the user's vocabulary — `<E>Repository` is the one way in. */
44
+ export function refuseStorageInUserCode(
45
+ frond: FrondDescriptor,
46
+ owners: Map<string, string>,
47
+ known: (entity: string) => boolean,
48
+ ): void {
63
49
  const doors = [
64
50
  ...frond.handlers.map((h) => ({ ...h, kind: 'handler' })),
65
51
  ...frond.presenters.map((p) => ({ ...p, kind: 'presenter' })),
@@ -70,7 +56,7 @@ export function refuseOrmInUserCode(frond: FrondDescriptor, owners: Map<string,
70
56
  for (const decl of [...doors, ...holders]) {
71
57
  const allowed = decl.kind === 'provider' ? builtOn(decl.ctor) : [];
72
58
  for (const dep of decl.deps) {
73
- const entity = entityOfOrmKey(dep);
59
+ const entity = entityOfStorageKey(dep, known);
74
60
  if (!entity) continue;
75
61
 
76
62
  const owner = owners.get(entity);
@@ -97,25 +83,11 @@ export function refuseOrmInUserCode(frond: FrondDescriptor, owners: Map<string,
97
83
  }
98
84
  }
99
85
 
100
- /**
101
- * An owned entity has no automatic CRUD — said at boot, not at the first request.
102
- *
103
- * `HandlerFacade.deps()` asks for `<E>Repository` when a handler inherits the five gestures
104
- * and declares no constructor of its own, and an owned entity has no such key. That alone
105
- * refuses — but LAZILY, at the first call, on the container's own sentence: measured, the app
106
- * booted clean and answered every request with `'LedgerRepository' is not registered`. A
107
- * receiver that starts and then rejects everything is found in production, which is the
108
- * reason `serve()` checks its address at boot rather than per call.
109
- *
110
- * Recognized by FORM, like the façade recognizes it: a prototype carrying `list` and
111
- * `findById` needs storage of its own, whether `Crud()` put them there or an author did.
112
- */
86
+ /** An owned entity has no automatic CRUD — said at boot, not at the first request. */
113
87
  export function refuseCrudOnOwned(frond: FrondDescriptor, owners: Map<string, string>): void {
114
88
  for (const handler of frond.handlers) {
115
89
  const owner = owners.get(handler.address);
116
- if (!owner || handler.deps.length > 0) continue;
117
- const proto = (handler.ctor as { prototype?: Record<string, unknown> }).prototype;
118
- if (typeof proto?.list !== 'function' || typeof proto?.findById !== 'function') continue;
90
+ if (!owner || handler.deps.length > 0 || !inheritsCrud(handler.ctor)) continue;
119
91
 
120
92
  throw new Error(
121
93
  `[aggregate] ${handler.ctor.name} takes the five gestures on ${handler.address}, `
@@ -128,10 +100,3 @@ export function refuseCrudOnOwned(frond: FrondDescriptor, owners: Map<string, st
128
100
  );
129
101
  }
130
102
  }
131
-
132
- /** `'PostOrm'` → `'post'`, and nothing for a key that is not one. */
133
- function entityOfOrmKey(dep: string): string | undefined {
134
- if (!dep.endsWith('Orm') || dep === 'Orm') return undefined;
135
- const entity = lowerFirst(dep.slice(0, -'Orm'.length));
136
- return ormKeyOf(entity) === dep ? entity : undefined;
137
- }
package/src/boot/ports.ts CHANGED
@@ -1,19 +1,6 @@
1
- import type { ProviderEntry } from '../scan/frond.js';
1
+ import type { ProviderEntry } from '../descriptor/frond.js';
2
2
 
3
- /**
4
- * A port is a class something already answers under. Nothing declares one — the
5
- * prototype chain states it, so `class StripePayment extends Payment` IS the whole
6
- * registration, and so is `class MyLogger extends Logger` over a builtin.
7
- *
8
- * This is the fourth reading of the rule the other three already apply: the type
9
- * names the SUBJECT (`EntityOrm<E>`, `Emit<F>`, `Facade<H>`) and the container
10
- * holds the realization. Providers were the one case where the type named the
11
- * realization instead, so `constructor(private payment: Payment)` resolved to the
12
- * base class and a handler got an object whose method did not exist.
13
- *
14
- * Only the DIRECT base binds. A deeper chain binds each link to its own child, and
15
- * a case that wants otherwise states it in `ports:` — which wins over all of this.
16
- */
3
+ /** A port is a class something already answers under. */
17
4
  export function portBindings(
18
5
  providers: ProviderEntry[],
19
6
  answers: (name: string) => boolean,
@@ -1,32 +1,18 @@
1
- /**
2
- * Remote façade — what resolve() falls back to.
3
- *
4
- * When a handler isn't hosted locally and remotes are declared, resolve()
5
- * returns a façade-shaped stand-in: same call surface as a local facade,
6
- * every operation executed through a Transport. Routing is lazy — on the
7
- * first miss, each declared remote is asked what it hosts (rpc.discover)
8
- * and the answer is cached. A remote that can't be reached stays pending
9
- * and is retried on the next miss instead of being cached as absent.
10
- */
1
+ /** Remote façade — what resolve() falls back to. */
11
2
  import type { FrondCall, Transport } from '../wire/call.js';
12
3
  import { assertIdentityCard, RPC_ENTITY } from '../wire/call.js';
13
4
  import { runMiddlewares, type AppMiddleware, type OperationContext } from '../wire/middleware.js';
14
- import { EMPTY_INVOCATION, type InvocationContext } from '../contract/Invocation.js';
5
+ import { EMPTY_INVOCATION, type InvocationContext } from '../wire/Invocation.js';
15
6
  import { FougereError, ErrorCode } from '../wire/errors.js';
16
7
  import { Card, type SchemaView, type SchemaDescriptor } from '@fougere/schema';
17
- import { DynamicFacade } from '../entry/DynamicFacade.js';
8
+ import { dynamicOperations } from '../entry/facade.js';
18
9
 
19
10
  interface Route {
20
11
  frond: string;
21
12
  transport: Transport;
22
13
  /**
23
- * The entity's schema, rebuilt from the identity card — the same
24
- * `SchemaConstructor` shape `entity({...})` produces, live validation
25
- * included. Reconstructed once per entity, at discovery time.
26
- *
27
- * **Absent when the door stores nothing.** A handler may carry no entity, so the card
28
- * publishes it with ops and no shape; there is nothing to rebuild and pretending
29
- * otherwise would hand callers an empty schema that validates everything.
14
+ * The entity's schema, rebuilt from the identity card — the same `SchemaConstructor` shape
15
+ * `entity({...})` produces, live validation included.
30
16
  */
31
17
  schema?: SchemaView;
32
18
  }
@@ -79,27 +65,13 @@ export function createRemoteRouter(
79
65
  // adding one here would answer a call with a transport to a door that
80
66
  // does not exist.
81
67
  for (const door of frond.doors) {
82
- const held = claimedBy.get(door.name);
83
- /**
84
- * Two remotes claiming one name is refused, not silently arbitrated.
85
- *
86
- * `byEntity` is keyed by the door name alone, so the second claim used to be
87
- * dropped with `if (!byEntity.has(...))` — no warning, and the winner was
88
- * whichever remote answered first. The local boot already refuses the same
89
- * collision (`assertOneOwnerPerKey`) and it refused the OTHER duplicate: in
90
- * process the last frond loaded won, here the first discovered did. One
91
- * application, two topologies, two different handlers answering — which is
92
- * precisely the gradient not holding.
93
- *
94
- * Refusing is the honest answer while a call names an entity and not a frond.
95
- * `FrondCall` already carries an optional `frond`; the day it is required, this
96
- * becomes a disambiguation instead of a refusal.
97
- */
98
- if (held !== undefined && held !== label) {
68
+ const first = claimedBy.get(door.name);
69
+ /** Two remotes claiming one name is refused, not silently arbitrated. */
70
+ if (first !== undefined && first !== label) {
99
71
  throw new FougereError({
100
72
  code: ErrorCode.INTERNAL_ERROR,
101
73
  message:
102
- `Two remotes serve '${door.name}': '${held}' and '${label}'.\n`
74
+ `Two remotes serve '${door.name}': '${first}' and '${label}'.\n`
103
75
  + ` A call names an entity, not a frond, so nothing could choose between them.\n`
104
76
  + ` - Keep one of the two out of \`remotes:\`, or\n`
105
77
  + ` - expose one of them under a different entity name.`,
@@ -140,26 +112,7 @@ export function createRemoteRouter(
140
112
 
141
113
  type Facade = Record<string, (invocation?: InvocationContext) => Promise<unknown>>;
142
114
 
143
- /**
144
- * Façade-shaped stand-in — the consumer can't tell it from a local facade.
145
- *
146
- * Every trap answers the same question, and that is the point: the runner asks
147
- * `Object.hasOwn(facade, op)` before calling, so a proxy that only trapped `get`
148
- * reported *no* operations and every split call came back `Unknown operation` —
149
- * `get` said yes, `hasOwn` said no, and the runner believed `hasOwn`.
150
- *
151
- * The stand-in claims every legal op name because it cannot know better: routing is
152
- * lazy on purpose (the card is fetched at the first miss), and the remote is the
153
- * authority on its own surface anyway. An op it does not serve comes back as its
154
- * NOT_FOUND — judged where it is owned, which is the same answer a local façade gives.
155
- *
156
- * It runs the app's middlewares, like `HandlerFacade` does, because "the consumer can't
157
- * tell it from a local facade" was false of the one thing a consumer installs: measured,
158
- * `runMiddlewares` had a single caller, so a frond that moved lost every middleware on
159
- * the calling side — no log, no retry, no cache — from a `remotes:` line alone.
160
- * The invocation the transport sends is the one the chain leaves behind, so a middleware
161
- * can still put something on the wire.
162
- */
115
+ /** Façade-shaped stand-in — the consumer can't tell it from a local facade. */
163
116
  export function createRemoteFacade(
164
117
  entity: string,
165
118
  router: RemoteRouter,
@@ -175,5 +128,5 @@ export function createRemoteFacade(
175
128
  transport(call, ctx.invocation ?? invocation));
176
129
  };
177
130
 
178
- return new DynamicFacade(opFn).operations as Facade;
131
+ return dynamicOperations(opFn) as Facade;
179
132
  }
@@ -0,0 +1,17 @@
1
+ /** A Transport built from an app — the two ways a call enters this process. */
2
+ import type { App } from './types.js';
3
+ import type { Transport } from '../wire/call.js';
4
+ import { createTransportEntry } from '../entry/transport.js';
5
+
6
+ /** Build the local runner — the reference realization of Transport. */
7
+ export function createLocalRunner(app: App, surface?: string): Transport {
8
+ return createTransportEntry(app.local, surface);
9
+ }
10
+
11
+ /**
12
+ * Build the app runner — same verdict, but resolution follows the app's topology: local façades
13
+ * and remote doublures alike.
14
+ */
15
+ export function createAppRunner(app: App, surface?: string): Transport {
16
+ return createTransportEntry(app, surface);
17
+ }
package/src/boot/seed.ts CHANGED
@@ -1,25 +1,10 @@
1
1
  import { Role } from '@fougere/schema';
2
2
  import { facadeKeyOf } from '../wire/call.js';
3
- import type { FrondDescriptor, SeedEntry, SeedFactory } from '../scan/frond.js';
3
+ import type { FrondDescriptor, SeedEntry, SeedFactory } from '../descriptor/frond.js';
4
4
  import type { App } from './types.js';
5
5
  import type { Extension } from './AppLifecycle.js';
6
6
 
7
- /**
8
- * Seeds in dependency order — a `ref()` target is planted before its referrer.
9
- *
10
- * The order is a fact about the entity graph, not about the surface running the seeds,
11
- * so it is stated once here. The Nuxt module read it off a pairwise comparator (which
12
- * `Array.sort` cannot make transitive: `a` before `b` and `b` before `c` never implies
13
- * `a` before `c`), and `boot()` had no order at all — the same fact, told twice and
14
- * wrong both times. A list seeded before its owner failed on the foreign key, and the
15
- * driver's error named neither the entity nor the file.
16
- *
17
- * Kahn, like `orderTables` in `@fougere/adapter-sql` — the same shape one level up: there
18
- * the nodes are tables and the edges FK columns, here they are seeds and the edges the
19
- * `one` relations of the entities they target. A cycle cannot be satisfied by ordering,
20
- * so its remaining seeds keep their scan order and land last: the driver refuses what is
21
- * genuinely impossible, and everything acyclic around it still gets planted.
22
- */
7
+ /** Seeds in dependency order — a `ref()` target is planted before its referrer. */
23
8
  export function orderSeeds(fronds: FrondDescriptor[]): SeedEntry[] {
24
9
  const refs = new Map<string, Set<string>>();
25
10
  for (const frond of fronds) {
@@ -69,14 +54,7 @@ interface SeedDoor {
69
54
  write(item: unknown): Promise<unknown>;
70
55
  }
71
56
 
72
- /**
73
- * Plant a set of seeds, in the order given. Reports what it did, one line per entity.
74
- *
75
- * The one seeding loop. `boot()` had one and the Nuxt module generated a second into its
76
- * Nitro plugin, which had drifted: no ORM fallback, so an entity with no façade was
77
- * skipped there and planted here. Two answers to "how does a row get in at boot" is one
78
- * too many, and the second was the one running in the browser.
79
- */
57
+ /** Plant a set of seeds, in the order given. */
80
58
  export async function runSeeds(
81
59
  app: App,
82
60
  seeds: SeedEntry[],
@@ -88,7 +66,7 @@ export async function runSeeds(
88
66
 
89
67
  const door = doorFor(app, seed.entityName);
90
68
  if (!door) {
91
- report(` ${seed.entityName}: no handler façade nor ORM — skipping seed`);
69
+ report(` ${seed.entityName}: no handler façade nor storage — skipping seed`);
92
70
  continue;
93
71
  }
94
72
 
@@ -114,11 +92,7 @@ export async function runSeeds(
114
92
  }
115
93
  }
116
94
 
117
- /**
118
- * A seed is not a client: it writes at boot, from inside. The façade is used when the
119
- * entity declares one (its judge catches a bad seed early), the storage when it does
120
- * not — an entity that exposes nothing is still an entity whose reference rows must land.
121
- */
95
+ /** A seed is not a client. */
122
96
  function doorFor(app: App, entityName: string): SeedDoor | undefined {
123
97
  let handler: Record<string, Function> | undefined;
124
98
  try { handler = app.resolve<Record<string, Function>>(facadeKeyOf(entityName)); } catch {}
@@ -126,26 +100,21 @@ function doorFor(app: App, entityName: string): SeedDoor | undefined {
126
100
  if (typeof handler?.list === 'function' && typeof handler.create === 'function') {
127
101
  return {
128
102
  list: () => handler!.list() as Promise<unknown[]>,
129
- write: (item) => handler!.create({ params: {}, query: {}, body: item, state: {} }),
103
+ write: (item) => handler!.create({ params: {}, query: {}, input: item, state: {} }),
130
104
  };
131
105
  }
132
106
 
133
- const orm = app.ormFor(entityName) as
107
+ const storage = app.storageFor(entityName) as
134
108
  | { list: () => Promise<unknown[]>; create: (input: unknown) => Promise<unknown> }
135
109
  | undefined;
136
- if (!orm) return undefined;
110
+ if (!storage) return undefined;
137
111
 
138
- return { list: () => orm.list(), write: (item) => orm.create(item) };
112
+ return { list: () => storage.list(), write: (item) => storage.create(item) };
139
113
  }
140
114
 
141
115
  /**
142
- * The framework's own ascent for rows, named — so a host can REPLACE it rather than take
143
- * over the whole post-boot to get its own.
144
- *
145
- * That is what Nuxt's Nitro plugin had to do: a bundler needs its seed modules spelled out
146
- * as static imports, so the plugin claimed everything after the boot and its copy of the
147
- * loop drifted. It now declares an extension under this same name instead, and the delta
148
- * is one member of a list.
116
+ * The framework's own ascent for rows, named — so a host can REPLACE it rather than take over the
117
+ * whole post-boot to get its own.
149
118
  */
150
119
  export function seeding(report?: (message: string) => void): Extension {
151
120
  return {
@@ -1,35 +1,17 @@
1
- /**
2
- * Where a STATED contract and the signature it is about have stopped agreeing.
3
- *
4
- * `frond.config.ts` states an operation's contract and wins over the scan — that order is
5
- * deliberate, and it is the only answer for a method inherited from an installed base class
6
- * the workspace scan cannot see. But winning silently is how a statement made about
7
- * `publish(id: string)` keeps applying after the parameter was renamed to `postId`: the
8
- * façade binds what the config said, the method receives `undefined`, and nothing anywhere
9
- * says the two disagree.
10
- *
11
- * So this compares, and only where BOTH exist — a statement about a signature the scan
12
- * never read is not drift, it is the case config was built for. It is a `warning` and not
13
- * a refusal: the statement is still the author's word, and a boot that ran yesterday must
14
- * not stop running because a parameter moved. What it must not do is stay quiet.
15
- */
16
- import type { FrondDescriptor, HandlerEntry, ScanDiagnostic } from '../scan/frond.js';
17
- import type { BindingPlan } from './binding.js';
18
- import type { ParsedMethod } from '../scan/handler-parser.js';
19
-
20
- /** The parameters a stated binding names, against the ones the method declares. */
21
- function namesDisagreeing(stated: BindingPlan, signature: ParsedMethod): string[] {
1
+ /** Where a STATED contract and the signature it is about have stopped agreeing. */
2
+ import type { FrondDescriptor, HandlerEntry } from '../descriptor/frond.js';
3
+ import type { ScanDiagnostic } from '../scan/result.js';
4
+ import type { BindingPlan } from '../wire/binding.js';
5
+ import type { Signature } from '../wire/signature.js';
6
+
7
+ /** The parameters a binding plan names, against the ones the method declares. */
8
+ function namesDisagreeing(plan: BindingPlan, signature: Signature): string[] {
22
9
  const declared = new Set(signature.params.map((p: { name: string }) => p.name));
23
10
 
24
- return stated.map((b) => b.name).filter((name) => !declared.has(name));
11
+ return plan.map((b) => b.name).filter((name) => !declared.has(name));
25
12
  }
26
13
 
27
- /**
28
- * What a frond's stated contracts no longer match.
29
- *
30
- * Read by `resolveEffectiveOperations`, so the same answer reaches `fougere check` and a
31
- * boot — one comparison, two readers, no second opinion to drift on its own.
32
- */
14
+ /** What a frond's stated contracts no longer match. */
33
15
  export function statementDrift(frond: FrondDescriptor, handler: HandlerEntry): ScanDiagnostic[] {
34
16
  const found: ScanDiagnostic[] = [];
35
17