@fougere/core 0.6.0-alpha.0 → 0.8.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/AppLifecycle.d.ts +1 -1
- package/dist/boot/AppLifecycle.d.ts.map +1 -1
- package/dist/boot/AppLifecycle.js +13 -2
- package/dist/boot/AppLifecycle.js.map +1 -1
- package/dist/boot/Emissions.d.ts +13 -90
- 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 +9 -16
- package/dist/boot/apply.js.map +1 -1
- package/dist/boot/auth.d.ts +2 -12
- package/dist/boot/auth.d.ts.map +1 -1
- package/dist/boot/boot.d.ts +3 -16
- 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 +84 -130
- package/dist/boot/bootstrap.js.map +1 -1
- package/dist/boot/card.d.ts +1 -17
- package/dist/boot/card.d.ts.map +1 -1
- package/dist/boot/card.js +3 -32
- package/dist/boot/card.js.map +1 -1
- package/dist/boot/frame.d.ts +8 -32
- package/dist/boot/frame.d.ts.map +1 -1
- package/dist/boot/frame.js +17 -56
- package/dist/boot/frame.js.map +1 -1
- package/dist/boot/hosted.d.ts +2 -24
- package/dist/boot/hosted.d.ts.map +1 -1
- package/dist/boot/hosted.js +10 -15
- package/dist/boot/hosted.js.map +1 -1
- package/dist/boot/ownership.d.ts +3 -36
- package/dist/boot/ownership.d.ts.map +1 -1
- package/dist/boot/ownership.js +5 -40
- package/dist/boot/ownership.js.map +1 -1
- package/dist/boot/ports.d.ts +1 -14
- 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 +4 -21
- package/dist/boot/runner.d.ts.map +1 -1
- package/dist/boot/runner.js +4 -17
- package/dist/boot/runner.js.map +1 -1
- package/dist/boot/seed.d.ts +4 -31
- package/dist/boot/seed.d.ts.map +1 -1
- package/dist/boot/seed.js +6 -37
- package/dist/boot/seed.js.map +1 -1
- package/dist/boot/statement-drift.d.ts +2 -21
- 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 +4 -8
- package/dist/boot/together.d.ts.map +1 -1
- package/dist/boot/together.js +15 -50
- package/dist/boot/together.js.map +1 -1
- package/dist/boot/types.d.ts +31 -173
- 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 +15 -31
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +13 -26
- package/dist/contract.js.map +1 -1
- package/dist/criterion.d.ts +37 -0
- package/dist/criterion.d.ts.map +1 -0
- package/dist/criterion.js +28 -0
- package/dist/criterion.js.map +1 -0
- 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 +19 -37
- package/dist/declare.d.ts.map +1 -1
- package/dist/declare.js +23 -30
- package/dist/declare.js.map +1 -1
- 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 +3 -28
- package/dist/descriptor/Fronds.d.ts.map +1 -1
- package/dist/descriptor/Fronds.js +6 -31
- package/dist/descriptor/Fronds.js.map +1 -1
- package/dist/descriptor/frond.d.ts +25 -60
- package/dist/descriptor/frond.d.ts.map +1 -1
- package/dist/descriptor/frond.js +5 -1
- package/dist/descriptor/frond.js.map +1 -1
- package/dist/dispatch/ArgumentResolver.d.ts +1 -1
- package/dist/dispatch/ArgumentResolver.d.ts.map +1 -1
- package/dist/dispatch/ArgumentResolver.js +5 -5
- 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 -2
- 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 +40 -8
- package/dist/dispatch/StorageGuard.d.ts.map +1 -1
- package/dist/dispatch/StorageGuard.js +151 -20
- 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 +1 -24
- package/dist/effective-operation.d.ts.map +1 -1
- package/dist/effective-operation.js +21 -50
- 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 +7 -70
- 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/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 +1 -7
- 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 +17 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -18
- 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 +16 -32
- package/dist/prefab/crud.d.ts.map +1 -1
- package/dist/prefab/crud.js +31 -58
- package/dist/prefab/crud.js.map +1 -1
- package/dist/prefab/mirror.d.ts +2 -24
- package/dist/prefab/mirror.d.ts.map +1 -1
- package/dist/prefab/mirror.js +2 -20
- 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 +5 -73
- package/dist/prefab/repository.d.ts.map +1 -1
- package/dist/prefab/repository.js +3 -16
- 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/contract.d.ts +27 -0
- package/dist/scan/contract.d.ts.map +1 -0
- package/dist/scan/contract.js +46 -0
- package/dist/scan/contract.js.map +1 -0
- 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 +1 -5
- package/dist/scan/emit.d.ts.map +1 -1
- package/dist/scan/emit.js +10 -78
- package/dist/scan/emit.js.map +1 -1
- package/dist/scan/handler-parser.d.ts +4 -26
- package/dist/scan/handler-parser.d.ts.map +1 -1
- package/dist/scan/handler-parser.js +26 -83
- package/dist/scan/handler-parser.js.map +1 -1
- package/dist/scan/result.d.ts +3 -16
- package/dist/scan/result.d.ts.map +1 -1
- package/dist/scan/scanner.d.ts +2 -27
- package/dist/scan/scanner.d.ts.map +1 -1
- package/dist/scan/scanner.js +45 -133
- package/dist/scan/scanner.js.map +1 -1
- package/dist/scan/statement.d.ts.map +1 -1
- package/dist/scan/statement.js +60 -37
- package/dist/scan/statement.js.map +1 -1
- package/dist/source.d.ts +53 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +18 -0
- package/dist/source.js.map +1 -0
- package/dist/storage.d.ts +13 -210
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +4 -68
- package/dist/storage.js.map +1 -1
- package/dist/store.d.ts +18 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +179 -0
- package/dist/store.js.map +1 -0
- package/dist/verify.d.ts +5 -38
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +17 -37
- 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/{contract → wire}/RouteAddress.d.ts +5 -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 +5 -21
- package/dist/wire/binding.d.ts.map +1 -1
- package/dist/wire/binding.js +5 -10
- package/dist/wire/binding.js.map +1 -1
- package/dist/wire/call.d.ts +24 -133
- package/dist/wire/call.d.ts.map +1 -1
- package/dist/wire/call.js +15 -41
- 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 +7 -43
- package/dist/wire/operation.d.ts.map +1 -1
- package/dist/wire/operation.js +4 -15
- package/dist/wire/operation.js.map +1 -1
- package/dist/wire/signature.d.ts +4 -25
- package/dist/wire/signature.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/boot/AppLifecycle.ts +15 -2
- package/src/boot/Emissions.ts +21 -118
- 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 +9 -16
- package/src/boot/auth.ts +2 -12
- package/src/boot/boot.ts +6 -21
- package/src/boot/bootstrap.ts +95 -140
- package/src/boot/card.ts +4 -33
- package/src/boot/frame.ts +24 -64
- package/src/boot/hosted.ts +12 -34
- package/src/boot/ownership.ts +5 -39
- package/src/boot/ports.ts +1 -14
- package/src/boot/remote.ts +11 -58
- package/src/boot/runner.ts +5 -22
- package/src/boot/seed.ts +6 -37
- package/src/boot/statement-drift.ts +5 -24
- package/src/boot/together.ts +18 -51
- package/src/boot/types.ts +31 -173
- 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 +19 -39
- package/src/criterion.ts +54 -0
- 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/declare.ts +42 -41
- package/src/define.ts +2 -3
- package/src/descriptor/Fronds.ts +6 -31
- package/src/descriptor/frond.ts +26 -60
- package/src/dispatch/ArgumentResolver.ts +6 -6
- 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 -2
- 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 +175 -19
- 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 +21 -50
- 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 +7 -70
- package/src/identity-keys.ts +3 -16
- package/src/identity.ts +12 -80
- package/src/imports.ts +2 -31
- package/src/index.ts +17 -24
- package/src/loader.ts +2 -16
- package/src/node.ts +2 -11
- package/src/prefab/collector.ts +1 -22
- package/src/prefab/crud.ts +37 -76
- package/src/prefab/mirror.ts +4 -44
- package/src/prefab/prefab.ts +2 -21
- package/src/prefab/presenter.ts +2 -36
- package/src/prefab/repository.ts +7 -83
- package/src/scan/adapters.ts +32 -0
- package/src/scan/bundling.ts +1 -12
- package/src/scan/contract.ts +80 -0
- package/src/scan/conventions.ts +6 -40
- package/src/scan/emit.ts +11 -80
- package/src/scan/handler-parser.ts +27 -96
- package/src/scan/result.ts +3 -16
- package/src/scan/scanner.ts +46 -132
- package/src/scan/statement.ts +73 -41
- package/src/source.ts +63 -0
- package/src/storage.ts +14 -234
- package/src/store.ts +191 -0
- package/src/verify.ts +16 -57
- package/src/wire/CallLog.ts +30 -0
- package/src/{contract → wire}/Invocation.ts +24 -17
- package/src/{contract → wire}/RouteAddress.ts +7 -0
- package/src/wire/binding.ts +9 -25
- package/src/wire/call.ts +30 -133
- 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 +8 -48
- package/src/wire/signature.ts +4 -25
- package/dist/boot/HandlerFacade.d.ts.map +0 -1
- package/dist/boot/HandlerFacade.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.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/rows.d.ts +0 -40
- package/dist/rows.d.ts.map +0 -1
- package/dist/rows.js +0 -146
- package/dist/rows.js.map +0 -1
- package/src/boot/HandlerFacade.ts +0 -242
- 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/rows.ts +0 -155
- /package/dist/{contract → wire}/CallLog.js +0 -0
package/src/store.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/** The thirteen gestures of {@link Storage}, derived from four. */
|
|
2
|
+
import { applyCreate, applyUpdate, Lifecycle, Role, type SchemaView } from '@fougere/schema';
|
|
3
|
+
import { comparisonOf, comparisonsIn, type Comparison } from './criterion.js';
|
|
4
|
+
import type { Storage, StorageFactory } from './storage.js';
|
|
5
|
+
|
|
6
|
+
/** One instance, as every realization hands it over. */
|
|
7
|
+
export type Values = Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
/** Instances addressed by key — what an adapter supplies, and all of it. */
|
|
10
|
+
export interface Store {
|
|
11
|
+
get(key: string): Promise<Values | undefined>;
|
|
12
|
+
has(key: string): Promise<boolean>;
|
|
13
|
+
set(key: string, values: Values): Promise<void>;
|
|
14
|
+
delete(key: string): Promise<boolean>;
|
|
15
|
+
/** Everything it holds. A realization that cannot answer this cheaply says so in its doc. */
|
|
16
|
+
all(): Promise<Values[]>;
|
|
17
|
+
/** Handed on as `Storage.client` — the Map, the directory, whatever it is. */
|
|
18
|
+
readonly client: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function storageOver(open: (entity: SchemaView, name: string) => Store): StorageFactory {
|
|
22
|
+
return (entity: SchemaView, name: string): Storage => {
|
|
23
|
+
const fields = entity.getFields();
|
|
24
|
+
const store = open(entity, name);
|
|
25
|
+
const pk = Object.entries(fields).find(([, field]) => Role.of(field).isPrimary)?.[0] ?? 'id';
|
|
26
|
+
// `Storage.findById(id: string)` — but a key can hold a number, and a Map keyed on
|
|
27
|
+
// `1` does not answer `'1'`. SQL never had the question; here the divergence was
|
|
28
|
+
// silent and only on this storage.
|
|
29
|
+
const keyOf = (value: unknown) => String(value);
|
|
30
|
+
// Same contract as SQL: a criterion may name a SET, and an empty set matches nothing.
|
|
31
|
+
// A comparison is told from a value by the FIELD, never by the criterion's own shape.
|
|
32
|
+
const matches = (values: Record<string, unknown>, criteria: Record<string, unknown>) =>
|
|
33
|
+
Object.entries(criteria).every(([key, value]) => {
|
|
34
|
+
const comparison = comparisonOf(fields[key], value);
|
|
35
|
+
if (comparison) return compares(values[key], comparison);
|
|
36
|
+
|
|
37
|
+
return Array.isArray(value)
|
|
38
|
+
? value.some((v) => Object.is(values[key], v))
|
|
39
|
+
: Object.is(values[key], value);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// A store holds whole instances and reads them whole, so the scope SQL puts in its
|
|
43
|
+
// SELECT is applied here on the way out. Same set of gestures either way: everything
|
|
44
|
+
// that hands back an instance, which leaves `delete` and `upsertAll` alone.
|
|
45
|
+
const scoped = (selected?: Set<string>): Storage => {
|
|
46
|
+
const pick = (values: Values): Values => (selected
|
|
47
|
+
? Object.fromEntries(Object.entries(values).filter(([key]) => selected.has(key)))
|
|
48
|
+
: values);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
client: store.client,
|
|
52
|
+
async list(options?: any) {
|
|
53
|
+
let items = await store.all();
|
|
54
|
+
if (options?.where) items = items.filter((values) => matches(values, options.where));
|
|
55
|
+
// Held before the page is cut, and after the filter: `total` answers "how many
|
|
56
|
+
// match", which is what a paginator divides. Reading `store.size` at the end
|
|
57
|
+
// answered a different question — everything the store holds, including the ones
|
|
58
|
+
// the filter exists to keep out of this caller's sight.
|
|
59
|
+
const matching = items.length;
|
|
60
|
+
const limit = options?.limit;
|
|
61
|
+
const offset = options?.page && limit ? (options.page - 1) * limit : options?.offset ?? 0;
|
|
62
|
+
if (offset > 0) items = items.slice(offset);
|
|
63
|
+
const hasMore = limit ? items.length > limit : false;
|
|
64
|
+
if (limit) items = items.slice(0, limit);
|
|
65
|
+
// The cursor is read before the scope cuts: a view that drops the key still
|
|
66
|
+
// pages, the way it does over SQL.
|
|
67
|
+
const endCursor = items.length > 0 ? String((items[items.length - 1] as any)[pk] ?? '') : undefined;
|
|
68
|
+
const result = items.map(pick) as any;
|
|
69
|
+
result.hasMore = hasMore;
|
|
70
|
+
result.endCursor = endCursor;
|
|
71
|
+
if (options?.count) result.total = matching;
|
|
72
|
+
return result;
|
|
73
|
+
},
|
|
74
|
+
async findById(id: string) {
|
|
75
|
+
const values = await store.get(keyOf(id));
|
|
76
|
+
return values && pick(values);
|
|
77
|
+
},
|
|
78
|
+
async findBy(criteria: Record<string, unknown>) {
|
|
79
|
+
const values = (await store.all()).find((held) => matches(held, criteria));
|
|
80
|
+
return values && pick(values);
|
|
81
|
+
},
|
|
82
|
+
async findAllBy(criteria: Record<string, unknown>) {
|
|
83
|
+
return (await store.all()).filter((values) => matches(values, criteria)).map(pick);
|
|
84
|
+
},
|
|
85
|
+
// Same contract as SQL: a map keyed by the primary key, a miss being an absent key.
|
|
86
|
+
async findByKeys(ids: readonly string[]) {
|
|
87
|
+
const found = new Map<string, Record<string, unknown>>();
|
|
88
|
+
for (const id of ids) {
|
|
89
|
+
const values = await store.get(keyOf(id));
|
|
90
|
+
if (values) found.set(String(id), pick(values));
|
|
91
|
+
}
|
|
92
|
+
return found;
|
|
93
|
+
},
|
|
94
|
+
// The dual, same contract as SQL: grouped by the value read off the instance.
|
|
95
|
+
async findAllByKeys(field: string, keys: readonly string[]) {
|
|
96
|
+
const grouped = new Map<string, Record<string, unknown>[]>();
|
|
97
|
+
if (keys.length === 0) return grouped;
|
|
98
|
+
const wanted = new Set(keys.map(String));
|
|
99
|
+
for (const values of await store.all()) {
|
|
100
|
+
const key = String(values[field]);
|
|
101
|
+
if (!wanted.has(key)) continue;
|
|
102
|
+
const bucket = grouped.get(key);
|
|
103
|
+
if (bucket) bucket.push(pick(values)); else grouped.set(key, [pick(values)]);
|
|
104
|
+
}
|
|
105
|
+
return grouped;
|
|
106
|
+
},
|
|
107
|
+
// Same contract as SQL: the key and the creation stamps survive an overwrite.
|
|
108
|
+
async upsert(input: Partial<Record<string, unknown>>) {
|
|
109
|
+
const values = applyCreate(fields, applyUpdate(fields, input));
|
|
110
|
+
const id = values[pk] as string | undefined;
|
|
111
|
+
if (id === undefined) throw new Error(`${name}.upsert(): no \`${pk}\` — an upsert needs the key it writes at.`);
|
|
112
|
+
const previous = await store.get(keyOf(id));
|
|
113
|
+
if (previous) {
|
|
114
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
115
|
+
if (key === pk || Lifecycle.of(field).stampedOnce) values[key] = previous[key];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
await store.set(keyOf(id), values);
|
|
119
|
+
return pick(values);
|
|
120
|
+
},
|
|
121
|
+
async upsertAll(inputs: readonly Partial<Record<string, unknown>>[]) {
|
|
122
|
+
for (const input of inputs) await this.upsert(input);
|
|
123
|
+
return inputs.length;
|
|
124
|
+
},
|
|
125
|
+
async create(input: Partial<Record<string, unknown>>) {
|
|
126
|
+
const values = applyCreate(fields, input);
|
|
127
|
+
const id = values[pk] as string | undefined;
|
|
128
|
+
// `primary(text())` declares no generator, so nothing fills the hole and the
|
|
129
|
+
// caller has to. Keying on `undefined` would let the second create overwrite the
|
|
130
|
+
// first, in silence — the old version hid this by inventing an `id` field the
|
|
131
|
+
// entity never declared.
|
|
132
|
+
if (id === undefined) {
|
|
133
|
+
throw new Error(`${name}.create: '${pk}' is the primary key and nothing supplied it — this entity declares no generator for it.`);
|
|
134
|
+
}
|
|
135
|
+
// A create is not an upsert. `Map.set` overwrites, so a second create under the
|
|
136
|
+
// same key answered "created" while destroying the previous instance — SQL answers a
|
|
137
|
+
// constraint violation, and a store that loses data silently is worse than one
|
|
138
|
+
// that fails.
|
|
139
|
+
if (await store.has(keyOf(id))) {
|
|
140
|
+
throw new Error(`${name}.create: '${pk}' ${JSON.stringify(id)} already exists.`);
|
|
141
|
+
}
|
|
142
|
+
await store.set(keyOf(id), values);
|
|
143
|
+
return pick(values);
|
|
144
|
+
},
|
|
145
|
+
async update(id: string, input: Partial<Record<string, unknown>>) {
|
|
146
|
+
const existing = await store.get(keyOf(id));
|
|
147
|
+
if (!existing) throw new Error(`Not found: ${id}`);
|
|
148
|
+
const updated = { ...existing, ...applyUpdate(fields, input), [pk]: existing[pk] };
|
|
149
|
+
await store.set(keyOf(id), updated);
|
|
150
|
+
return pick(updated);
|
|
151
|
+
},
|
|
152
|
+
async delete(id: string) { return await store.delete(keyOf(id)); },
|
|
153
|
+
output(schema: SchemaView) { return scoped(new Set(Object.keys(schema.getFields()))); },
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return scoped();
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The same comparisons SQL compiles, answered in memory. Every one a criterion names has
|
|
163
|
+
* to hold — the rule two criteria already follow.
|
|
164
|
+
*/
|
|
165
|
+
function compares(held: unknown, comparison: Comparison): boolean {
|
|
166
|
+
return comparisonsIn(comparison).every(([name, asked]) => {
|
|
167
|
+
switch (name) {
|
|
168
|
+
case 'gte': return ordered(held, asked, (a, b) => a >= b);
|
|
169
|
+
case 'lte': return ordered(held, asked, (a, b) => a <= b);
|
|
170
|
+
case 'gt': return ordered(held, asked, (a, b) => a > b);
|
|
171
|
+
case 'lt': return ordered(held, asked, (a, b) => a < b);
|
|
172
|
+
case 'ne': return !Object.is(held, asked);
|
|
173
|
+
case 'contains': return String(held ?? '').includes(String(asked));
|
|
174
|
+
case 'notIn': return !(asked as readonly unknown[]).some((one) => Object.is(held, one));
|
|
175
|
+
case 'isNull': return (held === null || held === undefined) === Boolean(asked);
|
|
176
|
+
case 'between': {
|
|
177
|
+
const [low, high] = asked as [unknown, unknown];
|
|
178
|
+
|
|
179
|
+
return ordered(held, low, (a, b) => a >= b) && ordered(held, high, (a, b) => a <= b);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** A row that holds nothing compares to nothing — the answer SQL gives for NULL. */
|
|
186
|
+
const ordered = (held: unknown, asked: unknown, holds: (a: number, b: number) => boolean): boolean =>
|
|
187
|
+
held === null || held === undefined ? false : holds(order(held), order(asked));
|
|
188
|
+
|
|
189
|
+
/** What a Date and a number have in common, and a string keeps for itself. */
|
|
190
|
+
const order = (value: unknown): number =>
|
|
191
|
+
value instanceof Date ? value.getTime() : (value as number);
|
package/src/verify.ts
CHANGED
|
@@ -5,24 +5,11 @@ import { storageKeyOf } from './storage.js';
|
|
|
5
5
|
import { presenterKeyOf } from './prefab/presenter.js';
|
|
6
6
|
import { collectorKeyOf } from './prefab/collector.js';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* What a rule found in an app.
|
|
10
|
-
*
|
|
11
|
-
* `message` is the sentence the rule replaces — the prose a human used to have
|
|
12
|
-
* to remember. `Known issues` says "Keep collectors in the consuming frond";
|
|
13
|
-
* this is that sentence, told about a specific handler, by something that runs.
|
|
14
|
-
*/
|
|
8
|
+
/** What a rule found in an app. */
|
|
15
9
|
export interface Violation {
|
|
16
10
|
/** Rule name, stable — 'cross-frond-dependency'. */
|
|
17
11
|
rule: string;
|
|
18
|
-
/**
|
|
19
|
-
* What it costs, decided by the rule that raises it — never by whoever renders it.
|
|
20
|
-
*
|
|
21
|
-
* The two rules here are not the same animal: a cross-frond dependency resolves
|
|
22
|
-
* today and stops resolving the day the other frond answers over the wire, while a
|
|
23
|
-
* collector declared elsewhere is already wrong in one process. A reader holding a
|
|
24
|
-
* table of rule names would be a second opinion on a fact the rule already has.
|
|
25
|
-
*/
|
|
12
|
+
/** What it costs, decided by the rule that raises it — never by whoever renders it. */
|
|
26
13
|
severity: 'blocking' | 'warning';
|
|
27
14
|
/** The frond the subject lives in. */
|
|
28
15
|
frond: string;
|
|
@@ -30,15 +17,7 @@ export interface Violation {
|
|
|
30
17
|
subject: string;
|
|
31
18
|
/** Where to go and look. */
|
|
32
19
|
filePath: string;
|
|
33
|
-
/**
|
|
34
|
-
* What the subject reaches for, and where it actually lives.
|
|
35
|
-
*
|
|
36
|
-
* `frond` above is the CONSUMER; the target used to exist only inside the
|
|
37
|
-
* sentence. A reader that has to parse prose to learn which frond a violation
|
|
38
|
-
* points at is a second opinion on a fact the checker already held — so the
|
|
39
|
-
* boot can ask "does this violation target a frond named in `remotes:`?" by
|
|
40
|
-
* reading a field.
|
|
41
|
-
*/
|
|
20
|
+
/** What the subject reaches for, and where it actually lives. */
|
|
42
21
|
dependsOn: { key: string; frond: string; kind: string };
|
|
43
22
|
/** What breaks, and what the caller gets instead. */
|
|
44
23
|
message: string;
|
|
@@ -48,20 +27,16 @@ export interface Violation {
|
|
|
48
27
|
type Registration = { frond: string; kind: string };
|
|
49
28
|
|
|
50
29
|
/**
|
|
51
|
-
* The container keys a frond registers in its own scope, keyed as a handler's
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* Every key comes from the function that states it, never from a derivation
|
|
55
|
-
* respelled here: a second reader that spells one differently finds nothing and
|
|
56
|
-
* reports nothing wrong, which is the failure mode a checker must not have.
|
|
30
|
+
* The container keys a frond registers in its own scope, keyed as a handler's `deps` spell them —
|
|
31
|
+
* DI resolves by type name, so both sides are PascalCase.
|
|
57
32
|
*/
|
|
58
33
|
function registrationsOf(frond: FrondDescriptor): Map<string, Registration> {
|
|
59
34
|
const out = new Map<string, Registration>();
|
|
60
35
|
const put = (key: string, kind: string) => out.set(key, { frond: frond.name, kind });
|
|
61
36
|
|
|
62
|
-
for (const
|
|
63
|
-
for (const
|
|
64
|
-
for (const
|
|
37
|
+
for (const provider of frond.providers) put(provider.ctor.name, 'provider');
|
|
38
|
+
for (const presenter of frond.presenters) put(presenterKeyOf(presenter.entityName), 'presenter');
|
|
39
|
+
for (const collector of frond.collectors) put(collectorKeyOf(collector.typeName), 'collector');
|
|
65
40
|
for (const e of frond.entities) {
|
|
66
41
|
put(storageKeyOf(e.name), 'storage');
|
|
67
42
|
put(repositoryKeyOf(e.name), 'repository');
|
|
@@ -69,11 +44,7 @@ function registrationsOf(frond: FrondDescriptor): Map<string, Registration> {
|
|
|
69
44
|
return out;
|
|
70
45
|
}
|
|
71
46
|
|
|
72
|
-
/**
|
|
73
|
-
* Everything in a frond that is constructed by DI, so carries `deps`.
|
|
74
|
-
* Handlers, presenters and collectors are all built from a constructor whose
|
|
75
|
-
* argument types the scan read; each one can therefore reach across.
|
|
76
|
-
*/
|
|
47
|
+
/** Everything in a frond that is constructed by DI, so carries `deps`. */
|
|
77
48
|
function injectablesOf(frond: FrondDescriptor) {
|
|
78
49
|
return [
|
|
79
50
|
...frond.handlers.map((h) => ({ name: h.ctor.name, deps: h.deps, filePath: h.filePath })),
|
|
@@ -83,20 +54,8 @@ function injectablesOf(frond: FrondDescriptor) {
|
|
|
83
54
|
}
|
|
84
55
|
|
|
85
56
|
/**
|
|
86
|
-
* Does this app survive being split?
|
|
87
|
-
*
|
|
88
|
-
* A frond runs in-process or in its own process behind JSON-RPC with identical
|
|
89
|
-
* user code — that is the whole claim. What the claim does not say is that
|
|
90
|
-
* *every* app survives the move: a dependency that crosses a frond boundary
|
|
91
|
-
* resolves today because both scopes live in one container, and resolves to
|
|
92
|
-
* nothing the day the other frond answers over the wire.
|
|
93
|
-
*
|
|
94
|
-
* The question only exists where a module boundary is meant to become a process
|
|
95
|
-
* boundary later. Where every inter-module call is already remote there is
|
|
96
|
-
* nothing to check, and where no exit is planned there is nothing to check
|
|
97
|
-
* either. Here it means something, and until now it had no answer.
|
|
98
|
-
*
|
|
99
|
-
* Pure over `app.fronds`: no mount, no process, no file. Call it from a test.
|
|
57
|
+
* Does this app survive being split? A frond runs in-process or in its own process behind JSON-RPC
|
|
58
|
+
* with identical user code — that is the whole claim.
|
|
100
59
|
*/
|
|
101
60
|
export function verify(app: { fronds: readonly FrondDescriptor[] }): Violation[] {
|
|
102
61
|
const index = new Map<string, Registration>();
|
|
@@ -109,7 +68,7 @@ export function verify(app: { fronds: readonly FrondDescriptor[] }): Violation[]
|
|
|
109
68
|
// they need their own index and their own rule.
|
|
110
69
|
const collectorFronds = new Map<string, string>();
|
|
111
70
|
for (const frond of app.fronds) {
|
|
112
|
-
for (const
|
|
71
|
+
for (const collector of frond.collectors) collectorFronds.set(collector.typeName, frond.name);
|
|
113
72
|
}
|
|
114
73
|
|
|
115
74
|
const violations: Violation[] = [];
|
|
@@ -144,8 +103,8 @@ export function verify(app: { fronds: readonly FrondDescriptor[] }): Violation[]
|
|
|
144
103
|
|
|
145
104
|
// Rule 2 — an operation parameter that wanted a collector this frond has not
|
|
146
105
|
// got. The preliminary binding convention can only see this frond's collector
|
|
147
|
-
// set, so it produces
|
|
148
|
-
// before boot: another frond's collector proves the provenance is not
|
|
106
|
+
// set, so it produces input evidence. EffectiveOperation refuses that evidence
|
|
107
|
+
// before boot: another frond's collector proves the provenance is not an input.
|
|
149
108
|
const own = new Set(frond.collectors.map((c) => c.typeName));
|
|
150
109
|
for (const handler of frond.handlers) {
|
|
151
110
|
for (const [opName, op] of handler.operations) {
|
|
@@ -156,7 +115,7 @@ export function verify(app: { fronds: readonly FrondDescriptor[] }): Violation[]
|
|
|
156
115
|
const wanted = lowerFirst(param.type.name);
|
|
157
116
|
if (own.has(wanted)) continue;
|
|
158
117
|
const elsewhere = collectorFronds.get(wanted);
|
|
159
|
-
// No collector anywhere for that type may be an ordinary
|
|
118
|
+
// No collector anywhere for that type may be an ordinary input parameter.
|
|
160
119
|
// Only a collector that exists in the wrong place makes that interpretation
|
|
161
120
|
// provably false.
|
|
162
121
|
if (!elsewhere) continue;
|
|
@@ -170,7 +129,7 @@ export function verify(app: { fronds: readonly FrondDescriptor[] }): Violation[]
|
|
|
170
129
|
message:
|
|
171
130
|
`'${param.name}' is typed ${param.type.name}, and the collector that produces one ` +
|
|
172
131
|
`is declared in frond '${elsewhere}'. A binding plan only sees its own frond's ` +
|
|
173
|
-
`collectors, so the preliminary
|
|
132
|
+
`collectors, so the preliminary input interpretation is invalid. Fougere refuses ` +
|
|
174
133
|
`the operation before it can receive what the caller sent. ` +
|
|
175
134
|
`Move the collector into '${frond.name}'.`,
|
|
176
135
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RouteKind } from './RouteAddress.js';
|
|
2
|
+
|
|
3
|
+
/** What crosses the door. */
|
|
4
|
+
export interface CallRecord {
|
|
5
|
+
/** Monotonic, and the whole cursor protocol: a reader asks for what is above its own. */
|
|
6
|
+
seq: number;
|
|
7
|
+
frond?: string;
|
|
8
|
+
entity: string;
|
|
9
|
+
operation: string;
|
|
10
|
+
surface?: string;
|
|
11
|
+
/** Known at `resolved`, so absent on a call that never found a route. */
|
|
12
|
+
route?: RouteKind;
|
|
13
|
+
/** The traceparent the invocation carried, when one did. */
|
|
14
|
+
trace?: string;
|
|
15
|
+
/** The peer that established this call, when one did. */
|
|
16
|
+
caller?: string;
|
|
17
|
+
startedAt: number;
|
|
18
|
+
/** Known at `settled`. */
|
|
19
|
+
ms?: number;
|
|
20
|
+
verdict: 'running' | 'ok' | 'failed';
|
|
21
|
+
refusal?: { code?: string; message: string };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** One page of the ring. */
|
|
25
|
+
export interface CallPage {
|
|
26
|
+
calls: CallRecord[];
|
|
27
|
+
cursor: number;
|
|
28
|
+
inFlight: number;
|
|
29
|
+
dropped: number;
|
|
30
|
+
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
export interface InvocationContext {
|
|
2
2
|
params: Record<string, unknown>;
|
|
3
3
|
query: Record<string, unknown>;
|
|
4
|
-
|
|
4
|
+
input: unknown;
|
|
5
5
|
state: Record<string, unknown>;
|
|
6
6
|
trace?: string;
|
|
7
7
|
identity?: string;
|
|
8
8
|
caller?: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export type
|
|
11
|
+
export type PartialInvocation = Partial<InvocationContext>;
|
|
12
12
|
|
|
13
|
+
/** Freezes plain data deeply, and leaves a class instance alone — a `Date` is not a record. */
|
|
13
14
|
function canonicalValue(value: unknown): unknown {
|
|
14
15
|
if (value === null || value === undefined || typeof value !== 'object') return value;
|
|
15
16
|
if (Array.isArray(value)) return Object.freeze(value.map(canonicalValue));
|
|
@@ -19,6 +20,7 @@ function canonicalValue(value: unknown): unknown {
|
|
|
19
20
|
return canonicalRecord(value);
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
/** Drops the keys set to `undefined`, so an input and its JSON round-trip agree. */
|
|
22
24
|
function canonicalRecord(value: unknown): Record<string, unknown> {
|
|
23
25
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return Object.freeze({});
|
|
24
26
|
|
|
@@ -33,33 +35,37 @@ function canonicalRecord(value: unknown): Record<string, unknown> {
|
|
|
33
35
|
export class Invocation implements InvocationContext {
|
|
34
36
|
readonly params: Record<string, unknown>;
|
|
35
37
|
readonly query: Record<string, unknown>;
|
|
36
|
-
readonly
|
|
38
|
+
readonly input: unknown;
|
|
37
39
|
readonly state: Record<string, unknown>;
|
|
38
40
|
readonly trace?: string;
|
|
39
41
|
readonly identity?: string;
|
|
40
42
|
readonly caller?: string;
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
44
|
+
/** Gives every entry and every transport the same seven-member value, frozen. */
|
|
45
|
+
private constructor(context: PartialInvocation) {
|
|
46
|
+
this.params = canonicalRecord(context.params);
|
|
47
|
+
this.query = canonicalRecord(context.query);
|
|
48
|
+
this.input = canonicalValue(context.input);
|
|
46
49
|
// State is host-owned and may still be enriched by existing middlewares. Moving it
|
|
47
50
|
// to immutable lifecycle context is a separate migration.
|
|
48
|
-
this.state =
|
|
49
|
-
if (
|
|
50
|
-
if (
|
|
51
|
-
if (
|
|
51
|
+
this.state = context.state ?? {};
|
|
52
|
+
if (context.trace !== undefined) this.trace = context.trace;
|
|
53
|
+
if (context.identity !== undefined) this.identity = context.identity;
|
|
54
|
+
if (context.caller !== undefined) this.caller = context.caller;
|
|
52
55
|
Object.freeze(this);
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
/** Takes a raw object or an invocation, so a caller never has to know which it holds. */
|
|
59
|
+
static from(context?: PartialInvocation): Invocation {
|
|
60
|
+
return context instanceof Invocation ? context : new Invocation(context ?? {});
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
/** Replaces the input — how the façade hands on the value it parsed. */
|
|
64
|
+
withInput(input: unknown): Invocation {
|
|
65
|
+
return new Invocation({ ...this, input });
|
|
61
66
|
}
|
|
62
67
|
|
|
68
|
+
/** Replaces the host-owned state, which a middleware enriches before the handler runs. */
|
|
63
69
|
withState(state: Record<string, unknown>): Invocation {
|
|
64
70
|
return new Invocation({ ...this, state });
|
|
65
71
|
}
|
|
@@ -67,6 +73,7 @@ export class Invocation implements InvocationContext {
|
|
|
67
73
|
|
|
68
74
|
export const EMPTY_INVOCATION = Invocation.from();
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
/** Names the same gesture as `Invocation.from` for callers that read better this way. */
|
|
77
|
+
export function canonicalInvocation(context?: PartialInvocation): Invocation {
|
|
78
|
+
return Invocation.from(context);
|
|
72
79
|
}
|
|
@@ -7,11 +7,13 @@ export interface RouteAddressInput {
|
|
|
7
7
|
surface?: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/** Refuses an empty segment, so no address can be built that nothing can serve. */
|
|
10
11
|
function required(value: string, name: string): string {
|
|
11
12
|
if (value.trim().length === 0) throw new TypeError(`Route ${name} cannot be empty`);
|
|
12
13
|
return value;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
/** Applies the same refusal to a segment that may be absent, but not blank. */
|
|
15
17
|
function optional(value: string | undefined, name: string): string | undefined {
|
|
16
18
|
return value === undefined ? undefined : required(value, name);
|
|
17
19
|
}
|
|
@@ -22,6 +24,7 @@ export class RouteAddress {
|
|
|
22
24
|
readonly operation: string;
|
|
23
25
|
readonly surface?: string;
|
|
24
26
|
|
|
27
|
+
/** Names one callable operation, and freezes it so a registry key cannot drift. */
|
|
25
28
|
constructor(input: RouteAddressInput) {
|
|
26
29
|
this.entity = required(input.entity, 'entity');
|
|
27
30
|
this.operation = required(input.operation, 'operation');
|
|
@@ -29,19 +32,23 @@ export class RouteAddress {
|
|
|
29
32
|
Object.freeze(this);
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
/** Serializes the three segments so a route can be looked up in a `Map`. */
|
|
32
36
|
key(): string {
|
|
33
37
|
return JSON.stringify([this.surface ?? null, this.entity, this.operation]);
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
/** Compares two addresses by their key, so `surface` counts as much as the operation. */
|
|
36
41
|
equals(other: RouteAddress): boolean {
|
|
37
42
|
return this.key() === other.key();
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
/** Writes the address the way a log and an error message name it. */
|
|
40
46
|
toString(): string {
|
|
41
47
|
const audience = this.surface ? `${this.surface}/` : '';
|
|
42
48
|
return `${audience}${this.entity}.${this.operation}`;
|
|
43
49
|
}
|
|
44
50
|
|
|
51
|
+
/** Sends the address over the wire without `surface: undefined` riding along. */
|
|
45
52
|
toJSON(): RouteAddressInput {
|
|
46
53
|
return {
|
|
47
54
|
entity: this.entity,
|
package/src/wire/binding.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Where each parameter of an operation gets its value — decided once at boot from the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* The branches are ORDERED and each states why it sits where it does; the list used to
|
|
6
|
-
* be repeated here too, and it had already lost `Fact` — the one whose position is
|
|
7
|
-
* load-bearing, since the fall-through would otherwise hand it the caller's body.
|
|
2
|
+
* Where each parameter of an operation gets its value — decided once at boot from the parsed
|
|
3
|
+
* signature, replayed per call by `resolveArgs`.
|
|
8
4
|
*/
|
|
9
5
|
import type { Param } from './signature.js';
|
|
10
6
|
import { lowerFirst } from '@fougere/schema';
|
|
@@ -13,17 +9,10 @@ import { lowerFirst } from '@fougere/schema';
|
|
|
13
9
|
|
|
14
10
|
type ParamSource =
|
|
15
11
|
| { kind: 'collector'; typeName: string }
|
|
16
|
-
/**
|
|
17
|
-
* `Fact<PostPublished>` — something that happened, not something a caller typed.
|
|
18
|
-
*
|
|
19
|
-
* It resolves from the body exactly like `body` does, and that is deliberate: an
|
|
20
|
-
* emission and a direct call ARE the same call, so a subscriber cannot tell them apart
|
|
21
|
-
* and does not need to. The branch exists so the PLAN says what this parameter is —
|
|
22
|
-
* that sentence is what makes the subscriber index readable without reparsing types.
|
|
23
|
-
*/
|
|
12
|
+
/** `Fact<PostPublished>` — something that happened, not something a caller typed. */
|
|
24
13
|
| { kind: 'fact'; factName: string }
|
|
25
14
|
| { kind: 'param'; name: string; coerce?: 'number' | 'boolean' }
|
|
26
|
-
| { kind: '
|
|
15
|
+
| { kind: 'input' }
|
|
27
16
|
| { kind: 'context' }
|
|
28
17
|
/** The whole query bag, for an op whose argument IS the options (list). */
|
|
29
18
|
| { kind: 'query' };
|
|
@@ -48,12 +37,7 @@ function coercionFor(typeName: string): 'number' | 'boolean' | undefined {
|
|
|
48
37
|
|
|
49
38
|
// ── Compute ───────────────────────────────────
|
|
50
39
|
|
|
51
|
-
/**
|
|
52
|
-
* Build a BindingPlan from parsed method params.
|
|
53
|
-
*
|
|
54
|
-
* @param params - Parsed parameter list from AST
|
|
55
|
-
* @param collectorTypeNames - Registration keys of the types a Collector answers for
|
|
56
|
-
*/
|
|
40
|
+
/** Build a BindingPlan from parsed method params. */
|
|
57
41
|
export function computeBindingPlan(
|
|
58
42
|
params: Param[],
|
|
59
43
|
collectorTypeNames: Set<string>,
|
|
@@ -62,11 +46,11 @@ export function computeBindingPlan(
|
|
|
62
46
|
const typeName = param.type.name;
|
|
63
47
|
// `lowerFirst`, never `toLowerCase()`: the collector set is keyed the way the
|
|
64
48
|
// scan spells it, and the two agree on one word only — `AuthorUser` looked up as
|
|
65
|
-
// `authoruser` missed `authorUser` and fell through to branch 4, the request
|
|
49
|
+
// `authoruser` missed `authorUser` and fell through to branch 4, the request input.
|
|
66
50
|
const typeKey = lowerFirst(typeName);
|
|
67
51
|
|
|
68
52
|
// 0. Fact — `Fact<X>` names itself, so nothing has to be known in advance. It comes
|
|
69
|
-
// FIRST because branch 4 would otherwise hand it the caller's
|
|
53
|
+
// FIRST because branch 4 would otherwise hand it the caller's input under the name
|
|
70
54
|
// of something that happened.
|
|
71
55
|
const factOf = param.type.name === 'Fact' ? param.type.generics?.[0]?.name : undefined;
|
|
72
56
|
if (factOf) {
|
|
@@ -108,10 +92,10 @@ export function computeBindingPlan(
|
|
|
108
92
|
};
|
|
109
93
|
}
|
|
110
94
|
|
|
111
|
-
// 4. Everything else —
|
|
95
|
+
// 4. Everything else — input
|
|
112
96
|
return {
|
|
113
97
|
name: param.name,
|
|
114
|
-
source: { kind: '
|
|
98
|
+
source: { kind: 'input' as const },
|
|
115
99
|
optional: param.optional ?? false,
|
|
116
100
|
};
|
|
117
101
|
});
|