@fougere/core 0.6.0-alpha.0 → 0.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/boot/Emissions.d.ts +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 +3 -15
- 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 +3 -10
- package/dist/boot/boot.js.map +1 -1
- package/dist/boot/bootstrap.d.ts.map +1 -1
- package/dist/boot/bootstrap.js +61 -127
- 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 +20 -54
- 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 +28 -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 +13 -31
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +10 -26
- package/dist/contract.js.map +1 -1
- package/dist/crypto/encoding.d.ts +2 -15
- package/dist/crypto/encoding.d.ts.map +1 -1
- package/dist/crypto/encoding.js +2 -15
- package/dist/crypto/encoding.js.map +1 -1
- package/dist/crypto/node.d.ts.map +1 -1
- package/dist/crypto/node.js +1 -7
- package/dist/crypto/node.js.map +1 -1
- package/dist/crypto/port.d.ts +2 -18
- package/dist/crypto/port.d.ts.map +1 -1
- package/dist/crypto/port.js +1 -17
- package/dist/crypto/port.js.map +1 -1
- package/dist/crypto/webcrypto.d.ts.map +1 -1
- package/dist/crypto/webcrypto.js +1 -12
- package/dist/crypto/webcrypto.js.map +1 -1
- package/dist/declare.d.ts +6 -36
- package/dist/declare.d.ts.map +1 -1
- package/dist/declare.js +4 -29
- 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 +14 -63
- package/dist/descriptor/frond.d.ts.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 +8 -7
- package/dist/dispatch/StorageGuard.d.ts.map +1 -1
- package/dist/dispatch/StorageGuard.js +61 -18
- 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/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 +4 -38
- 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 +28 -127
- package/dist/scan/scanner.js.map +1 -1
- package/dist/scan/statement.d.ts.map +1 -1
- package/dist/scan/statement.js +4 -30
- package/dist/scan/statement.js.map +1 -1
- package/dist/source.d.ts +41 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +10 -0
- package/dist/source.js.map +1 -0
- package/dist/storage.d.ts +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 +146 -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/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 +3 -15
- package/src/boot/auth.ts +2 -12
- package/src/boot/boot.ts +5 -20
- package/src/boot/bootstrap.ts +69 -136
- package/src/boot/card.ts +4 -33
- package/src/boot/frame.ts +28 -62
- 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 +28 -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 +15 -39
- package/src/crypto/encoding.ts +2 -15
- package/src/crypto/node.ts +1 -7
- package/src/crypto/port.ts +2 -18
- package/src/crypto/webcrypto.ts +1 -12
- package/src/declare.ts +8 -39
- package/src/define.ts +2 -3
- package/src/descriptor/Fronds.ts +6 -31
- package/src/descriptor/frond.ts +14 -63
- 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 +70 -18
- 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/conventions.ts +6 -40
- package/src/scan/emit.ts +4 -38
- package/src/scan/handler-parser.ts +27 -96
- package/src/scan/result.ts +3 -16
- package/src/scan/scanner.ts +27 -126
- package/src/scan/statement.ts +4 -30
- package/src/source.ts +44 -0
- package/src/storage.ts +14 -234
- package/src/store.ts +152 -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
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The operation model after every declaration and convention has been resolved.
|
|
3
|
-
*
|
|
4
|
-
* The scanner produces evidence. This module turns that evidence into the one table
|
|
5
|
-
* boot, check, explain and protocol projections consume. It is deliberately pure: no
|
|
6
|
-
* container, filesystem, migration or handler construction is involved.
|
|
7
|
-
*/
|
|
1
|
+
/** The operation model after every declaration and convention has been resolved. */
|
|
8
2
|
import { lowerFirst, type SchemaView } from '@fougere/schema';
|
|
9
3
|
import { statementDrift } from './boot/statement-drift.js';
|
|
10
4
|
import { computeBindingPlan, type BindingPlan } from './wire/binding.js';
|
|
@@ -232,7 +226,7 @@ export function resolveEffectiveOperations(
|
|
|
232
226
|
resolutionDiagnostics,
|
|
233
227
|
)) continue;
|
|
234
228
|
|
|
235
|
-
// A fact is
|
|
229
|
+
// A fact is validated by the entity it names. This used to be patched into the
|
|
236
230
|
// facade after resolution, leaving check/explain with a different input.
|
|
237
231
|
let input = contract.input;
|
|
238
232
|
if (!input) {
|
|
@@ -326,9 +320,9 @@ export function resolveEffectiveOperations(
|
|
|
326
320
|
function groupedCollectors(collectors: readonly CollectorEntry[]): Map<string, CollectorEntry[]> {
|
|
327
321
|
const grouped = new Map<string, CollectorEntry[]>();
|
|
328
322
|
for (const collector of collectors) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
grouped.set(collector.typeName,
|
|
323
|
+
const sameName = grouped.get(collector.typeName) ?? [];
|
|
324
|
+
sameName.push(collector);
|
|
325
|
+
grouped.set(collector.typeName, sameName);
|
|
332
326
|
}
|
|
333
327
|
return grouped;
|
|
334
328
|
}
|
|
@@ -359,9 +353,9 @@ function normalizeBinding(
|
|
|
359
353
|
// Array order is never allowed to become semantic authority.
|
|
360
354
|
const byName = new Map<string, Binding[]>();
|
|
361
355
|
for (const binding of contract.binding) {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
byName.set(binding.name,
|
|
356
|
+
const sameName = byName.get(binding.name) ?? [];
|
|
357
|
+
sameName.push(binding);
|
|
358
|
+
byName.set(binding.name, sameName);
|
|
365
359
|
}
|
|
366
360
|
const expected = new Set(params.map((param) => param.name));
|
|
367
361
|
const invalid = params.filter((param) => (byName.get(param.name)?.length ?? 0) !== 1);
|
|
@@ -403,14 +397,14 @@ function validateProvenance(
|
|
|
403
397
|
const ambiguousInput = diagnostics.some((diagnostic) =>
|
|
404
398
|
diagnostic.code === 'input-contract-ambiguous'
|
|
405
399
|
&& diagnostic.subject === `${handler.ctor.name}.${name}`);
|
|
406
|
-
const
|
|
400
|
+
const fromInput = parameters.filter((parameter) => parameter.binding.source.kind === 'input');
|
|
407
401
|
const inferredBody = new Set<EffectiveParameter>();
|
|
408
402
|
|
|
409
403
|
if (!explicitBinding && !ambiguousInput && contract.input) {
|
|
410
|
-
if (
|
|
411
|
-
inferredBody.add(
|
|
412
|
-
} else if (
|
|
413
|
-
const matches =
|
|
404
|
+
if (fromInput.length === 1) {
|
|
405
|
+
inferredBody.add(fromInput[0]!);
|
|
406
|
+
} else if (fromInput.length > 1) {
|
|
407
|
+
const matches = fromInput.filter((parameter) =>
|
|
414
408
|
schemaMatches(contract.input!, contract.signature?.params[parameter.position]?.type));
|
|
415
409
|
if (matches.length > 1) {
|
|
416
410
|
diagnostics.push({
|
|
@@ -419,7 +413,7 @@ function validateProvenance(
|
|
|
419
413
|
filePath: handler.filePath,
|
|
420
414
|
frond: frond.name,
|
|
421
415
|
subject: `${handler.ctor.name}.${name}`,
|
|
422
|
-
message: `Cannot resolve which parameter of ${handler.ctor.name}.${name} receives the
|
|
416
|
+
message: `Cannot resolve which parameter of ${handler.ctor.name}.${name} receives the input: `
|
|
423
417
|
+ `${matches.map((parameter) => `${parameter.name}: ${parameter.type ?? 'unknown'}`).join('; ')} `
|
|
424
418
|
+ 'all match the resolved input contract. Declare an explicit binding plan.',
|
|
425
419
|
});
|
|
@@ -430,9 +424,9 @@ function validateProvenance(
|
|
|
430
424
|
}
|
|
431
425
|
|
|
432
426
|
// A type written with an inline object literal names nothing a collector can register
|
|
433
|
-
// under, so the parameter IS the
|
|
427
|
+
// under, so the parameter IS the input. Only a NAMED type can be the wrong-frond
|
|
434
428
|
// substitution the refusal below exists for.
|
|
435
|
-
for (const parameter of
|
|
429
|
+
for (const parameter of fromInput) {
|
|
436
430
|
if (structural(contract.signature?.params[parameter.position]?.type)) inferredBody.add(parameter);
|
|
437
431
|
}
|
|
438
432
|
|
|
@@ -455,7 +449,7 @@ function validateProvenance(
|
|
|
455
449
|
}
|
|
456
450
|
continue;
|
|
457
451
|
}
|
|
458
|
-
if (source.kind !== '
|
|
452
|
+
if (source.kind !== 'input' || explicitBinding || ambiguousInput) continue;
|
|
459
453
|
|
|
460
454
|
const typeName = lowerFirst(contract.signature?.params[parameter.position]?.type.name ?? '');
|
|
461
455
|
const elsewhere = fronds.flatMap((candidate) => candidate === frond
|
|
@@ -463,12 +457,12 @@ function validateProvenance(
|
|
|
463
457
|
: candidate.collectors.filter((collector) => collector.typeName === typeName));
|
|
464
458
|
if (elsewhere.length > 0) {
|
|
465
459
|
// verify() supplies the more complete topology diagnostic; do not also call this
|
|
466
|
-
// an unknown
|
|
460
|
+
// an unknown input.
|
|
467
461
|
continue;
|
|
468
462
|
}
|
|
469
463
|
|
|
470
|
-
// An inferred
|
|
471
|
-
//
|
|
464
|
+
// An inferred input must be backed by exactly one resolved interpretation. With one
|
|
465
|
+
// input, the value itself is sufficient evidence; with several, exactly one type may
|
|
472
466
|
// match. Explicit plans are authoritative because they state every provenance.
|
|
473
467
|
const recognized = explicitBinding || inferredBody.has(parameter);
|
|
474
468
|
if (recognized) continue;
|
|
@@ -596,30 +590,7 @@ function uniqueDiagnostics(diagnostics: readonly ScanDiagnostic[]): ScanDiagnost
|
|
|
596
590
|
});
|
|
597
591
|
}
|
|
598
592
|
|
|
599
|
-
/**
|
|
600
|
-
* The contract of every operation a handler serves — the three producers, merged once.
|
|
601
|
-
*
|
|
602
|
-
* This lived inline in `buildFacade`, which made the façade the only thing that could
|
|
603
|
-
* answer "what is this op's contract, really?". Anything else asking — a checker, a
|
|
604
|
-
* client generator, a descriptor — had to redo the merge, and a second opinion that
|
|
605
|
-
* drifts reports nothing wrong while looking at the wrong thing.
|
|
606
|
-
*
|
|
607
|
-
* The order is a claim about authority, not a convenience:
|
|
608
|
-
*
|
|
609
|
-
* 1. a prefab DECLARES what it built (`Crud(E).__ops`) — runtime, so it survives a
|
|
610
|
-
* scan that resolved nothing;
|
|
611
|
-
* 2. the scan DERIVES from source — a method written in this very file is the
|
|
612
|
-
* author's own word and beats everything; a method it merely READ on a base
|
|
613
|
-
* class is a guess about someone else's code, and yields to that code's own
|
|
614
|
-
* declaration;
|
|
615
|
-
* 3. `frond.config.ts` STATES — the most explicit statement, made by whoever
|
|
616
|
-
* assembles the app, and the only answer for an op inherited from an installed
|
|
617
|
-
* base class the workspace-only scan cannot see. Merged per key, so stating a
|
|
618
|
-
* `binding` alone does not erase an `input` the scan found.
|
|
619
|
-
*
|
|
620
|
-
* Pure: no container, no instance, no disk. The binding plan is resolved here, so
|
|
621
|
-
* nothing downstream ever meets an AST.
|
|
622
|
-
*/
|
|
593
|
+
/** The contract of every operation a handler serves — the three producers, merged once. */
|
|
623
594
|
export function resolveContracts(
|
|
624
595
|
handler: Pick<HandlerEntry, 'ctor' | 'operations'>,
|
|
625
596
|
overrides: FrondDescriptor['operationsOverrides'],
|
package/src/emit.ts
CHANGED
|
@@ -1,61 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Announcing a fact — the half of the topology `remotes:` never covered.
|
|
3
|
-
*
|
|
4
|
-
* Every other call in Fougere names **one** recipient: `remotes` names one address per
|
|
5
|
-
* frond, `Facade<T>` resolves one door. `Emit<T>` names a **subject** instead, and the
|
|
6
|
-
* number of readers is not the emitter's business.
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* constructor(private published: Emit<PostPublished>) {}
|
|
10
|
-
* await this.published({ id, title }); // I say it happened. I do not know who cares.
|
|
11
|
-
*
|
|
12
|
-
* async reindex(fact: Fact<PostPublished>) {} // any handler, any frond. Nothing to register.
|
|
13
|
-
* ```
|
|
14
|
-
*
|
|
15
|
-
* **It is a resolver, not a channel.** A bus moves messages — it has a queue, an envelope
|
|
16
|
-
* format, a delivery semantic. This has none of that: it answers *who*, then hands over to
|
|
17
|
-
* the call path that already exists. It is `resolve` returning N things instead of one.
|
|
18
|
-
* That is also why temporal decoupling stays out of reach: a resolver holds nothing. The
|
|
19
|
-
* day at-least-once is wanted, a real channel goes UNDER this, in the transport — the
|
|
20
|
-
* dispatch line becomes a publish and a consumer calls the same door on the far side.
|
|
21
|
-
*/
|
|
1
|
+
/** Announcing a fact — the half of the topology `remotes:` never covered. */
|
|
22
2
|
import { lowerFirst } from '@fougere/schema';
|
|
23
3
|
|
|
24
|
-
/**
|
|
25
|
-
* What an emitter injects. Resolved by type, like `Storage<Post>` and `Facade<T>`.
|
|
26
|
-
*
|
|
27
|
-
* The returned promise settles when the fact has been **dispatched**, never when it has
|
|
28
|
-
* been handled: a subscriber's failure is its own. The `EventBus` this replaces did
|
|
29
|
-
* `await Promise.all(handlers)` and handed their rejections back, which made a publication
|
|
30
|
-
* hostage to its own indexer.
|
|
31
|
-
*/
|
|
4
|
+
/** What an emitter injects. */
|
|
32
5
|
export type Emit<T> = (fact: T) => Promise<void>;
|
|
33
6
|
|
|
34
|
-
/**
|
|
35
|
-
* What a subscriber accepts — and what it PROMISES about itself.
|
|
36
|
-
*
|
|
37
|
-
* Not merely "I subscribe". Push is the strict mode and pull is a special case of it: an
|
|
38
|
-
* op written for push is correct when called directly, the reverse is false. So this
|
|
39
|
-
* wrapper commits the operation to three things its author must honour, because no type
|
|
40
|
-
* can check them:
|
|
41
|
-
*
|
|
42
|
-
* 1. **replayable** — delivery is at-least-once the day a broker sits underneath;
|
|
43
|
-
* 2. **no reader for its return** — nobody receives what it hands back;
|
|
44
|
-
* 3. **owner of its failures** — they reach a log, never the emitter.
|
|
45
|
-
*
|
|
46
|
-
* It is the identity at runtime. The scan reads the written name, which is the whole
|
|
47
|
-
* mechanism: `binding.ts` sees `Fact<X>` and binds the parameter as a fact instead of
|
|
48
|
-
* letting it fall through to "everything else — body".
|
|
49
|
-
*/
|
|
7
|
+
/** What a subscriber accepts — and what it PROMISES about itself. */
|
|
50
8
|
export type Fact<T> = T;
|
|
51
9
|
|
|
52
|
-
/**
|
|
53
|
-
* The container key of an emission — THE one place that spells the format.
|
|
54
|
-
*
|
|
55
|
-
* Its dual is right below, because the boot reads the fact back out of a handler's `deps`
|
|
56
|
-
* to know which emissions to register. A key and the way to undo it belong together: the
|
|
57
|
-
* pair that is split is the pair that drifts.
|
|
58
|
-
*/
|
|
10
|
+
/** The container key of an emission — THE one place that spells the format. */
|
|
59
11
|
export function emitKeyOf(fact: string): string {
|
|
60
12
|
return `${lowerFirst(fact)}Emit`;
|
|
61
13
|
}
|
|
@@ -69,17 +21,7 @@ export function factOfEmitKey(key: string): string | undefined {
|
|
|
69
21
|
: undefined;
|
|
70
22
|
}
|
|
71
23
|
|
|
72
|
-
/**
|
|
73
|
-
* What a set of handlers ANNOUNCES — `Emit<T>` read back out of their dependencies.
|
|
74
|
-
*
|
|
75
|
-
* Two readers, which is exactly why it is a function and not a line: the boot registers one
|
|
76
|
-
* emission value per name, and the identity card publishes the same set. Spelled twice they
|
|
77
|
-
* would drift the day an emission stops being a constructor dependency.
|
|
78
|
-
*
|
|
79
|
-
* The dual — what a handler ACCEPTS — is not here, because it is not read the same way: a
|
|
80
|
-
* `Fact<T>` parameter is a fact about one operation, and `computeBindingPlan` has already
|
|
81
|
-
* written it into the plan (`app.listensTo()`).
|
|
82
|
-
*/
|
|
24
|
+
/** What a set of handlers ANNOUNCES — `Emit<T>` read back out of their dependencies. */
|
|
83
25
|
export function factsAnnouncedBy(handlers: readonly { deps: readonly string[] }[]): string[] {
|
|
84
26
|
return [...new Set(
|
|
85
27
|
handlers
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Call } from '../wire/call.js';
|
|
2
|
+
import type { PartialInvocation } from '../wire/Invocation.js';
|
|
3
|
+
import { RouteAddress } from '../wire/RouteAddress.js';
|
|
4
|
+
import type { DispatchPort } from '../dispatch/DispatchPort.js';
|
|
5
|
+
|
|
6
|
+
type Operation = (...args: any[]) => unknown;
|
|
7
|
+
|
|
8
|
+
/** Facade for a contract whose operation names are only known at discovery. */
|
|
9
|
+
export function dynamicOperations(operation: (name: string) => Operation): Record<string, Operation> {
|
|
10
|
+
const isOperationName = (name: string | symbol): name is string =>
|
|
11
|
+
typeof name === 'string'
|
|
12
|
+
&& name !== 'then'
|
|
13
|
+
&& name !== 'toJSON'
|
|
14
|
+
&& !Object.hasOwn(Object.prototype, name);
|
|
15
|
+
|
|
16
|
+
return new Proxy({}, {
|
|
17
|
+
get: (_target, name) => (isOperationName(name) ? operation(name) : undefined),
|
|
18
|
+
has: (_target, name) => isOperationName(name),
|
|
19
|
+
getOwnPropertyDescriptor: (_target, name) => (isOperationName(name)
|
|
20
|
+
? { value: operation(name), writable: false, enumerable: true, configurable: true }
|
|
21
|
+
: undefined),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Turns facade method calls into canonical dispatches. */
|
|
26
|
+
export function facadeOperations(
|
|
27
|
+
dispatcher: DispatchPort,
|
|
28
|
+
entity: string,
|
|
29
|
+
operationNames?: Iterable<string>,
|
|
30
|
+
surface?: string,
|
|
31
|
+
): Record<string, Operation> {
|
|
32
|
+
const operation = (name: string): Operation => (invocation) => dispatcher.dispatch(new Call(
|
|
33
|
+
new RouteAddress({
|
|
34
|
+
entity,
|
|
35
|
+
operation: name,
|
|
36
|
+
...(surface !== undefined ? { surface } : {}),
|
|
37
|
+
}),
|
|
38
|
+
invocation,
|
|
39
|
+
));
|
|
40
|
+
|
|
41
|
+
return operationNames
|
|
42
|
+
? Object.fromEntries([...operationNames].map((name) => [name, operation(name)]))
|
|
43
|
+
: dynamicOperations(operation);
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Call } from '../wire/call.js';
|
|
2
|
+
import { RouteAddress } from '../wire/RouteAddress.js';
|
|
3
|
+
import type { DispatchPort } from '../dispatch/DispatchPort.js';
|
|
4
|
+
import type { Transport } from '../wire/call.js';
|
|
5
|
+
|
|
6
|
+
/** Adapts the historical transport signature to the canonical dispatch port. */
|
|
7
|
+
export function createTransportEntry(dispatcher: DispatchPort, surface?: string): Transport {
|
|
8
|
+
return (legacy, invocation) => dispatcher.dispatch(new Call(
|
|
9
|
+
new RouteAddress({
|
|
10
|
+
entity: legacy.entity,
|
|
11
|
+
operation: legacy.op,
|
|
12
|
+
...(surface !== undefined ? { surface } : {}),
|
|
13
|
+
}),
|
|
14
|
+
invocation,
|
|
15
|
+
));
|
|
16
|
+
}
|
package/src/frond-config.ts
CHANGED
|
@@ -5,45 +5,11 @@ import type { BindingPlan } from './wire/binding.js';
|
|
|
5
5
|
|
|
6
6
|
// ── Types ────────────────────────────────────────
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Per-operation override. Config takes precedence over conventions (isReadOp, facade lookup).
|
|
10
|
-
*
|
|
11
|
-
* Two families of keys, and they act at different depths:
|
|
12
|
-
*
|
|
13
|
-
* - **Resolution** (`kind`, `handler`, `method`) — intent and implementation, resolved
|
|
14
|
-
* once into core's `EffectiveOperation`; every local or remote door consumes it.
|
|
15
|
-
* - **Projection** (`graphql`) — protocol vocabulary, read only by that adapter.
|
|
16
|
-
* - **Contract** (`input`, `output`, `binding`) — what the op IS. Read by the façade,
|
|
17
|
-
* and this is the third producer of an {@link OperationContract}: a prefab DECLARES its
|
|
18
|
-
* ops (`Crud.__ops`), the scan DERIVES them from source, config STATES them outright.
|
|
19
|
-
* The façade cannot tell the three apart.
|
|
20
|
-
*
|
|
21
|
-
* Stating a contract here makes the scan optional rather than load-bearing. Two cases it
|
|
22
|
-
* answers that nothing else does:
|
|
23
|
-
* - a method inherited from an **installed** base class — the scan resolves nothing there
|
|
24
|
-
* (workspace-only heritage) and says nothing, so the op silently misses the façade;
|
|
25
|
-
* - an operation inherited from a declaration unavailable to the project's type checker.
|
|
26
|
-
*
|
|
27
|
-
* Config wins over both other producers — it is the most explicit statement, made by
|
|
28
|
-
* whoever assembles the app. Precedence: CLI > frond config > fougere config > scan >
|
|
29
|
-
* conventions.
|
|
30
|
-
*/
|
|
8
|
+
/** Per-operation override. */
|
|
31
9
|
export interface OperationOverride {
|
|
32
|
-
/**
|
|
33
|
-
* Force operation kind, over the naming convention (`isReadOp`).
|
|
34
|
-
*
|
|
35
|
-
* The convention reads the NAME, which is a weak signal — an app naming its reads in
|
|
36
|
-
* domain terms (`ofBook`, `roots`, `bySlug`) matches no prefix and every one of them is
|
|
37
|
-
* published as a mutation and a POST. This is the only place that fixes it.
|
|
38
|
-
*/
|
|
10
|
+
/** Force operation kind, over the naming convention (`isReadOp`). */
|
|
39
11
|
kind?: 'query' | 'command';
|
|
40
|
-
/**
|
|
41
|
-
* The GraphQL root field this op answers to. Defaults to the method name.
|
|
42
|
-
*
|
|
43
|
-
* A GraphQL root is flat, so two handlers naming a method `ofBook` claim one field and
|
|
44
|
-
* the build is refused, naming both. Nothing is renamed for you: the root vocabulary is
|
|
45
|
-
* the app's, and a derived name would move the day a distant frond gained an entity.
|
|
46
|
-
*/
|
|
12
|
+
/** The GraphQL root field this op answers to. */
|
|
47
13
|
graphql?: string;
|
|
48
14
|
/**
|
|
49
15
|
* Handler class to delegate to (overrides the default `{Entity}Handler` lookup).
|
|
@@ -52,22 +18,12 @@ export interface OperationOverride {
|
|
|
52
18
|
handler?: EntityConstructor;
|
|
53
19
|
/** Method name on `handler` (defaults to the operation name). */
|
|
54
20
|
method?: string;
|
|
55
|
-
/**
|
|
56
|
-
* CASL ability check (e.g. 'archive Post'). **Declared, not implemented** — no
|
|
57
|
-
* reader interprets it today, in any adapter. Kept as the named slot for the
|
|
58
|
-
* question rather than silently dropped, but do not rely on it: a config that
|
|
59
|
-
* states a policy is not enforced anywhere.
|
|
60
|
-
*
|
|
61
|
-
* Wiring it means adopting a rules engine, which is precisely what the design
|
|
62
|
-
* turns down: an identity-dependent right is judged INSIDE the operation
|
|
63
|
-
* (`publish` reads `post.authorId !== user.id`), and a door-dependent one is a
|
|
64
|
-
* surface. Neither needs a second vocabulary evaluated by a second engine.
|
|
65
|
-
*/
|
|
21
|
+
/** CASL ability check (e.g. */
|
|
66
22
|
policy?: string;
|
|
67
23
|
|
|
68
24
|
// ── The contract itself — see the note above ──
|
|
69
25
|
|
|
70
|
-
/** What
|
|
26
|
+
/** What validates the input. The view carries its own mode (`partial()` → patch). */
|
|
71
27
|
input?: SchemaView;
|
|
72
28
|
/**
|
|
73
29
|
* Where each argument is read from — states what the scan would otherwise derive
|
|
@@ -82,18 +38,7 @@ export interface OperationOverride {
|
|
|
82
38
|
export interface FrondConfig {
|
|
83
39
|
/** Class names exposed as the frond's public contract (all surfaces). */
|
|
84
40
|
expose?: string[];
|
|
85
|
-
/**
|
|
86
|
-
* The entities this frond may read ACROSS sources, by name.
|
|
87
|
-
*
|
|
88
|
-
* It is not a permission checked after the fact: the list IS the environment a
|
|
89
|
-
* cross-source query runs in — a source holding none of these is never opened, so
|
|
90
|
-
* its tables do not exist in that connection. `facadeFor` excludes an entity with no
|
|
91
|
-
* door on purpose ("it would publish the auth tables to anyone who asks"), and a SQL
|
|
92
|
-
* door at app scope would hand them over; this is what keeps it shut.
|
|
93
|
-
*
|
|
94
|
-
* Declaring it is what makes `Reads` injectable here. A frond that declares none
|
|
95
|
-
* asks for none, and nothing is attached on its behalf.
|
|
96
|
-
*/
|
|
41
|
+
/** The entities this frond may read ACROSS sources, by name. */
|
|
97
42
|
reads?: string[];
|
|
98
43
|
/** Per-surface entity lists. Overrides default deduction for each named surface. */
|
|
99
44
|
surfaces?: Record<string, string[]>;
|
|
@@ -105,15 +50,7 @@ export interface FrondConfig {
|
|
|
105
50
|
|
|
106
51
|
// ── Helper ───────────────────────────────────────
|
|
107
52
|
|
|
108
|
-
/**
|
|
109
|
-
* Define a frond configuration (typed identity helper).
|
|
110
|
-
*
|
|
111
|
-
* ```ts
|
|
112
|
-
* // fronds/auth/frond.config.ts
|
|
113
|
-
* import { defineFrond } from '@fougere/core'
|
|
114
|
-
* export default defineFrond({ expose: ['User', 'AuthHandler'] })
|
|
115
|
-
* ```
|
|
116
|
-
*/
|
|
53
|
+
/** Define a frond configuration (typed identity helper). */
|
|
117
54
|
export function defineFrond(config: FrondConfig): FrondConfig {
|
|
118
55
|
return config;
|
|
119
56
|
}
|
package/src/identity-keys.ts
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Making keys and issuing grants — the half of identity that runs at a DEPLOYMENT.
|
|
3
|
-
*
|
|
4
|
-
* It sits on the Node entry because it is the CLI speaking: `fougere keys` generates a
|
|
5
|
-
* pair, `fougere grant` binds a name to one, and both happen once, on a machine with a
|
|
6
|
-
* filesystem. Neither is reachable from a request path, so nothing here is on any hot
|
|
7
|
-
* path and `generateKeyPairSync` — the one gesture WebCrypto could not replace without
|
|
8
|
-
* changing what a key IS — never has to leave `node:crypto`.
|
|
9
|
-
*
|
|
10
|
-
* The verifying half is elsewhere (`identity.ts`) because it runs per call, everywhere.
|
|
11
|
-
*/
|
|
1
|
+
/** Making keys and issuing grants — the half of identity that runs at a DEPLOYMENT. */
|
|
12
2
|
import { createPrivateKey, createPublicKey, generateKeyPairSync, sign } from 'node:crypto';
|
|
13
3
|
import { b64url } from './crypto/encoding.js';
|
|
14
4
|
|
|
@@ -22,11 +12,8 @@ export function generateKeyPair(): { privateKey: string; publicKey: string } {
|
|
|
22
12
|
}
|
|
23
13
|
|
|
24
14
|
/**
|
|
25
|
-
* Bind a name to a public key, signed by the root — the whole of what a receiver
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* `ttlDays` bounds the damage of a leaked frond key without a revocation list:
|
|
29
|
-
* re-issuing is a deployment, which is the same gesture that leaked it.
|
|
15
|
+
* Bind a name to a public key, signed by the root — the whole of what a receiver needs to
|
|
16
|
+
* recognize a frond it has never seen.
|
|
30
17
|
*/
|
|
31
18
|
export function issueGrant(
|
|
32
19
|
rootPrivateKey: string,
|
package/src/identity.ts
CHANGED
|
@@ -1,35 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Who is calling — the proof, not the claim.
|
|
3
|
-
*
|
|
4
|
-
* `InvocationContext.state` is what a caller SAYS about itself, and a split receiver
|
|
5
|
-
* used to believe it: identity read straight off the wire, so a reader could post
|
|
6
|
-
* `{ state: { user: { role: 'admin' } } }` and be one. This module is what turns that
|
|
7
|
-
* sack into something a receiver establishes instead of accepts.
|
|
8
|
-
*
|
|
9
|
-
* Two signatures, one public key to distribute:
|
|
10
|
-
*
|
|
11
|
-
* GRANT the root says "this key is `blog`" — issued once, at deployment
|
|
12
|
-
* ENVELOPE `blog` says "here is my whole call" — signed per call
|
|
13
|
-
*
|
|
14
|
-
* The envelope binds the CALL and not only its state: address, params, query, a digest
|
|
15
|
-
* of the body. Signing the state alone proved WHO without proving WHAT, so anyone on the
|
|
16
|
-
* wire could replay a captured envelope against another operation for as long as it
|
|
17
|
-
* stayed valid — `post.list` re-sent as `post.delete`, same signature, still good.
|
|
18
|
-
*
|
|
19
|
-
* A receiver holds the root's public key and nothing else: it validates any frond it
|
|
20
|
-
* has never seen, which is what a per-caller list could not do. The private root key
|
|
21
|
-
* signs grants and never leaves the machine that issued them.
|
|
22
|
-
*
|
|
23
|
-
* Ed25519 and a JWS-shaped grant rather than X.509: node can PARSE a certificate but
|
|
24
|
-
* not ISSUE one, so a real chain would mean openssl or a library. The grant says the
|
|
25
|
-
* same thing — a name bound to a public key, signed by the root — with no dependency.
|
|
26
|
-
*
|
|
27
|
-
* The Ed25519 itself comes through `#crypto`, which has two realizations: `node:crypto`
|
|
28
|
-
* everywhere, WebCrypto under `workerd`. Everything here is therefore async — WebCrypto
|
|
29
|
-
* has no synchronous form — and a key is parsed ONCE, into a `Signer` or a `Verifier`,
|
|
30
|
-
* never per call. Making the keys and issuing grants happen at a deployment and live in
|
|
31
|
-
* `identity-keys.ts`, on the Node entry.
|
|
32
|
-
*/
|
|
1
|
+
/** Who is calling — the proof, not the claim. */
|
|
33
2
|
import { crypto } from '#crypto';
|
|
34
3
|
import type { PublicJwk, Signer, Verifier } from './crypto/port.js';
|
|
35
4
|
import { b64url, unb64url, bytesOf, textOf, unb64 } from './crypto/encoding.js';
|
|
@@ -50,13 +19,13 @@ export interface FrondIdentity {
|
|
|
50
19
|
grant: string;
|
|
51
20
|
}
|
|
52
21
|
|
|
53
|
-
/** The
|
|
54
|
-
async function digestOf(
|
|
22
|
+
/** The input's fingerprint. Absence and explicit null are different signed calls. */
|
|
23
|
+
async function digestOf(input: unknown): Promise<string> {
|
|
55
24
|
// The tag is outside the caller value, so no user object can collide with it. JSON's
|
|
56
25
|
// own omission rule still applies inside `value`, matching what crosses the wire.
|
|
57
|
-
const canonical =
|
|
26
|
+
const canonical = input === undefined
|
|
58
27
|
? { kind: 'undefined' }
|
|
59
|
-
: { kind: 'value', value:
|
|
28
|
+
: { kind: 'value', value: input };
|
|
60
29
|
return b64url(await crypto.sha256(bytesOf(JSON.stringify(canonical))));
|
|
61
30
|
}
|
|
62
31
|
|
|
@@ -67,7 +36,7 @@ async function boundTo(call: SignedCall) {
|
|
|
67
36
|
op: call.op,
|
|
68
37
|
params: call.params ?? {},
|
|
69
38
|
query: call.query ?? {},
|
|
70
|
-
|
|
39
|
+
input: await digestOf(call.input),
|
|
71
40
|
};
|
|
72
41
|
}
|
|
73
42
|
|
|
@@ -85,11 +54,7 @@ async function signJws(header: object, payload: object, signer: Signer): Promise
|
|
|
85
54
|
return `${signingInput}.${b64url(await signer.sign(bytesOf(signingInput)))}`;
|
|
86
55
|
}
|
|
87
56
|
|
|
88
|
-
/**
|
|
89
|
-
* The payload, once the signature holds. Throws rather than returning a falsy value:
|
|
90
|
-
* every caller here is deciding whether to admit a call, and an unverified payload
|
|
91
|
-
* must never be reachable by forgetting a check.
|
|
92
|
-
*/
|
|
57
|
+
/** The payload, once the signature holds. */
|
|
93
58
|
async function verifyJws(token: string, verifier: Verifier, what: string): Promise<Record<string, unknown>> {
|
|
94
59
|
const parts = token.split('.');
|
|
95
60
|
if (parts.length !== 3) throw new Error(`Malformed ${what}`);
|
|
@@ -111,13 +76,7 @@ function headerOf(token: string): Record<string, unknown> {
|
|
|
111
76
|
return JSON.parse(textOf(unb64url(encodedHeader))) as Record<string, unknown>;
|
|
112
77
|
}
|
|
113
78
|
|
|
114
|
-
/**
|
|
115
|
-
* Sign one call, whole: who is asking, what is asked, and on whose behalf.
|
|
116
|
-
*
|
|
117
|
-
* The private key is parsed on every call here, which is the convenience form. A process
|
|
118
|
-
* that signs in a request path builds its signer once — `identityFromEnv` does exactly
|
|
119
|
-
* that, and `sign` on the value it returns holds the parsed key.
|
|
120
|
-
*/
|
|
79
|
+
/** Sign one call, whole. */
|
|
121
80
|
export async function signEnvelope(identity: FrondIdentity, call: SignedCall): Promise<string> {
|
|
122
81
|
return sealWith(await crypto.signerOf(identity.privateKey), identity.grant, call);
|
|
123
82
|
}
|
|
@@ -133,11 +92,7 @@ async function sealWith(signer: Signer, grant: string, call: SignedCall): Promis
|
|
|
133
92
|
);
|
|
134
93
|
}
|
|
135
94
|
|
|
136
|
-
/**
|
|
137
|
-
* Establish the caller, or throw. Order matters: the grant is checked against the ROOT
|
|
138
|
-
* first, and only the key it carries verifies the envelope — reading the envelope's own
|
|
139
|
-
* claim of who it is before that would be believing the thing under examination.
|
|
140
|
-
*/
|
|
95
|
+
/** Establish the caller, or throw. */
|
|
141
96
|
export async function verifyEnvelope(token: string, rootPublicKey: string, presented: SignedCall): Promise<VerifiedCall> {
|
|
142
97
|
return openWith(await crypto.verifierOf(rootPublicKey), token, presented);
|
|
143
98
|
}
|
|
@@ -173,13 +128,7 @@ async function openWith(root: Verifier, token: string, presented: SignedCall): P
|
|
|
173
128
|
|
|
174
129
|
/** The two halves a boot needs, and the environment they come from. */
|
|
175
130
|
export interface CallIdentity {
|
|
176
|
-
/**
|
|
177
|
-
* Signs an outgoing call, whole. Absent when this process holds no key — it only answers.
|
|
178
|
-
*
|
|
179
|
-
* A promise because WebCrypto has no synchronous form. On Node the work stays
|
|
180
|
-
* synchronous inside and only the answer is wrapped: measured at 14.28 µs awaited
|
|
181
|
-
* against 14.30 µs called directly, while WebCrypto on the same curve costs 22.72.
|
|
182
|
-
*/
|
|
131
|
+
/** Signs an outgoing call, whole. */
|
|
183
132
|
sign?: (call: SignedCall) => Promise<string>;
|
|
184
133
|
/** Establishes an incoming caller, against the call that actually arrived. */
|
|
185
134
|
verify?: (identity: string, presented: SignedCall) => Promise<VerifiedCall>;
|
|
@@ -187,29 +136,12 @@ export interface CallIdentity {
|
|
|
187
136
|
requireIdentity: boolean;
|
|
188
137
|
}
|
|
189
138
|
|
|
190
|
-
/**
|
|
191
|
-
* A PEM, however the deployment chose to carry it.
|
|
192
|
-
*
|
|
193
|
-
* A PEM is multi-line and an environment variable that spans lines survives poorly —
|
|
194
|
-
* docker-compose, systemd and CI secret stores each mangle it differently — so
|
|
195
|
-
* `fougere keys` prints base64. Both forms are read here rather than one being decreed:
|
|
196
|
-
* a human pasting a real PEM is not making a mistake.
|
|
197
|
-
*/
|
|
139
|
+
/** A PEM, however the deployment chose to carry it. */
|
|
198
140
|
function pemOf(value: string): string {
|
|
199
141
|
return value.trimStart().startsWith('-----') ? value : textOf(unb64(value));
|
|
200
142
|
}
|
|
201
143
|
|
|
202
|
-
/**
|
|
203
|
-
* What the deployment injected, read once at boot.
|
|
204
|
-
*
|
|
205
|
-
* Three variables, no config key: a private key never belongs in a committed file, and
|
|
206
|
-
* `fougere keys` prints exactly these. A process may hold either half or both — a frond
|
|
207
|
-
* that only answers has no key, one that only calls trusts no root, one in the middle
|
|
208
|
-
* does both.
|
|
209
|
-
*
|
|
210
|
-
* Trusting a root IS asking to refuse: there is no separate flag, because a deployment
|
|
211
|
-
* that names an authority and then accepts unsigned calls has said two things at once.
|
|
212
|
-
*/
|
|
144
|
+
/** What the deployment injected, read once at boot. */
|
|
213
145
|
export async function identityFromEnv(env: Record<string, string | undefined> = envOfProcess()): Promise<CallIdentity> {
|
|
214
146
|
const root = env.FOUGERE_ROOT_KEY ? pemOf(env.FOUGERE_ROOT_KEY) : undefined;
|
|
215
147
|
const privateKey = env.FOUGERE_KEY ? pemOf(env.FOUGERE_KEY) : undefined;
|
package/src/imports.ts
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A frond reaching into another one by FILE PATH.
|
|
3
|
-
*
|
|
4
|
-
* `verify()` next door answers the same question — does this app survive a split? — from
|
|
5
|
-
* the MODEL: what a constructor asks for, what a parameter is typed. This one can only be
|
|
6
|
-
* answered from the source text, so it reads files and lives apart rather than making
|
|
7
|
-
* `verify` lose the sentence that says it reads none.
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* import User from '../../user/entities/User.js'; // these two folders are neighbours
|
|
11
|
-
* import User from '@fronds/user/entities/User'; // I depend on the frond named user
|
|
12
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
* Both resolve today, and that is exactly the trap: a frond declared in `remotes:` is
|
|
15
|
-
* still scanned, its code is still on this disk, so the relative form keeps working right
|
|
16
|
-
* up to the day the folder is not there — an extraction into its own repository, an image
|
|
17
|
-
* that copies one frond. Then it fails at build time, with a message about a file path
|
|
18
|
-
* that says nothing about the model.
|
|
19
|
-
*
|
|
20
|
-
* So a relative path across a boundary is not a bug. It is a **colocation constraint that
|
|
21
|
-
* nothing declares**: real, load-bearing, and invisible to the scan, to the identity card
|
|
22
|
-
* and to `remotes:`. The named form states the same dependency in terms the model can
|
|
23
|
-
* read — and it is the form `fougere sync` writes, so it survives the move.
|
|
24
|
-
*/
|
|
1
|
+
/** A frond reaching into another one by FILE PATH. */
|
|
25
2
|
import type ts from '@typescript/typescript6';
|
|
26
3
|
import { readdir, readFile } from 'node:fs/promises';
|
|
27
4
|
import { join, resolve, dirname, relative, isAbsolute } from 'node:path';
|
|
@@ -71,13 +48,7 @@ async function sourcesUnder(dir: string): Promise<string[]> {
|
|
|
71
48
|
return out;
|
|
72
49
|
}
|
|
73
50
|
|
|
74
|
-
/**
|
|
75
|
-
* Every relative import that resolves outside its own frond.
|
|
76
|
-
*
|
|
77
|
-
* `preProcessFile` rather than a regex or a full parse: it is TypeScript's own scanner for
|
|
78
|
-
* exactly this question, so `// import x from '../../other'` in a comment is not a finding
|
|
79
|
-
* and a specifier split across lines still is.
|
|
80
|
-
*/
|
|
51
|
+
/** Every relative import that resolves outside its own frond. */
|
|
81
52
|
export async function crossFrondImports(
|
|
82
53
|
fronds: readonly Pick<FrondDescriptor, 'name' | 'source'>[],
|
|
83
54
|
): Promise<CrossFrondImport[]> {
|