@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/scan/statement.ts
CHANGED
|
@@ -1,40 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The scan, written as the STATEMENT an author would have written.
|
|
3
|
-
*
|
|
4
|
-
* A scan runs at build and the app runs elsewhere — two runtimes, no shared memory — so
|
|
5
|
-
* something has to cross. What used to cross was the scan RESULT: every operation's
|
|
6
|
-
* TypeScript signature re-serialized as JSON, beside the five CRUD ops `Crud.__ops`
|
|
7
|
-
* declares at runtime anyway. A second writing of what the classes carry, and one that
|
|
8
|
-
* drifts, since nothing compares the two.
|
|
9
|
-
*
|
|
10
|
-
* What crosses here is what `fronds.ts` holds: imports that bring the ORIGINAL classes
|
|
11
|
-
* back, and `frond()` calls. Everything else `frond()` derives — `Post` is stored as
|
|
12
|
-
* `post`, `PostHandler` answers at `post`, a computed field IS a method, and
|
|
13
|
-
* `Presenter(Post)` keeps its subject. Only what TypeScript erases is named: a
|
|
14
|
-
* constructor's parameter types (`deps`), and the surface a handler answers on, which the
|
|
15
|
-
* scan read from its directory.
|
|
16
|
-
*
|
|
17
|
-
* Measured on demos/nuxt-blog: 102 lines of scan against 31 of statement, and the same app
|
|
18
|
-
* — same rows, same computed fields, and no `typescript` loaded at boot.
|
|
19
|
-
*/
|
|
1
|
+
/** The scan, written as the STATEMENT an author would have written. */
|
|
20
2
|
import { relative } from 'node:path';
|
|
3
|
+
import { nameOf } from '../descriptor/frond.js';
|
|
21
4
|
import type { FrondDescriptor } from '../descriptor/frond.js';
|
|
22
5
|
import type { ScanResult } from './result.js';
|
|
23
|
-
|
|
24
|
-
type Live = { name?: string };
|
|
6
|
+
import { type Aliases, type Live, operationsOf } from './contract.js';
|
|
25
7
|
|
|
26
8
|
/**
|
|
27
|
-
* A file becomes the specifier the PROJECT already uses for it: `@fronds/blog/…`, the
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* A relative path would name the same file by a second route, and two routes to one module
|
|
32
|
-
* are two modules — so `Post` would not equal `Post` and every identity check would fail
|
|
33
|
-
* quietly. It also puts the file outside what the alias resolves, which is what made Node,
|
|
34
|
-
* not the bundler, read the frond's `.ts` and answer 500 on `../entities/Post.js`.
|
|
35
|
-
*
|
|
36
|
-
* `.js`, because the source is `.ts` and the project spells a TypeScript source that way
|
|
37
|
-
* everywhere else — the alias resolves through the same rule as a hand-written import.
|
|
9
|
+
* A file becomes the specifier the PROJECT already uses for it: `@fronds/blog/…`, the import scope
|
|
10
|
+
* a handler names its neighbour by, and which the Nuxt module registers as an alias for every
|
|
11
|
+
* frond it found.
|
|
38
12
|
*/
|
|
39
13
|
function specifierOf(filePath: string, frond: FrondDescriptor): string {
|
|
40
14
|
const inside = relative(frond.source.path, filePath).replace(/\.tsx?$/, '.js');
|
|
@@ -43,30 +17,66 @@ function specifierOf(filePath: string, frond: FrondDescriptor): string {
|
|
|
43
17
|
}
|
|
44
18
|
|
|
45
19
|
/** One alias per file, so a class imported twice is one binding and one identity. */
|
|
46
|
-
class Imports {
|
|
20
|
+
class Imports implements Aliases {
|
|
47
21
|
private readonly byPath = new Map<string, string>();
|
|
22
|
+
private readonly byValue = new Map<Live, string>();
|
|
23
|
+
private readonly byClassName = new Map<string, Live>();
|
|
48
24
|
private readonly lines: string[] = [];
|
|
25
|
+
/** The frond a file belongs to — a named import needs the specifier its default got. */
|
|
26
|
+
private frondOfFile = new Map<string, FrondDescriptor>();
|
|
49
27
|
|
|
50
|
-
default(filePath: string, frond: FrondDescriptor): string {
|
|
28
|
+
default(filePath: string, frond: FrondDescriptor, value?: Live): string {
|
|
29
|
+
this.frondOfFile.set(filePath, frond);
|
|
51
30
|
const known = this.byPath.get(filePath);
|
|
52
|
-
if (known)
|
|
31
|
+
if (known) {
|
|
32
|
+
if (value) this.remember(value, known);
|
|
33
|
+
|
|
34
|
+
return known;
|
|
35
|
+
}
|
|
53
36
|
const alias = `_${this.byPath.size}`;
|
|
54
37
|
this.lines.push(`import ${alias} from '${specifierOf(filePath, frond)}';`);
|
|
55
38
|
this.byPath.set(filePath, alias);
|
|
39
|
+
if (value) this.remember(value, alias);
|
|
40
|
+
|
|
41
|
+
return alias;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A view a handler declares beside itself — `PostPublic` is exported by name. */
|
|
45
|
+
named(value: Live, filePath: string, name: string): string {
|
|
46
|
+
const known = this.byValue.get(value);
|
|
47
|
+
if (known) return known;
|
|
48
|
+
const frond = this.frondOfFile.get(filePath);
|
|
49
|
+
if (!frond) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`A statement cannot be written: ${name} lives in ${filePath}, which no frond imported first.`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const alias = `_${this.byPath.size}_${name}`;
|
|
55
|
+
this.lines.push(`import { ${name} as ${alias} } from '${specifierOf(filePath, frond)}';`);
|
|
56
|
+
this.remember(value, alias);
|
|
56
57
|
|
|
57
58
|
return alias;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
aliasOf(value: Live): string | undefined { return this.byValue.get(value); }
|
|
62
|
+
classNamed(name: string): Live | undefined { return this.byClassName.get(name); }
|
|
63
|
+
|
|
64
|
+
private remember(value: Live, alias: string): void {
|
|
65
|
+
this.byValue.set(value, alias);
|
|
66
|
+
const name = (value as { name?: string }).name;
|
|
67
|
+
if (name) this.byClassName.set(name, value);
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
render(): string {
|
|
61
71
|
return this.lines.join('\n');
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
/** `{ ctor: X, deps: [...] }` when there is something to say, the bare class otherwise. */
|
|
66
|
-
function subject(alias: string, deps: string[], extra
|
|
76
|
+
function subject(alias: string, deps: string[], ...extra: string[]): string {
|
|
67
77
|
const parts = [
|
|
68
78
|
...(deps.length ? [`deps: ${JSON.stringify(deps)}`] : []),
|
|
69
|
-
...(
|
|
79
|
+
...extra.filter(Boolean),
|
|
70
80
|
];
|
|
71
81
|
|
|
72
82
|
return parts.length ? `{ ctor: ${alias}, ${parts.join(', ')} }` : alias;
|
|
@@ -76,12 +86,21 @@ function frondOf(frond: FrondDescriptor, imports: Imports): string {
|
|
|
76
86
|
const list = (items: string[]): string => `[${items.join(', ')}]`;
|
|
77
87
|
const members: string[] = [];
|
|
78
88
|
|
|
89
|
+
// Entities first, and by VALUE: an operation names its input and output as schemas, and
|
|
90
|
+
// the one a `Partial<X>` derives from is found here rather than imported a second time.
|
|
79
91
|
if (frond.entities.length) {
|
|
80
|
-
members.push(`entities: ${list(frond.entities.map((e) =>
|
|
92
|
+
members.push(`entities: ${list(frond.entities.map((e) =>
|
|
93
|
+
imports.default(e.filePath, frond, e.entityClass as Live)))}`);
|
|
81
94
|
}
|
|
82
95
|
if (frond.handlers.length) {
|
|
83
|
-
members.push(`handlers: ${list(frond.handlers.map((h) =>
|
|
84
|
-
|
|
96
|
+
members.push(`handlers: ${list(frond.handlers.map((h) => subject(
|
|
97
|
+
imports.default(h.filePath, frond, h.ctor as Live),
|
|
98
|
+
h.deps,
|
|
99
|
+
h.surface ? `surface: ${JSON.stringify(h.surface)}` : '',
|
|
100
|
+
// What the scan read from source, and what no class carries at runtime. Without it
|
|
101
|
+
// a host that boots from this statement serves a prefab's five ops and nothing else.
|
|
102
|
+
h.operations.size ? `operations: ${operationsOf(h.operations, h.filePath, imports, ' ')}` : '',
|
|
103
|
+
)))}`);
|
|
85
104
|
}
|
|
86
105
|
if (frond.presenters.length) {
|
|
87
106
|
members.push(`presenters: ${list(frond.presenters.map((p) => subject(imports.default(p.filePath, frond), p.deps)))}`);
|
|
@@ -90,13 +109,26 @@ function frondOf(frond: FrondDescriptor, imports: Imports): string {
|
|
|
90
109
|
members.push(`collectors: ${list(frond.collectors.map((c) => subject(imports.default(c.filePath, frond), c.deps)))}`);
|
|
91
110
|
}
|
|
92
111
|
if (frond.providers.length) {
|
|
93
|
-
members.push(`providers: ${list(frond.providers.map((p) => subject(
|
|
112
|
+
members.push(`providers: ${list(frond.providers.map((p) => subject(
|
|
113
|
+
imports.default(p.filePath, frond, p.ctor as Live),
|
|
114
|
+
p.deps,
|
|
115
|
+
// The container key, and a bundler is free to rewrite the class's own name — it did,
|
|
116
|
+
// and a handler asking for `Communes` met a provider registered as `_Communes`.
|
|
117
|
+
`name: ${JSON.stringify(nameOf(p))}`,
|
|
118
|
+
)))}`);
|
|
94
119
|
}
|
|
95
120
|
// A seed is DATA, not a class — the one member a statement cannot derive from an import.
|
|
96
121
|
if (frond.seeds.length) {
|
|
97
122
|
members.push(`seeds: ${JSON.stringify(frond.seeds.map((s) => ({ entityName: s.entityName, data: s.data })))}`);
|
|
98
123
|
}
|
|
99
124
|
if (frond.surfaces) members.push(`surfaces: ${JSON.stringify(frond.surfaces)}`);
|
|
125
|
+
// What `frond.config.ts` states — read BY the scan, so a host that boots from a written
|
|
126
|
+
// statement never sees the file. It is the only answer for the kind of an op whose name
|
|
127
|
+
// leads with no known verb, and the only one for a method inherited from a base class
|
|
128
|
+
// the workspace scan cannot see.
|
|
129
|
+
if (frond.operationsOverrides && Object.keys(frond.operationsOverrides).length) {
|
|
130
|
+
members.push(`operationsOverrides: ${JSON.stringify(frond.operationsOverrides)}`);
|
|
131
|
+
}
|
|
100
132
|
|
|
101
133
|
const scope = (frond.source.package as string | undefined)?.split('/')[0];
|
|
102
134
|
if (scope) members.push(`scope: ${JSON.stringify(scope)}`);
|
package/src/source.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Registry, Role, type SchemaView } from '@fougere/schema';
|
|
2
|
+
import type { StorageFactory } from './storage.js';
|
|
3
|
+
|
|
4
|
+
/** A promise the judge at the door cannot keep, because it is about rows it never sees. */
|
|
5
|
+
export type Constraint = 'unique';
|
|
6
|
+
|
|
7
|
+
/** Whether an entity asks for one, anywhere but on its key. */
|
|
8
|
+
export function declares(schema: SchemaView, constraint: Constraint): boolean {
|
|
9
|
+
if (constraint !== 'unique') return false;
|
|
10
|
+
if ((schema.getUnique() ?? []).length > 0) return true;
|
|
11
|
+
|
|
12
|
+
return Object.values(schema.getFields()).some((field) => Role.of(field).isUnique);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A place rows live, whatever realizes it. */
|
|
16
|
+
export interface Source {
|
|
17
|
+
storageFactory: StorageFactory;
|
|
18
|
+
/**
|
|
19
|
+
* Bring the shape of what lives here up to date, and say what it could not bring.
|
|
20
|
+
*
|
|
21
|
+
* A pass is additive by design and leaves what already exists alone — which is a
|
|
22
|
+
* promise worth keeping and a silence worth breaking: what it declined to change is
|
|
23
|
+
* still a difference, and a boot is where a reader can act on it.
|
|
24
|
+
*/
|
|
25
|
+
migrate?(view: SourceView): Promise<void | string>;
|
|
26
|
+
/** Run `fn` as ONE unit of work, with a factory bound to it. */
|
|
27
|
+
transacted?<R>(fn: (factory: StorageFactory) => Promise<R>): Promise<R>;
|
|
28
|
+
/** What it refuses at the rows themselves. Absent leaves the judge alone with it. */
|
|
29
|
+
enforces?: readonly Constraint[];
|
|
30
|
+
close?(): Promise<void>;
|
|
31
|
+
/** What distinguishes it when a query is reported. */
|
|
32
|
+
name?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The app as ONE source sees it. */
|
|
36
|
+
export interface SourceView {
|
|
37
|
+
fronds: readonly { readonly name: string; readonly entities: readonly { readonly name: string }[] }[];
|
|
38
|
+
/** The auth provider's own entities, when they ride with this source. */
|
|
39
|
+
auth?: unknown;
|
|
40
|
+
elsewhere: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** What a config file can carry about a source — values, never a live driver. */
|
|
44
|
+
export interface SourceConfig {
|
|
45
|
+
/** The adapter that realizes it. Absent means the conventional one. */
|
|
46
|
+
source?: string;
|
|
47
|
+
/** The entities whose rows live here. Absent on the default source: it holds the rest. */
|
|
48
|
+
entities?: string[];
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Which adapter answers a source name — one per process, no subject to hold. */
|
|
53
|
+
class SourceRegistry extends Registry<(conf: SourceConfig) => Source> {
|
|
54
|
+
/** The source this name stands for, built from the config entry that named it. */
|
|
55
|
+
open(name: string, conf: SourceConfig, path?: string): Source {
|
|
56
|
+
return this.resolve(name, path)(conf);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const Sources = new SourceRegistry(
|
|
61
|
+
'source',
|
|
62
|
+
'import the adapter that answers it, or call Sources.register(name, build)',
|
|
63
|
+
);
|
package/src/storage.ts
CHANGED
|
@@ -24,9 +24,8 @@ export interface ListOptions {
|
|
|
24
24
|
count?: boolean;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Equality criteria, field by field — `{ orderId: '…' }`. Named rather than spread
|
|
28
|
-
*
|
|
29
|
-
* filter. `listBy(criteria)` is the same thing said as an intention.
|
|
27
|
+
* Equality criteria, field by field — `{ orderId: '…' }`. Named rather than spread across the
|
|
28
|
+
* options so an unknown key stays ignored instead of silently becoming a filter.
|
|
30
29
|
*/
|
|
31
30
|
where?: Record<string, unknown>;
|
|
32
31
|
}
|
|
@@ -41,12 +40,7 @@ export interface ListResult<T> extends Array<T> {
|
|
|
41
40
|
hasMore?: boolean;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
/**
|
|
45
|
-
* The keys `list()` answers to. Anything else is a mistake, and saying so is the point:
|
|
46
|
-
* the façade refuses an unknown key in a CLIENT's input (`Unknown field`) — this applies the
|
|
47
|
-
* same rule to the framework's own arguments. `list({ orderId })` used to be accepted and
|
|
48
|
-
* the filter dropped, so a one-to-many relation quietly returned the whole table.
|
|
49
|
-
*/
|
|
43
|
+
/** The keys `list()` answers to. */
|
|
50
44
|
const LIST_OPTION_KEYS = [
|
|
51
45
|
'limit', 'offset', 'page', 'after', 'orderBy', 'order', 'count', 'where', 'select',
|
|
52
46
|
] as const;
|
|
@@ -73,83 +67,27 @@ export interface Storage<T = Record<string, unknown>> {
|
|
|
73
67
|
list(options?: ListOptions & SelectOption): Promise<ListResult<T>>;
|
|
74
68
|
findById(id: string, options?: SelectOption): Promise<T | undefined>;
|
|
75
69
|
/**
|
|
76
|
-
* Read by criteria — `findBy({ email })` for the one, `findAllBy({ orderId })` for the
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* Both existed on the SQL implementation from the start and neither was declared here.
|
|
80
|
-
* A port that hides what it offers is a port nobody can use: `auth-better` cast its way
|
|
81
|
-
* in (`storage as StorageWithFindBy`), a presenter that needed the lines of an order read the
|
|
82
|
-
* whole table instead, and the GraphQL relation resolver passed criteria to `list()`
|
|
83
|
-
* — which drops what it does not know.
|
|
70
|
+
* Read by criteria — `findBy({ email })` for the one, `findAllBy({ orderId })` for the many,
|
|
71
|
+
* which is what a one-to-many relation *is*.
|
|
84
72
|
*/
|
|
85
73
|
findBy(criteria: Partial<T> | Record<string, unknown>, options?: SelectOption): Promise<T | undefined>;
|
|
86
74
|
findAllBy(criteria: Partial<T> | Record<string, unknown>, options?: SelectOption): Promise<T[]>;
|
|
87
75
|
/**
|
|
88
|
-
* Read a SET of rows by their key, in one go — the gesture every other one was
|
|
89
|
-
* being bent into.
|
|
90
|
-
*
|
|
91
|
-
* `findAllBy` compares with `=`, so a list of ids could not be passed to it; the
|
|
92
|
-
* only way to read N rows was `list()` then filter in memory, which is what 14 of
|
|
93
|
-
* 14 handlers of a real app measured on 2026-08-14 were doing. It is invisible on
|
|
94
|
-
* SQLite and it is the whole table the day the rows are not local.
|
|
95
|
-
*
|
|
96
|
-
* It answers a MAP, because the caller holds keys and not positions: a page zips
|
|
97
|
-
* against it by `get(row.authorId)`, a miss is the absence of a key, and a repeated
|
|
98
|
-
* key is one entry. The list form this replaced promised that zip and could not
|
|
99
|
-
* keep it — dropping a miss shifts every later position — so each caller rebuilt
|
|
100
|
-
* the very index the implementation had just thrown away.
|
|
76
|
+
* Read a SET of rows by their key, in one go — the gesture every other one was being bent into.
|
|
101
77
|
*/
|
|
102
78
|
findByKeys(ids: readonly string[], options?: SelectOption): Promise<Map<string, T>>;
|
|
103
|
-
/**
|
|
104
|
-
* Its dual: the rows that point AT each of these keys, grouped by the one they point at.
|
|
105
|
-
*
|
|
106
|
-
* `findByKeys` answers the side a row designates — one each, at most. This answers the
|
|
107
|
-
* side that designates the row — several each, and a key with none is simply absent.
|
|
108
|
-
* Together they are both directions of a relation, each in one query.
|
|
109
|
-
*
|
|
110
|
-
* Written because the page-shaped gesture only covered one of them: a presenter holding
|
|
111
|
-
* its page and wanting "the items of these lists" had no vocabulary for it and read the
|
|
112
|
-
* whole table instead, measured on a real app. `field` names the foreign key on THIS
|
|
113
|
-
* entity, the one carrying the value.
|
|
114
|
-
*/
|
|
79
|
+
/** The dual of `findByKeys`: many rows per key, not one. */
|
|
115
80
|
findAllByKeys(field: string, keys: readonly string[], options?: SelectOption): Promise<Map<string, T[]>>;
|
|
116
81
|
create(input: Partial<T>, options?: SelectOption): Promise<T>;
|
|
117
|
-
/**
|
|
118
|
-
* Write the row, or make the existing one look like this — one statement.
|
|
119
|
-
*
|
|
120
|
-
* What an import needs and the port did not have: `create` throws on the second run,
|
|
121
|
-
* so re-reading a source meant deleting first. Measured pulling an API twice.
|
|
122
|
-
*
|
|
123
|
-
* The key and the creation stamps survive an overwrite — a row keeps the moment it
|
|
124
|
-
* appeared. An engine with no upsert clause refuses by name rather than emulating
|
|
125
|
-
* one with a read in front, which would promise an atomicity it has not got.
|
|
126
|
-
*/
|
|
82
|
+
/** Write the row, or make the existing one look like this — one statement. */
|
|
127
83
|
upsert(input: Partial<T>, options?: SelectOption): Promise<T>;
|
|
128
|
-
/**
|
|
129
|
-
* A whole page in one statement — what an import writes through.
|
|
130
|
-
*
|
|
131
|
-
* Row by row, 500 rows were 500 statements (measured); the shape of an import is a
|
|
132
|
-
* page, so the write is one too. Answers how many rows were written rather than the
|
|
133
|
-
* rows: `create` hands back the complete row because a caller acts on it, and an
|
|
134
|
-
* import acts on none of them — re-reading a page for a symmetry nobody uses would
|
|
135
|
-
* double the work.
|
|
136
|
-
*/
|
|
84
|
+
/** A whole page in one statement — what an import writes through. */
|
|
137
85
|
upsertAll(inputs: readonly Partial<T>[], options?: SelectOption): Promise<number>;
|
|
138
86
|
update(id: string, input: Partial<T>, options?: SelectOption): Promise<T>;
|
|
139
87
|
delete(id: string): Promise<boolean>;
|
|
140
88
|
/** Returns a scoped storage that restricts all read results to the fields of the given schema. */
|
|
141
89
|
output(schema: SchemaView): Storage<T>;
|
|
142
|
-
/**
|
|
143
|
-
* What this storage wraps — the Kysely instance for the SQL one, something else elsewhere.
|
|
144
|
-
*
|
|
145
|
-
* Every judge sits on the storage's own methods, so a statement issued here meets none of
|
|
146
|
-
* them: a value the entity refuses lands in the table without a word. It is the port's
|
|
147
|
-
* own escape hatch rather than a handle on the side, so it keeps the scope the container
|
|
148
|
-
* gave you — `productStorage.client` reaches the products, not the whole database.
|
|
149
|
-
*
|
|
150
|
-
* `unknown` on purpose: the client belongs to the implementation, and narrowing it is
|
|
151
|
-
* the caller saying out loud which one they are standing on.
|
|
152
|
-
*/
|
|
90
|
+
/** What this storage wraps — the Kysely instance for the SQL one, something else elsewhere. */
|
|
153
91
|
readonly client: unknown;
|
|
154
92
|
}
|
|
155
93
|
|
|
@@ -159,118 +97,12 @@ export interface Storage<T = Record<string, unknown>> {
|
|
|
159
97
|
*/
|
|
160
98
|
export type StorageFactory = (entity: SchemaView, name: string) => Storage;
|
|
161
99
|
|
|
162
|
-
/**
|
|
163
|
-
* A place rows live, whatever realizes it.
|
|
164
|
-
*
|
|
165
|
-
* `StorageFactory` plus its lifecycle, which is why it lives beside it. Three of the four
|
|
166
|
-
* gestures are optional and ABSENCE IS THE ANSWER: no `transacted` and a frame compensates
|
|
167
|
-
* instead of transacting (`boot/together.ts`), no `migrate` and there is no shape to bring
|
|
168
|
-
* up to date. What a source is MADE OF is not here — `adapter/sql` states `dialect`, `db`
|
|
169
|
-
* and `sink` on its own `SqlSource`, reached by narrowing, the rule {@link Storage.client}
|
|
170
|
-
* already obeys one level down.
|
|
171
|
-
*/
|
|
172
|
-
export interface Source {
|
|
173
|
-
storageFactory: StorageFactory;
|
|
174
|
-
/** Bring the shape of what lives here up to date. */
|
|
175
|
-
migrate?(view: SourceView): Promise<void>;
|
|
176
|
-
/** Run `fn` as ONE unit of work, with a factory bound to it. */
|
|
177
|
-
transacted?<R>(fn: (factory: StorageFactory) => Promise<R>): Promise<R>;
|
|
178
|
-
close?(): Promise<void>;
|
|
179
|
-
/** What distinguishes it when a query is reported. */
|
|
180
|
-
name?: string;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* The app as ONE source sees it: what lives there, and the NAMES of what does not.
|
|
185
|
-
*
|
|
186
|
-
* The second half is what lets a DDL stop lying. A batch holding every entity cannot tell
|
|
187
|
-
* a cross-source target from a typo, so a `ref()` falls back to a derived table name and
|
|
188
|
-
* the constraint is emitted against a table that may not exist. `elsewhere` says which
|
|
189
|
-
* misses are legitimate — and a target in neither list is a mistake, out loud.
|
|
190
|
-
*/
|
|
191
|
-
export interface SourceView {
|
|
192
|
-
fronds: readonly { readonly name: string; readonly entities: readonly { readonly name: string }[] }[];
|
|
193
|
-
/** The auth provider's own entities, when they ride with this source. */
|
|
194
|
-
auth?: unknown;
|
|
195
|
-
elsewhere: readonly string[];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* What a config file can carry about a source — values, never a live driver.
|
|
200
|
-
*
|
|
201
|
-
* `source` names the ADAPTER, and everything else belongs to the adapter it named:
|
|
202
|
-
* `adapter/sql` reads `dialect`, a file one reads `path`. That is the shape
|
|
203
|
-
* `EntityAdapters` already has — addressed by adapter, and what sits below is the
|
|
204
|
-
* adapter's own. Which is why the level `schema` owns is not repeated here.
|
|
205
|
-
*/
|
|
206
|
-
export interface SourceConfig {
|
|
207
|
-
/** The adapter that realizes it. Absent means the conventional one. */
|
|
208
|
-
source?: string;
|
|
209
|
-
/** The entities whose rows live here. Absent on the default source: it holds the rest. */
|
|
210
|
-
entities?: string[];
|
|
211
|
-
[key: string]: unknown;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Which adapter answers a source name — one per process, no subject to hold.
|
|
216
|
-
*
|
|
217
|
-
* The shape `Generators` already has, and the refusal `resolveStorage` already made: only
|
|
218
|
-
* `sqlite` could be resolved from its name, because it was the one driver `defaults`
|
|
219
|
-
* depended on. That refusal had no owner — it lived in the package that happened to import
|
|
220
|
-
* the driver — so a second adapter had nowhere to say it exists. Here it does, and an
|
|
221
|
-
* unknown name is refused naming what this process answers.
|
|
222
|
-
*
|
|
223
|
-
* Registered at IMPORT by each adapter, so nothing central lists them.
|
|
224
|
-
*/
|
|
225
|
-
export class Sources {
|
|
226
|
-
private static readonly registry = new Map<string, (conf: SourceConfig) => Source>();
|
|
227
|
-
|
|
228
|
-
static register(name: string, build: (conf: SourceConfig) => Source): void {
|
|
229
|
-
this.registry.set(name, build);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** The source this name stands for, refused by name when nothing does. */
|
|
233
|
-
static resolve(name: string, conf: SourceConfig): Source {
|
|
234
|
-
const build = this.registry.get(name);
|
|
235
|
-
if (build) return build(conf);
|
|
236
|
-
|
|
237
|
-
throw new Error(
|
|
238
|
-
`Unknown source '${name}' — import the adapter that answers it, or register one with `
|
|
239
|
-
+ `Sources.register('${name}', build). This process answers `
|
|
240
|
-
+ `${[...this.registry.keys()].join(', ') || 'nothing yet'}.`,
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/** Whether a name is answered, for a caller that must not throw to find out. */
|
|
245
|
-
static answers(name: string): boolean {
|
|
246
|
-
return this.registry.has(name);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/** What this process answers — what a refusal elsewhere prints. */
|
|
250
|
-
static answered(): string[] {
|
|
251
|
-
return [...this.registry.keys()];
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Container key of an entity's storage — 'reading' → 'ReadingStorage'.
|
|
257
|
-
*
|
|
258
|
-
* The twin of {@link repositoryKeyOf} and of `facadeKeyOf`: the key of a thing
|
|
259
|
-
* lives with the thing. This one was spelled by hand in four places in
|
|
260
|
-
* `bootstrap.ts` and a fifth in `scanner.ts` — where the SCAN derives what a
|
|
261
|
-
* constructor asks for. Two readers of one convention, neither of them naming it,
|
|
262
|
-
* so a rename would have moved one and left the other resolving to nothing.
|
|
263
|
-
*/
|
|
100
|
+
/** Container key of an entity's storage — 'reading' → 'ReadingStorage'. */
|
|
264
101
|
export function storageKeyOf(entity: string): string {
|
|
265
102
|
return `${upperFirst(entity)}${HELD}`;
|
|
266
103
|
}
|
|
267
104
|
|
|
268
|
-
/**
|
|
269
|
-
* The entity behind a storage key, or `undefined` when the key is not one.
|
|
270
|
-
*
|
|
271
|
-
* The dual of the line above, for the reason `membersOfTogetherKey` is. `known` is what the
|
|
272
|
-
* suffix alone cannot answer: `FileStorage` is an ordinary class name.
|
|
273
|
-
*/
|
|
105
|
+
/** The entity behind a storage key, or `undefined` when the key is not one. */
|
|
274
106
|
export function entityOfStorageKey(key: string, known: (entity: string) => boolean): string | undefined {
|
|
275
107
|
if (key.length <= HELD.length || !key.endsWith(HELD)) return undefined;
|
|
276
108
|
const entity = lowerFirst(key.slice(0, -HELD.length));
|
|
@@ -281,47 +113,7 @@ export function entityOfStorageKey(key: string, known: (entity: string) => boole
|
|
|
281
113
|
/** What a holder keeps, said in the key it is registered under. */
|
|
282
114
|
const HELD = 'Storage';
|
|
283
115
|
|
|
284
|
-
/**
|
|
285
|
-
* `Together<[Account, Ledger]>` — writes that stand or fall as one.
|
|
286
|
-
*
|
|
287
|
-
* `Storage` is the port whose every gesture is ONE statement, and one statement is
|
|
288
|
-
* atomic in every engine. This is the port whose unit is a BLOCK: what the callback did
|
|
289
|
-
* happens entirely, or not at all. Nothing else separates them — the arity of the unit
|
|
290
|
-
* of work is the whole distinction, which is why this lives here and not in a file of
|
|
291
|
-
* its own.
|
|
292
|
-
*
|
|
293
|
-
* ```ts
|
|
294
|
-
* constructor(private together: Together<[Account, Ledger]>) {}
|
|
295
|
-
*
|
|
296
|
-
* await this.together.run(async ([accounts, ledger]) => {
|
|
297
|
-
* await accounts.update(from, { balance: b - amount });
|
|
298
|
-
* await ledger.create({ from, to, amount });
|
|
299
|
-
* });
|
|
300
|
-
* ```
|
|
301
|
-
*
|
|
302
|
-
* **The second list is providers**, rebuilt inside the frame so that what THEY write is
|
|
303
|
-
* covered too — a `Mirror` writes its pages through `Storage<T>`, so naming it puts
|
|
304
|
-
* them under the same unwind, with no locator and no second injection path:
|
|
305
|
-
*
|
|
306
|
-
* ```ts
|
|
307
|
-
* constructor(private together: Together<[RateCard, Ledger], [RateMirror]>) {}
|
|
308
|
-
*
|
|
309
|
-
* await this.together.run(async ([rates, ledger], [mirror]) => { await mirror.refresh(); });
|
|
310
|
-
* ```
|
|
311
|
-
*
|
|
312
|
-
* Two lists rather than one, because in a signature an entity and a provider are both
|
|
313
|
-
* written as a class name and their instance types do not separate them — the type would
|
|
314
|
-
* have to guess, by looking for methods or for a brand, and both answers are worse than
|
|
315
|
-
* saying it. They are two different facts anyway: what the unwind covers, and what is
|
|
316
|
-
* rebuilt to make that true.
|
|
317
|
-
*
|
|
318
|
-
* **All or nothing is the promise; isolation is not.** On one engine the members are
|
|
319
|
-
* rebuilt over a transaction and the engine gives both. Across engines a transaction
|
|
320
|
-
* cannot exist, so the frame keeps the before-image of each write and replays the
|
|
321
|
-
* inverse in reverse order — the unwind holds, the isolation does not, and a reader
|
|
322
|
-
* between two writes sees the half. The boot says which of the two it built rather
|
|
323
|
-
* than letting the author assume the stronger one.
|
|
324
|
-
*/
|
|
116
|
+
/** `Together<[Account, Ledger]>` — writes that stand or fall as one. */
|
|
325
117
|
export interface Together<E extends readonly unknown[], P extends readonly unknown[] = []> {
|
|
326
118
|
run<R>(fn: (entities: { [K in keyof E]: Storage<E[K]> }, providers: P) => Promise<R>): Promise<R>;
|
|
327
119
|
}
|
|
@@ -329,12 +121,6 @@ export interface Together<E extends readonly unknown[], P extends readonly unkno
|
|
|
329
121
|
/**
|
|
330
122
|
* The container key of a frame — `[['Account', 'Ledger'], ['RateMirror']]` →
|
|
331
123
|
* 'Account+Ledger|RateMirrorTogether'.
|
|
332
|
-
*
|
|
333
|
-
* The DECLARED order, not a sorted one. The tuples are what the callback destructures, so
|
|
334
|
-
* reordering here would hand `[ledger, accounts]` to a signature that says the opposite —
|
|
335
|
-
* the type and the runtime disagreeing about the same line. Two orders of one frame are
|
|
336
|
-
* therefore two keys and two registrations; they cost nothing, a frame holding no state
|
|
337
|
-
* between runs.
|
|
338
124
|
*/
|
|
339
125
|
export function togetherKeyOf(entities: readonly string[], providers: readonly string[] = []): string {
|
|
340
126
|
const named = entities.map(upperFirst).join(SEPARATOR);
|
|
@@ -346,13 +132,7 @@ const SEPARATOR = '+';
|
|
|
346
132
|
/** Separates the two lists — what the unwind covers, and what is rebuilt to make it true. */
|
|
347
133
|
const KINDS = '|';
|
|
348
134
|
|
|
349
|
-
/**
|
|
350
|
-
* The members behind a frame key, or `undefined` when the key is not one.
|
|
351
|
-
*
|
|
352
|
-
* The dual of the line above, and here for the reason `factOfEmitKey` is: the boot reads
|
|
353
|
-
* the key back out of a handler's `deps` to know which frames to build. A key and the way
|
|
354
|
-
* to undo it belong together — the pair that is split is the pair that drifts.
|
|
355
|
-
*/
|
|
135
|
+
/** The members behind a frame key, or `undefined` when the key is not one. */
|
|
356
136
|
export function membersOfTogetherKey(key: string): { entities: string[]; providers: string[] } | undefined {
|
|
357
137
|
if (key.length <= FRAME.length || !key.endsWith(FRAME)) return undefined;
|
|
358
138
|
const [entities, providers = ''] = key.slice(0, -FRAME.length).split(KINDS);
|