@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.
Files changed (110) hide show
  1. package/README.md +56 -8
  2. package/REFERENCE.md +151 -39
  3. package/dist/agent/agent-live-ai-runtime.d.ts +1 -1
  4. package/dist/agent/agent-live-ai-runtime.js +1 -1
  5. package/dist/agent/agent-live-budget.d.ts +1 -1
  6. package/dist/agent/agent-live-budget.js +1 -1
  7. package/dist/agent/agent-live-read-runtime.d.ts +1 -1
  8. package/dist/agent/agent-live-read-runtime.js +1 -1
  9. package/dist/browser/browser-admission.d.ts +47 -0
  10. package/dist/browser/browser-admission.d.ts.map +1 -0
  11. package/dist/browser/browser-admission.js +200 -0
  12. package/dist/browser/browser-admission.js.map +1 -0
  13. package/dist/browser/browser-server.d.ts +14 -7
  14. package/dist/browser/browser-server.d.ts.map +1 -1
  15. package/dist/browser/browser-server.js +462 -129
  16. package/dist/browser/browser-server.js.map +1 -1
  17. package/dist/browser/index.d.ts +1 -1
  18. package/dist/browser/index.d.ts.map +1 -1
  19. package/dist/browser/options.d.ts +48 -2
  20. package/dist/browser/options.d.ts.map +1 -1
  21. package/dist/bus/command-bus.d.ts +6 -1
  22. package/dist/bus/command-bus.d.ts.map +1 -1
  23. package/dist/bus/command-bus.js +6 -1
  24. package/dist/bus/command-bus.js.map +1 -1
  25. package/dist/bus/event-bus.d.ts +6 -1
  26. package/dist/bus/event-bus.d.ts.map +1 -1
  27. package/dist/bus/event-bus.js +6 -1
  28. package/dist/bus/event-bus.js.map +1 -1
  29. package/dist/context/bounded-context.d.ts +30 -28
  30. package/dist/context/bounded-context.d.ts.map +1 -1
  31. package/dist/context/bounded-context.js +136 -82
  32. package/dist/context/bounded-context.js.map +1 -1
  33. package/dist/context/entity-inbox.d.ts +12 -17
  34. package/dist/context/entity-inbox.d.ts.map +1 -1
  35. package/dist/context/entity-inbox.js +106 -119
  36. package/dist/context/entity-inbox.js.map +1 -1
  37. package/dist/context/local-inbox-handoff.d.ts +13 -13
  38. package/dist/context/local-inbox-handoff.d.ts.map +1 -1
  39. package/dist/context/local-inbox-handoff.js +60 -32
  40. package/dist/context/local-inbox-handoff.js.map +1 -1
  41. package/dist/context/persistent-tenant-index.d.ts +81 -0
  42. package/dist/context/persistent-tenant-index.d.ts.map +1 -0
  43. package/dist/context/persistent-tenant-index.js +270 -0
  44. package/dist/context/persistent-tenant-index.js.map +1 -0
  45. package/dist/context/projection-handoff.d.ts +9 -9
  46. package/dist/context/projection-handoff.d.ts.map +1 -1
  47. package/dist/context/projection-handoff.js +31 -23
  48. package/dist/context/projection-handoff.js.map +1 -1
  49. package/dist/context/tenant-index.d.ts +7 -6
  50. package/dist/context/tenant-index.d.ts.map +1 -1
  51. package/dist/context/tenant-index.js +2 -188
  52. package/dist/context/tenant-index.js.map +1 -1
  53. package/dist/context/tenant-unknown-error.d.ts +2 -2
  54. package/dist/context/tenant-unknown-error.d.ts.map +1 -1
  55. package/dist/context/tenant-unknown-error.js +4 -1
  56. package/dist/context/tenant-unknown-error.js.map +1 -1
  57. package/dist/delivery/delivery-supervisor.d.ts.map +1 -1
  58. package/dist/delivery/delivery-supervisor.js +12 -3
  59. package/dist/delivery/delivery-supervisor.js.map +1 -1
  60. package/dist/delivery/delivery.d.ts +4 -3
  61. package/dist/delivery/delivery.d.ts.map +1 -1
  62. package/dist/delivery/delivery.js +82 -34
  63. package/dist/delivery/delivery.js.map +1 -1
  64. package/dist/delivery/reception-observation.d.ts +3 -3
  65. package/dist/delivery/reception-observation.js +2 -2
  66. package/dist/index.d.ts +4 -1
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +2 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/repository/command-routing.d.ts +1 -1
  71. package/dist/repository/command-routing.js +1 -1
  72. package/dist/repository/event-routing.d.ts +1 -1
  73. package/dist/repository/event-routing.js +1 -1
  74. package/dist/repository/repository.d.ts +23 -31
  75. package/dist/repository/repository.d.ts.map +1 -1
  76. package/dist/repository/repository.js +244 -218
  77. package/dist/repository/repository.js.map +1 -1
  78. package/dist/repository/state-update-routing.d.ts +1 -1
  79. package/dist/repository/state-update-routing.js +1 -1
  80. package/dist/runtime/signal-publisher.d.ts +23 -8
  81. package/dist/runtime/signal-publisher.d.ts.map +1 -1
  82. package/dist/runtime/signal-publisher.js +11 -8
  83. package/dist/runtime/signal-publisher.js.map +1 -1
  84. package/dist/server/node-coordinator.d.ts.map +1 -1
  85. package/dist/server/node-coordinator.js +220 -54
  86. package/dist/server/node-coordinator.js.map +1 -1
  87. package/dist/server/server-environment.d.ts +6 -5
  88. package/dist/server/server-environment.d.ts.map +1 -1
  89. package/dist/server/server-environment.js +13 -9
  90. package/dist/server/server-environment.js.map +1 -1
  91. package/dist/server/server.js +1 -0
  92. package/dist/server/server.js.map +1 -1
  93. package/dist/services/app-query-execution.js +2 -2
  94. package/dist/services/app-query-execution.js.map +1 -1
  95. package/dist/services/native-operation.d.ts +34 -0
  96. package/dist/services/native-operation.d.ts.map +1 -0
  97. package/dist/services/native-operation.js +77 -0
  98. package/dist/services/native-operation.js.map +1 -0
  99. package/dist/services/spine-services.d.ts +6 -0
  100. package/dist/services/spine-services.d.ts.map +1 -1
  101. package/dist/services/spine-services.js +128 -30
  102. package/dist/services/spine-services.js.map +1 -1
  103. package/dist/services/trusted-reader-ingress.d.ts +23 -5
  104. package/dist/services/trusted-reader-ingress.d.ts.map +1 -1
  105. package/dist/services/trusted-reader-ingress.js +18 -5
  106. package/dist/services/trusted-reader-ingress.js.map +1 -1
  107. package/dist/stand/stand.d.ts +1 -1
  108. package/dist/stand/stand.js +1 -1
  109. package/dist/tsconfig.tsbuildinfo +1 -1
  110. package/package.json +16 -14
@@ -24,6 +24,7 @@ import { DeliveryReadiness } from "./local-inbox-handoff.js";
24
24
  import { LocalEntityInbox } from "./entity-inbox.js";
25
25
  import { LocalProjectionInbox } from "./projection-handoff.js";
26
26
  import { TenantAdmissions } from "./tenant-unknown-error.js";
27
+ import { SINGLE_TENANT } from "./tenant-index.js";
27
28
  import { AgentExecutionCapacity, } from "../agent/agent-execution-capacity.js";
28
29
  import { AgentAcceptanceReceipts, agentAcceptanceReceiptGroup, agentAcceptanceReceiptSpec, } from "../agent/agent-acceptance-receipts.js";
29
30
  import { Repository, repositoryAccess, } from "../repository/repository.js";
@@ -152,7 +153,7 @@ export class BoundedContext {
152
153
  #agentReceipts;
153
154
  #agentController = new AbortController();
154
155
  #agentReservations = new Set();
155
- #activeReplays = new Set();
156
+ #activeDeliveries = new Set();
156
157
  #activePreparations = new Set();
157
158
  #tenantPreparations = new Map();
158
159
  #preparationController = new AbortController();
@@ -226,7 +227,7 @@ export class BoundedContext {
226
227
  eventBusAccess.bindEnvironment(this.#eventBus, this.#environment);
227
228
  eventBusAccess.bindEnvironment(this.#systemEventBus, this.#environment);
228
229
  commandBusAccess.setAdmission(this.#commandBus, (command) => this.#admitTenant(command.context?.actorContext?.tenantId));
229
- eventBusAccess.setAdmission(this.#eventBus, (event) => this.#admitTenant(ContextParts.readReplayTenant(event)));
230
+ eventBusAccess.setAdmission(this.#eventBus, (event) => this.#admitTenant(ContextParts.readCatchUpTenant(event)));
230
231
  standAccess.setAdmission(this.#stand, (tenantId) => this.#admitTenant(tenantId));
231
232
  standAccess.setPublicAdmission(this.#stand, () => {
232
233
  if (closingContexts.has(this) && !runtimeAccess.isRunningAdmittedWork(this.#environment))
@@ -374,10 +375,13 @@ export class BoundedContext {
374
375
  async #prepareCurrentTenants(mode) {
375
376
  if (!this.isMultitenant)
376
377
  return this.#requiredPrepare(() => this.#prepareTenant(undefined, mode));
378
+ const index = this.tenantIndex;
379
+ if (index === SINGLE_TENANT)
380
+ throw new Error("Multitenant preparation requires a tenant index.");
377
381
  let after;
378
382
  do {
379
383
  serverEnvironmentAccess.requireAvailable(this.#environment);
380
- const page = await this.tenantIndex.page({
384
+ const page = await index.page({
381
385
  count: 64,
382
386
  signal: this.#preparationController.signal,
383
387
  ...(after === undefined ? {} : { after }),
@@ -385,7 +389,7 @@ export class BoundedContext {
385
389
  serverEnvironmentAccess.requireAvailable(this.#environment);
386
390
  for (const id of page.ids) {
387
391
  serverEnvironmentAccess.requireAvailable(this.#environment);
388
- await TenantAdmissions.require(this.tenantIndex, this.name.value, true, id);
392
+ await TenantAdmissions.require(index, this.name.value, true, id);
389
393
  serverEnvironmentAccess.requireAvailable(this.#environment);
390
394
  await this.#requiredPrepare(() => this.#prepareTenant(id, mode));
391
395
  }
@@ -468,8 +472,8 @@ export class BoundedContext {
468
472
  /**
469
473
  * Creates tenant-aware Inboxes and their shared readiness signal.
470
474
  *
471
- * @param tenantIndex Effective membership index for this context.
472
- * @returns Inboxes, tenant index, and readiness signal.
475
+ * @param tenantIndex Captured marker or directory for this Bounded Context.
476
+ * @returns Inboxes, tenant setting, and readiness signal.
473
477
  */
474
478
  #createDelivery(tenantIndex) {
475
479
  const deliveryReadiness = this.#createReadiness();
@@ -477,8 +481,8 @@ export class BoundedContext {
477
481
  const entityInbox = new LocalEntityInbox(this.#snapshot.name.value, deliveryReadiness, onAdmit, this.#environment.delivery.strategy);
478
482
  const projectionInbox = new LocalProjectionInbox(this.#snapshot.name.value, deliveryReadiness, onAdmit);
479
483
  deliveryReadiness.configureDirect((message, tenantId) => message.label === "UPDATE_SUBSCRIBER"
480
- ? projectionInbox.replay(message, tenantId)
481
- : entityInbox.replay(message, tenantId));
484
+ ? projectionInbox.deliver(message, tenantId)
485
+ : entityInbox.deliver(message, tenantId));
482
486
  return { deliveryReadiness, tenantIndex, entityInbox, projectionInbox };
483
487
  }
484
488
  /**
@@ -518,7 +522,7 @@ export class BoundedContext {
518
522
  this.#beginClose();
519
523
  },
520
524
  drain: () => this.#drainWork(),
521
- trackReplay: (onReplay) => this.#trackReplay(onReplay),
525
+ trackDelivery: (onDelivery) => this.#trackDelivery(onDelivery),
522
526
  });
523
527
  contextDeliveryDescriptors.set(this, ContextParts.createDeliveryDescriptor(this.#entityInbox, this.#projectionInbox));
524
528
  }
@@ -699,9 +703,10 @@ export class BoundedContext {
699
703
  return this.#snapshot.tenantMode === "multitenant";
700
704
  }
701
705
  /**
702
- * Returns the live index configured for this Bounded Context.
706
+ * Returns the captured tenant setting for this Bounded Context.
703
707
  *
704
- * @returns The effective configured index.
708
+ * @returns SINGLE_TENANT in single mode, even when the environment has an index;
709
+ * otherwise the effective directory. Narrow before calling index methods.
705
710
  */
706
711
  get tenantIndex() {
707
712
  return ContextParts.requireTenantIndex(this);
@@ -781,17 +786,16 @@ export class BoundedContext {
781
786
  throw new Error("Entity constructor is not registered in this Bounded Context.");
782
787
  }
783
788
  /**
784
- * Clears and locally replays every registered Projection from already-stored events.
789
+ * Clears registered Projection state and processes already-stored Events locally.
785
790
  *
786
- * Despite its legacy name, this method is not Projection catch-up. It is a
787
- * process-local maintenance helper and provides no Projection targeting,
791
+ * This process-local maintenance helper provides no Projection targeting,
788
792
  * historical starting point, durable operation identity, progress,
789
793
  * historical/live coordination, restart, resumption, or multi-node work.
790
794
  *
791
795
  * Supported boundary:
792
796
  * - projection subscribers only;
793
797
  * - already-stored events only;
794
- * - clear then replay, with no event re-append;
798
+ * - clear then dispatch stored Events, with no event re-append;
795
799
  * - single-tenant contexts reject `tenantId`;
796
800
  * - multitenant contexts require the exact non-blank `tenantId`;
797
801
  * - process-local sequential execution on the same EventBus runtime queue as
@@ -803,14 +807,14 @@ export class BoundedContext {
803
807
  * - durable live-traffic catch-up orchestration across processes.
804
808
  *
805
809
  * @param options Selects the tenant slice to rebuild.
806
- * @returns Resolves to replay and clear counts for the selected slice.
810
+ * @returns Dispatch and clear counts for the selected slice.
807
811
  */
808
812
  async catchUpReadSide(options = {}) {
809
813
  return eventBusAccess.runExclusive(this.#eventBus, () => this.#catchUpReadSideOnce(options));
810
814
  }
811
815
  /**
812
816
  * Clears registered Projection state for the selected tenant slice, reads stored events,
813
- * validates each event’s tenant, and dispatches replay sequentially.
817
+ * validates each Event’s tenant, and dispatches stored Events sequentially.
814
818
  */
815
819
  async #catchUpReadSideOnce(options) {
816
820
  const storageContext = ContextParts.catchUpStorageContext(this.#snapshot.spec, options);
@@ -819,7 +823,7 @@ export class BoundedContext {
819
823
  const clearTargets = ContextParts.projectionStateClearTargets(projections);
820
824
  const clearedStateTypes = [];
821
825
  let clearedEntityCount = 0;
822
- let replayedEventCount = 0;
826
+ let processedEventCount = 0;
823
827
  for (const target of clearTargets) {
824
828
  clearedEntityCount += await this.#stand.clear(target.schema, tenantOptions);
825
829
  clearedStateTypes.push(target.typeUrl);
@@ -827,15 +831,15 @@ export class BoundedContext {
827
831
  const events = await ContextParts.readStoredEvents(storageContext, this.#storageFactory);
828
832
  for (const event of events) {
829
833
  try {
830
- ContextParts.validateReplayTenant(storageContext, event);
831
- replayedEventCount += await ContextParts.dispatchStoredProjectionEvent(projections, event, true);
834
+ ContextParts.validateCatchUpTenant(storageContext, event);
835
+ processedEventCount += await ContextParts.dispatchStoredProjectionEvent(projections, event, true);
832
836
  }
833
837
  catch (error) {
834
- throw ContextParts.catchUpReplayError(event, error);
838
+ throw ContextParts.catchUpDispatchError(event, error);
835
839
  }
836
840
  }
837
841
  return Object.freeze({
838
- replayedEventCount,
842
+ processedEventCount,
839
843
  clearedEntityCount,
840
844
  clearedStateTypes: Object.freeze(clearedStateTypes),
841
845
  });
@@ -902,13 +906,12 @@ export class BoundedContext {
902
906
  ContextParts.clearContextMetadata(this);
903
907
  }
904
908
  /**
905
- * Settles entered replay, local follow-ups, and reserved Agent turns.
909
+ * Settles entered deliveries, outgoing handoffs, and reserved Agent turns.
906
910
  * @param errors Collects independent close failures.
907
911
  */
908
912
  async #drainAdmittedContextWork(errors) {
909
913
  await this.#closePart(() => Promise.allSettled([...this.#activePreparations]).then(() => undefined), errors);
910
- await this.#closePart(() => Promise.allSettled([...this.#activeReplays]).then(() => undefined), errors);
911
- await this.#closePart(() => this.#entityInbox.whenFollowUpsIdle(), errors);
914
+ await this.#closePart(() => Promise.allSettled([...this.#activeDeliveries]).then(() => undefined), errors);
912
915
  await this.#closePart(() => Promise.allSettled([...this.#agentReservations]).then(() => undefined), errors);
913
916
  }
914
917
  /**
@@ -943,15 +946,15 @@ export class BoundedContext {
943
946
  }
944
947
  }
945
948
  /**
946
- * Registers an entered shared replay through its complete follow-up callback.
947
- * @param onReplay Complete replay callback.
948
- * @returns Completion of the captured callback.
949
+ * Registers an entered Inbox delivery through recipient processing and outgoing handoff.
950
+ * @param onDelivery Delivers the stored message.
951
+ * @returns Completion after the delivery callback returns.
949
952
  */
950
- #trackReplay(onReplay) {
951
- const replay = Promise.resolve().then(onReplay);
952
- this.#activeReplays.add(replay);
953
- void replay.then(() => this.#activeReplays.delete(replay), () => this.#activeReplays.delete(replay));
954
- return replay;
953
+ #trackDelivery(onDelivery) {
954
+ const delivery = Promise.resolve().then(onDelivery);
955
+ this.#activeDeliveries.add(delivery);
956
+ void delivery.then(() => this.#activeDeliveries.delete(delivery), () => this.#activeDeliveries.delete(delivery));
957
+ return delivery;
955
958
  }
956
959
  /**
957
960
  * Calls a close action and collects its failure before later cleanup.
@@ -1003,7 +1006,7 @@ export const boundedContextAccess = Object.freeze({
1003
1006
  const phase = contextClosePhases.get(context);
1004
1007
  if (prepare === undefined || phase === undefined)
1005
1008
  return Promise.reject(new TypeError("Service input requires a built context."));
1006
- return phase.trackReplay(async () => {
1009
+ return phase.trackDelivery(async () => {
1007
1010
  await onMembership();
1008
1011
  await prepare(tenantId);
1009
1012
  await onReady?.();
@@ -1022,16 +1025,16 @@ export const boundedContextAccess = Object.freeze({
1022
1025
  const phase = contextClosePhases.get(context);
1023
1026
  if (phase === undefined)
1024
1027
  return Promise.reject(new TypeError("Service registry requires a built context."));
1025
- return phase.trackReplay(onOperation);
1028
+ return phase.trackDelivery(onOperation);
1026
1029
  },
1027
1030
  /**
1028
- * Registers replay work with the context close lifecycle so shutdown waits for it.
1031
+ * Registers entered delivery work with the context close lifecycle.
1029
1032
  */
1030
- trackReplay(context, onReplay) {
1033
+ trackDelivery(context, onDelivery) {
1031
1034
  const phase = contextClosePhases.get(context);
1032
1035
  if (phase === undefined)
1033
- return Promise.reject(new TypeError("Replay requires a built context."));
1034
- return phase.trackReplay(onReplay);
1036
+ return Promise.reject(new TypeError("Delivery requires a built context."));
1037
+ return phase.trackDelivery(onDelivery);
1035
1038
  },
1036
1039
  /**
1037
1040
  * Resolves a view only within the Bounded Context that issued it.
@@ -1059,7 +1062,7 @@ export const boundedContextAccess = Object.freeze({
1059
1062
  phase.begin();
1060
1063
  },
1061
1064
  /**
1062
- * Waits for accepted runtime work and replay operations to finish.
1065
+ * Waits for accepted runtime work and entered delivery operations to finish.
1063
1066
  */
1064
1067
  drainWork(context) {
1065
1068
  const phase = contextClosePhases.get(context);
@@ -1165,7 +1168,7 @@ export const boundedContextAccess = Object.freeze({
1165
1168
  return ContextParts.cloneSystemPairing(ContextParts.requireSystemPairing(context));
1166
1169
  },
1167
1170
  /**
1168
- * Returns the live tenant membership index configured for this context.
1171
+ * Returns the captured marker or directory for this Bounded Context.
1169
1172
  */
1170
1173
  tenantIndex(context) {
1171
1174
  return ContextParts.requireTenantIndex(context);
@@ -1397,7 +1400,9 @@ export class BoundedContextBuilder {
1397
1400
  return this;
1398
1401
  }
1399
1402
  /**
1400
- * Sets a live tenant index for this Bounded Context.
1403
+ * Sets a directory that overrides the environment index for this multitenant Bounded Context.
1404
+ * The environment must already have a real index at build time; an override
1405
+ * cannot enable multitenancy in a SINGLE_TENANT environment.
1401
1406
  *
1402
1407
  * @param tenantIndex Application membership index.
1403
1408
  * @returns This builder.
@@ -1485,10 +1490,11 @@ export class BoundedContextBuilder {
1485
1490
  * @returns The integrated context.
1486
1491
  */
1487
1492
  async #buildAsyncReady(options, environment) {
1493
+ const tenantIndex = this.#selectTenantIndex(environment);
1488
1494
  const generated = this.#loadGeneratedArtifacts([...this.#entityTypes]);
1489
1495
  serverEnvironmentAccess.requireAvailable(environment);
1490
1496
  const repositories = [...this.#repositories, ...generated.repositories];
1491
- const context = await this.#buildWithResources(repositories, environment.storageFactory, generated.standalone, this.#aiRegistry ?? environment.ai);
1497
+ const context = await this.#buildWithResources(repositories, environment.storageFactory, generated.standalone, this.#aiRegistry ?? environment.ai, tenantIndex);
1492
1498
  try {
1493
1499
  await this.#integrateBuiltContext(context, options, environment);
1494
1500
  }
@@ -1497,6 +1503,20 @@ export class BoundedContextBuilder {
1497
1503
  }
1498
1504
  return context;
1499
1505
  }
1506
+ /**
1507
+ * Captures tenant selection before acquiring business storage.
1508
+ *
1509
+ * @param environment Process facilities selected for this build.
1510
+ * @returns Marker for single mode or the effective directory for multi mode.
1511
+ */
1512
+ #selectTenantIndex(environment) {
1513
+ if (!this.#specSnapshot.multitenant)
1514
+ return SINGLE_TENANT;
1515
+ const configured = environment.tenantIndex;
1516
+ if (configured === SINGLE_TENANT)
1517
+ throw new Error("Multitenant Bounded Context requires an environment tenant index.");
1518
+ return this.#tenantIndex ?? configured;
1519
+ }
1500
1520
  /**
1501
1521
  * Completes required integration and requested initialization before publication.
1502
1522
  * @param context Constructed context.
@@ -1545,14 +1565,15 @@ export class BoundedContextBuilder {
1545
1565
  * @param storageFactory Storage factory for the context.
1546
1566
  * @param standalone Generated standalone handler groups.
1547
1567
  * @param ai Optional AI registry.
1568
+ * @param tenantIndex Captured marker or directory for admission.
1548
1569
  * @returns The assembled context.
1549
1570
  */
1550
- async #buildWithResources(repositories, storageFactory, standalone, ai) {
1571
+ async #buildWithResources(repositories, storageFactory, standalone, ai, tenantIndex) {
1551
1572
  const resources = this.#subscriptionRegistry === undefined ? {} : { registry: this.#subscriptionRegistry };
1552
1573
  this.#subscriptionRegistry = undefined;
1553
1574
  const registeredRepositories = [...repositories];
1554
1575
  try {
1555
- return this.#assembleContext(registeredRepositories, storageFactory, standalone, resources, ai);
1576
+ return this.#assembleContext(registeredRepositories, storageFactory, standalone, resources, ai, tenantIndex);
1556
1577
  }
1557
1578
  catch (error) {
1558
1579
  return await this.#failBuild(resources, error);
@@ -1561,8 +1582,16 @@ export class BoundedContextBuilder {
1561
1582
  /**
1562
1583
  * Assembles dispatchers, buses, Stand, subscription runtime, and integration hooks, registering
1563
1584
  * the completed context with its environment.
1564
- */
1565
- #assembleContext(repositories, storageFactory, standalone, resources, ai) {
1585
+ *
1586
+ * @param repositories Registered repository views.
1587
+ * @param storageFactory Provider for business records.
1588
+ * @param standalone Generated standalone handlers.
1589
+ * @param resources Partial resources to close if assembly fails.
1590
+ * @param ai Selected AI registry, when configured.
1591
+ * @param tenantIndex Captured marker or directory.
1592
+ * @returns Assembled Bounded Context.
1593
+ */
1594
+ #assembleContext(repositories, storageFactory, standalone, resources, ai, tenantIndex) {
1566
1595
  ContextParts.preflightRepositories(repositories);
1567
1596
  this.#preflightAgents(repositories, storageFactory, ai);
1568
1597
  if (ai !== undefined)
@@ -1576,17 +1605,28 @@ export class BoundedContextBuilder {
1576
1605
  ...ContextParts.repositoryProducedEventSchemas(repositories),
1577
1606
  ...ContextParts.standaloneProducedEventSchemas(standalone),
1578
1607
  ]);
1579
- const running = this.#buildRuntime(storageFactory, buses, resources);
1580
- const context = this.#createContext(repositories, storageFactory, buses, running, ai);
1608
+ const running = this.#buildRuntime(storageFactory, buses, resources, tenantIndex);
1609
+ const context = this.#createContext(repositories, storageFactory, buses, running, tenantIndex, ai);
1581
1610
  resources.context = context;
1582
1611
  if (registerBoundedContext === undefined)
1583
1612
  throw new Error("Context registration is unavailable.");
1584
1613
  registerBoundedContext(context, repositories);
1614
+ this.#attachIntegration(context, buses, dispatchers, standaloneEvent);
1615
+ return context;
1616
+ }
1617
+ /**
1618
+ * Registers external Event routes after Bounded Context construction.
1619
+ *
1620
+ * @param context Completed Bounded Context.
1621
+ * @param buses Signal buses and System metadata.
1622
+ * @param dispatchers Repository dispatchers.
1623
+ * @param standaloneEvent Generated standalone Event dispatcher, when present.
1624
+ */
1625
+ #attachIntegration(context, buses, dispatchers, standaloneEvent) {
1585
1626
  ContextParts.attachIntegration(context, buses.eventBus, buses.systemSpec, ContextParts.externalEventSchemas([
1586
1627
  ...dispatchers.domain,
1587
1628
  ...(standaloneEvent === undefined ? [] : [standaloneEvent]),
1588
1629
  ]));
1589
- return context;
1590
1630
  }
1591
1631
  /**
1592
1632
  * Rejects missing Agent prerequisites before repository intake is installed.
@@ -1705,9 +1745,15 @@ export class BoundedContextBuilder {
1705
1745
  }
1706
1746
  /**
1707
1747
  * Creates the context Stand, subscription registry, and runtime that observes domain and System events.
1748
+ *
1749
+ * @param storageFactory Provider for business records.
1750
+ * @param buses Assembled signal buses.
1751
+ * @param resources Partial resources to close if assembly fails.
1752
+ * @param tenantIndex Captured marker or directory.
1753
+ * @returns Assembled Stand and subscription runtime.
1708
1754
  */
1709
- #buildRuntime(storageFactory, buses, resources) {
1710
- const stand = this.#buildStand(storageFactory);
1755
+ #buildRuntime(storageFactory, buses, resources, tenantIndex) {
1756
+ const stand = this.#buildStand(storageFactory, tenantIndex);
1711
1757
  resources.stand = stand;
1712
1758
  const registry = resources.registry ??
1713
1759
  new StorageSubscriptionRegistry(ContextParts.createSubscriptionStorageContext(this.#specSnapshot), storageFactory, subscriptionRecordGroup(this.#specSnapshot.name.value));
@@ -1717,13 +1763,13 @@ export class BoundedContextBuilder {
1717
1763
  return { stand, registry, runtime };
1718
1764
  }
1719
1765
  /**
1720
- * Builds the context Stand with a captured live membership directory.
1766
+ * Builds the Bounded Context Stand with captured tenant admission.
1721
1767
  *
1722
1768
  * @param storageFactory Provider used for Entity records.
1769
+ * @param tenantIndex Captured marker or directory.
1723
1770
  * @returns Direct read-side Stand.
1724
1771
  */
1725
- #buildStand(storageFactory) {
1726
- const tenantIndex = this.#tenantIndex ?? ServerEnvironment.instance().tenantIndex;
1772
+ #buildStand(storageFactory, tenantIndex) {
1727
1773
  const stand = new Stand({
1728
1774
  context: ContextParts.createStorageMode(this.#specSnapshot),
1729
1775
  storageFactory,
@@ -1735,10 +1781,18 @@ export class BoundedContextBuilder {
1735
1781
  }
1736
1782
  /**
1737
1783
  * Constructs the immutable BoundedContext using assembled buses, runtime parts, environment
1738
- * delivery strategy, and tenant index.
1784
+ * delivery strategy, and tenant setting.
1785
+ *
1786
+ * @param repositories Registered repository views.
1787
+ * @param storageFactory Provider for business records.
1788
+ * @param buses Assembled signal buses.
1789
+ * @param running Prepared Stand and subscription runtime.
1790
+ * @param tenantIndex Captured marker or directory.
1791
+ * @param ai Selected AI registry, when configured.
1792
+ * @returns Immutable Bounded Context.
1739
1793
  */
1740
- #createContext(repositories, storageFactory, buses, running, ai) {
1741
- return ContextParts.createBoundedContext(this.#specSnapshot, storageFactory, repositories, ServerEnvironment.instance().delivery.strategy, buses, running, ai, this.#tenantIndex ?? ServerEnvironment.instance().tenantIndex);
1794
+ #createContext(repositories, storageFactory, buses, running, tenantIndex, ai) {
1795
+ return ContextParts.createBoundedContext(this.#specSnapshot, storageFactory, repositories, ServerEnvironment.instance().delivery.strategy, buses, running, ai, tenantIndex);
1742
1796
  }
1743
1797
  /**
1744
1798
  * Closes partial context resources after assembly fails and aggregates cleanup errors with the original failure.
@@ -1873,28 +1927,28 @@ export class ContextSpec {
1873
1927
  }
1874
1928
  const registeredRepositories = new WeakMap();
1875
1929
  /**
1876
- * Reports failure while redispatching a stored event during read-side replay.
1930
+ * Reports failure while dispatching a stored Event during read-side catch-up.
1877
1931
  */
1878
- class CatchUpReplayError extends Error {
1879
- code = "READ_SIDE_CATCH_UP_REPLAY_FAILED";
1932
+ class CatchUpDispatchError extends Error {
1933
+ code = "READ_SIDE_CATCH_UP_DISPATCH_FAILED";
1880
1934
  eventId;
1881
1935
  detail;
1882
1936
  /**
1883
- * Creates a replay error tied to the stored event that failed.
1937
+ * Creates a catch-up error tied to the stored Event that failed.
1884
1938
  *
1885
1939
  * @param eventId Identifies the stored event.
1886
1940
  * @param detail Contains the bounded cause name and message.
1887
1941
  */
1888
1942
  constructor(eventId, detail) {
1889
1943
  super(`Read-side catch-up failed for stored event "${eventId}".`);
1890
- this.name = "ReadCatchUpReplayError";
1944
+ this.name = "ReadSideCatchUpDispatchError";
1891
1945
  this.eventId = eventId;
1892
1946
  this.detail = detail;
1893
1947
  Object.setPrototypeOf(this, new.target.prototype);
1894
1948
  }
1895
1949
  }
1896
1950
  /**
1897
- * Assembles private bounded-context lifecycle and replay details.
1951
+ * Assembles private bounded-context lifecycle and catch-up details.
1898
1952
  */
1899
1953
  const ContextParts = Object.freeze({
1900
1954
  /**
@@ -2039,7 +2093,7 @@ const ContextParts = Object.freeze({
2039
2093
  * @param buses Prepared domain and System buses.
2040
2094
  * @param running Prepared Stand and subscription runtime.
2041
2095
  * @param ai Effective AI registry when Agent repositories are present.
2042
- * @param tenantIndex Effective live membership index.
2096
+ * @param tenantIndex Captured marker or directory.
2043
2097
  * @returns Constructed bounded context.
2044
2098
  */
2045
2099
  createBoundedContext(specSnapshot, storageFactory, repositories, deliveryStrategy, buses, running, ai, tenantIndex) {
@@ -2054,7 +2108,7 @@ const ContextParts = Object.freeze({
2054
2108
  subscriptionRuntime: running.runtime,
2055
2109
  systemSpec: buses.systemSpec,
2056
2110
  storageFactory,
2057
- tenantIndex: tenantIndex ?? ServerEnvironment.instance().tenantIndex,
2111
+ tenantIndex,
2058
2112
  repositories,
2059
2113
  deliveryStrategy,
2060
2114
  ...(ai === undefined ? {} : { ai }),
@@ -2329,7 +2383,7 @@ const ContextParts = Object.freeze({
2329
2383
  * @param event Imported event to validate.
2330
2384
  */
2331
2385
  validateImportedTenant(context, event) {
2332
- const tenantId = ContextParts.readReplayTenant(event);
2386
+ const tenantId = ContextParts.readCatchUpTenant(event);
2333
2387
  if (!context.isMultitenant) {
2334
2388
  if (tenantId !== undefined) {
2335
2389
  throw new Error(`Single-tenant context "${context.name.value}" does not accept tenantId.`);
@@ -2384,10 +2438,10 @@ const ContextParts = Object.freeze({
2384
2438
  return pairing;
2385
2439
  },
2386
2440
  /**
2387
- * Reads the tenant index recorded for a built context.
2441
+ * Reads the marker or directory recorded for a built Bounded Context.
2388
2442
  *
2389
- * @param context Context to inspect.
2390
- * @returns Tenant index; throws if unavailable.
2443
+ * @param context Bounded Context to inspect.
2444
+ * @returns Captured marker or directory; throws if unavailable.
2391
2445
  */
2392
2446
  requireTenantIndex(context) {
2393
2447
  const tenantIndex = contextTenantIndexes.get(context);
@@ -2713,9 +2767,9 @@ const ContextParts = Object.freeze({
2713
2767
  createDeliveryDescriptor(entityInbox, projections) {
2714
2768
  return Object.freeze({
2715
2769
  endpoints: () => Object.freeze([...entityInbox.endpoints(), ...projections.endpoints()]),
2716
- replay: (message, tenantId) => message.label === "UPDATE_SUBSCRIBER"
2717
- ? projections.replay(message, tenantId)
2718
- : entityInbox.replay(message, tenantId),
2770
+ deliver: (message, tenantId) => message.label === "UPDATE_SUBSCRIBER"
2771
+ ? projections.deliver(message, tenantId)
2772
+ : entityInbox.deliver(message, tenantId),
2719
2773
  });
2720
2774
  },
2721
2775
  /**
@@ -2986,12 +3040,12 @@ const ContextParts = Object.freeze({
2986
3040
  * @param context Catch-up storage context.
2987
3041
  * @param event Stored event to validate.
2988
3042
  */
2989
- validateReplayTenant(context, event) {
3043
+ validateCatchUpTenant(context, event) {
2990
3044
  if (!context.multitenant) {
2991
3045
  return;
2992
3046
  }
2993
3047
  const expectedTenantId = context.tenantId;
2994
- const envelopeTenantId = ContextParts.readReplayTenant(event);
3048
+ const envelopeTenantId = ContextParts.readCatchUpTenant(event);
2995
3049
  if (envelopeTenantId === undefined) {
2996
3050
  throw new Error("Read-side catch-up requires stored event envelope tenant.");
2997
3051
  }
@@ -3005,7 +3059,7 @@ const ContextParts = Object.freeze({
3005
3059
  * @param event Event whose origin is inspected.
3006
3060
  * @returns Cloned tenant ID when present.
3007
3061
  */
3008
- readReplayTenant(event) {
3062
+ readCatchUpTenant(event) {
3009
3063
  switch (event.context?.origin.case) {
3010
3064
  case "importContext":
3011
3065
  return ContextParts.tenantIdValue(event.context.origin.value.tenantId);
@@ -3047,14 +3101,14 @@ const ContextParts = Object.freeze({
3047
3101
  return matching.length > 0 ? 1 : 0;
3048
3102
  },
3049
3103
  /**
3050
- * Creates a replay error with the event ID and bounded cause details.
3104
+ * Creates a catch-up error with the Event ID and bounded cause details.
3051
3105
  *
3052
3106
  * @param event Event that failed.
3053
- * @param cause Thrown replay cause.
3054
- * @returns Replay error.
3107
+ * @param cause Thrown catch-up cause.
3108
+ * @returns Catch-up error.
3055
3109
  */
3056
- catchUpReplayError(event, cause) {
3057
- return new CatchUpReplayError(event.id?.value ?? "(missing)", ContextParts.catchUpReplayDetail(cause));
3110
+ catchUpDispatchError(event, cause) {
3111
+ return new CatchUpDispatchError(event.id?.value ?? "(missing)", ContextParts.catchUpDispatchDetail(cause));
3058
3112
  },
3059
3113
  /**
3060
3114
  * Returns an error string truncated to a maximum length.
@@ -3072,7 +3126,7 @@ const ContextParts = Object.freeze({
3072
3126
  * @param error Thrown value.
3073
3127
  * @returns Immutable bounded details.
3074
3128
  */
3075
- catchUpReplayDetail(error) {
3129
+ catchUpDispatchDetail(error) {
3076
3130
  if (error instanceof Error) {
3077
3131
  return Object.freeze({
3078
3132
  name: ContextParts.boundedErrorString(error.name, errorDetailLimit) || "Error",