@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,235 @@
1
+ /**
2
+ * Who is calling — the proof, not the claim.
3
+ *
4
+ * `InvocationContext.state` is what a caller SAYS about itself, and a split receiver
5
+ * used to believe it: identity read straight off the wire, so a reader could post
6
+ * `{ state: { user: { role: 'admin' } } }` and be one. This module is what turns that
7
+ * sack into something a receiver establishes instead of accepts.
8
+ *
9
+ * Two signatures, one public key to distribute:
10
+ *
11
+ * GRANT the root says "this key is `blog`" — issued once, at deployment
12
+ * ENVELOPE `blog` says "here is my whole call" — signed per call
13
+ *
14
+ * The envelope binds the CALL and not only its state: address, params, query, a digest
15
+ * of the body. Signing the state alone proved WHO without proving WHAT, so anyone on the
16
+ * wire could replay a captured envelope against another operation for as long as it
17
+ * stayed valid — `post.list` re-sent as `post.delete`, same signature, still good.
18
+ *
19
+ * A receiver holds the root's public key and nothing else: it validates any frond it
20
+ * has never seen, which is what a per-caller list could not do. The private root key
21
+ * signs grants and never leaves the machine that issued them.
22
+ *
23
+ * Ed25519 and a JWS-shaped grant rather than X.509: node can PARSE a certificate but
24
+ * not ISSUE one, so a real chain would mean openssl or a library. The grant says the
25
+ * same thing — a name bound to a public key, signed by the root — with no dependency.
26
+ *
27
+ * The Ed25519 itself comes through `#crypto`, which has two realizations: `node:crypto`
28
+ * everywhere, WebCrypto under `workerd`. Everything here is therefore async — WebCrypto
29
+ * has no synchronous form — and a key is parsed ONCE, into a `Signer` or a `Verifier`,
30
+ * never per call. Making the keys and issuing grants happen at a deployment and live in
31
+ * `identity-keys.ts`, on the Node entry.
32
+ */
33
+ import { crypto } from '#crypto';
34
+ import type { PublicJwk, Signer, Verifier } from './crypto/port.js';
35
+ import { b64url, unb64url, bytesOf, textOf, unb64 } from './crypto/encoding.js';
36
+ import type { SignedCall } from './wire/call.js';
37
+
38
+ export type { SignedCall } from './wire/call.js';
39
+
40
+ /** How long a call envelope stays valid. A signed call is not a session. */
41
+ const ENVELOPE_TTL_MS = 60_000;
42
+ /** Clock skew tolerated on both sides of a validity window. */
43
+ const SKEW_MS = 30_000;
44
+
45
+ /** What a deployment hands a frond that CALLS: its own key, and the root's word for it. */
46
+ export interface FrondIdentity {
47
+ /** The frond's private key, PEM (PKCS#8). */
48
+ privateKey: string;
49
+ /** The root's statement binding this frond's name to its public key. */
50
+ grant: string;
51
+ }
52
+
53
+ /** The body's fingerprint. Absence and explicit null are different signed calls. */
54
+ async function digestOf(body: unknown): Promise<string> {
55
+ // The tag is outside the caller value, so no user object can collide with it. JSON's
56
+ // own omission rule still applies inside `value`, matching what crosses the wire.
57
+ const canonical = body === undefined
58
+ ? { kind: 'undefined' }
59
+ : { kind: 'value', value: body };
60
+ return b64url(await crypto.sha256(bytesOf(JSON.stringify(canonical))));
61
+ }
62
+
63
+ /** What the envelope pins, as one comparable value. */
64
+ async function boundTo(call: SignedCall) {
65
+ return {
66
+ entity: call.entity,
67
+ op: call.op,
68
+ params: call.params ?? {},
69
+ query: call.query ?? {},
70
+ body: await digestOf(call.body),
71
+ };
72
+ }
73
+
74
+ /** What `verifyEnvelope` establishes — never what the caller asked for. */
75
+ export interface VerifiedCall {
76
+ /** The frond that signed, as the root named it. */
77
+ caller: string;
78
+ /** The state it asserted, now proven to come from `caller`. */
79
+ state: Record<string, unknown>;
80
+ }
81
+
82
+ /** A JWS compact serialization, signed with Ed25519. */
83
+ async function signJws(header: object, payload: object, signer: Signer): Promise<string> {
84
+ const signingInput = `${b64url(JSON.stringify(header))}.${b64url(JSON.stringify(payload))}`;
85
+ return `${signingInput}.${b64url(await signer.sign(bytesOf(signingInput)))}`;
86
+ }
87
+
88
+ /**
89
+ * The payload, once the signature holds. Throws rather than returning a falsy value:
90
+ * every caller here is deciding whether to admit a call, and an unverified payload
91
+ * must never be reachable by forgetting a check.
92
+ */
93
+ async function verifyJws(token: string, verifier: Verifier, what: string): Promise<Record<string, unknown>> {
94
+ const parts = token.split('.');
95
+ if (parts.length !== 3) throw new Error(`Malformed ${what}`);
96
+ const [encodedHeader, encodedPayload, encodedSignature] = parts;
97
+ if (!await verifier.verify(bytesOf(`${encodedHeader}.${encodedPayload}`), unb64url(encodedSignature))) {
98
+ throw new Error(`Bad ${what} signature`);
99
+ }
100
+ const payload = JSON.parse(textOf(unb64url(encodedPayload))) as Record<string, unknown>;
101
+ const now = Date.now();
102
+ if (typeof payload.exp === 'number' && now > payload.exp + SKEW_MS) throw new Error(`Expired ${what}`);
103
+ if (typeof payload.nbf === 'number' && now < payload.nbf - SKEW_MS) throw new Error(`${what} not yet valid`);
104
+ return payload;
105
+ }
106
+
107
+ /** Read a JWS header without verifying anything — only to find which key to verify WITH. */
108
+ function headerOf(token: string): Record<string, unknown> {
109
+ const encodedHeader = token.split('.')[0];
110
+ if (!encodedHeader) throw new Error('Malformed envelope');
111
+ return JSON.parse(textOf(unb64url(encodedHeader))) as Record<string, unknown>;
112
+ }
113
+
114
+ /**
115
+ * Sign one call, whole: who is asking, what is asked, and on whose behalf.
116
+ *
117
+ * The private key is parsed on every call here, which is the convenience form. A process
118
+ * that signs in a request path builds its signer once — `identityFromEnv` does exactly
119
+ * that, and `sign` on the value it returns holds the parsed key.
120
+ */
121
+ export async function signEnvelope(identity: FrondIdentity, call: SignedCall): Promise<string> {
122
+ return sealWith(await crypto.signerOf(identity.privateKey), identity.grant, call);
123
+ }
124
+
125
+ /** The same envelope, against a key someone already parsed. */
126
+ async function sealWith(signer: Signer, grant: string, call: SignedCall): Promise<string> {
127
+ const now = Date.now();
128
+ const { sub } = JSON.parse(textOf(unb64url(grant.split('.')[1]))) as { sub: string };
129
+ return signJws(
130
+ { alg: 'EdDSA', typ: 'fougere-call', grant },
131
+ { iss: sub, state: call.state ?? {}, bound: await boundTo(call), iat: now, exp: now + ENVELOPE_TTL_MS },
132
+ signer,
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Establish the caller, or throw. Order matters: the grant is checked against the ROOT
138
+ * first, and only the key it carries verifies the envelope — reading the envelope's own
139
+ * claim of who it is before that would be believing the thing under examination.
140
+ */
141
+ export async function verifyEnvelope(token: string, rootPublicKey: string, presented: SignedCall): Promise<VerifiedCall> {
142
+ return openWith(await crypto.verifierOf(rootPublicKey), token, presented);
143
+ }
144
+
145
+ /** The same check, against a root key someone already parsed. */
146
+ async function openWith(root: Verifier, token: string, presented: SignedCall): Promise<VerifiedCall> {
147
+ const { grant } = headerOf(token);
148
+ if (typeof grant !== 'string') throw new Error('Envelope carries no grant');
149
+
150
+ const granted = await verifyJws(grant, root, 'grant');
151
+ if (typeof granted.sub !== 'string' || typeof granted.jwk !== 'object' || granted.jwk === null) {
152
+ throw new Error('Grant names no frond');
153
+ }
154
+
155
+ const payload = await verifyJws(token, await crypto.verifierOf(granted.jwk as PublicJwk), 'envelope');
156
+
157
+ // The grant is the authority on the name; the envelope only repeats it. They disagree
158
+ // when a frond signs under someone else's name with its own key.
159
+ if (payload.iss !== granted.sub) throw new Error(`Envelope signed by '${granted.sub}' claims to be '${String(payload.iss)}'`);
160
+
161
+ // The signature says this envelope was made by `blog`; this says it was made for THIS
162
+ // call. Without it a captured envelope is a blank cheque until it expires.
163
+ const bound = JSON.stringify(payload.bound);
164
+ if (bound !== JSON.stringify(await boundTo(presented))) {
165
+ throw new Error(`Envelope was signed for a different call than ${presented.entity}.${presented.op}`);
166
+ }
167
+
168
+ return {
169
+ caller: granted.sub,
170
+ state: (payload.state as Record<string, unknown>) ?? {},
171
+ };
172
+ }
173
+
174
+ /** The two halves a boot needs, and the environment they come from. */
175
+ export interface CallIdentity {
176
+ /**
177
+ * Signs an outgoing call, whole. Absent when this process holds no key — it only answers.
178
+ *
179
+ * A promise because WebCrypto has no synchronous form. On Node the work stays
180
+ * synchronous inside and only the answer is wrapped: measured at 14.28 µs awaited
181
+ * against 14.30 µs called directly, while WebCrypto on the same curve costs 22.72.
182
+ */
183
+ sign?: (call: SignedCall) => Promise<string>;
184
+ /** Establishes an incoming caller, against the call that actually arrived. */
185
+ verify?: (identity: string, presented: SignedCall) => Promise<VerifiedCall>;
186
+ /** Refuse an unsigned call. True exactly when a root is trusted. */
187
+ requireIdentity: boolean;
188
+ }
189
+
190
+ /**
191
+ * A PEM, however the deployment chose to carry it.
192
+ *
193
+ * A PEM is multi-line and an environment variable that spans lines survives poorly —
194
+ * docker-compose, systemd and CI secret stores each mangle it differently — so
195
+ * `fougere keys` prints base64. Both forms are read here rather than one being decreed:
196
+ * a human pasting a real PEM is not making a mistake.
197
+ */
198
+ function pemOf(value: string): string {
199
+ return value.trimStart().startsWith('-----') ? value : textOf(unb64(value));
200
+ }
201
+
202
+ /**
203
+ * What the deployment injected, read once at boot.
204
+ *
205
+ * Three variables, no config key: a private key never belongs in a committed file, and
206
+ * `fougere keys` prints exactly these. A process may hold either half or both — a frond
207
+ * that only answers has no key, one that only calls trusts no root, one in the middle
208
+ * does both.
209
+ *
210
+ * Trusting a root IS asking to refuse: there is no separate flag, because a deployment
211
+ * that names an authority and then accepts unsigned calls has said two things at once.
212
+ */
213
+ export async function identityFromEnv(env: Record<string, string | undefined> = envOfProcess()): Promise<CallIdentity> {
214
+ const root = env.FOUGERE_ROOT_KEY ? pemOf(env.FOUGERE_ROOT_KEY) : undefined;
215
+ const privateKey = env.FOUGERE_KEY ? pemOf(env.FOUGERE_KEY) : undefined;
216
+ const grant = env.FOUGERE_GRANT;
217
+
218
+ // Async because the keys are parsed HERE, once, and both closures below capture the
219
+ // result: importing a key is per-key work, and a per-call import would put it inside
220
+ // every request. This is the one gesture a boot pays for.
221
+ const signer = privateKey ? await crypto.signerOf(privateKey) : undefined;
222
+ const rootKey = root ? await crypto.verifierOf(root) : undefined;
223
+
224
+ return {
225
+ ...(signer && grant ? { sign: (call: SignedCall) => sealWith(signer, grant, call) } : {}),
226
+ ...(rootKey ? { verify: (identity: string, presented: SignedCall) => openWith(rootKey, identity, presented) } : {}),
227
+ requireIdentity: Boolean(root),
228
+ };
229
+ }
230
+
231
+ /** A Worker has no `process`. Reading the global is what makes an absent one an empty env. */
232
+ function envOfProcess(): Record<string, string | undefined> {
233
+ const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;
234
+ return proc?.env ?? {};
235
+ }
package/src/imports.ts ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * A frond reaching into another one by FILE PATH.
3
+ *
4
+ * `verify()` next door answers the same question — does this app survive a split? — from
5
+ * the MODEL: what a constructor asks for, what a parameter is typed. This one can only be
6
+ * answered from the source text, so it reads files and lives apart rather than making
7
+ * `verify` lose the sentence that says it reads none.
8
+ *
9
+ * ```ts
10
+ * import User from '../../user/entities/User.js'; // these two folders are neighbours
11
+ * import User from '@fronds/user/entities/User'; // I depend on the frond named user
12
+ * ```
13
+ *
14
+ * Both resolve today, and that is exactly the trap: a frond declared in `remotes:` is
15
+ * still scanned, its code is still on this disk, so the relative form keeps working right
16
+ * up to the day the folder is not there — an extraction into its own repository, an image
17
+ * that copies one frond. Then it fails at build time, with a message about a file path
18
+ * that says nothing about the model.
19
+ *
20
+ * So a relative path across a boundary is not a bug. It is a **colocation constraint that
21
+ * nothing declares**: real, load-bearing, and invisible to the scan, to the identity card
22
+ * and to `remotes:`. The named form states the same dependency in terms the model can
23
+ * read — and it is the form `fougere sync` writes, so it survives the move.
24
+ */
25
+ import type ts from '@typescript/typescript6';
26
+ import { readdir, readFile } from 'node:fs/promises';
27
+ import { join, resolve, dirname, relative, isAbsolute } from 'node:path';
28
+ import type { FrondDescriptor } from './scan/frond.js';
29
+
30
+ let _ts: typeof ts | undefined;
31
+ async function loadTs(): Promise<typeof ts> {
32
+ if (!_ts) _ts = (await import('@typescript/typescript6')).default;
33
+ return _ts;
34
+ }
35
+
36
+ export interface CrossFrondImport {
37
+ /** Stable rule name — the same vocabulary `verify()` uses. */
38
+ rule: 'cross-frond-import';
39
+ /** The frond doing the reaching. */
40
+ frond: string;
41
+ filePath: string;
42
+ /** The specifier as written. */
43
+ specifier: string;
44
+ /** The frond the path lands in — absent when it lands outside every frond. */
45
+ target?: string;
46
+ message: string;
47
+ }
48
+
49
+ /** Is `child` inside `parent`? Path-based, so it says nothing about either existing. */
50
+ function inside(parent: string, child: string): boolean {
51
+ const rel = relative(parent, child);
52
+ return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel);
53
+ }
54
+
55
+ async function sourcesUnder(dir: string): Promise<string[]> {
56
+ const out: string[] = [];
57
+ let entries;
58
+ try {
59
+ entries = await readdir(dir, { withFileTypes: true });
60
+ } catch {
61
+ // Unreadable is the scan's complaint, not this rule's — and an absent directory is
62
+ // ordinary (a frond with no handlers).
63
+ return out;
64
+ }
65
+ for (const entry of entries) {
66
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
67
+ const full = join(dir, entry.name);
68
+ if (entry.isDirectory()) out.push(...await sourcesUnder(full));
69
+ else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) out.push(full);
70
+ }
71
+ return out;
72
+ }
73
+
74
+ /**
75
+ * Every relative import that resolves outside its own frond.
76
+ *
77
+ * `preProcessFile` rather than a regex or a full parse: it is TypeScript's own scanner for
78
+ * exactly this question, so `// import x from '../../other'` in a comment is not a finding
79
+ * and a specifier split across lines still is.
80
+ */
81
+ export async function crossFrondImports(
82
+ fronds: readonly Pick<FrondDescriptor, 'name' | 'source'>[],
83
+ ): Promise<CrossFrondImport[]> {
84
+ const typescript = await loadTs();
85
+ // `source.package` is the scoped name the scan already resolved — the remedy this rule
86
+ // prints must be the name that actually resolves, not one rebuilt from a prefix here.
87
+ const roots = fronds.map((frond) => ({
88
+ name: frond.name, path: resolve(frond.source.path), package: frond.source.package,
89
+ }));
90
+ const found: CrossFrondImport[] = [];
91
+
92
+ for (const root of roots) {
93
+ for (const filePath of await sourcesUnder(root.path)) {
94
+ const text = await readFile(filePath, 'utf8').catch(() => undefined);
95
+ if (text === undefined) continue;
96
+
97
+ for (const { fileName: specifier } of typescript.preProcessFile(text, true, true).importedFiles) {
98
+ if (!specifier.startsWith('.')) continue;
99
+ const landed = resolve(dirname(filePath), specifier);
100
+ if (inside(root.path, landed)) continue;
101
+
102
+ const target = roots.find((other) => other.name !== root.name && inside(other.path, landed));
103
+ found.push({
104
+ rule: 'cross-frond-import',
105
+ frond: root.name,
106
+ filePath,
107
+ specifier,
108
+ ...(target ? { target: target.name } : {}),
109
+ message: target
110
+ ? `'${specifier}' resolves into frond '${target.name}'. A relative path states that `
111
+ + `these two fronds share a directory tree — a constraint nothing declares, and one `
112
+ + `that nothing here can see. Write '${target.package}/…' instead: it says the `
113
+ + `same dependency in terms the model reads, and it is the form \`fougere sync\` writes, `
114
+ + `so it survives '${target.name}' moving out.`
115
+ : `'${specifier}' resolves outside frond '${root.name}', into no frond at all. `
116
+ + `Whatever it reaches is not part of any frond's contract, so nothing carries it `
117
+ + `when this one is deployed on its own.`,
118
+ });
119
+ }
120
+ }
121
+ }
122
+ return found;
123
+ }
package/src/index.ts ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * What a consumer writes, and nothing else.
3
+ *
4
+ * `exports` publishes this barrel and `./contract`, so an import that is not here
5
+ * cannot be reached from outside the package at all — which is what makes this file
6
+ * the contract rather than a convenience. The machinery the boot uses to keep its own
7
+ * promises stays inside: container keys, the binding plan, the mixin's runtime
8
+ * accessors, the config merge. Measured on 2026-08-16, none of them had a single
9
+ * importer anywhere in the workspace.
10
+ */
11
+ export { createApp } from './boot/bootstrap.js';
12
+ export { orderSeeds, runSeeds, seeding } from './boot/seed.js';
13
+ export { AppLifecycle, AppLifecycle as Lifecycle, migrating } from './boot/AppLifecycle.js';
14
+ export type { Extension } from './boot/AppLifecycle.js';
15
+ export { defineFougere } from './define.js';
16
+ export type { AdapterConfig, FougereConfig } from './config-loader.js';
17
+ export type { FrondConfig, OperationOverride } from './frond-config.js';
18
+ export { buildGraph, clusterEntities, suggestSplit, type EntityNode, type DomainCluster } from './graph.js';
19
+ export { Crud } from './prefab/crud.js';
20
+ export type { CrudOps, CrudOpName, CrudViews, CrudConstructor } from './prefab/crud.js';
21
+ export { Mirror } from './prefab/mirror.js';
22
+ export type { MirrorOf, MirrorConstructor, Refreshed } from './prefab/mirror.js';
23
+ export { Presenter } from './prefab/presenter.js';
24
+ export type { PresenterViews } from './prefab/presenter.js';
25
+ export { Collector } from './prefab/collector.js';
26
+ export { Repository, type RepositoryOf, type RepositoryConstructor, type AggregateOf, type AggregateConstructor } from './prefab/repository.js';
27
+ export { Invocation, canonicalInvocation, EMPTY_INVOCATION } from './contract/Invocation.js';
28
+ export type { InvocationContext, InvocationInput } from './contract/Invocation.js';
29
+ export { Call } from './contract/Call.js';
30
+ export { RouteAddress } from './contract/RouteAddress.js';
31
+ export type { RouteAddressInput } from './contract/RouteAddress.js';
32
+ export { DispatchLifecycle } from './dispatch/DispatchLifecycle.js';
33
+ export { Dispatcher } from './dispatch/Dispatcher.js';
34
+ export type { DispatchEvent, DispatchObserver } from './dispatch/DispatchEvent.js';
35
+ export type { DispatchPort } from './dispatch/DispatchPort.js';
36
+ export {
37
+ inferOperationKind,
38
+ resolveContracts,
39
+ resolveIsReadOp,
40
+ resolveOperationKind,
41
+ } from './wire/operation.js';
42
+ export type {
43
+ OperationContract,
44
+ OperationKind,
45
+ OperationKindInference,
46
+ OperationsMap,
47
+ ParsedParam,
48
+ ParsedType,
49
+ } from './wire/operation.js';
50
+ export {
51
+ EFFECTIVE_OPERATION_SEMANTICS,
52
+ EffectiveOperationModel,
53
+ resolveEffectiveOperations,
54
+ } from './effective-operation.js';
55
+ export type {
56
+ EffectiveCollector,
57
+ EffectiveOperation,
58
+ EffectiveOperationOptions,
59
+ EffectiveOperationsMap,
60
+ EffectiveParameter,
61
+ } from './effective-operation.js';
62
+ export type { ModuleLoader } from './loader.js';
63
+ export { FougereError, ErrorCode, validationErrorsOf, type FougereErrorOptions } from './wire/errors.js';
64
+ export type { OperationContext, AppNext, AppMiddleware } from './wire/middleware.js';
65
+ export { createLocalRunner, createAppRunner, assertIdentityCard } from './wire/call.js';
66
+ export type {
67
+ FrondCall, Transport, IdentityCard, CardOp, Facade, RpcAnswer,
68
+ TopologyReport, FrondPlacement, Edge,
69
+ } from './wire/call.js';
70
+ export { type Emit, type Fact } from './emit.js';
71
+ export { callValueOf } from './contract.js';
72
+ export type { CallValue } from './contract.js';
73
+ export { toHttpError, toPublicError } from './wire/http-error.js';
74
+ export { loggerMiddleware } from './wire/loggerMiddleware.js';
75
+ export { Logger, setLogLevel, logLevel, envLevel, onLog } from './builtins/logger.js';
76
+ export type { LogLevel, LogRecord, LogSink } from './builtins/logger.js';
77
+ // What a re-read config changes in a running process — and what it cannot.
78
+ export { applyConfig, type ConfigApplication } from './boot/apply.js';
79
+ export { Config } from './builtins/config.js';
80
+ export type { EntityOrm, OrmFactory, ListOptions, ListResult, Together } from './orm.js';
81
+ export { togetherKeyOf, membersOfTogetherKey } from './orm.js';
82
+ export type { App, CreateAppOptions } from './boot/types.js';
83
+ export type {
84
+ ScanResult,
85
+ ScanDiagnostic,
86
+ FrondDescriptor,
87
+ FrondSource,
88
+ ProviderEntry,
89
+ EntityEntry,
90
+ HandlerEntry,
91
+ SeedEntry,
92
+ SeedFactory,
93
+ PresenterEntry,
94
+ PresenterFieldMeta,
95
+ CollectorEntry,
96
+ } from './scan/frond.js';
97
+ export type { AuthConfig, AuthContext, AuthRuntime } from './boot/auth.js';
98
+ export { Fronds } from './scan/Fronds.js';
99
+ export { verify, assertSplittable, type Violation } from './verify.js';
100
+ // Same question as verify(), answered from the source text instead of the model.
101
+ export type { CrossFrondImport } from './imports.js';
102
+ // Who is calling, established rather than accepted — the proof beside `state`'s claim.
103
+ // `generateKeyPair` and `issueGrant` are NOT here: they make keys at a deployment and
104
+ // need `node:crypto` for a gesture WebCrypto has no equal of. They sit on `/node`.
105
+ export { signEnvelope, verifyEnvelope, identityFromEnv } from './identity.js';
106
+ export type { FrondIdentity, VerifiedCall, CallIdentity, SignedCall } from './identity.js';
package/src/loader.ts ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * How a source file becomes a module — one registry, two readers.
3
+ *
4
+ * The scanner loads fronds and `config-loader` loads a config, and both must use the
5
+ * loader the host installed: a TS file needs jiti under Nuxt and plain `import` under
6
+ * tsx. It lived in `scan/scanner.ts`, so reading a config dragged the scanner, its AST
7
+ * parser and the TypeScript compiler behind it.
8
+ */
9
+ import { pathToFileURL } from 'node:url';
10
+
11
+ /**
12
+ * Module loader — can be swapped (e.g. jiti for TS files in Nuxt context).
13
+ *
14
+ * `fresh` asks for a file that may have changed since it was last read. Every loader
15
+ * caches, so without it a second read of an EDITED file hands back the first one —
16
+ * which is what re-reading a config is for. A loader that cannot honour it may ignore
17
+ * the flag; it then answers with what it already had.
18
+ */
19
+ export type ModuleLoader = (
20
+ filePath: string,
21
+ options?: { fresh?: boolean },
22
+ ) => Promise<Record<string, unknown>>;
23
+
24
+ const defaultLoader: ModuleLoader = async (filePath, options) => {
25
+ // On the URL, never on the path: `pathToFileURL` percent-encodes a `?` into the
26
+ // filename, and the import then looks for a file whose name ends in `%3Fv=…`.
27
+ const url = pathToFileURL(filePath).href;
28
+ return await import(options?.fresh ? `${url}?v=${Date.now()}` : url);
29
+ };
30
+
31
+ let activeLoader: ModuleLoader = defaultLoader;
32
+
33
+ /** Override the module loader used by the scanner (e.g. for jiti/tsx support). */
34
+ export function setModuleLoader(loader: ModuleLoader): void {
35
+ activeLoader = loader;
36
+ }
37
+
38
+ /** Used by config-loader to load fougere.config.ts via the same TS-aware loader. */
39
+ export function getModuleLoader(): ModuleLoader {
40
+ return activeLoader;
41
+ }
package/src/node.ts ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What Fougere does with a filesystem — the half of core that a Worker cannot run.
3
+ *
4
+ * The line is not "build vs runtime": `boot()` and `loadConfig` run in production, on a
5
+ * server, every time. It is whether the thing reaches for a disk. Everything here does,
6
+ * transitively, and nothing on the main entry does — which is what lets a bundler for a
7
+ * runtime without `node:fs` trace the main entry and find no builtin at all.
8
+ *
9
+ * The third entry, `@fougere/core/contract`, answers a different question: what crosses a
10
+ * process boundary. A foreign frond reads it without reading our boot.
11
+ */
12
+ export { boot } from './boot/boot.js';
13
+
14
+ export { scanProject, frondAliases } from './scan/scanner.js';
15
+ export {
16
+ type Conventions, type ConventionsInput, DEFAULT_CONVENTIONS,
17
+ resolveConventions, frondPackage, frondDirsOf, providerDirsOf, watchPathsOf,
18
+ } from './scan/conventions.js';
19
+ export { emitScan, type EmitOptions } from './scan/emit.js';
20
+ export { setModuleLoader, getModuleLoader } from './loader.js';
21
+ export { loadConfig, loadCascadedConfig } from './config-loader.js';
22
+ export { defineFrond } from './frond-config.js';
23
+ export { crossFrondImports } from './imports.js';
24
+
25
+ // Making a key and binding a name to it happen once, at a deployment, on a machine with
26
+ // a filesystem — the CLI speaking. Verifying happens per call, everywhere, and stays on
27
+ // the main entry behind `#crypto`.
28
+ export { generateKeyPair, issueGrant } from './identity-keys.js';