@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.
- package/README.md +3 -2
- package/dist/boot/AppLifecycle.d.ts +18 -0
- package/dist/boot/AppLifecycle.d.ts.map +1 -0
- package/dist/boot/AppLifecycle.js +42 -0
- package/dist/boot/AppLifecycle.js.map +1 -0
- package/dist/boot/Emissions.d.ts +126 -0
- package/dist/boot/Emissions.d.ts.map +1 -0
- package/dist/boot/Emissions.js +233 -0
- package/dist/boot/Emissions.js.map +1 -0
- package/dist/boot/HandlerFacade.d.ts +72 -0
- package/dist/boot/HandlerFacade.d.ts.map +1 -0
- package/dist/boot/HandlerFacade.js +174 -0
- package/dist/boot/HandlerFacade.js.map +1 -0
- package/dist/boot/Lifecycle.d.ts +4 -0
- package/dist/boot/Lifecycle.d.ts.map +1 -0
- package/dist/boot/Lifecycle.js +3 -0
- package/dist/boot/Lifecycle.js.map +1 -0
- package/dist/boot/ambient-port.d.ts +38 -0
- package/dist/boot/ambient-port.d.ts.map +1 -0
- package/dist/boot/ambient-port.js +2 -0
- package/dist/boot/ambient-port.js.map +1 -0
- package/dist/boot/ambient.als.d.ts +3 -0
- package/dist/boot/ambient.als.d.ts.map +1 -0
- package/dist/boot/ambient.als.js +34 -0
- package/dist/boot/ambient.als.js.map +1 -0
- package/dist/boot/ambient.queue.d.ts +10 -0
- package/dist/boot/ambient.queue.d.ts.map +1 -0
- package/dist/boot/ambient.queue.js +60 -0
- package/dist/boot/ambient.queue.js.map +1 -0
- package/dist/boot/apply.d.ts +22 -0
- package/dist/boot/apply.d.ts.map +1 -0
- package/dist/boot/apply.js +38 -0
- package/dist/boot/apply.js.map +1 -0
- package/dist/boot/auth.d.ts +53 -0
- package/dist/boot/auth.d.ts.map +1 -0
- package/dist/boot/auth.js +2 -0
- package/dist/boot/auth.js.map +1 -0
- package/dist/{binding.d.ts → boot/binding.d.ts} +14 -17
- package/dist/boot/binding.d.ts.map +1 -0
- package/dist/{binding.js → boot/binding.js} +19 -10
- package/dist/boot/binding.js.map +1 -0
- package/dist/{boot.d.ts → boot/boot.d.ts} +25 -5
- package/dist/boot/boot.d.ts.map +1 -0
- package/dist/boot/boot.js +70 -0
- package/dist/boot/boot.js.map +1 -0
- package/dist/boot/bootstrap.d.ts.map +1 -0
- package/dist/boot/bootstrap.js +722 -0
- package/dist/boot/bootstrap.js.map +1 -0
- package/dist/boot/frame.d.ts +44 -0
- package/dist/boot/frame.d.ts.map +1 -0
- package/dist/boot/frame.js +172 -0
- package/dist/boot/frame.js.map +1 -0
- package/dist/boot/ownership.d.ts +42 -0
- package/dist/boot/ownership.d.ts.map +1 -0
- package/dist/boot/ownership.js +127 -0
- package/dist/boot/ownership.js.map +1 -0
- package/dist/boot/ports.d.ts +17 -0
- package/dist/boot/ports.d.ts.map +1 -0
- package/dist/boot/ports.js +57 -0
- package/dist/boot/ports.js.map +1 -0
- package/dist/{remote.d.ts → boot/remote.d.ts} +11 -3
- package/dist/boot/remote.d.ts.map +1 -0
- package/dist/{remote.js → boot/remote.js} +26 -28
- package/dist/boot/remote.js.map +1 -0
- package/dist/{seed.d.ts → boot/seed.d.ts} +13 -1
- package/dist/boot/seed.d.ts.map +1 -0
- package/dist/{seed.js → boot/seed.js} +24 -3
- package/dist/boot/seed.js.map +1 -0
- package/dist/boot/together.d.ts +26 -0
- package/dist/boot/together.d.ts.map +1 -0
- package/dist/boot/together.js +163 -0
- package/dist/boot/together.js.map +1 -0
- package/dist/boot/types.d.ts +260 -0
- package/dist/boot/types.d.ts.map +1 -0
- package/dist/boot/types.js.map +1 -0
- package/dist/builtins/config.d.ts +9 -0
- package/dist/builtins/config.d.ts.map +1 -1
- package/dist/builtins/config.js +16 -1
- package/dist/builtins/config.js.map +1 -1
- package/dist/builtins/logger.d.ts +37 -4
- package/dist/builtins/logger.d.ts.map +1 -1
- package/dist/builtins/logger.js +66 -7
- package/dist/builtins/logger.js.map +1 -1
- package/dist/config-loader.d.ts +39 -35
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +15 -54
- package/dist/config-loader.js.map +1 -1
- package/dist/contract/Call.d.ts +10 -0
- package/dist/contract/Call.d.ts.map +1 -0
- package/dist/contract/Call.js +15 -0
- package/dist/contract/Call.js.map +1 -0
- package/dist/contract/Invocation.d.ts +27 -0
- package/dist/contract/Invocation.d.ts.map +1 -0
- package/dist/contract/Invocation.js +59 -0
- package/dist/contract/Invocation.js.map +1 -0
- package/dist/contract/RouteAddress.d.ts +17 -0
- package/dist/contract/RouteAddress.d.ts.map +1 -0
- package/dist/contract/RouteAddress.js +38 -0
- package/dist/contract/RouteAddress.js.map +1 -0
- package/dist/contract.d.ts +25 -19
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +25 -10
- package/dist/contract.js.map +1 -1
- package/dist/crypto/encoding.d.ts +25 -0
- package/dist/crypto/encoding.d.ts.map +1 -0
- package/dist/crypto/encoding.js +58 -0
- package/dist/crypto/encoding.js.map +1 -0
- package/dist/crypto/node.d.ts +4 -0
- package/dist/crypto/node.d.ts.map +1 -0
- package/dist/crypto/node.js +25 -0
- package/dist/crypto/node.js.map +1 -0
- package/dist/crypto/port.d.ts +42 -0
- package/dist/crypto/port.d.ts.map +1 -0
- package/dist/crypto/port.js +19 -0
- package/dist/crypto/port.js.map +1 -0
- package/dist/crypto/webcrypto.d.ts +4 -0
- package/dist/crypto/webcrypto.d.ts.map +1 -0
- package/dist/crypto/webcrypto.js +34 -0
- package/dist/crypto/webcrypto.js.map +1 -0
- package/dist/dispatch/ArgumentResolver.d.ts +10 -0
- package/dist/dispatch/ArgumentResolver.d.ts.map +1 -0
- package/dist/dispatch/ArgumentResolver.js +12 -0
- package/dist/dispatch/ArgumentResolver.js.map +1 -0
- package/dist/dispatch/ArrayResult.d.ts +3 -0
- package/dist/dispatch/ArrayResult.d.ts.map +1 -0
- package/dist/dispatch/ArrayResult.js +11 -0
- package/dist/dispatch/ArrayResult.js.map +1 -0
- package/dist/dispatch/DispatchEvent.d.ts +18 -0
- package/dist/dispatch/DispatchEvent.d.ts.map +1 -0
- package/dist/dispatch/DispatchEvent.js +30 -0
- package/dist/dispatch/DispatchEvent.js.map +1 -0
- package/dist/dispatch/DispatchLifecycle.d.ts +9 -0
- package/dist/dispatch/DispatchLifecycle.d.ts.map +1 -0
- package/dist/dispatch/DispatchLifecycle.js +25 -0
- package/dist/dispatch/DispatchLifecycle.js.map +1 -0
- package/dist/dispatch/DispatchPort.d.ts +6 -0
- package/dist/dispatch/DispatchPort.d.ts.map +1 -0
- package/dist/dispatch/DispatchPort.js +2 -0
- package/dist/dispatch/DispatchPort.js.map +1 -0
- package/dist/dispatch/Dispatcher.d.ts +16 -0
- package/dist/dispatch/Dispatcher.d.ts.map +1 -0
- package/dist/dispatch/Dispatcher.js +44 -0
- package/dist/dispatch/Dispatcher.js.map +1 -0
- package/dist/dispatch/InFlight.d.ts +12 -0
- package/dist/dispatch/InFlight.d.ts.map +1 -0
- package/dist/dispatch/InFlight.js +46 -0
- package/dist/dispatch/InFlight.js.map +1 -0
- package/dist/dispatch/InputValidator.d.ts +7 -0
- package/dist/dispatch/InputValidator.d.ts.map +1 -0
- package/dist/dispatch/InputValidator.js +22 -0
- package/dist/dispatch/InputValidator.js.map +1 -0
- package/dist/dispatch/LocalRoutePolicy.d.ts +11 -0
- package/dist/dispatch/LocalRoutePolicy.d.ts.map +1 -0
- package/dist/dispatch/LocalRoutePolicy.js +32 -0
- package/dist/dispatch/LocalRoutePolicy.js.map +1 -0
- package/dist/dispatch/OperationExecutor.d.ts +25 -0
- package/dist/dispatch/OperationExecutor.d.ts.map +1 -0
- package/dist/dispatch/OperationExecutor.js +32 -0
- package/dist/dispatch/OperationExecutor.js.map +1 -0
- package/dist/dispatch/OperationRoute.d.ts +13 -0
- package/dist/dispatch/OperationRoute.d.ts.map +1 -0
- package/dist/dispatch/OperationRoute.js +15 -0
- package/dist/dispatch/OperationRoute.js.map +1 -0
- package/dist/dispatch/OutputProjector.d.ts +12 -0
- package/dist/dispatch/OutputProjector.d.ts.map +1 -0
- package/dist/dispatch/OutputProjector.js +30 -0
- package/dist/dispatch/OutputProjector.js.map +1 -0
- package/dist/dispatch/OutputView.d.ts +8 -0
- package/dist/dispatch/OutputView.d.ts.map +1 -0
- package/dist/dispatch/OutputView.js +10 -0
- package/dist/dispatch/OutputView.js.map +1 -0
- package/dist/dispatch/PresenterArgumentResolver.d.ts +12 -0
- package/dist/dispatch/PresenterArgumentResolver.d.ts.map +1 -0
- package/dist/dispatch/PresenterArgumentResolver.js +20 -0
- package/dist/dispatch/PresenterArgumentResolver.js.map +1 -0
- package/dist/dispatch/PresenterExecutor.d.ts +11 -0
- package/dist/dispatch/PresenterExecutor.d.ts.map +1 -0
- package/dist/dispatch/PresenterExecutor.js +56 -0
- package/dist/dispatch/PresenterExecutor.js.map +1 -0
- package/dist/dispatch/RemoteRouteResolver.d.ts +13 -0
- package/dist/dispatch/RemoteRouteResolver.d.ts.map +1 -0
- package/dist/dispatch/RemoteRouteResolver.js +18 -0
- package/dist/dispatch/RemoteRouteResolver.js.map +1 -0
- package/dist/dispatch/Route.d.ts +10 -0
- package/dist/dispatch/Route.d.ts.map +1 -0
- package/dist/dispatch/Route.js +2 -0
- package/dist/dispatch/Route.js.map +1 -0
- package/dist/dispatch/RouteNotFoundError.d.ts +10 -0
- package/dist/dispatch/RouteNotFoundError.d.ts.map +1 -0
- package/dist/dispatch/RouteNotFoundError.js +24 -0
- package/dist/dispatch/RouteNotFoundError.js.map +1 -0
- package/dist/dispatch/RoutePolicy.d.ts +8 -0
- package/dist/dispatch/RoutePolicy.d.ts.map +1 -0
- package/dist/dispatch/RoutePolicy.js +2 -0
- package/dist/dispatch/RoutePolicy.js.map +1 -0
- package/dist/dispatch/RouteRegistry.d.ts +18 -0
- package/dist/dispatch/RouteRegistry.d.ts.map +1 -0
- package/dist/dispatch/RouteRegistry.js +62 -0
- package/dist/dispatch/RouteRegistry.js.map +1 -0
- package/dist/dispatch/RouteResolver.d.ts +7 -0
- package/dist/dispatch/RouteResolver.d.ts.map +1 -0
- package/dist/dispatch/RouteResolver.js +2 -0
- package/dist/dispatch/RouteResolver.js.map +1 -0
- package/dist/dispatch/StorageGuard.d.ts +15 -0
- package/dist/dispatch/StorageGuard.d.ts.map +1 -0
- package/dist/dispatch/StorageGuard.js +63 -0
- package/dist/dispatch/StorageGuard.js.map +1 -0
- package/dist/effective-operation.d.ts +90 -0
- package/dist/effective-operation.d.ts.map +1 -0
- package/dist/effective-operation.js +449 -0
- package/dist/effective-operation.js.map +1 -0
- package/dist/emit.d.ts +2 -2
- package/dist/emit.d.ts.map +1 -1
- package/dist/emit.js +2 -2
- package/dist/emit.js.map +1 -1
- package/dist/entry/DynamicFacade.d.ts +10 -0
- package/dist/entry/DynamicFacade.d.ts.map +1 -0
- package/dist/entry/DynamicFacade.js +27 -0
- package/dist/entry/DynamicFacade.js.map +1 -0
- package/dist/entry/FacadeEntry.d.ts +11 -0
- package/dist/entry/FacadeEntry.d.ts.map +1 -0
- package/dist/entry/FacadeEntry.js +26 -0
- package/dist/entry/FacadeEntry.js.map +1 -0
- package/dist/entry/TransportEntry.d.ts +13 -0
- package/dist/entry/TransportEntry.d.ts.map +1 -0
- package/dist/entry/TransportEntry.js +24 -0
- package/dist/entry/TransportEntry.js.map +1 -0
- package/dist/frond-config.d.ts +24 -7
- package/dist/frond-config.d.ts.map +1 -1
- 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/graph.js +3 -2
- package/dist/graph.js.map +1 -1
- package/dist/identity-keys.d.ts +14 -0
- package/dist/identity-keys.d.ts.map +1 -0
- package/dist/identity-keys.js +37 -0
- package/dist/identity-keys.js.map +1 -0
- package/dist/identity.d.ts +58 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +182 -0
- package/dist/identity.js.map +1 -0
- package/dist/imports.d.ts +2 -2
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +7 -3
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +57 -38
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -32
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +16 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +25 -0
- package/dist/loader.js.map +1 -0
- package/dist/node.d.ts +21 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +24 -0
- package/dist/node.js.map +1 -0
- package/dist/orm.d.ts +69 -8
- package/dist/orm.d.ts.map +1 -1
- package/dist/orm.js +35 -2
- package/dist/orm.js.map +1 -1
- package/dist/prefab/collector.d.ts +29 -0
- package/dist/prefab/collector.d.ts.map +1 -0
- package/dist/prefab/collector.js +34 -0
- package/dist/prefab/collector.js.map +1 -0
- package/dist/{crud.d.ts → prefab/crud.d.ts} +7 -8
- package/dist/prefab/crud.d.ts.map +1 -0
- package/dist/{crud.js → prefab/crud.js} +39 -5
- package/dist/prefab/crud.js.map +1 -0
- package/dist/prefab/mirror.d.ts +52 -0
- package/dist/prefab/mirror.d.ts.map +1 -0
- package/dist/prefab/mirror.js +66 -0
- package/dist/prefab/mirror.js.map +1 -0
- package/dist/prefab/prefab.d.ts +15 -0
- package/dist/prefab/prefab.d.ts.map +1 -0
- package/dist/prefab/prefab.js +19 -0
- package/dist/prefab/prefab.js.map +1 -0
- package/dist/{presenter.d.ts → prefab/presenter.d.ts} +6 -17
- package/dist/prefab/presenter.d.ts.map +1 -0
- package/dist/{presenter.js → prefab/presenter.js} +5 -23
- package/dist/prefab/presenter.js.map +1 -0
- package/dist/prefab/repository.d.ts +104 -0
- package/dist/prefab/repository.d.ts.map +1 -0
- package/dist/prefab/repository.js +62 -0
- package/dist/prefab/repository.js.map +1 -0
- package/dist/scan/Fronds.d.ts +45 -0
- package/dist/scan/Fronds.d.ts.map +1 -0
- package/dist/scan/Fronds.js +66 -0
- package/dist/scan/Fronds.js.map +1 -0
- package/dist/scan/conventions.d.ts +74 -0
- package/dist/scan/conventions.d.ts.map +1 -0
- package/dist/scan/conventions.js +82 -0
- package/dist/scan/conventions.js.map +1 -0
- package/dist/scan/emit.d.ts +14 -0
- package/dist/scan/emit.d.ts.map +1 -0
- package/dist/scan/emit.js +212 -0
- package/dist/scan/emit.js.map +1 -0
- package/dist/scan/frond.d.ts +224 -0
- package/dist/scan/frond.d.ts.map +1 -0
- package/dist/scan/frond.js +2 -0
- package/dist/scan/frond.js.map +1 -0
- package/dist/{handler-parser.d.ts → scan/handler-parser.d.ts} +20 -9
- package/dist/scan/handler-parser.d.ts.map +1 -0
- package/dist/scan/handler-parser.js +665 -0
- package/dist/scan/handler-parser.js.map +1 -0
- package/dist/scan/scan-cache.d.ts +16 -0
- package/dist/scan/scan-cache.d.ts.map +1 -0
- package/dist/{scan-cache.js → scan/scan-cache.js} +27 -20
- package/dist/scan/scan-cache.js.map +1 -0
- package/dist/scan/scanner.d.ts +20 -0
- package/dist/scan/scanner.d.ts.map +1 -0
- package/dist/{scanner.js → scan/scanner.js} +212 -167
- package/dist/scan/scanner.js.map +1 -0
- package/dist/verify.d.ts +16 -3
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +21 -18
- package/dist/verify.js.map +1 -1
- package/dist/{call.d.ts → wire/call.d.ts} +76 -7
- package/dist/wire/call.d.ts.map +1 -0
- package/dist/{call.js → wire/call.js} +53 -80
- package/dist/wire/call.js.map +1 -0
- package/dist/{middleware.d.ts → wire/errors.d.ts} +18 -19
- package/dist/wire/errors.d.ts.map +1 -0
- package/dist/{middleware.js → wire/errors.js} +26 -14
- package/dist/wire/errors.js.map +1 -0
- package/dist/{errors.d.ts → wire/http-error.d.ts} +5 -6
- package/dist/wire/http-error.d.ts.map +1 -0
- package/dist/{errors.js → wire/http-error.js} +7 -6
- package/dist/wire/http-error.js.map +1 -0
- package/dist/wire/invocation.d.ts +4 -0
- package/dist/wire/invocation.d.ts.map +1 -0
- package/dist/wire/invocation.js +3 -0
- package/dist/wire/invocation.js.map +1 -0
- package/dist/{middleware/logger.d.ts → wire/loggerMiddleware.d.ts} +3 -3
- package/dist/wire/loggerMiddleware.d.ts.map +1 -0
- package/dist/{middleware/logger.js → wire/loggerMiddleware.js} +2 -2
- package/dist/wire/loggerMiddleware.js.map +1 -0
- package/dist/wire/middleware.d.ts +29 -0
- package/dist/wire/middleware.d.ts.map +1 -0
- package/dist/wire/middleware.js +20 -0
- package/dist/wire/middleware.js.map +1 -0
- package/dist/{operation.d.ts → wire/operation.d.ts} +39 -10
- package/dist/wire/operation.d.ts.map +1 -0
- package/dist/wire/operation.js +167 -0
- package/dist/wire/operation.js.map +1 -0
- package/package.json +27 -8
- package/src/boot/AppLifecycle.ts +50 -0
- package/src/boot/Emissions.ts +263 -0
- package/src/boot/HandlerFacade.ts +242 -0
- package/src/boot/Lifecycle.ts +3 -0
- package/src/boot/ambient-port.ts +41 -0
- package/src/boot/ambient.als.ts +43 -0
- package/src/boot/ambient.queue.ts +75 -0
- package/src/boot/apply.ts +47 -0
- package/src/boot/auth.ts +55 -0
- package/src/boot/binding.ts +182 -0
- package/src/boot/boot.ts +125 -0
- package/src/boot/bootstrap.ts +839 -0
- package/src/boot/frame.ts +210 -0
- package/src/boot/ownership.ts +140 -0
- package/src/boot/ports.ts +66 -0
- package/src/boot/remote.ts +179 -0
- package/src/boot/seed.ts +158 -0
- package/src/boot/together.ts +215 -0
- package/src/boot/types.ts +261 -0
- package/src/builtins/config.ts +19 -0
- package/src/builtins/logger.ts +175 -0
- package/src/config-loader.ts +146 -0
- package/src/contract/Call.ts +18 -0
- package/src/contract/Invocation.ts +72 -0
- package/src/contract/RouteAddress.ts +49 -0
- package/src/contract.ts +74 -0
- package/src/crypto/encoding.ts +59 -0
- package/src/crypto/node.ts +30 -0
- package/src/crypto/port.ts +45 -0
- package/src/crypto/webcrypto.ts +55 -0
- package/src/define.ts +10 -0
- package/src/dispatch/ArgumentResolver.ts +17 -0
- package/src/dispatch/ArrayResult.ts +10 -0
- package/src/dispatch/DispatchEvent.ts +38 -0
- package/src/dispatch/DispatchLifecycle.ts +23 -0
- package/src/dispatch/DispatchPort.ts +6 -0
- package/src/dispatch/Dispatcher.ts +48 -0
- package/src/dispatch/InFlight.ts +49 -0
- package/src/dispatch/InputValidator.ts +28 -0
- package/src/dispatch/LocalRoutePolicy.ts +34 -0
- package/src/dispatch/OperationExecutor.ts +60 -0
- package/src/dispatch/OperationRoute.ts +18 -0
- package/src/dispatch/OutputProjector.ts +32 -0
- package/src/dispatch/OutputView.ts +9 -0
- package/src/dispatch/PresenterArgumentResolver.ts +25 -0
- package/src/dispatch/PresenterExecutor.ts +55 -0
- package/src/dispatch/RemoteRouteResolver.ts +21 -0
- package/src/dispatch/Route.ts +11 -0
- package/src/dispatch/RouteNotFoundError.ts +29 -0
- package/src/dispatch/RoutePolicy.ts +8 -0
- package/src/dispatch/RouteRegistry.ts +73 -0
- package/src/dispatch/RouteResolver.ts +7 -0
- package/src/dispatch/StorageGuard.ts +71 -0
- package/src/effective-operation.ts +597 -0
- package/src/emit.ts +90 -0
- package/src/entry/DynamicFacade.ts +28 -0
- package/src/entry/FacadeEntry.ts +32 -0
- package/src/entry/TransportEntry.ts +30 -0
- package/src/frond-config.ts +138 -0
- package/src/graph.ts +180 -0
- package/src/identity-keys.ts +43 -0
- package/src/identity.ts +235 -0
- package/src/imports.ts +123 -0
- package/src/index.ts +106 -0
- package/src/loader.ts +41 -0
- package/src/node.ts +28 -0
- package/src/orm.ts +252 -0
- package/src/prefab/collector.ts +36 -0
- package/src/prefab/crud.ts +188 -0
- package/src/prefab/mirror.ts +122 -0
- package/src/prefab/prefab.ts +46 -0
- package/src/prefab/presenter.ts +63 -0
- package/src/prefab/repository.ts +170 -0
- package/src/scan/Fronds.ts +73 -0
- package/src/scan/conventions.ts +122 -0
- package/src/scan/emit.ts +231 -0
- package/src/scan/frond.ts +235 -0
- package/src/scan/handler-parser.ts +818 -0
- package/src/scan/scan-cache.ts +115 -0
- package/src/scan/scanner.ts +758 -0
- package/src/verify.ts +193 -0
- package/src/wire/call.ts +369 -0
- package/src/wire/errors.ts +124 -0
- package/src/wire/http-error.ts +77 -0
- package/src/wire/invocation.ts +10 -0
- package/src/wire/loggerMiddleware.ts +29 -0
- package/src/wire/middleware.ts +47 -0
- package/src/wire/operation.ts +258 -0
- package/dist/binding.d.ts.map +0 -1
- package/dist/binding.js.map +0 -1
- package/dist/boot.d.ts.map +0 -1
- package/dist/boot.js +0 -53
- package/dist/boot.js.map +0 -1
- package/dist/bootstrap.d.ts.map +0 -1
- package/dist/bootstrap.js +0 -879
- package/dist/bootstrap.js.map +0 -1
- package/dist/call.d.ts.map +0 -1
- package/dist/call.js.map +0 -1
- package/dist/collector.d.ts +0 -28
- package/dist/collector.d.ts.map +0 -1
- package/dist/collector.js +0 -32
- package/dist/collector.js.map +0 -1
- package/dist/crud.d.ts.map +0 -1
- package/dist/crud.js.map +0 -1
- package/dist/egress.d.ts +0 -52
- package/dist/egress.d.ts.map +0 -1
- package/dist/egress.js +0 -186
- package/dist/egress.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/handler-parser.d.ts.map +0 -1
- package/dist/handler-parser.js +0 -505
- package/dist/handler-parser.js.map +0 -1
- package/dist/invocation.d.ts +0 -20
- package/dist/invocation.d.ts.map +0 -1
- package/dist/invocation.js +0 -15
- package/dist/invocation.js.map +0 -1
- package/dist/middleware/error-handler.d.ts +0 -15
- package/dist/middleware/error-handler.d.ts.map +0 -1
- package/dist/middleware/error-handler.js +0 -29
- package/dist/middleware/error-handler.js.map +0 -1
- package/dist/middleware/logger.d.ts.map +0 -1
- package/dist/middleware/logger.js.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.js.map +0 -1
- package/dist/mirror.d.ts +0 -93
- package/dist/mirror.d.ts.map +0 -1
- package/dist/mirror.js +0 -96
- package/dist/mirror.js.map +0 -1
- package/dist/operation.d.ts.map +0 -1
- package/dist/operation.js +0 -95
- package/dist/operation.js.map +0 -1
- package/dist/presenter.d.ts.map +0 -1
- package/dist/presenter.js.map +0 -1
- package/dist/remote.d.ts.map +0 -1
- package/dist/remote.js.map +0 -1
- package/dist/repository.d.ts +0 -55
- package/dist/repository.d.ts.map +0 -1
- package/dist/repository.js +0 -26
- package/dist/repository.js.map +0 -1
- package/dist/scan-cache.d.ts +0 -10
- package/dist/scan-cache.d.ts.map +0 -1
- package/dist/scan-cache.js.map +0 -1
- package/dist/scanner.d.ts +0 -34
- package/dist/scanner.d.ts.map +0 -1
- package/dist/scanner.js.map +0 -1
- package/dist/seed.d.ts.map +0 -1
- package/dist/seed.js.map +0 -1
- package/dist/types.d.ts +0 -421
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- /package/dist/{bootstrap.d.ts → boot/bootstrap.d.ts} +0 -0
- /package/dist/{types.js → boot/types.js} +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ed25519 through WebCrypto — what a runtime with no `node:` builtin has.
|
|
3
|
+
*
|
|
4
|
+
* Verified in real workerd with no compatibility flag (2026-08-23): sign, verify, a JWK
|
|
5
|
+
* import, an SPKI import and SHA-256 all answer. `Ed25519` is the algorithm name; the
|
|
6
|
+
* older `NODE-ED25519` spelling is not used, and a runtime that only knows that one will
|
|
7
|
+
* refuse at `importKey` rather than silently signing with something else.
|
|
8
|
+
*
|
|
9
|
+
* The four gestures are declared here rather than pulled from `lib.dom`: this package
|
|
10
|
+
* compiles with `lib: ["ESNext"]` and naming DOM would make every consumer carry a
|
|
11
|
+
* browser's globals to read a server type. What the file needs IS the declaration.
|
|
12
|
+
*/
|
|
13
|
+
import { derOf } from './encoding.js';
|
|
14
|
+
import type { CryptoPort, PublicJwk, Signer, Verifier } from './port.js';
|
|
15
|
+
|
|
16
|
+
interface WebSubtle {
|
|
17
|
+
digest(algorithm: string, data: Uint8Array): Promise<ArrayBuffer>;
|
|
18
|
+
importKey(
|
|
19
|
+
format: 'pkcs8' | 'spki' | 'jwk',
|
|
20
|
+
key: Uint8Array | PublicJwk,
|
|
21
|
+
algorithm: { name: string },
|
|
22
|
+
extractable: boolean,
|
|
23
|
+
usages: string[],
|
|
24
|
+
): Promise<unknown>;
|
|
25
|
+
sign(algorithm: { name: string }, key: unknown, data: Uint8Array): Promise<ArrayBuffer>;
|
|
26
|
+
verify(algorithm: { name: string }, key: unknown, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ED25519 = { name: 'Ed25519' } as const;
|
|
30
|
+
|
|
31
|
+
/** Read at call time — a Worker has the global, and reading it at module load does not. */
|
|
32
|
+
const subtle = (): WebSubtle =>
|
|
33
|
+
(globalThis as unknown as { crypto: { subtle: WebSubtle } }).crypto.subtle;
|
|
34
|
+
|
|
35
|
+
export const crypto: CryptoPort = {
|
|
36
|
+
async sha256(data) {
|
|
37
|
+
return new Uint8Array(await subtle().digest('SHA-256', data));
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
async signerOf(privateKeyPem): Promise<Signer> {
|
|
41
|
+
// Imported once, at boot. Doing it per call would put an async key parse inside
|
|
42
|
+
// every outgoing request — the reason the port hands back a signer at all.
|
|
43
|
+
const key = await subtle().importKey('pkcs8', derOf(privateKeyPem), ED25519, false, ['sign']);
|
|
44
|
+
return { async sign(data) { return new Uint8Array(await subtle().sign(ED25519, key, data)); } };
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
async verifierOf(key): Promise<Verifier> {
|
|
48
|
+
const imported = typeof key === 'string'
|
|
49
|
+
? await subtle().importKey('spki', derOf(key), ED25519, false, ['verify'])
|
|
50
|
+
: await subtle().importKey('jwk', key, ED25519, false, ['verify']);
|
|
51
|
+
return { verify: (data, signature) => subtle().verify(ED25519, imported, signature, data) };
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type { CryptoPort, PublicJwk, Signer, Verifier };
|
package/src/define.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FougereConfig } from './config-loader.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Identity helper for fougere.config.ts — preserves literal types for autocomplete
|
|
5
|
+
* while validating against FougereConfig. Equivalent to `satisfies FougereConfig`
|
|
6
|
+
* but more explicit and aligned with defineFrond().
|
|
7
|
+
*/
|
|
8
|
+
export function defineFougere<T extends FougereConfig>(config: T): T {
|
|
9
|
+
return config;
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveArgs,
|
|
3
|
+
type BindingPlan,
|
|
4
|
+
type CollectorResolver,
|
|
5
|
+
} from '../boot/binding.js';
|
|
6
|
+
import type { InvocationContext } from '../contract/Invocation.js';
|
|
7
|
+
|
|
8
|
+
export type CollectorLookup = (typeName: string) => CollectorResolver | undefined;
|
|
9
|
+
|
|
10
|
+
/** Resolves an operation's declared binding plan against one invocation. */
|
|
11
|
+
export class ArgumentResolver {
|
|
12
|
+
constructor(private readonly collectors?: CollectorLookup) {}
|
|
13
|
+
|
|
14
|
+
resolve(plan: BindingPlan, invocation: InvocationContext): Promise<unknown[]> {
|
|
15
|
+
return resolveArgs(plan, invocation, this.collectors);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Preserve the named properties carried by a list result when its rows are replaced. */
|
|
2
|
+
export function preserveArrayProperties<T extends unknown[]>(source: unknown[], target: T): T {
|
|
3
|
+
for (const key of Object.keys(source)) {
|
|
4
|
+
if (!/^\d+$/.test(key)) {
|
|
5
|
+
(target as unknown as Record<string, unknown>)[key] =
|
|
6
|
+
(source as unknown as Record<string, unknown>)[key];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return target;
|
|
10
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import type { RouteKind } from './Route.js';
|
|
3
|
+
|
|
4
|
+
export type DispatchStage = 'received' | 'resolved' | 'completed' | 'failed' | 'settled';
|
|
5
|
+
|
|
6
|
+
/** Immutable transition observed across one dispatch lifecycle. */
|
|
7
|
+
export class DispatchEvent {
|
|
8
|
+
private constructor(
|
|
9
|
+
readonly stage: DispatchStage,
|
|
10
|
+
readonly call: Call,
|
|
11
|
+
readonly routeKind?: RouteKind,
|
|
12
|
+
readonly error?: unknown,
|
|
13
|
+
) {
|
|
14
|
+
Object.freeze(this);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static received(call: Call): DispatchEvent {
|
|
18
|
+
return new DispatchEvent('received', call);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static resolved(call: Call, routeKind: RouteKind): DispatchEvent {
|
|
22
|
+
return new DispatchEvent('resolved', call, routeKind);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static completed(call: Call, routeKind: RouteKind): DispatchEvent {
|
|
26
|
+
return new DispatchEvent('completed', call, routeKind);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static failed(call: Call, error: unknown, routeKind?: RouteKind): DispatchEvent {
|
|
30
|
+
return new DispatchEvent('failed', call, routeKind, error);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static settled(call: Call, routeKind?: RouteKind): DispatchEvent {
|
|
34
|
+
return new DispatchEvent('settled', call, routeKind);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type DispatchObserver = (event: DispatchEvent) => void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DispatchEvent, DispatchObserver } from './DispatchEvent.js';
|
|
2
|
+
|
|
3
|
+
/** Publishes dispatch transitions without participating in dispatch decisions. */
|
|
4
|
+
export class DispatchLifecycle {
|
|
5
|
+
constructor(
|
|
6
|
+
private readonly observers: readonly DispatchObserver[] = [],
|
|
7
|
+
private readonly diagnose: (error: unknown, event: DispatchEvent) => void = () => {},
|
|
8
|
+
) {}
|
|
9
|
+
|
|
10
|
+
publish(event: DispatchEvent): void {
|
|
11
|
+
for (const observer of this.observers) {
|
|
12
|
+
try {
|
|
13
|
+
observer(event);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
try {
|
|
16
|
+
this.diagnose(error, event);
|
|
17
|
+
} catch {
|
|
18
|
+
// Diagnostics remain observational too.
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import { DispatchEvent } from './DispatchEvent.js';
|
|
3
|
+
import { DispatchLifecycle } from './DispatchLifecycle.js';
|
|
4
|
+
import type { DispatchPort } from './DispatchPort.js';
|
|
5
|
+
import type { Route } from './Route.js';
|
|
6
|
+
import type { RoutePolicy } from './RoutePolicy.js';
|
|
7
|
+
import { RouteRegistry } from './RouteRegistry.js';
|
|
8
|
+
import { RouteNotFoundError } from './RouteNotFoundError.js';
|
|
9
|
+
import type { InFlight } from './InFlight.js';
|
|
10
|
+
|
|
11
|
+
/** Resolves and executes every call through the same transverse lifecycle. */
|
|
12
|
+
export class Dispatcher implements DispatchPort {
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly routes: RouteRegistry,
|
|
15
|
+
private readonly inFlight: InFlight,
|
|
16
|
+
private readonly lifecycle = new DispatchLifecycle(),
|
|
17
|
+
private readonly policy?: RoutePolicy,
|
|
18
|
+
) {}
|
|
19
|
+
|
|
20
|
+
async dispatch(call: Call): Promise<unknown> {
|
|
21
|
+
let route: Route | undefined;
|
|
22
|
+
let release: (() => void) | undefined;
|
|
23
|
+
this.lifecycle.publish(DispatchEvent.received(call));
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
release = this.inFlight.enter(call.address.entity, call.address.operation);
|
|
27
|
+
const known = this.routes.find(call.address);
|
|
28
|
+
const resolved = known ?? await this.routes.resolve(call.address);
|
|
29
|
+
route = resolved && (!this.policy || this.policy.accepts(resolved)) ? resolved : undefined;
|
|
30
|
+
if (!route) {
|
|
31
|
+
throw this.policy?.notFound?.(call, this.routes.routes())
|
|
32
|
+
?? new RouteNotFoundError(call, this.routes.routes(), this.policy);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.lifecycle.publish(DispatchEvent.resolved(call, route.kind));
|
|
36
|
+
const result = await route.execute(call);
|
|
37
|
+
this.lifecycle.publish(DispatchEvent.completed(call, route.kind));
|
|
38
|
+
return result;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
this.lifecycle.publish(DispatchEvent.failed(call, error, route?.kind));
|
|
41
|
+
throw error;
|
|
42
|
+
} finally {
|
|
43
|
+
this.lifecycle.publish(DispatchEvent.settled(call, route?.kind));
|
|
44
|
+
release?.();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FougereError, ErrorCode } from '../wire/errors.js';
|
|
2
|
+
|
|
3
|
+
/** Controls dispatch admission and signals when every accepted call has settled. */
|
|
4
|
+
export class InFlight {
|
|
5
|
+
private running = 0;
|
|
6
|
+
private accepting = true;
|
|
7
|
+
private idle: (() => void)[] = [];
|
|
8
|
+
|
|
9
|
+
get count(): number {
|
|
10
|
+
return this.running;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get open(): boolean {
|
|
14
|
+
return this.accepting;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
enter(entity: string, operation: string): () => void {
|
|
18
|
+
if (!this.accepting) {
|
|
19
|
+
throw new FougereError({
|
|
20
|
+
code: ErrorCode.SERVICE_UNAVAILABLE,
|
|
21
|
+
message: 'This app is being released and takes no new call — reach the current one through its handle.',
|
|
22
|
+
entity,
|
|
23
|
+
operation,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.running++;
|
|
28
|
+
let released = false;
|
|
29
|
+
return () => {
|
|
30
|
+
if (released) return;
|
|
31
|
+
released = true;
|
|
32
|
+
this.running--;
|
|
33
|
+
if (this.running !== 0) return;
|
|
34
|
+
|
|
35
|
+
const waiting = this.idle;
|
|
36
|
+
this.idle = [];
|
|
37
|
+
for (const wake of waiting) wake();
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
close(): void {
|
|
42
|
+
this.accepting = false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
whenIdle(): Promise<void> {
|
|
46
|
+
if (this.running === 0) return Promise.resolve();
|
|
47
|
+
return new Promise((resolve) => this.idle.push(resolve));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RowJudge, type SchemaView } from '@fougere/schema';
|
|
2
|
+
import type { InvocationContext } from '../contract/Invocation.js';
|
|
3
|
+
import { ErrorCode, FougereError } from '../wire/errors.js';
|
|
4
|
+
|
|
5
|
+
/** Validates and decodes the input body declared by one operation contract. */
|
|
6
|
+
export class InputValidator {
|
|
7
|
+
validate(
|
|
8
|
+
schema: SchemaView | undefined,
|
|
9
|
+
invocation: InvocationContext,
|
|
10
|
+
entity: string,
|
|
11
|
+
operation: string,
|
|
12
|
+
): InvocationContext {
|
|
13
|
+
if (!schema || invocation.body === undefined || invocation.body === null) return invocation;
|
|
14
|
+
|
|
15
|
+
const result = RowJudge.of(schema.getFields(), { patch: schema.getOpts().patch })
|
|
16
|
+
.check(invocation.body);
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
throw new FougereError({
|
|
19
|
+
code: ErrorCode.VALIDATION_FAILED,
|
|
20
|
+
message: result.errors.map((error) => `${error.path}: ${error.message}`).join(', '),
|
|
21
|
+
details: result.errors,
|
|
22
|
+
entity,
|
|
23
|
+
operation,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return { ...invocation, body: result.data };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import { ErrorCode, FougereError } from '../wire/errors.js';
|
|
3
|
+
import type { Route } from './Route.js';
|
|
4
|
+
import type { RoutePolicy } from './RoutePolicy.js';
|
|
5
|
+
import { RouteNotFoundError } from './RouteNotFoundError.js';
|
|
6
|
+
|
|
7
|
+
/** Incoming calls may execute here but never forward to another host. */
|
|
8
|
+
export class LocalRoutePolicy implements RoutePolicy {
|
|
9
|
+
constructor(private readonly hostedNames: (surface?: string) => string[]) {}
|
|
10
|
+
|
|
11
|
+
accepts(route: Route): boolean {
|
|
12
|
+
return route.kind !== 'remote';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
notFound(call: Call, routes: readonly Route[]): Error | undefined {
|
|
16
|
+
if (call.address.entity === 'rpc') return undefined;
|
|
17
|
+
|
|
18
|
+
const unknownRoute = new RouteNotFoundError(call, routes, this);
|
|
19
|
+
if (unknownRoute.servedOperations.length > 0) return unknownRoute;
|
|
20
|
+
|
|
21
|
+
const hosted = this.hostedNames(call.address.surface);
|
|
22
|
+
const entity = call.address.entity;
|
|
23
|
+
const surface = call.address.surface;
|
|
24
|
+
return new FougereError({
|
|
25
|
+
code: ErrorCode.NOT_FOUND,
|
|
26
|
+
message: (surface
|
|
27
|
+
? `Entity '${entity}' is not served on surface '${surface}'`
|
|
28
|
+
: `Entity '${entity}' is not hosted here`)
|
|
29
|
+
+ (hosted.length ? `. Hosted here: ${hosted.join(', ')}.` : '. This app hosts no entity.'),
|
|
30
|
+
entity,
|
|
31
|
+
operation: call.address.operation,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { InvocationContext } from '../contract/Invocation.js';
|
|
2
|
+
import { canonicalInvocation } from '../contract/Invocation.js';
|
|
3
|
+
import type { OperationContract } from '../wire/operation.js';
|
|
4
|
+
import {
|
|
5
|
+
runMiddlewares,
|
|
6
|
+
type AppMiddleware,
|
|
7
|
+
type OperationContext,
|
|
8
|
+
} from '../wire/middleware.js';
|
|
9
|
+
import type { ArgumentResolver } from './ArgumentResolver.js';
|
|
10
|
+
import type { InputValidator } from './InputValidator.js';
|
|
11
|
+
import type { OutputProjector } from './OutputProjector.js';
|
|
12
|
+
|
|
13
|
+
export interface OperationExecution {
|
|
14
|
+
entity: string;
|
|
15
|
+
frond: string;
|
|
16
|
+
operation: string;
|
|
17
|
+
contract: OperationContract | undefined;
|
|
18
|
+
middlewares: () => AppMiddleware[];
|
|
19
|
+
validator: InputValidator;
|
|
20
|
+
arguments: ArgumentResolver;
|
|
21
|
+
invoke: (args: unknown[]) => unknown | Promise<unknown>;
|
|
22
|
+
projector: OutputProjector;
|
|
23
|
+
present?: (result: unknown, invocation: InvocationContext) => Promise<unknown>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Executes one operation through the same ordered boundary steps on every route. */
|
|
27
|
+
export class OperationExecutor {
|
|
28
|
+
constructor(private readonly execution: OperationExecution) {}
|
|
29
|
+
|
|
30
|
+
async execute(input?: Partial<InvocationContext>): Promise<unknown> {
|
|
31
|
+
const invocation = canonicalInvocation(input);
|
|
32
|
+
const context: OperationContext = {
|
|
33
|
+
entity: this.execution.entity,
|
|
34
|
+
frond: this.execution.frond,
|
|
35
|
+
operation: this.execution.operation,
|
|
36
|
+
args: [],
|
|
37
|
+
state: invocation.state,
|
|
38
|
+
invocation,
|
|
39
|
+
};
|
|
40
|
+
return runMiddlewares(this.execution.middlewares(), context, async () => {
|
|
41
|
+
const effective = this.execution.validator.validate(
|
|
42
|
+
this.execution.contract?.input,
|
|
43
|
+
invocation,
|
|
44
|
+
context.entity,
|
|
45
|
+
context.operation,
|
|
46
|
+
);
|
|
47
|
+
context.invocation = effective;
|
|
48
|
+
|
|
49
|
+
const args = this.execution.contract?.binding
|
|
50
|
+
? await this.execution.arguments.resolve(this.execution.contract.binding, effective)
|
|
51
|
+
: [];
|
|
52
|
+
const projected = this.execution.projector.project(
|
|
53
|
+
await this.execution.invoke(args),
|
|
54
|
+
);
|
|
55
|
+
return this.execution.present
|
|
56
|
+
? this.execution.present(projected, effective)
|
|
57
|
+
: projected;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import type { RouteAddress } from '../contract/RouteAddress.js';
|
|
3
|
+
import type { Route } from './Route.js';
|
|
4
|
+
|
|
5
|
+
export type RouteExecution = (call: Call) => unknown | Promise<unknown>;
|
|
6
|
+
|
|
7
|
+
/** One executable route, distinguished by its routing kind. */
|
|
8
|
+
export class OperationRoute implements Route {
|
|
9
|
+
constructor(
|
|
10
|
+
readonly kind: Route['kind'],
|
|
11
|
+
readonly address: RouteAddress,
|
|
12
|
+
private readonly execution: RouteExecution,
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
async execute(call: Call): Promise<unknown> {
|
|
16
|
+
return (await this.execution(call)) ?? null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Visibility } from '@fougere/schema';
|
|
2
|
+
import { preserveArrayProperties } from './ArrayResult.js';
|
|
3
|
+
import type { OutputView } from './OutputView.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Projects one operation result onto the fields its audience may read.
|
|
7
|
+
*
|
|
8
|
+
* One of the two exits a judge watches; `StorageGuard` is the other.
|
|
9
|
+
*/
|
|
10
|
+
export class OutputProjector {
|
|
11
|
+
constructor(private readonly view: OutputView) {}
|
|
12
|
+
|
|
13
|
+
project(result: unknown): unknown {
|
|
14
|
+
if (result === null || result === undefined) return result;
|
|
15
|
+
|
|
16
|
+
if (Array.isArray(result)) {
|
|
17
|
+
return preserveArrayProperties(result, result.map((item) => this.project(item)));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (typeof result !== 'object') return result;
|
|
21
|
+
|
|
22
|
+
const record = result as Record<string, unknown>;
|
|
23
|
+
const scoped = this.view.closed
|
|
24
|
+
? Object.fromEntries(
|
|
25
|
+
Object.keys(this.view.fields)
|
|
26
|
+
.filter((key) => key in record)
|
|
27
|
+
.map((key) => [key, record[key]]),
|
|
28
|
+
)
|
|
29
|
+
: record;
|
|
30
|
+
return Visibility.of(this.view.fields).encode(scoped);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { computeBindingPlan } from '../boot/binding.js';
|
|
2
|
+
import type { InvocationContext } from '../contract/Invocation.js';
|
|
3
|
+
import type { PresenterEntry } from '../scan/frond.js';
|
|
4
|
+
import type { ArgumentResolver } from './ArgumentResolver.js';
|
|
5
|
+
import type { PresenterArgs } from './PresenterExecutor.js';
|
|
6
|
+
|
|
7
|
+
/** Resolves the invocation-dependent arguments of every computed presenter field. */
|
|
8
|
+
export class PresenterArgumentResolver {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly argumentsResolver: ArgumentResolver,
|
|
11
|
+
private readonly collectorTypes: Set<string>,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async resolve(meta: PresenterEntry, invocation: InvocationContext): Promise<PresenterArgs> {
|
|
15
|
+
const argumentsByField: PresenterArgs = {};
|
|
16
|
+
for (const field of meta.fieldMeta) {
|
|
17
|
+
if (!field.params?.length) continue;
|
|
18
|
+
argumentsByField[field.name] = await this.argumentsResolver.resolve(
|
|
19
|
+
computeBindingPlan(field.params, this.collectorTypes),
|
|
20
|
+
invocation,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return argumentsByField;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ErrorCode, FougereError } from '../wire/errors.js';
|
|
2
|
+
import { preserveArrayProperties } from './ArrayResult.js';
|
|
3
|
+
|
|
4
|
+
export type PresenterArgs = Record<string, unknown[]>;
|
|
5
|
+
|
|
6
|
+
/** Adds a presenter's computed fields after output projection. */
|
|
7
|
+
export class PresenterExecutor {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly presenter: Record<string, unknown> | undefined,
|
|
10
|
+
private readonly fieldNames: readonly string[] | undefined,
|
|
11
|
+
private readonly entity = 'unknown',
|
|
12
|
+
private readonly operation = 'unknown',
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
async present(result: unknown, args: PresenterArgs = {}): Promise<unknown> {
|
|
16
|
+
if (!this.presenter || !this.fieldNames?.length || result === null || typeof result !== 'object') {
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const rows = Array.isArray(result) ? result : [result];
|
|
21
|
+
const values = new Map<string, unknown[]>();
|
|
22
|
+
|
|
23
|
+
for (const name of this.fieldNames) {
|
|
24
|
+
const field = this.presenter[name];
|
|
25
|
+
if (typeof field !== 'function') continue;
|
|
26
|
+
try {
|
|
27
|
+
const answered = await field.call(this.presenter, rows, ...(args[name] ?? []));
|
|
28
|
+
if (!Array.isArray(answered) || answered.length !== rows.length) {
|
|
29
|
+
const actual = Array.isArray(answered) ? answered.length : typeof answered;
|
|
30
|
+
throw new Error(`expected ${rows.length} value(s) for ${rows.length} row(s), got ${actual}`);
|
|
31
|
+
}
|
|
32
|
+
values.set(name, answered);
|
|
33
|
+
} catch (cause) {
|
|
34
|
+
throw new FougereError({
|
|
35
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
36
|
+
message: `Computed field '${name}' failed: ${(cause as Error)?.message ?? cause}`,
|
|
37
|
+
entity: this.entity,
|
|
38
|
+
operation: this.operation,
|
|
39
|
+
cause,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const enriched = rows.map((item, index) => {
|
|
45
|
+
if (item === null || typeof item !== 'object') return item;
|
|
46
|
+
const output = { ...(item as Record<string, unknown>) };
|
|
47
|
+
for (const [name, answered] of values) output[name] = answered[index];
|
|
48
|
+
return output;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return Array.isArray(result)
|
|
52
|
+
? preserveArrayProperties(result, enriched)
|
|
53
|
+
: enriched[0];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RouteAddress } from '../contract/RouteAddress.js';
|
|
2
|
+
import { OperationRoute } from './OperationRoute.js';
|
|
3
|
+
import type { Route } from './Route.js';
|
|
4
|
+
import type { RouteResolver } from './RouteResolver.js';
|
|
5
|
+
|
|
6
|
+
type RemoteFacade = Record<string, Function>;
|
|
7
|
+
export type RemoteFacadeResolver = (entity: string) => RemoteFacade | undefined;
|
|
8
|
+
|
|
9
|
+
/** Builds a remote route on the first call, after the remote façade can be resolved. */
|
|
10
|
+
export class RemoteRouteResolver implements RouteResolver {
|
|
11
|
+
constructor(private readonly facades: RemoteFacadeResolver) {}
|
|
12
|
+
|
|
13
|
+
resolve(address: RouteAddress): Route | undefined {
|
|
14
|
+
if (address.surface !== undefined) return undefined;
|
|
15
|
+
|
|
16
|
+
const facade = this.facades(address.entity);
|
|
17
|
+
const operation = facade?.[address.operation];
|
|
18
|
+
if (typeof operation !== 'function') return undefined;
|
|
19
|
+
return new OperationRoute('remote', address, (call) => operation(call.invocation));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import type { RouteAddress } from '../contract/RouteAddress.js';
|
|
3
|
+
|
|
4
|
+
export type RouteKind = 'local' | 'remote' | 'system';
|
|
5
|
+
|
|
6
|
+
/** Executable destination known by the dispatcher. */
|
|
7
|
+
export interface Route {
|
|
8
|
+
readonly kind: RouteKind;
|
|
9
|
+
readonly address: RouteAddress;
|
|
10
|
+
execute(call: Call): Promise<unknown>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import { ErrorCode, FougereError } from '../wire/errors.js';
|
|
3
|
+
import type { Route } from './Route.js';
|
|
4
|
+
import type { RoutePolicy } from './RoutePolicy.js';
|
|
5
|
+
|
|
6
|
+
/** Describes an unresolved route from the destinations visible to one dispatcher. */
|
|
7
|
+
export class RouteNotFoundError extends FougereError {
|
|
8
|
+
readonly servedOperations: readonly string[];
|
|
9
|
+
|
|
10
|
+
constructor(call: Call, routes: readonly Route[], policy?: RoutePolicy) {
|
|
11
|
+
const served = routes
|
|
12
|
+
.filter((route) => !policy || policy.accepts(route))
|
|
13
|
+
.filter((route) => route.address.entity === call.address.entity)
|
|
14
|
+
.filter((route) => route.kind === 'system'
|
|
15
|
+
|| route.address.surface === call.address.surface)
|
|
16
|
+
.map((route) => route.address.operation);
|
|
17
|
+
const operation = call.address.operation;
|
|
18
|
+
const entity = call.address.entity;
|
|
19
|
+
const message = entity === 'rpc'
|
|
20
|
+
? `Unknown rpc operation '${operation}'. `
|
|
21
|
+
+ (served.length ? `It serves ${served.join(', ')}.` : 'It serves nothing.')
|
|
22
|
+
: served.length
|
|
23
|
+
? `Unknown operation '${operation}' on '${entity}'. It serves ${served.join(', ')}.`
|
|
24
|
+
: `No route serves '${call.address}'`;
|
|
25
|
+
|
|
26
|
+
super({ code: ErrorCode.NOT_FOUND, message, entity, operation });
|
|
27
|
+
this.servedOperations = served;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Call } from '../contract/Call.js';
|
|
2
|
+
import type { Route } from './Route.js';
|
|
3
|
+
|
|
4
|
+
/** Restricts which registered routes one dispatch capability may enter. */
|
|
5
|
+
export interface RoutePolicy {
|
|
6
|
+
accepts(route: Route): boolean;
|
|
7
|
+
notFound?(call: Call, routes: readonly Route[]): Error | undefined;
|
|
8
|
+
}
|