@spine-event-engine/server 2.0.0-snapshot.26 → 2.0.0-snapshot.28
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 +56 -8
- package/REFERENCE.md +151 -39
- package/dist/agent/agent-live-ai-runtime.d.ts +1 -1
- package/dist/agent/agent-live-ai-runtime.js +1 -1
- package/dist/agent/agent-live-budget.d.ts +1 -1
- package/dist/agent/agent-live-budget.js +1 -1
- package/dist/agent/agent-live-read-runtime.d.ts +1 -1
- package/dist/agent/agent-live-read-runtime.js +1 -1
- package/dist/browser/browser-admission.d.ts +47 -0
- package/dist/browser/browser-admission.d.ts.map +1 -0
- package/dist/browser/browser-admission.js +200 -0
- package/dist/browser/browser-admission.js.map +1 -0
- package/dist/browser/browser-server.d.ts +14 -7
- package/dist/browser/browser-server.d.ts.map +1 -1
- package/dist/browser/browser-server.js +462 -129
- package/dist/browser/browser-server.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/options.d.ts +48 -2
- package/dist/browser/options.d.ts.map +1 -1
- package/dist/bus/command-bus.d.ts +6 -1
- package/dist/bus/command-bus.d.ts.map +1 -1
- package/dist/bus/command-bus.js +6 -1
- package/dist/bus/command-bus.js.map +1 -1
- package/dist/bus/event-bus.d.ts +6 -1
- package/dist/bus/event-bus.d.ts.map +1 -1
- package/dist/bus/event-bus.js +6 -1
- package/dist/bus/event-bus.js.map +1 -1
- package/dist/context/bounded-context.d.ts +30 -28
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +136 -82
- package/dist/context/bounded-context.js.map +1 -1
- package/dist/context/entity-inbox.d.ts +12 -17
- package/dist/context/entity-inbox.d.ts.map +1 -1
- package/dist/context/entity-inbox.js +106 -119
- package/dist/context/entity-inbox.js.map +1 -1
- package/dist/context/local-inbox-handoff.d.ts +13 -13
- package/dist/context/local-inbox-handoff.d.ts.map +1 -1
- package/dist/context/local-inbox-handoff.js +60 -32
- package/dist/context/local-inbox-handoff.js.map +1 -1
- package/dist/context/persistent-tenant-index.d.ts +81 -0
- package/dist/context/persistent-tenant-index.d.ts.map +1 -0
- package/dist/context/persistent-tenant-index.js +270 -0
- package/dist/context/persistent-tenant-index.js.map +1 -0
- package/dist/context/projection-handoff.d.ts +9 -9
- package/dist/context/projection-handoff.d.ts.map +1 -1
- package/dist/context/projection-handoff.js +31 -23
- package/dist/context/projection-handoff.js.map +1 -1
- package/dist/context/tenant-index.d.ts +7 -6
- package/dist/context/tenant-index.d.ts.map +1 -1
- package/dist/context/tenant-index.js +2 -188
- package/dist/context/tenant-index.js.map +1 -1
- package/dist/context/tenant-unknown-error.d.ts +2 -2
- package/dist/context/tenant-unknown-error.d.ts.map +1 -1
- package/dist/context/tenant-unknown-error.js +4 -1
- package/dist/context/tenant-unknown-error.js.map +1 -1
- package/dist/delivery/delivery-supervisor.d.ts.map +1 -1
- package/dist/delivery/delivery-supervisor.js +12 -3
- package/dist/delivery/delivery-supervisor.js.map +1 -1
- package/dist/delivery/delivery.d.ts +4 -3
- package/dist/delivery/delivery.d.ts.map +1 -1
- package/dist/delivery/delivery.js +82 -34
- package/dist/delivery/delivery.js.map +1 -1
- package/dist/delivery/reception-observation.d.ts +3 -3
- package/dist/delivery/reception-observation.js +2 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/repository/command-routing.d.ts +1 -1
- package/dist/repository/command-routing.js +1 -1
- package/dist/repository/event-routing.d.ts +1 -1
- package/dist/repository/event-routing.js +1 -1
- package/dist/repository/repository.d.ts +23 -31
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +244 -218
- package/dist/repository/repository.js.map +1 -1
- package/dist/repository/state-update-routing.d.ts +1 -1
- package/dist/repository/state-update-routing.js +1 -1
- package/dist/runtime/signal-publisher.d.ts +23 -8
- package/dist/runtime/signal-publisher.d.ts.map +1 -1
- package/dist/runtime/signal-publisher.js +11 -8
- package/dist/runtime/signal-publisher.js.map +1 -1
- package/dist/server/node-coordinator.d.ts.map +1 -1
- package/dist/server/node-coordinator.js +220 -54
- package/dist/server/node-coordinator.js.map +1 -1
- package/dist/server/server-environment.d.ts +6 -5
- package/dist/server/server-environment.d.ts.map +1 -1
- package/dist/server/server-environment.js +13 -9
- package/dist/server/server-environment.js.map +1 -1
- package/dist/server/server.js +1 -0
- package/dist/server/server.js.map +1 -1
- package/dist/services/app-query-execution.js +2 -2
- package/dist/services/app-query-execution.js.map +1 -1
- package/dist/services/native-operation.d.ts +34 -0
- package/dist/services/native-operation.d.ts.map +1 -0
- package/dist/services/native-operation.js +77 -0
- package/dist/services/native-operation.js.map +1 -0
- package/dist/services/spine-services.d.ts +6 -0
- package/dist/services/spine-services.d.ts.map +1 -1
- package/dist/services/spine-services.js +128 -30
- package/dist/services/spine-services.js.map +1 -1
- package/dist/services/trusted-reader-ingress.d.ts +23 -5
- package/dist/services/trusted-reader-ingress.d.ts.map +1 -1
- package/dist/services/trusted-reader-ingress.js +18 -5
- package/dist/services/trusted-reader-ingress.js.map +1 -1
- package/dist/stand/stand.d.ts +1 -1
- package/dist/stand/stand.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -14
|
@@ -36,7 +36,7 @@ import { snapshotTrustedReader, } from "@spine-event-engine/core/spi/trusted-rea
|
|
|
36
36
|
import { Code, ConnectError } from "@connectrpc/connect";
|
|
37
37
|
import { EventDispatcherOriginSchemas } from "../bus/event-dispatcher-origin-schemas.js";
|
|
38
38
|
import { receptionObservation } from "../delivery/reception-observation.js";
|
|
39
|
-
import { commitFenced, withDeliveryCommitFence } from "./commit-fence.js";
|
|
39
|
+
import { commitFenced, withDeliveryCommitFence, withoutDeliveryCommitFence, } from "./commit-fence.js";
|
|
40
40
|
import { AgentHistoryReads, } from "../agent/agent-history.js";
|
|
41
41
|
import { AgentLiveAiRuntime } from "../agent/agent-live-ai-runtime.js";
|
|
42
42
|
import { AgentLiveAudit } from "../agent/agent-live-audit.js";
|
|
@@ -690,19 +690,19 @@ export const repositoryAccess = Object.freeze({
|
|
|
690
690
|
});
|
|
691
691
|
},
|
|
692
692
|
/**
|
|
693
|
-
* Looks up the Aggregate or Process Manager
|
|
693
|
+
* Looks up the Aggregate or Process Manager Inbox delivery target.
|
|
694
694
|
*
|
|
695
695
|
* @param repository Repository to inspect.
|
|
696
|
-
* @returns Its
|
|
696
|
+
* @returns Its delivery target, when registered.
|
|
697
697
|
*/
|
|
698
698
|
entityInboxTarget(repository) {
|
|
699
699
|
return repositoryEntityInboxTargets.get(repository);
|
|
700
700
|
},
|
|
701
701
|
/**
|
|
702
|
-
* Looks up the Projection
|
|
702
|
+
* Looks up the Projection Inbox delivery target.
|
|
703
703
|
*
|
|
704
704
|
* @param repository Repository to inspect.
|
|
705
|
-
* @returns Its
|
|
705
|
+
* @returns Its delivery target, when registered.
|
|
706
706
|
*/
|
|
707
707
|
projectionInboxTarget(repository) {
|
|
708
708
|
return repositoryProjectionInboxTargets.get(repository);
|
|
@@ -1067,7 +1067,8 @@ class AggregateExecutionSupport {
|
|
|
1067
1067
|
return Object.freeze([produced]);
|
|
1068
1068
|
}
|
|
1069
1069
|
/**
|
|
1070
|
-
*
|
|
1070
|
+
* Writes Aggregate state, diagnostic history, and produced Events through the configured
|
|
1071
|
+
* commit storage. Atomicity depends on that storage implementation.
|
|
1071
1072
|
*
|
|
1072
1073
|
* @param loaded Aggregate and commit storage to update.
|
|
1073
1074
|
* @param entityId Aggregate identifier.
|
|
@@ -1141,7 +1142,7 @@ class AggregateExecutionSupport {
|
|
|
1141
1142
|
await loaded.events.append(clone(EventSchema, event));
|
|
1142
1143
|
}
|
|
1143
1144
|
/**
|
|
1144
|
-
* Completes persistence
|
|
1145
|
+
* Completes persistence and one handoff attempt for each produced Event.
|
|
1145
1146
|
*
|
|
1146
1147
|
* @param loaded Aggregate and commit storage to update.
|
|
1147
1148
|
* @param entityId Aggregate identifier.
|
|
@@ -1149,14 +1150,14 @@ class AggregateExecutionSupport {
|
|
|
1149
1150
|
* @param dispatch Publishes one committed Event.
|
|
1150
1151
|
* @param onPersisted Runs after durable persistence.
|
|
1151
1152
|
* @param diagnostics Events to retain in diagnostic history with this commit.
|
|
1152
|
-
* @returns
|
|
1153
|
+
* @returns Completion after the Event handoff attempts settle.
|
|
1153
1154
|
*/
|
|
1154
1155
|
async persistAggregateAndDispatch(loaded, entityId, events, dispatch, onPersisted, diagnostics = events) {
|
|
1155
1156
|
const committed = await this.persistAggregateUpdate(loaded, entityId, events, diagnostics);
|
|
1156
1157
|
if (!committed)
|
|
1157
|
-
return
|
|
1158
|
+
return;
|
|
1158
1159
|
await onPersisted();
|
|
1159
|
-
|
|
1160
|
+
await withoutDeliveryCommitFence(async () => {
|
|
1160
1161
|
await Promise.all(events.map(async (event) => {
|
|
1161
1162
|
try {
|
|
1162
1163
|
await dispatch(event);
|
|
@@ -1165,7 +1166,7 @@ class AggregateExecutionSupport {
|
|
|
1165
1166
|
this.#runtime.publisher.reportFailure("event", event, error);
|
|
1166
1167
|
}
|
|
1167
1168
|
}));
|
|
1168
|
-
};
|
|
1169
|
+
});
|
|
1169
1170
|
}
|
|
1170
1171
|
/**
|
|
1171
1172
|
* Restores an Aggregate or creates one with initial state and version zero.
|
|
@@ -1225,27 +1226,27 @@ class AggregateCommandExecution {
|
|
|
1225
1226
|
/**
|
|
1226
1227
|
* Validates the Command and executes its assignee when registered.
|
|
1227
1228
|
*
|
|
1228
|
-
* @param
|
|
1229
|
-
* @returns
|
|
1229
|
+
* @param deliveredRoute Accepted route from durable inbox delivery, when present.
|
|
1230
|
+
* @returns Completion after processing and outgoing handoff attempts.
|
|
1230
1231
|
*/
|
|
1231
|
-
async run(
|
|
1232
|
+
async run(deliveredRoute) {
|
|
1232
1233
|
void RepositorySignals.requireCommandId(this.#command);
|
|
1233
|
-
const intake = await this.#readIntake(
|
|
1234
|
+
const intake = await this.#readIntake(deliveredRoute);
|
|
1234
1235
|
if (intake === undefined)
|
|
1235
1236
|
return undefined;
|
|
1236
|
-
|
|
1237
|
+
await this.#runAssignee(intake);
|
|
1237
1238
|
}
|
|
1238
1239
|
/**
|
|
1239
1240
|
* Decodes the Command and selects its registered assignee.
|
|
1240
1241
|
*
|
|
1241
|
-
* @param
|
|
1242
|
+
* @param deliveredRoute Accepted inbox route, when present.
|
|
1242
1243
|
* @returns Decoded message and route with an assignee, or `undefined`.
|
|
1243
1244
|
*/
|
|
1244
|
-
async #readIntake(
|
|
1245
|
+
async #readIntake(deliveredRoute) {
|
|
1245
1246
|
const commandMessage = EntityInvocation.requireSignalMessage(this.#command.message, "command");
|
|
1246
1247
|
const commandSchema = RepositoryRoutes.schemaForTypeUrl(this.#routing.commandSchemas, commandMessage.typeUrl, "command");
|
|
1247
1248
|
const message = EntityInvocation.unpackRequired(commandMessage, commandSchema, "command");
|
|
1248
|
-
const route =
|
|
1249
|
+
const route = deliveredRoute ?? (await this.#repository.routeCommand(this.#command));
|
|
1249
1250
|
const assignee = this.#routing.commandReadiness?.findCommandAssignee(route.messageFullTypeName);
|
|
1250
1251
|
return assignee === undefined ? undefined : Object.freeze({ message, route, assignee });
|
|
1251
1252
|
}
|
|
@@ -1253,7 +1254,7 @@ class AggregateCommandExecution {
|
|
|
1253
1254
|
* Invokes the assignee, persists its Events, or publishes a declared rejection.
|
|
1254
1255
|
*
|
|
1255
1256
|
* @param intake Decoded Command, target route, and assignee.
|
|
1256
|
-
* @returns
|
|
1257
|
+
* @returns Completion after processing and outgoing handoff attempts.
|
|
1257
1258
|
*/
|
|
1258
1259
|
async #runAssignee(intake) {
|
|
1259
1260
|
const loaded = await this.#support.loadAggregate(intake.route.entityId);
|
|
@@ -1263,23 +1264,24 @@ class AggregateCommandExecution {
|
|
|
1263
1264
|
produced = await this.#invokeAssignee(loaded.entity, intake.assignee.handler, intake.message, EntityInvocation.commandHandlerContext(this.#command), this.#command.context?.actorContext);
|
|
1264
1265
|
}
|
|
1265
1266
|
catch (error) {
|
|
1266
|
-
|
|
1267
|
+
await this.#postAssigneeRejection(intake, error);
|
|
1268
|
+
return undefined;
|
|
1267
1269
|
}
|
|
1268
1270
|
const events = this.#bindProducedEvents(this.#support.normalizeProducedSignals(produced), intake.route.entityId, RepositoryEntities.priorVersion(loaded.current));
|
|
1269
|
-
|
|
1271
|
+
await this.#persistAssigneeResult(loaded, intake.route.entityId, events);
|
|
1270
1272
|
}
|
|
1271
1273
|
/**
|
|
1272
1274
|
* Publishes a declared rejection from the invoked Aggregate assignee.
|
|
1273
1275
|
*
|
|
1274
1276
|
* @param intake Assignee and target route for the rejected Command.
|
|
1275
1277
|
* @param error Handler failure to classify and publish.
|
|
1276
|
-
* @returns
|
|
1278
|
+
* @returns Completion after the rejection Event handoff attempt.
|
|
1277
1279
|
*/
|
|
1278
|
-
#postAssigneeRejection(intake, error) {
|
|
1280
|
+
async #postAssigneeRejection(intake, error) {
|
|
1279
1281
|
if (!RejectionThrowable.is(error))
|
|
1280
1282
|
throw error;
|
|
1281
1283
|
RepositorySignals.requireDeclaredRejection(intake.assignee.handler, error);
|
|
1282
|
-
|
|
1284
|
+
await RepositorySignals.postRejectionEvent(this.#runtime, this.#repository, this.#command, intake.route.entityId, error);
|
|
1283
1285
|
}
|
|
1284
1286
|
/**
|
|
1285
1287
|
* Publishes a best-effort Command dispatch diagnostic.
|
|
@@ -1295,11 +1297,11 @@ class AggregateCommandExecution {
|
|
|
1295
1297
|
* @param loaded Aggregate and commit storage.
|
|
1296
1298
|
* @param entityId Target Aggregate identifier.
|
|
1297
1299
|
* @param events Bound Events from the assignee.
|
|
1298
|
-
* @returns
|
|
1300
|
+
* @returns Completion after committed Event handoff attempts.
|
|
1299
1301
|
*/
|
|
1300
|
-
#persistAssigneeResult(loaded, entityId, events) {
|
|
1302
|
+
async #persistAssigneeResult(loaded, entityId, events) {
|
|
1301
1303
|
const committedVersion = loaded.version + 1n;
|
|
1302
|
-
|
|
1304
|
+
await this.#support.persistAggregateAndDispatch(loaded, entityId, events, (event) => this.#runtime.publisher.publishCommittedEvent(event), () => {
|
|
1303
1305
|
if (!RepositoryEntities.repositoryChanged(loaded.entity))
|
|
1304
1306
|
return;
|
|
1305
1307
|
EntityStateChangePublisher.command(this.#runtime, this.#repository, this.#command, entityId, loaded.oldState, loaded.current === undefined
|
|
@@ -1489,10 +1491,9 @@ class AggregateEventExecution {
|
|
|
1489
1491
|
await this.#support.appendDiagnosticEvent(loaded, entityId, source);
|
|
1490
1492
|
return;
|
|
1491
1493
|
}
|
|
1492
|
-
|
|
1494
|
+
await this.#support.persistAggregateAndDispatch(loaded, entityId, produced, (event) => this.#runtime.publisher.publishReactorEvent(event), () => {
|
|
1493
1495
|
this.#publishStateChange(loaded, entityId);
|
|
1494
1496
|
}, [source, ...produced]);
|
|
1495
|
-
void dispatch();
|
|
1496
1497
|
}
|
|
1497
1498
|
/**
|
|
1498
1499
|
* Publishes an Entity state-change System Event when the Aggregate changed.
|
|
@@ -1675,7 +1676,7 @@ class ProjectionEventExecution {
|
|
|
1675
1676
|
* Delivers an accepted Event for one Projection target.
|
|
1676
1677
|
*
|
|
1677
1678
|
* @param entityId Target Projection identifier.
|
|
1678
|
-
* @param acceptedRoute Route accepted before
|
|
1679
|
+
* @param acceptedRoute Route accepted before deliver.
|
|
1679
1680
|
* @returns Completion after target delivery.
|
|
1680
1681
|
*/
|
|
1681
1682
|
async runTarget(entityId, acceptedRoute) {
|
|
@@ -2911,27 +2912,29 @@ class ProcessManagerCommandExecution {
|
|
|
2911
2912
|
/**
|
|
2912
2913
|
* Invokes the registered Command handler and commits its results.
|
|
2913
2914
|
*
|
|
2914
|
-
* @param
|
|
2915
|
-
* @returns
|
|
2915
|
+
* @param deliveredRoute Accepted route from durable inbox delivery, when present.
|
|
2916
|
+
* @returns Completion after processing and outgoing handoff attempts.
|
|
2916
2917
|
*/
|
|
2917
|
-
async run(
|
|
2918
|
+
async run(deliveredRoute) {
|
|
2918
2919
|
RepositorySignals.requireCommandId(this.#command);
|
|
2919
|
-
const intake = await this.#readIntake(
|
|
2920
|
+
const intake = await this.#readIntake(deliveredRoute);
|
|
2920
2921
|
if (intake === undefined)
|
|
2921
2922
|
return undefined;
|
|
2922
2923
|
const tenantOptions = RepositoryTenants.commandStandOptions(this.#runtime.context, this.#command);
|
|
2923
2924
|
const loaded = await this.#support.load(intake.route.entityId, tenantOptions);
|
|
2924
2925
|
await this.#publishDispatch(loaded, intake.route.entityId);
|
|
2926
|
+
let produced;
|
|
2925
2927
|
try {
|
|
2926
|
-
|
|
2927
|
-
return await this.#commitAndPublish(loaded, tenantOptions, intake, produced);
|
|
2928
|
+
produced = await this.#invoke(loaded.entity, intake.assignee, intake.message, tenantOptions.tenantId);
|
|
2928
2929
|
}
|
|
2929
2930
|
catch (error) {
|
|
2930
2931
|
if (!RejectionThrowable.is(error))
|
|
2931
2932
|
throw error;
|
|
2932
2933
|
RepositorySignals.requireDeclaredRejection(intake.assignee.handler, error);
|
|
2933
|
-
|
|
2934
|
+
await RepositorySignals.postRejectionEvent(this.#runtime, this.#repository, this.#command, intake.route.entityId, error);
|
|
2935
|
+
return undefined;
|
|
2934
2936
|
}
|
|
2937
|
+
await this.#commitAndPublish(loaded, tenantOptions, intake, produced);
|
|
2935
2938
|
}
|
|
2936
2939
|
/**
|
|
2937
2940
|
* Persists required Agent dispatch history before the handler runs.
|
|
@@ -2961,14 +2964,14 @@ class ProcessManagerCommandExecution {
|
|
|
2961
2964
|
/**
|
|
2962
2965
|
* Decodes a registered Command and finds its assignee.
|
|
2963
2966
|
*
|
|
2964
|
-
* @param
|
|
2967
|
+
* @param deliveredRoute Accepted inbox route, when present.
|
|
2965
2968
|
* @returns Decoded Command, route, and assignee, or `undefined`.
|
|
2966
2969
|
*/
|
|
2967
|
-
async #readIntake(
|
|
2970
|
+
async #readIntake(deliveredRoute) {
|
|
2968
2971
|
const commandMessage = EntityInvocation.requireSignalMessage(this.#command.message, "command");
|
|
2969
2972
|
const commandSchema = RepositoryRoutes.schemaForTypeUrl(this.#routing.commandSchemas, commandMessage.typeUrl, "command");
|
|
2970
2973
|
const message = EntityInvocation.unpackRequired(commandMessage, commandSchema, "command");
|
|
2971
|
-
const route =
|
|
2974
|
+
const route = deliveredRoute ?? (await this.#repository.routeCommand(this.#command));
|
|
2972
2975
|
const assignee = this.#routing.commandReadiness?.findCommandAssignee(route.messageFullTypeName);
|
|
2973
2976
|
return assignee === undefined ? undefined : Object.freeze({ assignee, message, route });
|
|
2974
2977
|
}
|
|
@@ -2979,7 +2982,7 @@ class ProcessManagerCommandExecution {
|
|
|
2979
2982
|
* @param tenantOptions Stand tenant selection.
|
|
2980
2983
|
* @param intake Assignee and target route.
|
|
2981
2984
|
* @param producedSignals Validated handler results.
|
|
2982
|
-
* @returns
|
|
2985
|
+
* @returns Completion after produced-signal handoff attempts.
|
|
2983
2986
|
*/
|
|
2984
2987
|
async #commitAndPublish(loaded, tenantOptions, intake, producedSignals) {
|
|
2985
2988
|
const commands = this.#commandOutputs(intake.assignee, producedSignals);
|
|
@@ -2988,12 +2991,10 @@ class ProcessManagerCommandExecution {
|
|
|
2988
2991
|
if (!committed)
|
|
2989
2992
|
return undefined;
|
|
2990
2993
|
this.#publishChangedState(loaded, intake.route.entityId);
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
await this.#postCommands(commands, this.#command);
|
|
2996
|
-
};
|
|
2994
|
+
await withoutDeliveryCommitFence(async () => {
|
|
2995
|
+
await this.#postEvents(events);
|
|
2996
|
+
await this.#postCommands(commands, this.#command);
|
|
2997
|
+
});
|
|
2997
2998
|
}
|
|
2998
2999
|
/**
|
|
2999
3000
|
* Binds substitution results as Commands and requires nonempty output.
|
|
@@ -3156,15 +3157,15 @@ class ProcessManagerCommandExecution {
|
|
|
3156
3157
|
}
|
|
3157
3158
|
}
|
|
3158
3159
|
/**
|
|
3159
|
-
*
|
|
3160
|
+
* Publishes the Process Manager Command's produced Events after its commit.
|
|
3160
3161
|
*
|
|
3161
3162
|
* @param events Bound Events to publish.
|
|
3163
|
+
* @returns Completion after each Event handoff attempt.
|
|
3162
3164
|
*/
|
|
3163
|
-
#postEvents(events) {
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
}
|
|
3165
|
+
async #postEvents(events) {
|
|
3166
|
+
await Promise.all(events.map((event) => {
|
|
3167
|
+
return this.#runtime.publisher.publishReactorEvent(event);
|
|
3168
|
+
}));
|
|
3168
3169
|
}
|
|
3169
3170
|
}
|
|
3170
3171
|
/**
|
|
@@ -3204,16 +3205,16 @@ class ProcessManagerEventExecution {
|
|
|
3204
3205
|
}
|
|
3205
3206
|
this.#validateSourceEventIdForFollowUps(intake);
|
|
3206
3207
|
if (intake.route.entityIds.length === 1) {
|
|
3207
|
-
await InboxHandoff.
|
|
3208
|
+
await InboxHandoff.handoffEntityEvent(this.#repository, this.#runtime, this.#event, intake.route.entityIds[0]);
|
|
3208
3209
|
return;
|
|
3209
3210
|
}
|
|
3210
|
-
await InboxHandoff.
|
|
3211
|
+
await InboxHandoff.handoffEntityEvents(this.#repository, this.#runtime, this.#event, intake.route.entityIds);
|
|
3211
3212
|
}
|
|
3212
3213
|
/**
|
|
3213
3214
|
* Delivers a routed Event for one target under the duplicate-dispatch guard.
|
|
3214
3215
|
*
|
|
3215
3216
|
* @param entityId Target Entity identifier.
|
|
3216
|
-
* @param acceptedRoute Route accepted before
|
|
3217
|
+
* @param acceptedRoute Route accepted before deliver.
|
|
3217
3218
|
* @returns Completion after guarded target execution.
|
|
3218
3219
|
*/
|
|
3219
3220
|
async runTarget(entityId, acceptedRoute) {
|
|
@@ -3267,8 +3268,10 @@ class ProcessManagerEventExecution {
|
|
|
3267
3268
|
if (!committed)
|
|
3268
3269
|
return;
|
|
3269
3270
|
this.#publishChangedState(loaded, entityId);
|
|
3270
|
-
|
|
3271
|
-
|
|
3271
|
+
await withoutDeliveryCommitFence(async () => {
|
|
3272
|
+
await this.#postEvents(events);
|
|
3273
|
+
await this.#postCommands(commands);
|
|
3274
|
+
});
|
|
3272
3275
|
}
|
|
3273
3276
|
/**
|
|
3274
3277
|
* Publishes a state-change System Event when the Entity changed.
|
|
@@ -3446,23 +3449,24 @@ class ProcessManagerEventExecution {
|
|
|
3446
3449
|
* Publishes each produced Command in handler order.
|
|
3447
3450
|
*
|
|
3448
3451
|
* @param commands Bound Commands to publish.
|
|
3452
|
+
* @returns Completion after each Command handoff attempt.
|
|
3449
3453
|
*/
|
|
3450
|
-
#postCommands(commands) {
|
|
3454
|
+
async #postCommands(commands) {
|
|
3451
3455
|
for (const command of commands) {
|
|
3452
3456
|
// spine-log-boundary: server.process_manager_command_follow_up
|
|
3453
|
-
|
|
3457
|
+
await this.#runtime.publisher.publishCommand(command);
|
|
3454
3458
|
}
|
|
3455
3459
|
}
|
|
3456
3460
|
/**
|
|
3457
|
-
*
|
|
3461
|
+
* Publishes the Process Manager Event's produced Events after its commit.
|
|
3458
3462
|
*
|
|
3459
3463
|
* @param events Bound Events to publish.
|
|
3464
|
+
* @returns Completion after each Event handoff attempt.
|
|
3460
3465
|
*/
|
|
3461
|
-
#postEvents(events) {
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
}
|
|
3466
|
+
async #postEvents(events) {
|
|
3467
|
+
await Promise.all(events.map((event) => {
|
|
3468
|
+
return this.#runtime.publisher.publishReactorEvent(event);
|
|
3469
|
+
}));
|
|
3466
3470
|
}
|
|
3467
3471
|
}
|
|
3468
3472
|
/**
|
|
@@ -4132,18 +4136,18 @@ const RepositorySignals = {
|
|
|
4132
4136
|
});
|
|
4133
4137
|
},
|
|
4134
4138
|
/**
|
|
4135
|
-
* Builds a rejection Event and
|
|
4139
|
+
* Builds a rejection Event and awaits one publication attempt.
|
|
4136
4140
|
*
|
|
4137
4141
|
* @param runtime Context signal and publication services.
|
|
4138
4142
|
* @param repository Repository of the rejected Command.
|
|
4139
4143
|
* @param command Command rejected by its handler.
|
|
4140
4144
|
* @param entityId Target Entity identifier.
|
|
4141
4145
|
* @param rejection Declared handler rejection.
|
|
4142
|
-
* @returns
|
|
4146
|
+
* @returns Completion after the rejection handoff attempt settles.
|
|
4143
4147
|
*/
|
|
4144
|
-
postRejectionEvent(runtime, repository, command, entityId, rejection) {
|
|
4148
|
+
async postRejectionEvent(runtime, repository, command, entityId, rejection) {
|
|
4145
4149
|
const event = this.rejectionEvent(runtime, repository, command, entityId, rejection);
|
|
4146
|
-
|
|
4150
|
+
await withoutDeliveryCommitFence(async () => {
|
|
4147
4151
|
try {
|
|
4148
4152
|
// spine-log-boundary: server.repository_rejection_follow_up
|
|
4149
4153
|
await runtime.publisher.publishRejectionEvent(event);
|
|
@@ -4151,7 +4155,7 @@ const RepositorySignals = {
|
|
|
4151
4155
|
catch (error) {
|
|
4152
4156
|
runtime.publisher.reportFailure("event", event, error);
|
|
4153
4157
|
}
|
|
4154
|
-
};
|
|
4158
|
+
});
|
|
4155
4159
|
},
|
|
4156
4160
|
/**
|
|
4157
4161
|
* Creates the original declared rejection envelope without publishing it.
|
|
@@ -4738,13 +4742,13 @@ const RepositoryTenants = {
|
|
|
4738
4742
|
return RepositoryTenants.require(tenantId);
|
|
4739
4743
|
},
|
|
4740
4744
|
/**
|
|
4741
|
-
* Validates an Event tenant before
|
|
4745
|
+
* Validates an Event tenant before Entity Inbox handoff.
|
|
4742
4746
|
*
|
|
4743
4747
|
* @param context Bounded context storage mode.
|
|
4744
|
-
* @param event Event entering
|
|
4748
|
+
* @param event Event entering Entity Inbox delivery.
|
|
4745
4749
|
* @returns Validated tenant, or `undefined` for single-tenant contexts.
|
|
4746
4750
|
*/
|
|
4747
|
-
|
|
4751
|
+
requireEntityEventTenant(context, event) {
|
|
4748
4752
|
if (!context.multitenant) {
|
|
4749
4753
|
return undefined;
|
|
4750
4754
|
}
|
|
@@ -7254,7 +7258,7 @@ const InboxMessages = {
|
|
|
7254
7258
|
}
|
|
7255
7259
|
}
|
|
7256
7260
|
if (entityId === undefined) {
|
|
7257
|
-
throw new Error("Entity Inbox
|
|
7261
|
+
throw new Error("Entity Inbox delivery stored target ID is incompatible with the repository.");
|
|
7258
7262
|
}
|
|
7259
7263
|
return RepositoryRoutes.readRouteId(entityId, idField, "command");
|
|
7260
7264
|
},
|
|
@@ -7266,7 +7270,7 @@ const InboxMessages = {
|
|
|
7266
7270
|
*/
|
|
7267
7271
|
readInboxCommand(message) {
|
|
7268
7272
|
if (message.label !== "HANDLE_COMMAND") {
|
|
7269
|
-
throw new Error(`Entity Inbox
|
|
7273
|
+
throw new Error(`Entity Inbox delivery does not handle "${message.label}" messages.`);
|
|
7270
7274
|
}
|
|
7271
7275
|
const command = message.signal === undefined ? undefined : AnyPacker.tryUnpack(message.signal, CommandSchema);
|
|
7272
7276
|
if (command === undefined) {
|
|
@@ -7275,13 +7279,13 @@ const InboxMessages = {
|
|
|
7275
7279
|
return command;
|
|
7276
7280
|
},
|
|
7277
7281
|
/**
|
|
7278
|
-
* Reads an Event labeled for
|
|
7282
|
+
* Reads an Event labeled for an Entity reaction.
|
|
7279
7283
|
*
|
|
7280
7284
|
* @param message Stored Inbox message to validate and unpack.
|
|
7281
7285
|
* @returns The stored Event envelope.
|
|
7282
7286
|
*/
|
|
7283
|
-
|
|
7284
|
-
return InboxMessages.readStoredEvent(message, "REACT_UPON_EVENT", "Entity Inbox
|
|
7287
|
+
readEntityInboxEvent(message) {
|
|
7288
|
+
return InboxMessages.readStoredEvent(message, "REACT_UPON_EVENT", "Entity Inbox delivery", "Entity Inbox delivery requires a readable stored event.");
|
|
7285
7289
|
},
|
|
7286
7290
|
/**
|
|
7287
7291
|
* Reads an Event labeled for a Projection update.
|
|
@@ -7290,20 +7294,20 @@ const InboxMessages = {
|
|
|
7290
7294
|
* @returns The stored Event envelope.
|
|
7291
7295
|
*/
|
|
7292
7296
|
readProjectionInboxEvent(message) {
|
|
7293
|
-
return InboxMessages.readStoredEvent(message, "UPDATE_SUBSCRIBER", "Projection inbox
|
|
7297
|
+
return InboxMessages.readStoredEvent(message, "UPDATE_SUBSCRIBER", "Projection inbox delivery", "Projection inbox delivery requires a readable stored event.");
|
|
7294
7298
|
},
|
|
7295
7299
|
/**
|
|
7296
7300
|
* Validates an Inbox operation label and decodes its stored Event bytes.
|
|
7297
7301
|
*
|
|
7298
7302
|
* @param message Stored Inbox message to inspect.
|
|
7299
7303
|
* @param expectedLabel Operation label required by the caller.
|
|
7300
|
-
* @param
|
|
7304
|
+
* @param deliverName Human-readable operation name used in label errors.
|
|
7301
7305
|
* @param unreadableMessage Error text used when Event decoding fails.
|
|
7302
7306
|
* @returns The stored Event envelope.
|
|
7303
7307
|
*/
|
|
7304
|
-
readStoredEvent(message, expectedLabel,
|
|
7308
|
+
readStoredEvent(message, expectedLabel, deliverName, unreadableMessage) {
|
|
7305
7309
|
if (message.label !== expectedLabel) {
|
|
7306
|
-
throw new Error(`${
|
|
7310
|
+
throw new Error(`${deliverName} does not handle "${message.label}" messages.`);
|
|
7307
7311
|
}
|
|
7308
7312
|
const signal = message.signal === undefined
|
|
7309
7313
|
? undefined
|
|
@@ -7322,7 +7326,7 @@ Object.freeze(InboxMessages);
|
|
|
7322
7326
|
/**
|
|
7323
7327
|
* Validates and dispatches stored Inbox signals to their recorded Entity targets.
|
|
7324
7328
|
*/
|
|
7325
|
-
const
|
|
7329
|
+
const InboxDelivery = {
|
|
7326
7330
|
/**
|
|
7327
7331
|
* Dispatches a stored Aggregate Command after checking its tenant and payload.
|
|
7328
7332
|
*
|
|
@@ -7330,44 +7334,66 @@ const InboxReplay = {
|
|
|
7330
7334
|
* @param routing Registered handlers and message schemas.
|
|
7331
7335
|
* @param message Stored Inbox message with the recorded target.
|
|
7332
7336
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7333
|
-
* @returns
|
|
7337
|
+
* @returns Completion after processing and outgoing handoff attempts.
|
|
7334
7338
|
*/
|
|
7335
|
-
async
|
|
7339
|
+
async deliverAggregateCommand(repository, routing, message, deliveryTenantId) {
|
|
7336
7340
|
const runtime = repositoryRuntimes.get(repository);
|
|
7337
7341
|
if (runtime === undefined) {
|
|
7338
|
-
throw new Error("Aggregate inbox
|
|
7342
|
+
throw new Error("Aggregate inbox delivery requires a bound repository runtime.");
|
|
7339
7343
|
}
|
|
7340
7344
|
if (message.label !== "HANDLE_COMMAND") {
|
|
7341
|
-
throw new Error(`Aggregate inbox
|
|
7345
|
+
throw new Error(`Aggregate inbox delivery does not handle "${message.label}" messages.`);
|
|
7342
7346
|
}
|
|
7343
7347
|
const command = InboxMessages.readInboxCommand(message);
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
const route =
|
|
7347
|
-
|
|
7348
|
+
InboxDelivery.validateDeliveryTenant(runtime.context, deliveryTenantId, command);
|
|
7349
|
+
InboxDelivery.validateDeliveredCommandPayload(routing, command);
|
|
7350
|
+
const route = InboxDelivery.deliverCommandRoute(repository, routing, message, command);
|
|
7351
|
+
await new AggregateCommandExecution(repository, routing, runtime, command).run(route);
|
|
7348
7352
|
},
|
|
7349
7353
|
/**
|
|
7350
|
-
*
|
|
7354
|
+
* Delivers a stored Event to the recorded Aggregate target.
|
|
7355
|
+
*
|
|
7356
|
+
* @param repository Aggregate repository receiving the Event.
|
|
7357
|
+
* @param routing Registered Event handlers and message schemas.
|
|
7358
|
+
* @param message Stored Inbox row with the recorded target.
|
|
7359
|
+
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7360
|
+
* @returns Completion after the guarded reactor and outgoing handoff attempts.
|
|
7361
|
+
*/
|
|
7362
|
+
async deliverAggregateEvent(repository, routing, message, deliveryTenantId) {
|
|
7363
|
+
const runtime = repositoryRuntimes.get(repository);
|
|
7364
|
+
if (runtime === undefined) {
|
|
7365
|
+
throw new Error("Aggregate inbox delivery requires a bound repository runtime.");
|
|
7366
|
+
}
|
|
7367
|
+
const event = InboxMessages.readEntityInboxEvent(message);
|
|
7368
|
+
InboxDelivery.validateEventTenant(runtime.context, deliveryTenantId, event);
|
|
7369
|
+
InboxDelivery.validateDeliveredEventPayload(routing, event, "Aggregate inbox delivery requires a readable event payload.");
|
|
7370
|
+
const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Aggregate inbox delivery");
|
|
7371
|
+
const [entityId] = route.entityIds;
|
|
7372
|
+
await DispatchGuards.guardedEntityEventDispatch(repository, runtime, event, entityId, () => new AggregateEventExecution(repository, routing, runtime, event).runTarget(entityId, route));
|
|
7373
|
+
},
|
|
7374
|
+
/**
|
|
7375
|
+
* Routes Process Manager Command or Event deliver by its stored operation label.
|
|
7351
7376
|
*
|
|
7352
7377
|
* @param repository Process Manager repository receiving the signal.
|
|
7353
7378
|
* @param routing Registered handlers and message schemas.
|
|
7354
7379
|
* @param message Stored Inbox message with the recorded target.
|
|
7355
7380
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7356
|
-
* @returns
|
|
7381
|
+
* @returns Completion after processing and outgoing handoff attempts.
|
|
7357
7382
|
*/
|
|
7358
|
-
async
|
|
7383
|
+
async deliverPmInbox(repository, routing, message, deliveryTenantId) {
|
|
7359
7384
|
if (repository.entityFamily === "agent") {
|
|
7360
|
-
await
|
|
7385
|
+
await InboxDelivery.deliverAgentInbox(repository, routing, message, deliveryTenantId);
|
|
7361
7386
|
return undefined;
|
|
7362
7387
|
}
|
|
7363
7388
|
if (message.label === "HANDLE_COMMAND") {
|
|
7364
|
-
|
|
7389
|
+
await InboxDelivery.deliverProcessManagerCommand(repository, routing, message, deliveryTenantId);
|
|
7390
|
+
return;
|
|
7365
7391
|
}
|
|
7366
7392
|
if (message.label === "REACT_UPON_EVENT") {
|
|
7367
|
-
await
|
|
7393
|
+
await InboxDelivery.deliverProcessManagerEvent(repository, routing, message, deliveryTenantId);
|
|
7368
7394
|
return undefined;
|
|
7369
7395
|
}
|
|
7370
|
-
throw new Error(`Entity Inbox
|
|
7396
|
+
throw new Error(`Entity Inbox delivery does not handle "${message.label}" messages.`);
|
|
7371
7397
|
},
|
|
7372
7398
|
/**
|
|
7373
7399
|
* Persists selected Agent work before the normal Inbox acknowledges delivery.
|
|
@@ -7378,17 +7404,17 @@ const InboxReplay = {
|
|
|
7378
7404
|
* @param deliveryTenantId Tenant selected by delivery.
|
|
7379
7405
|
* @returns When the fenced repository operation completes.
|
|
7380
7406
|
*/
|
|
7381
|
-
async
|
|
7407
|
+
async deliverAgentInbox(repository, routing, message, deliveryTenantId) {
|
|
7382
7408
|
const runtime = repositoryRuntimes.get(repository);
|
|
7383
7409
|
if (runtime === undefined)
|
|
7384
|
-
throw new Error("Agent Inbox
|
|
7410
|
+
throw new Error("Agent Inbox delivery requires a bound runtime.");
|
|
7385
7411
|
if (message.label === "HANDLE_COMMAND") {
|
|
7386
|
-
await
|
|
7412
|
+
await InboxDelivery.deliverAgentCommand(repository, routing, runtime, message, deliveryTenantId);
|
|
7387
7413
|
return;
|
|
7388
7414
|
}
|
|
7389
7415
|
if (message.label !== "REACT_UPON_EVENT")
|
|
7390
|
-
throw new Error(`Agent Inbox
|
|
7391
|
-
await
|
|
7416
|
+
throw new Error(`Agent Inbox delivery does not handle "${message.label}" messages.`);
|
|
7417
|
+
await InboxDelivery.deliverAgentEvent(repository, routing, runtime, message, deliveryTenantId);
|
|
7392
7418
|
},
|
|
7393
7419
|
/**
|
|
7394
7420
|
* Admits a Command using its stored target and registered assignee.
|
|
@@ -7400,15 +7426,15 @@ const InboxReplay = {
|
|
|
7400
7426
|
* @param tenantId Delivery tenant.
|
|
7401
7427
|
* @returns When the fenced repository operation completes.
|
|
7402
7428
|
*/
|
|
7403
|
-
async
|
|
7429
|
+
async deliverAgentCommand(repository, routing, runtime, message, tenantId) {
|
|
7404
7430
|
const command = InboxMessages.readInboxCommand(message);
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
const route =
|
|
7431
|
+
InboxDelivery.validateDeliveryTenant(runtime.context, tenantId, command);
|
|
7432
|
+
InboxDelivery.validateDeliveredCommandPayload(routing, command);
|
|
7433
|
+
const route = InboxDelivery.deliverCommandRoute(repository, routing, message, command);
|
|
7408
7434
|
const assignee = routing.commandReadiness?.findCommandAssignee(route.messageFullTypeName);
|
|
7409
7435
|
if (assignee === undefined)
|
|
7410
7436
|
throw new Error("Agent Command has no selected assignee.");
|
|
7411
|
-
await
|
|
7437
|
+
await InboxDelivery.admitAgent(repository, runtime, message, tenantId, route.entityId, { case: "command", value: command }, [assignee.registeredHandler]);
|
|
7412
7438
|
},
|
|
7413
7439
|
/**
|
|
7414
7440
|
* Admits matching Event handlers from the stored target without rerouting.
|
|
@@ -7420,15 +7446,15 @@ const InboxReplay = {
|
|
|
7420
7446
|
* @param tenantId Delivery tenant.
|
|
7421
7447
|
* @returns When the fenced repository operation completes.
|
|
7422
7448
|
*/
|
|
7423
|
-
async
|
|
7424
|
-
const event = InboxMessages.
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
const route =
|
|
7428
|
-
const handlers =
|
|
7449
|
+
async deliverAgentEvent(repository, routing, runtime, message, tenantId) {
|
|
7450
|
+
const event = InboxMessages.readEntityInboxEvent(message);
|
|
7451
|
+
InboxDelivery.validateEventTenant(runtime.context, tenantId, event);
|
|
7452
|
+
InboxDelivery.validateDeliveredEventPayload(routing, event, "Agent Inbox delivery requires an Event payload.");
|
|
7453
|
+
const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Agent Inbox delivery");
|
|
7454
|
+
const handlers = InboxDelivery.agentEventHandlers(routing, route.messageFullTypeName, event);
|
|
7429
7455
|
if (handlers.length === 0)
|
|
7430
7456
|
return;
|
|
7431
|
-
await
|
|
7457
|
+
await InboxDelivery.admitAgent(repository, runtime, message, tenantId, route.entityIds[0], { case: "event", value: event }, handlers);
|
|
7432
7458
|
},
|
|
7433
7459
|
/**
|
|
7434
7460
|
* Restores selected Event and Command reactions from the original payload.
|
|
@@ -7467,14 +7493,14 @@ const InboxReplay = {
|
|
|
7467
7493
|
if (deliverySignal === undefined)
|
|
7468
7494
|
throw new Error("Agent admission requires delivery scope.");
|
|
7469
7495
|
const cancellation = AbortSignal.any([deliverySignal, runtime.agentSignal]);
|
|
7470
|
-
const key =
|
|
7496
|
+
const key = InboxDelivery.capacityKeyFor(repository, input.context, input.id.key(entityId));
|
|
7471
7497
|
const reservation = runtime.reserveAgent(key, cancellation);
|
|
7472
7498
|
if (reservation === undefined) {
|
|
7473
7499
|
runtime.deferAgent(message, tenantId);
|
|
7474
7500
|
AgentDeliveryScope.record({ kind: "deferred" });
|
|
7475
7501
|
return;
|
|
7476
7502
|
}
|
|
7477
|
-
await
|
|
7503
|
+
await InboxDelivery.admitReservedAgent({
|
|
7478
7504
|
repository,
|
|
7479
7505
|
runtime,
|
|
7480
7506
|
context: input.context,
|
|
@@ -7516,13 +7542,13 @@ const InboxReplay = {
|
|
|
7516
7542
|
async admitReservedAgent(input) {
|
|
7517
7543
|
const { repository, runtime, context, message, signal, reservation } = input;
|
|
7518
7544
|
try {
|
|
7519
|
-
const accepted = await
|
|
7545
|
+
const accepted = await InboxDelivery.acceptAgentReceipt(runtime, context, repository, message, signal);
|
|
7520
7546
|
if (!accepted) {
|
|
7521
7547
|
reservation.release();
|
|
7522
7548
|
AgentDeliveryScope.record({ kind: "duplicate" });
|
|
7523
7549
|
return;
|
|
7524
7550
|
}
|
|
7525
|
-
|
|
7551
|
+
InboxDelivery.recordAcceptedAgent(input);
|
|
7526
7552
|
}
|
|
7527
7553
|
catch (error) {
|
|
7528
7554
|
reservation.release();
|
|
@@ -7547,7 +7573,7 @@ const InboxReplay = {
|
|
|
7547
7573
|
},
|
|
7548
7574
|
run: (fence, checkSession) => {
|
|
7549
7575
|
const cancellation = AbortSignal.any([fence, runtime.agentSignal]);
|
|
7550
|
-
const checkAgentSession =
|
|
7576
|
+
const checkAgentSession = InboxDelivery.agentSessionGuard(cancellation, checkSession);
|
|
7551
7577
|
return reservation.run(() => withDeliveryCommitFence(checkAgentSession, () => new AgentLiveRunner(repository, runtime, tenantId, entityId, invocation, handlers, cancellation, checkAgentSession).run()));
|
|
7552
7578
|
},
|
|
7553
7579
|
});
|
|
@@ -7576,8 +7602,8 @@ const InboxReplay = {
|
|
|
7576
7602
|
*/
|
|
7577
7603
|
acceptAgentReceipt(runtime, context, repository, message, signal) {
|
|
7578
7604
|
const source = signal.case === "command"
|
|
7579
|
-
? { kind: "command", id:
|
|
7580
|
-
: { kind: "event", id:
|
|
7605
|
+
? { kind: "command", id: InboxDelivery.requireAgentCommandId(signal.value) }
|
|
7606
|
+
: { kind: "event", id: InboxDelivery.requireAgentEventId(signal.value) };
|
|
7581
7607
|
return runtime.agentReceipts.accept(context, {
|
|
7582
7608
|
stateType: repository.stateSchema.typeName,
|
|
7583
7609
|
recipientId: message.inboxId.targetId,
|
|
@@ -7612,18 +7638,18 @@ const InboxReplay = {
|
|
|
7612
7638
|
* @param routing Registered handlers and message schemas.
|
|
7613
7639
|
* @param message Stored Inbox message with the recorded target.
|
|
7614
7640
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7615
|
-
* @returns
|
|
7641
|
+
* @returns Completion after processing and outgoing handoff attempts.
|
|
7616
7642
|
*/
|
|
7617
|
-
async
|
|
7643
|
+
async deliverProcessManagerCommand(repository, routing, message, deliveryTenantId) {
|
|
7618
7644
|
const runtime = repositoryRuntimes.get(repository);
|
|
7619
7645
|
if (runtime === undefined) {
|
|
7620
|
-
throw new Error("Entity Inbox
|
|
7646
|
+
throw new Error("Entity Inbox delivery requires a bound repository runtime.");
|
|
7621
7647
|
}
|
|
7622
7648
|
const command = InboxMessages.readInboxCommand(message);
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
const route =
|
|
7626
|
-
|
|
7649
|
+
InboxDelivery.validateDeliveryTenant(runtime.context, deliveryTenantId, command);
|
|
7650
|
+
InboxDelivery.validateDeliveredCommandPayload(routing, command);
|
|
7651
|
+
const route = InboxDelivery.deliverCommandRoute(repository, routing, message, command);
|
|
7652
|
+
await new ProcessManagerCommandExecution(repository, routing, runtime, command).run(route);
|
|
7627
7653
|
},
|
|
7628
7654
|
/**
|
|
7629
7655
|
* Dispatches a validated Event to the Process Manager target recorded in its Inbox.
|
|
@@ -7634,15 +7660,15 @@ const InboxReplay = {
|
|
|
7634
7660
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7635
7661
|
* @returns Completion of dispatch to the recorded target.
|
|
7636
7662
|
*/
|
|
7637
|
-
async
|
|
7663
|
+
async deliverProcessManagerEvent(repository, routing, message, deliveryTenantId) {
|
|
7638
7664
|
const runtime = repositoryRuntimes.get(repository);
|
|
7639
7665
|
if (runtime === undefined) {
|
|
7640
|
-
throw new Error("Entity Inbox
|
|
7666
|
+
throw new Error("Entity Inbox delivery requires a bound repository runtime.");
|
|
7641
7667
|
}
|
|
7642
|
-
const event = InboxMessages.
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
const route =
|
|
7668
|
+
const event = InboxMessages.readEntityInboxEvent(message);
|
|
7669
|
+
InboxDelivery.validateEventTenant(runtime.context, deliveryTenantId, event);
|
|
7670
|
+
InboxDelivery.validateDeliveredEventPayload(routing, event, "Entity Inbox delivery requires a readable event payload.");
|
|
7671
|
+
const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Entity Inbox delivery");
|
|
7646
7672
|
const [entityId] = route.entityIds;
|
|
7647
7673
|
await new ProcessManagerEventExecution(repository, routing, runtime, event).runTarget(entityId, route);
|
|
7648
7674
|
},
|
|
@@ -7655,34 +7681,34 @@ const InboxReplay = {
|
|
|
7655
7681
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7656
7682
|
* @returns Completion of dispatch to the recorded target.
|
|
7657
7683
|
*/
|
|
7658
|
-
async
|
|
7684
|
+
async deliverProjectionEvent(repository, routing, message, deliveryTenantId) {
|
|
7659
7685
|
const runtime = repositoryRuntimes.get(repository);
|
|
7660
7686
|
if (runtime === undefined) {
|
|
7661
|
-
throw new Error("Projection inbox
|
|
7687
|
+
throw new Error("Projection inbox delivery requires a bound repository runtime.");
|
|
7662
7688
|
}
|
|
7663
7689
|
const event = InboxMessages.readProjectionInboxEvent(message);
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
const route =
|
|
7690
|
+
InboxDelivery.validateProjectionDeliveryTenant(runtime.context, deliveryTenantId, event);
|
|
7691
|
+
InboxDelivery.validateDeliveredEventPayload(routing, event);
|
|
7692
|
+
const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Projection inbox delivery");
|
|
7667
7693
|
const [entityId] = route.entityIds;
|
|
7668
7694
|
await new ProjectionEventExecution(repository, routing, runtime, event).runTarget(entityId, route);
|
|
7669
7695
|
},
|
|
7670
7696
|
/**
|
|
7671
|
-
* Routes a Projection Inbox message to domain Event or Entity-state update
|
|
7697
|
+
* Routes a Projection Inbox message to domain Event or Entity-state update deliver.
|
|
7672
7698
|
*
|
|
7673
7699
|
* @param repository Projection repository receiving the update.
|
|
7674
7700
|
* @param routing Registered subscribers and message schemas.
|
|
7675
7701
|
* @param message Stored Projection Inbox message.
|
|
7676
7702
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7677
|
-
* @returns Completion of the selected
|
|
7703
|
+
* @returns Completion of the selected deliver operation.
|
|
7678
7704
|
*/
|
|
7679
|
-
async
|
|
7705
|
+
async deliverProjectionMessage(repository, routing, message, deliveryTenantId) {
|
|
7680
7706
|
const event = InboxMessages.readProjectionInboxEvent(message);
|
|
7681
7707
|
if (event.message?.typeUrl === TypeUrls.derive(EntityLog.EntityStateChangedSchema)) {
|
|
7682
|
-
await
|
|
7708
|
+
await InboxDelivery.deliverProjectionStateUpdate(repository, routing, message, event, deliveryTenantId);
|
|
7683
7709
|
return;
|
|
7684
7710
|
}
|
|
7685
|
-
await
|
|
7711
|
+
await InboxDelivery.deliverProjectionEvent(repository, routing, message, deliveryTenantId);
|
|
7686
7712
|
},
|
|
7687
7713
|
/**
|
|
7688
7714
|
* Dispatches an Entity-state update to the Projection target recorded in its Inbox.
|
|
@@ -7694,12 +7720,12 @@ const InboxReplay = {
|
|
|
7694
7720
|
* @param deliveryTenantId Tenant selected by delivery in a multitenant context.
|
|
7695
7721
|
* @returns Completion of state-subscriber dispatch to the recorded target.
|
|
7696
7722
|
*/
|
|
7697
|
-
async
|
|
7723
|
+
async deliverProjectionStateUpdate(repository, routing, message, event, deliveryTenantId) {
|
|
7698
7724
|
const runtime = repositoryRuntimes.get(repository);
|
|
7699
7725
|
if (runtime === undefined)
|
|
7700
|
-
throw new Error("Projection inbox
|
|
7701
|
-
|
|
7702
|
-
const route =
|
|
7726
|
+
throw new Error("Projection inbox delivery requires a bound repository runtime.");
|
|
7727
|
+
InboxDelivery.validateProjectionDeliveryTenant(runtime.context, deliveryTenantId, event);
|
|
7728
|
+
const route = InboxDelivery.deliverStateUpdateRoute(repository, routing, message, event);
|
|
7703
7729
|
const [entityId] = route.entityIds;
|
|
7704
7730
|
const subscribers = route.subscribers;
|
|
7705
7731
|
await ProjectionEventExecution.runStateTarget(repository, routing, runtime, event, entityId, route, subscribers);
|
|
@@ -7708,9 +7734,9 @@ const InboxReplay = {
|
|
|
7708
7734
|
* Validates a stored Command against its schema and implicit identifier requirements.
|
|
7709
7735
|
*
|
|
7710
7736
|
* @param routing Registered Command schemas.
|
|
7711
|
-
* @param command Envelope whose payload must remain valid on
|
|
7737
|
+
* @param command Envelope whose payload must remain valid on deliver.
|
|
7712
7738
|
*/
|
|
7713
|
-
|
|
7739
|
+
validateDeliveredCommandPayload(routing, command) {
|
|
7714
7740
|
const commandMessage = EntityInvocation.requireSignalMessage(command.message, "command");
|
|
7715
7741
|
const commandSchema = RepositoryRoutes.schemaForTypeUrl(routing.commandSchemas, commandMessage.typeUrl, "command");
|
|
7716
7742
|
const payload = AnyPacker.tryUnpack(commandMessage, commandSchema);
|
|
@@ -7735,10 +7761,10 @@ const InboxReplay = {
|
|
|
7735
7761
|
* Unpacks and validates a stored Event against its registered schema.
|
|
7736
7762
|
*
|
|
7737
7763
|
* @param routing Registered Event schemas.
|
|
7738
|
-
* @param event Envelope whose payload must remain valid on
|
|
7764
|
+
* @param event Envelope whose payload must remain valid on deliver.
|
|
7739
7765
|
* @param invalidPayloadMessage Error text used when the payload cannot be unpacked.
|
|
7740
7766
|
*/
|
|
7741
|
-
|
|
7767
|
+
validateDeliveredEventPayload(routing, event, invalidPayloadMessage = "Projection inbox delivery requires a readable event payload.") {
|
|
7742
7768
|
const eventMessage = EntityInvocation.requireSignalMessage(event.message, "event");
|
|
7743
7769
|
const eventSchema = RepositoryRoutes.schemaForTypeUrl(routing.eventSchemas, eventMessage.typeUrl, "event");
|
|
7744
7770
|
const payload = AnyPacker.tryUnpack(eventMessage, eventSchema);
|
|
@@ -7748,69 +7774,69 @@ const InboxReplay = {
|
|
|
7748
7774
|
Validate.check(eventSchema, payload);
|
|
7749
7775
|
},
|
|
7750
7776
|
/**
|
|
7751
|
-
* Checks that a
|
|
7777
|
+
* Checks that a delivered Command's tenant matches its delivery tenant.
|
|
7752
7778
|
*
|
|
7753
7779
|
* @param context Context name and tenant mode; single-tenant contexts need no check.
|
|
7754
7780
|
* @param deliveryTenantId Tenant selected by Inbox delivery.
|
|
7755
7781
|
* @param command Stored Command containing the original actor context.
|
|
7756
7782
|
*/
|
|
7757
|
-
|
|
7783
|
+
validateDeliveryTenant(context, deliveryTenantId, command) {
|
|
7758
7784
|
if (!context.multitenant) {
|
|
7759
7785
|
return;
|
|
7760
7786
|
}
|
|
7761
7787
|
if (deliveryTenantId === undefined) {
|
|
7762
|
-
throw new Error(`Multitenant Entity Inbox
|
|
7788
|
+
throw new Error(`Multitenant Entity Inbox delivery for "${context.name}" requires tenantId.`);
|
|
7763
7789
|
}
|
|
7764
7790
|
const envelopeTenantId = RepositoryTenants.readCommandTenant(command);
|
|
7765
7791
|
if (envelopeTenantId === undefined) {
|
|
7766
|
-
throw new Error("Entity Inbox
|
|
7792
|
+
throw new Error("Entity Inbox delivery requires stored command tenant metadata.");
|
|
7767
7793
|
}
|
|
7768
7794
|
if (!RepositoryTenants.equal(envelopeTenantId, deliveryTenantId)) {
|
|
7769
|
-
throw new Error("Entity Inbox
|
|
7795
|
+
throw new Error("Entity Inbox delivery stored command tenant does not match.");
|
|
7770
7796
|
}
|
|
7771
7797
|
},
|
|
7772
7798
|
/**
|
|
7773
|
-
* Checks that a
|
|
7799
|
+
* Checks that a delivered Projection Event's tenant matches its delivery tenant.
|
|
7774
7800
|
*
|
|
7775
7801
|
* @param context Context name and tenant mode; single-tenant contexts need no check.
|
|
7776
7802
|
* @param deliveryTenantId Tenant selected by Inbox delivery.
|
|
7777
7803
|
* @param event Stored Event containing the original tenant metadata.
|
|
7778
7804
|
*/
|
|
7779
|
-
|
|
7805
|
+
validateProjectionDeliveryTenant(context, deliveryTenantId, event) {
|
|
7780
7806
|
if (!context.multitenant) {
|
|
7781
7807
|
return;
|
|
7782
7808
|
}
|
|
7783
7809
|
if (deliveryTenantId === undefined) {
|
|
7784
|
-
throw new Error(`Multitenant projection inbox
|
|
7810
|
+
throw new Error(`Multitenant projection inbox delivery for "${context.name}" requires tenantId.`);
|
|
7785
7811
|
}
|
|
7786
7812
|
const envelopeTenantId = RepositoryTenants.readEventTenant(event);
|
|
7787
7813
|
if (envelopeTenantId === undefined) {
|
|
7788
|
-
throw new Error("Projection inbox
|
|
7814
|
+
throw new Error("Projection inbox delivery requires stored event tenant metadata.");
|
|
7789
7815
|
}
|
|
7790
7816
|
if (!RepositoryTenants.equal(envelopeTenantId, deliveryTenantId)) {
|
|
7791
|
-
throw new Error("Projection inbox
|
|
7817
|
+
throw new Error("Projection inbox delivery stored event tenant does not match.");
|
|
7792
7818
|
}
|
|
7793
7819
|
},
|
|
7794
7820
|
/**
|
|
7795
|
-
* Checks that a
|
|
7821
|
+
* Checks that a delivered Entity Event's tenant matches its delivery tenant.
|
|
7796
7822
|
*
|
|
7797
7823
|
* @param context Context name and tenant mode; single-tenant contexts need no check.
|
|
7798
7824
|
* @param deliveryTenantId Tenant selected by Inbox delivery.
|
|
7799
7825
|
* @param event Stored Event containing the original tenant metadata.
|
|
7800
7826
|
*/
|
|
7801
|
-
|
|
7827
|
+
validateEventTenant(context, deliveryTenantId, event) {
|
|
7802
7828
|
if (!context.multitenant) {
|
|
7803
7829
|
return;
|
|
7804
7830
|
}
|
|
7805
7831
|
if (deliveryTenantId === undefined) {
|
|
7806
|
-
throw new Error(`Multitenant Entity Inbox
|
|
7832
|
+
throw new Error(`Multitenant Entity Inbox delivery for "${context.name}" requires tenantId.`);
|
|
7807
7833
|
}
|
|
7808
7834
|
const envelopeTenantId = RepositoryTenants.readEventTenant(event);
|
|
7809
7835
|
if (envelopeTenantId === undefined) {
|
|
7810
|
-
throw new Error("Entity Inbox
|
|
7836
|
+
throw new Error("Entity Inbox delivery requires stored event tenant metadata.");
|
|
7811
7837
|
}
|
|
7812
7838
|
if (!RepositoryTenants.equal(envelopeTenantId, deliveryTenantId)) {
|
|
7813
|
-
throw new Error("Entity Inbox
|
|
7839
|
+
throw new Error("Entity Inbox delivery stored event tenant does not match.");
|
|
7814
7840
|
}
|
|
7815
7841
|
},
|
|
7816
7842
|
/**
|
|
@@ -7822,10 +7848,10 @@ const InboxReplay = {
|
|
|
7822
7848
|
* @param command Stored Command used to identify the registered handler schema.
|
|
7823
7849
|
* @returns A deferred route to the recorded Entity identifier.
|
|
7824
7850
|
*/
|
|
7825
|
-
|
|
7851
|
+
deliverCommandRoute(repository, routing, message, command) {
|
|
7826
7852
|
const expectedTargetTypeUrl = TypeUrls.derive(repository.stateSchema);
|
|
7827
7853
|
if (message.inboxId.targetTypeUrl !== expectedTargetTypeUrl) {
|
|
7828
|
-
throw new Error("Entity Inbox
|
|
7854
|
+
throw new Error("Entity Inbox delivery stored target type does not match the routed repository.");
|
|
7829
7855
|
}
|
|
7830
7856
|
const commandMessage = EntityInvocation.requireSignalMessage(command.message, "command");
|
|
7831
7857
|
const schema = RepositoryRoutes.schemaForTypeUrl(routing.commandSchemas, commandMessage.typeUrl, "command");
|
|
@@ -7842,13 +7868,13 @@ const InboxReplay = {
|
|
|
7842
7868
|
* @param routing Registered Event schemas.
|
|
7843
7869
|
* @param message Inbox message recording the target type and identifier.
|
|
7844
7870
|
* @param event Stored Event used to identify the registered handler schema.
|
|
7845
|
-
* @param
|
|
7871
|
+
* @param deliverName Operation name used when reporting a target-type mismatch.
|
|
7846
7872
|
* @returns A deferred route containing exactly the recorded target identifier.
|
|
7847
7873
|
*/
|
|
7848
|
-
|
|
7874
|
+
deliverEventRoute(repository, routing, message, event, deliverName) {
|
|
7849
7875
|
const expectedTargetTypeUrl = TypeUrls.derive(repository.stateSchema);
|
|
7850
7876
|
if (message.inboxId.targetTypeUrl !== expectedTargetTypeUrl) {
|
|
7851
|
-
throw new Error(`${
|
|
7877
|
+
throw new Error(`${deliverName} stored target type does not match the routed repository.`);
|
|
7852
7878
|
}
|
|
7853
7879
|
const eventMessage = EntityInvocation.requireSignalMessage(event.message, "event");
|
|
7854
7880
|
const schema = RepositoryRoutes.schemaForTypeUrl(routing.eventSchemas, eventMessage.typeUrl, "event");
|
|
@@ -7869,15 +7895,15 @@ const InboxReplay = {
|
|
|
7869
7895
|
* @param event Stored Entity-state update envelope.
|
|
7870
7896
|
* @returns A deferred route with the unpacked state and matching subscribers.
|
|
7871
7897
|
*/
|
|
7872
|
-
|
|
7898
|
+
deliverStateUpdateRoute(repository, routing, message, event) {
|
|
7873
7899
|
const expectedTargetTypeUrl = TypeUrls.derive(repository.stateSchema);
|
|
7874
7900
|
if (message.inboxId.targetTypeUrl !== expectedTargetTypeUrl) {
|
|
7875
|
-
throw new Error("Projection inbox
|
|
7901
|
+
throw new Error("Projection inbox delivery stored target type does not match the routed repository.");
|
|
7876
7902
|
}
|
|
7877
|
-
const update = RepositoryRoutes.decodeStateUpdate(event, routing.stateSchemas, "Projection inbox
|
|
7903
|
+
const update = RepositoryRoutes.decodeStateUpdate(event, routing.stateSchemas, "Projection inbox delivery");
|
|
7878
7904
|
if (update === undefined ||
|
|
7879
7905
|
(routing.stateSubscriptions.get(update.schema.typeName)?.length ?? 0) === 0) {
|
|
7880
|
-
throw new Error("Projection inbox
|
|
7906
|
+
throw new Error("Projection inbox delivery requires a readable stored Entity state update.");
|
|
7881
7907
|
}
|
|
7882
7908
|
const { schema, state } = update;
|
|
7883
7909
|
const entityId = InboxMessages.targetEntityId(message.inboxId.targetId, repository.idField);
|
|
@@ -7886,7 +7912,7 @@ const InboxReplay = {
|
|
|
7886
7912
|
entityIds,
|
|
7887
7913
|
messageFullTypeName: schema.typeName,
|
|
7888
7914
|
state,
|
|
7889
|
-
subscribers:
|
|
7915
|
+
subscribers: InboxDelivery.stateSubscribers(routing, schema, event),
|
|
7890
7916
|
invocation: "deferred",
|
|
7891
7917
|
});
|
|
7892
7918
|
},
|
|
@@ -7903,7 +7929,7 @@ const InboxReplay = {
|
|
|
7903
7929
|
return Object.freeze(candidates.filter((subscriber) => (subscriber.handler.origin === "external") === (event.context?.external === true)));
|
|
7904
7930
|
},
|
|
7905
7931
|
};
|
|
7906
|
-
Object.freeze(
|
|
7932
|
+
Object.freeze(InboxDelivery);
|
|
7907
7933
|
/**
|
|
7908
7934
|
* Records routed signals in the appropriate Entity or Projection Inbox.
|
|
7909
7935
|
*/
|
|
@@ -7914,7 +7940,7 @@ const InboxHandoff = {
|
|
|
7914
7940
|
* @param repository Repository supplying the Command route and Entity type.
|
|
7915
7941
|
* @param runtime Inbox, storage, tenant mode, and delivery strategy.
|
|
7916
7942
|
* @param command Command envelope to retain and deliver.
|
|
7917
|
-
* @returns Completion
|
|
7943
|
+
* @returns Completion after Inbox receipt and eligible delivery scheduling.
|
|
7918
7944
|
* @param acceptedRoute Recipient route saved when the signal was accepted.
|
|
7919
7945
|
*/
|
|
7920
7946
|
async handoffEntityCommand(repository, runtime, command, acceptedRoute) {
|
|
@@ -7942,7 +7968,7 @@ const InboxHandoff = {
|
|
|
7942
7968
|
* @param runtime Projection Inbox, storage, and tenant mode.
|
|
7943
7969
|
* @param event Event envelope to retain and deliver.
|
|
7944
7970
|
* @param entityId Routed Projection identifier.
|
|
7945
|
-
* @returns Completion
|
|
7971
|
+
* @returns Completion after Inbox receipt and eligible delivery scheduling.
|
|
7946
7972
|
*/
|
|
7947
7973
|
async handoffProjectionEvent(repository, runtime, event, entityId) {
|
|
7948
7974
|
const eventId = RepositorySignals.requireEventId(event);
|
|
@@ -7963,53 +7989,53 @@ const InboxHandoff = {
|
|
|
7963
7989
|
}, deliveryTenantId);
|
|
7964
7990
|
},
|
|
7965
7991
|
/**
|
|
7966
|
-
* Delivers an Event to one
|
|
7992
|
+
* Delivers an Event to one Entity target using its Inbox.
|
|
7967
7993
|
*
|
|
7968
|
-
* @param repository Repository supplying the
|
|
7994
|
+
* @param repository Repository supplying the Entity type and ID descriptor.
|
|
7969
7995
|
* @param runtime Entity Inbox, storage, tenant mode, and delivery strategy.
|
|
7970
7996
|
* @param event Event envelope to retain and deliver.
|
|
7971
|
-
* @param entityId Routed
|
|
7972
|
-
* @returns Completion
|
|
7997
|
+
* @param entityId Routed Entity identifier.
|
|
7998
|
+
* @returns Completion after Inbox receipt and eligible delivery scheduling.
|
|
7973
7999
|
*/
|
|
7974
|
-
async
|
|
8000
|
+
async handoffEntityEvent(repository, runtime, event, entityId) {
|
|
7975
8001
|
const eventId = RepositorySignals.requireEventId(event);
|
|
7976
8002
|
const keepUntil = new Date(Time.currentTimeMillis() + inboxDedupMs);
|
|
7977
|
-
const deliveryTenantId = RepositoryTenants.
|
|
8003
|
+
const deliveryTenantId = RepositoryTenants.requireEntityEventTenant(runtime.context, event);
|
|
7978
8004
|
const delivery = serverEnvironmentAccess.coreDelivery(ServerEnvironment.instance());
|
|
7979
|
-
await runtime.entityInbox.receive(delivery, InboxHandoff.
|
|
8005
|
+
await runtime.entityInbox.receive(delivery, InboxHandoff.entityEventInboxInput(repository, eventId.value, event, entityId, keepUntil), deliveryTenantId);
|
|
7980
8006
|
},
|
|
7981
8007
|
/**
|
|
7982
|
-
* Delivers an Event to all routed
|
|
8008
|
+
* Delivers an Event to all routed Entity targets through batch receipt.
|
|
7983
8009
|
*
|
|
7984
|
-
* @param repository Repository supplying the
|
|
8010
|
+
* @param repository Repository supplying the Entity type and ID descriptor.
|
|
7985
8011
|
* @param runtime Entity Inbox, storage, tenant mode, and delivery strategy.
|
|
7986
8012
|
* @param event Event envelope shared by the target deliveries.
|
|
7987
|
-
* @param entityIds Routed
|
|
7988
|
-
* @returns Completion
|
|
8013
|
+
* @param entityIds Routed Entity identifiers.
|
|
8014
|
+
* @returns Completion after batch Inbox receipts and eligible delivery scheduling.
|
|
7989
8015
|
*/
|
|
7990
|
-
async
|
|
8016
|
+
async handoffEntityEvents(repository, runtime, event, entityIds) {
|
|
7991
8017
|
const eventId = RepositorySignals.requireEventId(event);
|
|
7992
8018
|
const keepUntil = new Date(Time.currentTimeMillis() + inboxDedupMs);
|
|
7993
|
-
const deliveryTenantId = RepositoryTenants.
|
|
8019
|
+
const deliveryTenantId = RepositoryTenants.requireEntityEventTenant(runtime.context, event);
|
|
7994
8020
|
const delivery = serverEnvironmentAccess.coreDelivery(ServerEnvironment.instance());
|
|
7995
8021
|
for (let start = 0; start < entityIds.length; start += 1_000) {
|
|
7996
8022
|
const inputs = entityIds
|
|
7997
8023
|
.slice(start, start + 1_000)
|
|
7998
|
-
.map((entityId) => InboxHandoff.
|
|
8024
|
+
.map((entityId) => InboxHandoff.entityEventInboxInput(repository, eventId.value, event, entityId, keepUntil));
|
|
7999
8025
|
await runtime.entityInbox.receiveAll(delivery, inputs, deliveryTenantId);
|
|
8000
8026
|
}
|
|
8001
8027
|
},
|
|
8002
8028
|
/**
|
|
8003
|
-
* Builds a pending
|
|
8029
|
+
* Builds a pending Entity Event delivery for a single target.
|
|
8004
8030
|
*
|
|
8005
8031
|
* @param repository Repository supplying the target type and ID descriptor.
|
|
8006
8032
|
* @param signalId Identifier of the original Event.
|
|
8007
8033
|
* @param event Event envelope to pack without repeating validation.
|
|
8008
|
-
* @param entityId Routed
|
|
8034
|
+
* @param entityId Routed Entity identifier.
|
|
8009
8035
|
* @param keepUntil Duplicate-retention deadline for this receipt.
|
|
8010
8036
|
* @returns Input for Entity Inbox receipt.
|
|
8011
8037
|
*/
|
|
8012
|
-
|
|
8038
|
+
entityEventInboxInput(repository, signalId, event, entityId, keepUntil) {
|
|
8013
8039
|
return {
|
|
8014
8040
|
inboxId: {
|
|
8015
8041
|
targetId: InboxMessages.inboxTargetId(entityId, repository.idField),
|
|
@@ -8025,7 +8051,7 @@ const InboxHandoff = {
|
|
|
8025
8051
|
};
|
|
8026
8052
|
Object.freeze(InboxHandoff);
|
|
8027
8053
|
/**
|
|
8028
|
-
* Connects bus dispatchers and Inbox
|
|
8054
|
+
* Connects bus dispatchers and Inbox delivery to repository execution.
|
|
8029
8055
|
*/
|
|
8030
8056
|
const RepositoryDispatch = {
|
|
8031
8057
|
/**
|
|
@@ -8126,7 +8152,7 @@ const RepositoryDispatch = {
|
|
|
8126
8152
|
: RepositoryDispatch.dispatchRepositoryStateUpdate(repository, routing, event, route);
|
|
8127
8153
|
},
|
|
8128
8154
|
/**
|
|
8129
|
-
* Creates
|
|
8155
|
+
* Creates deliver access for an Aggregate or Process Manager with signal handlers.
|
|
8130
8156
|
*
|
|
8131
8157
|
* @param repository Repository providing signal routes and Entity identity.
|
|
8132
8158
|
* @param routing Registered handlers and message schemas.
|
|
@@ -8143,19 +8169,17 @@ const RepositoryDispatch = {
|
|
|
8143
8169
|
targetTypeUrl: TypeUrls.derive(repository.stateSchema),
|
|
8144
8170
|
labels: Object.freeze([
|
|
8145
8171
|
...(routing.commandSchemas.length === 0 ? [] : ["HANDLE_COMMAND"]),
|
|
8146
|
-
...(
|
|
8147
|
-
repository.entityFamily === "agent") &&
|
|
8148
|
-
routing.eventSchemas.length > 0
|
|
8149
|
-
? ["REACT_UPON_EVENT"]
|
|
8150
|
-
: []),
|
|
8172
|
+
...(routing.eventSchemas.length > 0 ? ["REACT_UPON_EVENT"] : []),
|
|
8151
8173
|
]),
|
|
8152
|
-
|
|
8153
|
-
?
|
|
8154
|
-
|
|
8174
|
+
deliver: (message, deliveryTenantId) => repository.entityFamily === "aggregate"
|
|
8175
|
+
? message.label === "REACT_UPON_EVENT"
|
|
8176
|
+
? InboxDelivery.deliverAggregateEvent(repository, routing, message, deliveryTenantId)
|
|
8177
|
+
: InboxDelivery.deliverAggregateCommand(repository, routing, message, deliveryTenantId)
|
|
8178
|
+
: InboxDelivery.deliverPmInbox(repository, routing, message, deliveryTenantId),
|
|
8155
8179
|
});
|
|
8156
8180
|
},
|
|
8157
8181
|
/**
|
|
8158
|
-
* Creates
|
|
8182
|
+
* Creates deliver access for a Projection with Event or state subscribers.
|
|
8159
8183
|
*
|
|
8160
8184
|
* @param repository Repository providing Projection identity and Event routes.
|
|
8161
8185
|
* @param routing Registered Event and state subscribers.
|
|
@@ -8168,7 +8192,7 @@ const RepositoryDispatch = {
|
|
|
8168
8192
|
}
|
|
8169
8193
|
return Object.freeze({
|
|
8170
8194
|
targetTypeUrl: TypeUrls.derive(repository.stateSchema),
|
|
8171
|
-
|
|
8195
|
+
deliver: (message, deliveryTenantId) => InboxDelivery.deliverProjectionMessage(repository, routing, message, deliveryTenantId),
|
|
8172
8196
|
});
|
|
8173
8197
|
},
|
|
8174
8198
|
/**
|
|
@@ -8206,7 +8230,7 @@ const RepositoryDispatch = {
|
|
|
8206
8230
|
const route = acceptedRoute ?? (await repository.routeEvent(event));
|
|
8207
8231
|
switch (repository.entityFamily) {
|
|
8208
8232
|
case "aggregate":
|
|
8209
|
-
await RepositoryDispatch.dispatchAggregateEvent(repository,
|
|
8233
|
+
await RepositoryDispatch.dispatchAggregateEvent(repository, runtime, event, route);
|
|
8210
8234
|
return;
|
|
8211
8235
|
case "process-manager":
|
|
8212
8236
|
case "agent":
|
|
@@ -8221,17 +8245,19 @@ const RepositoryDispatch = {
|
|
|
8221
8245
|
* Dispatches an Event to each routed Aggregate with its configured duplicate guard.
|
|
8222
8246
|
*
|
|
8223
8247
|
* @param repository Aggregate repository receiving the Event.
|
|
8224
|
-
* @param routing Registered Aggregate Event handlers and schemas.
|
|
8225
8248
|
* @param runtime Bound storage, publisher, and tenant context.
|
|
8226
8249
|
* @param event Event envelope to dispatch.
|
|
8227
8250
|
* @param route Accepted route listing target Aggregate identifiers.
|
|
8228
8251
|
* @returns Completion of all target dispatches in route order.
|
|
8229
8252
|
*/
|
|
8230
|
-
async dispatchAggregateEvent(repository,
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8253
|
+
async dispatchAggregateEvent(repository, runtime, event, route) {
|
|
8254
|
+
if (route.entityIds.length === 0)
|
|
8255
|
+
return;
|
|
8256
|
+
if (route.entityIds.length === 1) {
|
|
8257
|
+
await InboxHandoff.handoffEntityEvent(repository, runtime, event, route.entityIds[0]);
|
|
8258
|
+
return;
|
|
8234
8259
|
}
|
|
8260
|
+
await InboxHandoff.handoffEntityEvents(repository, runtime, event, route.entityIds);
|
|
8235
8261
|
},
|
|
8236
8262
|
/**
|
|
8237
8263
|
* Delivers a routed Entity-state update to each target Projection Inbox.
|