@bett3r-dev/pv3 1.0.0 → 2.5.1
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/CHANGELOG.md +329 -0
- package/build/adapters/cache/memory/index.d.ts.map +1 -1
- package/build/adapters/cache/memory/index.js +93 -20
- package/build/adapters/cache/memory/index.js.map +1 -1
- package/build/adapters/cache/memory/index.test.d.ts +2 -0
- package/build/adapters/cache/memory/index.test.d.ts.map +1 -0
- package/build/adapters/cache/memory/index.test.js +98 -0
- package/build/adapters/cache/memory/index.test.js.map +1 -0
- package/build/adapters/configuration/dotEnv.d.ts.map +1 -1
- package/build/adapters/configuration/dotEnv.js.map +1 -1
- package/build/adapters/database/memory/index.d.ts +5 -1
- package/build/adapters/database/memory/index.d.ts.map +1 -1
- package/build/adapters/database/memory/index.js +336 -44
- package/build/adapters/database/memory/index.js.map +1 -1
- package/build/adapters/database/memory/index.test.d.ts +2 -0
- package/build/adapters/database/memory/index.test.d.ts.map +1 -0
- package/build/adapters/database/memory/index.test.js +167 -0
- package/build/adapters/database/memory/index.test.js.map +1 -0
- package/build/adapters/database/memory/pagingCursorZero.test.d.ts +2 -0
- package/build/adapters/database/memory/pagingCursorZero.test.d.ts.map +1 -0
- package/build/adapters/database/memory/pagingCursorZero.test.js +60 -0
- package/build/adapters/database/memory/pagingCursorZero.test.js.map +1 -0
- package/build/adapters/database/memory/pagingVanishedCursor.test.d.ts +2 -0
- package/build/adapters/database/memory/pagingVanishedCursor.test.d.ts.map +1 -0
- package/build/adapters/database/memory/pagingVanishedCursor.test.js +72 -0
- package/build/adapters/database/memory/pagingVanishedCursor.test.js.map +1 -0
- package/build/adapters/endpoints/addAuthUser/index.d.ts +6 -4
- package/build/adapters/endpoints/addAuthUser/index.d.ts.map +1 -1
- package/build/adapters/endpoints/addAuthUser/index.js +12 -31
- package/build/adapters/endpoints/addAuthUser/index.js.map +1 -1
- package/build/adapters/endpoints/addDevAuthUser/index.d.ts +32 -0
- package/build/adapters/endpoints/addDevAuthUser/index.d.ts.map +1 -0
- package/build/adapters/endpoints/addDevAuthUser/index.js +39 -0
- package/build/adapters/endpoints/addDevAuthUser/index.js.map +1 -0
- package/build/adapters/endpoints/asyncLocalStorage/__tests__/asyncLocalStorage.test.d.ts +2 -0
- package/build/adapters/endpoints/asyncLocalStorage/__tests__/asyncLocalStorage.test.d.ts.map +1 -0
- package/build/adapters/endpoints/asyncLocalStorage/__tests__/asyncLocalStorage.test.js +97 -0
- package/build/adapters/endpoints/asyncLocalStorage/__tests__/asyncLocalStorage.test.js.map +1 -0
- package/build/adapters/endpoints/asyncLocalStorage/index.d.ts +22 -0
- package/build/adapters/endpoints/asyncLocalStorage/index.d.ts.map +1 -0
- package/build/adapters/endpoints/asyncLocalStorage/index.js +62 -0
- package/build/adapters/endpoints/asyncLocalStorage/index.js.map +1 -0
- package/build/adapters/endpoints/endpointValidation/__tests__/endpointValidation.test.d.ts +2 -0
- package/build/adapters/endpoints/endpointValidation/__tests__/endpointValidation.test.d.ts.map +1 -0
- package/build/adapters/endpoints/endpointValidation/__tests__/endpointValidation.test.js +98 -0
- package/build/adapters/endpoints/endpointValidation/__tests__/endpointValidation.test.js.map +1 -0
- package/build/adapters/endpoints/endpointValidation/index.d.ts +2 -2
- package/build/adapters/endpoints/endpointValidation/index.d.ts.map +1 -1
- package/build/adapters/endpoints/endpointValidation/index.js +19 -9
- package/build/adapters/endpoints/endpointValidation/index.js.map +1 -1
- package/build/adapters/endpoints/genericMiddleware/index.d.ts +23 -0
- package/build/adapters/endpoints/genericMiddleware/index.d.ts.map +1 -0
- package/build/adapters/endpoints/genericMiddleware/index.js +30 -0
- package/build/adapters/endpoints/genericMiddleware/index.js.map +1 -0
- package/build/adapters/endpoints/httpMethodOverride/index.d.ts +8 -0
- package/build/adapters/endpoints/httpMethodOverride/index.d.ts.map +1 -0
- package/build/adapters/endpoints/httpMethodOverride/index.js +44 -0
- package/build/adapters/endpoints/httpMethodOverride/index.js.map +1 -0
- package/build/adapters/endpoints/index.d.ts +5 -0
- package/build/adapters/endpoints/index.d.ts.map +1 -1
- package/build/adapters/endpoints/index.js +5 -1
- package/build/adapters/endpoints/index.js.map +1 -1
- package/build/adapters/endpoints/localAuthorization/index.d.ts +1 -0
- package/build/adapters/endpoints/localAuthorization/index.js +2 -0
- package/build/adapters/endpoints/localAuthorization/index.js.map +1 -1
- package/build/adapters/endpoints/mapQueryFromHeaders/index.d.ts +8 -0
- package/build/adapters/endpoints/mapQueryFromHeaders/index.d.ts.map +1 -0
- package/build/adapters/endpoints/mapQueryFromHeaders/index.js +36 -0
- package/build/adapters/endpoints/mapQueryFromHeaders/index.js.map +1 -0
- package/build/adapters/endpoints/tcpConsumer/index.d.ts.map +1 -1
- package/build/adapters/endpoints/tcpConsumer/index.js +8 -7
- package/build/adapters/endpoints/tcpConsumer/index.js.map +1 -1
- package/build/adapters/endpoints/userSession/__tests__/userSession.test.d.ts +2 -0
- package/build/adapters/endpoints/userSession/__tests__/userSession.test.d.ts.map +1 -0
- package/build/adapters/endpoints/userSession/__tests__/userSession.test.js +175 -0
- package/build/adapters/endpoints/userSession/__tests__/userSession.test.js.map +1 -0
- package/build/adapters/endpoints/userSession/index.d.ts +2 -2
- package/build/adapters/endpoints/userSession/index.d.ts.map +1 -1
- package/build/adapters/endpoints/userSession/index.js +36 -2
- package/build/adapters/endpoints/userSession/index.js.map +1 -1
- package/build/adapters/eventstore/database.d.ts.map +1 -1
- package/build/adapters/eventstore/database.js +261 -58
- package/build/adapters/eventstore/database.js.map +1 -1
- package/build/adapters/eventstore/database.test.d.ts +2 -0
- package/build/adapters/eventstore/database.test.d.ts.map +1 -0
- package/build/adapters/eventstore/database.test.js +123 -0
- package/build/adapters/eventstore/database.test.js.map +1 -0
- package/build/adapters/infrastructure/local/index.d.ts +2 -2
- package/build/adapters/infrastructure/local/index.d.ts.map +1 -1
- package/build/adapters/infrastructure/local/index.js +3 -3
- package/build/adapters/infrastructure/local/index.js.map +1 -1
- package/build/adapters/logger/__tests__/json.test.d.ts +2 -0
- package/build/adapters/logger/__tests__/json.test.d.ts.map +1 -0
- package/build/adapters/logger/__tests__/json.test.js +125 -0
- package/build/adapters/logger/__tests__/json.test.js.map +1 -0
- package/build/adapters/logger/console.d.ts.map +1 -1
- package/build/adapters/logger/console.js +4 -2
- package/build/adapters/logger/console.js.map +1 -1
- package/build/adapters/logger/http.d.ts +3 -0
- package/build/adapters/logger/http.d.ts.map +1 -0
- package/build/adapters/logger/http.js +49 -0
- package/build/adapters/logger/http.js.map +1 -0
- package/build/adapters/logger/index.d.ts +3 -0
- package/build/adapters/logger/index.d.ts.map +1 -1
- package/build/adapters/logger/index.js +3 -0
- package/build/adapters/logger/index.js.map +1 -1
- package/build/adapters/logger/json.d.ts +3 -0
- package/build/adapters/logger/json.d.ts.map +1 -0
- package/build/adapters/logger/json.js +41 -0
- package/build/adapters/logger/json.js.map +1 -0
- package/build/adapters/logger/stdout.d.ts +3 -0
- package/build/adapters/logger/stdout.d.ts.map +1 -0
- package/build/adapters/logger/stdout.js +52 -0
- package/build/adapters/logger/stdout.js.map +1 -0
- package/build/index.d.ts +3 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -1
- package/build/index.js.map +1 -1
- package/build/libraries/deployment-units/computeMDUs.d.ts +11 -0
- package/build/libraries/deployment-units/computeMDUs.d.ts.map +1 -0
- package/build/libraries/deployment-units/computeMDUs.js +695 -0
- package/build/libraries/deployment-units/computeMDUs.js.map +1 -0
- package/build/libraries/deployment-units/computeMDUs.test.d.ts +2 -0
- package/build/libraries/deployment-units/computeMDUs.test.d.ts.map +1 -0
- package/build/libraries/deployment-units/computeMDUs.test.js +996 -0
- package/build/libraries/deployment-units/computeMDUs.test.js.map +1 -0
- package/build/libraries/deployment-units/index.d.ts +6 -0
- package/build/libraries/deployment-units/index.d.ts.map +1 -0
- package/build/libraries/deployment-units/index.js +8 -0
- package/build/libraries/deployment-units/index.js.map +1 -0
- package/build/libraries/deployment-units/manifestWriter.d.ts +11 -0
- package/build/libraries/deployment-units/manifestWriter.d.ts.map +1 -0
- package/build/libraries/deployment-units/manifestWriter.js +28 -0
- package/build/libraries/deployment-units/manifestWriter.js.map +1 -0
- package/build/libraries/deployment-units/types.d.ts +43 -0
- package/build/libraries/deployment-units/types.d.ts.map +1 -0
- package/build/libraries/deployment-units/types.js +3 -0
- package/build/libraries/deployment-units/types.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/defaultVisibilityThings.readmodel.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/defaultVisibilityThings.readmodel.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/defaultVisibilityThings.readmodel.js +17 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/defaultVisibilityThings.readmodel.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupA/things.readmodel.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupA/things.readmodel.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupA/things.readmodel.js +13 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupA/things.readmodel.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupB/things.readmodel.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupB/things.readmodel.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupB/things.readmodel.js +12 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/dupB/things.readmodel.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/publicThings.readmodel.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/publicThings.readmodel.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/publicThings.readmodel.js +21 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/publicThings.readmodel.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/queryOnlyThings.readmodel.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/queryOnlyThings.readmodel.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/queryOnlyThings.readmodel.js +16 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/queryOnlyThings.readmodel.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/subscribingThings.readmodel.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/subscribingThings.readmodel.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/subscribingThings.readmodel.js +14 -0
- package/build/libraries/eventsourcing/__tests__/fixtures/subscribingThings.readmodel.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/queryOnlyReadmodel.test.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/queryOnlyReadmodel.test.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/queryOnlyReadmodel.test.js +88 -0
- package/build/libraries/eventsourcing/__tests__/queryOnlyReadmodel.test.js.map +1 -0
- package/build/libraries/eventsourcing/__tests__/queryVisibility.test.d.ts +2 -0
- package/build/libraries/eventsourcing/__tests__/queryVisibility.test.d.ts.map +1 -0
- package/build/libraries/eventsourcing/__tests__/queryVisibility.test.js +82 -0
- package/build/libraries/eventsourcing/__tests__/queryVisibility.test.js.map +1 -0
- package/build/libraries/eventsourcing/commandHandlers/index.d.ts +40 -0
- package/build/libraries/eventsourcing/commandHandlers/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/commandHandlers/index.js +1065 -0
- package/build/libraries/eventsourcing/commandHandlers/index.js.map +1 -0
- package/build/libraries/eventsourcing/commandTemplates/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/commandTemplates/index.js.map +1 -0
- package/build/libraries/eventsourcing/commandTemplates/multiStream.d.ts +7 -0
- package/build/libraries/eventsourcing/commandTemplates/multiStream.d.ts.map +1 -0
- package/build/libraries/eventsourcing/commandTemplates/multiStream.js +116 -0
- package/build/libraries/eventsourcing/commandTemplates/multiStream.js.map +1 -0
- package/build/libraries/eventsourcing/commandTemplates/snapshot.d.ts +108 -0
- package/build/libraries/eventsourcing/commandTemplates/snapshot.d.ts.map +1 -0
- package/build/libraries/eventsourcing/commandTemplates/snapshot.js +127 -0
- package/build/libraries/eventsourcing/commandTemplates/snapshot.js.map +1 -0
- package/build/libraries/eventsourcing/eventHandlers/__tests__/queryResponseFormatterCaller.test.d.ts +2 -0
- package/build/libraries/eventsourcing/eventHandlers/__tests__/queryResponseFormatterCaller.test.d.ts.map +1 -0
- package/build/libraries/eventsourcing/eventHandlers/__tests__/queryResponseFormatterCaller.test.js +77 -0
- package/build/libraries/eventsourcing/eventHandlers/__tests__/queryResponseFormatterCaller.test.js.map +1 -0
- package/build/libraries/eventsourcing/eventHandlers/index.d.ts +52 -0
- package/build/libraries/eventsourcing/eventHandlers/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/eventHandlers/index.js +474 -0
- package/build/libraries/eventsourcing/eventHandlers/index.js.map +1 -0
- package/build/libraries/eventsourcing/executionContext.d.ts +50 -0
- package/build/libraries/eventsourcing/executionContext.d.ts.map +1 -0
- package/build/libraries/eventsourcing/executionContext.js +10 -0
- package/build/libraries/eventsourcing/executionContext.js.map +1 -0
- package/build/libraries/eventsourcing/idempotencyChecks/index.d.ts +5 -0
- package/build/libraries/eventsourcing/idempotencyChecks/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/idempotencyChecks/index.js +26 -0
- package/build/libraries/eventsourcing/idempotencyChecks/index.js.map +1 -0
- package/build/libraries/eventsourcing/index.d.ts +14 -0
- package/build/libraries/eventsourcing/index.d.ts.map +1 -0
- package/build/{ports → libraries}/eventsourcing/index.js +50 -15
- package/build/{ports → libraries}/eventsourcing/index.js.map +1 -1
- package/build/libraries/eventsourcing/invariants/combinators.d.ts +4 -0
- package/build/libraries/eventsourcing/invariants/combinators.d.ts.map +1 -0
- package/build/{ports → libraries}/eventsourcing/invariants/combinators.js +3 -3
- package/build/libraries/eventsourcing/invariants/combinators.js.map +1 -0
- package/build/libraries/eventsourcing/invariants/common.d.ts +15 -0
- package/build/libraries/eventsourcing/invariants/common.d.ts.map +1 -0
- package/build/libraries/eventsourcing/invariants/common.js +27 -0
- package/build/libraries/eventsourcing/invariants/common.js.map +1 -0
- package/build/libraries/eventsourcing/invariants/comparisons.d.ts +16 -0
- package/build/libraries/eventsourcing/invariants/comparisons.d.ts.map +1 -0
- package/build/libraries/eventsourcing/invariants/comparisons.js +35 -0
- package/build/libraries/eventsourcing/invariants/comparisons.js.map +1 -0
- package/build/libraries/eventsourcing/invariants/comparisons.test.d.ts +2 -0
- package/build/libraries/eventsourcing/invariants/comparisons.test.d.ts.map +1 -0
- package/build/libraries/eventsourcing/invariants/comparisons.test.js +25 -0
- package/build/libraries/eventsourcing/invariants/comparisons.test.js.map +1 -0
- package/build/libraries/eventsourcing/invariants/index.d.ts +17 -0
- package/build/libraries/eventsourcing/invariants/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/invariants/index.js +47 -0
- package/build/libraries/eventsourcing/invariants/index.js.map +1 -0
- package/build/libraries/eventsourcing/invariants/stateExistance.d.ts +4 -0
- package/build/libraries/eventsourcing/invariants/stateExistance.d.ts.map +1 -0
- package/build/libraries/eventsourcing/invariants/stateExistance.js +22 -0
- package/build/libraries/eventsourcing/invariants/stateExistance.js.map +1 -0
- package/build/libraries/eventsourcing/subscriptions/__tests__/sseSubscriptions.test.d.ts +2 -0
- package/build/libraries/eventsourcing/subscriptions/__tests__/sseSubscriptions.test.d.ts.map +1 -0
- package/build/libraries/eventsourcing/subscriptions/__tests__/sseSubscriptions.test.js +563 -0
- package/build/libraries/eventsourcing/subscriptions/__tests__/sseSubscriptions.test.js.map +1 -0
- package/build/libraries/eventsourcing/subscriptions/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/subscriptions/index.js.map +1 -0
- package/build/libraries/eventsourcing/subscriptions/sseSubscriptions.d.ts +5 -0
- package/build/libraries/eventsourcing/subscriptions/sseSubscriptions.d.ts.map +1 -0
- package/build/libraries/eventsourcing/subscriptions/sseSubscriptions.js +198 -0
- package/build/libraries/eventsourcing/subscriptions/sseSubscriptions.js.map +1 -0
- package/build/libraries/eventsourcing/utils/aggregateBuilder.d.ts +5 -0
- package/build/libraries/eventsourcing/utils/aggregateBuilder.d.ts.map +1 -0
- package/build/{ports → libraries}/eventsourcing/utils/aggregateBuilder.js +17 -3
- package/build/libraries/eventsourcing/utils/aggregateBuilder.js.map +1 -0
- package/build/libraries/eventsourcing/utils/commandBuilder.d.ts +3 -0
- package/build/libraries/eventsourcing/utils/commandBuilder.d.ts.map +1 -0
- package/build/{ports → libraries}/eventsourcing/utils/commandBuilder.js +44 -1
- package/build/libraries/eventsourcing/utils/commandBuilder.js.map +1 -0
- package/build/{ports → libraries}/eventsourcing/utils/eventHandlerBuilder.d.ts +2 -2
- package/build/libraries/eventsourcing/utils/eventHandlerBuilder.d.ts.map +1 -0
- package/build/libraries/eventsourcing/utils/eventHandlerBuilder.js.map +1 -0
- package/build/libraries/eventsourcing/utils/externalSystemBuilder.d.ts +5 -0
- package/build/libraries/eventsourcing/utils/externalSystemBuilder.d.ts.map +1 -0
- package/build/libraries/eventsourcing/utils/externalSystemBuilder.js +43 -0
- package/build/libraries/eventsourcing/utils/externalSystemBuilder.js.map +1 -0
- package/build/libraries/eventsourcing/utils/index.d.ts +22 -0
- package/build/libraries/eventsourcing/utils/index.d.ts.map +1 -0
- package/build/libraries/eventsourcing/utils/index.js +88 -0
- package/build/libraries/eventsourcing/utils/index.js.map +1 -0
- package/build/libraries/eventsourcing/utils/policyBuilder.d.ts +4 -0
- package/build/libraries/eventsourcing/utils/policyBuilder.d.ts.map +1 -0
- package/build/libraries/eventsourcing/utils/policyBuilder.js +53 -0
- package/build/libraries/eventsourcing/utils/policyBuilder.js.map +1 -0
- package/build/libraries/eventsourcing/utils/readmodelBuilder.d.ts +6 -0
- package/build/libraries/eventsourcing/utils/readmodelBuilder.d.ts.map +1 -0
- package/build/libraries/eventsourcing/utils/readmodelBuilder.js +68 -0
- package/build/libraries/eventsourcing/utils/readmodelBuilder.js.map +1 -0
- package/build/libraries/localOutbox/index.d.ts +6 -0
- package/build/libraries/localOutbox/index.d.ts.map +1 -0
- package/build/libraries/localOutbox/index.js +72 -0
- package/build/libraries/localOutbox/index.js.map +1 -0
- package/build/libraries/modulePath.d.ts +14 -0
- package/build/libraries/modulePath.d.ts.map +1 -0
- package/build/libraries/modulePath.js +21 -0
- package/build/libraries/modulePath.js.map +1 -0
- package/build/libraries/modules/fs.d.ts +2 -4
- package/build/libraries/modules/fs.d.ts.map +1 -1
- package/build/libraries/modules/fs.js +21 -84
- package/build/libraries/modules/fs.js.map +1 -1
- package/build/libraries/modules/index.d.ts +2 -0
- package/build/libraries/modules/index.d.ts.map +1 -1
- package/build/libraries/modules/index.js +2 -0
- package/build/libraries/modules/index.js.map +1 -1
- package/build/libraries/modules/scopedPortsView.d.ts +42 -0
- package/build/libraries/modules/scopedPortsView.d.ts.map +1 -0
- package/build/libraries/modules/scopedPortsView.js +55 -0
- package/build/libraries/modules/scopedPortsView.js.map +1 -0
- package/build/libraries/modules/scopedPortsView.test.d.ts +10 -0
- package/build/libraries/modules/scopedPortsView.test.d.ts.map +1 -0
- package/build/libraries/modules/scopedPortsView.test.js +103 -0
- package/build/libraries/modules/scopedPortsView.test.js.map +1 -0
- package/build/libraries/modules/selectiveLoader.d.ts +21 -0
- package/build/libraries/modules/selectiveLoader.d.ts.map +1 -0
- package/build/libraries/modules/selectiveLoader.js +164 -0
- package/build/libraries/modules/selectiveLoader.js.map +1 -0
- package/build/libraries/modules/selectiveLoader.test.d.ts +2 -0
- package/build/libraries/modules/selectiveLoader.test.d.ts.map +1 -0
- package/build/libraries/modules/selectiveLoader.test.js +471 -0
- package/build/libraries/modules/selectiveLoader.test.js.map +1 -0
- package/build/libraries/openApi/pruneUnusedRef.d.ts.map +1 -1
- package/build/libraries/openApi/pruneUnusedRef.js.map +1 -1
- package/build/libraries/tcp/index.d.ts +0 -1
- package/build/libraries/tcp/index.d.ts.map +1 -1
- package/build/libraries/tcp/index.js +32 -9
- package/build/libraries/tcp/index.js.map +1 -1
- package/build/libraries/tcp/types.d.ts +0 -1
- package/build/libraries/tcp/types.d.ts.map +1 -1
- package/build/libraries/validation/__tests__/readmodelQuerySchema.test.d.ts +2 -0
- package/build/libraries/validation/__tests__/readmodelQuerySchema.test.d.ts.map +1 -0
- package/build/libraries/validation/__tests__/readmodelQuerySchema.test.js +100 -0
- package/build/libraries/validation/__tests__/readmodelQuerySchema.test.js.map +1 -0
- package/build/libraries/validation/__tests__/validation.test.js +17 -7
- package/build/libraries/validation/__tests__/validation.test.js.map +1 -1
- package/build/libraries/validation/index.d.ts +3 -3
- package/build/libraries/validation/index.d.ts.map +1 -1
- package/build/libraries/validation/index.js +49 -15
- package/build/libraries/validation/index.js.map +1 -1
- package/build/ports/authentication/index.js.map +1 -1
- package/build/ports/authentication/index.test.d.ts +2 -0
- package/build/ports/authentication/index.test.d.ts.map +1 -0
- package/build/ports/authentication/index.test.js +38 -0
- package/build/ports/authentication/index.test.js.map +1 -0
- package/build/ports/base.d.ts.map +1 -1
- package/build/ports/base.js +39 -5
- package/build/ports/base.js.map +1 -1
- package/build/ports/base.test.d.ts +2 -0
- package/build/ports/base.test.d.ts.map +1 -0
- package/build/ports/base.test.js +92 -0
- package/build/ports/base.test.js.map +1 -0
- package/build/ports/cache/index.js.map +1 -1
- package/build/ports/cache/index.test.d.ts +2 -0
- package/build/ports/cache/index.test.d.ts.map +1 -0
- package/build/ports/cache/index.test.js +43 -0
- package/build/ports/cache/index.test.js.map +1 -0
- package/build/ports/configuration/__tests__/cliArgs.test.d.ts +2 -0
- package/build/ports/configuration/__tests__/cliArgs.test.d.ts.map +1 -0
- package/build/ports/configuration/__tests__/cliArgs.test.js +158 -0
- package/build/ports/configuration/__tests__/cliArgs.test.js.map +1 -0
- package/build/ports/configuration/__tests__/configurationPortEmitter.test.d.ts +2 -0
- package/build/ports/configuration/__tests__/configurationPortEmitter.test.d.ts.map +1 -0
- package/build/ports/configuration/__tests__/configurationPortEmitter.test.js +63 -0
- package/build/ports/configuration/__tests__/configurationPortEmitter.test.js.map +1 -0
- package/build/ports/configuration/__tests__/getArgsSync.test.d.ts +2 -0
- package/build/ports/configuration/__tests__/getArgsSync.test.d.ts.map +1 -0
- package/build/ports/configuration/__tests__/getArgsSync.test.js +85 -0
- package/build/ports/configuration/__tests__/getArgsSync.test.js.map +1 -0
- package/build/ports/configuration/args.d.ts +50 -43
- package/build/ports/configuration/args.d.ts.map +1 -1
- package/build/ports/configuration/args.js +76 -13
- package/build/ports/configuration/args.js.map +1 -1
- package/build/ports/configuration/common.js +1 -2
- package/build/ports/configuration/common.js.map +1 -1
- package/build/ports/configuration/index.d.ts +1 -1
- package/build/ports/configuration/index.d.ts.map +1 -1
- package/build/ports/configuration/index.js +85 -17
- package/build/ports/configuration/index.js.map +1 -1
- package/build/ports/configuration/localConfig.d.ts.map +1 -1
- package/build/ports/configuration/localConfig.js +46 -27
- package/build/ports/configuration/localConfig.js.map +1 -1
- package/build/ports/database/index.d.ts +1 -2
- package/build/ports/database/index.d.ts.map +1 -1
- package/build/ports/database/index.js +23 -17
- package/build/ports/database/index.js.map +1 -1
- package/build/ports/database/index.test.d.ts +2 -0
- package/build/ports/database/index.test.d.ts.map +1 -0
- package/build/ports/database/index.test.js +43 -0
- package/build/ports/database/index.test.js.map +1 -0
- package/build/ports/endpoints/__tests__/declarationSite.test.d.ts +2 -0
- package/build/ports/endpoints/__tests__/declarationSite.test.d.ts.map +1 -0
- package/build/ports/endpoints/__tests__/declarationSite.test.js +165 -0
- package/build/ports/endpoints/__tests__/declarationSite.test.js.map +1 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/appLoginUrl.d.ts +9 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/appLoginUrl.d.ts.map +1 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/appLoginUrl.js +20 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/appLoginUrl.js.map +1 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/index.d.ts +10 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/index.d.ts.map +1 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/index.js +21 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/index.js.map +1 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/orders.endpoints.d.ts +15 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/orders.endpoints.d.ts.map +1 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/orders.endpoints.js +46 -0
- package/build/ports/endpoints/__tests__/fixtures/modules/sales/orders.endpoints.js.map +1 -0
- package/build/ports/endpoints/__tests__/manifestEndpoints.test.d.ts +2 -0
- package/build/ports/endpoints/__tests__/manifestEndpoints.test.d.ts.map +1 -0
- package/build/ports/endpoints/__tests__/manifestEndpoints.test.js +117 -0
- package/build/ports/endpoints/__tests__/manifestEndpoints.test.js.map +1 -0
- package/build/ports/endpoints/declarationSite.d.ts +63 -0
- package/build/ports/endpoints/declarationSite.d.ts.map +1 -0
- package/build/ports/endpoints/declarationSite.js +126 -0
- package/build/ports/endpoints/declarationSite.js.map +1 -0
- package/build/ports/endpoints/health.d.ts +26 -0
- package/build/ports/endpoints/health.d.ts.map +1 -0
- package/build/ports/endpoints/health.js +96 -0
- package/build/ports/endpoints/health.js.map +1 -0
- package/build/ports/endpoints/index.d.ts +43 -7
- package/build/ports/endpoints/index.d.ts.map +1 -1
- package/build/ports/endpoints/index.js +317 -67
- package/build/ports/endpoints/index.js.map +1 -1
- package/build/ports/endpoints/openApi.d.ts +3 -2
- package/build/ports/endpoints/openApi.d.ts.map +1 -1
- package/build/ports/endpoints/openApi.js +184 -55
- package/build/ports/endpoints/openApi.js.map +1 -1
- package/build/ports/endpoints/utils.d.ts.map +1 -1
- package/build/ports/endpoints/utils.js.map +1 -1
- package/build/ports/eventstore/index.d.ts.map +1 -1
- package/build/ports/eventstore/index.js +37 -5
- package/build/ports/eventstore/index.js.map +1 -1
- package/build/ports/eventstore/index.test.d.ts +2 -0
- package/build/ports/eventstore/index.test.d.ts.map +1 -0
- package/build/ports/eventstore/index.test.js +68 -0
- package/build/ports/eventstore/index.test.js.map +1 -0
- package/build/ports/infrastructure/index.d.ts +61 -23
- package/build/ports/infrastructure/index.d.ts.map +1 -1
- package/build/ports/infrastructure/index.js +187 -37
- package/build/ports/infrastructure/index.js.map +1 -1
- package/build/ports/infrastructure/index.test.d.ts +2 -0
- package/build/ports/infrastructure/index.test.d.ts.map +1 -0
- package/build/ports/infrastructure/index.test.js +228 -0
- package/build/ports/infrastructure/index.test.js.map +1 -0
- package/build/ports/infrastructure/utils.d.ts +2 -1
- package/build/ports/infrastructure/utils.d.ts.map +1 -1
- package/build/ports/infrastructure/utils.js +48 -22
- package/build/ports/infrastructure/utils.js.map +1 -1
- package/build/ports/logger/__tests__/logger.test.d.ts +2 -0
- package/build/ports/logger/__tests__/logger.test.d.ts.map +1 -0
- package/build/ports/logger/__tests__/logger.test.js +69 -0
- package/build/ports/logger/__tests__/logger.test.js.map +1 -0
- package/build/ports/logger/index.d.ts.map +1 -1
- package/build/ports/logger/index.js +3 -2
- package/build/ports/logger/index.js.map +1 -1
- package/build/utils/__tests__/applyCollectionFilterInMemory.test.d.ts +2 -0
- package/build/utils/__tests__/applyCollectionFilterInMemory.test.d.ts.map +1 -0
- package/build/utils/__tests__/applyCollectionFilterInMemory.test.js +33 -0
- package/build/utils/__tests__/applyCollectionFilterInMemory.test.js.map +1 -0
- package/build/utils/__tests__/decodeObjectQueryParams.test.d.ts +2 -0
- package/build/utils/__tests__/decodeObjectQueryParams.test.d.ts.map +1 -0
- package/build/utils/__tests__/decodeObjectQueryParams.test.js +118 -0
- package/build/utils/__tests__/decodeObjectQueryParams.test.js.map +1 -0
- package/build/utils/index.d.ts +26 -34
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +159 -170
- package/build/utils/index.js.map +1 -1
- package/package.json +31 -11
- package/build/adapters/cache/memory/__tests__/memoryCache.test.d.ts +0 -1
- package/build/adapters/cache/memory/__tests__/memoryCache.test.d.ts.map +0 -1
- package/build/adapters/cache/memory/__tests__/memoryCache.test.js +0 -6
- package/build/adapters/cache/memory/__tests__/memoryCache.test.js.map +0 -1
- package/build/adapters/database/memory/__tests__/memoryDb.test.d.ts +0 -1
- package/build/adapters/database/memory/__tests__/memoryDb.test.d.ts.map +0 -1
- package/build/adapters/database/memory/__tests__/memoryDb.test.js +0 -36
- package/build/adapters/database/memory/__tests__/memoryDb.test.js.map +0 -1
- package/build/ports/endpoints/__tests__/endpointsCall.test.d.ts +0 -2
- package/build/ports/endpoints/__tests__/endpointsCall.test.d.ts.map +0 -1
- package/build/ports/endpoints/__tests__/endpointsCall.test.js +0 -21
- package/build/ports/endpoints/__tests__/endpointsCall.test.js.map +0 -1
- package/build/ports/endpoints/__tests__/test-client-library/base.d.ts +0 -77
- package/build/ports/endpoints/__tests__/test-client-library/base.d.ts.map +0 -1
- package/build/ports/endpoints/__tests__/test-client-library/base.js +0 -91
- package/build/ports/endpoints/__tests__/test-client-library/base.js.map +0 -1
- package/build/ports/endpoints/__tests__/test-client-library/index.d.ts +0 -29
- package/build/ports/endpoints/__tests__/test-client-library/index.d.ts.map +0 -1
- package/build/ports/endpoints/__tests__/test-client-library/index.js +0 -43
- package/build/ports/endpoints/__tests__/test-client-library/index.js.map +0 -1
- package/build/ports/endpoints/__tests__/test-client-library/services/service.d.ts +0 -106
- package/build/ports/endpoints/__tests__/test-client-library/services/service.d.ts.map +0 -1
- package/build/ports/endpoints/__tests__/test-client-library/services/service.js +0 -62
- package/build/ports/endpoints/__tests__/test-client-library/services/service.js.map +0 -1
- package/build/ports/endpoints/__tests__/utils.test.d.ts +0 -1
- package/build/ports/endpoints/__tests__/utils.test.d.ts.map +0 -1
- package/build/ports/endpoints/__tests__/utils.test.js +0 -53
- package/build/ports/endpoints/__tests__/utils.test.js.map +0 -1
- package/build/ports/eventsourcing/__tests__/eventhandlers.test.d.ts +0 -2
- package/build/ports/eventsourcing/__tests__/eventhandlers.test.d.ts.map +0 -1
- package/build/ports/eventsourcing/__tests__/eventhandlers.test.js +0 -35
- package/build/ports/eventsourcing/__tests__/eventhandlers.test.js.map +0 -1
- package/build/ports/eventsourcing/__tests__/invariants.test.d.ts +0 -2
- package/build/ports/eventsourcing/__tests__/invariants.test.d.ts.map +0 -1
- package/build/ports/eventsourcing/__tests__/invariants.test.js +0 -210
- package/build/ports/eventsourcing/__tests__/invariants.test.js.map +0 -1
- package/build/ports/eventsourcing/commandHandlers/index.d.ts +0 -25
- package/build/ports/eventsourcing/commandHandlers/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/commandHandlers/index.js +0 -392
- package/build/ports/eventsourcing/commandHandlers/index.js.map +0 -1
- package/build/ports/eventsourcing/commandTemplates/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/commandTemplates/index.js.map +0 -1
- package/build/ports/eventsourcing/commandTemplates/multiStream.d.ts +0 -4
- package/build/ports/eventsourcing/commandTemplates/multiStream.d.ts.map +0 -1
- package/build/ports/eventsourcing/commandTemplates/multiStream.js +0 -73
- package/build/ports/eventsourcing/commandTemplates/multiStream.js.map +0 -1
- package/build/ports/eventsourcing/commandTemplates/snapshot.d.ts +0 -9
- package/build/ports/eventsourcing/commandTemplates/snapshot.d.ts.map +0 -1
- package/build/ports/eventsourcing/commandTemplates/snapshot.js +0 -39
- package/build/ports/eventsourcing/commandTemplates/snapshot.js.map +0 -1
- package/build/ports/eventsourcing/eventHandlers/index.d.ts +0 -33
- package/build/ports/eventsourcing/eventHandlers/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/eventHandlers/index.js +0 -276
- package/build/ports/eventsourcing/eventHandlers/index.js.map +0 -1
- package/build/ports/eventsourcing/index.d.ts +0 -9
- package/build/ports/eventsourcing/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/invariants/combinators.d.ts +0 -4
- package/build/ports/eventsourcing/invariants/combinators.d.ts.map +0 -1
- package/build/ports/eventsourcing/invariants/combinators.js.map +0 -1
- package/build/ports/eventsourcing/invariants/common.d.ts +0 -10
- package/build/ports/eventsourcing/invariants/common.d.ts.map +0 -1
- package/build/ports/eventsourcing/invariants/common.js +0 -37
- package/build/ports/eventsourcing/invariants/common.js.map +0 -1
- package/build/ports/eventsourcing/invariants/comparisons.d.ts +0 -19
- package/build/ports/eventsourcing/invariants/comparisons.d.ts.map +0 -1
- package/build/ports/eventsourcing/invariants/comparisons.js +0 -83
- package/build/ports/eventsourcing/invariants/comparisons.js.map +0 -1
- package/build/ports/eventsourcing/invariants/index.d.ts +0 -5
- package/build/ports/eventsourcing/invariants/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/invariants/index.js +0 -21
- package/build/ports/eventsourcing/invariants/index.js.map +0 -1
- package/build/ports/eventsourcing/invariants/stateExistance.d.ts +0 -4
- package/build/ports/eventsourcing/invariants/stateExistance.d.ts.map +0 -1
- package/build/ports/eventsourcing/invariants/stateExistance.js +0 -33
- package/build/ports/eventsourcing/invariants/stateExistance.js.map +0 -1
- package/build/ports/eventsourcing/subscriptions/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/subscriptions/index.js.map +0 -1
- package/build/ports/eventsourcing/subscriptions/sseSubscriptions.d.ts +0 -3
- package/build/ports/eventsourcing/subscriptions/sseSubscriptions.d.ts.map +0 -1
- package/build/ports/eventsourcing/subscriptions/sseSubscriptions.js +0 -81
- package/build/ports/eventsourcing/subscriptions/sseSubscriptions.js.map +0 -1
- package/build/ports/eventsourcing/utils/aggregateBuilder.d.ts +0 -4
- package/build/ports/eventsourcing/utils/aggregateBuilder.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/aggregateBuilder.js.map +0 -1
- package/build/ports/eventsourcing/utils/commandBuilder.d.ts +0 -3
- package/build/ports/eventsourcing/utils/commandBuilder.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/commandBuilder.js.map +0 -1
- package/build/ports/eventsourcing/utils/eventHandlerBuilder.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/eventHandlerBuilder.js.map +0 -1
- package/build/ports/eventsourcing/utils/externalSystemBuilder.d.ts +0 -4
- package/build/ports/eventsourcing/utils/externalSystemBuilder.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/externalSystemBuilder.js +0 -34
- package/build/ports/eventsourcing/utils/externalSystemBuilder.js.map +0 -1
- package/build/ports/eventsourcing/utils/index.d.ts +0 -13
- package/build/ports/eventsourcing/utils/index.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/index.js +0 -45
- package/build/ports/eventsourcing/utils/index.js.map +0 -1
- package/build/ports/eventsourcing/utils/policyBuilder.d.ts +0 -3
- package/build/ports/eventsourcing/utils/policyBuilder.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/policyBuilder.js +0 -29
- package/build/ports/eventsourcing/utils/policyBuilder.js.map +0 -1
- package/build/ports/eventsourcing/utils/readmodelBuilder.d.ts +0 -5
- package/build/ports/eventsourcing/utils/readmodelBuilder.d.ts.map +0 -1
- package/build/ports/eventsourcing/utils/readmodelBuilder.js +0 -45
- package/build/ports/eventsourcing/utils/readmodelBuilder.js.map +0 -1
- package/build/ports/infrastructure/__tests__/fixture/index.d.ts +0 -3
- package/build/ports/infrastructure/__tests__/fixture/index.d.ts.map +0 -1
- package/build/ports/infrastructure/__tests__/fixture/index.js +0 -19
- package/build/ports/infrastructure/__tests__/fixture/index.js.map +0 -1
- package/build/ports/infrastructure/__tests__/fixture/infrastructureServices.d.ts +0 -19
- package/build/ports/infrastructure/__tests__/fixture/infrastructureServices.d.ts.map +0 -1
- package/build/ports/infrastructure/__tests__/fixture/infrastructureServices.js +0 -76
- package/build/ports/infrastructure/__tests__/fixture/infrastructureServices.js.map +0 -1
- package/build/ports/infrastructure/__tests__/fixture/structureState.d.ts +0 -177
- package/build/ports/infrastructure/__tests__/fixture/structureState.d.ts.map +0 -1
- package/build/ports/infrastructure/__tests__/fixture/structureState.js +0 -258
- package/build/ports/infrastructure/__tests__/fixture/structureState.js.map +0 -1
- package/build/ports/infrastructure/__tests__/infrastructure.test.d.ts +0 -2
- package/build/ports/infrastructure/__tests__/infrastructure.test.d.ts.map +0 -1
- package/build/ports/infrastructure/__tests__/infrastructure.test.js +0 -11
- package/build/ports/infrastructure/__tests__/infrastructure.test.js.map +0 -1
- package/src/adapters/cache/index.ts +0 -1
- package/src/adapters/cache/memory/__tests__/memoryCache.test.ts +0 -6
- package/src/adapters/cache/memory/index.ts +0 -142
- package/src/adapters/configuration/__tests__/.env +0 -4
- package/src/adapters/configuration/__tests__/dotEnv.test.ts +0 -38
- package/src/adapters/configuration/dotEnv.ts +0 -33
- package/src/adapters/configuration/index.ts +0 -1
- package/src/adapters/database/index.ts +0 -1
- package/src/adapters/database/memory/__tests__/memoryDb.test.ts +0 -37
- package/src/adapters/database/memory/index.ts +0 -279
- package/src/adapters/endpoints/addAuthUser/index.ts +0 -55
- package/src/adapters/endpoints/endpointValidation/index.ts +0 -26
- package/src/adapters/endpoints/index.ts +0 -4
- package/src/adapters/endpoints/localAuthorization/index.ts +0 -75
- package/src/adapters/endpoints/tcpConsumer/index.ts +0 -69
- package/src/adapters/endpoints/userSession/index.ts +0 -40
- package/src/adapters/eventstore/database.ts +0 -178
- package/src/adapters/eventstore/index.ts +0 -1
- package/src/adapters/infrastructure/index.ts +0 -1
- package/src/adapters/infrastructure/local/index.ts +0 -40
- package/src/adapters/logger/console.ts +0 -42
- package/src/adapters/logger/index.ts +0 -1
- package/src/index.ts +0 -25
- package/src/libraries/modules/fs.ts +0 -88
- package/src/libraries/modules/index.ts +0 -1
- package/src/libraries/openApi/index.ts +0 -1
- package/src/libraries/openApi/pruneUnusedRef.ts +0 -35
- package/src/libraries/tcp/index.ts +0 -98
- package/src/libraries/tcp/types.ts +0 -43
- package/src/libraries/validation/__tests__/validation.test.ts +0 -25
- package/src/libraries/validation/index.ts +0 -48
- package/src/ports/authentication/index.ts +0 -25
- package/src/ports/base.ts +0 -20
- package/src/ports/cache/index.ts +0 -17
- package/src/ports/configuration/__tests__/configurationPort.test.ts +0 -47
- package/src/ports/configuration/args.ts +0 -39
- package/src/ports/configuration/common.ts +0 -12
- package/src/ports/configuration/index.ts +0 -110
- package/src/ports/configuration/localConfig.ts +0 -117
- package/src/ports/database/index.ts +0 -25
- package/src/ports/endpoints/__tests__/endpointsCall.test.ts +0 -20
- package/src/ports/endpoints/__tests__/test-client-library/base.ts +0 -167
- package/src/ports/endpoints/__tests__/test-client-library/index.ts +0 -23
- package/src/ports/endpoints/__tests__/test-client-library/services/service.ts +0 -181
- package/src/ports/endpoints/__tests__/utils.test.ts +0 -54
- package/src/ports/endpoints/index.ts +0 -272
- package/src/ports/endpoints/openApi.ts +0 -191
- package/src/ports/endpoints/utils.ts +0 -31
- package/src/ports/eventsourcing/__tests__/eventhandlers.test.ts +0 -30
- package/src/ports/eventsourcing/__tests__/invariants.test.ts +0 -213
- package/src/ports/eventsourcing/commandHandlers/index.ts +0 -625
- package/src/ports/eventsourcing/commandTemplates/index.ts +0 -2
- package/src/ports/eventsourcing/commandTemplates/multiStream.ts +0 -70
- package/src/ports/eventsourcing/commandTemplates/snapshot.ts +0 -43
- package/src/ports/eventsourcing/eventHandlers/index.ts +0 -429
- package/src/ports/eventsourcing/index.ts +0 -98
- package/src/ports/eventsourcing/invariants/combinators.ts +0 -25
- package/src/ports/eventsourcing/invariants/common.ts +0 -42
- package/src/ports/eventsourcing/invariants/comparisons.ts +0 -90
- package/src/ports/eventsourcing/invariants/index.ts +0 -4
- package/src/ports/eventsourcing/invariants/stateExistance.ts +0 -34
- package/src/ports/eventsourcing/subscriptions/index.ts +0 -1
- package/src/ports/eventsourcing/subscriptions/sseSubscriptions.ts +0 -103
- package/src/ports/eventsourcing/utils/aggregateBuilder.ts +0 -49
- package/src/ports/eventsourcing/utils/commandBuilder.ts +0 -113
- package/src/ports/eventsourcing/utils/eventHandlerBuilder.ts +0 -22
- package/src/ports/eventsourcing/utils/externalSystemBuilder.ts +0 -42
- package/src/ports/eventsourcing/utils/index.ts +0 -25
- package/src/ports/eventsourcing/utils/policyBuilder.ts +0 -31
- package/src/ports/eventsourcing/utils/readmodelBuilder.ts +0 -52
- package/src/ports/eventstore/index.ts +0 -11
- package/src/ports/infrastructure/__tests__/fixture/index.ts +0 -2
- package/src/ports/infrastructure/__tests__/fixture/infrastructureServices.ts +0 -72
- package/src/ports/infrastructure/__tests__/fixture/structureState.ts +0 -254
- package/src/ports/infrastructure/__tests__/infrastructure.test.ts +0 -11
- package/src/ports/infrastructure/index.ts +0 -162
- package/src/ports/infrastructure/utils.ts +0 -130
- package/src/ports/logger/index.ts +0 -34
- package/src/utils/index.ts +0 -186
- package/tsconfig.json +0 -19
- /package/build/{ports → libraries}/eventsourcing/commandTemplates/index.d.ts +0 -0
- /package/build/{ports → libraries}/eventsourcing/commandTemplates/index.js +0 -0
- /package/build/{ports → libraries}/eventsourcing/subscriptions/index.d.ts +0 -0
- /package/build/{ports → libraries}/eventsourcing/subscriptions/index.js +0 -0
- /package/build/{ports → libraries}/eventsourcing/utils/eventHandlerBuilder.js +0 -0
|
@@ -0,0 +1,1065 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createCommandHandlers = exports.handleCommand = exports.defaultEventsourcingLoad = exports.validateInvariants = exports.formatEventSourcedCommandResponse = exports.formatDomainModelCommandResponse = exports.reduceEventsIntoState = exports.defaultCommit = exports.defaultHandler = exports.domainModelCommit = exports.domainModelLoad = exports.loadAggregateState = exports.getNonNoopEventNames = exports.loadStream = exports.getStreamReducer = exports.commitEvents = exports.appendEventsToOwnStreams = exports.prepareEventsToCommit = exports.addMetadata = exports.appendEventsToStream = exports.getEventReducers = exports.formatAggregateGetQueryParams = void 0;
|
|
7
|
+
const bett3r_utils_1 = require("@bett3r-dev/bett3r-utils");
|
|
8
|
+
const jsonschema_definer_1 = __importDefault(require("@bett3r-dev/jsonschema-definer"));
|
|
9
|
+
const pv3_types_1 = require("@bett3r-dev/pv3-types");
|
|
10
|
+
const change_case_1 = require("change-case");
|
|
11
|
+
const ramda_1 = require("ramda");
|
|
12
|
+
const uuidv7_1 = require("uuidv7");
|
|
13
|
+
const reducersByAggregateMap = new Map();
|
|
14
|
+
let getActiveTraceId = () => undefined;
|
|
15
|
+
// Capture the metrics FACADE (not a meter/counter) at module load — that is safe. Resolving a
|
|
16
|
+
// concrete counter here (`metrics.getMeter(...).createCounter(...)`) would bind to the no-op
|
|
17
|
+
// MeterProvider before the host registers its real one and stay a permanent no-op (the OTel
|
|
18
|
+
// dual-api module-load hazard); the counter is instead resolved lazily on first skip below.
|
|
19
|
+
let otelMetrics;
|
|
20
|
+
try {
|
|
21
|
+
const { trace, metrics } = require('@opentelemetry/api');
|
|
22
|
+
getActiveTraceId = () => {
|
|
23
|
+
const span = trace.getActiveSpan();
|
|
24
|
+
const traceId = span?.spanContext().traceId;
|
|
25
|
+
return traceId && traceId !== '00000000000000000000000000000000' ? traceId : undefined;
|
|
26
|
+
};
|
|
27
|
+
otelMetrics = metrics;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// @opentelemetry/api not available
|
|
31
|
+
}
|
|
32
|
+
// Lazily-resolved, memoized counter for declarative-idempotency dedup skips. Every time a
|
|
33
|
+
// `withIdempotencyCheck(...)` short-circuits the command pipeline (the skip branch below), this
|
|
34
|
+
// increments so the otherwise-invisible dedup activity is countable. Resolved on FIRST use —
|
|
35
|
+
// after the host has registered its MeterProvider — never at module load (see note above).
|
|
36
|
+
let idempotencySkipCounter;
|
|
37
|
+
const getIdempotencySkipCounter = () => {
|
|
38
|
+
if (idempotencySkipCounter || !otelMetrics)
|
|
39
|
+
return idempotencySkipCounter;
|
|
40
|
+
idempotencySkipCounter = otelMetrics.getMeter('pv3').createCounter('pv3.command.idempotency_skip', {
|
|
41
|
+
description: 'Declarative withIdempotencyCheck dedup short-circuits: a duplicate command matched an idempotency check and skipped the handler + commit before any application code ran. Labelled by { command, aggregate }.'
|
|
42
|
+
});
|
|
43
|
+
return idempotencySkipCounter;
|
|
44
|
+
};
|
|
45
|
+
/* ─── Optimistic-concurrency retry observability + backoff ──────────────────────────────
|
|
46
|
+
*
|
|
47
|
+
* `executeCommand` has always retried a `ConcurrencyError` up to ten times, IMMEDIATELY and
|
|
48
|
+
* SILENTLY: nothing counted the retries, nothing named the stream that lost, and giving up
|
|
49
|
+
* produced one `logger.error` indistinguishable from any other failed command. That is the
|
|
50
|
+
* wrong shape for a multi-stream command whose fan-out width is a property of the CATALOG —
|
|
51
|
+
* a Composite Item ("Kit") whose component sits in fifty kits re-runs a fifty-one-stream
|
|
52
|
+
* command on every conflict, so contention is the thing that decides whether the design
|
|
53
|
+
* holds, and it was invisible.
|
|
54
|
+
*
|
|
55
|
+
* Three instruments, all `{ command, aggregate }`-labelled and therefore BOUNDED. The
|
|
56
|
+
* contended STREAM is deliberately NOT a label: a stream name is per-entity, so labelling by
|
|
57
|
+
* it makes the series cardinality equal to the catalog. It goes in the log line instead,
|
|
58
|
+
* which is where the "WHICH hot item" question is actually answered.
|
|
59
|
+
*
|
|
60
|
+
* pv3.command.occ_retry one per re-execution — the leading contention indicator.
|
|
61
|
+
* pv3.command.occ_retry_backoff ms actually waited, so backoff can be told apart from
|
|
62
|
+
* latency spent doing work.
|
|
63
|
+
* pv3.command.occ_retry_exhausted PAGE ON THIS. The command failed after the whole budget;
|
|
64
|
+
* for a stock decrement that means an order's stock was
|
|
65
|
+
* never decremented.
|
|
66
|
+
*/
|
|
67
|
+
let occInstruments;
|
|
68
|
+
const getOccInstruments = () => {
|
|
69
|
+
if (occInstruments || !otelMetrics)
|
|
70
|
+
return occInstruments;
|
|
71
|
+
const meter = otelMetrics.getMeter('pv3');
|
|
72
|
+
occInstruments = {
|
|
73
|
+
retry: meter.createCounter('pv3.command.occ_retry', {
|
|
74
|
+
description: 'A command re-executed from the top because its commit lost an optimistic-concurrency check. The leading indicator of write contention on a stream. Labelled by { command, aggregate } — the contended stream is in the accompanying debug log, never a label (per-entity cardinality).'
|
|
75
|
+
}),
|
|
76
|
+
backoff: meter.createHistogram('pv3.command.occ_retry_backoff', {
|
|
77
|
+
description: 'Milliseconds waited before an optimistic-concurrency re-execution (full-jitter, capped). Separates time spent BACKING OFF from time spent working, so a contention problem is not read as a slow command. Labelled by { command, aggregate }.',
|
|
78
|
+
unit: 'ms'
|
|
79
|
+
}),
|
|
80
|
+
exhausted: meter.createCounter('pv3.command.occ_retry_exhausted', {
|
|
81
|
+
description: 'A command that exhausted its optimistic-concurrency retry budget and FAILED — nothing was committed. PAGE ON THIS: for a stock decrement it means an order never decremented its stock. Labelled by { command, aggregate }.'
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
return occInstruments;
|
|
85
|
+
};
|
|
86
|
+
/** The retry budget. Deliberately NOT raised to absorb contention: under sustained
|
|
87
|
+
* contention more attempts mostly add load — the lever is the WAIT below, not the count. */
|
|
88
|
+
const OCC_RETRY_CEILING = 10;
|
|
89
|
+
const OCC_BACKOFF_BASE_MS = 5;
|
|
90
|
+
const OCC_BACKOFF_CAP_MS = 250;
|
|
91
|
+
/**
|
|
92
|
+
* FULL JITTER over an exponentially-growing window, plus a small floor.
|
|
93
|
+
*
|
|
94
|
+
* Immediate retry is what turns one hot stream into a thundering herd: every loser re-reads,
|
|
95
|
+
* re-computes and re-appends in lockstep, so they collide again on the same tick and the
|
|
96
|
+
* conflict rate is preserved rather than drained. Spreading the attempts over a random
|
|
97
|
+
* interval de-synchronizes them, which is what actually lets one of them win. The floor
|
|
98
|
+
* guarantees a non-zero wait even on the first retry (a zero-length "backoff" is not one),
|
|
99
|
+
* and the cap keeps a pathological stream from turning a retry budget into a stall.
|
|
100
|
+
*
|
|
101
|
+
* Budget across all 10 retries (attempts 0..9): floor 10×5ms plus a jitter window of
|
|
102
|
+
* 5+10+20+40+80+160+250+250+250+250 = 1315ms ⇒ **1365ms worst case, ~707ms mean**. Applies
|
|
103
|
+
* to the pooled path only (see the call site).
|
|
104
|
+
*/
|
|
105
|
+
const occBackoffMs = (attempt) => OCC_BACKOFF_BASE_MS + Math.floor(Math.random() * Math.min(2 ** attempt * OCC_BACKOFF_BASE_MS, OCC_BACKOFF_CAP_MS));
|
|
106
|
+
const canSavepoint = (transaction) => typeof transaction.savepoint === 'function'
|
|
107
|
+
&& typeof transaction.rollbackToSavepoint === 'function'
|
|
108
|
+
&& typeof transaction.releaseSavepoint === 'function';
|
|
109
|
+
/**
|
|
110
|
+
* The concurrency mode a command actually runs under — resolved here and never read raw, so the
|
|
111
|
+
* default and the one illegal combination are decided in ONE place.
|
|
112
|
+
*
|
|
113
|
+
* `optimistic` is the default (see `CommandConcurrencyMode` for what each mode costs).
|
|
114
|
+
*
|
|
115
|
+
* A NON-AGGREGATE External System is `unversioned` BY CONSTRUCTION, whatever it declares: its
|
|
116
|
+
* load hands the commit `expectedVersion: null` (below), so every event it writes is stored
|
|
117
|
+
* version-free. Saying so here rather than letting it default to `optimistic` keeps the mode a
|
|
118
|
+
* true description of what reaches the append — which is what the savepoint gate keys on.
|
|
119
|
+
* ONE EXCEPTION, and it is not resolvable here: an aggregate command with a CUSTOM `load`
|
|
120
|
+
* (`multiStream`, `snapshot`'s delegating load aside) bypasses the derivation entirely and keeps
|
|
121
|
+
* whatever expectation its own load built, so its resolved mode describes the savepoint decision
|
|
122
|
+
* rather than the append. See the gate in `executeCommand` for what that costs.
|
|
123
|
+
*
|
|
124
|
+
* And that is exactly why an AGGREGATE may not declare `unversioned`: it would be asking to
|
|
125
|
+
* behave like a non-aggregate. An aggregate reduces its stream to state, and a stream whose
|
|
126
|
+
* events carry no version has no deterministic order to reduce in, so the same events could fold
|
|
127
|
+
* to a different state on every load. Refused LOUDLY — a silent fallback would produce precisely
|
|
128
|
+
* the unorderable stream, and it would be found much later, in the reduced state, by someone with
|
|
129
|
+
* no reason to suspect the declaration.
|
|
130
|
+
*/
|
|
131
|
+
const resolveConcurrencyMode = (commandHandler, command) => {
|
|
132
|
+
if (command?.concurrency === 'unversioned' && commandHandler?.isAggregate)
|
|
133
|
+
throw new pv3_types_1.InternalServerError(`Command '${command.name}' on aggregate '${commandHandler.name}' declares concurrency: 'unversioned', which writes every event with version NULL. An aggregate REDUCES its stream to state, and a version-free stream has no deterministic order to reduce in, so the same events could fold to a different state on every load. Version-free streams belong to non-aggregate External Systems, which reduce nothing. Use 'optimistic' (the default), or 'rebase' if — and only if — this aggregate's events are provably commutative.`, 'UNVERSIONED_CONCURRENCY_ON_AGGREGATE', { aggregate: commandHandler.name, command: command.name });
|
|
134
|
+
return commandHandler?.isAggregate ? (command?.concurrency || 'optimistic') : 'unversioned';
|
|
135
|
+
};
|
|
136
|
+
const validation_1 = require("../../../libraries/validation");
|
|
137
|
+
const utils_1 = require("../../../utils");
|
|
138
|
+
const utils_2 = require("../utils");
|
|
139
|
+
const executionContext_1 = require("../executionContext");
|
|
140
|
+
const formatAggregateGetQueryParams = (params) => ({
|
|
141
|
+
stream: params.stream,
|
|
142
|
+
events: params.names,
|
|
143
|
+
direction: params.backward ? 'backwards' : 'forwards',
|
|
144
|
+
from: params.from,
|
|
145
|
+
limit: params.limit,
|
|
146
|
+
after: params.after,
|
|
147
|
+
before: params.before
|
|
148
|
+
});
|
|
149
|
+
exports.formatAggregateGetQueryParams = formatAggregateGetQueryParams;
|
|
150
|
+
const getEventReducers = (aggregate) => (reducedState /* = { state: aggregate.initialValue() } */, event) => {
|
|
151
|
+
const reducer = aggregate.eventReducers[event.name];
|
|
152
|
+
if (!reducer || reducer === pv3_types_1.ReducerNOOP)
|
|
153
|
+
return reducedState;
|
|
154
|
+
return {
|
|
155
|
+
...reducedState,
|
|
156
|
+
state: reducer(reducedState.state, event.data, event.metadata)
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
exports.getEventReducers = getEventReducers;
|
|
160
|
+
const appendEventsToStream = (logger, eventstore, expectedVersion, transaction, retryAttempts = 0) => (events) => {
|
|
161
|
+
const stream = events[0].stream;
|
|
162
|
+
return events.length
|
|
163
|
+
? eventstore.appendToStream(stream, events, expectedVersion, transaction)
|
|
164
|
+
.catch((err) => {
|
|
165
|
+
if (err.type === 'ConcurrencyError' && expectedVersion === null) {
|
|
166
|
+
if (retryAttempts >= 10) {
|
|
167
|
+
logger.error('Event', events[0].name, 'failed after 10 retries', err);
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
logger.debug('Retrying event', events[0].name, 'due to ConcurrencyError', transaction ? 'with transaction' : 'without transaction');
|
|
171
|
+
return (0, exports.appendEventsToStream)(logger, eventstore, null, transaction, retryAttempts + 1)(events);
|
|
172
|
+
}
|
|
173
|
+
throw err;
|
|
174
|
+
})
|
|
175
|
+
: Promise.resolve([]);
|
|
176
|
+
};
|
|
177
|
+
exports.appendEventsToStream = appendEventsToStream;
|
|
178
|
+
const addMetadata = ({ metadata, context, stream }) => (event) => {
|
|
179
|
+
(0, ramda_1.mergeRight)(metadata || {}, event.metadata || {}); //?
|
|
180
|
+
return {
|
|
181
|
+
stream,
|
|
182
|
+
...event,
|
|
183
|
+
metadata: {
|
|
184
|
+
...(context?.user ? { userId: context.user.id } : {}),
|
|
185
|
+
...(0, ramda_1.mergeRight)(metadata || {}, event.metadata || {})
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
exports.addMetadata = addMetadata;
|
|
190
|
+
const prepareEventsToCommit = (handlerState) => {
|
|
191
|
+
return Promise.resolve(handlerState.events)
|
|
192
|
+
.then(bett3r_utils_1.ensureArray)
|
|
193
|
+
.then((0, bett3r_utils_1.map)((eventFactory) => {
|
|
194
|
+
return { ...eventFactory() };
|
|
195
|
+
}))
|
|
196
|
+
.then((0, bett3r_utils_1.map)((0, exports.addMetadata)(handlerState)));
|
|
197
|
+
};
|
|
198
|
+
exports.prepareEventsToCommit = prepareEventsToCommit;
|
|
199
|
+
/**
|
|
200
|
+
* `expectedVersion` narrowed to the shape the SINGLE-stream append takes.
|
|
201
|
+
*
|
|
202
|
+
* It carries two shapes (see `CommandHandlerState.expectedVersion`): the scalar this
|
|
203
|
+
* path wants, and the per-stream MAP that `multiStream.commit` consumes. A map reaching
|
|
204
|
+
* here means a command paired a multi-stream `load` with the single-stream `commit` —
|
|
205
|
+
* mis-wired, and the one thing we must NOT do about it is coerce it to `undefined`:
|
|
206
|
+
* that would append with no version expectation at all, silently discarding the
|
|
207
|
+
* optimistic-concurrency control the load went to the trouble of computing. Fail loudly.
|
|
208
|
+
*
|
|
209
|
+
* Still exactly this guard now that the default commit can fan out to several streams
|
|
210
|
+
* (`appendEventsToOwnStreams` below): what it produces there is a SCALAR expectation routed to
|
|
211
|
+
* the one stream the load read, never a caller-built per-stream map. A map arriving here is the
|
|
212
|
+
* same mis-wiring it always was.
|
|
213
|
+
*/
|
|
214
|
+
const singleStreamExpectedVersion = (expectedVersion, commandName) => {
|
|
215
|
+
if (expectedVersion !== null && typeof expectedVersion === 'object') {
|
|
216
|
+
throw new pv3_types_1.InternalServerError('A per-stream expectedVersion map reached the single-stream commit. The command\'s load produced a multi-stream expectation but its commit is not the multiStream template.', 'EXPECTED_VERSION_SHAPE_MISMATCH', { command: commandName, streams: Object.keys(expectedVersion) });
|
|
217
|
+
}
|
|
218
|
+
return expectedVersion;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* The prepared events keyed by the stream each one actually TARGETS, in first-appearance order.
|
|
222
|
+
*
|
|
223
|
+
* A handler may emit onto a stream other than its aggregate's — `createEvent( name, data,
|
|
224
|
+
* { stream } )` puts a stream on the event and `addMetadata` spreads `stream` BEFORE `...event`,
|
|
225
|
+
* so the event's own stream wins. `Object.keys` preserves insertion order for non-numeric keys,
|
|
226
|
+
* so the aggregate's own stream keeps whatever position the handler gave it.
|
|
227
|
+
*/
|
|
228
|
+
const groupEventsByStream = (events) => events.reduce((groups, event) => {
|
|
229
|
+
(groups[event.stream] ||= []).push(event);
|
|
230
|
+
return groups;
|
|
231
|
+
}, {});
|
|
232
|
+
/**
|
|
233
|
+
* The committed events back in the order the HANDLER emitted them.
|
|
234
|
+
*
|
|
235
|
+
* A multi-stream append returns its rows GROUPED BY STREAM, but the response is not a set:
|
|
236
|
+
* `formatEventSourcedCommandResponse` reduces `committedEvents` in array order into the state it
|
|
237
|
+
* returns, and hosts assert on `events[0].name`. So an interleaved emit (`companion, own,
|
|
238
|
+
* companion` — teselly's composite-release shape) must not come back regrouped.
|
|
239
|
+
*
|
|
240
|
+
* Each stream's rows keep their own relative order through the adapters (both build and insert a
|
|
241
|
+
* stream's events in the order given, and `RETURNING` follows the VALUES list), so re-threading
|
|
242
|
+
* the groups against the prepared events restores the emit order exactly. If the two ever fail to
|
|
243
|
+
* line up — which the adapters make impossible, since both prove nothing was dropped before
|
|
244
|
+
* returning — the adapter's own array is handed back untouched rather than silently short.
|
|
245
|
+
*/
|
|
246
|
+
const inEmitOrder = (prepared, committed) => {
|
|
247
|
+
const queues = committed.reduce((grouped, event) => {
|
|
248
|
+
(grouped[event.stream] ||= []).push(event);
|
|
249
|
+
return grouped;
|
|
250
|
+
}, {});
|
|
251
|
+
const ordered = prepared.map((event) => queues[event.stream]?.shift());
|
|
252
|
+
return ordered.length === committed.length && ordered.every(Boolean)
|
|
253
|
+
? ordered
|
|
254
|
+
: committed;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Append each prepared event to THE STREAM IT NAMES, asserting the expectation on THE STREAM THE
|
|
258
|
+
* LOAD READ and on no other.
|
|
259
|
+
*
|
|
260
|
+
* `defaultEventsourcingLoad` takes the head of `handlerState.stream` and records it as the
|
|
261
|
+
* command's expectation. A single `appendToStream` then targeted `events[0].stream` while
|
|
262
|
+
* carrying that number, so a handler emitting onto any other stream had its aggregate's head
|
|
263
|
+
* asserted against a stream nothing had ever compared it to — two streams, one number. It also
|
|
264
|
+
* numbered EVERY event off `events[0].stream`'s head + index, so a cross-stream command wrote
|
|
265
|
+
* per-stream version GAPS (which the outbox's per-stream watermark reads as missing events).
|
|
266
|
+
* Both close here.
|
|
267
|
+
*/
|
|
268
|
+
const appendEventsToOwnStreams = (logger, eventstore, loadedStream, expectedVersion, transaction) => async (events) => {
|
|
269
|
+
if (!events.length)
|
|
270
|
+
return [];
|
|
271
|
+
/* `null` IS NOT AN ASSERTION ABOUT A HEAD — it declares the whole command version-FREE, so
|
|
272
|
+
* every event it writes is stored with `version = NULL` whatever stream it lands on. There is
|
|
273
|
+
* nothing per-stream to get right: no numbering happens, so no gaps can open, and nothing is
|
|
274
|
+
* compared, so no stream can be asserted wrongly. The single append is already exactly
|
|
275
|
+
* correct for it.
|
|
276
|
+
*
|
|
277
|
+
* Keeping it here is also what keeps `appendEventsToStream`'s `expectedVersion === null`
|
|
278
|
+
* RETRY LOOP on the only path that can ever reach it — the loop is not dropped, it is proven
|
|
279
|
+
* unreachable from the multi-stream route below, which never sees a null expectation.
|
|
280
|
+
*
|
|
281
|
+
* And routing it through `appendToMultipleStreams` would not be equivalent:
|
|
282
|
+
* `DatabaseEventstore`'s takes every stream's head unconditionally and would VERSION events
|
|
283
|
+
* that are version-free today, silently changing the class the outbox dedups them by. */
|
|
284
|
+
if (expectedVersion === null)
|
|
285
|
+
return (0, exports.appendEventsToStream)(logger, eventstore, null, transaction)(events);
|
|
286
|
+
const eventsByStream = groupEventsByStream(events);
|
|
287
|
+
const streams = Object.keys(eventsByStream);
|
|
288
|
+
// The expectation was computed from ONE stream's head — the stream the load reduced. Every
|
|
289
|
+
// other stream gets `undefined`: the append reads that stream's own head and numbers from it,
|
|
290
|
+
// asserting nothing. Never assert a head this command never read; on a stream whose head
|
|
291
|
+
// moves independently the two can never converge, so the "conflict" is unbreakable and burns
|
|
292
|
+
// the whole retry budget on a stream the command has no opinion about.
|
|
293
|
+
const expectationFor = (stream) => stream === loadedStream ? expectedVersion : undefined;
|
|
294
|
+
if (streams.length === 1)
|
|
295
|
+
return (0, exports.appendEventsToStream)(logger, eventstore, expectationFor(streams[0]), transaction)(events);
|
|
296
|
+
if (!eventstore.appendToMultipleStreams)
|
|
297
|
+
throw new pv3_types_1.InternalServerError('A command emitted events onto several streams but the Eventstore in use does not support multiple streams. Appending them as one stream would number every event off the first stream\'s head, leaving per-stream version gaps.', 'MULTI_STREAM_COMMANDS_NOT_SUPPORTED', { stream: loadedStream, streams });
|
|
298
|
+
const committed = await eventstore.appendToMultipleStreams(streams.reduce((perStream, stream) => {
|
|
299
|
+
perStream[stream] = { events: eventsByStream[stream], expectedVersion: expectationFor(stream) };
|
|
300
|
+
return perStream;
|
|
301
|
+
}, {}), transaction);
|
|
302
|
+
return inEmitOrder(events, committed);
|
|
303
|
+
};
|
|
304
|
+
exports.appendEventsToOwnStreams = appendEventsToOwnStreams;
|
|
305
|
+
const commitEvents = (logger, eventstore) => (handlerState, transaction) => {
|
|
306
|
+
if (!handlerState.events.length)
|
|
307
|
+
return Promise.resolve(handlerState);
|
|
308
|
+
const expectedVersion = singleStreamExpectedVersion(handlerState.expectedVersion, handlerState.command?.name);
|
|
309
|
+
return (0, exports.prepareEventsToCommit)(handlerState)
|
|
310
|
+
.then((0, exports.appendEventsToOwnStreams)(logger, eventstore, handlerState.stream, expectedVersion, transaction))
|
|
311
|
+
.then((0, ramda_1.objOf)('committedEvents'))
|
|
312
|
+
.then((0, ramda_1.mergeRight)(handlerState));
|
|
313
|
+
};
|
|
314
|
+
exports.commitEvents = commitEvents;
|
|
315
|
+
const getStreamReducer = (state, event) => {
|
|
316
|
+
state[event.stream] ||= { events: [], state: null };
|
|
317
|
+
state[event.stream].events?.push(event);
|
|
318
|
+
return state;
|
|
319
|
+
};
|
|
320
|
+
exports.getStreamReducer = getStreamReducer;
|
|
321
|
+
const loadStream = (eventstore) => (stream, options) => {
|
|
322
|
+
return eventstore.reduceStream({ ...options, stream }, exports.getStreamReducer, {})
|
|
323
|
+
.then((state) => !Object.keys(state).length
|
|
324
|
+
? undefined
|
|
325
|
+
: state[stream].events);
|
|
326
|
+
};
|
|
327
|
+
exports.loadStream = loadStream;
|
|
328
|
+
const getNonNoopEventNames = (aggregate) => {
|
|
329
|
+
if (reducersByAggregateMap.has(aggregate.name)) {
|
|
330
|
+
return reducersByAggregateMap.get(aggregate.name) || [];
|
|
331
|
+
}
|
|
332
|
+
const nonNoopEvents = Object.entries(aggregate.eventReducers)
|
|
333
|
+
.filter(([, reducer]) => reducer !== pv3_types_1.ReducerNOOP)
|
|
334
|
+
.map(([name]) => name);
|
|
335
|
+
reducersByAggregateMap.set(aggregate.name, nonNoopEvents);
|
|
336
|
+
return nonNoopEvents;
|
|
337
|
+
};
|
|
338
|
+
exports.getNonNoopEventNames = getNonNoopEventNames;
|
|
339
|
+
const loadAggregateState = (eventstore) => (aggregate, stream, options, state = aggregate.initialValue()) => {
|
|
340
|
+
const nonNoopEvents = (0, exports.getNonNoopEventNames)(aggregate);
|
|
341
|
+
const eventFilter = options?.events
|
|
342
|
+
? options.events.filter((name) => nonNoopEvents.includes(name))
|
|
343
|
+
: nonNoopEvents;
|
|
344
|
+
return !stream || !aggregate.isAggregate
|
|
345
|
+
? Promise.resolve(null)
|
|
346
|
+
: eventstore.reduceStream({ ...options, stream, events: eventFilter }, (0, exports.getEventReducers)(aggregate), { state })
|
|
347
|
+
.then((_state) => {
|
|
348
|
+
return _state || { state };
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
exports.loadAggregateState = loadAggregateState;
|
|
352
|
+
const domainModelLoad = (database, collection, transaction) => (handlerState) => {
|
|
353
|
+
const innerTransactionOperation = (innerTransaction) => {
|
|
354
|
+
return innerTransaction
|
|
355
|
+
.getCollection(collection)
|
|
356
|
+
.readById(handlerState.params.id)
|
|
357
|
+
.then((state) => {
|
|
358
|
+
return (0, ramda_1.assoc)('state', state
|
|
359
|
+
? (0, ramda_1.omit)(['id'], state)
|
|
360
|
+
: handlerState.commandHandler.initialValue(), handlerState);
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
return (transaction || handlerState.transaction) ? innerTransactionOperation(transaction || handlerState.transaction) : database.initTransaction(innerTransactionOperation);
|
|
364
|
+
};
|
|
365
|
+
exports.domainModelLoad = domainModelLoad;
|
|
366
|
+
exports.domainModelCommit = (0, ramda_1.curry)((logger, eventstore, database, collection, transaction) => async (handlerState) => {
|
|
367
|
+
const innerTransactionOperation = async (innerTransaction) => {
|
|
368
|
+
const { params, expectedVersion } = handlerState;
|
|
369
|
+
const initialValue = handlerState.commandHandler.initialValue();
|
|
370
|
+
const eventsToCommit = await (0, exports.prepareEventsToCommit)(handlerState);
|
|
371
|
+
if (eventsToCommit.length === 0) {
|
|
372
|
+
return handlerState;
|
|
373
|
+
}
|
|
374
|
+
// Snapshot-consistency fix: reduce the committed events onto the CURRENT persisted snapshot,
|
|
375
|
+
// re-read FOR UPDATE inside THIS transaction — NOT handlerState.state (the state loaded, unlocked,
|
|
376
|
+
// at the START of the command). The row lock is held until this transaction commits, so concurrent
|
|
377
|
+
// committers on the same aggregate serialize here; a late delta event (e.g. StructureAcked, whose
|
|
378
|
+
// reducer carries the whole prior state forward) then reduces onto the LATEST committed state and
|
|
379
|
+
// can never resurrect a nested key (a removed broker) that a concurrent commit dropped. This keeps
|
|
380
|
+
// the notEventsourced snapshot a faithful, serialized projection of the event log == a full replay.
|
|
381
|
+
const currentRow = await innerTransaction.getCollection(collection).readById(params.id, { forUpdate: true });
|
|
382
|
+
const currentState = currentRow ? (0, ramda_1.omit)(['id', 'version'], currentRow) : initialValue;
|
|
383
|
+
const { state, events } = (0, exports.reduceEventsIntoState)(currentState, handlerState.commandHandler, eventsToCommit);
|
|
384
|
+
let lastCommittedVersion = 0;
|
|
385
|
+
if (eventstore._adapter()._adapter().connectionId === database._adapter().connectionId) {
|
|
386
|
+
const state = await (0, exports.commitEvents)(logger, eventstore)(handlerState, innerTransaction);
|
|
387
|
+
lastCommittedVersion = state.committedEvents?.at(-1)?.version || 1;
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
/* THE OUTBOX BRANCH HAS ITS OWN AUDIT LOG, AND ITS OWN WAY TO NUMBER IT.
|
|
391
|
+
*
|
|
392
|
+
* Nothing is appended to the eventstore here — the events land in `<collection>_outbox`
|
|
393
|
+
* — so there are no `committedEvents` to read a version off. The version is DERIVED
|
|
394
|
+
* instead, and it is derived from the one place that keeps it truthful: `currentRow`,
|
|
395
|
+
* the snapshot re-read FOR UPDATE a few lines above. That read is what the
|
|
396
|
+
* snapshot-consistency fix documented above rests on, and this reuses it rather than
|
|
397
|
+
* taking a second, unlocked one. The row lock is held until this transaction commits,
|
|
398
|
+
* so concurrent committers on the same aggregate serialize HERE, each one reading the
|
|
399
|
+
* version the previous one wrote and numbering from it. No gaps, no reuse.
|
|
400
|
+
*
|
|
401
|
+
* Why `+ events.length` is the same numbering the eventstore would have produced: the
|
|
402
|
+
* eventstore numbers an append from the stream head, head N -> N+1 … N+k, and the
|
|
403
|
+
* snapshot is by construction a faithful, serialized projection of that log — version N
|
|
404
|
+
* means N events precede this commit. Writing k more therefore puts the head at N + k,
|
|
405
|
+
* which is a POSITION in the audit log and not a counter that merely increases.
|
|
406
|
+
*/
|
|
407
|
+
const currentVersion = Number(currentRow?.version ?? 0);
|
|
408
|
+
lastCommittedVersion = currentVersion + events.length;
|
|
409
|
+
await innerTransaction
|
|
410
|
+
.getCollection(`${collection}_outbox`)
|
|
411
|
+
.createMany(events.map((e) => (0, ramda_1.assoc)('id', (0, uuidv7_1.uuidv7)(), e)));
|
|
412
|
+
}
|
|
413
|
+
// REPLACE (not merge) the snapshot with the fully-reduced state: it is the COMPLETE aggregate
|
|
414
|
+
// state, so a merge could only accumulate stale nested keys a reducer dropped (e.g. a removed
|
|
415
|
+
// broker never leaving `brokers`) — the eventstore_cluster ↔ cluster_infrastructure divergence.
|
|
416
|
+
if (expectedVersion) {
|
|
417
|
+
const updated = await innerTransaction.getCollection(collection).updateMany([
|
|
418
|
+
{ field: 'id', op: 'eq', value: params.id },
|
|
419
|
+
{ field: 'version', op: 'eq', value: expectedVersion }
|
|
420
|
+
], { ...state, version: lastCommittedVersion }, { replace: true });
|
|
421
|
+
/* A COMPARE-AND-SET THAT MATCHED NOTHING IS A LOST COMMAND, NOT A SUCCESS.
|
|
422
|
+
*
|
|
423
|
+
* `updateMany` reports the rows it wrote, and this write is a CAS —
|
|
424
|
+
* `WHERE id = … AND version = expectedVersion`. Discarding that result made a failed
|
|
425
|
+
* assertion indistinguishable from a satisfied one: the caller was told it won, the
|
|
426
|
+
* audit row had already been written, and the snapshot never moved. Raising here is
|
|
427
|
+
* what makes the assertion mean something, and it rolls the audit row back with it.
|
|
428
|
+
*
|
|
429
|
+
* `ConcurrencyError` specifically, because that is the type the command pipeline knows:
|
|
430
|
+
* a command that asserted its OWN expectation (`?expectedVersion=`) gets the 409, while
|
|
431
|
+
* one whose expectation the library derived is re-run against fresh state.
|
|
432
|
+
*/
|
|
433
|
+
if (!updated.length)
|
|
434
|
+
throw new pv3_types_1.ConcurrencyError(`Concurrency Error: the ${collection} snapshot for '${params.id}' is no longer at the expected version ${expectedVersion}`, 'SNAPSHOT_EXPECTED_VERSION_MISMATCH');
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
if (state !== null) {
|
|
438
|
+
await innerTransaction
|
|
439
|
+
.getCollection(collection)
|
|
440
|
+
.upsert(handlerState.params.id, {
|
|
441
|
+
...state,
|
|
442
|
+
version: lastCommittedVersion
|
|
443
|
+
}, { replace: true });
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
await innerTransaction
|
|
447
|
+
.getCollection(collection)
|
|
448
|
+
.destroyById(handlerState.params.id);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
...handlerState,
|
|
453
|
+
state
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
return (transaction || handlerState.transaction) ? innerTransactionOperation(transaction || handlerState.transaction) : database.initTransaction(innerTransactionOperation);
|
|
457
|
+
});
|
|
458
|
+
const defaultHandler = (eventsProducedByCommand) => (_1, _2, data) => {
|
|
459
|
+
return Promise.all((eventsProducedByCommand || []).map((e) => () => ({
|
|
460
|
+
name: e,
|
|
461
|
+
data
|
|
462
|
+
})));
|
|
463
|
+
};
|
|
464
|
+
exports.defaultHandler = defaultHandler;
|
|
465
|
+
const defaultCommit = (logger, eventstore) => (state) => {
|
|
466
|
+
if (!state.transaction || (state.transaction && eventstore.getConnectionId() === state.transaction?.connectionId)) {
|
|
467
|
+
return (0, exports.commitEvents)(logger, eventstore)(state, state.transaction);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
logger.error('Attempting to Transactionally commit events with a transaction belonging to a different database. Dying now');
|
|
471
|
+
logger.info(state);
|
|
472
|
+
process.exit(1);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
exports.defaultCommit = defaultCommit;
|
|
476
|
+
const reduceEventsIntoState = (initialState, commandHandler, events) => {
|
|
477
|
+
const _state = events.reduce((0, exports.getEventReducers)(commandHandler), { state: initialState });
|
|
478
|
+
return { events, state: _state.state };
|
|
479
|
+
};
|
|
480
|
+
exports.reduceEventsIntoState = reduceEventsIntoState;
|
|
481
|
+
const formatDomainModelCommandResponse = (handlerState) => {
|
|
482
|
+
return Promise.resolve({
|
|
483
|
+
state: handlerState.state
|
|
484
|
+
});
|
|
485
|
+
};
|
|
486
|
+
exports.formatDomainModelCommandResponse = formatDomainModelCommandResponse;
|
|
487
|
+
const formatEventSourcedCommandResponse = async (handlerState) => {
|
|
488
|
+
const { commandHandler, state } = handlerState;
|
|
489
|
+
// Default to [] (not undefined) so an empty-event command still returns an
|
|
490
|
+
// `events: []` response. Mirrors the snapshot command-template's `format`
|
|
491
|
+
// (`committedEvents || []`); without this the response shape diverges between
|
|
492
|
+
// snapshotted and non-snapshotted aggregates (a no-event command returns
|
|
493
|
+
// `{ state }` with no `events` key here, but `{ events: [], state }` there).
|
|
494
|
+
const committedEvents = handlerState.committedEvents || [];
|
|
495
|
+
if (!commandHandler.isAggregate) {
|
|
496
|
+
return Promise.resolve({ events: committedEvents });
|
|
497
|
+
}
|
|
498
|
+
return (0, exports.reduceEventsIntoState)(state, commandHandler, committedEvents);
|
|
499
|
+
};
|
|
500
|
+
exports.formatEventSourcedCommandResponse = formatEventSourcedCommandResponse;
|
|
501
|
+
const validateInvariants = (invariants) => (state) => {
|
|
502
|
+
return invariants.reduce((success, invariant) => {
|
|
503
|
+
return success
|
|
504
|
+
.then((state) => invariant.check(state))
|
|
505
|
+
.then((resultState) => resultState || state);
|
|
506
|
+
}, Promise.resolve(state));
|
|
507
|
+
};
|
|
508
|
+
exports.validateInvariants = validateInvariants;
|
|
509
|
+
const checkIdempotency = (idempotencyChecks) => (state) => {
|
|
510
|
+
return idempotencyChecks.reduce((success, idempotencyCheck) => {
|
|
511
|
+
return success
|
|
512
|
+
.then((state) => idempotencyCheck.check(state))
|
|
513
|
+
.then((resultState) => resultState || state);
|
|
514
|
+
}, Promise.resolve(state));
|
|
515
|
+
};
|
|
516
|
+
const defaultEventsourcingLoad = (eventstore) => async (handlerState, options, state) => {
|
|
517
|
+
/* ⚠ THE HEAD READ IS STRICTLY BEFORE THE REDUCE. Do not swap these two statements.
|
|
518
|
+
*
|
|
519
|
+
* The command runs inside `initTransaction` (see `executeCommand` below) at READ COMMITTED,
|
|
520
|
+
* so EVERY STATEMENT GETS ITS OWN SNAPSHOT and a concurrent commit can land between two of
|
|
521
|
+
* them. Which of the two runs first is therefore the whole correctness of this change:
|
|
522
|
+
*
|
|
523
|
+
* head -> reduce (this order) — head <= what we reduced. An interleaving writer means we
|
|
524
|
+
* reduced MORE than the version we assert, the commit's assertion FAILS CLOSED, and the
|
|
525
|
+
* command retries against the winner's state. Costs at worst a spurious retry.
|
|
526
|
+
* (`head <= reduced` holds while both reads are POOL-EQUIVALENT. The head read below is
|
|
527
|
+
* never pool-SCOPED — it passes the transaction on purpose, see the last paragraph — but
|
|
528
|
+
* on the default path that transaction is the one `executeCommand` opened for this command
|
|
529
|
+
* and it has not written this stream yet, so it answers exactly what a pool read would.
|
|
530
|
+
* It does NOT hold inside a caller-owned transaction that has ALREADY appended to THIS
|
|
531
|
+
* stream: there the head sees those uncommitted rows and `loadAggregateState`, which
|
|
532
|
+
* reduces through the pool, does not. That exposure predates this read — the reduce was
|
|
533
|
+
* already pool-scoped and there was no assertion at all — and it cannot produce a conflict,
|
|
534
|
+
* since both the head here and the head the append numbers from come from the same
|
|
535
|
+
* per-transaction cache. Fixing it means giving the reduce the transaction, its own change.)
|
|
536
|
+
* reduce -> head (reversed) — head >= what we reduced. We would assert version 7 having
|
|
537
|
+
* only reduced 1-5, the assertion PASSES, and a decision computed on stale state gets
|
|
538
|
+
* committed. That is precisely the lost update this change exists to remove.
|
|
539
|
+
*
|
|
540
|
+
* Reversing them produces NO type error and NO other test failure — the tripwire is the
|
|
541
|
+
* ordering case in `occLoadTimeExpectation.deps.test.ts`.
|
|
542
|
+
*
|
|
543
|
+
* The expectation comes from the HEAD, never from the reduce: the reduce is filtered by
|
|
544
|
+
* event name at the SQL level (`getNonNoopEventNames`) and yields only `{ state }`, so the
|
|
545
|
+
* greatest version among the events it saw sits permanently behind the head on any stream
|
|
546
|
+
* carrying a `ReducerNOOP` event or another writer's event. Sourcing it there would make
|
|
547
|
+
* every command on such a stream conflict, burn its whole retry budget and fail forever.
|
|
548
|
+
*
|
|
549
|
+
* And the transaction is passed on purpose: inside a caller-owned transaction that has
|
|
550
|
+
* already appended to this stream, a pool read would miss those uncommitted appends, assert
|
|
551
|
+
* a head the commit can never agree with, and retry to exhaustion.
|
|
552
|
+
*/
|
|
553
|
+
/* The command's declared mode, spelled out as the three things the append can be told. This is
|
|
554
|
+
* the whole of the dispatch — the adapters already branch on exactly these values:
|
|
555
|
+
*
|
|
556
|
+
* optimistic — the head read below: assert it, and conflict when it moved.
|
|
557
|
+
* rebase — `undefined`: the append reads the head itself and numbers from it, asserting
|
|
558
|
+
* NOTHING. Per-stream order survives; conflict DETECTION does not. The head read
|
|
559
|
+
* is skipped rather than taken and discarded, so a mode that asserts nothing
|
|
560
|
+
* also costs nothing.
|
|
561
|
+
* unversioned — `null`: every event is written version-free. Unreachable for an aggregate
|
|
562
|
+
* (`resolveConcurrencyMode` refuses it) and reachable here only for a
|
|
563
|
+
* non-aggregate that borrowed this load through a custom template, which is
|
|
564
|
+
* already what the non-aggregate load gives it.
|
|
565
|
+
*/
|
|
566
|
+
const concurrency = resolveConcurrencyMode(handlerState.commandHandler, handlerState.command);
|
|
567
|
+
const expectedVersion = handlerState.expectedVersion !== undefined
|
|
568
|
+
// An expectation SUPPLIED by the caller is never overwritten — the test is "was one
|
|
569
|
+
// supplied at all", not "was it exactly null". `null` means "version-free stream", and a
|
|
570
|
+
// custom load may have built a per-stream map; a null-only carve-out would clobber both.
|
|
571
|
+
? handlerState.expectedVersion
|
|
572
|
+
: concurrency === 'rebase'
|
|
573
|
+
? undefined
|
|
574
|
+
: concurrency === 'unversioned'
|
|
575
|
+
? null
|
|
576
|
+
: await eventstore.getStreamVersion(handlerState.stream, handlerState.transaction);
|
|
577
|
+
const reducedState = await (0, exports.loadAggregateState)(eventstore)(handlerState.commandHandler, handlerState.stream, options, state ||
|
|
578
|
+
handlerState.state ||
|
|
579
|
+
handlerState.commandHandler.initialValue());
|
|
580
|
+
return {
|
|
581
|
+
...handlerState,
|
|
582
|
+
expectedVersion,
|
|
583
|
+
state: reducedState?.state
|
|
584
|
+
};
|
|
585
|
+
};
|
|
586
|
+
exports.defaultEventsourcingLoad = defaultEventsourcingLoad;
|
|
587
|
+
const handleCommand = (handler) => async (handlerState) => {
|
|
588
|
+
const { state, data } = handlerState;
|
|
589
|
+
handlerState.events = await Promise.resolve()
|
|
590
|
+
.then(() => handler((0, utils_1.createEvent)(handlerState.commandHandler), state ? (0, ramda_1.clone)(state) : null, (0, ramda_1.clone)(data), handlerState))
|
|
591
|
+
.then((events) => {
|
|
592
|
+
return [...handlerState.events, ...events];
|
|
593
|
+
});
|
|
594
|
+
return handlerState;
|
|
595
|
+
};
|
|
596
|
+
exports.handleCommand = handleCommand;
|
|
597
|
+
const createCommandHandlers = (logger, endpoint, eventstore, metadataSchema, formatMetadataFromContext = () => ({}), instrumentCommandExecution) => {
|
|
598
|
+
const internalExecuteCommand = (commandHandler, commandName, transaction) => async (actionParams) => {
|
|
599
|
+
const command = commandHandler.commands[commandName]
|
|
600
|
+
.build
|
|
601
|
+
? commandHandler.commands[commandName].build()
|
|
602
|
+
: commandHandler.commands[commandName];
|
|
603
|
+
command.name = commandName;
|
|
604
|
+
const start = Date.now();
|
|
605
|
+
logger.log('Processing Command', commandName, 'in', commandHandler.isAggregate ? 'Aggregate' : 'External System', commandHandler.name);
|
|
606
|
+
const alsContext = (0, executionContext_1.getExecutionContext)();
|
|
607
|
+
const { body, params, query, context: explicitContext } = actionParams;
|
|
608
|
+
// Merge: explicit params > ALS > defaults
|
|
609
|
+
const context = (explicitContext?.user
|
|
610
|
+
? explicitContext
|
|
611
|
+
: alsContext
|
|
612
|
+
? { ...explicitContext, user: { id: alsContext.userId, accountId: alsContext.accountId, impersonatedBy: alsContext.impersonatedBy } }
|
|
613
|
+
: explicitContext);
|
|
614
|
+
const id = command.dataPropertyId
|
|
615
|
+
? (0, utils_2.existsPath)(command.dataPropertyId.split('.'), body)
|
|
616
|
+
: params?.id;
|
|
617
|
+
if ((commandHandler.isStreamable || commandHandler.isAggregate) && !id) {
|
|
618
|
+
throw Error(`Command requires an id to be executed for commandHandler ${commandHandler.name} and command ${command.name}`);
|
|
619
|
+
}
|
|
620
|
+
// Non-streamable, non-aggregate systems with no supplied id emit null-version,
|
|
621
|
+
// order-free events. Fan them out by varying the stream id with a random bounded
|
|
622
|
+
// token (affects ONLY `stream`; `id` stays untouched for downstream use).
|
|
623
|
+
const streamId = (!id && !command.dataPropertyId && !commandHandler.isAggregate && !commandHandler.isStreamable)
|
|
624
|
+
? (0, utils_2.randomStreamSuffix)()
|
|
625
|
+
: id;
|
|
626
|
+
const stream = (0, utils_2.formatStream)(commandHandler.name, streamId);
|
|
627
|
+
const mergedQuery = query || {};
|
|
628
|
+
const correlationId = mergedQuery.correlationId || alsContext?.correlationId;
|
|
629
|
+
const causationId = mergedQuery.causationId || alsContext?.causationId;
|
|
630
|
+
const handlerState = {
|
|
631
|
+
command,
|
|
632
|
+
data: body,
|
|
633
|
+
query,
|
|
634
|
+
params,
|
|
635
|
+
context,
|
|
636
|
+
stream,
|
|
637
|
+
events: [],
|
|
638
|
+
commandHandler,
|
|
639
|
+
expectedVersion: query?.expectedVersion,
|
|
640
|
+
state: undefined,
|
|
641
|
+
metadata: {
|
|
642
|
+
// Ambient execution TAGS ride NESTED under `metadata.tags`, never spread, so a
|
|
643
|
+
// tag can never collide with (or forge) a reserved metadata key. Written FIRST
|
|
644
|
+
// so the reserved keys below always win even if a host's
|
|
645
|
+
// `formatMetadataFromContext` were to emit its own `tags`.
|
|
646
|
+
...(alsContext?.tags ? { tags: alsContext.tags } : {}),
|
|
647
|
+
correlationId: correlationId || getActiveTraceId() || (0, uuidv7_1.uuidv7)(),
|
|
648
|
+
causationId,
|
|
649
|
+
...formatMetadataFromContext(context || {})
|
|
650
|
+
},
|
|
651
|
+
transaction
|
|
652
|
+
};
|
|
653
|
+
const loadFunction = command.load ||
|
|
654
|
+
(!commandHandler.isAggregate
|
|
655
|
+
? (state) => ({ ...state, expectedVersion: null })
|
|
656
|
+
: commandHandler.isEventsourced
|
|
657
|
+
? (0, exports.defaultEventsourcingLoad)(eventstore)
|
|
658
|
+
: (0, exports.domainModelLoad)(commandHandler.outboxDatabase, commandHandler.outboxCollection));
|
|
659
|
+
const commitFunction = command.commit ||
|
|
660
|
+
(commandHandler.isEventsourced
|
|
661
|
+
? (0, exports.defaultCommit)(logger, eventstore)
|
|
662
|
+
: (0, exports.domainModelCommit)(logger, eventstore, commandHandler.outboxDatabase, commandHandler.outboxCollection, undefined));
|
|
663
|
+
const formatFunction = command.format ||
|
|
664
|
+
(commandHandler.isEventsourced
|
|
665
|
+
? exports.formatEventSourcedCommandResponse
|
|
666
|
+
: exports.formatDomainModelCommandResponse);
|
|
667
|
+
const executePreProcessing = (state) => {
|
|
668
|
+
if (!command.preProcessing) {
|
|
669
|
+
return Promise.resolve(state);
|
|
670
|
+
}
|
|
671
|
+
return Promise.resolve(command.preProcessing(state))
|
|
672
|
+
.then((newData) => ({
|
|
673
|
+
...state,
|
|
674
|
+
data: newData
|
|
675
|
+
}));
|
|
676
|
+
};
|
|
677
|
+
const executePipeline = () => Promise.resolve(handlerState)
|
|
678
|
+
.then(loadFunction)
|
|
679
|
+
.then(executePreProcessing)
|
|
680
|
+
.then(checkIdempotency(command.idempotencyChecks || []))
|
|
681
|
+
.then((0, exports.validateInvariants)(command.invariants || []))
|
|
682
|
+
.then((0, exports.handleCommand)(command.handler || (0, exports.defaultHandler)(command.events)))
|
|
683
|
+
.then(commitFunction)
|
|
684
|
+
.catch((err) => {
|
|
685
|
+
if (err.ignore === '--IdempotencyCheck--') {
|
|
686
|
+
// Pure side effect at the skip site — `add` is no-throw; control flow is
|
|
687
|
+
// unchanged (still resolve with `err.handlerState`). Low-cardinality labels:
|
|
688
|
+
// command + aggregate names only (never ids).
|
|
689
|
+
getIdempotencySkipCounter()?.add(1, { command: commandName, aggregate: commandHandler.name });
|
|
690
|
+
return err.handlerState;
|
|
691
|
+
}
|
|
692
|
+
return Promise.reject(err);
|
|
693
|
+
})
|
|
694
|
+
.then(formatFunction)
|
|
695
|
+
.then((result) => {
|
|
696
|
+
logger.log('Command', commandName, ' Processed in', ((Date.now() - start) / 1000).toFixed(2), 's');
|
|
697
|
+
return result;
|
|
698
|
+
});
|
|
699
|
+
return instrumentCommandExecution
|
|
700
|
+
? instrumentCommandExecution({
|
|
701
|
+
commandName: commandName,
|
|
702
|
+
aggregateName: commandHandler.name,
|
|
703
|
+
stream,
|
|
704
|
+
isAggregate: !!commandHandler.isAggregate,
|
|
705
|
+
correlationId: handlerState.metadata?.correlationId,
|
|
706
|
+
causationId: handlerState.metadata?.causationId,
|
|
707
|
+
payload: handlerState.data
|
|
708
|
+
}, executePipeline)
|
|
709
|
+
: executePipeline();
|
|
710
|
+
};
|
|
711
|
+
const executeCommand = (commandHandler, commandName, transaction, schemas, retryAttempts = 0, occSavepoint) => async (actionParams) => {
|
|
712
|
+
const command = commandHandler.commands[commandName]
|
|
713
|
+
.build
|
|
714
|
+
? commandHandler.commands[commandName].build()
|
|
715
|
+
: commandHandler.commands[commandName];
|
|
716
|
+
schemas = schemas || getCommandSchemas(commandHandler, command);
|
|
717
|
+
command.name = commandName;
|
|
718
|
+
// Resolved BEFORE anything is opened or executed, so a command declaring the one illegal
|
|
719
|
+
// combination (`unversioned` on an aggregate) fails at the door instead of half-way
|
|
720
|
+
// through a transaction it already wrote to.
|
|
721
|
+
const concurrency = resolveConcurrencyMode(commandHandler, command);
|
|
722
|
+
const innerTransactionOperation = async (transaction) => {
|
|
723
|
+
return Promise.resolve(actionParams)
|
|
724
|
+
.then((0, validation_1.validateEndpoint)(validation_1.validateSchema, schemas, true))
|
|
725
|
+
.then(internalExecuteCommand(commandHandler, commandName, transaction));
|
|
726
|
+
};
|
|
727
|
+
/* ── THE REWIND POINT, TAKEN ONCE, BEFORE THE FIRST ATTEMPT ──────────────────────────
|
|
728
|
+
*
|
|
729
|
+
* Only for a transaction the CALLER owns. When we open the transaction ourselves (below)
|
|
730
|
+
* a failed attempt is discarded wholesale by `initTransaction`'s rollback, and the retry
|
|
731
|
+
* starts a brand-new one — there is nothing to rewind.
|
|
732
|
+
*
|
|
733
|
+
* ESTABLISHED EXACTLY ONCE, AT `retryAttempts === 0`, and carried through the retries.
|
|
734
|
+
* `occSavepoint` is that carried token; it is set only by the recursive call, which is
|
|
735
|
+
* why it doubles as "an attempt already took one".
|
|
736
|
+
*
|
|
737
|
+
* The reason is ECONOMY, not correctness — be precise about this, because the obvious
|
|
738
|
+
* story is wrong. A per-attempt savepoint would NOT rewind less: the rollback below runs
|
|
739
|
+
* strictly BEFORE the recursive call, so each new savepoint would be taken against an
|
|
740
|
+
* already-clean state and would behave identically on the data. What it would cost is one
|
|
741
|
+
* extra round trip AND one extra Postgres SUBTRANSACTION per attempt. Subtransactions are
|
|
742
|
+
* the scarce thing: a top-level transaction keeps every subtransaction XID it ever
|
|
743
|
+
* assigned in its `PGPROC` list for its whole life — `RELEASE SAVEPOINT` ends the nesting
|
|
744
|
+
* but does NOT give the XID back — and past `PGPROC_MAX_CACHED_SUBXIDS` (64) its snapshot
|
|
745
|
+
* goes suboverflowed, pushing every other backend's visibility checks into the
|
|
746
|
+
* `pg_subtrans` SLRU. One caller-owned transaction that runs many commands (item merge's
|
|
747
|
+
* nested loops) is already close to that ceiling at one savepoint per COMMAND; one per
|
|
748
|
+
* ATTEMPT would multiply it by the retry budget exactly when contention is highest.
|
|
749
|
+
*
|
|
750
|
+
* AND ONLY FOR AN `optimistic` COMMAND. That is the only mode that can lose a conflict it
|
|
751
|
+
* did not cause — it asserts a head it read, so another writer's commit invalidates it and
|
|
752
|
+
* the retry needs a clean state to resume from. `rebase` asserts nothing and `unversioned`
|
|
753
|
+
* writes version-free rows the unique index cannot catch, so neither has a conflict a
|
|
754
|
+
* rewind would help with; a subtransaction spent on them buys nothing. The consequence is
|
|
755
|
+
* deliberate and is the same rule slice 3 set: no rewind means NO RETRY inside a
|
|
756
|
+
* caller-owned transaction, so a `rebase` command that does hit a genuine INSERT collision
|
|
757
|
+
* there propagates to the transaction's owner instead of re-executing on top of its own
|
|
758
|
+
* unrewound rows. On the pooled path — where `rebase`'s retry actually lives — nothing
|
|
759
|
+
* changes.
|
|
760
|
+
*
|
|
761
|
+
* WHAT THIS GATE DOES NOT DO, since `optimistic` is the DEFAULT: it excludes only commands
|
|
762
|
+
* that explicitly declare `rebase`/`unversioned` and non-aggregate External Systems. It
|
|
763
|
+
* does NOT bound the subtransaction accumulation described above for a caller-owned
|
|
764
|
+
* transaction that issues many DEFAULT commands (teselly's `itemMerge.endpoints.ts` opens
|
|
765
|
+
* one transaction and runs commands inside five data-driven nested loops) — that
|
|
766
|
+
* transaction still passes `PGPROC_MAX_CACHED_SUBXIDS` and still goes suboverflowed. That
|
|
767
|
+
* remains a carried risk of running many commands on one transaction, not something this
|
|
768
|
+
* narrowing solves.
|
|
769
|
+
*
|
|
770
|
+
* Nor does it exclude an aggregate command with a CUSTOM `load` — `multiStream` above all.
|
|
771
|
+
* Such a command never runs `defaultEventsourcingLoad`, so it derives no expectation from
|
|
772
|
+
* the mode, yet it declares nothing and therefore resolves to `optimistic` and spends a
|
|
773
|
+
* savepoint here. That is the one population where the resolved mode is not a literal
|
|
774
|
+
* description of what its append asserts, and it is not a rounding error: every
|
|
775
|
+
* `multiStream(…)` command in the known host is in it, and they are precisely the commands
|
|
776
|
+
* run inside caller-owned transactions. Left as-is deliberately — their per-stream
|
|
777
|
+
* expectation map DOES carry real expectations, so a rewind is not obviously wasted, and
|
|
778
|
+
* narrowing this further is a behavior change with no oracle behind it.
|
|
779
|
+
*/
|
|
780
|
+
const rewindable = transaction && concurrency === 'optimistic' && canSavepoint(transaction) ? transaction : undefined;
|
|
781
|
+
const savepoint = occSavepoint ?? (rewindable ? await rewindable.savepoint() : undefined);
|
|
782
|
+
const establishedHere = !!savepoint && !occSavepoint;
|
|
783
|
+
const executionPromise = transaction ? innerTransactionOperation(transaction) : eventstore._adapter().initTransaction?.(innerTransactionOperation) || innerTransactionOperation();
|
|
784
|
+
const attempt = executionPromise.catch(async (err) => {
|
|
785
|
+
if (err instanceof pv3_types_1.ValidationError) {
|
|
786
|
+
logger.error('Validation Error executing command', commandName, 'in', commandHandler.name, err);
|
|
787
|
+
}
|
|
788
|
+
/* ── ONLY THE LIBRARY'S OWN EXPECTATION IS THE LIBRARY'S TO RETRY ───────────────────
|
|
789
|
+
*
|
|
790
|
+
* `!= null` — a NULL/UNDEFINED comparison, deliberately not a falsy one. `0` is a real
|
|
791
|
+
* expectation ("this stream must be EMPTY"), and a falsy test read it as "the caller
|
|
792
|
+
* supplied nothing", so a caller pinning 0 was retried into a stream that already had
|
|
793
|
+
* events in it — against an expectation that, unlike a derived one, can never become
|
|
794
|
+
* true on a later attempt. It burned the whole budget and then failed anyway.
|
|
795
|
+
*
|
|
796
|
+
* And it keys on the CALLER-SUPPLIED `query`, never on `handlerState.expectedVersion`,
|
|
797
|
+
* which slice 2 now fills in for every optimistic command — keying on the derived one
|
|
798
|
+
* would make retry unreachable for the entire default path. The split is the semantics:
|
|
799
|
+
* an expectation the library DERIVED from the head it just read is a race it can
|
|
800
|
+
* resolve by re-reading, so it retries; an expectation the caller PINNED encodes a
|
|
801
|
+
* decision the caller made about a specific version, so re-running the handler against
|
|
802
|
+
* a different version would answer a question nobody asked. That one propagates. */
|
|
803
|
+
const isOccRetryable = err.type === 'ConcurrencyError' && actionParams.query?.expectedVersion == null;
|
|
804
|
+
// The generic "gave up" line, kept for the tail case it still covers: `retryAttempts`
|
|
805
|
+
// only ever advances on a ConcurrencyError, so reaching the ceiling with some OTHER
|
|
806
|
+
// error means the final attempt failed for a different reason. When it IS an OCC
|
|
807
|
+
// exhaustion the dedicated line below says strictly more, so this one stands down —
|
|
808
|
+
// one failure, one error log.
|
|
809
|
+
if (retryAttempts >= OCC_RETRY_CEILING && !isOccRetryable) {
|
|
810
|
+
logger.error('Command', commandName, 'in', commandHandler.name, `failed after ${OCC_RETRY_CEILING} retries`, err);
|
|
811
|
+
}
|
|
812
|
+
if (isOccRetryable) {
|
|
813
|
+
// Bounded labels — see the instrument block at the top of this file for why the
|
|
814
|
+
// contended stream is logged rather than labelled.
|
|
815
|
+
const occLabels = { command: commandName, aggregate: commandHandler.name };
|
|
816
|
+
if (retryAttempts < OCC_RETRY_CEILING && transaction && !rewindable) {
|
|
817
|
+
/* ── A TRANSACTION WE CANNOT REWIND IS NOT RETRIED ─────────────────────────
|
|
818
|
+
*
|
|
819
|
+
* The transaction is the CALLER's and it is still open, holding whatever this
|
|
820
|
+
* attempt already wrote through it (the append that lost is not necessarily the
|
|
821
|
+
* only thing the command did). Re-executing here would run the whole command a
|
|
822
|
+
* second time ON TOP OF those uncommitted rows: the load would read them back as
|
|
823
|
+
* if they were somebody's committed history, and the append would number itself
|
|
824
|
+
* from work that the caller may be about to roll away.
|
|
825
|
+
*
|
|
826
|
+
* So the conflict goes to the caller, who OWNS the transaction and is the only
|
|
827
|
+
* party that can end it. Deliberately BEFORE the instruments below: this is not a
|
|
828
|
+
* retry and must not be counted as one. The absence of the capability can never
|
|
829
|
+
* silently become an unsafe retry — that is the whole point of detecting it.
|
|
830
|
+
*
|
|
831
|
+
* TWO ways to land here, and the log says which: the transaction cannot savepoint at
|
|
832
|
+
* all (MemoryDb, Mongo), or no rewind point was taken because this command is not
|
|
833
|
+
* `optimistic` (the gate above). Same refusal, same reason — nothing can rewind this
|
|
834
|
+
* attempt's partial rows — but they are diagnosed differently, so they are named.
|
|
835
|
+
*
|
|
836
|
+
* "RESOLVES TO", not "declares": the mode may be the command's own declaration or the
|
|
837
|
+
* one `resolveConcurrencyMode` assigns it, and a non-aggregate External System reads
|
|
838
|
+
* as `unversioned` having declared nothing at all. Saying "declares" would send the
|
|
839
|
+
* reader looking for a declaration that is not in the source. */
|
|
840
|
+
const noRewindReason = canSavepoint(transaction)
|
|
841
|
+
? `the command resolves to concurrency: '${concurrency}', so no rewind point was taken`
|
|
842
|
+
: 'the caller-supplied transaction cannot SAVEPOINT';
|
|
843
|
+
logger.error('Command', commandName, 'in', commandHandler.name, 'lost an optimistic-concurrency check on stream', err.details?.stream, `— NOT retried: ${noRewindReason}, so a retry would re-execute on top of this attempt's own uncommitted rows. Propagating to the transaction's owner`, err);
|
|
844
|
+
}
|
|
845
|
+
else if (retryAttempts < OCC_RETRY_CEILING) {
|
|
846
|
+
/* ── BACKOFF ONLY WHEN WE OWN THE TRANSACTION ──────────────────────────────
|
|
847
|
+
*
|
|
848
|
+
* A caller-supplied `transaction` is still OPEN here: the rejection came from
|
|
849
|
+
* `innerTransactionOperation( transaction )` above, which — unlike the pooled
|
|
850
|
+
* path — does not commit-or-rollback-and-release before rejecting. The
|
|
851
|
+
* transaction is the caller's to end, so its BEGIN is live, and under PgBouncer
|
|
852
|
+
* TRANSACTION POOLING an open transaction PINS one server backend out of a
|
|
853
|
+
* small pool (`default_pool_size`). Sleeping there would pin a scarce backend
|
|
854
|
+
* while doing nothing at all, and the callers that take this path are exactly
|
|
855
|
+
* the fan-out ones — bulk item/stock writes, item merge, publication batch
|
|
856
|
+
* editing — where several such commands run concurrently. That converts a
|
|
857
|
+
* herd-breaking measure into a pool-exhaustion one.
|
|
858
|
+
*
|
|
859
|
+
* Nothing is lost by not sleeping: the caller-owned path now REWINDS below, so it
|
|
860
|
+
* re-executes from the state its first attempt began with rather than on top of
|
|
861
|
+
* its own partial rows.
|
|
862
|
+
*
|
|
863
|
+
* Recorded as `0` rather than skipped, so "how much of this command's latency
|
|
864
|
+
* was backoff" stays answerable — and so the two paths are distinguishable in
|
|
865
|
+
* the histogram instead of one of them silently vanishing from it. */
|
|
866
|
+
const backoffMs = transaction ? 0 : occBackoffMs(retryAttempts);
|
|
867
|
+
// Pure side effects — both instruments are no-throw, so control flow below is
|
|
868
|
+
// exactly what it was before.
|
|
869
|
+
getOccInstruments()?.retry.add(1, occLabels);
|
|
870
|
+
getOccInstruments()?.backoff.record(backoffMs, occLabels);
|
|
871
|
+
logger.debug('Retrying command', commandName, 'in', commandHandler.name, 'due to ConcurrencyError on stream', err.details?.stream, `— attempt ${retryAttempts + 1}/${OCC_RETRY_CEILING} after ${backoffMs}ms`, transaction ? 'with transaction' : 'without transaction');
|
|
872
|
+
// De-synchronize the losers before they collide again on the same tick.
|
|
873
|
+
if (backoffMs)
|
|
874
|
+
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
875
|
+
if (rewindable && savepoint) {
|
|
876
|
+
// Discard everything this attempt wrote through the caller's transaction, back to
|
|
877
|
+
// the point the FIRST attempt started from. The transaction survives it: the
|
|
878
|
+
// conflict was raised by us, not by Postgres — the statement completed (that is
|
|
879
|
+
// what `ON CONFLICT` buys) — so this is a healthy transaction, not an aborted one.
|
|
880
|
+
await rewindable.rollbackToSavepoint(savepoint);
|
|
881
|
+
// IMMEDIATELY after the rollback, and the ordering is the point: an eventstore may
|
|
882
|
+
// cache per-transaction state that was only true while those rows existed
|
|
883
|
+
// (`PostgresEventstore` caches the head version of every stream the transaction
|
|
884
|
+
// appended to). Left in place it would go on claiming rows the rollback deleted,
|
|
885
|
+
// and the next append would number itself from a version that no longer exists —
|
|
886
|
+
// a permanent gap, silently, on a run that otherwise looks green.
|
|
887
|
+
eventstore.forgetTransactionState?.(rewindable);
|
|
888
|
+
}
|
|
889
|
+
return executeCommand(commandHandler, commandName, transaction, schemas, retryAttempts + 1, savepoint)(actionParams);
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
// The budget is spent and NOTHING was committed. This is the alertable event: the
|
|
893
|
+
// caller's intent — an order's stock decrement, a ledger posting — did not happen.
|
|
894
|
+
getOccInstruments()?.exhausted.add(1, occLabels);
|
|
895
|
+
logger.error('Command', commandName, 'in', commandHandler.name, `EXHAUSTED ${OCC_RETRY_CEILING} optimistic-concurrency retries on stream`, err.details?.stream, '— nothing was committed', err);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (command.onErrorHandler)
|
|
899
|
+
return command.onErrorHandler(err, actionParams.body);
|
|
900
|
+
return Promise.reject(err);
|
|
901
|
+
});
|
|
902
|
+
if (!establishedHere || !rewindable || !savepoint)
|
|
903
|
+
return attempt;
|
|
904
|
+
const result = await attempt;
|
|
905
|
+
/* Release only the savepoint this call ESTABLISHED, and only once the whole retry chain
|
|
906
|
+
* has SUCCEEDED. Releasing merges the subtransaction into its parent and frees its
|
|
907
|
+
* resource owner — it undoes nothing, and it keeps the nesting flat so a later
|
|
908
|
+
* `ROLLBACK TO` cannot land on a stale inner point.
|
|
909
|
+
*
|
|
910
|
+
* It does NOT stop subtransactions from accumulating, and must not be read as if it did:
|
|
911
|
+
* the released subtransaction's XID stays in the top-level transaction's `PGPROC` subxid
|
|
912
|
+
* list until that transaction ends, so a caller-owned transaction issuing more than
|
|
913
|
+
* `PGPROC_MAX_CACHED_SUBXIDS` (64) commands still goes suboverflowed. That is a CARRIED
|
|
914
|
+
* RISK of running many commands on one transaction (`itemMerge.endpoints.ts`), recorded
|
|
915
|
+
* as such — releasing is hygiene, not a cure.
|
|
916
|
+
*
|
|
917
|
+
* Not released on the failure path on purpose: the transaction may be aborted by then, and
|
|
918
|
+
* `RELEASE SAVEPOINT` would throw and MASK the caller's real error. Postgres discards every
|
|
919
|
+
* savepoint when the transaction ends, so the only cost of skipping it is the memory of a
|
|
920
|
+
* transaction that is about to end anyway.
|
|
921
|
+
*
|
|
922
|
+
* A failure to release does NOT fail a command that already committed its events: the
|
|
923
|
+
* caller would see an error for work that actually happened and could reasonably re-issue
|
|
924
|
+
* it, duplicating the events. One leaked savepoint on a transaction its owner is about to
|
|
925
|
+
* end is the cheaper of the two. */
|
|
926
|
+
try {
|
|
927
|
+
await rewindable.releaseSavepoint(savepoint);
|
|
928
|
+
}
|
|
929
|
+
catch (releaseError) {
|
|
930
|
+
logger.warn('Command', commandName, 'in', commandHandler.name, 'could not release its optimistic-concurrency savepoint; the command itself succeeded', releaseError);
|
|
931
|
+
}
|
|
932
|
+
return result;
|
|
933
|
+
};
|
|
934
|
+
const getCommandSchemas = (commandHandler, command, name) => {
|
|
935
|
+
const eventsSchemas = command.events?.reduce((schemas, eventName) => {
|
|
936
|
+
if (!!commandHandler.events[eventName])
|
|
937
|
+
schemas[eventName] = commandHandler.events[eventName]().schema || jsonschema_definer_1.default.null();
|
|
938
|
+
if (schemas[eventName])
|
|
939
|
+
schemas[eventName] = schemas[eventName].id(eventName);
|
|
940
|
+
return schemas;
|
|
941
|
+
}, {});
|
|
942
|
+
const responses = !eventsSchemas || Object.keys(eventsSchemas).length === 0
|
|
943
|
+
? {
|
|
944
|
+
200: [{
|
|
945
|
+
schema: jsonschema_definer_1.default.shape({
|
|
946
|
+
state: commandHandler.schema.id(`${commandHandler.name}State`)
|
|
947
|
+
}),
|
|
948
|
+
name: 'OK'
|
|
949
|
+
}]
|
|
950
|
+
}
|
|
951
|
+
: {
|
|
952
|
+
200: [{
|
|
953
|
+
schema: commandHandler.isAggregate
|
|
954
|
+
? jsonschema_definer_1.default.shape({
|
|
955
|
+
state: commandHandler.schema.id(`${commandHandler.name}State`),
|
|
956
|
+
events: (0, pv3_types_1.CommittedEventSchema)(jsonschema_definer_1.default.anyOf(...Object.values(eventsSchemas)), Object.keys(eventsSchemas))
|
|
957
|
+
})
|
|
958
|
+
: jsonschema_definer_1.default.shape({
|
|
959
|
+
events: (0, pv3_types_1.CommittedEventSchema)(jsonschema_definer_1.default.anyOf(...Object.values(eventsSchemas)), Object.keys(eventsSchemas))
|
|
960
|
+
}),
|
|
961
|
+
name: 'OK'
|
|
962
|
+
}]
|
|
963
|
+
};
|
|
964
|
+
command.schema.id(command.name || name);
|
|
965
|
+
const query = pv3_types_1.CommandEndpointQuerySchema;
|
|
966
|
+
return {
|
|
967
|
+
query,
|
|
968
|
+
body: command.schema,
|
|
969
|
+
responses,
|
|
970
|
+
// If it has dataPropertyId, it is a multiStream command, so it does not need params
|
|
971
|
+
...(commandHandler.isStreamable && !command.dataPropertyId
|
|
972
|
+
? { params: pv3_types_1.SystemEndpointParamsSchema }
|
|
973
|
+
: {})
|
|
974
|
+
};
|
|
975
|
+
};
|
|
976
|
+
const registerCommandHandlerGetEndpoints = (commandHandler, name = commandHandler.name) => {
|
|
977
|
+
const isStreamable = !!commandHandler.eventReducers ||
|
|
978
|
+
commandHandler.isStreamable;
|
|
979
|
+
const [streamRoute, idRoute] = (0, utils_1.getCommandHandlerGetRoutes)(isStreamable ? 'aggregate' : 'system', commandHandler);
|
|
980
|
+
if (!commandHandler.isEventsourced && !commandHandler.outboxDatabase)
|
|
981
|
+
throw Error('Aggregate declared as Not Eventsourced without Outbox database.');
|
|
982
|
+
isStreamable &&
|
|
983
|
+
endpoint.registerEndpoint({
|
|
984
|
+
name: `Get ${name} state by Id`,
|
|
985
|
+
description: `Get current reduced ${name} state by Id`,
|
|
986
|
+
method: 'GET',
|
|
987
|
+
loggingModule: (0, change_case_1.paramCase)(name),
|
|
988
|
+
subdomain: commandHandler.subdomain,
|
|
989
|
+
artifact: {
|
|
990
|
+
type: commandHandler.isAggregate ? 'aggregate' : 'externalSystem',
|
|
991
|
+
name: commandHandler.name
|
|
992
|
+
},
|
|
993
|
+
route: idRoute,
|
|
994
|
+
tags: [],
|
|
995
|
+
schemas: {
|
|
996
|
+
params: pv3_types_1.SystemEndpointParamsSchema,
|
|
997
|
+
query: pv3_types_1.SystemGetQuerySchema
|
|
998
|
+
},
|
|
999
|
+
action: ({ params, query }) => (0, exports.loadAggregateState)(eventstore)(commandHandler, (0, utils_2.formatStream)(commandHandler.name, params?.id), (0, exports.formatAggregateGetQueryParams)(query)).then((response) => response && Object.values(response)[0])
|
|
1000
|
+
});
|
|
1001
|
+
endpoint.registerEndpoint({
|
|
1002
|
+
name: (0, utils_1.formatRouteForCommandHandler)(name, change_case_1.pascalCase),
|
|
1003
|
+
description: `Get the stream of events for ${name} by Id`,
|
|
1004
|
+
method: 'GET',
|
|
1005
|
+
loggingModule: (0, change_case_1.paramCase)(name),
|
|
1006
|
+
subdomain: commandHandler.subdomain,
|
|
1007
|
+
artifact: {
|
|
1008
|
+
type: commandHandler.isAggregate ? 'aggregate' : 'externalSystem',
|
|
1009
|
+
name: commandHandler.name
|
|
1010
|
+
},
|
|
1011
|
+
tags: commandHandler.isAggregate ? ['aggregate'] : ['system'],
|
|
1012
|
+
route: streamRoute,
|
|
1013
|
+
schemas: {
|
|
1014
|
+
params: isStreamable ? pv3_types_1.SystemEndpointParamsSchema : undefined,
|
|
1015
|
+
query: pv3_types_1.SystemGetQuerySchema
|
|
1016
|
+
},
|
|
1017
|
+
action: ({ params, query }) => (isStreamable
|
|
1018
|
+
? (0, exports.loadStream)(eventstore)((0, utils_2.formatStream)(commandHandler.name, params?.id), query)
|
|
1019
|
+
: (0, exports.loadStream)(eventstore)(name, (0, exports.formatAggregateGetQueryParams)(query))).then((response) => (Array.isArray(response) ? response : []))
|
|
1020
|
+
});
|
|
1021
|
+
return [idRoute, streamRoute];
|
|
1022
|
+
};
|
|
1023
|
+
const registerCommandHandlerPostEndpoints = (commandHandler) => {
|
|
1024
|
+
const commandHandlerName = commandHandler.name;
|
|
1025
|
+
return !commandHandler.commands
|
|
1026
|
+
? {}
|
|
1027
|
+
: (0, bett3r_utils_1.reduce)((result, name) => {
|
|
1028
|
+
const command = commandHandler.commands[name]?.build
|
|
1029
|
+
? commandHandler.commands[name]?.build()
|
|
1030
|
+
: commandHandler.commands[name];
|
|
1031
|
+
const isStreamable = commandHandler.isStreamable && !command.dataPropertyId;
|
|
1032
|
+
const route = (0, utils_1.getCommandPostRoute)(isStreamable ? 'aggregate' : 'system', commandHandler, name);
|
|
1033
|
+
const schemas = getCommandSchemas(commandHandler, command, name);
|
|
1034
|
+
endpoint.registerEndpoint({
|
|
1035
|
+
loggingModule: (0, change_case_1.paramCase)(commandHandlerName),
|
|
1036
|
+
subdomain: commandHandler.subdomain,
|
|
1037
|
+
artifact: {
|
|
1038
|
+
type: commandHandler.isAggregate ? 'aggregate' : 'externalSystem',
|
|
1039
|
+
name: commandHandler.name
|
|
1040
|
+
},
|
|
1041
|
+
name: (0, utils_1.formatRouteForCommandHandler)(name, change_case_1.pascalCase),
|
|
1042
|
+
description: command.description,
|
|
1043
|
+
route,
|
|
1044
|
+
tags: [],
|
|
1045
|
+
schemas,
|
|
1046
|
+
...(command.visibility ? { visibility: command.visibility } : {}),
|
|
1047
|
+
// It is not validated because the command handler will validate it as part of the command handling process. That way the error can be handled by the command handler.
|
|
1048
|
+
shouldValidate: false,
|
|
1049
|
+
method: 'POST',
|
|
1050
|
+
action: executeCommand(commandHandler, name, undefined, schemas)
|
|
1051
|
+
});
|
|
1052
|
+
result[name] = route;
|
|
1053
|
+
return result;
|
|
1054
|
+
}, {}, Object.keys(commandHandler.commands));
|
|
1055
|
+
};
|
|
1056
|
+
return {
|
|
1057
|
+
loadStream: (0, exports.loadStream)(eventstore),
|
|
1058
|
+
loadAggregateState: (0, exports.loadAggregateState)(eventstore),
|
|
1059
|
+
executeCommand,
|
|
1060
|
+
registerCommandHandlerGetEndpoints,
|
|
1061
|
+
registerCommandHandlerPostEndpoints
|
|
1062
|
+
};
|
|
1063
|
+
};
|
|
1064
|
+
exports.createCommandHandlers = createCommandHandlers;
|
|
1065
|
+
//# sourceMappingURL=index.js.map
|