@fougere/core 0.5.0-alpha.1 → 0.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/boot/Emissions.d.ts +14 -91
- package/dist/boot/Emissions.d.ts.map +1 -1
- package/dist/boot/Emissions.js +21 -118
- package/dist/boot/Emissions.js.map +1 -1
- package/dist/boot/ambient-port.d.ts +3 -24
- package/dist/boot/ambient-port.d.ts.map +1 -1
- package/dist/boot/ambient.als.d.ts.map +1 -1
- package/dist/boot/ambient.als.js +7 -12
- package/dist/boot/ambient.als.js.map +1 -1
- package/dist/boot/ambient.queue.d.ts +2 -5
- package/dist/boot/ambient.queue.d.ts.map +1 -1
- package/dist/boot/ambient.queue.js.map +1 -1
- package/dist/boot/apply.d.ts +1 -13
- package/dist/boot/apply.d.ts.map +1 -1
- package/dist/boot/apply.js +3 -15
- package/dist/boot/apply.js.map +1 -1
- package/dist/boot/auth.d.ts +6 -16
- package/dist/boot/auth.d.ts.map +1 -1
- package/dist/boot/boot.d.ts +5 -18
- package/dist/boot/boot.d.ts.map +1 -1
- package/dist/boot/boot.js +4 -11
- package/dist/boot/boot.js.map +1 -1
- package/dist/boot/bootstrap.d.ts.map +1 -1
- package/dist/boot/bootstrap.js +106 -163
- package/dist/boot/bootstrap.js.map +1 -1
- package/dist/boot/card.d.ts +5 -0
- package/dist/boot/card.d.ts.map +1 -0
- package/dist/boot/card.js +71 -0
- package/dist/boot/card.js.map +1 -0
- package/dist/boot/frame.d.ts +8 -32
- package/dist/boot/frame.d.ts.map +1 -1
- package/dist/boot/frame.js +23 -57
- package/dist/boot/frame.js.map +1 -1
- package/dist/boot/hosted.d.ts +3 -19
- package/dist/boot/hosted.d.ts.map +1 -1
- package/dist/boot/hosted.js +12 -17
- package/dist/boot/hosted.js.map +1 -1
- package/dist/boot/ownership.d.ts +5 -36
- package/dist/boot/ownership.d.ts.map +1 -1
- package/dist/boot/ownership.js +9 -49
- package/dist/boot/ownership.js.map +1 -1
- package/dist/boot/ports.d.ts +2 -15
- package/dist/boot/ports.d.ts.map +1 -1
- package/dist/boot/ports.js +1 -14
- package/dist/boot/ports.js.map +1 -1
- package/dist/boot/remote.d.ts +5 -38
- package/dist/boot/remote.d.ts.map +1 -1
- package/dist/boot/remote.js +8 -41
- package/dist/boot/remote.js.map +1 -1
- package/dist/boot/runner.d.ts +11 -0
- package/dist/boot/runner.d.ts.map +1 -0
- package/dist/boot/runner.js +13 -0
- package/dist/boot/runner.js.map +1 -0
- package/dist/boot/seed.d.ts +5 -32
- package/dist/boot/seed.d.ts.map +1 -1
- package/dist/boot/seed.js +10 -41
- package/dist/boot/seed.js.map +1 -1
- package/dist/boot/statement-drift.d.ts +4 -22
- package/dist/boot/statement-drift.d.ts.map +1 -1
- package/dist/boot/statement-drift.js +4 -9
- package/dist/boot/statement-drift.js.map +1 -1
- package/dist/boot/together.d.ts +8 -12
- package/dist/boot/together.d.ts.map +1 -1
- package/dist/boot/together.js +28 -65
- package/dist/boot/together.js.map +1 -1
- package/dist/boot/types.d.ts +36 -180
- package/dist/boot/types.d.ts.map +1 -1
- package/dist/builtin/config.d.ts +7 -0
- package/dist/builtin/config.d.ts.map +1 -0
- package/dist/builtin/config.js +15 -0
- package/dist/builtin/config.js.map +1 -0
- package/dist/{builtins → builtin}/logger.d.ts +4 -25
- package/dist/builtin/logger.d.ts.map +1 -0
- package/dist/{builtins → builtin}/logger.js +5 -32
- package/dist/builtin/logger.js.map +1 -0
- package/dist/config-loader.d.ts +9 -67
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +5 -18
- package/dist/config-loader.js.map +1 -1
- package/dist/contract.d.ts +13 -31
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +10 -26
- package/dist/contract.js.map +1 -1
- package/dist/crypto/encoding.d.ts +2 -15
- package/dist/crypto/encoding.d.ts.map +1 -1
- package/dist/crypto/encoding.js +2 -15
- package/dist/crypto/encoding.js.map +1 -1
- package/dist/crypto/node.d.ts.map +1 -1
- package/dist/crypto/node.js +1 -7
- package/dist/crypto/node.js.map +1 -1
- package/dist/crypto/port.d.ts +2 -18
- package/dist/crypto/port.d.ts.map +1 -1
- package/dist/crypto/port.js +1 -17
- package/dist/crypto/port.js.map +1 -1
- package/dist/crypto/webcrypto.d.ts.map +1 -1
- package/dist/crypto/webcrypto.js +1 -12
- package/dist/crypto/webcrypto.js.map +1 -1
- package/dist/declare.d.ts +41 -0
- package/dist/declare.d.ts.map +1 -0
- package/dist/{scan/declare.js → declare.js} +6 -31
- package/dist/declare.js.map +1 -0
- package/dist/define.d.ts +2 -3
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +2 -3
- package/dist/define.js.map +1 -1
- package/dist/descriptor/Fronds.d.ts +19 -0
- package/dist/descriptor/Fronds.d.ts.map +1 -0
- package/dist/descriptor/Fronds.js +40 -0
- package/dist/descriptor/Fronds.js.map +1 -0
- package/dist/descriptor/frond.d.ts +135 -0
- package/dist/descriptor/frond.d.ts.map +1 -0
- package/dist/{scan → descriptor}/frond.js.map +1 -1
- package/dist/dispatch/ArgumentResolver.d.ts +6 -3
- package/dist/dispatch/ArgumentResolver.d.ts.map +1 -1
- package/dist/dispatch/ArgumentResolver.js +48 -3
- package/dist/dispatch/ArgumentResolver.js.map +1 -1
- package/dist/dispatch/DispatchEvent.d.ts +2 -2
- package/dist/dispatch/DispatchEvent.d.ts.map +1 -1
- package/dist/dispatch/DispatchLifecycle.d.ts +1 -7
- package/dist/dispatch/DispatchLifecycle.d.ts.map +1 -1
- package/dist/dispatch/DispatchLifecycle.js +1 -7
- package/dist/dispatch/DispatchLifecycle.js.map +1 -1
- package/dist/dispatch/DispatchPort.d.ts +1 -1
- package/dist/dispatch/DispatchPort.d.ts.map +1 -1
- package/dist/dispatch/Dispatcher.d.ts +1 -1
- package/dist/dispatch/Dispatcher.d.ts.map +1 -1
- package/dist/dispatch/Dispatcher.js +2 -2
- package/dist/dispatch/Dispatcher.js.map +1 -1
- package/dist/{boot → dispatch}/HandlerFacade.d.ts +25 -38
- package/dist/dispatch/HandlerFacade.d.ts.map +1 -0
- package/dist/{boot → dispatch}/HandlerFacade.js +65 -74
- package/dist/dispatch/HandlerFacade.js.map +1 -0
- package/dist/dispatch/LocalRoutePolicy.d.ts +1 -1
- package/dist/dispatch/LocalRoutePolicy.d.ts.map +1 -1
- package/dist/dispatch/LocalRoutePolicy.js +4 -4
- package/dist/dispatch/LocalRoutePolicy.js.map +1 -1
- package/dist/dispatch/OperationRoute.d.ts +2 -2
- package/dist/dispatch/OperationRoute.d.ts.map +1 -1
- package/dist/dispatch/OutputView.d.ts +3 -2
- package/dist/dispatch/OutputView.d.ts.map +1 -1
- package/dist/dispatch/OutputView.js +19 -1
- package/dist/dispatch/OutputView.js.map +1 -1
- package/dist/dispatch/Route.d.ts +2 -3
- package/dist/dispatch/Route.d.ts.map +1 -1
- package/dist/dispatch/RoutePolicy.d.ts +1 -1
- package/dist/dispatch/RoutePolicy.d.ts.map +1 -1
- package/dist/dispatch/RouteRegistry.d.ts +1 -1
- package/dist/dispatch/RouteRegistry.d.ts.map +1 -1
- package/dist/dispatch/RouteRegistry.js +2 -2
- package/dist/dispatch/RouteRegistry.js.map +1 -1
- package/dist/dispatch/RouteResolver.d.ts +2 -4
- package/dist/dispatch/RouteResolver.d.ts.map +1 -1
- package/dist/dispatch/StorageGuard.d.ts +9 -8
- package/dist/dispatch/StorageGuard.d.ts.map +1 -1
- package/dist/dispatch/StorageGuard.js +66 -23
- package/dist/dispatch/StorageGuard.js.map +1 -1
- package/dist/dispatch/presenterArguments.d.ts +7 -0
- package/dist/dispatch/presenterArguments.d.ts.map +1 -0
- package/dist/dispatch/presenterArguments.js +12 -0
- package/dist/dispatch/presenterArguments.js.map +1 -0
- package/dist/dispatch/remoteRoutes.d.ts +7 -0
- package/dist/dispatch/remoteRoutes.d.ts.map +1 -0
- package/dist/dispatch/{RemoteRouteResolver.js → remoteRoutes.js} +6 -10
- package/dist/dispatch/remoteRoutes.js.map +1 -0
- package/dist/dispatch/routeNotFound.d.ts +9 -0
- package/dist/dispatch/routeNotFound.d.ts.map +1 -0
- package/dist/dispatch/routeNotFound.js +21 -0
- package/dist/dispatch/routeNotFound.js.map +1 -0
- package/dist/dispatch/validateInput.d.ts +5 -0
- package/dist/dispatch/validateInput.d.ts.map +1 -0
- package/dist/dispatch/validateInput.js +20 -0
- package/dist/dispatch/validateInput.js.map +1 -0
- package/dist/effective-operation.d.ts +6 -3
- package/dist/effective-operation.d.ts.map +1 -1
- package/dist/effective-operation.js +49 -27
- package/dist/effective-operation.js.map +1 -1
- package/dist/emit.d.ts +4 -42
- package/dist/emit.d.ts.map +1 -1
- package/dist/emit.js +3 -39
- package/dist/emit.js.map +1 -1
- package/dist/entry/facade.d.ts +8 -0
- package/dist/entry/facade.d.ts.map +1 -0
- package/dist/entry/facade.js +28 -0
- package/dist/entry/facade.js.map +1 -0
- package/dist/entry/transport.d.ts +5 -0
- package/dist/entry/transport.d.ts.map +1 -0
- package/dist/entry/transport.js +11 -0
- package/dist/entry/transport.js.map +1 -0
- package/dist/frond-config.d.ts +8 -71
- package/dist/frond-config.d.ts.map +1 -1
- package/dist/frond-config.js +1 -9
- package/dist/frond-config.js.map +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/graph.d.ts.map +1 -1
- package/dist/identity-keys.d.ts +2 -5
- package/dist/identity-keys.d.ts.map +1 -1
- package/dist/identity-keys.js +3 -16
- package/dist/identity-keys.js.map +1 -1
- package/dist/identity.d.ts +4 -30
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +11 -73
- package/dist/identity.js.map +1 -1
- package/dist/imports.d.ts +2 -8
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +1 -7
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +28 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -22
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +1 -8
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +1 -8
- package/dist/loader.js.map +1 -1
- package/dist/node.d.ts +2 -11
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +2 -11
- package/dist/node.js.map +1 -1
- package/dist/prefab/collector.d.ts +1 -22
- package/dist/prefab/collector.d.ts.map +1 -1
- package/dist/prefab/collector.js +1 -22
- package/dist/prefab/collector.js.map +1 -1
- package/dist/prefab/crud.d.ts +19 -35
- package/dist/prefab/crud.d.ts.map +1 -1
- package/dist/prefab/crud.js +39 -66
- package/dist/prefab/crud.js.map +1 -1
- package/dist/prefab/mirror.d.ts +5 -27
- package/dist/prefab/mirror.d.ts.map +1 -1
- package/dist/prefab/mirror.js +6 -24
- package/dist/prefab/mirror.js.map +1 -1
- package/dist/prefab/prefab.d.ts +1 -7
- package/dist/prefab/prefab.d.ts.map +1 -1
- package/dist/prefab/prefab.js +1 -7
- package/dist/prefab/prefab.js.map +1 -1
- package/dist/prefab/presenter.d.ts +2 -36
- package/dist/prefab/presenter.d.ts.map +1 -1
- package/dist/prefab/presenter.js +2 -36
- package/dist/prefab/presenter.js.map +1 -1
- package/dist/prefab/repository.d.ts +12 -80
- package/dist/prefab/repository.d.ts.map +1 -1
- package/dist/prefab/repository.js +22 -35
- package/dist/prefab/repository.js.map +1 -1
- package/dist/scan/adapters.d.ts +3 -0
- package/dist/scan/adapters.d.ts.map +1 -0
- package/dist/scan/adapters.js +25 -0
- package/dist/scan/adapters.js.map +1 -0
- package/dist/scan/bundling.d.ts +1 -12
- package/dist/scan/bundling.d.ts.map +1 -1
- package/dist/scan/bundling.js +1 -12
- package/dist/scan/bundling.js.map +1 -1
- package/dist/scan/conventions.d.ts +6 -40
- package/dist/scan/conventions.d.ts.map +1 -1
- package/dist/scan/conventions.js +5 -34
- package/dist/scan/conventions.js.map +1 -1
- package/dist/scan/emit.d.ts +2 -6
- package/dist/scan/emit.d.ts.map +1 -1
- package/dist/scan/emit.js +5 -39
- package/dist/scan/emit.js.map +1 -1
- package/dist/scan/handler-parser.d.ts +9 -76
- package/dist/scan/handler-parser.d.ts.map +1 -1
- package/dist/scan/handler-parser.js +28 -85
- package/dist/scan/handler-parser.js.map +1 -1
- package/dist/scan/result.d.ts +28 -0
- package/dist/scan/result.d.ts.map +1 -0
- package/dist/scan/result.js +2 -0
- package/dist/scan/result.js.map +1 -0
- package/dist/scan/scanner.d.ts +3 -28
- package/dist/scan/scanner.d.ts.map +1 -1
- package/dist/scan/scanner.js +36 -135
- package/dist/scan/scanner.js.map +1 -1
- package/dist/scan/statement.d.ts +1 -1
- package/dist/scan/statement.d.ts.map +1 -1
- package/dist/scan/statement.js +4 -30
- package/dist/scan/statement.js.map +1 -1
- package/dist/source.d.ts +41 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +10 -0
- package/dist/source.js.map +1 -0
- package/dist/storage.d.ts +92 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +50 -0
- package/dist/storage.js.map +1 -0
- package/dist/store.d.ts +18 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +146 -0
- package/dist/store.js.map +1 -0
- package/dist/verify.d.ts +6 -39
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +19 -39
- package/dist/verify.js.map +1 -1
- package/dist/wire/CallLog.d.ts +32 -0
- package/dist/wire/CallLog.d.ts.map +1 -0
- package/dist/{contract → wire}/CallLog.js.map +1 -1
- package/dist/wire/Invocation.d.ts +32 -0
- package/dist/wire/Invocation.d.ts.map +1 -0
- package/dist/wire/Invocation.js +66 -0
- package/dist/wire/Invocation.js.map +1 -0
- package/dist/wire/RouteAddress.d.ts +24 -0
- package/dist/wire/RouteAddress.d.ts.map +1 -0
- package/dist/{contract → wire}/RouteAddress.js +7 -0
- package/dist/wire/RouteAddress.js.map +1 -0
- package/dist/wire/binding.d.ts +36 -0
- package/dist/wire/binding.d.ts.map +1 -0
- package/dist/{boot → wire}/binding.js +5 -62
- package/dist/wire/binding.js.map +1 -0
- package/dist/wire/call.d.ts +25 -172
- package/dist/wire/call.d.ts.map +1 -1
- package/dist/wire/call.js +15 -166
- package/dist/wire/call.js.map +1 -1
- package/dist/wire/drift.d.ts +3 -28
- package/dist/wire/drift.d.ts.map +1 -1
- package/dist/wire/drift.js +4 -23
- package/dist/wire/drift.js.map +1 -1
- package/dist/wire/errors.d.ts +4 -24
- package/dist/wire/errors.d.ts.map +1 -1
- package/dist/wire/errors.js +4 -24
- package/dist/wire/errors.js.map +1 -1
- package/dist/wire/http-error.d.ts +2 -13
- package/dist/wire/http-error.d.ts.map +1 -1
- package/dist/wire/http-error.js +5 -19
- package/dist/wire/http-error.js.map +1 -1
- package/dist/wire/loggerMiddleware.d.ts +2 -8
- package/dist/wire/loggerMiddleware.d.ts.map +1 -1
- package/dist/wire/loggerMiddleware.js +1 -7
- package/dist/wire/loggerMiddleware.js.map +1 -1
- package/dist/wire/middleware.d.ts +3 -7
- package/dist/wire/middleware.d.ts.map +1 -1
- package/dist/wire/middleware.js +1 -5
- package/dist/wire/middleware.js.map +1 -1
- package/dist/wire/operation.d.ts +12 -74
- package/dist/wire/operation.d.ts.map +1 -1
- package/dist/wire/operation.js +4 -66
- package/dist/wire/operation.js.map +1 -1
- package/dist/wire/signature.d.ts +37 -0
- package/dist/wire/signature.d.ts.map +1 -0
- package/dist/wire/signature.js +2 -0
- package/dist/wire/signature.js.map +1 -0
- package/package.json +3 -3
- package/src/boot/Emissions.ts +22 -119
- package/src/boot/ambient-port.ts +3 -24
- package/src/boot/ambient.als.ts +7 -12
- package/src/boot/ambient.queue.ts +2 -5
- package/src/boot/apply.ts +3 -15
- package/src/boot/auth.ts +6 -16
- package/src/boot/boot.ts +8 -23
- package/src/boot/bootstrap.ts +117 -173
- package/src/boot/card.ts +84 -0
- package/src/boot/frame.ts +31 -65
- package/src/boot/hosted.ts +15 -40
- package/src/boot/ownership.ts +14 -49
- package/src/boot/ports.ts +2 -15
- package/src/boot/remote.ts +11 -58
- package/src/boot/runner.ts +17 -0
- package/src/boot/seed.ts +11 -42
- package/src/boot/statement-drift.ts +10 -28
- package/src/boot/together.ts +38 -72
- package/src/boot/types.ts +36 -180
- package/src/{builtins → builtin}/config.ts +1 -7
- package/src/{builtins → builtin}/logger.ts +6 -39
- package/src/config-loader.ts +12 -71
- package/src/contract.ts +15 -39
- package/src/crypto/encoding.ts +2 -15
- package/src/crypto/node.ts +1 -7
- package/src/crypto/port.ts +2 -18
- package/src/crypto/webcrypto.ts +1 -12
- package/src/{scan/declare.ts → declare.ts} +11 -42
- package/src/define.ts +2 -3
- package/src/descriptor/Fronds.ts +47 -0
- package/src/descriptor/frond.ts +145 -0
- package/src/dispatch/ArgumentResolver.ts +54 -8
- package/src/dispatch/DispatchEvent.ts +2 -2
- package/src/dispatch/DispatchLifecycle.ts +1 -7
- package/src/dispatch/DispatchPort.ts +1 -1
- package/src/dispatch/Dispatcher.ts +3 -3
- package/src/dispatch/HandlerFacade.ts +231 -0
- package/src/dispatch/LocalRoutePolicy.ts +4 -4
- package/src/dispatch/OperationRoute.ts +2 -2
- package/src/dispatch/OutputView.ts +24 -2
- package/src/dispatch/Route.ts +2 -4
- package/src/dispatch/RoutePolicy.ts +1 -1
- package/src/dispatch/RouteRegistry.ts +2 -2
- package/src/dispatch/RouteResolver.ts +2 -4
- package/src/dispatch/StorageGuard.ts +75 -23
- package/src/dispatch/presenterArguments.ts +25 -0
- package/src/dispatch/{RemoteRouteResolver.ts → remoteRoutes.ts} +7 -9
- package/src/dispatch/routeNotFound.ts +33 -0
- package/src/dispatch/validateInput.ts +28 -0
- package/src/effective-operation.ts +60 -37
- package/src/emit.ts +5 -63
- package/src/entry/facade.ts +44 -0
- package/src/entry/transport.ts +16 -0
- package/src/frond-config.ts +8 -71
- package/src/graph.ts +1 -1
- package/src/identity-keys.ts +3 -16
- package/src/identity.ts +12 -80
- package/src/imports.ts +3 -32
- package/src/index.ts +28 -33
- package/src/loader.ts +2 -16
- package/src/node.ts +2 -11
- package/src/prefab/collector.ts +1 -22
- package/src/prefab/crud.ts +51 -90
- package/src/prefab/mirror.ts +9 -49
- package/src/prefab/prefab.ts +2 -21
- package/src/prefab/presenter.ts +2 -36
- package/src/prefab/repository.ts +32 -108
- package/src/scan/adapters.ts +32 -0
- package/src/scan/bundling.ts +1 -12
- package/src/scan/conventions.ts +6 -40
- package/src/scan/emit.ts +7 -43
- package/src/scan/handler-parser.ts +41 -163
- package/src/scan/result.ts +29 -0
- package/src/scan/scanner.ts +40 -138
- package/src/scan/statement.ts +6 -31
- package/src/source.ts +44 -0
- package/src/storage.ts +141 -0
- package/src/store.ts +152 -0
- package/src/verify.ts +19 -60
- package/src/wire/CallLog.ts +30 -0
- package/src/{contract → wire}/Invocation.ts +24 -17
- package/src/{contract → wire}/RouteAddress.ts +10 -0
- package/src/wire/binding.ts +102 -0
- package/src/wire/call.ts +30 -261
- package/src/wire/drift.ts +5 -30
- package/src/wire/errors.ts +4 -24
- package/src/wire/http-error.ts +5 -19
- package/src/wire/loggerMiddleware.ts +2 -8
- package/src/wire/middleware.ts +3 -7
- package/src/wire/operation.ts +13 -110
- package/src/wire/signature.ts +38 -0
- package/dist/boot/HandlerFacade.d.ts.map +0 -1
- package/dist/boot/HandlerFacade.js.map +0 -1
- package/dist/boot/binding.d.ts +0 -60
- package/dist/boot/binding.d.ts.map +0 -1
- package/dist/boot/binding.js.map +0 -1
- package/dist/builtins/config.d.ts +0 -13
- package/dist/builtins/config.d.ts.map +0 -1
- package/dist/builtins/config.js +0 -21
- package/dist/builtins/config.js.map +0 -1
- package/dist/builtins/logger.d.ts.map +0 -1
- package/dist/builtins/logger.js.map +0 -1
- package/dist/contract/Call.d.ts +0 -10
- package/dist/contract/Call.d.ts.map +0 -1
- package/dist/contract/Call.js +0 -15
- package/dist/contract/Call.js.map +0 -1
- package/dist/contract/CallLog.d.ts +0 -57
- package/dist/contract/CallLog.d.ts.map +0 -1
- package/dist/contract/Invocation.d.ts +0 -27
- package/dist/contract/Invocation.d.ts.map +0 -1
- package/dist/contract/Invocation.js +0 -59
- package/dist/contract/Invocation.js.map +0 -1
- package/dist/contract/RouteAddress.d.ts +0 -17
- package/dist/contract/RouteAddress.d.ts.map +0 -1
- package/dist/contract/RouteAddress.js.map +0 -1
- package/dist/dispatch/InputValidator.d.ts +0 -7
- package/dist/dispatch/InputValidator.d.ts.map +0 -1
- package/dist/dispatch/InputValidator.js +0 -22
- package/dist/dispatch/InputValidator.js.map +0 -1
- package/dist/dispatch/OperationExecutor.d.ts +0 -25
- package/dist/dispatch/OperationExecutor.d.ts.map +0 -1
- package/dist/dispatch/OperationExecutor.js +0 -32
- package/dist/dispatch/OperationExecutor.js.map +0 -1
- package/dist/dispatch/OutputProjector.d.ts +0 -12
- package/dist/dispatch/OutputProjector.d.ts.map +0 -1
- package/dist/dispatch/OutputProjector.js +0 -30
- package/dist/dispatch/OutputProjector.js.map +0 -1
- package/dist/dispatch/PresenterArgumentResolver.d.ts +0 -12
- package/dist/dispatch/PresenterArgumentResolver.d.ts.map +0 -1
- package/dist/dispatch/PresenterArgumentResolver.js +0 -20
- package/dist/dispatch/PresenterArgumentResolver.js.map +0 -1
- package/dist/dispatch/RemoteRouteResolver.d.ts +0 -13
- package/dist/dispatch/RemoteRouteResolver.d.ts.map +0 -1
- package/dist/dispatch/RemoteRouteResolver.js.map +0 -1
- package/dist/dispatch/RouteNotFoundError.d.ts +0 -10
- package/dist/dispatch/RouteNotFoundError.d.ts.map +0 -1
- package/dist/dispatch/RouteNotFoundError.js +0 -24
- package/dist/dispatch/RouteNotFoundError.js.map +0 -1
- package/dist/entry/DynamicFacade.d.ts +0 -10
- package/dist/entry/DynamicFacade.d.ts.map +0 -1
- package/dist/entry/DynamicFacade.js +0 -27
- package/dist/entry/DynamicFacade.js.map +0 -1
- package/dist/entry/FacadeEntry.d.ts +0 -11
- package/dist/entry/FacadeEntry.d.ts.map +0 -1
- package/dist/entry/FacadeEntry.js +0 -26
- package/dist/entry/FacadeEntry.js.map +0 -1
- package/dist/entry/TransportEntry.d.ts +0 -13
- package/dist/entry/TransportEntry.d.ts.map +0 -1
- package/dist/entry/TransportEntry.js +0 -24
- package/dist/entry/TransportEntry.js.map +0 -1
- package/dist/orm.d.ts +0 -207
- package/dist/orm.d.ts.map +0 -1
- package/dist/orm.js +0 -66
- package/dist/orm.js.map +0 -1
- package/dist/scan/Fronds.d.ts +0 -45
- package/dist/scan/Fronds.d.ts.map +0 -1
- package/dist/scan/Fronds.js +0 -66
- package/dist/scan/Fronds.js.map +0 -1
- package/dist/scan/declare.d.ts +0 -71
- package/dist/scan/declare.d.ts.map +0 -1
- package/dist/scan/declare.js.map +0 -1
- package/dist/scan/frond.d.ts +0 -224
- package/dist/scan/frond.d.ts.map +0 -1
- package/src/boot/HandlerFacade.ts +0 -242
- package/src/boot/binding.ts +0 -182
- package/src/contract/Call.ts +0 -18
- package/src/contract/CallLog.ts +0 -55
- package/src/dispatch/InputValidator.ts +0 -28
- package/src/dispatch/OperationExecutor.ts +0 -60
- package/src/dispatch/OutputProjector.ts +0 -32
- package/src/dispatch/PresenterArgumentResolver.ts +0 -25
- package/src/dispatch/RouteNotFoundError.ts +0 -29
- package/src/entry/DynamicFacade.ts +0 -28
- package/src/entry/FacadeEntry.ts +0 -32
- package/src/entry/TransportEntry.ts +0 -30
- package/src/orm.ts +0 -252
- package/src/scan/Fronds.ts +0 -73
- package/src/scan/frond.ts +0 -235
- /package/dist/{scan → descriptor}/frond.js +0 -0
- /package/dist/{contract → wire}/CallLog.js +0 -0
package/src/boot/bootstrap.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { Container } from '@fougere/container';
|
|
2
2
|
import { lowerFirst, type SchemaView } from '@fougere/schema';
|
|
3
|
-
import type { EntityEntry, HandlerEntry, PresenterEntry } from '../
|
|
3
|
+
import type { EntityEntry, HandlerEntry, PresenterEntry } from '../descriptor/frond.js';
|
|
4
4
|
import { hostedBy } from './hosted.js';
|
|
5
5
|
import type { AuthRuntime } from './auth.js';
|
|
6
6
|
import type { CreateAppOptions, App } from './types.js';
|
|
7
7
|
import type { AppMiddleware } from '../wire/middleware.js';
|
|
8
|
-
import { Logger } from '../
|
|
9
|
-
import { Config } from '../
|
|
8
|
+
import { Logger } from '../builtin/logger.js';
|
|
9
|
+
import { Config } from '../builtin/config.js';
|
|
10
10
|
import { createRemoteRouter, createRemoteFacade } from './remote.js';
|
|
11
11
|
import { registerFrames } from './together.js';
|
|
12
12
|
import { Emissions } from './Emissions.js';
|
|
13
|
-
import { HandlerFacade } from '
|
|
13
|
+
import { HandlerFacade } from '../dispatch/HandlerFacade.js';
|
|
14
14
|
import { targetOf } from '../prefab/prefab.js';
|
|
15
|
-
import { ownersOf,
|
|
15
|
+
import { ownersOf, refuseStorageInUserCode, refuseCrudOnOwned } from './ownership.js';
|
|
16
16
|
import type { OperationContract, OperationsMap } from '../wire/operation.js';
|
|
17
17
|
import {
|
|
18
18
|
resolveEffectiveOperations,
|
|
@@ -22,50 +22,31 @@ import { StorageGuard } from '../dispatch/StorageGuard.js';
|
|
|
22
22
|
import { portBindings } from './ports.js';
|
|
23
23
|
import { InFlight } from '../dispatch/InFlight.js';
|
|
24
24
|
// The keys, each read from where its concept is declared — never respelled here.
|
|
25
|
-
import { facadeKeyOf, contractsKeyOf,
|
|
25
|
+
import { facadeKeyOf, contractsKeyOf, type RpcAnswer } from '../wire/call.js';
|
|
26
|
+
import { identityCardOf } from './card.js';
|
|
26
27
|
import { AppLifecycle } from './AppLifecycle.js';
|
|
28
|
+
import { inheritsCrud, subjectOf } from '../prefab/crud.js';
|
|
27
29
|
import { repositoryKeyOf } from '../prefab/repository.js';
|
|
28
|
-
import {
|
|
30
|
+
import { storageKeyOf } from '../storage.js';
|
|
29
31
|
import { presenterKeyOf } from '../prefab/presenter.js';
|
|
30
32
|
import { collectorKeyOf } from '../prefab/collector.js';
|
|
31
|
-
import { RouteAddress } from '../
|
|
33
|
+
import { RouteAddress } from '../wire/RouteAddress.js';
|
|
32
34
|
import { DispatchLifecycle } from '../dispatch/DispatchLifecycle.js';
|
|
33
35
|
import { Dispatcher } from '../dispatch/Dispatcher.js';
|
|
34
36
|
import { LocalRoutePolicy } from '../dispatch/LocalRoutePolicy.js';
|
|
35
37
|
import { OperationRoute } from '../dispatch/OperationRoute.js';
|
|
36
|
-
import {
|
|
38
|
+
import { remoteRoutes } from '../dispatch/remoteRoutes.js';
|
|
37
39
|
import { RouteRegistry } from '../dispatch/RouteRegistry.js';
|
|
38
|
-
import {
|
|
40
|
+
import { facadeOperations } from '../entry/facade.js';
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
/**
|
|
42
|
-
* The one wording for "nobody hosts this here", with both ways out. Said twice, and the
|
|
43
|
-
* second copy (`schemaFor`) had lost the two remedies — the same dead end, strictly less
|
|
44
|
-
* useful, for no reason.
|
|
45
|
-
*/
|
|
43
|
+
/** The one wording for "nobody hosts this here", with both ways out. */
|
|
46
44
|
const notLoaded = (entity: string) =>
|
|
47
45
|
`Frond for '${entity}' is not loaded.\n` +
|
|
48
46
|
` - Add '${entity}' to --fronds flag\n` +
|
|
49
47
|
` - Or declare a remote: remotes: { ${entity}: 'http://...' }`;
|
|
50
48
|
|
|
51
|
-
/**
|
|
52
|
-
* Two fronds cannot claim one name — said at boot, because nothing else says it.
|
|
53
|
-
*
|
|
54
|
-
* A door lands on the ROOT container under `facadeKeyOf(address)`, and that key carries
|
|
55
|
-
* no frond; a presenter lands there too. `registerValue` is a `Map.set`, so the second
|
|
56
|
-
* frond loaded simply replaced the first and every call meant for one went to the other.
|
|
57
|
-
* Silent in-process, and worse than silent under a split: `createRemoteRouter` guards its
|
|
58
|
-
* index with `if (!byEntity.has(...))`, so THERE the first frond discovered wins. The same
|
|
59
|
-
* application answered differently depending on how it was deployed.
|
|
60
|
-
*
|
|
61
|
-
* Refusing is the honest answer while a key cannot say which frond owns it. It is not the
|
|
62
|
-
* last word: qualify the key and this boot can accept both. ORMs and repositories are not
|
|
63
|
-
* checked because they are registered in the frond's own scope, where two fronds do not meet.
|
|
64
|
-
*
|
|
65
|
-
* A frond declared remote registers nothing locally, so it cannot collide here. Two REMOTE
|
|
66
|
-
* fronds publishing one entity still shadow each other inside the router — a hole this
|
|
67
|
-
* check does not reach.
|
|
68
|
-
*/
|
|
49
|
+
/** Two fronds cannot claim one name — said at boot, because nothing else says it. */
|
|
69
50
|
function assertOneOwnerPerKey(
|
|
70
51
|
fronds: { name: string; handlers: HandlerEntry[]; presenters: PresenterEntry[] }[],
|
|
71
52
|
remotes: Record<string, string> | undefined,
|
|
@@ -73,10 +54,10 @@ function assertOneOwnerPerKey(
|
|
|
73
54
|
const owner = new Map<string, string>();
|
|
74
55
|
|
|
75
56
|
const claim = (key: string, frond: string, what: string) => {
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
57
|
+
const first = owner.get(key);
|
|
58
|
+
if (first !== undefined && first !== frond) {
|
|
78
59
|
throw new Error(
|
|
79
|
-
`Two fronds claim the key '${key}': '${
|
|
60
|
+
`Two fronds claim the key '${key}': '${first}' and '${frond}'.\n`
|
|
80
61
|
+ ` A ${what} is registered under a key that names no frond, so one would silently replace the other.\n`
|
|
81
62
|
+ ` - Rename one of the two classes, or\n`
|
|
82
63
|
+ ` - keep one of the two fronds out of this process (--fronds), or declare it in remotes:`,
|
|
@@ -112,6 +93,16 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
112
93
|
// no builtin and a Worker can run what it builds.
|
|
113
94
|
const scanStart = performance.now();
|
|
114
95
|
const { fronds, diagnostics } = await hostedBy(options);
|
|
96
|
+
// An app that states nothing AND scans nothing is a mistake — unless something else it
|
|
97
|
+
// declares brings its own entities, which an auth provider does. Refused here and not in
|
|
98
|
+
// `hostedBy`, which is handed the frond sources and cannot see the rest of the app. The
|
|
99
|
+
// condition is the KEYS, not the count: a scan that found nothing is an ordinary answer.
|
|
100
|
+
if (!options.fronds && !options.scan && !options.auth) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
'createApp needs `fronds:` (what this app states) or `scan:` (what a scanner found). '
|
|
103
|
+
+ 'Neither was given, and nothing else declares entities of its own.',
|
|
104
|
+
);
|
|
105
|
+
}
|
|
115
106
|
const operationModel = resolveEffectiveOperations(fronds, {
|
|
116
107
|
diagnostics,
|
|
117
108
|
remotes: options.remotes,
|
|
@@ -122,22 +113,11 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
122
113
|
log.info(`read ${fronds.length} frond(s) in ${scanMs}ms`
|
|
123
114
|
+ (diagnostics.length ? ` — ${diagnostics.length} thing(s) the scan could not do` : ''));
|
|
124
115
|
|
|
125
|
-
/**
|
|
126
|
-
* Say what could not be read, at the one line everyone already watches.
|
|
127
|
-
*
|
|
128
|
-
* Not a refusal: an app whose `presenters/` is unreadable still serves its
|
|
129
|
-
* entities, and stopping the boot would trade a partial app for none. But it is
|
|
130
|
-
* an ERROR, not a debug line — the app now serves less than its source declares,
|
|
131
|
-
* and nothing downstream can tell that from a source that declares less.
|
|
132
|
-
*/
|
|
116
|
+
/** Say what could not be read, at the one line everyone already watches. */
|
|
133
117
|
for (const d of blocking) log.error(`[${d.code}] ${d.message}`, d.cause);
|
|
134
118
|
for (const d of diagnostics) if (d.severity === 'warning') log.warn(`[${d.code}] ${d.message}`);
|
|
135
119
|
|
|
136
|
-
/**
|
|
137
|
-
* An ambiguous convention is not a partial scan. Every relevant declaration was read,
|
|
138
|
-
* but more than one executable contract can be built from it. Refuse before auth,
|
|
139
|
-
* storage, migrations or seeds make the boot observable.
|
|
140
|
-
*/
|
|
120
|
+
/** An ambiguous convention is not a partial scan. */
|
|
141
121
|
const invalidOperations = operationModel.resolutionDiagnostics
|
|
142
122
|
.filter((diagnostic) => diagnostic.severity === 'blocking');
|
|
143
123
|
if (invalidOperations.length > 0) {
|
|
@@ -152,11 +132,11 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
152
132
|
|
|
153
133
|
// Auth runtime — built once from the lazy AuthConfig produced by a provider factory
|
|
154
134
|
// (e.g. betterAuth({...})) in fougere.config.ts. The provider receives our db +
|
|
155
|
-
//
|
|
135
|
+
// storageFactory so all auth writes flow through Storage.
|
|
156
136
|
let authRuntime: AuthRuntime | undefined;
|
|
157
137
|
if (options.auth) {
|
|
158
|
-
if (!options.
|
|
159
|
-
throw new Error('createApp: `auth` is set but `
|
|
138
|
+
if (!options.storageFactory) {
|
|
139
|
+
throw new Error('createApp: `auth` is set but `storageFactory` is missing — auth providers need it to back their adapter.');
|
|
160
140
|
}
|
|
161
141
|
if (options.db === undefined) {
|
|
162
142
|
throw new Error('createApp: `auth` is set but `db` is missing — pass the storage handle through CreateAppOptions.db.');
|
|
@@ -164,12 +144,12 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
164
144
|
log.info('initializing auth runtime');
|
|
165
145
|
authRuntime = await options.auth.create({
|
|
166
146
|
db: options.db,
|
|
167
|
-
|
|
147
|
+
storageFactory: options.storageFactory,
|
|
168
148
|
});
|
|
169
149
|
log.info(`auth ready — mounted at ${authRuntime.basePath}`);
|
|
170
150
|
}
|
|
171
151
|
|
|
172
|
-
// Remote routing —
|
|
152
|
+
// Remote routing — validated at boot: declaring remotes without a transport is a config error.
|
|
173
153
|
// A remote declaration wins over local presence: `remotes: { blog: url }` IS
|
|
174
154
|
// the topology statement — the frond's code may sit in fronds/**, it runs elsewhere.
|
|
175
155
|
const declaredRemotes = Object.entries(options.remotes ?? {});
|
|
@@ -214,7 +194,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
214
194
|
|
|
215
195
|
assertOneOwnerPerKey(fronds, options.remotes);
|
|
216
196
|
|
|
217
|
-
// Every entity of every frond, by name — so a fact can be
|
|
197
|
+
// Every entity of every frond, by name — so a fact can be validated where it LANDS, and
|
|
218
198
|
// so a `reads:` clause can name a neighbour's.
|
|
219
199
|
const entityByName = fronds.schemas();
|
|
220
200
|
// Which frond holds an entity — what turns "a member is remote" into a refusal that
|
|
@@ -254,14 +234,14 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
254
234
|
// `reads:` is what makes a cross-source reader exist here, and the list IS its
|
|
255
235
|
// environment — a source holding none of these is never opened. Registered under
|
|
256
236
|
// the type's own name, which is the key `depKeyOf` already derives for a plain
|
|
257
|
-
// parameter: `constructor(private
|
|
237
|
+
// parameter: `constructor(private reads: Reads)` and nothing else to say.
|
|
258
238
|
// Declaring `reads:` with nothing to build the reader is a boot that ignores a
|
|
259
|
-
// clause: the handler asking for `
|
|
239
|
+
// clause: the handler asking for `Reads` then dies at its first call, on a
|
|
260
240
|
// container message that names neither the clause nor what is missing.
|
|
261
241
|
if (frond.reads?.length && !options.sourcesFactory) {
|
|
262
242
|
frondLog.warn(
|
|
263
243
|
`[reads] ${frond.reads.join(', ')} — declared in frond.config.ts, but this boot passes no `
|
|
264
|
-
+ '`sourcesFactory`, so no reader is registered and a handler asking for `
|
|
244
|
+
+ '`sourcesFactory`, so no reader is registered and a handler asking for `Reads` will fail '
|
|
265
245
|
+ 'at its first call. Pass one (`@fougere/adapter-duckdb`), or drop the clause.',
|
|
266
246
|
);
|
|
267
247
|
}
|
|
@@ -280,14 +260,14 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
280
260
|
+ 'so a query naming one would find no table. Check the spelling, or the entity file.',
|
|
281
261
|
);
|
|
282
262
|
}
|
|
283
|
-
scope.registerValue('
|
|
263
|
+
scope.registerValue('Reads', await options.sourcesFactory(named, frond.name));
|
|
284
264
|
frondLog.debug(`cross-source reader over ${named.length} entit(ies)`);
|
|
285
265
|
}
|
|
286
266
|
|
|
287
267
|
// Who owns what, and the rule that makes owning mean something. Before anything is
|
|
288
268
|
// registered, so a bad line is named by this refusal rather than by the container's.
|
|
289
269
|
const owners = ownersOf(frond.providers);
|
|
290
|
-
|
|
270
|
+
refuseStorageInUserCode(frond, owners, (entity) => entityByName.has(entity));
|
|
291
271
|
refuseCrudOnOwned(frond, owners);
|
|
292
272
|
|
|
293
273
|
for (const provider of frond.providers) {
|
|
@@ -306,28 +286,28 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
306
286
|
frondLog.debug(`${frond.providers.length} provider(s): ${frond.providers.map((p) => p.ctor.name).join(', ')}`);
|
|
307
287
|
}
|
|
308
288
|
|
|
309
|
-
// Register
|
|
310
|
-
// When a handler declares Crud(Entity, Output), scope the
|
|
311
|
-
if (options.
|
|
289
|
+
// Register Storage for each entity — PascalCase type name (e.g. 'PostStorage')
|
|
290
|
+
// When a handler declares Crud(Entity, Output), scope the storage via .output(Output)
|
|
291
|
+
if (options.storageFactory) {
|
|
312
292
|
for (const entity of frond.entities) {
|
|
313
|
-
const
|
|
314
|
-
const
|
|
293
|
+
const key = storageKeyOf(entity.name);
|
|
294
|
+
const baseStorage = options.storageFactory(entity.entityClass, entity.name);
|
|
315
295
|
|
|
316
296
|
// Check if the default handler (no surface) declares an output override
|
|
317
297
|
const defaultHandler = frond.handlers.find((h) => h.address === entity.name && !h.surface);
|
|
318
298
|
const outputSchema = defaultHandler?.outputOverride ?? (defaultHandler?.ctor as any)?.__output;
|
|
319
299
|
const scoped = outputSchema && outputSchema !== entity.entityClass
|
|
320
|
-
?
|
|
321
|
-
:
|
|
300
|
+
? baseStorage.output(outputSchema)
|
|
301
|
+
: baseStorage;
|
|
322
302
|
|
|
323
303
|
// Storage is a way out like the client surface — see `StorageGuard`.
|
|
324
304
|
const guarded = new StorageGuard(entity.entityClass.getFields(), entity.name).guard(scoped);
|
|
325
|
-
scope.registerValue(
|
|
305
|
+
scope.registerValue(key, guarded);
|
|
326
306
|
|
|
327
307
|
// The default repository IS the guarded port — it already answers every gesture a
|
|
328
308
|
// declared one forwards, so the two forms have the same shape and a handler reads
|
|
329
|
-
// `repo.list()` either way. The wrapper that used to sit here (`{
|
|
330
|
-
// existed to make `repo.
|
|
309
|
+
// `repo.list()` either way. The wrapper that used to sit here (`{ storage: guarded }`)
|
|
310
|
+
// existed to make `repo.storage` true in both, back when `.storage` was the way in.
|
|
331
311
|
//
|
|
332
312
|
// Not registered for an OWNED entity: an aggregate's members are reached through it
|
|
333
313
|
// and nowhere else, and the default would be a second door under a name a handler
|
|
@@ -342,7 +322,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
342
322
|
}
|
|
343
323
|
}
|
|
344
324
|
if (frond.entities.length > 0) {
|
|
345
|
-
frondLog.debug(`${frond.entities.length} entity
|
|
325
|
+
frondLog.debug(`${frond.entities.length} entity storage(s): ${frond.entities.map((e) => e.name).join(', ')}`);
|
|
346
326
|
}
|
|
347
327
|
}
|
|
348
328
|
|
|
@@ -357,8 +337,9 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
357
337
|
entityByName,
|
|
358
338
|
frondOf,
|
|
359
339
|
hostedHere: (name) => !(options.remotes && name in options.remotes),
|
|
360
|
-
|
|
340
|
+
storageFactory: options.storageFactory,
|
|
361
341
|
sourceOf: options.sourceOf,
|
|
342
|
+
transacts: options.transacts,
|
|
362
343
|
transacted: options.transacted,
|
|
363
344
|
log: frondLog,
|
|
364
345
|
},
|
|
@@ -395,25 +376,25 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
395
376
|
targetScope: Container,
|
|
396
377
|
facadeKey: string,
|
|
397
378
|
) => {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
);
|
|
379
|
+
if (inheritsCrud(handler.ctor) && !entity) {
|
|
380
|
+
// An installed Crud subject may be absent from the local scan.
|
|
381
|
+
frondLog.debug(`${handler.ctor.name} extends Crud() and no scanned entity is named `
|
|
382
|
+
+ `'${subjectOf(handler.ctor, handler.address)}' — installed entity, or a missing `
|
|
383
|
+
+ `one: no storage will be injected`);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const facade = new HandlerFacade(handler, targetScope, {
|
|
387
|
+
key: facadeKey,
|
|
388
|
+
frond: frond.name,
|
|
389
|
+
handlers: frond.handlers,
|
|
390
|
+
operations: operationModel.forHandler(handler),
|
|
391
|
+
collectors: collectorTypeNames,
|
|
392
|
+
presenter: presenterMap.get(handler.address),
|
|
393
|
+
presenterScope: scope,
|
|
394
|
+
middlewares: () => getMiddlewares(handler.address),
|
|
395
|
+
});
|
|
396
|
+
// Emissions use the same contracts and execution path as direct calls.
|
|
397
|
+
emissions.note(facade.contracts, facadeKey);
|
|
417
398
|
// The terms alongside the door, under the same audience — a surface that serves
|
|
418
399
|
// fewer ops describes fewer ops.
|
|
419
400
|
container.registerValue(contractsKeyOf(handler.address, handler.surface), facade.contracts);
|
|
@@ -440,18 +421,18 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
440
421
|
routeRegistry.register(new OperationRoute(
|
|
441
422
|
'local',
|
|
442
423
|
address,
|
|
443
|
-
(call) => facade.
|
|
424
|
+
(call) => facade.execute(operation, call.invocation),
|
|
444
425
|
));
|
|
445
426
|
}
|
|
446
427
|
}
|
|
447
428
|
|
|
448
|
-
const
|
|
429
|
+
const operations = facadeOperations(
|
|
449
430
|
handler.surface ? localDispatcher : dispatcher,
|
|
450
431
|
handler.address,
|
|
451
432
|
routeRegistry.operationNames(handler.address, handler.surface),
|
|
452
433
|
handler.surface,
|
|
453
434
|
);
|
|
454
|
-
container.registerValue(facadeKey,
|
|
435
|
+
container.registerValue(facadeKey, operations);
|
|
455
436
|
};
|
|
456
437
|
|
|
457
438
|
// A presenter is about an entity — computed fields sit on a shape — so this walks
|
|
@@ -485,7 +466,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
485
466
|
const facadeKey = facadeKeyOf(handler.address);
|
|
486
467
|
buildFacade(entity, handler, scope, facadeKey);
|
|
487
468
|
frondLog.debug(`${facadeKey} [${Object.keys(container.resolve(facadeKey) as any).join(', ')}]`
|
|
488
|
-
+ (entity ? '' : ' — no entity of that name: no
|
|
469
|
+
+ (entity ? '' : ' — no entity of that name: no storage, no projection, no presenter'));
|
|
489
470
|
}
|
|
490
471
|
|
|
491
472
|
// The dual, and it stays: a shape that declares no operation answers nothing. Said
|
|
@@ -496,7 +477,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
496
477
|
}
|
|
497
478
|
}
|
|
498
479
|
|
|
499
|
-
// Surface handlers — create sub-scope per surface handler with scoped
|
|
480
|
+
// Surface handlers — create sub-scope per surface handler with scoped storage
|
|
500
481
|
//
|
|
501
482
|
// Pointing at nothing is legal HERE TOO. This loop used to `continue` when no entity
|
|
502
483
|
// carried the handler's name, so `handlers/public/SearchHandler.ts` with no `Search`
|
|
@@ -506,25 +487,25 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
506
487
|
const entity = frond.entities.find((e) => e.name === handler.address);
|
|
507
488
|
const surfaceScope = scope.createScope();
|
|
508
489
|
|
|
509
|
-
// Register scoped
|
|
490
|
+
// Register scoped storage if output override differs from entity — under the REPOSITORY
|
|
510
491
|
// key, which is what a Crud handler asks for, and under the port's own for a holder
|
|
511
492
|
// that legitimately names it. Registering only the latter left a named surface with
|
|
512
493
|
// no door at all once the façade stopped spelling the storage.
|
|
513
|
-
if (entity && options.
|
|
514
|
-
const
|
|
494
|
+
if (entity && options.storageFactory) {
|
|
495
|
+
const baseStorage = options.storageFactory(entity.entityClass, entity.name);
|
|
515
496
|
const outputSchema = handler.outputOverride ?? (handler.ctor as any).__output;
|
|
516
497
|
const scoped = outputSchema && outputSchema !== entity.entityClass
|
|
517
|
-
?
|
|
518
|
-
:
|
|
498
|
+
? baseStorage.output(outputSchema)
|
|
499
|
+
: baseStorage;
|
|
519
500
|
const guarded = new StorageGuard(entity.entityClass.getFields(), entity.name).guard(scoped);
|
|
520
|
-
surfaceScope.registerValue(
|
|
501
|
+
surfaceScope.registerValue(storageKeyOf(entity.name), guarded);
|
|
521
502
|
surfaceScope.registerValue(repositoryKeyOf(entity.name), guarded);
|
|
522
503
|
}
|
|
523
504
|
|
|
524
505
|
const facadeKey = facadeKeyOf(handler.address, handler.surface);
|
|
525
506
|
buildFacade(entity, handler, surfaceScope, facadeKey);
|
|
526
507
|
frondLog.debug(`${facadeKey} [${Object.keys(container.resolve(facadeKey) as any).join(', ')}]`
|
|
527
|
-
+ (entity ? '' : ' — no entity of that name: no
|
|
508
|
+
+ (entity ? '' : ' — no entity of that name: no storage, no projection, no presenter'));
|
|
528
509
|
}
|
|
529
510
|
|
|
530
511
|
// A named surface is closed, so what it contains is a fact worth stating.
|
|
@@ -562,17 +543,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
562
543
|
// Once every door exists: what is announced here and what is listened to are both known.
|
|
563
544
|
emissions.register();
|
|
564
545
|
|
|
565
|
-
/**
|
|
566
|
-
* The last resort, held by the container so every resolution path shares it.
|
|
567
|
-
*
|
|
568
|
-
* It used to live on `app.resolve` alone, which meant the runner found a remote façade
|
|
569
|
-
* and dependency injection did not — a handler asking for a neighbour that had moved
|
|
570
|
-
* got `is not registered` while the very same call over the wire worked. One door now.
|
|
571
|
-
*
|
|
572
|
-
* Surface-scoped keys ('admin:productHandler') stay local: a named surface resolves in
|
|
573
|
-
* this container only, so fabricating one for a remote frond would answer NOT_FOUND on
|
|
574
|
-
* everything (see Known issues).
|
|
575
|
-
*/
|
|
546
|
+
/** The last resort, held by the container so every resolution path shares it. */
|
|
576
547
|
container.setFallback?.((name) => {
|
|
577
548
|
if (!remoteRouter) return undefined;
|
|
578
549
|
if (!name.endsWith('Handler') || name.includes(':')) return undefined;
|
|
@@ -580,19 +551,15 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
580
551
|
// `lowerFirst` because a DEPENDENCY names the type as written — `ProductHandler`,
|
|
581
552
|
// PascalCase — while a card declares `product`, so the raw strip asked the router for
|
|
582
553
|
// 'Product' and every by-type dependency on a remote handler answered NOT_FOUND.
|
|
583
|
-
return
|
|
554
|
+
return facadeOperations(
|
|
584
555
|
dispatcher,
|
|
585
556
|
lowerFirst(name.replace(/Handler$/, '')),
|
|
586
|
-
)
|
|
557
|
+
);
|
|
587
558
|
});
|
|
588
559
|
|
|
589
560
|
/**
|
|
590
|
-
* Everything this app holds, let go in reverse of how it was taken: what an extension
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
* It does NOT wait for running calls — `drain()` is that, and it is a separate gesture
|
|
594
|
-
* because waiting and releasing do not have the same owner: a test releases at once, a
|
|
595
|
-
* host turning the ring wants the work finished first.
|
|
561
|
+
* Everything this app holds, let go in reverse of how it was taken: what an extension took on
|
|
562
|
+
* last, then the container's own, then whoever handed a resource in.
|
|
596
563
|
*/
|
|
597
564
|
const release = async (): Promise<void> => {
|
|
598
565
|
// Every level is told to close even when one refuses, and the refusals leave together —
|
|
@@ -615,13 +582,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
615
582
|
}
|
|
616
583
|
};
|
|
617
584
|
|
|
618
|
-
/**
|
|
619
|
-
* Stop taking calls, and resolve once the ones already running are done.
|
|
620
|
-
*
|
|
621
|
-
* Refuses on `timeoutMs` rather than resolving anyway: a drain that gives up quietly
|
|
622
|
-
* reads exactly like a drain that succeeded, and the caller — who is about to release
|
|
623
|
-
* a storage connection under whatever is left — is the one who must decide.
|
|
624
|
-
*/
|
|
585
|
+
/** Stop taking calls, and resolve once the ones already running are done. */
|
|
625
586
|
const drain = async (timeoutMs?: number): Promise<void> => {
|
|
626
587
|
inflight.close();
|
|
627
588
|
if (timeoutMs === undefined) return inflight.whenIdle();
|
|
@@ -676,28 +637,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
676
637
|
}
|
|
677
638
|
};
|
|
678
639
|
|
|
679
|
-
/**
|
|
680
|
-
* THE membership rule, stated once — every projection reads this and nothing
|
|
681
|
-
* else. It used to live twice, verbatim, in the REST and GraphQL adapters,
|
|
682
|
-
* and two other readers invented their own answer.
|
|
683
|
-
*
|
|
684
|
-
* Naming an audience closes it. Two ways to name an entity into a surface,
|
|
685
|
-
* in precedence order:
|
|
686
|
-
* - `surfaces:` in frond.config.ts — when the list exists, it IS the list;
|
|
687
|
-
* - a handler under `handlers/<surface>/` — which also restricts the façade.
|
|
688
|
-
* `@expose` is a THIRD way and this rule does not read it: the scan sets a
|
|
689
|
-
* boolean, read by the two adapters and by `exposedAdapters` — never here.
|
|
690
|
-
* What neither of the two names is not served. It used to be the reverse: no
|
|
691
|
-
* `public:categoryHandler` meant the FULL CategoryHandler rode the public
|
|
692
|
-
* door, create/update/delete included (measured on demos/nuxt-blog).
|
|
693
|
-
*
|
|
694
|
-
* A named entity with no façade of its own falls back to the default one —
|
|
695
|
-
* that is not the old widening, it is the author saying "this one, as it is".
|
|
696
|
-
* The leak was exposure with no statement behind it.
|
|
697
|
-
*
|
|
698
|
-
* A surface key stays local: a doublure serves whatever the remote's own door
|
|
699
|
-
* serves, which is the remote's business and not ours to re-audience.
|
|
700
|
-
*/
|
|
640
|
+
/** THE membership rule, stated once — every projection reads this and nothing else. */
|
|
701
641
|
const facadeFor = (entity: string, surface?: string): Record<string, Function> | undefined => {
|
|
702
642
|
if (!surface) return facadeAt(facadeKeyOf(entity), true);
|
|
703
643
|
|
|
@@ -709,18 +649,18 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
709
649
|
|
|
710
650
|
const fallback = facadeAt(facadeKeyOf(entity), false);
|
|
711
651
|
return fallback
|
|
712
|
-
?
|
|
652
|
+
? facadeOperations(
|
|
713
653
|
localDispatcher,
|
|
714
654
|
entity,
|
|
715
655
|
routeRegistry.operationNames(entity, surface),
|
|
716
656
|
surface,
|
|
717
|
-
)
|
|
657
|
+
)
|
|
718
658
|
: undefined;
|
|
719
659
|
};
|
|
720
660
|
|
|
721
661
|
if (remoteRouter) {
|
|
722
662
|
const remoteFacades = new Map<string, Record<string, Function>>();
|
|
723
|
-
routeRegistry.addResolver(
|
|
663
|
+
routeRegistry.addResolver(remoteRoutes((entity) => {
|
|
724
664
|
const known = remoteFacades.get(entity);
|
|
725
665
|
if (known) return known;
|
|
726
666
|
const facade = createRemoteFacade(entity, remoteRouter, getMiddlewares);
|
|
@@ -742,19 +682,14 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
742
682
|
};
|
|
743
683
|
|
|
744
684
|
/**
|
|
745
|
-
* The storage an entity is backed by — the dual of `facadeFor`, which serves its
|
|
746
|
-
*
|
|
747
|
-
*
|
|
748
|
-
* It resolves through the owning frond's scope, because that is where entity ORMs live:
|
|
749
|
-
* `resolve('UserOrm')` reads the ROOT container and never finds one, so callers outside
|
|
750
|
-
* the frond concluded there was no storage. The seed loop did exactly that, and skipped
|
|
751
|
-
* every entity with no façade — the one case its own fallback existed for.
|
|
685
|
+
* The storage an entity is backed by — the dual of `facadeFor`, which serves its client-facing
|
|
686
|
+
* door.
|
|
752
687
|
*/
|
|
753
|
-
const
|
|
688
|
+
const storageFor = (entity: string): unknown | undefined => {
|
|
754
689
|
const owner = fronds.owner(entity);
|
|
755
690
|
if (!owner) return undefined;
|
|
756
691
|
|
|
757
|
-
const key =
|
|
692
|
+
const key = storageKeyOf(entity);
|
|
758
693
|
try {
|
|
759
694
|
return container.resolve<Container>(`frond:${owner.name}`).resolve(key);
|
|
760
695
|
} catch {
|
|
@@ -762,14 +697,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
762
697
|
}
|
|
763
698
|
};
|
|
764
699
|
|
|
765
|
-
/**
|
|
766
|
-
* The presenter of an entity, resolved through its owning frond's scope.
|
|
767
|
-
*
|
|
768
|
-
* Same shape as `ormFor`, and it exists for the same reason: without it an adapter
|
|
769
|
-
* has to spell the container key itself. `schema-graphql` did — a hand-written
|
|
770
|
-
* `${Name}Presenter` — and a key respelled elsewhere finds nothing and says nothing
|
|
771
|
-
* the day the convention moves, which is exactly the failure `verify.ts` refuses.
|
|
772
|
-
*/
|
|
700
|
+
/** The presenter of an entity, resolved through its owning frond's scope. */
|
|
773
701
|
const presenterFor = (entity: string): unknown | undefined => {
|
|
774
702
|
const owner = fronds.owner(entity);
|
|
775
703
|
if (!owner) return undefined;
|
|
@@ -799,7 +727,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
799
727
|
operationsFor,
|
|
800
728
|
listensTo: () => emissions.listensTo(),
|
|
801
729
|
deliver: (fact, payload) => emissions.deliver(fact, payload),
|
|
802
|
-
|
|
730
|
+
storageFor,
|
|
803
731
|
presenterFor,
|
|
804
732
|
dispose: release,
|
|
805
733
|
drain,
|
|
@@ -841,7 +769,23 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
841
769
|
|
|
842
770
|
// The last thing the boot does, and the first thing a release undoes. An extension may
|
|
843
771
|
// await here — which is what a provider needing to OPEN something could never do.
|
|
844
|
-
|
|
772
|
+
//
|
|
773
|
+
// A refusal here has to release what the boot took, because the caller cannot: it handed
|
|
774
|
+
// `onDispose` over BEFORE this line and never receives the app that would carry it back.
|
|
775
|
+
// Whoever opened a connection to give it to us would otherwise leak it on every failed boot.
|
|
776
|
+
try {
|
|
777
|
+
await appLifecycle.up(app);
|
|
778
|
+
} catch (cause) {
|
|
779
|
+
try {
|
|
780
|
+
await release();
|
|
781
|
+
} catch (refused) {
|
|
782
|
+
throw new AggregateError(
|
|
783
|
+
[cause, ...(refused instanceof AggregateError ? refused.errors : [refused])],
|
|
784
|
+
`The boot failed and could not release everything it had taken: ${(cause as Error)?.message ?? String(cause)}`,
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
throw cause;
|
|
788
|
+
}
|
|
845
789
|
|
|
846
790
|
return app;
|
|
847
791
|
}
|
package/src/boot/card.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** What an app says about ITSELF — the `rpc.discover` answer, built from the app. */
|
|
2
|
+
import { Card } from '@fougere/schema';
|
|
3
|
+
import type { App } from './types.js';
|
|
4
|
+
import { factsAnnouncedBy } from '../emit.js';
|
|
5
|
+
import type { InvocationContext } from '../wire/Invocation.js';
|
|
6
|
+
import { facadeKeyOf, contractsKeyOf, type CardOp, type IdentityCard } from '../wire/call.js';
|
|
7
|
+
import type { OperationContract } from '../wire/operation.js';
|
|
8
|
+
|
|
9
|
+
type AnyFacade = Record<string, (invocation?: InvocationContext) => Promise<unknown>>;
|
|
10
|
+
|
|
11
|
+
/** Serialize what the app hosts, for one audience. */
|
|
12
|
+
export function identityCardOf(app: App, surface?: string): IdentityCard {
|
|
13
|
+
const declared = app.fronds.schemas();
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
fronds: app.fronds.map((frond) => {
|
|
17
|
+
// What the frond answers to, not what it stores. This walked `frond.entities`, so a
|
|
18
|
+
// handler carrying no entity — a health check, a search across shapes — was built,
|
|
19
|
+
// served, and absent from the card: `sync` could not generate its door and a remote
|
|
20
|
+
// consumer had no way to know it existed. The boot has said "pointing at nothing is
|
|
21
|
+
// legal" since handlers became the subject; the card had not caught up.
|
|
22
|
+
const byEntity = new Map(frond.entities.map((entity) => [entity.name, entity]));
|
|
23
|
+
const addresses = [...new Set([
|
|
24
|
+
...frond.entities.map((entity) => entity.name),
|
|
25
|
+
...frond.handlers.map((handler) => handler.address),
|
|
26
|
+
])];
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
name: frond.name,
|
|
30
|
+
doors: addresses.flatMap((address) => {
|
|
31
|
+
const ops = facadeOps(app, address, surface);
|
|
32
|
+
if (ops.length === 0) return [];
|
|
33
|
+
const entity = byEntity.get(address);
|
|
34
|
+
return [{
|
|
35
|
+
name: address,
|
|
36
|
+
ops,
|
|
37
|
+
// Absent when nothing of that name is stored. A door is still a door.
|
|
38
|
+
...(entity ? { schema: Card.fromSchema(entity.entityClass, address).descriptor } : {}),
|
|
39
|
+
}];
|
|
40
|
+
}),
|
|
41
|
+
/** What leaves on its own — the same list on every surface, deliberately. */
|
|
42
|
+
facts: factsAnnouncedBy(frond.handlers).map((name) => {
|
|
43
|
+
const entityClass = declared.get(name);
|
|
44
|
+
return { name, ...(entityClass ? { schema: Card.fromSchema(entityClass, name).descriptor } : {}) };
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function facadeOps(app: App, entityName: string, surface?: string): CardOp[] {
|
|
52
|
+
let facade: AnyFacade;
|
|
53
|
+
try {
|
|
54
|
+
facade = app.container.resolve<AnyFacade>(facadeKeyOf(entityName, surface));
|
|
55
|
+
} catch {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// The façade is the list of names; the model is the resolved terms.
|
|
60
|
+
const effective = app.operationsFor(entityName, surface);
|
|
61
|
+
if (!effective) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Facade '${facadeKeyOf(entityName, surface)}' exists without an effective operation table.`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return Object.keys(facade).map((name) => {
|
|
68
|
+
const contract = effective.get(name);
|
|
69
|
+
if (!contract) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Facade '${facadeKeyOf(entityName, surface)}' serves '${name}' without an effective contract.`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
name,
|
|
77
|
+
...(contract?.description && { description: contract.description }),
|
|
78
|
+
...(contract?.input && { input: Card.fromSchema(contract.input, name).descriptor }),
|
|
79
|
+
...(contract?.output && { output: Card.fromSchema(contract.output, name).descriptor }),
|
|
80
|
+
...(contract?.cardinality && { cardinality: contract.cardinality }),
|
|
81
|
+
kind: contract.kind,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|