@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
@@ -1,9 +1,9 @@
1
- import {
2
- resolveArgs,
3
- type BindingPlan,
4
- type CollectorResolver,
5
- } from '../boot/binding.js';
6
- import type { InvocationContext } from '../contract/Invocation.js';
1
+ import type { InvocationContext } from '../wire/Invocation.js';
2
+ import type { BindingPlan } from '../wire/binding.js';
3
+
4
+ export interface CollectorResolver {
5
+ collect(ctx: InvocationContext): Promise<unknown>;
6
+ }
7
7
 
8
8
  export type CollectorLookup = (typeName: string) => CollectorResolver | undefined;
9
9
 
@@ -11,7 +11,53 @@ export type CollectorLookup = (typeName: string) => CollectorResolver | undefine
11
11
  export class ArgumentResolver {
12
12
  constructor(private readonly collectors?: CollectorLookup) {}
13
13
 
14
- resolve(plan: BindingPlan, invocation: InvocationContext): Promise<unknown[]> {
15
- return resolveArgs(plan, invocation, this.collectors);
14
+ async resolve(plan: BindingPlan, ctx: InvocationContext): Promise<unknown[]> {
15
+ const args: unknown[] = [];
16
+
17
+ for (const binding of plan) {
18
+ switch (binding.source.kind) {
19
+ case 'collector': {
20
+ const collector = this.collectors?.(binding.source.typeName);
21
+ args.push(collector ? await collector.collect(ctx) : undefined);
22
+ break;
23
+ }
24
+ case 'context': {
25
+ args.push(ctx);
26
+ break;
27
+ }
28
+ case 'param': {
29
+ // `null` is a value, not a miss. Nullish coalescing used to make an explicit
30
+ // nullable path/GraphQL argument fall through to query (or become undefined),
31
+ // collapsing `T | null` into `T | undefined`. Only undefined means absent.
32
+ const fromParams = ctx.params[binding.source.name];
33
+ let val: unknown = fromParams === undefined
34
+ ? ctx.query[binding.source.name]
35
+ : fromParams;
36
+ if (val != null && binding.source.coerce === 'number') val = Number(val);
37
+ if (val != null && binding.source.coerce === 'boolean') val = val === 'true' || val === '1' || val === true;
38
+ args.push(val);
39
+ break;
40
+ }
41
+ case 'fact': {
42
+ // A fact IS the payload — the whole of what happened, never a piece of it.
43
+ // Identical to `input` today, and deliberately not sharing its branch: the two
44
+ // agree by coincidence, not by rule, and the day `input` learns to look up a
45
+ // value by parameter name a subscriber would receive ONE FIELD of the fact it
46
+ // subscribed to. Splitting it costs nothing and removes that trap.
47
+ args.push(ctx.input);
48
+ break;
49
+ }
50
+ case 'input': {
51
+ args.push(ctx.input);
52
+ break;
53
+ }
54
+ case 'query': {
55
+ args.push(ctx.query);
56
+ break;
57
+ }
58
+ }
59
+ }
60
+
61
+ return args;
16
62
  }
17
63
  }
@@ -1,5 +1,5 @@
1
- import type { Call } from '../contract/Call.js';
2
- import type { RouteKind } from './Route.js';
1
+ import type { Call } from '../wire/call.js';
2
+ import type { RouteKind } from '../wire/RouteAddress.js';
3
3
 
4
4
  export type DispatchStage = 'received' | 'resolved' | 'completed' | 'failed' | 'settled';
5
5
 
@@ -11,13 +11,7 @@ export class DispatchLifecycle {
11
11
  this.observers = [...observers];
12
12
  }
13
13
 
14
- /**
15
- * Subscribe after the dispatcher was built, and get the unsubscription back.
16
- *
17
- * The list used to be settled at construction, so only the caller of `createApp` could
18
- * observe — an extension, which runs in `up(app)`, could not. `app.use` already adds a
19
- * middleware this late; this is its dual, and the pair is *participate* / *watch*.
20
- */
14
+ /** Subscribe after the dispatcher was built, and get the unsubscription back. */
21
15
  add(observer: DispatchObserver): () => void {
22
16
  this.observers.push(observer);
23
17
 
@@ -1,4 +1,4 @@
1
- import type { Call } from '../contract/Call.js';
1
+ import type { Call } from '../wire/call.js';
2
2
 
3
3
  /** The only capability an entry needs. */
4
4
  export interface DispatchPort {
@@ -1,11 +1,11 @@
1
- import type { Call } from '../contract/Call.js';
1
+ import type { Call } from '../wire/call.js';
2
2
  import { DispatchEvent } from './DispatchEvent.js';
3
3
  import { DispatchLifecycle } from './DispatchLifecycle.js';
4
4
  import type { DispatchPort } from './DispatchPort.js';
5
5
  import type { Route } from './Route.js';
6
6
  import type { RoutePolicy } from './RoutePolicy.js';
7
7
  import { RouteRegistry } from './RouteRegistry.js';
8
- import { RouteNotFoundError } from './RouteNotFoundError.js';
8
+ import { routeNotFound, servedOperations } from './routeNotFound.js';
9
9
  import type { InFlight } from './InFlight.js';
10
10
 
11
11
  /** Resolves and executes every call through the same transverse lifecycle. */
@@ -29,7 +29,7 @@ export class Dispatcher implements DispatchPort {
29
29
  route = resolved && (!this.policy || this.policy.accepts(resolved)) ? resolved : undefined;
30
30
  if (!route) {
31
31
  throw this.policy?.notFound?.(call, this.routes.routes())
32
- ?? new RouteNotFoundError(call, this.routes.routes(), this.policy);
32
+ ?? routeNotFound(call, servedOperations(call, this.routes.routes(), this.policy));
33
33
  }
34
34
 
35
35
  this.lifecycle.publish(DispatchEvent.resolved(call, route.kind));
@@ -0,0 +1,231 @@
1
+ import type { Fields } from '@fougere/schema';
2
+ import type { Container } from '@fougere/container';
3
+ import {
4
+ runMiddlewares,
5
+ type AppMiddleware,
6
+ type OperationContext,
7
+ } from '../wire/middleware.js';
8
+ import type { CollectorResolver } from './ArgumentResolver.js';
9
+ import { collectorKeyOf } from '../prefab/collector.js';
10
+ import { inheritsCrud, subjectOf } from '../prefab/crud.js';
11
+ import { presenterKeyOf } from '../prefab/presenter.js';
12
+ import { repositoryKeyOf } from '../prefab/repository.js';
13
+ import type { OperationContract, OperationsMap } from '../wire/operation.js';
14
+ import type { EffectiveOperation, EffectiveOperationsMap } from '../effective-operation.js';
15
+ import { canonicalInvocation, type InvocationContext } from '../wire/Invocation.js';
16
+ import type { HandlerEntry, PresenterEntry } from '../descriptor/frond.js';
17
+ import { ArgumentResolver } from './ArgumentResolver.js';
18
+ import { OutputView } from './OutputView.js';
19
+ import { PresenterExecutor } from './PresenterExecutor.js';
20
+ import { presenterArguments } from './presenterArguments.js';
21
+ import { validateInput } from './validateInput.js';
22
+
23
+ /** What boot resolved around one handler, beyond the handler and the scope it resolves in. */
24
+ export interface Door {
25
+ /** The container key this door answers under. */
26
+ key: string;
27
+ /** The frond this door belongs to — travels on every OperationContext. */
28
+ frond: string;
29
+ /** Handlers in the owning frond, used to realize a resolved implementation override. */
30
+ handlers: readonly HandlerEntry[];
31
+ /** The canonical operation table resolved before boot performs any side effect. */
32
+ operations: EffectiveOperationsMap;
33
+ /** Entity names this frond has a collector for. */
34
+ collectors: Set<string>;
35
+ /** The presenter over this handler's entity, when the frond declares one. */
36
+ presenter: PresenterEntry | undefined;
37
+ /** Presenters live in the frond's own scope, whatever sub-scope this door resolves in. */
38
+ presenterScope: Container;
39
+ /** The middlewares that apply to this address, read at call time and never at boot. */
40
+ middlewares: () => AppMiddleware[];
41
+ }
42
+
43
+ /** Adapts one handler door to executable operations. */
44
+ export class HandlerFacade {
45
+ /** Rich operation facts shared with check, explain and adapters. */
46
+ readonly effectiveOperations: EffectiveOperationsMap;
47
+ /** Contracts served by this door. */
48
+ readonly contracts: OperationsMap;
49
+
50
+ private readonly cachedViews = new Map<string, OutputView>();
51
+ private instance: any;
52
+ private readonly implementationKeys = new Map<string, string>();
53
+ private readonly implementationInstances = new Map<string, any>();
54
+ private readonly arguments = new ArgumentResolver(
55
+ (typeName) => this.collectorResolver(typeName),
56
+ );
57
+
58
+ constructor(
59
+ private readonly handler: HandlerEntry,
60
+ private readonly scope: Container,
61
+ private readonly door: Door,
62
+ ) {
63
+ this.refuseCrudWithoutRepository(handler);
64
+
65
+ scope.register(this.handlerKey, handler.ctor, { deps: this.depsOf(handler) });
66
+
67
+ this.effectiveOperations = door.operations;
68
+ this.contracts = new Map(
69
+ [...door.operations].map(([name, operation]) => [name, operation as OperationContract] as const),
70
+ );
71
+ handler.operations = this.contracts;
72
+
73
+ // Register model-selected implementations in the same execution scope.
74
+ for (const [name, operation] of door.operations) {
75
+ if (this.isBaseImplementation(operation)) continue;
76
+ const implementation = this.implementationHandler(name);
77
+ this.refuseCrudWithoutRepository(implementation);
78
+ const key = `${this.handlerKey}:implementation:${operation.implementation.className}`;
79
+ if (!this.implementationKeys.has(operation.implementation.className)) {
80
+ scope.register(key, implementation.ctor, { deps: this.depsOf(implementation) });
81
+ this.implementationKeys.set(operation.implementation.className, key);
82
+ }
83
+ }
84
+ }
85
+
86
+ /** One operation, through the same ordered boundary steps on every route. */
87
+ async execute(op: string, input?: Partial<InvocationContext>): Promise<unknown> {
88
+ const entity = this.handler.address;
89
+ const contract = this.contracts.get(op);
90
+ if (!contract) {
91
+ throw new Error(
92
+ `${entity} serves no operation '${op}'. `
93
+ + `It serves ${[...this.contracts.keys()].join(', ')}.`,
94
+ );
95
+ }
96
+
97
+ const invocation = canonicalInvocation(input);
98
+ const context: OperationContext = {
99
+ entity,
100
+ frond: this.door.frond,
101
+ operation: op,
102
+ args: [],
103
+ state: invocation.state,
104
+ invocation,
105
+ };
106
+
107
+ return runMiddlewares(this.door.middlewares(), context, async () => {
108
+ const validated = validateInput(contract.input, invocation, entity, op);
109
+ context.invocation = validated;
110
+
111
+ const args = contract.binding
112
+ ? await this.arguments.resolve(contract.binding, validated)
113
+ : [];
114
+ const { instance, method } = this.resolveImplementation(op);
115
+ const view = this.viewOf(op);
116
+ const output = view.project(await instance[method](...args));
117
+
118
+ const { presenter } = this.door;
119
+ return view.closed || !presenter ? output : this.present(op, presenter, output, validated);
120
+ });
121
+ }
122
+
123
+ /** The computed fields a presenter adds, over the page the façade just projected. */
124
+ private present(
125
+ op: string,
126
+ presenter: PresenterEntry,
127
+ output: unknown,
128
+ invocation: InvocationContext,
129
+ ): Promise<unknown> {
130
+ const entity = this.handler.address;
131
+ const executor = new PresenterExecutor(
132
+ this.door.presenterScope.resolve(presenterKeyOf(entity)),
133
+ presenter.fields,
134
+ entity,
135
+ op,
136
+ );
137
+
138
+ return presenterArguments(presenter, invocation, this.arguments, this.door.collectors)
139
+ .then((args) => executor.present(output, args));
140
+ }
141
+
142
+ private get handlerKey(): string {
143
+ return `_handler:${this.door.key}`;
144
+ }
145
+
146
+ private depsOf(handler: HandlerEntry): string[] {
147
+ const { deps } = handler;
148
+ if (deps.length > 0) return deps;
149
+
150
+ return inheritsCrud(handler.ctor)
151
+ ? [repositoryKeyOf(subjectOf(handler.ctor, handler.address))]
152
+ : [];
153
+ }
154
+
155
+ /** A custom Crud constructor must explicitly receive its repository. */
156
+ private refuseCrudWithoutRepository(handler: HandlerEntry): void {
157
+ const repoTypeName = repositoryKeyOf(subjectOf(handler.ctor, handler.address));
158
+ if (!inheritsCrud(handler.ctor) || handler.deps.length === 0 || handler.deps.includes(repoTypeName)) return;
159
+ throw new Error(
160
+ `${handler.ctor.name} extends Crud() and declares a constructor, so its storage is no ` +
161
+ `longer injected for it — but it does not take any.\n` +
162
+ ` Add it and hand it to super():\n` +
163
+ ` constructor(repo: ${repoTypeName}, …) { super(repo); }`,
164
+ );
165
+ }
166
+
167
+ /** Resolve and cache the output view declared for one operation. */
168
+ private viewOf(op: string): OutputView {
169
+ const known = this.cachedViews.get(op);
170
+ if (known) return known;
171
+
172
+ const operation = this.effectiveOperations.get(op);
173
+ const schema = operation?.output as { getFields?: () => Fields } | undefined;
174
+ const resolved = new OutputView(
175
+ typeof schema?.getFields === 'function' ? schema.getFields() : {},
176
+ operation?.outputClosed ?? false,
177
+ );
178
+ this.cachedViews.set(op, resolved);
179
+ return resolved;
180
+ }
181
+
182
+ private collectorResolver = (typeName: string): CollectorResolver | undefined => {
183
+ try { return this.scope.resolve(collectorKeyOf(typeName)) as CollectorResolver; }
184
+ catch { return undefined; }
185
+ };
186
+
187
+ /** The handler itself, resolved on first call — never at boot. */
188
+ private resolveHandler(): any {
189
+ if (!this.instance) this.instance = this.scope.resolve(this.handlerKey);
190
+ return this.instance;
191
+ }
192
+
193
+ private isBaseImplementation(operation: EffectiveOperation): boolean {
194
+ return operation.implementation.className === this.handler.ctor.name
195
+ && operation.implementation.address === this.handler.address
196
+ && operation.implementation.filePath === this.handler.filePath;
197
+ }
198
+
199
+ /** The exact handler entry the pure model selected; no name-only retry or fallback. */
200
+ private implementationHandler(operationName: string): HandlerEntry {
201
+ const operation = this.effectiveOperations.get(operationName)!;
202
+ const matches = this.door.handlers.filter((handler) =>
203
+ handler.ctor.name === operation.implementation.className
204
+ && handler.address === operation.implementation.address
205
+ && handler.filePath === operation.implementation.filePath);
206
+ if (matches.length !== 1) {
207
+ throw new Error(
208
+ `EffectiveOperation '${operation.id}' names ${operation.implementation.className}.`
209
+ + `${operation.implementation.method}, but boot found ${matches.length} matching handlers.`,
210
+ );
211
+ }
212
+ return matches[0]!;
213
+ }
214
+
215
+ private resolveImplementation(operationName: string): { instance: any; method: string } {
216
+ const operation = this.effectiveOperations.get(operationName)!;
217
+ if (this.isBaseImplementation(operation)) {
218
+ return { instance: this.resolveHandler(), method: operation.implementation.method };
219
+ }
220
+
221
+ const className = operation.implementation.className;
222
+ const key = this.implementationKeys.get(className);
223
+ if (!key) throw new Error(`No registered implementation for EffectiveOperation '${operation.id}'.`);
224
+ let instance = this.implementationInstances.get(key);
225
+ if (!instance) {
226
+ instance = this.scope.resolve(key);
227
+ this.implementationInstances.set(key, instance);
228
+ }
229
+ return { instance, method: operation.implementation.method };
230
+ }
231
+ }
@@ -1,8 +1,8 @@
1
- import type { Call } from '../contract/Call.js';
1
+ import type { Call } from '../wire/call.js';
2
2
  import { ErrorCode, FougereError } from '../wire/errors.js';
3
3
  import type { Route } from './Route.js';
4
4
  import type { RoutePolicy } from './RoutePolicy.js';
5
- import { RouteNotFoundError } from './RouteNotFoundError.js';
5
+ import { routeNotFound, servedOperations } from './routeNotFound.js';
6
6
 
7
7
  /** Incoming calls may execute here but never forward to another host. */
8
8
  export class LocalRoutePolicy implements RoutePolicy {
@@ -15,8 +15,8 @@ export class LocalRoutePolicy implements RoutePolicy {
15
15
  notFound(call: Call, routes: readonly Route[]): Error | undefined {
16
16
  if (call.address.entity === 'rpc') return undefined;
17
17
 
18
- const unknownRoute = new RouteNotFoundError(call, routes, this);
19
- if (unknownRoute.servedOperations.length > 0) return unknownRoute;
18
+ const served = servedOperations(call, routes, this);
19
+ if (served.length > 0) return routeNotFound(call, served);
20
20
 
21
21
  const hosted = this.hostedNames(call.address.surface);
22
22
  const entity = call.address.entity;
@@ -1,5 +1,5 @@
1
- import type { Call } from '../contract/Call.js';
2
- import type { RouteAddress } from '../contract/RouteAddress.js';
1
+ import type { Call } from '../wire/call.js';
2
+ import type { RouteAddress } from '../wire/RouteAddress.js';
3
3
  import type { Route } from './Route.js';
4
4
 
5
5
  export type RouteExecution = (call: Call) => unknown | Promise<unknown>;
@@ -1,9 +1,31 @@
1
- import type { Fields } from '@fougere/schema';
1
+ import { Visibility, type Fields } from '@fougere/schema';
2
+ import { preserveArrayProperties } from './ArrayResult.js';
2
3
 
3
- /** Immutable projection boundary of one operation result. */
4
+ /** What one operation result may show. One of the two exits a validator watches. */
4
5
  export class OutputView {
5
6
  constructor(
6
7
  readonly fields: Fields,
7
8
  readonly closed = false,
8
9
  ) {}
10
+
11
+ project(result: unknown): unknown {
12
+ if (result === null || result === undefined) return result;
13
+
14
+ if (Array.isArray(result)) {
15
+ return preserveArrayProperties(result, result.map((item) => this.project(item)));
16
+ }
17
+
18
+ if (typeof result !== 'object') return result;
19
+
20
+ const record = result as Record<string, unknown>;
21
+ const scoped = this.closed
22
+ ? Object.fromEntries(
23
+ Object.keys(this.fields)
24
+ .filter((key) => key in record)
25
+ .map((key) => [key, record[key]]),
26
+ )
27
+ : record;
28
+
29
+ return Visibility.of(this.fields).encode(scoped);
30
+ }
9
31
  }
@@ -1,7 +1,5 @@
1
- import type { Call } from '../contract/Call.js';
2
- import type { RouteAddress } from '../contract/RouteAddress.js';
3
-
4
- export type RouteKind = 'local' | 'remote' | 'system';
1
+ import type { Call } from '../wire/call.js';
2
+ import type { RouteAddress, RouteKind } from '../wire/RouteAddress.js';
5
3
 
6
4
  /** Executable destination known by the dispatcher. */
7
5
  export interface Route {
@@ -1,4 +1,4 @@
1
- import type { Call } from '../contract/Call.js';
1
+ import type { Call } from '../wire/call.js';
2
2
  import type { Route } from './Route.js';
3
3
 
4
4
  /** Restricts which registered routes one dispatch capability may enter. */
@@ -1,4 +1,4 @@
1
- import { RouteAddress } from '../contract/RouteAddress.js';
1
+ import { RouteAddress } from '../wire/RouteAddress.js';
2
2
  import type { Route } from './Route.js';
3
3
  import type { RouteResolver } from './RouteResolver.js';
4
4
 
@@ -53,7 +53,7 @@ export class RouteRegistry {
53
53
 
54
54
  private async resolveUnknown(address: RouteAddress): Promise<Route | undefined> {
55
55
  for (const resolver of this.resolvers) {
56
- const route = await resolver.resolve(address);
56
+ const route = await resolver(address);
57
57
  if (!route) continue;
58
58
  this.register(route);
59
59
  return route;
@@ -1,7 +1,5 @@
1
- import type { RouteAddress } from '../contract/RouteAddress.js';
1
+ import type { RouteAddress } from '../wire/RouteAddress.js';
2
2
  import type { Route } from './Route.js';
3
3
 
4
4
  /** Resolves routes that cannot be known when the registry is built. */
5
- export interface RouteResolver {
6
- resolve(address: RouteAddress): Route | undefined | Promise<Route | undefined>;
7
- }
5
+ export type RouteResolver = (address: RouteAddress) => Route | undefined | Promise<Route | undefined>;
@@ -1,61 +1,111 @@
1
- import { ValueJudge, type Fields } from '@fougere/schema';
2
- import { assertListOptions } from '../orm.js';
1
+ import { Boundary, FieldSet, FieldValueValidator, InputRefusal, type Fields } from '@fougere/schema';
2
+ import { assertListOptions } from '../storage.js';
3
3
  import { ErrorCode, FougereError } from '../wire/errors.js';
4
4
 
5
+ /** The gestures this guard grafts onto. */
5
6
  interface Writer {
6
7
  create(...args: [Record<string, unknown>, ...unknown[]]): Promise<unknown>;
7
8
  update(...args: [unknown, Record<string, unknown>, ...unknown[]]): Promise<unknown>;
9
+ upsert?(...args: [Record<string, unknown>, ...unknown[]]): Promise<unknown>;
10
+ upsertAll?(...args: [readonly Record<string, unknown>[], ...unknown[]]): Promise<unknown>;
11
+ list?(...args: unknown[]): unknown;
8
12
  }
9
13
 
10
- /**
11
- * Judges storage writes and list options without narrowing the ORM interface.
12
- *
13
- * Storage is a way out like the client surface, so what goes to it is judged too — the
14
- * same rule `OutputProjector` applies on the other exit.
15
- */
14
+ /** Judges storage writes and list options without narrowing the storage interface. */
16
15
  export class StorageGuard {
17
16
  constructor(
18
17
  private readonly fields: Fields,
19
18
  private readonly entity: string,
20
19
  ) {}
21
20
 
22
- guard<T extends object>(orm: T): T {
23
- const writer = orm as unknown as Writer;
24
- if (typeof writer.create !== 'function' || typeof writer.update !== 'function') return orm;
21
+ guard<T extends object>(storage: T): T {
22
+ const writer = storage as unknown as Writer;
23
+ if (typeof writer.create !== 'function' || typeof writer.update !== 'function') return storage;
25
24
 
26
25
  const validation = this;
27
- const guarded = Object.create(orm) as T & Writer;
26
+ const guarded = Object.create(storage) as T & Writer;
28
27
 
29
28
  guarded.create = async function (...args) {
30
- validation.judge(args[0], 'create');
29
+ args[0] = validation.validated(args[0], 'create');
31
30
  return writer.create.apply(this, args);
32
31
  };
33
32
 
34
33
  guarded.update = async function (...args) {
35
- validation.judge(args[1], 'update');
34
+ args[1] = validation.validated(args[1], 'update');
36
35
  return writer.update.apply(this, args);
37
36
  };
38
37
 
39
- const reader = orm as unknown as { list?: (...args: unknown[]) => unknown };
40
- if (typeof reader.list === 'function') {
41
- (guarded as unknown as typeof reader).list = async function (...args: unknown[]) {
38
+ const upsert = writer.upsert;
39
+ if (typeof upsert === 'function') {
40
+ guarded.upsert = async function (...args) {
41
+ args[0] = validation.validated(args[0], 'upsert');
42
+ return upsert.apply(this, args);
43
+ };
44
+ }
45
+
46
+ const upsertAll = writer.upsertAll;
47
+ if (typeof upsertAll === 'function') {
48
+ // Every row before the first write: a page refused halfway leaves rows behind that
49
+ // the caller asked for as one, and the refusal is readable from the input alone.
50
+ guarded.upsertAll = async function (...args) {
51
+ args[0] = args[0].map((row, index) => validation.validated(row, 'upsertAll', index));
52
+ return upsertAll.apply(this, args);
53
+ };
54
+ }
55
+
56
+ const list = writer.list;
57
+ if (typeof list === 'function') {
58
+ guarded.list = async function (...args: unknown[]) {
42
59
  assertListOptions(args[0] as object | undefined, validation.entity);
43
- return (reader.list as Function).apply(this, args);
60
+ return list.apply(this, args);
44
61
  };
45
62
  }
46
63
 
47
64
  return guarded;
48
65
  }
49
66
 
50
- private judge(value: unknown, operation: string): void {
51
- if (typeof value !== 'object' || value === null) return;
67
+ /**
68
+ * The values this write carries, validated and handed on PARSED — the rule the client door
69
+ * already holds (`InputValidator`), applied to a write that never passed through it. What a
70
+ * handler is allowed to write is not asked here: only the value is.
71
+ */
72
+ private rowAt(row: unknown, index: number): string {
73
+ const primary = FieldSet.of(this.fields).primary;
74
+ const key = primary === undefined ? undefined : (row as Record<string, unknown>)[primary];
75
+ return key === undefined ? `row ${index} of this page` : `row ${primary} ${JSON.stringify(key)}`;
76
+ }
77
+
78
+ private validated<T>(value: T, operation: string, index?: number): T {
79
+ if (typeof value !== 'object' || value === null) return value;
52
80
 
53
81
  const errors: string[] = [];
82
+ const where = index === undefined ? '' : `${this.rowAt(value, index)} — `;
83
+ const parsed: Record<string, unknown> = {};
84
+
54
85
  for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
55
86
  const field = this.fields[key];
56
- if (!field || item === undefined) continue;
57
- const checked = ValueJudge.of(field).check(item);
58
- if ('error' in checked) errors.push(`${key}: ${checked.error}`);
87
+ // A key the entity does not declare has no column to land in and no judge to pass:
88
+ // on the client door it is a typo, and on this one it is a mapping that went stale.
89
+ if (!field) {
90
+ errors.push(`${where}${key}: ${InputRefusal.unknownField}`);
91
+ continue;
92
+ }
93
+ if (item === undefined) {
94
+ parsed[key] = item;
95
+ continue;
96
+ }
97
+ const checked = FieldValueValidator.of(field).validate(item);
98
+ if ('error' in checked) {
99
+ errors.push(`${where}${key}: ${checked.error}`);
100
+ continue;
101
+ }
102
+ if (checked.value === null) {
103
+ parsed[key] = null;
104
+ continue;
105
+ }
106
+ const decoded = Boundary.of(field).decode(checked.value);
107
+ if ('error' in decoded) errors.push(`${where}${key}: ${decoded.error}`);
108
+ else parsed[key] = decoded.value;
59
109
  }
60
110
 
61
111
  if (errors.length > 0) {
@@ -67,5 +117,7 @@ export class StorageGuard {
67
117
  details: errors,
68
118
  });
69
119
  }
120
+
121
+ return parsed as T;
70
122
  }
71
123
  }
@@ -0,0 +1,25 @@
1
+ import { computeBindingPlan } from '../wire/binding.js';
2
+ import type { InvocationContext } from '../wire/Invocation.js';
3
+ import type { PresenterEntry } from '../descriptor/frond.js';
4
+ import type { ArgumentResolver } from './ArgumentResolver.js';
5
+ import type { PresenterArgs } from './PresenterExecutor.js';
6
+
7
+ /** The invocation-dependent arguments of every computed presenter field. */
8
+ export async function presenterArguments(
9
+ meta: PresenterEntry,
10
+ invocation: InvocationContext,
11
+ resolver: ArgumentResolver,
12
+ collectorTypes: Set<string>,
13
+ ): Promise<PresenterArgs> {
14
+ const argumentsByField: PresenterArgs = {};
15
+
16
+ for (const field of meta.fieldMeta) {
17
+ if (!field.params?.length) continue;
18
+ argumentsByField[field.name] = await resolver.resolve(
19
+ computeBindingPlan(field.params, collectorTypes),
20
+ invocation,
21
+ );
22
+ }
23
+
24
+ return argumentsByField;
25
+ }