@fougere/core 0.2.0-alpha.2 → 0.4.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 (500) hide show
  1. package/README.md +3 -2
  2. package/dist/boot/AppLifecycle.d.ts +18 -0
  3. package/dist/boot/AppLifecycle.d.ts.map +1 -0
  4. package/dist/boot/AppLifecycle.js +42 -0
  5. package/dist/boot/AppLifecycle.js.map +1 -0
  6. package/dist/boot/Emissions.d.ts +126 -0
  7. package/dist/boot/Emissions.d.ts.map +1 -0
  8. package/dist/boot/Emissions.js +233 -0
  9. package/dist/boot/Emissions.js.map +1 -0
  10. package/dist/boot/HandlerFacade.d.ts +72 -0
  11. package/dist/boot/HandlerFacade.d.ts.map +1 -0
  12. package/dist/boot/HandlerFacade.js +174 -0
  13. package/dist/boot/HandlerFacade.js.map +1 -0
  14. package/dist/boot/Lifecycle.d.ts +4 -0
  15. package/dist/boot/Lifecycle.d.ts.map +1 -0
  16. package/dist/boot/Lifecycle.js +3 -0
  17. package/dist/boot/Lifecycle.js.map +1 -0
  18. package/dist/boot/ambient-port.d.ts +38 -0
  19. package/dist/boot/ambient-port.d.ts.map +1 -0
  20. package/dist/boot/ambient-port.js +2 -0
  21. package/dist/boot/ambient-port.js.map +1 -0
  22. package/dist/boot/ambient.als.d.ts +3 -0
  23. package/dist/boot/ambient.als.d.ts.map +1 -0
  24. package/dist/boot/ambient.als.js +34 -0
  25. package/dist/boot/ambient.als.js.map +1 -0
  26. package/dist/boot/ambient.queue.d.ts +10 -0
  27. package/dist/boot/ambient.queue.d.ts.map +1 -0
  28. package/dist/boot/ambient.queue.js +60 -0
  29. package/dist/boot/ambient.queue.js.map +1 -0
  30. package/dist/boot/apply.d.ts +22 -0
  31. package/dist/boot/apply.d.ts.map +1 -0
  32. package/dist/boot/apply.js +38 -0
  33. package/dist/boot/apply.js.map +1 -0
  34. package/dist/boot/auth.d.ts +53 -0
  35. package/dist/boot/auth.d.ts.map +1 -0
  36. package/dist/boot/auth.js +2 -0
  37. package/dist/boot/auth.js.map +1 -0
  38. package/dist/{binding.d.ts → boot/binding.d.ts} +14 -17
  39. package/dist/boot/binding.d.ts.map +1 -0
  40. package/dist/{binding.js → boot/binding.js} +19 -10
  41. package/dist/boot/binding.js.map +1 -0
  42. package/dist/{boot.d.ts → boot/boot.d.ts} +25 -5
  43. package/dist/boot/boot.d.ts.map +1 -0
  44. package/dist/boot/boot.js +70 -0
  45. package/dist/boot/boot.js.map +1 -0
  46. package/dist/boot/bootstrap.d.ts.map +1 -0
  47. package/dist/boot/bootstrap.js +722 -0
  48. package/dist/boot/bootstrap.js.map +1 -0
  49. package/dist/boot/frame.d.ts +44 -0
  50. package/dist/boot/frame.d.ts.map +1 -0
  51. package/dist/boot/frame.js +172 -0
  52. package/dist/boot/frame.js.map +1 -0
  53. package/dist/boot/ownership.d.ts +42 -0
  54. package/dist/boot/ownership.d.ts.map +1 -0
  55. package/dist/boot/ownership.js +127 -0
  56. package/dist/boot/ownership.js.map +1 -0
  57. package/dist/boot/ports.d.ts +17 -0
  58. package/dist/boot/ports.d.ts.map +1 -0
  59. package/dist/boot/ports.js +57 -0
  60. package/dist/boot/ports.js.map +1 -0
  61. package/dist/{remote.d.ts → boot/remote.d.ts} +11 -3
  62. package/dist/boot/remote.d.ts.map +1 -0
  63. package/dist/{remote.js → boot/remote.js} +26 -28
  64. package/dist/boot/remote.js.map +1 -0
  65. package/dist/{seed.d.ts → boot/seed.d.ts} +13 -1
  66. package/dist/boot/seed.d.ts.map +1 -0
  67. package/dist/{seed.js → boot/seed.js} +24 -3
  68. package/dist/boot/seed.js.map +1 -0
  69. package/dist/boot/together.d.ts +26 -0
  70. package/dist/boot/together.d.ts.map +1 -0
  71. package/dist/boot/together.js +163 -0
  72. package/dist/boot/together.js.map +1 -0
  73. package/dist/boot/types.d.ts +260 -0
  74. package/dist/boot/types.d.ts.map +1 -0
  75. package/dist/boot/types.js.map +1 -0
  76. package/dist/builtins/config.d.ts +9 -0
  77. package/dist/builtins/config.d.ts.map +1 -1
  78. package/dist/builtins/config.js +16 -1
  79. package/dist/builtins/config.js.map +1 -1
  80. package/dist/builtins/logger.d.ts +37 -4
  81. package/dist/builtins/logger.d.ts.map +1 -1
  82. package/dist/builtins/logger.js +66 -7
  83. package/dist/builtins/logger.js.map +1 -1
  84. package/dist/config-loader.d.ts +39 -35
  85. package/dist/config-loader.d.ts.map +1 -1
  86. package/dist/config-loader.js +15 -54
  87. package/dist/config-loader.js.map +1 -1
  88. package/dist/contract/Call.d.ts +10 -0
  89. package/dist/contract/Call.d.ts.map +1 -0
  90. package/dist/contract/Call.js +15 -0
  91. package/dist/contract/Call.js.map +1 -0
  92. package/dist/contract/Invocation.d.ts +27 -0
  93. package/dist/contract/Invocation.d.ts.map +1 -0
  94. package/dist/contract/Invocation.js +59 -0
  95. package/dist/contract/Invocation.js.map +1 -0
  96. package/dist/contract/RouteAddress.d.ts +17 -0
  97. package/dist/contract/RouteAddress.d.ts.map +1 -0
  98. package/dist/contract/RouteAddress.js +38 -0
  99. package/dist/contract/RouteAddress.js.map +1 -0
  100. package/dist/contract.d.ts +25 -19
  101. package/dist/contract.d.ts.map +1 -1
  102. package/dist/contract.js +25 -10
  103. package/dist/contract.js.map +1 -1
  104. package/dist/crypto/encoding.d.ts +25 -0
  105. package/dist/crypto/encoding.d.ts.map +1 -0
  106. package/dist/crypto/encoding.js +58 -0
  107. package/dist/crypto/encoding.js.map +1 -0
  108. package/dist/crypto/node.d.ts +4 -0
  109. package/dist/crypto/node.d.ts.map +1 -0
  110. package/dist/crypto/node.js +25 -0
  111. package/dist/crypto/node.js.map +1 -0
  112. package/dist/crypto/port.d.ts +42 -0
  113. package/dist/crypto/port.d.ts.map +1 -0
  114. package/dist/crypto/port.js +19 -0
  115. package/dist/crypto/port.js.map +1 -0
  116. package/dist/crypto/webcrypto.d.ts +4 -0
  117. package/dist/crypto/webcrypto.d.ts.map +1 -0
  118. package/dist/crypto/webcrypto.js +34 -0
  119. package/dist/crypto/webcrypto.js.map +1 -0
  120. package/dist/dispatch/ArgumentResolver.d.ts +10 -0
  121. package/dist/dispatch/ArgumentResolver.d.ts.map +1 -0
  122. package/dist/dispatch/ArgumentResolver.js +12 -0
  123. package/dist/dispatch/ArgumentResolver.js.map +1 -0
  124. package/dist/dispatch/ArrayResult.d.ts +3 -0
  125. package/dist/dispatch/ArrayResult.d.ts.map +1 -0
  126. package/dist/dispatch/ArrayResult.js +11 -0
  127. package/dist/dispatch/ArrayResult.js.map +1 -0
  128. package/dist/dispatch/DispatchEvent.d.ts +18 -0
  129. package/dist/dispatch/DispatchEvent.d.ts.map +1 -0
  130. package/dist/dispatch/DispatchEvent.js +30 -0
  131. package/dist/dispatch/DispatchEvent.js.map +1 -0
  132. package/dist/dispatch/DispatchLifecycle.d.ts +9 -0
  133. package/dist/dispatch/DispatchLifecycle.d.ts.map +1 -0
  134. package/dist/dispatch/DispatchLifecycle.js +25 -0
  135. package/dist/dispatch/DispatchLifecycle.js.map +1 -0
  136. package/dist/dispatch/DispatchPort.d.ts +6 -0
  137. package/dist/dispatch/DispatchPort.d.ts.map +1 -0
  138. package/dist/dispatch/DispatchPort.js +2 -0
  139. package/dist/dispatch/DispatchPort.js.map +1 -0
  140. package/dist/dispatch/Dispatcher.d.ts +16 -0
  141. package/dist/dispatch/Dispatcher.d.ts.map +1 -0
  142. package/dist/dispatch/Dispatcher.js +44 -0
  143. package/dist/dispatch/Dispatcher.js.map +1 -0
  144. package/dist/dispatch/InFlight.d.ts +12 -0
  145. package/dist/dispatch/InFlight.d.ts.map +1 -0
  146. package/dist/dispatch/InFlight.js +46 -0
  147. package/dist/dispatch/InFlight.js.map +1 -0
  148. package/dist/dispatch/InputValidator.d.ts +7 -0
  149. package/dist/dispatch/InputValidator.d.ts.map +1 -0
  150. package/dist/dispatch/InputValidator.js +22 -0
  151. package/dist/dispatch/InputValidator.js.map +1 -0
  152. package/dist/dispatch/LocalRoutePolicy.d.ts +11 -0
  153. package/dist/dispatch/LocalRoutePolicy.d.ts.map +1 -0
  154. package/dist/dispatch/LocalRoutePolicy.js +32 -0
  155. package/dist/dispatch/LocalRoutePolicy.js.map +1 -0
  156. package/dist/dispatch/OperationExecutor.d.ts +25 -0
  157. package/dist/dispatch/OperationExecutor.d.ts.map +1 -0
  158. package/dist/dispatch/OperationExecutor.js +32 -0
  159. package/dist/dispatch/OperationExecutor.js.map +1 -0
  160. package/dist/dispatch/OperationRoute.d.ts +13 -0
  161. package/dist/dispatch/OperationRoute.d.ts.map +1 -0
  162. package/dist/dispatch/OperationRoute.js +15 -0
  163. package/dist/dispatch/OperationRoute.js.map +1 -0
  164. package/dist/dispatch/OutputProjector.d.ts +12 -0
  165. package/dist/dispatch/OutputProjector.d.ts.map +1 -0
  166. package/dist/dispatch/OutputProjector.js +30 -0
  167. package/dist/dispatch/OutputProjector.js.map +1 -0
  168. package/dist/dispatch/OutputView.d.ts +8 -0
  169. package/dist/dispatch/OutputView.d.ts.map +1 -0
  170. package/dist/dispatch/OutputView.js +10 -0
  171. package/dist/dispatch/OutputView.js.map +1 -0
  172. package/dist/dispatch/PresenterArgumentResolver.d.ts +12 -0
  173. package/dist/dispatch/PresenterArgumentResolver.d.ts.map +1 -0
  174. package/dist/dispatch/PresenterArgumentResolver.js +20 -0
  175. package/dist/dispatch/PresenterArgumentResolver.js.map +1 -0
  176. package/dist/dispatch/PresenterExecutor.d.ts +11 -0
  177. package/dist/dispatch/PresenterExecutor.d.ts.map +1 -0
  178. package/dist/dispatch/PresenterExecutor.js +56 -0
  179. package/dist/dispatch/PresenterExecutor.js.map +1 -0
  180. package/dist/dispatch/RemoteRouteResolver.d.ts +13 -0
  181. package/dist/dispatch/RemoteRouteResolver.d.ts.map +1 -0
  182. package/dist/dispatch/RemoteRouteResolver.js +18 -0
  183. package/dist/dispatch/RemoteRouteResolver.js.map +1 -0
  184. package/dist/dispatch/Route.d.ts +10 -0
  185. package/dist/dispatch/Route.d.ts.map +1 -0
  186. package/dist/dispatch/Route.js +2 -0
  187. package/dist/dispatch/Route.js.map +1 -0
  188. package/dist/dispatch/RouteNotFoundError.d.ts +10 -0
  189. package/dist/dispatch/RouteNotFoundError.d.ts.map +1 -0
  190. package/dist/dispatch/RouteNotFoundError.js +24 -0
  191. package/dist/dispatch/RouteNotFoundError.js.map +1 -0
  192. package/dist/dispatch/RoutePolicy.d.ts +8 -0
  193. package/dist/dispatch/RoutePolicy.d.ts.map +1 -0
  194. package/dist/dispatch/RoutePolicy.js +2 -0
  195. package/dist/dispatch/RoutePolicy.js.map +1 -0
  196. package/dist/dispatch/RouteRegistry.d.ts +18 -0
  197. package/dist/dispatch/RouteRegistry.d.ts.map +1 -0
  198. package/dist/dispatch/RouteRegistry.js +62 -0
  199. package/dist/dispatch/RouteRegistry.js.map +1 -0
  200. package/dist/dispatch/RouteResolver.d.ts +7 -0
  201. package/dist/dispatch/RouteResolver.d.ts.map +1 -0
  202. package/dist/dispatch/RouteResolver.js +2 -0
  203. package/dist/dispatch/RouteResolver.js.map +1 -0
  204. package/dist/dispatch/StorageGuard.d.ts +15 -0
  205. package/dist/dispatch/StorageGuard.d.ts.map +1 -0
  206. package/dist/dispatch/StorageGuard.js +63 -0
  207. package/dist/dispatch/StorageGuard.js.map +1 -0
  208. package/dist/effective-operation.d.ts +90 -0
  209. package/dist/effective-operation.d.ts.map +1 -0
  210. package/dist/effective-operation.js +449 -0
  211. package/dist/effective-operation.js.map +1 -0
  212. package/dist/emit.d.ts +2 -2
  213. package/dist/emit.d.ts.map +1 -1
  214. package/dist/emit.js +2 -2
  215. package/dist/emit.js.map +1 -1
  216. package/dist/entry/DynamicFacade.d.ts +10 -0
  217. package/dist/entry/DynamicFacade.d.ts.map +1 -0
  218. package/dist/entry/DynamicFacade.js +27 -0
  219. package/dist/entry/DynamicFacade.js.map +1 -0
  220. package/dist/entry/FacadeEntry.d.ts +11 -0
  221. package/dist/entry/FacadeEntry.d.ts.map +1 -0
  222. package/dist/entry/FacadeEntry.js +26 -0
  223. package/dist/entry/FacadeEntry.js.map +1 -0
  224. package/dist/entry/TransportEntry.d.ts +13 -0
  225. package/dist/entry/TransportEntry.d.ts.map +1 -0
  226. package/dist/entry/TransportEntry.js +24 -0
  227. package/dist/entry/TransportEntry.js.map +1 -0
  228. package/dist/frond-config.d.ts +24 -7
  229. package/dist/frond-config.d.ts.map +1 -1
  230. package/dist/frond-config.js.map +1 -1
  231. package/dist/graph.d.ts +1 -1
  232. package/dist/graph.d.ts.map +1 -1
  233. package/dist/graph.js +3 -2
  234. package/dist/graph.js.map +1 -1
  235. package/dist/identity-keys.d.ts +14 -0
  236. package/dist/identity-keys.d.ts.map +1 -0
  237. package/dist/identity-keys.js +37 -0
  238. package/dist/identity-keys.js.map +1 -0
  239. package/dist/identity.d.ts +58 -0
  240. package/dist/identity.d.ts.map +1 -0
  241. package/dist/identity.js +182 -0
  242. package/dist/identity.js.map +1 -0
  243. package/dist/imports.d.ts +2 -2
  244. package/dist/imports.d.ts.map +1 -1
  245. package/dist/imports.js +7 -3
  246. package/dist/imports.js.map +1 -1
  247. package/dist/index.d.ts +57 -38
  248. package/dist/index.d.ts.map +1 -1
  249. package/dist/index.js +38 -32
  250. package/dist/index.js.map +1 -1
  251. package/dist/loader.d.ts +16 -0
  252. package/dist/loader.d.ts.map +1 -0
  253. package/dist/loader.js +25 -0
  254. package/dist/loader.js.map +1 -0
  255. package/dist/node.d.ts +21 -0
  256. package/dist/node.d.ts.map +1 -0
  257. package/dist/node.js +24 -0
  258. package/dist/node.js.map +1 -0
  259. package/dist/orm.d.ts +69 -8
  260. package/dist/orm.d.ts.map +1 -1
  261. package/dist/orm.js +35 -2
  262. package/dist/orm.js.map +1 -1
  263. package/dist/prefab/collector.d.ts +29 -0
  264. package/dist/prefab/collector.d.ts.map +1 -0
  265. package/dist/prefab/collector.js +34 -0
  266. package/dist/prefab/collector.js.map +1 -0
  267. package/dist/{crud.d.ts → prefab/crud.d.ts} +7 -8
  268. package/dist/prefab/crud.d.ts.map +1 -0
  269. package/dist/{crud.js → prefab/crud.js} +39 -5
  270. package/dist/prefab/crud.js.map +1 -0
  271. package/dist/prefab/mirror.d.ts +52 -0
  272. package/dist/prefab/mirror.d.ts.map +1 -0
  273. package/dist/prefab/mirror.js +66 -0
  274. package/dist/prefab/mirror.js.map +1 -0
  275. package/dist/prefab/prefab.d.ts +15 -0
  276. package/dist/prefab/prefab.d.ts.map +1 -0
  277. package/dist/prefab/prefab.js +19 -0
  278. package/dist/prefab/prefab.js.map +1 -0
  279. package/dist/{presenter.d.ts → prefab/presenter.d.ts} +6 -17
  280. package/dist/prefab/presenter.d.ts.map +1 -0
  281. package/dist/{presenter.js → prefab/presenter.js} +5 -23
  282. package/dist/prefab/presenter.js.map +1 -0
  283. package/dist/prefab/repository.d.ts +104 -0
  284. package/dist/prefab/repository.d.ts.map +1 -0
  285. package/dist/prefab/repository.js +62 -0
  286. package/dist/prefab/repository.js.map +1 -0
  287. package/dist/scan/Fronds.d.ts +45 -0
  288. package/dist/scan/Fronds.d.ts.map +1 -0
  289. package/dist/scan/Fronds.js +66 -0
  290. package/dist/scan/Fronds.js.map +1 -0
  291. package/dist/scan/conventions.d.ts +74 -0
  292. package/dist/scan/conventions.d.ts.map +1 -0
  293. package/dist/scan/conventions.js +82 -0
  294. package/dist/scan/conventions.js.map +1 -0
  295. package/dist/scan/emit.d.ts +14 -0
  296. package/dist/scan/emit.d.ts.map +1 -0
  297. package/dist/scan/emit.js +212 -0
  298. package/dist/scan/emit.js.map +1 -0
  299. package/dist/scan/frond.d.ts +224 -0
  300. package/dist/scan/frond.d.ts.map +1 -0
  301. package/dist/scan/frond.js +2 -0
  302. package/dist/scan/frond.js.map +1 -0
  303. package/dist/{handler-parser.d.ts → scan/handler-parser.d.ts} +20 -9
  304. package/dist/scan/handler-parser.d.ts.map +1 -0
  305. package/dist/scan/handler-parser.js +665 -0
  306. package/dist/scan/handler-parser.js.map +1 -0
  307. package/dist/scan/scan-cache.d.ts +16 -0
  308. package/dist/scan/scan-cache.d.ts.map +1 -0
  309. package/dist/{scan-cache.js → scan/scan-cache.js} +27 -20
  310. package/dist/scan/scan-cache.js.map +1 -0
  311. package/dist/scan/scanner.d.ts +20 -0
  312. package/dist/scan/scanner.d.ts.map +1 -0
  313. package/dist/{scanner.js → scan/scanner.js} +212 -167
  314. package/dist/scan/scanner.js.map +1 -0
  315. package/dist/verify.d.ts +16 -3
  316. package/dist/verify.d.ts.map +1 -1
  317. package/dist/verify.js +21 -18
  318. package/dist/verify.js.map +1 -1
  319. package/dist/{call.d.ts → wire/call.d.ts} +76 -7
  320. package/dist/wire/call.d.ts.map +1 -0
  321. package/dist/{call.js → wire/call.js} +53 -80
  322. package/dist/wire/call.js.map +1 -0
  323. package/dist/{middleware.d.ts → wire/errors.d.ts} +18 -19
  324. package/dist/wire/errors.d.ts.map +1 -0
  325. package/dist/{middleware.js → wire/errors.js} +26 -14
  326. package/dist/wire/errors.js.map +1 -0
  327. package/dist/{errors.d.ts → wire/http-error.d.ts} +5 -6
  328. package/dist/wire/http-error.d.ts.map +1 -0
  329. package/dist/{errors.js → wire/http-error.js} +7 -6
  330. package/dist/wire/http-error.js.map +1 -0
  331. package/dist/wire/invocation.d.ts +4 -0
  332. package/dist/wire/invocation.d.ts.map +1 -0
  333. package/dist/wire/invocation.js +3 -0
  334. package/dist/wire/invocation.js.map +1 -0
  335. package/dist/{middleware/logger.d.ts → wire/loggerMiddleware.d.ts} +3 -3
  336. package/dist/wire/loggerMiddleware.d.ts.map +1 -0
  337. package/dist/{middleware/logger.js → wire/loggerMiddleware.js} +2 -2
  338. package/dist/wire/loggerMiddleware.js.map +1 -0
  339. package/dist/wire/middleware.d.ts +29 -0
  340. package/dist/wire/middleware.d.ts.map +1 -0
  341. package/dist/wire/middleware.js +20 -0
  342. package/dist/wire/middleware.js.map +1 -0
  343. package/dist/{operation.d.ts → wire/operation.d.ts} +39 -10
  344. package/dist/wire/operation.d.ts.map +1 -0
  345. package/dist/wire/operation.js +167 -0
  346. package/dist/wire/operation.js.map +1 -0
  347. package/package.json +27 -8
  348. package/src/boot/AppLifecycle.ts +50 -0
  349. package/src/boot/Emissions.ts +263 -0
  350. package/src/boot/HandlerFacade.ts +242 -0
  351. package/src/boot/Lifecycle.ts +3 -0
  352. package/src/boot/ambient-port.ts +41 -0
  353. package/src/boot/ambient.als.ts +43 -0
  354. package/src/boot/ambient.queue.ts +75 -0
  355. package/src/boot/apply.ts +47 -0
  356. package/src/boot/auth.ts +55 -0
  357. package/src/boot/binding.ts +182 -0
  358. package/src/boot/boot.ts +125 -0
  359. package/src/boot/bootstrap.ts +839 -0
  360. package/src/boot/frame.ts +210 -0
  361. package/src/boot/ownership.ts +140 -0
  362. package/src/boot/ports.ts +66 -0
  363. package/src/boot/remote.ts +179 -0
  364. package/src/boot/seed.ts +158 -0
  365. package/src/boot/together.ts +215 -0
  366. package/src/boot/types.ts +261 -0
  367. package/src/builtins/config.ts +19 -0
  368. package/src/builtins/logger.ts +175 -0
  369. package/src/config-loader.ts +146 -0
  370. package/src/contract/Call.ts +18 -0
  371. package/src/contract/Invocation.ts +72 -0
  372. package/src/contract/RouteAddress.ts +49 -0
  373. package/src/contract.ts +74 -0
  374. package/src/crypto/encoding.ts +59 -0
  375. package/src/crypto/node.ts +30 -0
  376. package/src/crypto/port.ts +45 -0
  377. package/src/crypto/webcrypto.ts +55 -0
  378. package/src/define.ts +10 -0
  379. package/src/dispatch/ArgumentResolver.ts +17 -0
  380. package/src/dispatch/ArrayResult.ts +10 -0
  381. package/src/dispatch/DispatchEvent.ts +38 -0
  382. package/src/dispatch/DispatchLifecycle.ts +23 -0
  383. package/src/dispatch/DispatchPort.ts +6 -0
  384. package/src/dispatch/Dispatcher.ts +48 -0
  385. package/src/dispatch/InFlight.ts +49 -0
  386. package/src/dispatch/InputValidator.ts +28 -0
  387. package/src/dispatch/LocalRoutePolicy.ts +34 -0
  388. package/src/dispatch/OperationExecutor.ts +60 -0
  389. package/src/dispatch/OperationRoute.ts +18 -0
  390. package/src/dispatch/OutputProjector.ts +32 -0
  391. package/src/dispatch/OutputView.ts +9 -0
  392. package/src/dispatch/PresenterArgumentResolver.ts +25 -0
  393. package/src/dispatch/PresenterExecutor.ts +55 -0
  394. package/src/dispatch/RemoteRouteResolver.ts +21 -0
  395. package/src/dispatch/Route.ts +11 -0
  396. package/src/dispatch/RouteNotFoundError.ts +29 -0
  397. package/src/dispatch/RoutePolicy.ts +8 -0
  398. package/src/dispatch/RouteRegistry.ts +73 -0
  399. package/src/dispatch/RouteResolver.ts +7 -0
  400. package/src/dispatch/StorageGuard.ts +71 -0
  401. package/src/effective-operation.ts +597 -0
  402. package/src/emit.ts +90 -0
  403. package/src/entry/DynamicFacade.ts +28 -0
  404. package/src/entry/FacadeEntry.ts +32 -0
  405. package/src/entry/TransportEntry.ts +30 -0
  406. package/src/frond-config.ts +138 -0
  407. package/src/graph.ts +180 -0
  408. package/src/identity-keys.ts +43 -0
  409. package/src/identity.ts +235 -0
  410. package/src/imports.ts +123 -0
  411. package/src/index.ts +106 -0
  412. package/src/loader.ts +41 -0
  413. package/src/node.ts +28 -0
  414. package/src/orm.ts +252 -0
  415. package/src/prefab/collector.ts +36 -0
  416. package/src/prefab/crud.ts +188 -0
  417. package/src/prefab/mirror.ts +122 -0
  418. package/src/prefab/prefab.ts +46 -0
  419. package/src/prefab/presenter.ts +63 -0
  420. package/src/prefab/repository.ts +170 -0
  421. package/src/scan/Fronds.ts +73 -0
  422. package/src/scan/conventions.ts +122 -0
  423. package/src/scan/emit.ts +231 -0
  424. package/src/scan/frond.ts +235 -0
  425. package/src/scan/handler-parser.ts +818 -0
  426. package/src/scan/scan-cache.ts +115 -0
  427. package/src/scan/scanner.ts +758 -0
  428. package/src/verify.ts +193 -0
  429. package/src/wire/call.ts +369 -0
  430. package/src/wire/errors.ts +124 -0
  431. package/src/wire/http-error.ts +77 -0
  432. package/src/wire/invocation.ts +10 -0
  433. package/src/wire/loggerMiddleware.ts +29 -0
  434. package/src/wire/middleware.ts +47 -0
  435. package/src/wire/operation.ts +258 -0
  436. package/dist/binding.d.ts.map +0 -1
  437. package/dist/binding.js.map +0 -1
  438. package/dist/boot.d.ts.map +0 -1
  439. package/dist/boot.js +0 -53
  440. package/dist/boot.js.map +0 -1
  441. package/dist/bootstrap.d.ts.map +0 -1
  442. package/dist/bootstrap.js +0 -879
  443. package/dist/bootstrap.js.map +0 -1
  444. package/dist/call.d.ts.map +0 -1
  445. package/dist/call.js.map +0 -1
  446. package/dist/collector.d.ts +0 -28
  447. package/dist/collector.d.ts.map +0 -1
  448. package/dist/collector.js +0 -32
  449. package/dist/collector.js.map +0 -1
  450. package/dist/crud.d.ts.map +0 -1
  451. package/dist/crud.js.map +0 -1
  452. package/dist/egress.d.ts +0 -52
  453. package/dist/egress.d.ts.map +0 -1
  454. package/dist/egress.js +0 -186
  455. package/dist/egress.js.map +0 -1
  456. package/dist/errors.d.ts.map +0 -1
  457. package/dist/errors.js.map +0 -1
  458. package/dist/handler-parser.d.ts.map +0 -1
  459. package/dist/handler-parser.js +0 -505
  460. package/dist/handler-parser.js.map +0 -1
  461. package/dist/invocation.d.ts +0 -20
  462. package/dist/invocation.d.ts.map +0 -1
  463. package/dist/invocation.js +0 -15
  464. package/dist/invocation.js.map +0 -1
  465. package/dist/middleware/error-handler.d.ts +0 -15
  466. package/dist/middleware/error-handler.d.ts.map +0 -1
  467. package/dist/middleware/error-handler.js +0 -29
  468. package/dist/middleware/error-handler.js.map +0 -1
  469. package/dist/middleware/logger.d.ts.map +0 -1
  470. package/dist/middleware/logger.js.map +0 -1
  471. package/dist/middleware.d.ts.map +0 -1
  472. package/dist/middleware.js.map +0 -1
  473. package/dist/mirror.d.ts +0 -93
  474. package/dist/mirror.d.ts.map +0 -1
  475. package/dist/mirror.js +0 -96
  476. package/dist/mirror.js.map +0 -1
  477. package/dist/operation.d.ts.map +0 -1
  478. package/dist/operation.js +0 -95
  479. package/dist/operation.js.map +0 -1
  480. package/dist/presenter.d.ts.map +0 -1
  481. package/dist/presenter.js.map +0 -1
  482. package/dist/remote.d.ts.map +0 -1
  483. package/dist/remote.js.map +0 -1
  484. package/dist/repository.d.ts +0 -55
  485. package/dist/repository.d.ts.map +0 -1
  486. package/dist/repository.js +0 -26
  487. package/dist/repository.js.map +0 -1
  488. package/dist/scan-cache.d.ts +0 -10
  489. package/dist/scan-cache.d.ts.map +0 -1
  490. package/dist/scan-cache.js.map +0 -1
  491. package/dist/scanner.d.ts +0 -34
  492. package/dist/scanner.d.ts.map +0 -1
  493. package/dist/scanner.js.map +0 -1
  494. package/dist/seed.d.ts.map +0 -1
  495. package/dist/seed.js.map +0 -1
  496. package/dist/types.d.ts +0 -421
  497. package/dist/types.d.ts.map +0 -1
  498. package/dist/types.js.map +0 -1
  499. /package/dist/{bootstrap.d.ts → boot/bootstrap.d.ts} +0 -0
  500. /package/dist/{types.js → boot/types.js} +0 -0
@@ -0,0 +1,158 @@
1
+ import { Role } from '@fougere/schema';
2
+ import { facadeKeyOf } from '../wire/call.js';
3
+ import type { FrondDescriptor, SeedEntry, SeedFactory } from '../scan/frond.js';
4
+ import type { App } from './types.js';
5
+ import type { Extension } from './AppLifecycle.js';
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
+ */
23
+ export function orderSeeds(fronds: FrondDescriptor[]): SeedEntry[] {
24
+ const refs = new Map<string, Set<string>>();
25
+ for (const frond of fronds) {
26
+ for (const entity of frond.entities) {
27
+ const targets = new Set<string>();
28
+ for (const field of Object.values(entity.entityClass.getFields())) {
29
+ if (!Role.of(field).isReference) continue;
30
+ const target = (Role.of(field).target as { name?: string }).name?.toLowerCase();
31
+ if (target && target !== entity.name.toLowerCase()) targets.add(target);
32
+ }
33
+ refs.set(entity.name.toLowerCase(), targets);
34
+ }
35
+ }
36
+
37
+ const seeds = fronds.flatMap((frond) => frond.seeds);
38
+ const seeded = new Set(seeds.map((seed) => seed.entityName.toLowerCase()));
39
+
40
+ // Only what is actually seeded can be waited for: a relation to an entity with no seed
41
+ // is already satisfied by whatever put its rows there.
42
+ const waiting = new Map(
43
+ seeds.map((seed) => {
44
+ const own = seed.entityName.toLowerCase();
45
+ const targets = [...(refs.get(own) ?? [])].filter((target) => seeded.has(target) && target !== own);
46
+
47
+ return [seed, new Set(targets)] as const;
48
+ }),
49
+ );
50
+
51
+ const ordered: SeedEntry[] = [];
52
+ const planted = new Set<string>();
53
+
54
+ while (waiting.size > 0) {
55
+ const ready = [...waiting.keys()].find((seed) => [...waiting.get(seed)!].every((dep) => planted.has(dep)));
56
+ if (!ready) break;
57
+
58
+ ordered.push(ready);
59
+ planted.add(ready.entityName.toLowerCase());
60
+ waiting.delete(ready);
61
+ }
62
+
63
+ return [...ordered, ...waiting.keys()];
64
+ }
65
+
66
+ /** Where a seed writes, and what it may skip — resolved per entity. */
67
+ interface SeedDoor {
68
+ list(): Promise<unknown[]>;
69
+ write(item: unknown): Promise<unknown>;
70
+ }
71
+
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
+ */
80
+ export async function runSeeds(
81
+ app: App,
82
+ seeds: SeedEntry[],
83
+ report: (message: string) => void = () => {},
84
+ ): Promise<void> {
85
+ for (const seed of seeds) {
86
+ const resolve = <T>(name: string) => app.resolve<T>(name + 'Handler');
87
+ const data = typeof seed.data === 'function' ? await (seed.data as SeedFactory)(resolve) : seed.data;
88
+
89
+ const door = doorFor(app, seed.entityName);
90
+ if (!door) {
91
+ report(` ${seed.entityName}: no handler façade nor ORM — skipping seed`);
92
+ continue;
93
+ }
94
+
95
+ const existing = await door.list();
96
+ if (existing.length > 0) {
97
+ report(` ${seed.entityName}: skipped (${existing.length} exist)`);
98
+ continue;
99
+ }
100
+
101
+ // The driver's error alone names neither the entity nor the row — and a foreign
102
+ // key is exactly what a seed gets wrong.
103
+ for (const item of data) {
104
+ try {
105
+ await door.write(item);
106
+ } catch (cause) {
107
+ throw new Error(
108
+ `Seed '${seed.entityName}' failed on ${JSON.stringify(item)}: ${(cause as Error)?.message ?? cause}`,
109
+ { cause },
110
+ );
111
+ }
112
+ }
113
+ report(` ${seed.entityName}: ${data.length} records`);
114
+ }
115
+ }
116
+
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
+ */
122
+ function doorFor(app: App, entityName: string): SeedDoor | undefined {
123
+ let handler: Record<string, Function> | undefined;
124
+ try { handler = app.resolve<Record<string, Function>>(facadeKeyOf(entityName)); } catch {}
125
+
126
+ if (typeof handler?.list === 'function' && typeof handler.create === 'function') {
127
+ return {
128
+ list: () => handler!.list() as Promise<unknown[]>,
129
+ write: (item) => handler!.create({ params: {}, query: {}, body: item, state: {} }),
130
+ };
131
+ }
132
+
133
+ const orm = app.ormFor(entityName) as
134
+ | { list: () => Promise<unknown[]>; create: (input: unknown) => Promise<unknown> }
135
+ | undefined;
136
+ if (!orm) return undefined;
137
+
138
+ return { list: () => orm.list(), write: (item) => orm.create(item) };
139
+ }
140
+
141
+ /**
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.
149
+ */
150
+ export function seeding(report?: (message: string) => void): Extension {
151
+ return {
152
+ name: 'seeds',
153
+ up: async (app: App) => {
154
+ const seeds = orderSeeds(app.fronds);
155
+ if (seeds.length > 0) await runSeeds(app, seeds, report);
156
+ },
157
+ };
158
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Building a frame — what a handler asking for `Together<[…]>` receives.
3
+ *
4
+ * The declaration names its members and nothing else; where they live, and therefore
5
+ * which of the two realizations they get, is read HERE and stated at boot. A frame whose
6
+ * members share an engine is a transaction; one whose members are split replays its own
7
+ * inverses (`frame.ts`). Same user code, two guarantees, and the boot says which — the
8
+ * one thing a gradient must never leave to assumption.
9
+ */
10
+ import { ambient } from '#ambient';
11
+ import { upperFirst, lowerFirst, type SchemaView } from '@fougere/schema';
12
+ import type { Container } from '@fougere/container';
13
+ import { membersOfTogetherKey, ormKeyOf, type EntityOrm, type OrmFactory } from '../orm.js';
14
+ import type { Logger } from '../builtins/logger.js';
15
+ import type { ProviderEntry } from '../scan/frond.js';
16
+ import { StorageGuard } from '../dispatch/StorageGuard.js';
17
+ import { recording, unwind, type Undo } from './frame.js';
18
+
19
+ /** Everything the boot knows that a frame needs, gathered once for every frond. */
20
+ export interface FrameWorld {
21
+ /** Every entity of every frond, by registration key. A frame crosses fronds by design. */
22
+ entityByName: Map<string, SchemaView>;
23
+ /** Which frond holds an entity — the question `remotes:` turns into a refusal. */
24
+ frondOf: Map<string, string>;
25
+ hostedHere: (frond: string) => boolean;
26
+ ormFactory?: OrmFactory;
27
+ sourceOf?: (entityName: string) => string;
28
+ transacted?: <R>(source: string, fn: (ormFactory: OrmFactory) => Promise<R>) => Promise<R>;
29
+ log: Logger;
30
+ }
31
+
32
+ /** An entity the block writes through, and a provider rebuilt so that its writes count too. */
33
+ interface Members {
34
+ entities: { name: string; schema: SchemaView }[];
35
+ providers: ProviderEntry[];
36
+ }
37
+
38
+ /**
39
+ * Each declared name, resolved to what it designates.
40
+ *
41
+ * A name that resolves to nothing is refused rather than skipped: `Together<[Account,
42
+ * Ledgre]>` is a typo whose only other symptom is a frame quietly one member short. The
43
+ * two lists are checked against different registries, which is exactly why the declaration
44
+ * separates them — nothing here has to guess what kind a name is.
45
+ */
46
+ function resolve(names: { entities: string[]; providers: string[] }, declared: readonly ProviderEntry[], world: FrameWorld): Members {
47
+ const entities = names.entities.map((member) => {
48
+ const name = lowerFirst(member);
49
+ const schema = world.entityByName.get(name);
50
+ if (!schema) {
51
+ throw new Error(
52
+ `Together<[…${member}…]>: no entity named '${member}' is scanned in this app. ` +
53
+ `The first list names entities; a class of this frond goes in the second.`,
54
+ );
55
+ }
56
+ return { name, schema };
57
+ });
58
+
59
+ const providers = names.providers.map((member) => {
60
+ const entry = declared.find((provider) => provider.ctor.name === member);
61
+ if (!entry) {
62
+ throw new Error(
63
+ `Together<[…], [… ${member} …]>: this frond declares no class named '${member}'. ` +
64
+ `The second list names providers to rebuild inside the frame — a service, a mirror, ` +
65
+ `a repository — so that what they write is covered by the unwind.`,
66
+ );
67
+ }
68
+ return entry;
69
+ });
70
+
71
+ return { entities, providers };
72
+ }
73
+
74
+ /**
75
+ * A member that cannot write here at all — its frond is hosted elsewhere.
76
+ *
77
+ * Refused rather than compensated: a compensated frame still writes through a local ORM,
78
+ * and a remote frond registers none. There is nothing to record and nothing to undo.
79
+ */
80
+ function refuseRemote(members: Members, world: FrameWorld, key: string): void {
81
+ for (const member of members.entities) {
82
+ const frond = world.frondOf.get(member.name);
83
+ if (frond && !world.hostedHere(frond)) {
84
+ throw new Error(
85
+ `Together<[…]> (${key}): '${member.name}' belongs to frond '${frond}', which this ` +
86
+ `process declares in remotes: — it registers no storage here, so its writes cannot be ` +
87
+ `part of a frame. Host the frond here, or split the work and join the halves with a fact.`,
88
+ );
89
+ }
90
+ }
91
+ }
92
+
93
+ /**
94
+ * A provider member writing an entity the frame does not name.
95
+ *
96
+ * The frame does not widen itself to cover it: doing so would pull an entity from another
97
+ * source into the group without anyone writing it down. Named instead, with the one-word fix.
98
+ */
99
+ function refuseUncoveredWrites(members: Members, key: string): void {
100
+ const covered = new Set(members.entities.map((member) => member.name));
101
+ for (const provider of members.providers) {
102
+ for (const dep of provider.deps) {
103
+ if (!dep.endsWith('Orm')) continue;
104
+ const entity = lowerFirst(dep.slice(0, -'Orm'.length));
105
+ if (covered.has(entity)) continue;
106
+ throw new Error(
107
+ `Together<[…]> (${key}): ${provider.ctor.name} writes ${entity}, which is not in the ` +
108
+ `frame's entity list — its writes would escape the unwind. Add it: ` +
109
+ `Together<[…, ${upperFirst(entity)}], [… ${provider.ctor.name} …]>.`,
110
+ );
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Open the block: build every member over `factory`, in a scope of their own.
117
+ *
118
+ * The scope is what makes a provider member work without a locator — its ORM keys are
119
+ * registered here, so the container hands it the framed ones through the ordinary
120
+ * constructor. It is disposed when the block ends, whichever way it ended.
121
+ */
122
+ async function inScope<R>(
123
+ parent: Container,
124
+ members: Members,
125
+ factory: OrmFactory,
126
+ wrap: (orm: EntityOrm, name: string, schema: SchemaView) => EntityOrm,
127
+ fn: (entities: unknown[], providers: unknown[]) => Promise<R>,
128
+ ): Promise<R> {
129
+ const scope = parent.createScope();
130
+ try {
131
+ const orms = members.entities.map((member) => {
132
+ const orm = wrap(factory(member.schema, member.name), member.name, member.schema);
133
+ scope.registerValue(ormKeyOf(member.name), orm);
134
+ return orm;
135
+ });
136
+ // Providers after every ORM is in place: one may depend on another member's.
137
+ const built = members.providers.map((provider) => {
138
+ scope.register(provider.ctor.name, provider.ctor, { deps: provider.deps });
139
+ return scope.resolve(provider.ctor.name);
140
+ });
141
+ return await fn(orms, built);
142
+ } finally {
143
+ await scope.dispose();
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Register one frame per key a handler or provider of this frond asked for.
149
+ *
150
+ * Called with the frond's scope, because that is where the asking constructor resolves —
151
+ * while the MEMBERS are looked up app-wide, a frame crossing fronds being the ordinary case
152
+ * rather than the exception (the frond is not the storage boundary; `sources:` is).
153
+ */
154
+ export function registerFrames(
155
+ scope: Container,
156
+ keys: Iterable<string>,
157
+ providers: readonly ProviderEntry[],
158
+ world: FrameWorld,
159
+ ): void {
160
+ let registered = 0;
161
+ for (const key of new Set(keys)) {
162
+ const names = membersOfTogetherKey(key);
163
+ if (!names) continue;
164
+ registered += 1;
165
+ if (!world.ormFactory) {
166
+ throw new Error(`Together<[${names.entities.join(', ')}]> needs storage, and this boot declares none.`);
167
+ }
168
+
169
+ const members = resolve(names, providers, world);
170
+ refuseRemote(members, world, key);
171
+ refuseUncoveredWrites(members, key);
172
+
173
+ const sources = new Set(members.entities.map((member) => world.sourceOf?.(member.name) ?? 'db'));
174
+ const judge = (orm: EntityOrm, name: string, schema: SchemaView) =>
175
+ new StorageGuard(schema.getFields(), name).guard(orm);
176
+
177
+ // One engine and a way into it: the engine gives the unwind AND the isolation.
178
+ if (world.transacted && sources.size === 1) {
179
+ const source = [...sources][0];
180
+ world.log.info(`${key} — transaction, source '${source}'`);
181
+ scope.registerValue(key, {
182
+ run: <R>(fn: (entities: never, providers: never) => Promise<R>) =>
183
+ ambient.enterFrame(key, () =>
184
+ world.transacted!(source, (factory) => inScope(scope, members, factory, judge, fn as never))),
185
+ });
186
+ continue;
187
+ }
188
+
189
+ // Split, or an engine that hands out no transaction: the frame keeps the before-image
190
+ // of every write and replays the inverses itself. `judge` stays OUTSIDE `recording`, so
191
+ // a write the entity refuses never enters the journal.
192
+ const why = sources.size > 1
193
+ ? members.entities.map((m) => `${m.name} in '${world.sourceOf?.(m.name) ?? 'db'}'`).join(', ')
194
+ : 'this storage hands out no transaction';
195
+ world.log.info(`${key} — compensated: ${why} — no isolation`);
196
+ scope.registerValue(key, {
197
+ run: <R>(fn: (entities: never, providers: never) => Promise<R>): Promise<R> => ambient.enterFrame(key, async () => {
198
+ const journal: Undo[] = [];
199
+ const record = (orm: EntityOrm, name: string, schema: SchemaView) =>
200
+ judge(recording(orm, name, schema.getFields(), journal), name, schema);
201
+ try {
202
+ return await inScope(scope, members, world.ormFactory!, record, fn as never);
203
+ } catch (cause) {
204
+ return unwind(journal, cause, world.log);
205
+ }
206
+ }),
207
+ });
208
+ }
209
+ if (registered > 0 && ambient.degraded) {
210
+ world.log.warn(
211
+ 'no async context on this runtime — frames run one at a time, and a frame opened '
212
+ + 'inside another times out instead of being refused',
213
+ );
214
+ }
215
+ }
@@ -0,0 +1,261 @@
1
+ /**
2
+ * The boot's two ends: what `createApp` takes, and what it hands back.
3
+ *
4
+ * The scan's descriptors moved to `frond.ts` and the auth contract to `auth.ts` — this
5
+ * file was named after a role ("the types"), so everything with nowhere else to be
6
+ * landed in it, seventeen notions deep.
7
+ */
8
+ import type { Container } from '@fougere/container';
9
+ import type { Fronds } from '../scan/Fronds.js';
10
+ import type { ScanResult } from '../scan/frond.js';
11
+ import type { SchemaView } from '@fougere/schema';
12
+ import type { OrmFactory } from '../orm.js';
13
+ import type { AppMiddleware } from '../wire/middleware.js';
14
+ import type { RpcAnswer, Transport } from '../wire/call.js';
15
+ import type { Extension } from './AppLifecycle.js';
16
+ import type { AuthConfig, AuthRuntime } from './auth.js';
17
+ import type { EffectiveOperationsMap } from '../effective-operation.js';
18
+ import type { DispatchObserver } from '../dispatch/DispatchEvent.js';
19
+ import type { DispatchPort } from '../dispatch/DispatchPort.js';
20
+
21
+ /** Options for createApp(). */
22
+ export interface CreateAppOptions {
23
+ /** Factory function to create the container. Required. */
24
+ createContainer: () => Container;
25
+ /** Factory to auto-generate EntityOrm for each scanned entity. */
26
+ ormFactory?: OrmFactory;
27
+ /**
28
+ * Which source an entity's rows live in, and how to open a transaction on one — the two
29
+ * questions that decide whether `Together<[…]>` gets the engine's own unwind or replays
30
+ * inverses itself.
31
+ *
32
+ * Optional together, because a host may hand in a bare `ormFactory` and know neither. A
33
+ * frame then compensates: not knowing where the rows are and promising atomicity over
34
+ * them are two different things, and only one of them is honest.
35
+ */
36
+ sourceOf?: (entityName: string) => string;
37
+ transacted?: <R>(source: string, fn: (ormFactory: OrmFactory) => Promise<R>) => Promise<R>;
38
+ /**
39
+ * Builds the cross-source reader a frond gets when it declares `reads:`.
40
+ *
41
+ * A factory rather than a value, for the same reason `ormFactory` is one: core must
42
+ * not name a storage package, and this one costs 71 MB of downloaded extensions and a
43
+ * native module — nothing a first run that only wanted sqlite should carry. The host
44
+ * decides what backs it; `@fougere/adapter-duckdb` is one answer, not the contract.
45
+ *
46
+ * Called once per frond that asks, with the entity CLASSES its `reads:` named — a
47
+ * name would make the reader resolve the schema a second time.
48
+ */
49
+ sourcesFactory?: (reads: unknown[], frond: string) => Promise<unknown> | unknown;
50
+ /**
51
+ * What this app is built from — required, because producing it is what reads a disk.
52
+ *
53
+ * `scanProject` (`@fougere/core/node`) reads the fronds off the filesystem; a module a
54
+ * build wrote holds the same value with no disk at all. `createApp` cannot tell them
55
+ * apart, and that is the point: it names no builtin, so a runtime without `node:fs`
56
+ * runs it. `root` and `fronds` used to live here — both were arguments to the scan.
57
+ */
58
+ scan: ScanResult | (() => Promise<ScanResult> | ScanResult);
59
+ /**
60
+ * Remote fronds — label → address. What each remote hosts is discovered
61
+ * at the first miss (rpc.discover), never declared here.
62
+ */
63
+ remotes?: Record<string, string>;
64
+ /**
65
+ * Builds the transport used to reach `remotes` addresses. Wired by
66
+ * layer-2 packages (e.g. @fougere/transport-http); required when
67
+ * `remotes` is non-empty.
68
+ */
69
+ remoteTransport?: (url: string) => Transport;
70
+ /**
71
+ * Which realization answers which port — see `FougereConfig.ports`. Needed only
72
+ * when two classes extend the same port; one is resolved by convention.
73
+ */
74
+ ports?: Record<string, string>;
75
+ /**
76
+ * What this app takes on beyond its fronds, each stating what it does and what it undoes.
77
+ *
78
+ * `up` runs before `createApp` returns, in this order; `down` runs inside `dispose()`,
79
+ * in reverse. Three levels release in reverse of construction, which is the container's
80
+ * own rule read one level out: extensions first (built last), then the container, then
81
+ * `onDispose` — a resource opened before any of this existed.
82
+ *
83
+ * A member may be `undefined`, so a host writes a conditional one inline rather than a
84
+ * spread over a ternary. The framework's own two are always declared, `migrate` as an
85
+ * empty slot when nothing migrates: a host filling it later REPLACES that member in
86
+ * place instead of adding one after the seeds.
87
+ */
88
+ extensions?: readonly (Extension | undefined)[];
89
+ /**
90
+ * Released by `app.dispose()` AFTER the container, for a resource handed in rather
91
+ * than built here — a storage connection is the one case today.
92
+ *
93
+ * NOT an extension, and the difference is a time: this was opened BEFORE the container,
94
+ * so it closes after it, while an extension's `up` runs after the container and its
95
+ * `down` therefore runs before. A storage's migration is an extension; its connection
96
+ * is not, and `ResolvedStorage` declares the two beside each other.
97
+ */
98
+ onDispose?: () => Promise<void> | void;
99
+ /**
100
+ * Which protocol adapters this app serves — see `FougereConfig.adapters`.
101
+ * Carried onto the App so every door reads one answer instead of each host
102
+ * deciding for itself.
103
+ */
104
+ adapters?: Record<string, boolean | undefined>;
105
+ /**
106
+ * Carries an announced fact out of this process — a broker, a queue, a log.
107
+ *
108
+ * Called for every emission, ALONGSIDE the local dispatch and never instead of it: a
109
+ * listener in this process is reached directly, and this is how the others hear.
110
+ *
111
+ * It exists because the local dispatch finds its listeners by having READ their code,
112
+ * which stops at the repository boundary. A carrier hands the fact to a NAME; the far
113
+ * side subscribes to that same name from its own code, and neither ever reads the other.
114
+ *
115
+ * Its failure never reaches the emitter — same rule as a subscriber's.
116
+ */
117
+ onEmit?: (fact: string, payload: unknown) => void | Promise<void>;
118
+ /** Passive observers of every dispatch transition. */
119
+ dispatchObservers?: readonly DispatchObserver[];
120
+ /**
121
+ * Storage handle to expose to the auth provider via AuthContext.db.
122
+ * Required when `auth` is set.
123
+ */
124
+ db?: unknown;
125
+ /** Auth declaration to wire into the app at boot. */
126
+ auth?: AuthConfig;
127
+ }
128
+
129
+ /** The App object returned by createApp(). */
130
+ export interface App extends DispatchPort {
131
+ /** Process-only dispatch capability used by incoming transports. */
132
+ local: DispatchPort;
133
+ /** Root container with builtins + frond scopes. */
134
+ container: Container;
135
+ /**
136
+ * Which protocol adapters this app declared, from `fougere.config.ts`.
137
+ *
138
+ * Read by the doors themselves, so an undeclared adapter serves nothing whatever
139
+ * the host mounted — the route file may exist, the middleware may be installed, and
140
+ * the answer is still "not here".
141
+ */
142
+ adapters: Record<string, boolean | undefined>;
143
+ /** Discovered fronds metadata. */
144
+ fronds: Fronds;
145
+ /** Resolve from root container (shortcut). */
146
+ resolve<T>(name: string): T;
147
+ /**
148
+ * Resolve an entity's schema — the local `entityClass` when it's hosted or
149
+ * scanned here, else reconstructed from the remote's identity card
150
+ * (`rpc.discover` to `Card.toSchema`). The one way to get a live schema for an
151
+ * entity whose class may not be importable at all (another repo, another
152
+ * language) — a card travelled, but until now its `schema` was thrown away.
153
+ */
154
+ schemaFor(entity: string): Promise<SchemaView>;
155
+ /**
156
+ * The door a name exposes to one audience, or `undefined` when it exposes
157
+ * none. A named surface is CLOSED: a name with no door of its own under that
158
+ * surface is not in it — it never falls back to the full one.
159
+ *
160
+ * **Not always a façade**, despite the name: when the owning frond is declared
161
+ * remote, nothing is registered locally (`bootstrap.ts`, `declaredRemotes`) and
162
+ * this resolves to a doublure — a façade-shaped stand-in (`remote.ts`). The
163
+ * caller cannot tell, which is the point; the word here was simply wrong.
164
+ *
165
+ * The one way an adapter reaches that door. It exists so the key format stays
166
+ * inside core (see `facadeKeyOf`), which is what lets a projection package
167
+ * stay structurally typed and depend on nothing.
168
+ */
169
+ facadeFor(entity: string, surface?: string): Record<string, Function> | undefined;
170
+ /**
171
+ * The canonical contracts served beside a facade, after prefab + scan + config,
172
+ * binding, kind, topology and surface resolution. Check, explain and adapters read
173
+ * this table instead of replaying those decisions.
174
+ */
175
+ operationsFor(entity: string, surface?: string): EffectiveOperationsMap | undefined;
176
+ /**
177
+ * The facts this app has a listener for — what a carrier must subscribe to on its behalf.
178
+ *
179
+ * Derived from the signatures it scanned (`Fact<T>` in an op's parameters), so a process
180
+ * states what it listens to without anyone declaring it twice. The dual of `onEmit`: one
181
+ * says what leaves, this says what should be brought in.
182
+ */
183
+ listensTo(): string[];
184
+ /**
185
+ * Hand a fact that came from OUTSIDE to the listeners in this process — and stop there.
186
+ *
187
+ * The dual of `onEmit`, and deliberately not the same thing as announcing: resolving the
188
+ * emission value to deliver an inbound fact would carry it straight back out through
189
+ * `onEmit`, so a hub echoed every reading it received to the whole fleet. Receiving and
190
+ * announcing are two operations; only one of them leaves.
191
+ *
192
+ * The local dispatch is identical either way — same judge, same binding, same
193
+ * middlewares — so a fact off a wire is no less checked than one raised next door.
194
+ *
195
+ * **It waits, and it tells** — the opposite of announcing, on purpose. It resolves once
196
+ * every listener here is done, and REJECTS with an `AggregateError` if any refused. A
197
+ * carrier's whole job is to know whether the fact landed: at-least-once is retrying what
198
+ * failed, so a delivery that cannot report makes durability impossible to build above it.
199
+ * "Dispatch is not delivery" protects the EMITTER from a slow subscriber; a carrier is
200
+ * not the emitter, it is the party whose business this is.
201
+ *
202
+ * It still holds nothing. A refused fact is refused, and whether it comes back is the
203
+ * carrier's decision — Fougere puts the channel underneath rather than reimplementing it.
204
+ */
205
+ deliver(fact: string, payload: unknown): Promise<void>;
206
+ /**
207
+ * The storage an entity is backed by, resolved through its owning frond's scope —
208
+ * the dual of {@link facadeFor}. `undefined` when no loaded frond hosts the entity,
209
+ * or when the app booted with no storage at all.
210
+ *
211
+ * `unknown` because the port belongs to whoever wired it: narrowing it to `EntityOrm`
212
+ * is the caller saying which implementation they are standing on.
213
+ */
214
+ ormFor(entity: string): unknown | undefined;
215
+ /**
216
+ * The presenter of an entity, resolved through its owning frond's scope.
217
+ *
218
+ * Same shape as {@link ormFor}, and it exists so an adapter never spells the container
219
+ * key itself: `schema-graphql` wrote out `${Name}Presenter` by hand, and a key respelled
220
+ * in a second place finds nothing and reports nothing the day the convention moves.
221
+ */
222
+ presenterFor(entity: string): unknown | undefined;
223
+ /** Dispose the root container. */
224
+ dispose(): Promise<void>;
225
+ /**
226
+ * Stop taking calls, and resolve once the running ones are done.
227
+ *
228
+ * The step before releasing, when there is work on the app: `dispose()` closes a
229
+ * storage connection the running calls are standing on. Rejects on `timeoutMs`
230
+ * naming how many are left, rather than resolving as if it had succeeded.
231
+ */
232
+ drain(timeoutMs?: number): Promise<void>;
233
+ /** How many calls are running right now — one count for all three doors and the wire. */
234
+ inFlight(): number;
235
+ /**
236
+ * The same disposal, spelled so the language does it: `await using app = await
237
+ * createApp(…)`. Twelve of the twenty-six mounts in this repo's own tests never
238
+ * called `dispose()` — a scope that closes itself is the only version of that
239
+ * rule nobody forgets.
240
+ */
241
+ [Symbol.asyncDispose](): Promise<void>;
242
+ /**
243
+ * What this app took on, in the order it will release them. The reading of
244
+ * `CreateAppOptions.extensions` after the boot resolved it.
245
+ */
246
+ extensions(): string[];
247
+ /**
248
+ * Declare one `rpc` op — what the app says about ITSELF, beside the card.
249
+ *
250
+ * The gesture a package uses to add a reading core does not hold: an app that never
251
+ * installed it never registers it, so the runner's refusal is the whole degradation.
252
+ * A name already declared is refused rather than replaced — `discover` included.
253
+ */
254
+ serveRpc(op: string, answer: RpcAnswer): void;
255
+ /** Register a global app middleware (runs on every operation). */
256
+ use(middleware: AppMiddleware): void;
257
+ /** Register an app middleware scoped to a specific entity. */
258
+ use(entity: string, middleware: AppMiddleware): void;
259
+ /** Auth runtime, present when fougere.config.ts declares `auth`. */
260
+ auth?: AuthRuntime;
261
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The process environment, as a service — so a handler asks for it rather than reading it.
3
+ *
4
+ * `process` is absent on a Worker, where the environment arrives as a binding. Read through
5
+ * `globalThis` and treated as empty when there is none: a missing variable and a missing
6
+ * `process` are the same answer to a caller, and the fallback already says what to do.
7
+ */
8
+ export class Config {
9
+ constructor(private readonly env: Record<string, string | undefined> = envOfProcess()) {}
10
+
11
+ get<T = string>(key: string, fallback?: T): T {
12
+ return (this.env[key] as T) ?? (fallback as T);
13
+ }
14
+ }
15
+
16
+ function envOfProcess(): Record<string, string | undefined> {
17
+ const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;
18
+ return proc?.env ?? {};
19
+ }