@spine-event-engine/server 2.0.0-snapshot.24 → 2.0.0-snapshot.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -19
- package/REFERENCE.md +538 -150
- package/dist/agent/agent-acceptance-receipts.d.ts +69 -0
- package/dist/agent/agent-acceptance-receipts.d.ts.map +1 -0
- package/dist/agent/agent-acceptance-receipts.js +198 -0
- package/dist/agent/agent-acceptance-receipts.js.map +1 -0
- package/dist/agent/agent-execution-capacity.d.ts +37 -9
- package/dist/agent/agent-execution-capacity.d.ts.map +1 -1
- package/dist/agent/agent-execution-capacity.js +73 -15
- package/dist/agent/agent-execution-capacity.js.map +1 -1
- package/dist/agent/agent-history.d.ts +33 -12
- package/dist/agent/agent-history.d.ts.map +1 -1
- package/dist/agent/agent-history.js +61 -18
- package/dist/agent/agent-history.js.map +1 -1
- package/dist/agent/agent-live-ai-audit.d.ts +95 -0
- package/dist/agent/agent-live-ai-audit.d.ts.map +1 -0
- package/dist/agent/agent-live-ai-audit.js +290 -0
- package/dist/agent/agent-live-ai-audit.js.map +1 -0
- package/dist/agent/agent-live-ai-runtime.d.ts +300 -0
- package/dist/agent/agent-live-ai-runtime.d.ts.map +1 -0
- package/dist/agent/agent-live-ai-runtime.js +611 -0
- package/dist/agent/agent-live-ai-runtime.js.map +1 -0
- package/dist/agent/agent-live-audit.d.ts +67 -0
- package/dist/agent/agent-live-audit.d.ts.map +1 -0
- package/dist/agent/agent-live-audit.js +121 -0
- package/dist/agent/agent-live-audit.js.map +1 -0
- package/dist/agent/agent-live-budget.d.ts +84 -0
- package/dist/agent/agent-live-budget.d.ts.map +1 -0
- package/dist/agent/agent-live-budget.js +161 -0
- package/dist/agent/agent-live-budget.js.map +1 -0
- package/dist/agent/agent-live-fault.d.ts +18 -0
- package/dist/agent/agent-live-fault.d.ts.map +1 -0
- package/dist/agent/{agent-execution-fault.js → agent-live-fault.js} +7 -7
- package/dist/agent/agent-live-fault.js.map +1 -0
- package/dist/agent/agent-live-inputs.d.ts +74 -0
- package/dist/agent/agent-live-inputs.d.ts.map +1 -0
- package/dist/agent/agent-live-inputs.js +15 -0
- package/dist/agent/agent-live-inputs.js.map +1 -0
- package/dist/agent/agent-live-interaction-events.d.ts +46 -0
- package/dist/agent/agent-live-interaction-events.d.ts.map +1 -0
- package/dist/agent/agent-live-interaction-events.js +104 -0
- package/dist/agent/agent-live-interaction-events.js.map +1 -0
- package/dist/agent/agent-live-mcp-controls.d.ts +129 -0
- package/dist/agent/agent-live-mcp-controls.d.ts.map +1 -0
- package/dist/agent/agent-live-mcp-controls.js +228 -0
- package/dist/agent/agent-live-mcp-controls.js.map +1 -0
- package/dist/agent/agent-live-mcp-host.d.ts +88 -0
- package/dist/agent/agent-live-mcp-host.d.ts.map +1 -0
- package/dist/agent/{agent-mcp-host.js → agent-live-mcp-host.js} +1 -1
- package/dist/agent/agent-live-mcp-host.js.map +1 -0
- package/dist/agent/{agent-mcp-runtime.d.ts → agent-live-mcp-runtime.d.ts} +6 -6
- package/dist/agent/agent-live-mcp-runtime.d.ts.map +1 -0
- package/dist/agent/{agent-mcp-runtime.js → agent-live-mcp-runtime.js} +13 -42
- package/dist/agent/agent-live-mcp-runtime.js.map +1 -0
- package/dist/agent/agent-live-read-runtime.d.ts +72 -0
- package/dist/agent/agent-live-read-runtime.d.ts.map +1 -0
- package/dist/agent/agent-live-read-runtime.js +122 -0
- package/dist/agent/agent-live-read-runtime.js.map +1 -0
- package/dist/agent/agent-model-selection.d.ts +21 -34
- package/dist/agent/agent-model-selection.d.ts.map +1 -1
- package/dist/agent/agent-model-selection.js +61 -78
- package/dist/agent/agent-model-selection.js.map +1 -1
- package/dist/browser/browser-server.d.ts +163 -0
- package/dist/browser/browser-server.d.ts.map +1 -1
- package/dist/browser/browser-server.js +579 -188
- package/dist/browser/browser-server.js.map +1 -1
- package/dist/browser/durable-subscription-bindings.d.ts +5 -0
- package/dist/browser/durable-subscription-bindings.d.ts.map +1 -1
- package/dist/browser/durable-subscription-bindings.js +226 -38
- package/dist/browser/durable-subscription-bindings.js.map +1 -1
- package/dist/browser/options.d.ts +5 -0
- package/dist/browser/options.d.ts.map +1 -1
- package/dist/bus/command-bus.d.ts +17 -18
- package/dist/bus/command-bus.d.ts.map +1 -1
- package/dist/bus/command-bus.js +97 -54
- package/dist/bus/command-bus.js.map +1 -1
- package/dist/bus/command-errors.d.ts +20 -4
- package/dist/bus/command-errors.d.ts.map +1 -1
- package/dist/bus/command-errors.js +47 -7
- package/dist/bus/command-errors.js.map +1 -1
- package/dist/bus/event-bus.d.ts +20 -4
- package/dist/bus/event-bus.d.ts.map +1 -1
- package/dist/bus/event-bus.js +166 -14
- package/dist/bus/event-bus.js.map +1 -1
- package/dist/context/bounded-context.d.ts +169 -98
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +837 -503
- package/dist/context/bounded-context.js.map +1 -1
- package/dist/context/entity-inbox.d.ts +7 -2
- package/dist/context/entity-inbox.d.ts.map +1 -1
- package/dist/context/entity-inbox.js +22 -13
- package/dist/context/entity-inbox.js.map +1 -1
- package/dist/context/local-inbox-handoff.d.ts +34 -34
- package/dist/context/local-inbox-handoff.d.ts.map +1 -1
- package/dist/context/local-inbox-handoff.js +108 -150
- package/dist/context/local-inbox-handoff.js.map +1 -1
- package/dist/context/projection-handoff.d.ts +2 -2
- package/dist/context/projection-handoff.d.ts.map +1 -1
- package/dist/context/projection-handoff.js +10 -8
- package/dist/context/projection-handoff.js.map +1 -1
- package/dist/context/tenant-index.d.ts +36 -31
- package/dist/context/tenant-index.d.ts.map +1 -1
- package/dist/context/tenant-index.js +123 -125
- package/dist/context/tenant-index.js.map +1 -1
- package/dist/context/tenant-unknown-error.d.ts +33 -0
- package/dist/context/tenant-unknown-error.d.ts.map +1 -0
- package/dist/context/tenant-unknown-error.js +75 -0
- package/dist/context/tenant-unknown-error.js.map +1 -0
- package/dist/delivery/agent-delivery-scope.d.ts +66 -0
- package/dist/delivery/agent-delivery-scope.d.ts.map +1 -0
- package/dist/delivery/agent-delivery-scope.js +44 -0
- package/dist/delivery/agent-delivery-scope.js.map +1 -0
- package/dist/delivery/delivery-builder.d.ts +25 -1
- package/dist/delivery/delivery-builder.d.ts.map +1 -1
- package/dist/delivery/delivery-builder.js +89 -0
- package/dist/delivery/delivery-builder.js.map +1 -1
- package/dist/delivery/delivery-monitor.d.ts +1 -1
- package/dist/delivery/delivery-monitor.js +1 -1
- package/dist/delivery/delivery-run-control.d.ts +6 -0
- package/dist/delivery/delivery-run-control.d.ts.map +1 -1
- package/dist/delivery/delivery-run-control.js +10 -0
- package/dist/delivery/delivery-run-control.js.map +1 -1
- package/dist/delivery/delivery-supervisor.d.ts.map +1 -1
- package/dist/delivery/delivery-supervisor.js +28 -4
- package/dist/delivery/delivery-supervisor.js.map +1 -1
- package/dist/delivery/delivery-tenant.d.ts +17 -0
- package/dist/delivery/delivery-tenant.d.ts.map +1 -0
- package/dist/delivery/delivery-tenant.js +50 -0
- package/dist/delivery/delivery-tenant.js.map +1 -0
- package/dist/delivery/delivery.d.ts +96 -2
- package/dist/delivery/delivery.d.ts.map +1 -1
- package/dist/delivery/delivery.js +693 -53
- package/dist/delivery/delivery.js.map +1 -1
- package/dist/delivery/inbox-records.d.ts.map +1 -1
- package/dist/delivery/inbox-records.js +9 -16
- package/dist/delivery/inbox-records.js.map +1 -1
- package/dist/delivery/inbox-storage.d.ts +6 -0
- package/dist/delivery/inbox-storage.d.ts.map +1 -1
- package/dist/delivery/inbox-storage.js +43 -6
- package/dist/delivery/inbox-storage.js.map +1 -1
- package/dist/delivery/inbox.d.ts.map +1 -1
- package/dist/delivery/inbox.js +3 -2
- package/dist/delivery/inbox.js.map +1 -1
- package/dist/delivery/reception-observation.d.ts +12 -4
- package/dist/delivery/reception-observation.d.ts.map +1 -1
- package/dist/delivery/reception-observation.js +14 -3
- package/dist/delivery/reception-observation.js.map +1 -1
- package/dist/delivery/sharded-work-registry.d.ts +6 -0
- package/dist/delivery/sharded-work-registry.d.ts.map +1 -1
- package/dist/delivery/sharded-work-registry.js +41 -4
- package/dist/delivery/sharded-work-registry.js.map +1 -1
- package/dist/entity/entity-storage-descriptor.d.ts.map +1 -1
- package/dist/entity/entity-storage-descriptor.js +7 -4
- package/dist/entity/entity-storage-descriptor.js.map +1 -1
- package/dist/entity/entity.d.ts +59 -0
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +60 -0
- package/dist/entity/entity.js.map +1 -1
- package/dist/handler/app-query-handler.d.ts +60 -0
- package/dist/handler/app-query-handler.d.ts.map +1 -0
- package/dist/{bus/saved-dispatcher-binding.js → handler/app-query-handler.js} +8 -12
- package/dist/handler/app-query-handler.js.map +1 -0
- package/dist/handler/generated-registry-discovery.d.ts +6 -0
- package/dist/handler/generated-registry-discovery.d.ts.map +1 -1
- package/dist/handler/generated-registry-discovery.js +71 -2
- package/dist/handler/generated-registry-discovery.js.map +1 -1
- package/dist/handler/handler-decorators.d.ts +8 -29
- package/dist/handler/handler-decorators.d.ts.map +1 -1
- package/dist/handler/handler-decorators.js +33 -210
- package/dist/handler/handler-decorators.js.map +1 -1
- package/dist/handler/spine-metadata-inventory.d.ts +99 -0
- package/dist/handler/spine-metadata-inventory.d.ts.map +1 -0
- package/dist/handler/spine-metadata-inventory.js +162 -0
- package/dist/handler/spine-metadata-inventory.js.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/integration/external-messages.d.ts.map +1 -1
- package/dist/integration/external-messages.js +9 -15
- package/dist/integration/external-messages.js.map +1 -1
- package/dist/integration/integration-broker.d.ts.map +1 -1
- package/dist/integration/integration-broker.js +112 -6
- package/dist/integration/integration-broker.js.map +1 -1
- package/dist/integration/third-party-context.d.ts.map +1 -1
- package/dist/integration/third-party-context.js +7 -10
- package/dist/integration/third-party-context.js.map +1 -1
- package/dist/repository/primitive-id.js +26 -11
- package/dist/repository/primitive-id.js.map +1 -1
- package/dist/repository/repository.d.ts +75 -60
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +1757 -1818
- package/dist/repository/repository.js.map +1 -1
- package/dist/runtime/runtime.d.ts +13 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +18 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/signal-metadata.d.ts.map +1 -1
- package/dist/runtime/signal-metadata.js +6 -6
- package/dist/runtime/signal-metadata.js.map +1 -1
- package/dist/runtime/signal-publisher.d.ts +0 -6
- package/dist/runtime/signal-publisher.d.ts.map +1 -1
- package/dist/runtime/signal-publisher.js +1 -9
- package/dist/runtime/signal-publisher.js.map +1 -1
- package/dist/runtime/standalone-handler-runtime.d.ts +0 -7
- package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -1
- package/dist/runtime/standalone-handler-runtime.js +13 -99
- package/dist/runtime/standalone-handler-runtime.js.map +1 -1
- package/dist/server/managed-delivery-gate.d.ts +34 -0
- package/dist/server/managed-delivery-gate.d.ts.map +1 -0
- package/dist/server/managed-delivery-gate.js +70 -0
- package/dist/server/managed-delivery-gate.js.map +1 -0
- package/dist/server/managed-server-application.d.ts +12 -11
- package/dist/server/managed-server-application.d.ts.map +1 -1
- package/dist/server/managed-server-application.js +48 -29
- package/dist/server/managed-server-application.js.map +1 -1
- package/dist/server/node-coordinator.d.ts +18 -5
- package/dist/server/node-coordinator.d.ts.map +1 -1
- package/dist/server/node-coordinator.js +554 -84
- package/dist/server/node-coordinator.js.map +1 -1
- package/dist/server/reserved-spine-rpc-paths.json +1 -0
- package/dist/server/server-environment.d.ts +220 -25
- package/dist/server/server-environment.d.ts.map +1 -1
- package/dist/server/server-environment.js +734 -145
- package/dist/server/server-environment.js.map +1 -1
- package/dist/server/server-log.d.ts +7 -0
- package/dist/server/server-log.d.ts.map +1 -1
- package/dist/server/server-log.js +14 -1
- package/dist/server/server-log.js.map +1 -1
- package/dist/server/server.d.ts +60 -29
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +155 -201
- package/dist/server/server.js.map +1 -1
- package/dist/services/app-query-execution.d.ts +53 -0
- package/dist/services/app-query-execution.d.ts.map +1 -0
- package/dist/services/app-query-execution.js +408 -0
- package/dist/services/app-query-execution.js.map +1 -0
- package/dist/services/query-reader.d.ts +32 -7
- package/dist/services/query-reader.d.ts.map +1 -1
- package/dist/services/query-reader.js +22 -2
- package/dist/services/query-reader.js.map +1 -1
- package/dist/services/read-request-status.d.ts +65 -0
- package/dist/services/read-request-status.d.ts.map +1 -0
- package/dist/services/read-request-status.js +151 -0
- package/dist/services/read-request-status.js.map +1 -0
- package/dist/services/spine-services.d.ts +37 -8
- package/dist/services/spine-services.d.ts.map +1 -1
- package/dist/services/spine-services.js +1103 -470
- package/dist/services/spine-services.js.map +1 -1
- package/dist/services/trusted-reader-ingress.d.ts +92 -0
- package/dist/services/trusted-reader-ingress.d.ts.map +1 -0
- package/dist/services/trusted-reader-ingress.js +89 -0
- package/dist/services/trusted-reader-ingress.js.map +1 -0
- package/dist/spi/handler-registry.d.ts +2 -0
- package/dist/spi/handler-registry.d.ts.map +1 -1
- package/dist/spi/handler-registry.js +1 -1
- package/dist/spi/handler-registry.js.map +1 -1
- package/dist/stand/event-origin-filter.js +3 -3
- package/dist/stand/event-origin-filter.js.map +1 -1
- package/dist/stand/read-side-filter-engine.d.ts +46 -0
- package/dist/stand/read-side-filter-engine.d.ts.map +1 -0
- package/dist/stand/read-side-filter-engine.js +356 -0
- package/dist/stand/read-side-filter-engine.js.map +1 -0
- package/dist/stand/read-side-filter.d.ts +247 -0
- package/dist/stand/read-side-filter.d.ts.map +1 -0
- package/dist/stand/read-side-filter.js +39 -0
- package/dist/stand/read-side-filter.js.map +1 -0
- package/dist/stand/read-side-message.d.ts +66 -0
- package/dist/stand/read-side-message.d.ts.map +1 -0
- package/dist/stand/read-side-message.js +167 -0
- package/dist/stand/read-side-message.js.map +1 -0
- package/dist/stand/stand-direct-delivery.d.ts +161 -0
- package/dist/stand/stand-direct-delivery.d.ts.map +1 -0
- package/dist/stand/stand-direct-delivery.js +210 -0
- package/dist/stand/stand-direct-delivery.js.map +1 -0
- package/dist/stand/stand.d.ts +94 -42
- package/dist/stand/stand.d.ts.map +1 -1
- package/dist/stand/stand.js +460 -60
- package/dist/stand/stand.js.map +1 -1
- package/dist/stand/subscription-observer.d.ts.map +1 -1
- package/dist/stand/subscription-observer.js +157 -40
- package/dist/stand/subscription-observer.js.map +1 -1
- package/dist/stand/subscription-read-filters.d.ts +40 -0
- package/dist/stand/subscription-read-filters.d.ts.map +1 -0
- package/dist/stand/subscription-read-filters.js +91 -0
- package/dist/stand/subscription-read-filters.js.map +1 -0
- package/dist/stand/subscription-reader-binding.d.ts +20 -0
- package/dist/stand/subscription-reader-binding.d.ts.map +1 -0
- package/dist/stand/subscription-reader-binding.js +56 -0
- package/dist/stand/subscription-reader-binding.js.map +1 -0
- package/dist/stand/subscription-records.d.ts +30 -3
- package/dist/stand/subscription-records.d.ts.map +1 -1
- package/dist/stand/subscription-records.js +61 -16
- package/dist/stand/subscription-records.js.map +1 -1
- package/dist/stand/subscription-registry.d.ts +54 -15
- package/dist/stand/subscription-registry.d.ts.map +1 -1
- package/dist/stand/subscription-registry.js +164 -41
- package/dist/stand/subscription-registry.js.map +1 -1
- package/dist/stand/subscription-runtime.d.ts +12 -5
- package/dist/stand/subscription-runtime.d.ts.map +1 -1
- package/dist/stand/subscription-runtime.js +183 -34
- package/dist/stand/subscription-runtime.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +4 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -14
- package/dist/agent/agent-admission.d.ts +0 -80
- package/dist/agent/agent-admission.d.ts.map +0 -1
- package/dist/agent/agent-admission.js +0 -127
- package/dist/agent/agent-admission.js.map +0 -1
- package/dist/agent/agent-ai-runtime.d.ts +0 -76
- package/dist/agent/agent-ai-runtime.d.ts.map +0 -1
- package/dist/agent/agent-ai-runtime.js +0 -1269
- package/dist/agent/agent-ai-runtime.js.map +0 -1
- package/dist/agent/agent-execution-fault.d.ts +0 -18
- package/dist/agent/agent-execution-fault.d.ts.map +0 -1
- package/dist/agent/agent-execution-fault.js.map +0 -1
- package/dist/agent/agent-execution-session.d.ts +0 -103
- package/dist/agent/agent-execution-session.d.ts.map +0 -1
- package/dist/agent/agent-execution-session.js +0 -238
- package/dist/agent/agent-execution-session.js.map +0 -1
- package/dist/agent/agent-interaction-audit.d.ts +0 -58
- package/dist/agent/agent-interaction-audit.d.ts.map +0 -1
- package/dist/agent/agent-interaction-audit.js +0 -114
- package/dist/agent/agent-interaction-audit.js.map +0 -1
- package/dist/agent/agent-interaction-events.d.ts +0 -40
- package/dist/agent/agent-interaction-events.d.ts.map +0 -1
- package/dist/agent/agent-interaction-events.js +0 -129
- package/dist/agent/agent-interaction-events.js.map +0 -1
- package/dist/agent/agent-mcp-budget.d.ts +0 -125
- package/dist/agent/agent-mcp-budget.d.ts.map +0 -1
- package/dist/agent/agent-mcp-budget.js +0 -566
- package/dist/agent/agent-mcp-budget.js.map +0 -1
- package/dist/agent/agent-mcp-host.d.ts +0 -125
- package/dist/agent/agent-mcp-host.d.ts.map +0 -1
- package/dist/agent/agent-mcp-host.js.map +0 -1
- package/dist/agent/agent-mcp-runtime.d.ts.map +0 -1
- package/dist/agent/agent-mcp-runtime.js.map +0 -1
- package/dist/agent/agent-read-runtime.d.ts +0 -70
- package/dist/agent/agent-read-runtime.d.ts.map +0 -1
- package/dist/agent/agent-read-runtime.js +0 -320
- package/dist/agent/agent-read-runtime.js.map +0 -1
- package/dist/agent/agent-revisions.d.ts +0 -35
- package/dist/agent/agent-revisions.d.ts.map +0 -1
- package/dist/agent/agent-revisions.js +0 -133
- package/dist/agent/agent-revisions.js.map +0 -1
- package/dist/agent/agent-scheduler.d.ts +0 -99
- package/dist/agent/agent-scheduler.d.ts.map +0 -1
- package/dist/agent/agent-scheduler.js +0 -398
- package/dist/agent/agent-scheduler.js.map +0 -1
- package/dist/bus/saved-dispatcher-binding.d.ts +0 -53
- package/dist/bus/saved-dispatcher-binding.d.ts.map +0 -1
- package/dist/bus/saved-dispatcher-binding.js.map +0 -1
- package/dist/delivery/delivery-run-coordinator.d.ts +0 -218
- package/dist/delivery/delivery-run-coordinator.d.ts.map +0 -1
- package/dist/delivery/delivery-run-coordinator.js +0 -609
- package/dist/delivery/delivery-run-coordinator.js.map +0 -1
- package/dist/delivery/parked-delivery-obligations.d.ts +0 -182
- package/dist/delivery/parked-delivery-obligations.d.ts.map +0 -1
- package/dist/delivery/parked-delivery-obligations.js +0 -390
- package/dist/delivery/parked-delivery-obligations.js.map +0 -1
- package/dist/server/environment-attachment.d.ts +0 -356
- package/dist/server/environment-attachment.d.ts.map +0 -1
- package/dist/server/environment-attachment.js +0 -2062
- package/dist/server/environment-attachment.js.map +0 -1
- package/dist/server/environment-delivery-records.d.ts +0 -77
- package/dist/server/environment-delivery-records.d.ts.map +0 -1
- package/dist/server/environment-delivery-records.js +0 -282
- package/dist/server/environment-delivery-records.js.map +0 -1
- package/dist/server/environment-delivery-worker.d.ts +0 -161
- package/dist/server/environment-delivery-worker.d.ts.map +0 -1
- package/dist/server/environment-delivery-worker.js +0 -973
- package/dist/server/environment-delivery-worker.js.map +0 -1
package/REFERENCE.md
CHANGED
|
@@ -33,7 +33,7 @@ versioned registries are rejected and must be regenerated.
|
|
|
33
33
|
Generated standalone handlers extend `AbstractAssignee`, `AbstractCommander`,
|
|
34
34
|
`AbstractEventReactor`, or `AbstractEventSubscriber`. Register instances with
|
|
35
35
|
`addAssignee()`, `addCommandDispatcher()`, or `addEventDispatcher()` as their
|
|
36
|
-
role requires, then use `
|
|
36
|
+
role requires, then use `build()` to load generated receiver metadata and
|
|
37
37
|
match the exact constructor. Assignees consume Commands and produce Events;
|
|
38
38
|
commanders consume Commands, Events, or rejections and produce Commands;
|
|
39
39
|
reactors consume Events or rejections and may produce Events; subscribers
|
|
@@ -139,7 +139,8 @@ valid event with no interested external receptor is simply not delivered.
|
|
|
139
139
|
## Server environment facilities
|
|
140
140
|
|
|
141
141
|
`ServerEnvironment.instance()` is a process-wide singleton. Production
|
|
142
|
-
resolution requires
|
|
142
|
+
resolution requires the complete application schema registry; storage defaults to
|
|
143
|
+
in-memory when `storageFactory` is omitted:
|
|
143
144
|
|
|
144
145
|
```ts
|
|
145
146
|
import { EnvironmentType, ServerEnvironment } from "@spine-event-engine/server";
|
|
@@ -153,9 +154,52 @@ ServerEnvironment.when(EnvironmentType.Production).use({
|
|
|
153
154
|
storageFactory,
|
|
154
155
|
typeRegistry,
|
|
155
156
|
});
|
|
157
|
+
await ServerEnvironment.instance().completeSetup();
|
|
156
158
|
```
|
|
157
159
|
|
|
158
|
-
`
|
|
160
|
+
Call `completeSetup()` explicitly before building any Bounded Context. It
|
|
161
|
+
checks the storage connection, initializes integration transport, and opens the
|
|
162
|
+
shared Delivery. Concurrent callers join one setup attempt; a failed attempt
|
|
163
|
+
closes acquired facilities and prevents context assembly. Building a context
|
|
164
|
+
does not start setup. The environment logs an INFO message after each successful
|
|
165
|
+
phase without implying that every Entity model has been prepared.
|
|
166
|
+
|
|
167
|
+
`BoundedContextBuilder.build({ createStorageStructures, startSubscriptionMonitoring })`
|
|
168
|
+
awaits both model preparation and the first subscription reconciliation by
|
|
169
|
+
default. Each option can be set to `false` independently. A deferred phase runs
|
|
170
|
+
before the first valid Command, Event, query, subscription operation, or Inbox
|
|
171
|
+
replay for the receiving context; lazy multitenant preparation selects only that
|
|
172
|
+
input's currently registered tenant. A failed lazy attempt rejects its current
|
|
173
|
+
input and can be retried by a later input. Monitoring requires the shared
|
|
174
|
+
subscription registry, so `startSubscriptionMonitoring: true` prepares that
|
|
175
|
+
registry even when `createStorageStructures: false`; it does not prepare all
|
|
176
|
+
tenant Entity families. An eager required preparation or initial monitoring
|
|
177
|
+
failure stops accepting new input and triggers attempt-all cleanup.
|
|
178
|
+
After a successful first pass, a failed periodic reconciliation logs a WARN
|
|
179
|
+
with the context name and bounded error name or code, leaves unaffected observers active,
|
|
180
|
+
and retries on the existing ten-second schedule. Closing the context cancels
|
|
181
|
+
the timer and drains an admitted pass before detaching observers.
|
|
182
|
+
|
|
183
|
+
`context.runtime.createStorageStructures(...tenantIds)` and
|
|
184
|
+
`context.runtime.checkStructureCompatibility(...tenantIds)` prepare declared
|
|
185
|
+
Record, Entity, history, and Agent audit structures through the configured
|
|
186
|
+
provider. The check is read-only; a successful provider check also satisfies
|
|
187
|
+
later creation readiness. Explicit IDs must be registered in the context's
|
|
188
|
+
effective tenant index. With no IDs, a multitenant context traverses its current
|
|
189
|
+
index in finite pages; a single-tenant context prepares its neutral destination
|
|
190
|
+
without registering a synthetic tenant. `context.runtime.startSubscriptionMonitoring()`
|
|
191
|
+
performs the first registry pass independently of per-tenant Entity preparation.
|
|
192
|
+
The environment's no-argument structure methods include both kinds of completed,
|
|
193
|
+
open context. With explicit IDs, they select only matching multitenant contexts,
|
|
194
|
+
respect each `withTenantIndex` override, and reject an ID absent from all current
|
|
195
|
+
indexes before provider work. They validate every supplied ID before preparing
|
|
196
|
+
any structures. Database-backed providers require an existing database; these
|
|
197
|
+
calls do not provision one or register a tenant. Required explicit provider or initial-monitor
|
|
198
|
+
failure stops new input and triggers automatic cleanup. Unknown or malformed IDs,
|
|
199
|
+
directory lookup failure, and local API misuse reject only that operation;
|
|
200
|
+
lazy first-input provider failures remain request-local and retryable.
|
|
201
|
+
|
|
202
|
+
`storageFactory` supplies records and events to every context. `typeRegistry` is the complete
|
|
159
203
|
application schema universe used by `ThirdPartyContext` to encode outgoing
|
|
160
204
|
imported events. An optional `integrationChannelFactory` overrides the
|
|
161
205
|
process-wide private
|
|
@@ -164,6 +208,26 @@ contexts share one in-memory factory, including in production. Local and test
|
|
|
164
208
|
environments default storage in memory and use the core registry only as a
|
|
165
209
|
fallback; those defaults are not production configuration.
|
|
166
210
|
|
|
211
|
+
`tenantIndex` selects a live application membership directory. When omitted,
|
|
212
|
+
the environment uses its storage factory's native catalog where available, or
|
|
213
|
+
a transient in-memory index for a custom factory without a catalog. The
|
|
214
|
+
transient index lasts only for this environment instance. `contains()` checks
|
|
215
|
+
membership without preparing storage; `keep()` makes a registration visible to
|
|
216
|
+
later reads and may reject for a read-only catalog. PostgreSQL and MySQL
|
|
217
|
+
catalogs expose only configured tenant entries: `keep()` is idempotent for
|
|
218
|
+
those entries and rejects unknown IDs. A dynamic SQL tenant resolver does not
|
|
219
|
+
register or enumerate tenants. Single-tenant contexts do not insert a synthetic
|
|
220
|
+
member into this directory.
|
|
221
|
+
|
|
222
|
+
Multitenant receiving contexts check current index membership before Command,
|
|
223
|
+
Event, query, direct repository/history, and subscription work. Inbox persistence
|
|
224
|
+
and later replay check separately, so removing a tenant prevents saved work from
|
|
225
|
+
restoring it. Input does not call `keep()` implicitly. A confirmed missing member
|
|
226
|
+
raises `TenantUnknownError` with the complete tenant ID and context name; native
|
|
227
|
+
services return `NotFound` with a structured `spine.base.Error` detail whose type
|
|
228
|
+
is `TENANT_UNKNOWN`. Lookup failures remain operational errors. Single-tenant
|
|
229
|
+
work does not consult the directory.
|
|
230
|
+
|
|
167
231
|
To override the default channel factory, add
|
|
168
232
|
`integrationChannelFactory: customFactory` to the same settings object.
|
|
169
233
|
|
|
@@ -265,8 +329,8 @@ callbacks receive that scope as their third argument while they run.
|
|
|
265
329
|
|
|
266
330
|
For contexts registered with one `Server`, the target Entity's type URL selects
|
|
267
331
|
its context. No context name or network request is required. The Server rejects
|
|
268
|
-
duplicate Entity type registrations before
|
|
269
|
-
|
|
332
|
+
duplicate Entity type registrations before opening the listener, identifying
|
|
333
|
+
the type and both contexts. Contexts used without a
|
|
270
334
|
Server retain local querying; separate Servers do not share query routes.
|
|
271
335
|
|
|
272
336
|
Cross-context targets must declare `query` or `full` visibility. This applies
|
|
@@ -282,9 +346,11 @@ partition in a multitenant destination. The query never replaces the tenant to
|
|
|
282
346
|
suit the target. A valid query with no matching record keeps its ordinary empty
|
|
283
347
|
result (`undefined` from `findById()`). Reads remain eventually consistent.
|
|
284
348
|
|
|
285
|
-
Routes are available before
|
|
286
|
-
|
|
287
|
-
|
|
349
|
+
Routes are available before ordinary Inbox work resumes. An accepted Agent
|
|
350
|
+
interaction never resumes after interruption; a fresh signal starts fresh work.
|
|
351
|
+
Server shutdown drains admitted handlers across contexts before closing any
|
|
352
|
+
target read-side; failed startup validation participates in context and
|
|
353
|
+
resource cleanup.
|
|
288
354
|
|
|
289
355
|
```ts
|
|
290
356
|
import type { Message } from "@bufbuild/protobuf";
|
|
@@ -506,7 +572,7 @@ const repository = new Repository<typeof ApprovalCoordinator>({
|
|
|
506
572
|
schema: CoordinationStateSchema,
|
|
507
573
|
handlers: handlers as EntityHandlersMetadata<ApprovalCoordinator, typeof CoordinationStateSchema>,
|
|
508
574
|
});
|
|
509
|
-
const context = BoundedContext.singleTenant("Projects").add(repository).build();
|
|
575
|
+
const context = await BoundedContext.singleTenant("Projects").add(repository).build();
|
|
510
576
|
await context.commandBus().post(
|
|
511
577
|
SignalEnvelopes.command({
|
|
512
578
|
context: create(CommandContextSchema),
|
|
@@ -519,9 +585,8 @@ await context.commandBus().post(
|
|
|
519
585
|
The generated record declares `ApproveProjectSchema` as the input and
|
|
520
586
|
`ScheduleProjectSchema` as the emitted Command schema; registry ingestion, not
|
|
521
587
|
manual decorator materialization, constructs the output-bearing metadata.
|
|
522
|
-
Application builds emit the record to
|
|
523
|
-
`generated/
|
|
524
|
-
`buildAsync()` with their compiled package root.
|
|
588
|
+
Application builds emit the record to `generated/spine-metadata.js` and import
|
|
589
|
+
`generated/spine-bootstrap.js` before `build()` selects registered classes.
|
|
525
590
|
|
|
526
591
|
One `@Where({ eventField, equals })` equality filter may narrow an event- or
|
|
527
592
|
rejection-consuming `@Subscribe`, `@React`, or `@Command` handler after type
|
|
@@ -531,18 +596,24 @@ repeated declarations fail closed. It is not an alternative routing mechanism.
|
|
|
531
596
|
Configure logging through `ServerEnvironment` when assembling the server. The
|
|
532
597
|
server installs that logger into its runtime components, where warnings and
|
|
533
598
|
failures carry operation context. Durable facts belong in events or storage.
|
|
534
|
-
|
|
535
|
-
path, so handler effects must be
|
|
599
|
+
Ordinary Aggregate, Process Manager, and Projection Inbox replay sends persisted
|
|
600
|
+
accepted work through the normal handler path, so those handler effects must be
|
|
601
|
+
replay-safe. An accepted Agent interaction is recorded by its receipt and is
|
|
602
|
+
never re-executed after interruption.
|
|
536
603
|
|
|
537
604
|
## Context assembly and entities
|
|
538
605
|
|
|
539
606
|
Create a context with `BoundedContext.singleTenant(name)` or
|
|
540
607
|
`BoundedContext.multitenant(name)`. Names are immutable. Use
|
|
541
|
-
`
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
`
|
|
545
|
-
|
|
608
|
+
`ServerEnvironment.when(type).use({ storageFactory: factory })` before explicit
|
|
609
|
+
environment setup to supply record/event storage to all contexts.
|
|
610
|
+
`withTenantIndex(index)` selects a different live membership directory for one
|
|
611
|
+
context; `context.tenantIndex` and `ServerEnvironment.instance().tenantIndex`
|
|
612
|
+
return the configured objects. Closing a context does not close either index.
|
|
613
|
+
The application imports its generated `spine-bootstrap.js` before registering
|
|
614
|
+
classes with `add(EntityClass)`; `build()` then selects passive descriptions
|
|
615
|
+
by exact constructor and performs assembly, including
|
|
616
|
+
explicit `Repository` registration. Await it before using the context. A built context contains `CommandBus`,
|
|
546
617
|
`EventBus`, `Stand`, repositories, and its storage lifecycle.
|
|
547
618
|
Trusted server-side code can call `context.getRepository(EntityClass)` to obtain
|
|
548
619
|
the already registered repository for that exact constructor. The lookup does
|
|
@@ -559,13 +630,12 @@ registry shapes with an instruction to regenerate.
|
|
|
559
630
|
Each built context also has one `StandSubscriptionRegistry`. By default the
|
|
560
631
|
builder creates a storage-backed registry from the resolved context
|
|
561
632
|
`StorageFactory` (including the `ServerEnvironment` factory used for a builder
|
|
562
|
-
added to a server). It stores one `spine.client.SubscriptionRecord` under each
|
|
633
|
+
added to a server). Its physical `StorageGroup` derives from the logical Bounded Context name, so two contexts using one factory keep distinct definitions. An injected `StorageSubscriptionRegistry` takes an explicit group as its third constructor argument and prepares its captured factory and context. It stores one `spine.client.SubscriptionRecord` under each
|
|
563
634
|
explicit `SubscriptionId`. A complete custom implementation can instead be
|
|
564
635
|
supplied with `withSubscriptionRegistry(registry)`; responsibility transfers to
|
|
565
636
|
the builder on the first build attempt.
|
|
566
637
|
|
|
567
|
-
`SubscriptionService` streams are live
|
|
568
|
-
ordering, or completeness contracts. A standalone Server defaults to the
|
|
638
|
+
`SubscriptionService` streams are live notifications. Each subscriber receives its admitted filtered updates in order, but there is no replay, exactly-once, or cluster-wide completeness guarantee. A standalone Server defaults to the
|
|
569
639
|
persistent registry. In a group of managed server replicas, the framework starts
|
|
570
640
|
and closes each child Server and accepts only every context's actual
|
|
571
641
|
`InMemorySubscriptionRegistry`; a persistent or custom registry is rejected
|
|
@@ -573,7 +643,12 @@ and the assembled child is closed before READY. Durable logical bindings remain
|
|
|
573
643
|
Gateway-only. The Coordinator fans each logical definition to ready children,
|
|
574
644
|
merges updates, propagates cancellation, and carries no subscription payload on
|
|
575
645
|
parent/child IPC. A late or replacement child synchronizes retained definitions
|
|
576
|
-
before it is eligible for normal requests.
|
|
646
|
+
before it is eligible for normal requests. The Coordinator resolves the same
|
|
647
|
+
`subscriptionQueueCapacity` before binding its HTTP/2 listener. Its activation
|
|
648
|
+
ACK is separate from the update queue, which reserves one active DATA update
|
|
649
|
+
plus the configured waiting count for each logical subscriber. Overflow closes
|
|
650
|
+
that subscriber's relay and aborts its child streams.
|
|
651
|
+
Active definitions attach their
|
|
577
652
|
child streams before admission; subscribed but inactive definitions do not
|
|
578
653
|
block readiness. Each child observes application-configured remote/shared
|
|
579
654
|
Delivery directly. During DRAINING, new unary and shard admission stops while
|
|
@@ -606,12 +681,21 @@ completed cycle. This is best-effort per-node convergence, not a
|
|
|
606
681
|
cluster-completeness, replay, ordering, gap-repair, or exactly-once guarantee.
|
|
607
682
|
|
|
608
683
|
The registry accepts only a generated `SubscriptionId` for activate, get, and
|
|
609
|
-
delete. `create(subscription)` returns `{ kind: "created", entry }` or
|
|
684
|
+
delete. `create(subscription, reader?)` returns `{ kind: "created", entry }` or
|
|
610
685
|
`{ kind: "existing", entry }`; the latter requires byte-equivalent canonical
|
|
611
|
-
content and
|
|
612
|
-
`activate(id)` returns `activated`,
|
|
613
|
-
`
|
|
614
|
-
durable records fail closed.
|
|
686
|
+
content and the same reader binding. A different definition or binding with the
|
|
687
|
+
same ID throws `StandConflictError`. `activate(id, reader?)` returns `activated`,
|
|
688
|
+
`active`, `missing`, `expired`, or `denied`. `delete(id, reader?)` returns `deleted`,
|
|
689
|
+
`missing`, or `denied`. Blank IDs or topics and malformed durable records fail closed.
|
|
690
|
+
|
|
691
|
+
Service requests always supply the admitted principal ID or an explicit anonymous
|
|
692
|
+
binding. When supplied, the registry checks the binding again after every failed
|
|
693
|
+
compare-and-set, before changing a reread record. The omitted argument is for
|
|
694
|
+
trusted internal lifecycle work; it is not a way to admit an unauthenticated RPC.
|
|
695
|
+
Reader identity is stored atomically with the subscription definition and phase.
|
|
696
|
+
Attributes, authority facts, and credentials are not part of the stored identity.
|
|
697
|
+
A missing legacy binding is not anonymous and cannot be claimed by a caller;
|
|
698
|
+
the client must create a new subscription.
|
|
615
699
|
|
|
616
700
|
Entries and nested subscriptions returned by create, activate, get, and
|
|
617
701
|
snapshot are clone-safe views. Protobuf byte arrays remain mutable runtime
|
|
@@ -654,24 +738,24 @@ start a new autonomous Entity loop.
|
|
|
654
738
|
### Configuration
|
|
655
739
|
|
|
656
740
|
Register a factory-created `AiRegistry`, enable `persistSystemEvents()`, and
|
|
657
|
-
configure `
|
|
741
|
+
configure `ai.models` for each Agent repository. Use
|
|
658
742
|
an empty `models` array when that Agent has no model calls. Readiness requires
|
|
659
|
-
indexed Agent history and
|
|
743
|
+
indexed Agent history and atomic live Agent commits from the selected provider.
|
|
660
744
|
The [Support Bounded Context](../../examples/support/src/index.ts) uses generated
|
|
661
745
|
registration with these options.
|
|
662
746
|
|
|
663
747
|
Configuration has these scopes:
|
|
664
748
|
|
|
665
|
-
| Scope | Setting
|
|
666
|
-
| --------------- |
|
|
667
|
-
|
|
|
668
|
-
| Bounded Context | `BoundedContextBuilder.withAi(registry)`
|
|
669
|
-
| Repository | `ai.defaultModels`
|
|
670
|
-
| Repository | `ai.allowedModels`
|
|
671
|
-
| Repository | `ai.resolveModel`
|
|
672
|
-
| Repository | `ai.authorizeSelection`
|
|
673
|
-
| Repository | `ai.invocationLimits`
|
|
674
|
-
| Instance | `this.ai.select(kind, ref)`
|
|
749
|
+
| Scope | Setting | Effect |
|
|
750
|
+
| --------------- | ------------------------------------------ | ---------------------------------------------------------------- |
|
|
751
|
+
| Environment | `ServerEnvironment.when(type).use({ ai })` | Default registry for Bounded Contexts. |
|
|
752
|
+
| Bounded Context | `BoundedContextBuilder.withAi(registry)` | Overrides environment AI for one Bounded Context. |
|
|
753
|
+
| Repository | `ai.defaultModels` | Generation and decision defaults before the registry's defaults. |
|
|
754
|
+
| Repository | `ai.allowedModels` | Deployment references the Agent may use. |
|
|
755
|
+
| Repository | `ai.resolveModel` | Optional accepted-source choice before the Agent handler. |
|
|
756
|
+
| Repository | `ai.authorizeSelection` | Authorizes explicit choices and staged preference changes. |
|
|
757
|
+
| Repository | `ai.invocationLimits` | Limits that can narrow the registry's whole-signal limits. |
|
|
758
|
+
| Instance | `this.ai.select(kind, ref)` | A saved preference applied to later accepted signals. |
|
|
675
759
|
|
|
676
760
|
A prebuilt Bounded Context already has its registry; adding it to a server does not
|
|
677
761
|
reconfigure it. An instance preference takes precedence over its repository
|
|
@@ -687,7 +771,7 @@ signal; `undefined` preserves it. This allows an Agent without a configured
|
|
|
687
771
|
default to start after a deployment is appended to the bound registry. The
|
|
688
772
|
runtime checks repository allowlists, capabilities and `authorizeSelection`
|
|
689
773
|
before saving the selection and connection identity. A saved selection is reused
|
|
690
|
-
|
|
774
|
+
for the current signal. Resolver and authorization callbacks receive linked cancellation
|
|
691
775
|
and the smaller of the invocation deadline and registry hook timeout. An
|
|
692
776
|
effective `this.ai.select()` change, including reset to inheritance, is
|
|
693
777
|
authorized before the Entity transition and preference Events commit; a no-op
|
|
@@ -702,60 +786,30 @@ See [adapter configuration](../ai-vercel-ax/README.md).
|
|
|
702
786
|
|
|
703
787
|
### Acceptance and completion
|
|
704
788
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
Bounded Contexts using
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
starts, recovery continues with the saved deadline and counts. The same deadline
|
|
713
|
-
bounds an awaited application handler. Expiry or Bounded Context shutdown ends that wait
|
|
714
|
-
and prevents late handler results from changing Entity state or emitting signals;
|
|
715
|
-
it cannot stop arbitrary application JavaScript or undo external effects.
|
|
716
|
-
|
|
717
|
-
Newly accepted work supplies its repository and tenant to prompt discovery.
|
|
718
|
-
Periodic discovery reads tenant pages and constructs repository scopes as they
|
|
719
|
-
are needed. It retains at most one page of 16 tenants, four periodic scan scopes,
|
|
720
|
-
and 64 scopes awaiting a prompt scan. A turn requests at most one tenant page
|
|
721
|
-
and reads at most four pending-work pages. It does not load the complete tenant
|
|
722
|
-
catalog or retain a scan position for every tenant.
|
|
723
|
-
|
|
724
|
-
A sweep finishes before another begins. The next starts no earlier than five
|
|
725
|
-
seconds after the preceding sweep started, measured by `Time`; longer sweeps
|
|
726
|
-
restart after completion. This lets discovery reach tenants near the end of a
|
|
727
|
-
large catalog and find later admissions on the next sweep. Periodic scans keep
|
|
728
|
-
their turn during new arrivals, including while execution capacity is full.
|
|
729
|
-
A pending catalog request does not block prompt scans of known scopes.
|
|
730
|
-
|
|
731
|
-
Bounded Context shutdown stops waiting for discovery reads even if a provider ignores
|
|
732
|
-
cancellation. Late results cannot submit work or restart scanning. Built-in
|
|
733
|
-
adapters use their available cancellation and timeout controls; detaching the
|
|
734
|
-
scheduler does not guarantee cancellation of an already issued native request.
|
|
789
|
+
An accepted signal and recipient are admitted through ordinary Delivery. A
|
|
790
|
+
typed receipt prevents a duplicate signal from starting the same Agent turn.
|
|
791
|
+
Within one process, live capacity serializes turns for one Agent instance and
|
|
792
|
+
permits different instances up to configured limits. The shared registry's
|
|
793
|
+
capacity applies across Bounded Contexts using that registry. A waiting signal
|
|
794
|
+
stays in the ordinary Inbox until capacity can admit it; capacity release wakes
|
|
795
|
+
the ordinary Delivery worker. There is no Agent-specific discovery scheduler.
|
|
735
796
|
|
|
736
797
|
The signal's matching handlers share one Entity draft. Each handler can await
|
|
737
|
-
`this.ai.invoke()` through the protected Spine facade. Calls in one handler
|
|
738
|
-
be sequential and finish before it returns. Requests, results and
|
|
739
|
-
validation failures are saved as
|
|
740
|
-
state, Version,
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
normal EventBus. The Agent does not track Event recipients, retry a failed handoff,
|
|
753
|
-
or replay Event delivery after restart. Immutable Agent history remains readable
|
|
754
|
-
independently of EventBus delivery. Saved outgoing Commands retain their original
|
|
755
|
-
IDs and recipient bindings for recovery without rerunning the producing handler
|
|
756
|
-
or model. Generated repository and standalone Command receivers provide the
|
|
757
|
-
required binding metadata; matching raw custom Command dispatchers without it
|
|
758
|
-
are rejected.
|
|
798
|
+
`this.ai.invoke()` through the protected Spine facade. Calls in one handler
|
|
799
|
+
must be sequential and finish before it returns. Requests, results, and
|
|
800
|
+
validation failures are saved as audited history while work progresses. The
|
|
801
|
+
final accepted state, Version, preference changes, and Agent history use an
|
|
802
|
+
atomic live Agent commit. Outgoing Commands enter ordinary command delivery;
|
|
803
|
+
there is no saved Agent-private list to finish after a restart. Emitted domain Events
|
|
804
|
+
enter immutable Agent history before normal EventBus publication. A no-op or
|
|
805
|
+
preference-only turn can commit without a state Version increase. Waiting for a
|
|
806
|
+
provider does not hold a database transaction open.
|
|
807
|
+
|
|
808
|
+
An admitted turn uses a current session and cancellation guard. Shutdown drains
|
|
809
|
+
tracked work and prevents late results from changing Entity state or emitting
|
|
810
|
+
signals. It cannot undo external effects already performed by application code.
|
|
811
|
+
A restarted process can read retained receipts and audit history, but it does
|
|
812
|
+
not replay a model response or re-enter an interrupted Agent handler.
|
|
759
813
|
|
|
760
814
|
### Retained history
|
|
761
815
|
|
|
@@ -775,7 +829,7 @@ persistent provider when records must survive process termination.
|
|
|
775
829
|
All methods return newest entries first. A request supplies positive `pageSize`
|
|
776
830
|
and an optional opaque cursor; `nextCursor` continues toward older entries.
|
|
777
831
|
There is no fixed 100-item or page-byte ceiling. Reads made during a handler count
|
|
778
|
-
toward any configured invocation limits for recorded reads
|
|
832
|
+
toward any configured invocation limits for recorded reads. Ordering
|
|
779
833
|
uses the full Spine `Time` timestamp, category and existing record ID. There is
|
|
780
834
|
no repository-managed history counter. Cursors cannot be transferred across
|
|
781
835
|
Agents, tenants, categories or conversations.
|
|
@@ -795,28 +849,36 @@ For a trusted application bridge, `context.getRepository(AgentClass)` returns
|
|
|
795
849
|
the registered Agent `Repository`, which exposes
|
|
796
850
|
`agentHistory(id, scope)` with the same four history methods and page contracts.
|
|
797
851
|
The scope is explicit: pass `{}` in a single-tenant Bounded Context or
|
|
798
|
-
`{ tenantId }` in a multitenant Bounded Context.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
handler runs
|
|
810
|
-
|
|
852
|
+
`{ tenantId }` in a multitenant Bounded Context. Reads use indexed storage
|
|
853
|
+
without restoring an Agent. The application bridge must authorize access;
|
|
854
|
+
actor metadata does not grant read permission.
|
|
855
|
+
For a trusted in-process caller, the scope can also include detached
|
|
856
|
+
`actorContext`, a verified `reader` with principal and authority facts, and a
|
|
857
|
+
`signal`. Read-side filters receive those facts for that history call; omitting
|
|
858
|
+
`reader` leaves principal and authority facts absent. The bridge supplies
|
|
859
|
+
verified facts explicitly and cannot derive them from `actorContext`.
|
|
860
|
+
|
|
861
|
+
If a selected model's `authorizeUse` callback explicitly returns `false`
|
|
862
|
+
before the handler, the turn records one `AgentInvocationTerminated` System
|
|
863
|
+
Event carrying `MODEL_USE_DENIED`. No handler runs, no application-domain
|
|
864
|
+
result Event is invented, and other failures remain distinct. Applications
|
|
865
|
+
may correlate this fact with the original source through paged Agent history.
|
|
811
866
|
|
|
812
867
|
## Signals, validation, and rejection behavior
|
|
813
868
|
|
|
814
|
-
`CommandBus`
|
|
815
|
-
before
|
|
816
|
-
|
|
817
|
-
`
|
|
818
|
-
|
|
819
|
-
`
|
|
869
|
+
`CommandBus` checks the nonempty Command ID, nondefault message and context,
|
|
870
|
+
and declared payload constraints before admission or dispatcher code runs.
|
|
871
|
+
Annotated packed messages use generated Proto modules registered in the process.
|
|
872
|
+
`SpineServices` reports invalid Commands in an error Ack with type
|
|
873
|
+
`spine.core.CommandValidationError`, numeric `INVALID_COMMAND` code, and a
|
|
874
|
+
packed `spine.validation.ValidationError`. Unsupported Commands use the same
|
|
875
|
+
enum type and numeric `UNSUPPORTED_COMMAND` code.
|
|
876
|
+
Technical validator failures use a sanitized `COMMAND_POST_ERROR` Ack without
|
|
877
|
+
constraint details; they are distinct from invalid Command input.
|
|
878
|
+
Entity transition validation failures that escape service processing map to
|
|
879
|
+
`COMMAND_STATE_TRANSITION_VALIDATION_FAILED` with the same detail type. Managed
|
|
880
|
+
reception of ordinary Entity work sends post-handler transition rejection to `DeliveryMonitor`;
|
|
881
|
+
its default action acknowledges the failed input without storing invalid state.
|
|
820
882
|
Framework-created runtime command and event metadata uses fresh Node secure
|
|
821
883
|
UUIDs; fixed IDs belong only to existing source envelopes retained through the
|
|
822
884
|
normal origin chain.
|
|
@@ -831,6 +893,8 @@ an internal diagnostic, not a retry guarantee.
|
|
|
831
893
|
Every domain context has an internal paired System Context. Domain events use
|
|
832
894
|
the domain `EventBus` and domain `EventStore`. System events use only the
|
|
833
895
|
System Context `EventBus`, so they never enter the domain EventStore.
|
|
896
|
+
Each EventBus validates the Event envelope and domain payload before admission,
|
|
897
|
+
storage, or delivery.
|
|
834
898
|
`persistSystemEvents()` enables the paired System Context's separate storage.
|
|
835
899
|
Bounded Contexts with Agents must enable it. For other Bounded Contexts it is optional; without
|
|
836
900
|
it, the bus validates, dispatches and notifies without appending. Schemas may come from an external dispatcher or
|
|
@@ -847,6 +911,204 @@ work to stop using dependencies, then closes contexts. Caller-managed `start()`
|
|
|
847
911
|
does not close global process facilities; close `ServerEnvironment.instance()`
|
|
848
912
|
separately when used. The final run-managed `run()` close closes its environment.
|
|
849
913
|
|
|
914
|
+
`ServerOptions.appQueries` selects concrete generated `AppQueryHandler<Q, R>`
|
|
915
|
+
instances by exact constructor metadata before listening. Duplicate Q routes
|
|
916
|
+
or missing metadata fail startup. On direct app-node ingress,
|
|
917
|
+
`QueryService.Execute` validates a complete AppQuery envelope and Q, then
|
|
918
|
+
returns one packed paired R. Native and browser Gateways and managed Coordinators
|
|
919
|
+
forward Execute to an app node; `ClientRequest.query(generatedQ)` decodes its paired R.
|
|
920
|
+
The internal
|
|
921
|
+
`Server.query(generatedQ, executionContext)` accepts a generated Q and returns
|
|
922
|
+
its paired generated R, using a detached request and the effective actor,
|
|
923
|
+
verified reader facts, and cancellation signal supplied by the current
|
|
924
|
+
framework invocation. `ProcessManager.currentActorContext` and
|
|
925
|
+
`Agent.currentActorContext` expose only the current signal's detached actor and
|
|
926
|
+
tenant during a handler; neither establishes a verified principal. Constructor
|
|
927
|
+
injection can bind the query function to a Server. Scoped Entity reads require
|
|
928
|
+
query/full visibility and destination tenant membership. Direct calls do not
|
|
929
|
+
cross the Server's gRPC output-filter boundary.
|
|
930
|
+
|
|
931
|
+
`ReadSideFilter<typeof MessageSchema>` declares a typed policy for a registered
|
|
932
|
+
Proto message. Its protected constructor takes the generated schema and optional
|
|
933
|
+
`{ nested: true }`; `filter(message, context)` receives a detached mutable value
|
|
934
|
+
and may return the same type or `null` to remove that occurrence. The context
|
|
935
|
+
separates actor metadata from verified reader facts and identifies the current
|
|
936
|
+
operation, plus a detached containing message and field for nested calls.
|
|
937
|
+
Read-only packed bytes remain available to Buf decoding through a detached
|
|
938
|
+
`value.slice()` passed to `fromBinary`.
|
|
939
|
+
Call `addReadSideFilter(filter)` on a `BoundedContextBuilder` before `build()` to apply it to that
|
|
940
|
+
Bounded Context's outward Entity reads and retained histories. Pass `readSideFilters`
|
|
941
|
+
to `new Server(...)` to apply policies to Entity Query and App Query results
|
|
942
|
+
leaving that Server over gRPC. The same instance can be installed in both
|
|
943
|
+
places; each boundary invokes it once. Direct `Server.query()` runs BC source
|
|
944
|
+
policies but does not cross the Server output boundary. An Entity root returned
|
|
945
|
+
as `null` is omitted without another storage read; an App Query root returned
|
|
946
|
+
as `null` produces OK with zero outer `AppQueryResponse.message` entries. A
|
|
947
|
+
non-null response whose child field is absent remains one response entry.
|
|
948
|
+
History removals retain the
|
|
949
|
+
original continuation. Retained storage, hydration, and replay remain raw.
|
|
950
|
+
Direct Stand and retained-history callbacks identify the producing Bounded
|
|
951
|
+
Context. Protected history called from a handler carries its current signal
|
|
952
|
+
actor; an out-of-handler diagnostic read has no actor or authenticated reader.
|
|
953
|
+
Native SubscriptionService delivery filters already matched Entity states and
|
|
954
|
+
Event payloads through the producing Bounded Context policy and then the
|
|
955
|
+
Server policy. The `subscription` operation includes the original Topic and
|
|
956
|
+
admitted subscription; its context carries the current verified reader facts,
|
|
957
|
+
effective tenant, actor metadata, producing Bounded Context, and cancellation
|
|
958
|
+
signal. Removing a state emits `no_longer_matching` with its original Entity
|
|
959
|
+
ID; removing every Event payload suppresses that data batch. ACKs and existing
|
|
960
|
+
removal controls remain unchanged. Policy failures end only that reader stream
|
|
961
|
+
with a sanitized technical status.
|
|
962
|
+
|
|
963
|
+
The operation describes the call that produced the value. `query` includes the
|
|
964
|
+
actual Query and, during an App Query child read, the enclosing AppQuery. `app-query`
|
|
965
|
+
identifies the final application result. `direct` identifies either a typed
|
|
966
|
+
Stand state read by type URL and Entity ID, a caller-supplied RecordQuery, or a
|
|
967
|
+
normalized query plan. `history` distinguishes an Entity state-at timestamp,
|
|
968
|
+
Entity state/Event history depth, and an Agent view with its page request and
|
|
969
|
+
optional cursor. Direct callers supply actor metadata, verified reader facts,
|
|
970
|
+
and cancellation separately; they cannot override the operation.
|
|
971
|
+
Direct subscription delivery uses `kind: "direct"` with
|
|
972
|
+
`operation.subscription.typeUrl`, distinct from a one-off Stand read's
|
|
973
|
+
`operation.read`.
|
|
974
|
+
|
|
975
|
+
This filter uses the generated Project state and can be installed on the Bounded
|
|
976
|
+
Context builder that contains its Repository:
|
|
977
|
+
|
|
978
|
+
<!-- docs-snippet-path: packages/server/test/server/app-query-execution.test.ts -->
|
|
979
|
+
|
|
980
|
+
```ts
|
|
981
|
+
import {
|
|
982
|
+
type BoundedContextBuilder,
|
|
983
|
+
ReadSideFilter,
|
|
984
|
+
type ReadSideContext,
|
|
985
|
+
} from "@spine-event-engine/server";
|
|
986
|
+
import {
|
|
987
|
+
type ProjectOverviewState,
|
|
988
|
+
ProjectOverviewStateSchema,
|
|
989
|
+
} from "../../test-fixtures/generated/repository-routing/project_states_pb.js";
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Replaces a project name in all ordinary Entity Query results.
|
|
993
|
+
*/
|
|
994
|
+
class PublicProjectName extends ReadSideFilter<typeof ProjectOverviewStateSchema> {
|
|
995
|
+
/**
|
|
996
|
+
* Registers the filter for project overview state.
|
|
997
|
+
*/
|
|
998
|
+
constructor() {
|
|
999
|
+
super(ProjectOverviewStateSchema);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Replaces the name only for ordinary Entity Query responses.
|
|
1004
|
+
*
|
|
1005
|
+
* @param state Project overview returned by the read side.
|
|
1006
|
+
* @param context Describes the read operation and verified reader.
|
|
1007
|
+
* @returns The project overview with its name replaced for ordinary Entity Queries.
|
|
1008
|
+
*/
|
|
1009
|
+
filter(state: ProjectOverviewState, context: ReadSideContext): ProjectOverviewState {
|
|
1010
|
+
if (context.operation.kind === "query") state.name = "Public project";
|
|
1011
|
+
return state;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
const projectPolicy = new PublicProjectName();
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Registers the project name policy in its supplying Bounded Context.
|
|
1019
|
+
*
|
|
1020
|
+
* @param builder Configures the project Bounded Context.
|
|
1021
|
+
* @returns The builder with the read policy installed.
|
|
1022
|
+
*/
|
|
1023
|
+
function installProjectPolicy(builder: BoundedContextBuilder): BoundedContextBuilder {
|
|
1024
|
+
return builder.addReadSideFilter(projectPolicy);
|
|
1025
|
+
}
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
The repository `onCreate` callback can inject `(q, context) => server.query(q, context)`
|
|
1029
|
+
into a Process Manager or Agent. Within an active handler, pass a generated Q
|
|
1030
|
+
with `{ actorContext: this.currentActorContext }`; the actor/tenant snapshot
|
|
1031
|
+
does not supply verified principal or provider facts. The
|
|
1032
|
+
[scoped integration test](https://github.com/SpineEventEngine/spine-ts/blob/master/packages/server/test/entity/process-manager-querying.test.ts) includes
|
|
1033
|
+
the full callback and handler invocation.
|
|
1034
|
+
|
|
1035
|
+
This example uses the generated Project query and the current Process Manager
|
|
1036
|
+
scope; pass `scopedOnCreate(server)` as the repository's `onCreate` callback.
|
|
1037
|
+
Ordinary generation and bootstrap register the decorated handler description:
|
|
1038
|
+
|
|
1039
|
+
<!-- docs-snippet-path: packages/server/test/entity/process-manager-querying.test.ts -->
|
|
1040
|
+
|
|
1041
|
+
```ts
|
|
1042
|
+
import { create } from "@bufbuild/protobuf";
|
|
1043
|
+
import {
|
|
1044
|
+
Assign,
|
|
1045
|
+
ProcessManager,
|
|
1046
|
+
type EntityOptions,
|
|
1047
|
+
type Server,
|
|
1048
|
+
type ServerQueryExecutionContext,
|
|
1049
|
+
} from "@spine-event-engine/server";
|
|
1050
|
+
import { ProcessManagerStateSchema } from "../../test-fixtures/generated/entity-metadata/visibility_pb.js";
|
|
1051
|
+
import { ProjectIdSchema } from "../../test-fixtures/generated/repository-routing/project_identifiers_pb.js";
|
|
1052
|
+
import {
|
|
1053
|
+
type ProjectCreated as ProjectionEvent,
|
|
1054
|
+
ProjectCreatedSchema as ProjectionEventSchema,
|
|
1055
|
+
} from "../../test-fixtures/generated/repository-routing/project_events_pb.js";
|
|
1056
|
+
import { type CreateReviewProject } from "../../test-fixtures/generated/validation-refusal/project_commands_pb.js";
|
|
1057
|
+
import {
|
|
1058
|
+
type GetProjectOverview_Query,
|
|
1059
|
+
type GetProjectOverview_Response,
|
|
1060
|
+
} from "../../test-fixtures/generated/repository-routing/project_queries_pb.js";
|
|
1061
|
+
import { GetProjectOverview } from "../../test-fixtures/generated/repository-routing/project_queries_app_query.js";
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Runs a typed App Query from an active Process Manager handler.
|
|
1065
|
+
*/
|
|
1066
|
+
class ScopedAppQueryManager extends ProcessManager<string, typeof ProcessManagerStateSchema> {
|
|
1067
|
+
/**
|
|
1068
|
+
* Captures the scoped query callback supplied during repository construction.
|
|
1069
|
+
*
|
|
1070
|
+
* @param options Configures this Process Manager instance.
|
|
1071
|
+
* @param ask Executes a generated App Query with trusted handler context.
|
|
1072
|
+
*/
|
|
1073
|
+
constructor(
|
|
1074
|
+
options: EntityOptions<string, typeof ProcessManagerStateSchema>,
|
|
1075
|
+
private readonly ask: (
|
|
1076
|
+
query: GetProjectOverview_Query,
|
|
1077
|
+
context: ServerQueryExecutionContext,
|
|
1078
|
+
) => Promise<GetProjectOverview_Response>,
|
|
1079
|
+
) {
|
|
1080
|
+
super(options);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Reads the current project overview while handling the creation Command.
|
|
1085
|
+
*
|
|
1086
|
+
* @param command Project creation request being assigned.
|
|
1087
|
+
* @returns Event carrying the selected overview name.
|
|
1088
|
+
*/
|
|
1089
|
+
@Assign
|
|
1090
|
+
async assign(command: CreateReviewProject): Promise<ProjectionEvent> {
|
|
1091
|
+
const result = await this.ask(
|
|
1092
|
+
create(GetProjectOverview.querySchema, {
|
|
1093
|
+
project: create(ProjectIdSchema, { value: command.id }),
|
|
1094
|
+
}),
|
|
1095
|
+
{ actorContext: this.currentActorContext },
|
|
1096
|
+
);
|
|
1097
|
+
return create(ProjectionEventSchema, {
|
|
1098
|
+
id: command.id,
|
|
1099
|
+
name: result.project?.name ?? "",
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* Injects the Server's typed App Query route into new Process Manager instances.
|
|
1106
|
+
*/
|
|
1107
|
+
export const scopedOnCreate =
|
|
1108
|
+
(server: Server) => (options: EntityOptions<string, typeof ProcessManagerStateSchema>) =>
|
|
1109
|
+
new ScopedAppQueryManager(options, (q, context) => server.query(q, context));
|
|
1110
|
+
```
|
|
1111
|
+
|
|
850
1112
|
`Stand` registers entity state for point/list reads, updates current state, and
|
|
851
1113
|
offers in-process subscriptions. The legacy-named local reset/replay helper
|
|
852
1114
|
`catchUpReadSide(options?)` clears every registered Projection state and replays
|
|
@@ -877,8 +1139,57 @@ authoritative queries from current state and Entity subscriptions observe
|
|
|
877
1139
|
committed `EntityStateChanged` messages on the paired System Context EventBus,
|
|
878
1140
|
so a direct Stand write alone does not produce a subscription update. Consumer
|
|
879
1141
|
callback failures are isolated from post-commit observation and other
|
|
880
|
-
consumers.
|
|
881
|
-
|
|
1142
|
+
consumers. Native subscription updates enter the existing bounded delivery
|
|
1143
|
+
queue before asynchronous read policies run; a full queue closes that stream.
|
|
1144
|
+
For a surviving Event, policy replaces only its domain payload and retains the original envelope.
|
|
1145
|
+
Direct `Stand.subscribe(schema, { next, error }, options)` applies only its
|
|
1146
|
+
producing Bounded Context's read policies, independently for each local
|
|
1147
|
+
subscriber. `next` receives either `{ kind: "state", state, previousState? }`
|
|
1148
|
+
or `{ kind: "removal", noLongerMatching: true }`; both retain the original type
|
|
1149
|
+
URL, Entity ID, version, and tenant metadata. A removed prior state is omitted
|
|
1150
|
+
from a surviving current state. `error` receives one terminal local policy,
|
|
1151
|
+
callback, or capacity fault. There is no raw callback overload. Options accept
|
|
1152
|
+
trusted `reader` facts, `actorContext` metadata, tenant, and cancellation;
|
|
1153
|
+
`ServerEnvironmentSettings.subscriptionQueueCapacity` sets the waiting count
|
|
1154
|
+
for direct and server-served subscriptions. Configure it before constructing
|
|
1155
|
+
the Stand or Bounded Context. It defaults to 100 waiting updates in addition to
|
|
1156
|
+
one active update; zero allows the active update with no waiting updates. Filter calls
|
|
1157
|
+
and `next` completion are sequential per subscriber. Overflow closes only that
|
|
1158
|
+
subscriber, clears waiting updates, invalidates the active result, and reports
|
|
1159
|
+
`StandSubscriptionCapacityError`; committed writes and other subscribers
|
|
1160
|
+
continue. Unsubscribe, cancellation, and Stand close invalidate outstanding
|
|
1161
|
+
results without waiting for a nonsettling policy. A producer does not await
|
|
1162
|
+
asynchronous policy or observer completion, although CPU-heavy synchronous
|
|
1163
|
+
policy work still runs on the producer's Node event loop.
|
|
1164
|
+
Direct subscribers do not cross a Server output-filter boundary. The package
|
|
1165
|
+
does not guarantee cluster-complete observations, subscription replay,
|
|
1166
|
+
event-gap repair, or exactly-once effects.
|
|
1167
|
+
|
|
1168
|
+
This typed local observer handles visible states, removals, and terminal faults.
|
|
1169
|
+
Configure `subscriptionQueueCapacity: 250` through `ServerEnvironment.when(...).use(...)`
|
|
1170
|
+
before creating the Stand to allow 250 waiting updates beyond the active one:
|
|
1171
|
+
|
|
1172
|
+
<!-- docs-snippet-path: packages/server/test/stand/stand-direct-subscription.test.ts -->
|
|
1173
|
+
|
|
1174
|
+
```ts
|
|
1175
|
+
import { type Stand, type StandSubscription } from "@spine-event-engine/server";
|
|
1176
|
+
import { ProjectOverviewStateSchema } from "../../test-fixtures/generated/repository-routing/project_states_pb.js";
|
|
1177
|
+
|
|
1178
|
+
export function observeProjects(
|
|
1179
|
+
stand: Stand,
|
|
1180
|
+
onState: (name: string) => void,
|
|
1181
|
+
onRemoval: (id: unknown) => void,
|
|
1182
|
+
onError: (error: Error) => void,
|
|
1183
|
+
): StandSubscription {
|
|
1184
|
+
return stand.subscribe(ProjectOverviewStateSchema, {
|
|
1185
|
+
next(update) {
|
|
1186
|
+
if (update.kind === "state") onState(update.state.name);
|
|
1187
|
+
else onRemoval(update.id);
|
|
1188
|
+
},
|
|
1189
|
+
error: onError,
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
```
|
|
882
1193
|
|
|
883
1194
|
### Native and managed hosting
|
|
884
1195
|
|
|
@@ -948,6 +1259,48 @@ gRPC-Web transport message accepted by the public listener, so the effective
|
|
|
948
1259
|
inbound limit is the stricter applicable limit. `writeMaxBytes` limits public
|
|
949
1260
|
transport responses independently.
|
|
950
1261
|
|
|
1262
|
+
### Native reader admission
|
|
1263
|
+
|
|
1264
|
+
Configure app-node admission at `ServerOptions.services.readerAdmission`:
|
|
1265
|
+
|
|
1266
|
+
- `direct.authenticate({ service, method, value, headers, peer })` authenticates
|
|
1267
|
+
a direct native request. It returns verified `{ principal, authorityFacts }`,
|
|
1268
|
+
an empty object for deliberate public access, or `undefined` to deny access.
|
|
1269
|
+
The request value contains canonical Proto bytes; `peer` is the Connect
|
|
1270
|
+
`HandlerContext` for that invocation.
|
|
1271
|
+
- `forwarded.verify(bytes, proof, peer)` verifies an assertion from a trusted
|
|
1272
|
+
forwarding peer. It must authenticate that peer and validate the supplied
|
|
1273
|
+
proof over the exact bytes. `BrowserServerOptions.forwardingProof.issue(bytes)`
|
|
1274
|
+
supplies the corresponding gateway adapter.
|
|
1275
|
+
|
|
1276
|
+
Admission completes before service validation, routing, or subscription mutation.
|
|
1277
|
+
Principal IDs and authority facts are copied per invocation. `principal.attributes`
|
|
1278
|
+
remains a string map; `authorityFacts` accepts finite JSON values, including
|
|
1279
|
+
arrays and nested objects. ActorContext remains separate from authentication.
|
|
1280
|
+
Neither the framework nor these ports promise live provider information.
|
|
1281
|
+
|
|
1282
|
+
With no admission adapters, native requests remain public. Internal identity
|
|
1283
|
+
headers are still rejected without a configured verifier. With a forwarding
|
|
1284
|
+
verifier but no direct adapter, a request without a forwarding assertion is
|
|
1285
|
+
rejected as unauthenticated. An application that also permits public direct
|
|
1286
|
+
requests can explicitly return an empty reader from its direct adapter.
|
|
1287
|
+
Malformed assertions and denied authentication return `UNAUTHENTICATED`;
|
|
1288
|
+
unexpected adapter faults return sanitized `INTERNAL`. Explicit cancellation,
|
|
1289
|
+
availability, and permission statuses retain their meaning.
|
|
1290
|
+
|
|
1291
|
+
`ManagedServerApplication` accepts `readerAdmission` for its Coordinator listener
|
|
1292
|
+
and `forwardingProof` for Coordinator-to-child requests. Configure the receiving
|
|
1293
|
+
child Servers with their verifier as well. Each hop verifies its incoming
|
|
1294
|
+
assertion and issues a new proof for the actual outgoing operation and payload.
|
|
1295
|
+
Loopback placement alone does not authenticate a forwarding peer.
|
|
1296
|
+
|
|
1297
|
+
Authenticated forwarding now requires an issuer; configure both gateway and
|
|
1298
|
+
receiving node when updating an existing authenticated deployment. The native
|
|
1299
|
+
Server root still does not load the optional auth package. The forwarding ports
|
|
1300
|
+
do not make a JVM endpoint understand the TS internal reader assertion.
|
|
1301
|
+
|
|
1302
|
+
### Browser hosting
|
|
1303
|
+
|
|
951
1304
|
For `BrowserServer` from `@spine-event-engine/server/browser`, origins must be unique canonical HTTP(S) origins with no path, query,
|
|
952
1305
|
fragment, or trailing slash. Requests without an allowed exact `Origin` receive
|
|
953
1306
|
403 before RPC handling. Allowed responses include credentialed exact-origin
|
|
@@ -1010,7 +1363,11 @@ never returns private native data through public subscription responses.
|
|
|
1010
1363
|
The durable registry preserves one approved `GatewayAuthenticatedSubscription`
|
|
1011
1364
|
per public subscription through a process restart. It validates the record ID,
|
|
1012
1365
|
full Subscription, and expiry before use. The trusted Actor and Tenant remain
|
|
1013
|
-
inside the stored Topic
|
|
1366
|
+
inside the stored Topic; a stable principal ID is stored beside it. Activate and
|
|
1367
|
+
Cancel check the newly admitted reader and Actor/Tenant before stream effects
|
|
1368
|
+
or record mutation. Changed authority facts do not change the principal ID.
|
|
1369
|
+
An explicit anonymous binding remains distinct from missing legacy identity;
|
|
1370
|
+
records with missing identity cannot be claimed by a caller. Create assigns
|
|
1014
1371
|
the public ID directly; no quota, reservation, fingerprint, or lease is
|
|
1015
1372
|
persisted. Cleanup remains bounded and restart-safe at the record level. It
|
|
1016
1373
|
cleans the backend definition before deleting its record. It is not a cleaner
|
|
@@ -1021,7 +1378,9 @@ delivery, global update ordering, nor cluster-complete notification delivery.
|
|
|
1021
1378
|
## Delivery and environment
|
|
1022
1379
|
|
|
1023
1380
|
`Inbox`, `InboxStorage`, `ShardIndex`, and `ShardedWorkRegistry` provide the
|
|
1024
|
-
local durable-row abstraction.
|
|
1381
|
+
local durable-row abstraction. Inbox and shard storage require a single-tenant
|
|
1382
|
+
Delivery storage context shared by all tenants; the packed signal supplies
|
|
1383
|
+
the dispatch tenant. Read limits are 1–1000; work leases are
|
|
1025
1384
|
1000–2147483647 ms. Framework replay supports command handling, projection
|
|
1026
1385
|
updates, and process-manager reactions. Callbacks are at-least-once/replay-safe:
|
|
1027
1386
|
lost renewal can prevent stale finalization but cannot undo a callback already
|
|
@@ -1059,24 +1418,53 @@ without an atomic compare-and-delete guarantee from this client. Pending,
|
|
|
1059
1418
|
retryable, non-delivered, and still-protected rows are skipped by cleanup. There
|
|
1060
1419
|
is no additional retention configuration, timer, or scheduler.
|
|
1061
1420
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
use the public builder chain:
|
|
1421
|
+
Configure one Delivery strategy for the environment before setup. It maps
|
|
1422
|
+
targets to shards across all contexts; the default is one shard. For example:
|
|
1065
1423
|
|
|
1066
1424
|
```ts
|
|
1067
|
-
import {
|
|
1425
|
+
import {
|
|
1426
|
+
BoundedContext,
|
|
1427
|
+
EnvironmentType,
|
|
1428
|
+
ServerEnvironment,
|
|
1429
|
+
UniformAcrossAllShards,
|
|
1430
|
+
} from "@spine-event-engine/server";
|
|
1068
1431
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1432
|
+
ServerEnvironment.when(EnvironmentType.Local).use({
|
|
1433
|
+
deliveryStrategy: UniformAcrossAllShards.forNumber(3),
|
|
1434
|
+
});
|
|
1435
|
+
await ServerEnvironment.instance().completeSetup();
|
|
1436
|
+
const context = await BoundedContext.singleTenant("Tasks").build();
|
|
1072
1437
|
```
|
|
1073
1438
|
|
|
1074
1439
|
Aggregate commands and Process Manager or Agent commands/events derive their target shard
|
|
1075
1440
|
internally and persist their envelope in the target Entity Inbox before any
|
|
1076
|
-
handler runs.
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1441
|
+
handler runs. Projection input uses the same environment Delivery and shared
|
|
1442
|
+
Inbox, with its separate recipient identity.
|
|
1443
|
+
|
|
1444
|
+
Local posting waits for the result of that signal's delivery attempt. For an
|
|
1445
|
+
Agent, successful acceptance and Inbox acknowledgement let posting finish while
|
|
1446
|
+
the live handler continues. If Agent execution capacity is unavailable, the input
|
|
1447
|
+
stays pending and the local call reports the existing command-posting error.
|
|
1448
|
+
|
|
1449
|
+
With remote Delivery and its environment supervisor, posting completes after the
|
|
1450
|
+
remote Inbox accepts the input and the shard notification is submitted. Processing
|
|
1451
|
+
may still be pending on another process. For example, importing an Event can return
|
|
1452
|
+
while another process holds its shard; the Projection update arrives after that
|
|
1453
|
+
process can dispatch the Event. Reception alone does not acknowledge delivery,
|
|
1454
|
+
create an Agent acceptance receipt, or prove that a handler ran.
|
|
1455
|
+
|
|
1456
|
+
A rejected remote receive operation rejects posting. If a local notification
|
|
1457
|
+
observer fails after reception succeeds, the failure is logged and the existing
|
|
1458
|
+
notifications and safety scan can find the pending work. The environment selects
|
|
1459
|
+
this behavior from its installed supervision; contexts have no attachment step or
|
|
1460
|
+
completion switch. Supplying custom ports without a source does not install remote
|
|
1461
|
+
supervision. Explicit `Delivery.run()` still returns the actual run result,
|
|
1462
|
+
including `SKIPPED` when another process is handling the shard.
|
|
1463
|
+
For ordinary Entity Inbox work, post-handler output and transition validation
|
|
1464
|
+
failures reach the reception monitor. Pre-handler input and routing errors and
|
|
1465
|
+
storage failures remain outside that monitor. Accepted Agent work has already
|
|
1466
|
+
acknowledged its Inbox row and does not enter this reception action. A detached
|
|
1467
|
+
run that throws emits a contained terminal error without exposing its message.
|
|
1080
1468
|
|
|
1081
1469
|
`DeliveryBuilder` constructs a controlled `Delivery`; `DeliverySupervisor`
|
|
1082
1470
|
receives `{ source, delivery, onMessage }`, manages bounded shard notifications
|
|
@@ -1141,33 +1529,33 @@ work, and then closes buses, subscriptions, Stands, and repository bindings.
|
|
|
1141
1529
|
Cleanup failures are aggregated and may be retried. A committed Entity Event,
|
|
1142
1530
|
reactor or Process Manager Event, and System Event receives one first-publication
|
|
1143
1531
|
attempt; a contained failure is logged and does not schedule publication again.
|
|
1144
|
-
Persisted System Events use a
|
|
1532
|
+
Persisted System Events use a storage group derived from their System Context
|
|
1533
|
+
name and role, separate from domain Event history. Command acceptance
|
|
1145
1534
|
alone does not promise recipient completion. Processing retries for Inbox rows
|
|
1146
1535
|
and acknowledgement recovery remain separate Delivery behavior.
|
|
1147
1536
|
|
|
1148
1537
|
`Environment` resolves the Node `local` or `production` profile once from
|
|
1149
1538
|
`NODE_ENV`. `ServerEnvironment` resolves configured facilities once for that
|
|
1150
|
-
profile and exposes its `storageFactory`,
|
|
1151
|
-
`
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
environment: attachment supervisors and their source reads belong to that facility.
|
|
1539
|
+
profile and exposes its `storageFactory`, `tenantIndex`, `nodeId`, and
|
|
1540
|
+
`close()` lifecycle. A healthy close with active contexts rejects without
|
|
1541
|
+
teardown; after required startup failure, close joins automatic cleanup and
|
|
1542
|
+
reports the original cause plus cleanup failures. After explicit
|
|
1543
|
+
`completeSetup()`, its `delivery` property
|
|
1544
|
+
is the usable shared public `Delivery` facade. A Bounded Context cannot build
|
|
1545
|
+
before setup, and a server does not start setup on the application's behalf.
|
|
1546
|
+
Neither API authenticates requests or supplies remote topology or a deployment
|
|
1547
|
+
policy.
|
|
1548
|
+
|
|
1549
|
+
`ServerEnvironmentDelivery` supplies an optional remote facility with `open()`,
|
|
1550
|
+
`inbox`, and `workRegistry` ports. Setup opens it once before creating the
|
|
1551
|
+
shared Delivery; failure closes acquired facilities. Its optional `source`
|
|
1552
|
+
supports remote shard snapshots and notifications through the environment's
|
|
1553
|
+
single supervisor. Local Delivery uses the environment's configured storage
|
|
1554
|
+
factory for its shared Inbox and work registry; the default factory is in-memory.
|
|
1555
|
+
Contexts register recipients with the same Delivery and never close that shared
|
|
1556
|
+
facility individually. Environment shutdown stops intake, drains local admitted
|
|
1557
|
+
work, then closes shared Delivery and configured facilities. Pending remote rows
|
|
1558
|
+
do not make a closing context wait indefinitely for other processes to finish.
|
|
1171
1559
|
|
|
1172
1560
|
## Signal identity and Aggregate semantics
|
|
1173
1561
|
|