@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/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[]> {
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a consumer writes, and nothing else.
|
|
3
|
-
*
|
|
4
|
-
* `exports` publishes this barrel and `./contract`, so an import that is not here
|
|
5
|
-
* cannot be reached from outside the package at all — which is what makes this file
|
|
6
|
-
* the contract rather than a convenience. The machinery the boot uses to keep its own
|
|
7
|
-
* promises stays inside: container keys, the binding plan, the mixin's runtime
|
|
8
|
-
* accessors, the config merge. Measured on 2026-08-16, none of them had a single
|
|
9
|
-
* importer anywhere in the workspace.
|
|
10
|
-
*/
|
|
1
|
+
/** What a consumer writes, and nothing else. */
|
|
11
2
|
export { createApp } from './boot/bootstrap.js';
|
|
12
3
|
export { orderSeeds, runSeeds, seeding } from './boot/seed.js';
|
|
13
|
-
export { AppLifecycle,
|
|
4
|
+
export { AppLifecycle, migrating } from './boot/AppLifecycle.js';
|
|
14
5
|
export type { Extension } from './boot/AppLifecycle.js';
|
|
15
6
|
export { defineFougere } from './define.js';
|
|
16
7
|
export type { AdapterConfig, FougereConfig } from './config-loader.js';
|
|
@@ -24,17 +15,17 @@ export { Presenter } from './prefab/presenter.js';
|
|
|
24
15
|
export type { PresenterViews } from './prefab/presenter.js';
|
|
25
16
|
export { Collector } from './prefab/collector.js';
|
|
26
17
|
export { Repository, type RepositoryOf, type RepositoryConstructor, type AggregateOf, type AggregateConstructor } from './prefab/repository.js';
|
|
27
|
-
export { Invocation, canonicalInvocation, EMPTY_INVOCATION } from './
|
|
28
|
-
export type { InvocationContext,
|
|
29
|
-
export { Call } from './
|
|
30
|
-
export { RouteAddress } from './
|
|
31
|
-
export type { RouteAddressInput } from './
|
|
18
|
+
export { Invocation, canonicalInvocation, EMPTY_INVOCATION } from './wire/Invocation.js';
|
|
19
|
+
export type { InvocationContext, PartialInvocation } from './wire/Invocation.js';
|
|
20
|
+
export { Call } from './wire/call.js';
|
|
21
|
+
export { RouteAddress } from './wire/RouteAddress.js';
|
|
22
|
+
export type { RouteAddressInput } from './wire/RouteAddress.js';
|
|
32
23
|
export { DispatchLifecycle } from './dispatch/DispatchLifecycle.js';
|
|
33
24
|
export { Dispatcher } from './dispatch/Dispatcher.js';
|
|
34
25
|
// The class and not only its type: an observer RECEIVES these, so a package that folds
|
|
35
26
|
// them — or a test of one — has to be able to make one through the door.
|
|
36
27
|
export { DispatchEvent } from './dispatch/DispatchEvent.js';
|
|
37
|
-
export type { CallPage, CallRecord } from './
|
|
28
|
+
export type { CallPage, CallRecord } from './wire/CallLog.js';
|
|
38
29
|
export { driftOf, agrees, explain, type CardDrift } from './wire/drift.js';
|
|
39
30
|
export type { DispatchObserver } from './dispatch/DispatchEvent.js';
|
|
40
31
|
export type { DispatchPort } from './dispatch/DispatchPort.js';
|
|
@@ -87,15 +78,17 @@ export { callValueOf } from './contract.js';
|
|
|
87
78
|
export type { CallValue } from './contract.js';
|
|
88
79
|
export { toHttpError, toPublicError } from './wire/http-error.js';
|
|
89
80
|
export { loggerMiddleware } from './wire/loggerMiddleware.js';
|
|
90
|
-
export { Logger, setLogLevel, logLevel, envLevel, onLog } from './
|
|
91
|
-
export type { LogLevel, LogRecord, LogSink } from './
|
|
81
|
+
export { Logger, setLogLevel, logLevel, envLevel, onLog } from './builtin/logger.js';
|
|
82
|
+
export type { LogLevel, LogRecord, LogSink } from './builtin/logger.js';
|
|
92
83
|
// What a re-read config changes in a running process — and what it cannot.
|
|
93
84
|
export { applyConfig, type ConfigApplication } from './boot/apply.js';
|
|
94
|
-
export { Config } from './
|
|
95
|
-
export type { Storage, StorageFactory,
|
|
96
|
-
export {
|
|
97
|
-
export {
|
|
98
|
-
export
|
|
85
|
+
export { Config } from './builtin/config.js';
|
|
86
|
+
export type { Storage, StorageFactory, ListOptions, ListResult, Together } from './storage.js';
|
|
87
|
+
export { togetherKeyOf, membersOfTogetherKey } from './storage.js';
|
|
88
|
+
export type { Constraint, Source, SourceConfig, SourceView } from './source.js';
|
|
89
|
+
export { Sources } from './source.js';
|
|
90
|
+
export { storageOver } from './store.js';
|
|
91
|
+
export type { Store, Values } from './store.js';
|
|
99
92
|
export type { App, CreateAppOptions } from './boot/types.js';
|
|
100
93
|
export type { ScanResult, ScanDiagnostic } from './scan/result.js';
|
|
101
94
|
export type {
|
package/src/loader.ts
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* How a source file becomes a module — one registry, two readers.
|
|
3
|
-
*
|
|
4
|
-
* The scanner loads fronds and `config-loader` loads a config, and both must use the
|
|
5
|
-
* loader the host installed: a TS file needs jiti under Nuxt and plain `import` under
|
|
6
|
-
* tsx. It lived in `scan/scanner.ts`, so reading a config dragged the scanner, its AST
|
|
7
|
-
* parser and the TypeScript compiler behind it.
|
|
8
|
-
*/
|
|
1
|
+
/** How a source file becomes a module — one registry, two readers. */
|
|
9
2
|
import { pathToFileURL } from 'node:url';
|
|
10
3
|
|
|
11
|
-
/**
|
|
12
|
-
* Module loader — can be swapped (e.g. jiti for TS files in Nuxt context).
|
|
13
|
-
*
|
|
14
|
-
* `fresh` asks for a file that may have changed since it was last read. Every loader
|
|
15
|
-
* caches, so without it a second read of an EDITED file hands back the first one —
|
|
16
|
-
* which is what re-reading a config is for. A loader that cannot honour it may ignore
|
|
17
|
-
* the flag; it then answers with what it already had.
|
|
18
|
-
*/
|
|
4
|
+
/** Module loader — can be swapped (e.g. */
|
|
19
5
|
export type ModuleLoader = (
|
|
20
6
|
filePath: string,
|
|
21
7
|
options?: { fresh?: boolean },
|
package/src/node.ts
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What Fougere does with a filesystem — the half of core that a Worker cannot run.
|
|
3
|
-
*
|
|
4
|
-
* The line is not "build vs runtime": `boot()` and `loadConfig` run in production, on a
|
|
5
|
-
* server, every time. It is whether the thing reaches for a disk. Everything here does,
|
|
6
|
-
* transitively, and nothing on the main entry does — which is what lets a bundler for a
|
|
7
|
-
* runtime without `node:fs` trace the main entry and find no builtin at all.
|
|
8
|
-
*
|
|
9
|
-
* The third entry, `@fougere/core/contract`, answers a different question: what crosses a
|
|
10
|
-
* process boundary. A foreign frond reads it without reading our boot.
|
|
11
|
-
*/
|
|
1
|
+
/** What Fougere does with a filesystem — the half of core that a Worker cannot run. */
|
|
12
2
|
export { boot } from './boot/boot.js';
|
|
13
3
|
|
|
14
4
|
export { scanProject, frondAliases, watchPathsOf } from './scan/scanner.js';
|
|
@@ -23,6 +13,7 @@ export { setModuleLoader, getModuleLoader } from './loader.js';
|
|
|
23
13
|
export { loadConfig, loadCascadedConfig } from './config-loader.js';
|
|
24
14
|
export { defineFrond } from './frond-config.js';
|
|
25
15
|
export { crossFrondImports } from './imports.js';
|
|
16
|
+
export { adaptersOf } from './scan/adapters.js';
|
|
26
17
|
|
|
27
18
|
// Making a key and binding a name to it happen once, at a deployment, on a machine with
|
|
28
19
|
// a filesystem — the CLI speaking. Verifying happens per call, everywhere, and stays on
|
package/src/prefab/collector.ts
CHANGED
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collector(Type) — resolves one handler input parameter from the invocation context.
|
|
3
|
-
*
|
|
4
|
-
* The target is a NAME matched against the parameter's type, never a schema: nothing
|
|
5
|
-
* here nor in the scan reads its fields. So `Ability`, built per call from state, sits
|
|
6
|
-
* beside `User`, loaded from a row.
|
|
7
|
-
*
|
|
8
|
-
* The dual of Presenter only in direction. A presenter's subject is a ROW — it adds
|
|
9
|
-
* computed fields to one, so its target must be an entity. A collector's subject is a
|
|
10
|
-
* PARAMETER.
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* ```ts
|
|
14
|
-
* export default class UserCollector extends Collector(User) {
|
|
15
|
-
* constructor(private userStorage: UserStorage) { super(); }
|
|
16
|
-
*
|
|
17
|
-
* async collect(ctx: InvocationContext) {
|
|
18
|
-
* return this.userStorage.findById(ctx.state.userId as string);
|
|
19
|
-
* }
|
|
20
|
-
* }
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
1
|
+
/** Collector(Type) — resolves one handler input parameter from the invocation context. */
|
|
23
2
|
|
|
24
3
|
import { upperFirst } from '@fougere/schema';
|
|
25
4
|
|
package/src/prefab/crud.ts
CHANGED
|
@@ -1,48 +1,42 @@
|
|
|
1
|
+
import { lowerFirst, type EntityConstructor, type SchemaView } from '@fougere/schema';
|
|
1
2
|
import type { Storage, ListOptions, ListResult } from '../storage.js';
|
|
2
3
|
import type { OperationContract } from '../wire/operation.js';
|
|
3
|
-
import
|
|
4
|
+
import { targetOf } from './prefab.js';
|
|
4
5
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* So a class is recognized by what it ANSWERS, since the mixin leaves no other trace.
|
|
8
|
+
* FR : pour qu'une classe se reconnaisse à ce qu'elle répond, le mixin ne laissant rien d'autre.
|
|
9
|
+
* `inheritsCrud(class PostHandler extends Crud(Post) {})` → `true`
|
|
10
|
+
*/
|
|
11
|
+
export function inheritsCrud(ctor: unknown): boolean {
|
|
12
|
+
const proto = (ctor as { prototype?: Record<string, unknown> } | undefined)?.prototype;
|
|
13
|
+
|
|
14
|
+
return typeof proto?.list === 'function' && typeof proto?.findById === 'function';
|
|
15
|
+
}
|
|
8
16
|
|
|
9
17
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `
|
|
13
|
-
* GraphQL argument needs the type. So a producer that fills only `binding` leaves
|
|
14
|
-
* `adapter/graphql` with nothing to declare — it drops the op (`registerOperations`,
|
|
15
|
-
* `if (!sig) continue`) and four of the five CRUD ops vanish from the schema while
|
|
16
|
-
* the façade and REST still serve them. Measured on an installed app: 16 handlers,
|
|
17
|
-
* 14 with unresolvable heritage, zero `createX` in the schema.
|
|
18
|
+
* So storage follows the shape the handler was built on, which may differ from its address.
|
|
19
|
+
* FR : pour que le stockage suive la forme sur laquelle le handler est bâti.
|
|
20
|
+
* `subjectOf(class Draft extends Crud(Post) {}, 'draft')` → `'post'`
|
|
18
21
|
*/
|
|
22
|
+
export function subjectOf(ctor: unknown, address: string): string {
|
|
23
|
+
const target = targetOf(ctor);
|
|
24
|
+
|
|
25
|
+
return target?.name ? lowerFirst(target.name) : address;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The id of the row an op acts on — a route segment, or a query fallback. */
|
|
29
|
+
const byId = { name: 'id', source: { kind: 'param' as const, name: 'id' }, optional: false };
|
|
30
|
+
const fromBody = { name: 'input', source: { kind: 'input' as const }, optional: false };
|
|
31
|
+
|
|
32
|
+
/** The same five, written as the scan would have written them. */
|
|
19
33
|
const idParam = { name: 'id', type: { raw: 'string', name: 'string' } };
|
|
20
34
|
const inputParam = (entity: string) => ({ name: 'input', type: { raw: `Partial<${entity}>`, name: entity } });
|
|
21
35
|
const returns = (raw: string, name: string, extra?: { array?: boolean; nullable?: boolean }) =>
|
|
22
36
|
({ raw, name, ...extra });
|
|
23
37
|
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
* The mixin built them, so it alone knows their contract in full: what judges
|
|
28
|
-
* their input, where each argument comes from. It says so on the class, at
|
|
29
|
-
* runtime — which is what makes the guarantee independent of the AST scan (an
|
|
30
|
-
* installed app cannot resolve this file, and never needs to).
|
|
31
|
-
*/
|
|
32
|
-
/**
|
|
33
|
-
* `output` says the entity, and saying it costs nothing at runtime.
|
|
34
|
-
*
|
|
35
|
-
* The façade already projected onto the entity when nothing else was named, so this
|
|
36
|
-
* changes no result: `outputFieldsFor` reads `contractOutput` and falls back to the
|
|
37
|
-
* entity, and both are the same shape here. What changes is that the sentence now
|
|
38
|
-
* EXISTS — the identity card publishes `output` per op, and a card was measured
|
|
39
|
-
* carrying none at all (2026-08-06, ten ops, zero outputs), which typed every remote
|
|
40
|
-
* return as `unknown` for anyone building on it.
|
|
41
|
-
*
|
|
42
|
-
* It does not close the view: only an explicit `__opOutputs` does (`closed: perOp !==
|
|
43
|
-
* undefined`), so a named view still wins and a presenter's computed fields still ride
|
|
44
|
-
* out. `delete` names none — a boolean is not a shape.
|
|
45
|
-
*/
|
|
38
|
+
/** The five ops a Crud handler brings, declared rather than discovered. */
|
|
39
|
+
/** `output` says the entity, and saying it costs nothing at runtime. */
|
|
46
40
|
function crudOps(entity: SchemaView & { partial?: () => SchemaView }): Record<string, OperationContract> {
|
|
47
41
|
const name = (entity as { name?: string }).name ?? 'Entity';
|
|
48
42
|
const input = inputParam(name);
|
|
@@ -76,15 +70,7 @@ function crudOps(entity: SchemaView & { partial?: () => SchemaView }): Record<st
|
|
|
76
70
|
};
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
/**
|
|
80
|
-
* The mixin's single "trust me" point — the twin of `asSchemaConstructor` in @fougere/schema.
|
|
81
|
-
*
|
|
82
|
-
* The implementation returns whatever the storage hands back; the declaration names the view
|
|
83
|
-
* each op emits at the port. TypeScript cannot connect the two (the view is a runtime
|
|
84
|
-
* argument, the type is a generic), so one assertion states that the mixin honours what it
|
|
85
|
-
* declared — and the façade makes it true, projecting each op's result onto its view
|
|
86
|
-
* (`outputFieldsFor` in `bootstrap.ts`).
|
|
87
|
-
*/
|
|
73
|
+
/** The mixin's single "trust me" point — the twin of `asSchemaConstructor` in @fougere/schema. */
|
|
88
74
|
function asCrudConstructor<T, V>(impl: object): CrudConstructor<T, V> {
|
|
89
75
|
return impl as CrudConstructor<T, V>;
|
|
90
76
|
}
|
|
@@ -95,12 +81,7 @@ export type CrudOpName = 'list' | 'findById' | 'create' | 'update' | 'delete';
|
|
|
95
81
|
/** Which view each op speaks — omitted ops speak the entity, the trivial view. */
|
|
96
82
|
export type CrudViews = Partial<Record<CrudOpName, EntityConstructor>>;
|
|
97
83
|
|
|
98
|
-
/**
|
|
99
|
-
* The view an op emits, fabricated: the one declared for it, the single view when the
|
|
100
|
-
* whole handler declares one, the entity otherwise. `PostCard` is not a hand-written
|
|
101
|
-
* type — `Post.pick(...)` derives it field by field, so an op's return is a projection
|
|
102
|
-
* of the entity exactly like the entity is the projection that keeps everything.
|
|
103
|
-
*/
|
|
84
|
+
/** The view an op emits, fabricated. */
|
|
104
85
|
type OutOf<V, K extends CrudOpName, T> =
|
|
105
86
|
// Bracketed on purpose: a naked `V extends …` DISTRIBUTES, and the no-view default
|
|
106
87
|
// is the empty map, whose `keyof` is `never` — distribution would then collapse
|
|
@@ -109,17 +90,7 @@ type OutOf<V, K extends CrudOpName, T> =
|
|
|
109
90
|
: K extends keyof V ? (V[K] extends EntityConstructor ? InstanceType<V[K]> : T)
|
|
110
91
|
: T;
|
|
111
92
|
|
|
112
|
-
/**
|
|
113
|
-
* The five ops, typed from the entity and its views.
|
|
114
|
-
*
|
|
115
|
-
* Two things the mixin declares but does not own. The **output** is the view the
|
|
116
|
-
* handler names (`Crud(Post, { list: PostCard })`) — fabricated, so a redefinition
|
|
117
|
-
* that returns cards stays assignable. The **trailing parameters** are resolved by
|
|
118
|
-
* type from the container (`delete(id, user?: User)` gets its user from a
|
|
119
|
-
* collector): the mixin cannot know them, they belong to the app, so it declares that
|
|
120
|
-
* a tail exists and that it supplies none — which is what `never` says, and what keeps
|
|
121
|
-
* a judged redefinition assignable.
|
|
122
|
-
*/
|
|
93
|
+
/** The five ops, typed from the entity and its views. */
|
|
123
94
|
export interface CrudOps<T, V = {}> {
|
|
124
95
|
storage: Storage<T>;
|
|
125
96
|
list(options?: ListOptions, ...collected: never[]): Promise<ListResult<OutOf<V, 'list', T>>>;
|
|
@@ -141,20 +112,7 @@ export interface CrudConstructor<T, V = {}> {
|
|
|
141
112
|
readonly __ops: Record<string, OperationContract>;
|
|
142
113
|
}
|
|
143
114
|
|
|
144
|
-
/**
|
|
145
|
-
* Mixin — extends Crud(Entity) to get all 5 typed CRUD methods.
|
|
146
|
-
*
|
|
147
|
-
* The second argument (optional) names the view the ops emit, and comes in two
|
|
148
|
-
* spellings of one idea — a view per op, or one view for all five:
|
|
149
|
-
*
|
|
150
|
-
* Crud(Post) → every op emits Post
|
|
151
|
-
* Crud(Post, { list: PostCard }) → list emits cards, the rest emit Post. Declaration
|
|
152
|
-
* only: the handler keeps its full-row storage, so a
|
|
153
|
-
* judge can still read `body`.
|
|
154
|
-
* Crud(Post, PostPublic) → every op emits PostPublic, and the bootstrap
|
|
155
|
-
* scopes the injected storage via .output(PostPublic) —
|
|
156
|
-
* the whole handler speaks the restricted view.
|
|
157
|
-
*/
|
|
115
|
+
/** Mixin — extends Crud(Entity) to get all 5 typed CRUD methods. */
|
|
158
116
|
export function Crud<E extends EntityConstructor, V extends CrudViews | EntityConstructor = {}>(
|
|
159
117
|
entity: E,
|
|
160
118
|
output?: V,
|
|
@@ -168,10 +126,13 @@ export function Crud<E extends EntityConstructor, V extends CrudViews | EntityCo
|
|
|
168
126
|
|
|
169
127
|
return asCrudConstructor<T, V>(class CrudHandler {
|
|
170
128
|
static __entity = entity;
|
|
171
|
-
/** Handler-wide view only — a per-op map must NOT scope the storage the
|
|
129
|
+
/** Handler-wide view only — a per-op map must NOT scope the storage the validators read. */
|
|
172
130
|
static __output = wholeHandler ?? entity;
|
|
173
131
|
static __opOutputs = perOp;
|
|
174
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* What this prefab handler declares — read by the façade, merged under the author's own
|
|
134
|
+
* methods.
|
|
135
|
+
*/
|
|
175
136
|
static __ops: Record<string, OperationContract> = crudOps(entity as unknown as SchemaView & { partial?: () => SchemaView });
|
|
176
137
|
|
|
177
138
|
storage: Storage<T>;
|
package/src/prefab/mirror.ts
CHANGED
|
@@ -1,32 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Lifecycle, type EntityConstructor, type Fields } from '@fougere/schema';
|
|
2
2
|
import type { Storage } from '../storage.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* A paginated local copy of a source that cannot be queried directly.
|
|
6
|
-
*
|
|
7
|
-
* The shape must contain an `updated()` field used as a high-water mark. Subclasses
|
|
8
|
-
* implement `pull`; `refresh` validates and upserts each returned page.
|
|
9
|
-
*
|
|
10
|
-
* ```ts
|
|
11
|
-
* export default class PartnerCatalog extends Mirror(BookCard) {
|
|
12
|
-
* constructor(storage: Storage<BookCard>, private catalog: Facade<CatalogHandler>) {
|
|
13
|
-
* super(storage);
|
|
14
|
-
* }
|
|
15
|
-
*
|
|
16
|
-
* async *pull(since?: Date) {
|
|
17
|
-
* for (let page = 0; page !== null;) {
|
|
18
|
-
* const body = await fetch(`${api}?page=${page}&since=${since?.toISOString() ?? ''}`);
|
|
19
|
-
* const { items, next } = await body.json();
|
|
20
|
-
* yield items.map(toCard);
|
|
21
|
-
* page = next;
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
4
|
+
/** A paginated local copy of a source that cannot be queried directly. */
|
|
27
5
|
/** What one refresh did — enough to log it, and to decide whether to run again. */
|
|
28
6
|
export interface Refreshed {
|
|
29
|
-
/**
|
|
7
|
+
/** Instances written, counting a replaced one once. */
|
|
30
8
|
written: number;
|
|
31
9
|
/** The age the pull was asked to start from — absent on the first ever run. */
|
|
32
10
|
since?: Date;
|
|
@@ -84,7 +62,7 @@ export function Mirror<E extends EntityConstructor>(shape: E): MirrorConstructor
|
|
|
84
62
|
// Preserve the source's page boundaries: one page becomes one upsert.
|
|
85
63
|
for await (const page of this.pull(since)) {
|
|
86
64
|
if (page.length === 0) continue;
|
|
87
|
-
written += await this.storage.upsertAll(
|
|
65
|
+
written += await this.storage.upsertAll(page);
|
|
88
66
|
}
|
|
89
67
|
return { written, since, ms: Date.now() - started };
|
|
90
68
|
}
|
|
@@ -102,21 +80,3 @@ export function ageFieldOf(shape: unknown): string | undefined {
|
|
|
102
80
|
}
|
|
103
81
|
return undefined;
|
|
104
82
|
}
|
|
105
|
-
|
|
106
|
-
/** Validate and decode a page, naming a refused row by its declared primary field. */
|
|
107
|
-
function judgePage<T>(shape: unknown, page: Partial<T>[]): Record<string, unknown>[] {
|
|
108
|
-
const judge = (shape as { validate?: (input: unknown) => ValidationResult<unknown> }).validate;
|
|
109
|
-
if (typeof judge !== 'function') return page as Record<string, unknown>[];
|
|
110
|
-
|
|
111
|
-
const name = (shape as { name?: string }).name ?? 'mirror';
|
|
112
|
-
const fields = (shape as { getFields?: () => Fields }).getFields?.();
|
|
113
|
-
const primary = fields ? FieldSet.of(fields).primary : undefined;
|
|
114
|
-
return page.map((row, index) => {
|
|
115
|
-
const verdict = judge.call(shape, row);
|
|
116
|
-
if (verdict.success) return verdict.data as Record<string, unknown>;
|
|
117
|
-
const key = primary === undefined ? undefined : (row as Record<string, unknown>)[primary];
|
|
118
|
-
const where = key !== undefined ? `row ${primary} ${JSON.stringify(key)}` : `row ${index} of this page`;
|
|
119
|
-
const why = verdict.errors.map((e) => `${e.path}: ${e.message}`).join(', ');
|
|
120
|
-
throw new Error(`${name} mirror refused ${where} — ${why}`);
|
|
121
|
-
});
|
|
122
|
-
}
|
package/src/prefab/prefab.ts
CHANGED
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import type { EntityConstructor } from '@fougere/schema';
|
|
2
2
|
import type { PresenterViews } from './presenter.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* What a prefab class declares about ITSELF, at runtime.
|
|
6
|
-
*
|
|
7
|
-
* `Crud(Post)`, `Presenter(Post)`, `Repository(Post)`, `Collector(User)` and
|
|
8
|
-
* `Mirror(BookCard)` all fabricate a class, and only the fabricator knows what it was
|
|
9
|
-
* built on: the AST scan is workspace-only, so an INSTALLED prefab resolves to nothing
|
|
10
|
-
* and a statement written in source would be lost. Hence a runtime marker — the same
|
|
11
|
-
* reason `__ops` exists.
|
|
12
|
-
*
|
|
13
|
-
* It was three spellings for one statement: `static __entity` on three of the five, a
|
|
14
|
-
* private `Symbol.for('fougere:x_target')` on the other two, and BOTH on `Repository`
|
|
15
|
-
* and `Mirror` — the same class recording its subject twice, under two names, with two
|
|
16
|
-
* readers that could disagree. A mark that answers one question answers it once.
|
|
17
|
-
*/
|
|
4
|
+
/** What a prefab class declares about ITSELF, at runtime. */
|
|
18
5
|
interface Prefab {
|
|
19
6
|
/** The shape this class was built on. `Mirror` calls it a shape; it is the same slot. */
|
|
20
7
|
readonly __entity?: EntityConstructor;
|
|
@@ -24,13 +11,7 @@ interface Prefab {
|
|
|
24
11
|
readonly __output?: EntityConstructor;
|
|
25
12
|
}
|
|
26
13
|
|
|
27
|
-
/**
|
|
28
|
-
* The shape a prefab was built on, or `undefined` when the class is not one.
|
|
29
|
-
*
|
|
30
|
-
* A plain property read: JavaScript walks a constructor's own prototype chain, so a
|
|
31
|
-
* subclass of a prefab answers what its base recorded. Three of the five accessors this
|
|
32
|
-
* replaces walked that chain by hand, and two did not — one question, two mechanisms.
|
|
33
|
-
*/
|
|
14
|
+
/** The shape a prefab was built on, or `undefined` when the class is not one. */
|
|
34
15
|
export function targetOf(ctor: unknown): EntityConstructor | undefined {
|
|
35
16
|
return (ctor as Prefab | undefined)?.__entity;
|
|
36
17
|
}
|
package/src/prefab/presenter.ts
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Presenter(Entity) — enriches an entity's output with computed fields.
|
|
3
|
-
*
|
|
4
|
-
* Each method on the presenter is a computed field resolver:
|
|
5
|
-
* - Receives the entity record as first argument
|
|
6
|
-
* - Can be sync or async
|
|
7
|
-
* - Injected via DI (constructor params resolved by the container)
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* ```ts
|
|
11
|
-
* export default class PostPresenter extends Presenter(Post) {
|
|
12
|
-
* constructor(private commentStorage: CommentStorage) { super(); }
|
|
13
|
-
*
|
|
14
|
-
* excerpt(post: Post) {
|
|
15
|
-
* return post.body.slice(0, 200);
|
|
16
|
-
* }
|
|
17
|
-
*
|
|
18
|
-
* async commentCount(post: Post) {
|
|
19
|
-
* return this.commentStorage.countFor(post.id);
|
|
20
|
-
* }
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
1
|
+
/** Presenter(Entity) — enriches an entity's output with computed fields. */
|
|
24
2
|
|
|
25
3
|
import { upperFirst, type EntityConstructor } from '@fougere/schema';
|
|
26
4
|
|
|
@@ -30,19 +8,7 @@ import { upperFirst, type EntityConstructor } from '@fougere/schema';
|
|
|
30
8
|
*/
|
|
31
9
|
export type PresenterViews = Record<string, EntityConstructor | [EntityConstructor]>;
|
|
32
10
|
|
|
33
|
-
/**
|
|
34
|
-
* `Presenter(Order, { items: [OrderItemView], user: UserCard })` — the second argument names
|
|
35
|
-
* the view each computed field emits, exactly as `Crud(Post, { list: PostCard })` names an
|
|
36
|
-
* op's. What fabricates a field declares its contract, and it declares it **once**: the
|
|
37
|
-
* façade applies the presenter (see `PresenterExecutor`), and every surface reads the same statement
|
|
38
|
-
* instead of guessing.
|
|
39
|
-
*
|
|
40
|
-
* Guessing was the cost of not stating it. The scan can read a scalar off a return type and
|
|
41
|
-
* nothing more, so a field returning an object had no derivable shape: the GraphQL projection
|
|
42
|
-
* fell back to a serialized `String`, and a client asking `items { quantity }` got a schema
|
|
43
|
-
* error on a field REST served whole. Declaring is optional — a scalar field needs nothing,
|
|
44
|
-
* and an undeclared object keeps the old behaviour.
|
|
45
|
-
*/
|
|
11
|
+
/** `Presenter(Order, { items. */
|
|
46
12
|
export function Presenter<E extends EntityConstructor>(entity: E, views?: PresenterViews) {
|
|
47
13
|
class PresenterBase {
|
|
48
14
|
static readonly __entity = entity;
|