@spine-event-engine/server 2.0.0-snapshot.25 → 2.0.0-snapshot.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -9
- package/REFERENCE.md +339 -22
- package/dist/agent/agent-history.d.ts +19 -3
- package/dist/agent/agent-history.d.ts.map +1 -1
- package/dist/agent/agent-history.js +41 -10
- package/dist/agent/agent-history.js.map +1 -1
- package/dist/agent/agent-live-read-runtime.d.ts +12 -1
- package/dist/agent/agent-live-read-runtime.d.ts.map +1 -1
- package/dist/agent/agent-live-read-runtime.js +5 -4
- package/dist/agent/agent-live-read-runtime.js.map +1 -1
- package/dist/browser/browser-server.d.ts +163 -0
- package/dist/browser/browser-server.d.ts.map +1 -1
- package/dist/browser/browser-server.js +579 -188
- package/dist/browser/browser-server.js.map +1 -1
- package/dist/browser/durable-subscription-bindings.d.ts +5 -0
- package/dist/browser/durable-subscription-bindings.d.ts.map +1 -1
- package/dist/browser/durable-subscription-bindings.js +226 -38
- package/dist/browser/durable-subscription-bindings.js.map +1 -1
- package/dist/browser/options.d.ts +5 -0
- package/dist/browser/options.d.ts.map +1 -1
- package/dist/bus/command-bus.d.ts +3 -0
- package/dist/bus/command-bus.d.ts.map +1 -1
- package/dist/bus/command-bus.js +69 -9
- package/dist/bus/command-bus.js.map +1 -1
- package/dist/bus/command-errors.d.ts +20 -4
- package/dist/bus/command-errors.d.ts.map +1 -1
- package/dist/bus/command-errors.js +47 -7
- package/dist/bus/command-errors.js.map +1 -1
- package/dist/bus/event-bus.d.ts +3 -0
- package/dist/bus/event-bus.d.ts.map +1 -1
- package/dist/bus/event-bus.js +130 -8
- package/dist/bus/event-bus.js.map +1 -1
- package/dist/context/bounded-context.d.ts +29 -11
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +147 -186
- package/dist/context/bounded-context.js.map +1 -1
- package/dist/entity/entity.d.ts +59 -0
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +60 -0
- package/dist/entity/entity.js.map +1 -1
- package/dist/handler/app-query-handler.d.ts +60 -0
- package/dist/handler/app-query-handler.d.ts.map +1 -0
- package/dist/handler/app-query-handler.js +23 -0
- package/dist/handler/app-query-handler.js.map +1 -0
- package/dist/handler/generated-registry-discovery.d.ts +6 -0
- package/dist/handler/generated-registry-discovery.d.ts.map +1 -1
- package/dist/handler/generated-registry-discovery.js +71 -2
- package/dist/handler/generated-registry-discovery.js.map +1 -1
- package/dist/handler/handler-decorators.d.ts +8 -29
- package/dist/handler/handler-decorators.d.ts.map +1 -1
- package/dist/handler/handler-decorators.js +33 -210
- package/dist/handler/handler-decorators.js.map +1 -1
- package/dist/handler/spine-metadata-inventory.d.ts +99 -0
- package/dist/handler/spine-metadata-inventory.d.ts.map +1 -0
- package/dist/handler/spine-metadata-inventory.js +162 -0
- package/dist/handler/spine-metadata-inventory.js.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/repository/repository.d.ts +44 -1
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +368 -88
- package/dist/repository/repository.js.map +1 -1
- package/dist/server/managed-server-application.d.ts +12 -11
- package/dist/server/managed-server-application.d.ts.map +1 -1
- package/dist/server/managed-server-application.js +41 -25
- package/dist/server/managed-server-application.js.map +1 -1
- package/dist/server/node-coordinator.d.ts +18 -5
- package/dist/server/node-coordinator.d.ts.map +1 -1
- package/dist/server/node-coordinator.js +554 -84
- package/dist/server/node-coordinator.js.map +1 -1
- package/dist/server/reserved-spine-rpc-paths.json +1 -0
- package/dist/server/server-environment.d.ts +17 -0
- package/dist/server/server-environment.d.ts.map +1 -1
- package/dist/server/server-environment.js +77 -16
- package/dist/server/server-environment.js.map +1 -1
- package/dist/server/server.d.ts +45 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +111 -3
- package/dist/server/server.js.map +1 -1
- package/dist/services/app-query-execution.d.ts +53 -0
- package/dist/services/app-query-execution.d.ts.map +1 -0
- package/dist/services/app-query-execution.js +408 -0
- package/dist/services/app-query-execution.js.map +1 -0
- package/dist/services/query-reader.d.ts +32 -7
- package/dist/services/query-reader.d.ts.map +1 -1
- package/dist/services/query-reader.js +22 -2
- package/dist/services/query-reader.js.map +1 -1
- package/dist/services/read-request-status.d.ts +65 -0
- package/dist/services/read-request-status.d.ts.map +1 -0
- package/dist/services/read-request-status.js +151 -0
- package/dist/services/read-request-status.js.map +1 -0
- package/dist/services/spine-services.d.ts +36 -7
- package/dist/services/spine-services.d.ts.map +1 -1
- package/dist/services/spine-services.js +900 -168
- package/dist/services/spine-services.js.map +1 -1
- package/dist/services/trusted-reader-ingress.d.ts +92 -0
- package/dist/services/trusted-reader-ingress.d.ts.map +1 -0
- package/dist/services/trusted-reader-ingress.js +89 -0
- package/dist/services/trusted-reader-ingress.js.map +1 -0
- package/dist/spi/handler-registry.d.ts +2 -0
- package/dist/spi/handler-registry.d.ts.map +1 -1
- package/dist/spi/handler-registry.js +1 -1
- package/dist/spi/handler-registry.js.map +1 -1
- package/dist/stand/read-side-filter-engine.d.ts +46 -0
- package/dist/stand/read-side-filter-engine.d.ts.map +1 -0
- package/dist/stand/read-side-filter-engine.js +356 -0
- package/dist/stand/read-side-filter-engine.js.map +1 -0
- package/dist/stand/read-side-filter.d.ts +247 -0
- package/dist/stand/read-side-filter.d.ts.map +1 -0
- package/dist/stand/read-side-filter.js +39 -0
- package/dist/stand/read-side-filter.js.map +1 -0
- package/dist/stand/read-side-message.d.ts +66 -0
- package/dist/stand/read-side-message.d.ts.map +1 -0
- package/dist/stand/read-side-message.js +167 -0
- package/dist/stand/read-side-message.js.map +1 -0
- package/dist/stand/stand-direct-delivery.d.ts +161 -0
- package/dist/stand/stand-direct-delivery.d.ts.map +1 -0
- package/dist/stand/stand-direct-delivery.js +210 -0
- package/dist/stand/stand-direct-delivery.js.map +1 -0
- package/dist/stand/stand.d.ts +80 -42
- package/dist/stand/stand.d.ts.map +1 -1
- package/dist/stand/stand.js +410 -54
- package/dist/stand/stand.js.map +1 -1
- package/dist/stand/subscription-observer.d.ts.map +1 -1
- package/dist/stand/subscription-observer.js +103 -0
- package/dist/stand/subscription-observer.js.map +1 -1
- package/dist/stand/subscription-read-filters.d.ts +40 -0
- package/dist/stand/subscription-read-filters.d.ts.map +1 -0
- package/dist/stand/subscription-read-filters.js +91 -0
- package/dist/stand/subscription-read-filters.js.map +1 -0
- package/dist/stand/subscription-reader-binding.d.ts +20 -0
- package/dist/stand/subscription-reader-binding.d.ts.map +1 -0
- package/dist/stand/subscription-reader-binding.js +56 -0
- package/dist/stand/subscription-reader-binding.js.map +1 -0
- package/dist/stand/subscription-records.d.ts +30 -3
- package/dist/stand/subscription-records.d.ts.map +1 -1
- package/dist/stand/subscription-records.js +61 -16
- package/dist/stand/subscription-records.js.map +1 -1
- package/dist/stand/subscription-registry.d.ts +49 -14
- package/dist/stand/subscription-registry.d.ts.map +1 -1
- package/dist/stand/subscription-registry.js +150 -31
- package/dist/stand/subscription-registry.js.map +1 -1
- package/dist/stand/subscription-runtime.d.ts +7 -2
- package/dist/stand/subscription-runtime.d.ts.map +1 -1
- package/dist/stand/subscription-runtime.js +131 -25
- package/dist/stand/subscription-runtime.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -14
|
@@ -11,10 +11,6 @@
|
|
|
11
11
|
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
12
|
* the License.
|
|
13
13
|
*/
|
|
14
|
-
import { constants as fsConstants } from "node:fs";
|
|
15
|
-
import { access, realpath } from "node:fs/promises";
|
|
16
|
-
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
17
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
18
14
|
import { clone, create, getOption, hasOption } from "@bufbuild/protobuf";
|
|
19
15
|
import { freezeRegistry, isAiModel, registryOptions } from "@spine-event-engine/ai/spi/runtime";
|
|
20
16
|
import { TypeUrls } from "@spine-event-engine/core";
|
|
@@ -31,15 +27,16 @@ import { TenantAdmissions } from "./tenant-unknown-error.js";
|
|
|
31
27
|
import { AgentExecutionCapacity, } from "../agent/agent-execution-capacity.js";
|
|
32
28
|
import { AgentAcceptanceReceipts, agentAcceptanceReceiptGroup, agentAcceptanceReceiptSpec, } from "../agent/agent-acceptance-receipts.js";
|
|
33
29
|
import { Repository, repositoryAccess, } from "../repository/repository.js";
|
|
34
|
-
import {
|
|
30
|
+
import { SpineMetadataInventory } from "../handler/spine-metadata-inventory.js";
|
|
35
31
|
import { HandlerRegistryIngestor, } from "../handler/generated-handler-registry.js";
|
|
36
32
|
import { AbstractAssignee, AbstractCommander, AbstractEventReactor, AbstractEventSubscriber, } from "../handler/standalone.js";
|
|
37
33
|
import { HandlerMetadataRegistry, } from "../handler/handler-metadata.js";
|
|
38
34
|
import { SignalMetadata } from "../runtime/signal-metadata.js";
|
|
39
35
|
import { runtimeAccess } from "../runtime/runtime.js";
|
|
40
36
|
import { Stand, standAccess } from "../stand/stand.js";
|
|
37
|
+
import { ReadSideFilter } from "../stand/read-side-filter.js";
|
|
41
38
|
import { SubscriptionRuntime, subscriptionRuntimeAccess } from "../stand/subscription-runtime.js";
|
|
42
|
-
import { StorageSubscriptionRegistry,
|
|
39
|
+
import { StorageSubscriptionRegistry, subscriptionRecordGroup, } from "../stand/subscription-registry.js";
|
|
43
40
|
import { IntegrationBroker } from "../integration/integration-broker.js";
|
|
44
41
|
import { ServerEnvironment, serverEnvironmentAccess } from "../server/server-environment.js";
|
|
45
42
|
import { SignalPublisher } from "../runtime/signal-publisher.js";
|
|
@@ -100,11 +97,8 @@ export class DuplicateEntityStateException extends Error {
|
|
|
100
97
|
const frameworkConstructionToken = Object.freeze({
|
|
101
98
|
frameworkConstructionToken: true,
|
|
102
99
|
});
|
|
103
|
-
const generatedRegistryFile = "generated/handler/generated-handler-registry.js";
|
|
104
100
|
const errorDetailLimit = 500;
|
|
105
|
-
const moduleSchemeRe = /^[A-Za-z][A-Za-z\d+.-]*:/;
|
|
106
101
|
const internalStoragePrefix = "__spine/";
|
|
107
|
-
const generatedRegistryLoadAttempts = new Map();
|
|
108
102
|
const eventSubscribers = new WeakMap();
|
|
109
103
|
const contextSystemPairings = new WeakMap();
|
|
110
104
|
const contextTenantIndexes = new WeakMap();
|
|
@@ -265,11 +259,12 @@ export class BoundedContext {
|
|
|
265
259
|
* @returns Shared preparation completion.
|
|
266
260
|
*/
|
|
267
261
|
#prepareShared(mode) {
|
|
268
|
-
|
|
262
|
+
const registry = this.#subscriptionRuntime.registry();
|
|
263
|
+
if (!(registry instanceof StorageSubscriptionRegistry))
|
|
269
264
|
return Promise.resolve();
|
|
270
265
|
if (this.#sharedPreparation !== undefined)
|
|
271
266
|
return this.#sharedPreparation;
|
|
272
|
-
const attempt = this.#trackPreparation(() =>
|
|
267
|
+
const attempt = this.#trackPreparation(() => registry.prepare(mode));
|
|
273
268
|
this.#sharedPreparation = attempt;
|
|
274
269
|
void attempt.catch(() => {
|
|
275
270
|
if (this.#sharedPreparation === attempt)
|
|
@@ -527,6 +522,10 @@ export class BoundedContext {
|
|
|
527
522
|
});
|
|
528
523
|
contextDeliveryDescriptors.set(this, ContextParts.createDeliveryDescriptor(this.#entityInbox, this.#projectionInbox));
|
|
529
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Prepares repository registrations, reserves their state types, and commits their Stand and
|
|
527
|
+
* inbox targets; rolls back uncommitted storage preparation on failure.
|
|
528
|
+
*/
|
|
530
529
|
#registerRepositories(repositories) {
|
|
531
530
|
const preparedRepositories = this.#prepareRepositories(repositories);
|
|
532
531
|
try {
|
|
@@ -566,6 +565,10 @@ export class BoundedContext {
|
|
|
566
565
|
throw new DuplicateEntityStateException(stateType, prior.name.value, this.name.value);
|
|
567
566
|
}
|
|
568
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Builds prepared repository registrations using this context’s storage and delivery services,
|
|
570
|
+
* cleaning earlier preparations if a later one fails.
|
|
571
|
+
*/
|
|
569
572
|
#prepareRepositories(repositories) {
|
|
570
573
|
const registration = this.#repositoryRegistration();
|
|
571
574
|
const preparedRepositories = [];
|
|
@@ -641,6 +644,10 @@ export class BoundedContext {
|
|
|
641
644
|
...(tenantId === undefined ? {} : { tenantId }),
|
|
642
645
|
});
|
|
643
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* Closes storage for repositories that were prepared but not committed, then rethrows the
|
|
649
|
+
* registration error with cleanup failures aggregated.
|
|
650
|
+
*/
|
|
644
651
|
#failRegistration(error, preparedRepositories) {
|
|
645
652
|
const uncommitted = preparedRepositories.filter(({ repository }) => !this.#repositoryViews.has(repository));
|
|
646
653
|
const closeErrors = ContextParts.closePreparedRepositories(uncommitted);
|
|
@@ -801,6 +808,10 @@ export class BoundedContext {
|
|
|
801
808
|
async catchUpReadSide(options = {}) {
|
|
802
809
|
return eventBusAccess.runExclusive(this.#eventBus, () => this.#catchUpReadSideOnce(options));
|
|
803
810
|
}
|
|
811
|
+
/**
|
|
812
|
+
* Clears registered Projection state for the selected tenant slice, reads stored events,
|
|
813
|
+
* validates each event’s tenant, and dispatches replay sequentially.
|
|
814
|
+
*/
|
|
804
815
|
async #catchUpReadSideOnce(options) {
|
|
805
816
|
const storageContext = ContextParts.catchUpStorageContext(this.#snapshot.spec, options);
|
|
806
817
|
const tenantOptions = ContextParts.catchUpStandOptions(storageContext);
|
|
@@ -1013,6 +1024,9 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1013
1024
|
return Promise.reject(new TypeError("Service registry requires a built context."));
|
|
1014
1025
|
return phase.trackReplay(onOperation);
|
|
1015
1026
|
},
|
|
1027
|
+
/**
|
|
1028
|
+
* Registers replay work with the context close lifecycle so shutdown waits for it.
|
|
1029
|
+
*/
|
|
1016
1030
|
trackReplay(context, onReplay) {
|
|
1017
1031
|
const phase = contextClosePhases.get(context);
|
|
1018
1032
|
if (phase === undefined)
|
|
@@ -1035,18 +1049,27 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1035
1049
|
? issued.repository
|
|
1036
1050
|
: undefined;
|
|
1037
1051
|
},
|
|
1052
|
+
/**
|
|
1053
|
+
* Stops new work at this Bounded Context and begins shutdown of its runtime facilities.
|
|
1054
|
+
*/
|
|
1038
1055
|
beginClose(context) {
|
|
1039
1056
|
const phase = contextClosePhases.get(context);
|
|
1040
1057
|
if (phase === undefined)
|
|
1041
1058
|
throw new TypeError("Close phase requires a built BoundedContext.");
|
|
1042
1059
|
phase.begin();
|
|
1043
1060
|
},
|
|
1061
|
+
/**
|
|
1062
|
+
* Waits for accepted runtime work and replay operations to finish.
|
|
1063
|
+
*/
|
|
1044
1064
|
drainWork(context) {
|
|
1045
1065
|
const phase = contextClosePhases.get(context);
|
|
1046
1066
|
if (phase === undefined)
|
|
1047
1067
|
return Promise.reject(new TypeError("Drain requires a built BoundedContext."));
|
|
1048
1068
|
return phase.drain();
|
|
1049
1069
|
},
|
|
1070
|
+
/**
|
|
1071
|
+
* Installs the context logger on both EventBuses, the signal publisher, and subscription runtime.
|
|
1072
|
+
*/
|
|
1050
1073
|
installLogger(context, logger) {
|
|
1051
1074
|
if (!contextStorageFactories.has(context)) {
|
|
1052
1075
|
throw new TypeError("Context logger requires a built BoundedContext instance.");
|
|
@@ -1068,6 +1091,9 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1068
1091
|
}
|
|
1069
1092
|
subscriptionRuntimeAccess.installLogger(runtime, logger, context.name.value);
|
|
1070
1093
|
},
|
|
1094
|
+
/**
|
|
1095
|
+
* Returns the diagnostic logger installed on this Bounded Context.
|
|
1096
|
+
*/
|
|
1071
1097
|
loggerFor(context) {
|
|
1072
1098
|
const logger = contextLoggers.get(context);
|
|
1073
1099
|
if (logger === undefined) {
|
|
@@ -1075,11 +1101,17 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1075
1101
|
}
|
|
1076
1102
|
return logger;
|
|
1077
1103
|
},
|
|
1104
|
+
/**
|
|
1105
|
+
* Checks whether a value is a BoundedContextBuilder created by this module.
|
|
1106
|
+
*/
|
|
1078
1107
|
isBuilder(value) {
|
|
1079
1108
|
return (typeof value === "object" &&
|
|
1080
1109
|
value !== null &&
|
|
1081
1110
|
builderBuilds.has(value));
|
|
1082
1111
|
},
|
|
1112
|
+
/**
|
|
1113
|
+
* Builds the supplied context builder and completes its configured initialization.
|
|
1114
|
+
*/
|
|
1083
1115
|
build(builder) {
|
|
1084
1116
|
const build = builderBuilds.get(builder);
|
|
1085
1117
|
if (build === undefined) {
|
|
@@ -1087,6 +1119,9 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1087
1119
|
}
|
|
1088
1120
|
return build();
|
|
1089
1121
|
},
|
|
1122
|
+
/**
|
|
1123
|
+
* Attaches a subscriber to the context domain EventBus for the requested event type.
|
|
1124
|
+
*/
|
|
1090
1125
|
subscribeToEvent(context, typeUrl, subscriber) {
|
|
1091
1126
|
const subscribe = eventSubscribers.get(context);
|
|
1092
1127
|
if (subscribe === undefined) {
|
|
@@ -1094,6 +1129,9 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1094
1129
|
}
|
|
1095
1130
|
return subscribe(typeUrl, subscriber);
|
|
1096
1131
|
},
|
|
1132
|
+
/**
|
|
1133
|
+
* Posts a framework System Event through the context System EventBus.
|
|
1134
|
+
*/
|
|
1097
1135
|
postSystemEvent(context, event) {
|
|
1098
1136
|
const post = systemEventPosters.get(context);
|
|
1099
1137
|
if (post === undefined) {
|
|
@@ -1101,12 +1139,18 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1101
1139
|
}
|
|
1102
1140
|
return post(event);
|
|
1103
1141
|
},
|
|
1142
|
+
/**
|
|
1143
|
+
* Posts an external domain Event through the context EventBus.
|
|
1144
|
+
*/
|
|
1104
1145
|
postExternalEvent(context, event) {
|
|
1105
1146
|
const imported = clone(EventSchema, event);
|
|
1106
1147
|
imported.context = clone(EventContextSchema, imported.context ?? create(EventContextSchema));
|
|
1107
1148
|
imported.context.external = true;
|
|
1108
1149
|
return context.eventBus().post(imported);
|
|
1109
1150
|
},
|
|
1151
|
+
/**
|
|
1152
|
+
* Subscribes to events produced by this context and forwards matching signals to the supplied observer.
|
|
1153
|
+
*/
|
|
1110
1154
|
observeProducedSignals(context, observer) {
|
|
1111
1155
|
const publisher = contextSignalPublishers.get(context);
|
|
1112
1156
|
if (publisher === undefined) {
|
|
@@ -1114,12 +1158,21 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1114
1158
|
}
|
|
1115
1159
|
return publisher.observe(observer);
|
|
1116
1160
|
},
|
|
1161
|
+
/**
|
|
1162
|
+
* Returns the domain/System specification pairing captured when the context was built.
|
|
1163
|
+
*/
|
|
1117
1164
|
systemPairing(context) {
|
|
1118
1165
|
return ContextParts.cloneSystemPairing(ContextParts.requireSystemPairing(context));
|
|
1119
1166
|
},
|
|
1167
|
+
/**
|
|
1168
|
+
* Returns the live tenant membership index configured for this context.
|
|
1169
|
+
*/
|
|
1120
1170
|
tenantIndex(context) {
|
|
1121
1171
|
return ContextParts.requireTenantIndex(context);
|
|
1122
1172
|
},
|
|
1173
|
+
/**
|
|
1174
|
+
* Returns the storage factory captured for repository and Stand operations in this context.
|
|
1175
|
+
*/
|
|
1123
1176
|
storageFactory(context) {
|
|
1124
1177
|
const storageFactory = contextStorageFactories.get(context);
|
|
1125
1178
|
if (storageFactory === undefined) {
|
|
@@ -1127,6 +1180,9 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1127
1180
|
}
|
|
1128
1181
|
return storageFactory;
|
|
1129
1182
|
},
|
|
1183
|
+
/**
|
|
1184
|
+
* Returns the persistent or in-memory registry used to store Stand subscription definitions.
|
|
1185
|
+
*/
|
|
1130
1186
|
subscriptionRegistry(context) {
|
|
1131
1187
|
const runtime = contextSubscriptionRuntimes.get(context);
|
|
1132
1188
|
if (runtime === undefined) {
|
|
@@ -1134,13 +1190,24 @@ export const boundedContextAccess = Object.freeze({
|
|
|
1134
1190
|
}
|
|
1135
1191
|
return runtime.registry();
|
|
1136
1192
|
},
|
|
1137
|
-
|
|
1193
|
+
/**
|
|
1194
|
+
* Consumes a registered Stand subscription update and returns its managed delivery handle.
|
|
1195
|
+
*/
|
|
1196
|
+
consumeSubscription(context, id, onUpdate, onInvalidated, expected) {
|
|
1138
1197
|
const runtime = contextSubscriptionRuntimes.get(context);
|
|
1139
1198
|
if (runtime === undefined) {
|
|
1140
1199
|
throw new TypeError("Subscription consumption requires a built BoundedContext instance.");
|
|
1141
1200
|
}
|
|
1142
|
-
return runtime.consume(id,
|
|
1201
|
+
return runtime.consume(id, (update) => {
|
|
1202
|
+
onUpdate({
|
|
1203
|
+
update,
|
|
1204
|
+
filter: (facts) => standAccess.filterSubscription(context.stand(), update, facts),
|
|
1205
|
+
});
|
|
1206
|
+
}, onInvalidated, expected);
|
|
1143
1207
|
},
|
|
1208
|
+
/**
|
|
1209
|
+
* Returns the context delivery descriptor used to route Entity and Projection inbox work.
|
|
1210
|
+
*/
|
|
1144
1211
|
delivery(context) {
|
|
1145
1212
|
const descriptor = contextDeliveryDescriptors.get(context);
|
|
1146
1213
|
if (descriptor === undefined) {
|
|
@@ -1161,12 +1228,12 @@ export class BoundedContextBuilder {
|
|
|
1161
1228
|
#eventReceivers = [];
|
|
1162
1229
|
#repositories = new Set();
|
|
1163
1230
|
#entityTypes = new Set();
|
|
1231
|
+
#readFilters = new Set();
|
|
1164
1232
|
#generatedRepositoryOptions = new Map();
|
|
1165
1233
|
#aiRegistry;
|
|
1166
1234
|
#tenantIndex;
|
|
1167
1235
|
#subscriptionRegistry;
|
|
1168
1236
|
#persistSystemEvents = false;
|
|
1169
|
-
#generatedRegistryRoot;
|
|
1170
1237
|
/**
|
|
1171
1238
|
* Registers the framework-only construction hook for this module.
|
|
1172
1239
|
*/
|
|
@@ -1217,6 +1284,15 @@ export class BoundedContextBuilder {
|
|
|
1217
1284
|
isMultitenant() {
|
|
1218
1285
|
return this.#specSnapshot.multitenant;
|
|
1219
1286
|
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Adds an outward read policy to this Bounded Context.
|
|
1289
|
+
* @param filter Policy applied before Server-level outward policies.
|
|
1290
|
+
* @returns This builder for further configuration.
|
|
1291
|
+
*/
|
|
1292
|
+
addReadSideFilter(filter) {
|
|
1293
|
+
this.#readFilters.add(filter);
|
|
1294
|
+
return this;
|
|
1295
|
+
}
|
|
1220
1296
|
/**
|
|
1221
1297
|
* Adds an explicitly assembled repository or an Entity class.
|
|
1222
1298
|
*
|
|
@@ -1365,16 +1441,6 @@ export class BoundedContextBuilder {
|
|
|
1365
1441
|
this.#subscriptionRegistry = registry;
|
|
1366
1442
|
return this;
|
|
1367
1443
|
}
|
|
1368
|
-
/**
|
|
1369
|
-
* Sets a trusted compiled application root for generated handler metadata.
|
|
1370
|
-
*
|
|
1371
|
-
* @param root Names the compiled package or application root.
|
|
1372
|
-
* @returns Returns this builder for further configuration.
|
|
1373
|
-
*/
|
|
1374
|
-
withGeneratedRegistryRoot(root) {
|
|
1375
|
-
this.#generatedRegistryRoot = root;
|
|
1376
|
-
return this;
|
|
1377
|
-
}
|
|
1378
1444
|
/**
|
|
1379
1445
|
* Builds a context after loading generated handlers and preparing runtime resources.
|
|
1380
1446
|
*
|
|
@@ -1384,6 +1450,10 @@ export class BoundedContextBuilder {
|
|
|
1384
1450
|
build(options = {}) {
|
|
1385
1451
|
return this.#buildAsyncWith(options);
|
|
1386
1452
|
}
|
|
1453
|
+
/**
|
|
1454
|
+
* Loads generated handlers and repositories, assembles context facilities, and completes
|
|
1455
|
+
* requested initialization before publishing the context.
|
|
1456
|
+
*/
|
|
1387
1457
|
async #buildAsyncWith(options = {}) {
|
|
1388
1458
|
const environment = ServerEnvironment.instance();
|
|
1389
1459
|
const finishBuild = serverEnvironmentAccess.beginContextBuild(environment);
|
|
@@ -1415,7 +1485,7 @@ export class BoundedContextBuilder {
|
|
|
1415
1485
|
* @returns The integrated context.
|
|
1416
1486
|
*/
|
|
1417
1487
|
async #buildAsyncReady(options, environment) {
|
|
1418
|
-
const generated =
|
|
1488
|
+
const generated = this.#loadGeneratedArtifacts([...this.#entityTypes]);
|
|
1419
1489
|
serverEnvironmentAccess.requireAvailable(environment);
|
|
1420
1490
|
const repositories = [...this.#repositories, ...generated.repositories];
|
|
1421
1491
|
const context = await this.#buildWithResources(repositories, environment.storageFactory, generated.standalone, this.#aiRegistry ?? environment.ai);
|
|
@@ -1488,6 +1558,10 @@ export class BoundedContextBuilder {
|
|
|
1488
1558
|
return await this.#failBuild(resources, error);
|
|
1489
1559
|
}
|
|
1490
1560
|
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Assembles dispatchers, buses, Stand, subscription runtime, and integration hooks, registering
|
|
1563
|
+
* the completed context with its environment.
|
|
1564
|
+
*/
|
|
1491
1565
|
#assembleContext(repositories, storageFactory, standalone, resources, ai) {
|
|
1492
1566
|
ContextParts.preflightRepositories(repositories);
|
|
1493
1567
|
this.#preflightAgents(repositories, storageFactory, ai);
|
|
@@ -1540,6 +1614,9 @@ export class BoundedContextBuilder {
|
|
|
1540
1614
|
throw new TypeError("Agent repository capabilities must be factory-created models.");
|
|
1541
1615
|
}
|
|
1542
1616
|
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Collects repository and configured event recipients into domain and System dispatcher groups.
|
|
1619
|
+
*/
|
|
1543
1620
|
#buildDispatchers(repositories) {
|
|
1544
1621
|
const event = [
|
|
1545
1622
|
...ContextParts.repositoryEventDispatchers(repositories),
|
|
@@ -1553,6 +1630,9 @@ export class BoundedContextBuilder {
|
|
|
1553
1630
|
],
|
|
1554
1631
|
};
|
|
1555
1632
|
}
|
|
1633
|
+
/**
|
|
1634
|
+
* Creates command, domain Event, and System Event buses plus their stores and signal publisher.
|
|
1635
|
+
*/
|
|
1556
1636
|
#buildBuses(repositories, storageFactory, dispatchers, resources) {
|
|
1557
1637
|
const commandBus = new CommandBus([
|
|
1558
1638
|
...this.#commandDispatchers,
|
|
@@ -1577,6 +1657,9 @@ export class BoundedContextBuilder {
|
|
|
1577
1657
|
systemSpec: system.spec,
|
|
1578
1658
|
};
|
|
1579
1659
|
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Creates the System context store, EventBus, and Stand, then registers System event dispatchers.
|
|
1662
|
+
*/
|
|
1580
1663
|
#buildSystemBuses(storageFactory, dispatchers, resources) {
|
|
1581
1664
|
const systemSpec = ContextParts.createSystemSpec(this.#specSnapshot, this.#persistSystemEvents);
|
|
1582
1665
|
const systemEventStore = systemSpec.storesEvents
|
|
@@ -1600,6 +1683,10 @@ export class BoundedContextBuilder {
|
|
|
1600
1683
|
spec: systemSpec,
|
|
1601
1684
|
};
|
|
1602
1685
|
}
|
|
1686
|
+
/**
|
|
1687
|
+
* Matches generated standalone handlers to configured instances and registers their dispatchers
|
|
1688
|
+
* on the appropriate buses.
|
|
1689
|
+
*/
|
|
1603
1690
|
#installStandalone(standalone, buses) {
|
|
1604
1691
|
ContextParts.assertUniqueCommandReceptors(standalone);
|
|
1605
1692
|
const runtime = standalone.length === 0
|
|
@@ -1616,11 +1703,14 @@ export class BoundedContextBuilder {
|
|
|
1616
1703
|
buses.systemEventBus.register(state);
|
|
1617
1704
|
return event;
|
|
1618
1705
|
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Creates the context Stand, subscription registry, and runtime that observes domain and System events.
|
|
1708
|
+
*/
|
|
1619
1709
|
#buildRuntime(storageFactory, buses, resources) {
|
|
1620
1710
|
const stand = this.#buildStand(storageFactory);
|
|
1621
1711
|
resources.stand = stand;
|
|
1622
1712
|
const registry = resources.registry ??
|
|
1623
|
-
new StorageSubscriptionRegistry(ContextParts.createSubscriptionStorageContext(this.#specSnapshot), storageFactory);
|
|
1713
|
+
new StorageSubscriptionRegistry(ContextParts.createSubscriptionStorageContext(this.#specSnapshot), storageFactory, subscriptionRecordGroup(this.#specSnapshot.name.value));
|
|
1624
1714
|
resources.registry = registry;
|
|
1625
1715
|
const runtime = new SubscriptionRuntime(stand, buses.systemStand, buses.eventBus, buses.systemEventBus, registry);
|
|
1626
1716
|
resources.runtime = runtime;
|
|
@@ -1638,12 +1728,21 @@ export class BoundedContextBuilder {
|
|
|
1638
1728
|
context: ContextParts.createStorageMode(this.#specSnapshot),
|
|
1639
1729
|
storageFactory,
|
|
1640
1730
|
});
|
|
1731
|
+
if (this.#readFilters.size > 0)
|
|
1732
|
+
standAccess.installReadFilters(stand, [...this.#readFilters]);
|
|
1641
1733
|
standAccess.setAdmission(stand, (tenantId) => TenantAdmissions.require(tenantIndex, this.#specSnapshot.name.value, this.#specSnapshot.multitenant, tenantId));
|
|
1642
1734
|
return stand;
|
|
1643
1735
|
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Constructs the immutable BoundedContext using assembled buses, runtime parts, environment
|
|
1738
|
+
* delivery strategy, and tenant index.
|
|
1739
|
+
*/
|
|
1644
1740
|
#createContext(repositories, storageFactory, buses, running, ai) {
|
|
1645
1741
|
return ContextParts.createBoundedContext(this.#specSnapshot, storageFactory, repositories, ServerEnvironment.instance().delivery.strategy, buses, running, ai, this.#tenantIndex ?? ServerEnvironment.instance().tenantIndex);
|
|
1646
1742
|
}
|
|
1743
|
+
/**
|
|
1744
|
+
* Closes partial context resources after assembly fails and aggregates cleanup errors with the original failure.
|
|
1745
|
+
*/
|
|
1647
1746
|
async #failBuild(resources, error) {
|
|
1648
1747
|
const cleanupErrors = [];
|
|
1649
1748
|
if (resources.context !== undefined) {
|
|
@@ -1675,28 +1774,27 @@ export class BoundedContextBuilder {
|
|
|
1675
1774
|
}
|
|
1676
1775
|
throw error;
|
|
1677
1776
|
}
|
|
1678
|
-
|
|
1777
|
+
/**
|
|
1778
|
+
* Selects generated metadata for configured Entity and standalone handler types and creates
|
|
1779
|
+
* repository views and handler groups.
|
|
1780
|
+
*/
|
|
1781
|
+
#loadGeneratedArtifacts(entityTypes) {
|
|
1679
1782
|
if (entityTypes.length === 0 && this.#standaloneInstances().length === 0) {
|
|
1680
1783
|
return Object.freeze({ repositories: Object.freeze([]), standalone: Object.freeze([]) });
|
|
1681
1784
|
}
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
const registries = (
|
|
1687
|
-
.load({
|
|
1688
|
-
modules: [registryModule],
|
|
1689
|
-
...ContextParts.generatedRegistryCacheBust(registryKey),
|
|
1690
|
-
})
|
|
1691
|
-
.catch((error) => {
|
|
1692
|
-
ContextParts.recordGeneratedRegistryFailure(registryKey);
|
|
1693
|
-
throw error;
|
|
1694
|
-
}));
|
|
1785
|
+
const selected = [
|
|
1786
|
+
...entityTypes,
|
|
1787
|
+
...this.#standaloneInstances().map((instance) => instance.constructor),
|
|
1788
|
+
];
|
|
1789
|
+
const registries = [SpineMetadataInventory.select(selected)];
|
|
1695
1790
|
const metadata = ContextParts.ingestGeneratedRegistries(registries);
|
|
1696
1791
|
const repositories = Object.freeze(entityTypes.map((entityType) => ContextParts.createGeneratedRepository(entityType, registries, metadata, this.#generatedRepositoryOptions.get(entityType))));
|
|
1697
1792
|
const standalone = Object.freeze(registries.flatMap((registry) => registry.receivers.filter((receiver) => receiver.receiverKind === "standalone")));
|
|
1698
1793
|
return Object.freeze({ repositories, standalone });
|
|
1699
1794
|
}
|
|
1795
|
+
/**
|
|
1796
|
+
* Returns a frozen list of configured standalone assignee, commander, and event-receiver instances.
|
|
1797
|
+
*/
|
|
1700
1798
|
#standaloneInstances() {
|
|
1701
1799
|
return Object.freeze([...this.#assignees, ...this.#commanders, ...this.#eventReceivers]);
|
|
1702
1800
|
}
|
|
@@ -1945,7 +2043,7 @@ const ContextParts = Object.freeze({
|
|
|
1945
2043
|
* @returns Constructed bounded context.
|
|
1946
2044
|
*/
|
|
1947
2045
|
createBoundedContext(specSnapshot, storageFactory, repositories, deliveryStrategy, buses, running, ai, tenantIndex) {
|
|
1948
|
-
|
|
2046
|
+
const context = constructBoundedContext({
|
|
1949
2047
|
snapshot: ContextParts.snapshotFor(specSnapshot),
|
|
1950
2048
|
commandBus: buses.commandBus,
|
|
1951
2049
|
eventBus: buses.eventBus,
|
|
@@ -1962,6 +2060,8 @@ const ContextParts = Object.freeze({
|
|
|
1962
2060
|
...(ai === undefined ? {} : { ai }),
|
|
1963
2061
|
token: frameworkConstructionToken,
|
|
1964
2062
|
});
|
|
2063
|
+
standAccess.bindProducingContext(running.stand, context);
|
|
2064
|
+
return context;
|
|
1965
2065
|
},
|
|
1966
2066
|
/**
|
|
1967
2067
|
* Captures public context identity from the build specification.
|
|
@@ -2318,151 +2418,6 @@ const ContextParts = Object.freeze({
|
|
|
2318
2418
|
throw new TypeError(`${operation} requires a Repository instance. Use an entity class only with build().`);
|
|
2319
2419
|
}
|
|
2320
2420
|
},
|
|
2321
|
-
/**
|
|
2322
|
-
* Validates that a root exists when generated metadata must be loaded.
|
|
2323
|
-
*
|
|
2324
|
-
* @param root Configured registry location.
|
|
2325
|
-
* @returns Configured root; throws when absent.
|
|
2326
|
-
*/
|
|
2327
|
-
requireGeneratedRegistryRoot(root) {
|
|
2328
|
-
if (root !== undefined) {
|
|
2329
|
-
return root;
|
|
2330
|
-
}
|
|
2331
|
-
throw new Error("BoundedContextBuilder.build() requires withGeneratedRegistryRoot(root) " +
|
|
2332
|
-
"when assembling entity classes from generated metadata.");
|
|
2333
|
-
},
|
|
2334
|
-
/**
|
|
2335
|
-
* Resolves the generated registry module and verifies it stays beneath the configured root.
|
|
2336
|
-
*
|
|
2337
|
-
* @param root Configured filesystem path or file URL.
|
|
2338
|
-
* @returns Registry module file URL.
|
|
2339
|
-
*/
|
|
2340
|
-
async trustedGeneratedRegistryModule(root) {
|
|
2341
|
-
const trustedRoot = await ContextParts.canonicalGeneratedRegistryRoot(root);
|
|
2342
|
-
const registryPath = resolve(trustedRoot, generatedRegistryFile);
|
|
2343
|
-
const canonicalRegistryPath = await ContextParts.canonicalReadableRegistryPath(registryPath);
|
|
2344
|
-
if (ContextParts.resolvesOutsideRoot(trustedRoot, canonicalRegistryPath)) {
|
|
2345
|
-
throw new Error(`Generated handler registry module "${canonicalRegistryPath}" must resolve within ` +
|
|
2346
|
-
`the configured generated registry root "${trustedRoot}".`);
|
|
2347
|
-
}
|
|
2348
|
-
return pathToFileURL(canonicalRegistryPath);
|
|
2349
|
-
},
|
|
2350
|
-
/**
|
|
2351
|
-
* Resolves a generated registry root to its canonical filesystem path.
|
|
2352
|
-
*
|
|
2353
|
-
* @param root Configured path or file URL.
|
|
2354
|
-
* @returns Canonical directory path.
|
|
2355
|
-
*/
|
|
2356
|
-
async canonicalGeneratedRegistryRoot(root) {
|
|
2357
|
-
const rootPath = ContextParts.generatedRegistryRootPath(root);
|
|
2358
|
-
try {
|
|
2359
|
-
return await realpath(rootPath);
|
|
2360
|
-
}
|
|
2361
|
-
catch (error) {
|
|
2362
|
-
throw new Error(`Generated registry root "${rootPath}" must be an existing readable directory.`, { cause: error });
|
|
2363
|
-
}
|
|
2364
|
-
},
|
|
2365
|
-
/**
|
|
2366
|
-
* Converts a registry root path or file URL to an absolute filesystem path.
|
|
2367
|
-
*
|
|
2368
|
-
* @param root Configured path or file URL.
|
|
2369
|
-
* @returns Absolute filesystem path.
|
|
2370
|
-
*/
|
|
2371
|
-
generatedRegistryRootPath(root) {
|
|
2372
|
-
if (root instanceof URL) {
|
|
2373
|
-
return ContextParts.fileUrlPath(root, "Generated registry root");
|
|
2374
|
-
}
|
|
2375
|
-
if (ContextParts.isUrlLike(root)) {
|
|
2376
|
-
return ContextParts.fileUrlPath(ContextParts.parseRootUrl(root), "Generated registry root");
|
|
2377
|
-
}
|
|
2378
|
-
return resolve(root);
|
|
2379
|
-
},
|
|
2380
|
-
/**
|
|
2381
|
-
* Validates a file URL and converts it to an absolute filesystem path.
|
|
2382
|
-
*
|
|
2383
|
-
* @param url File URL to convert.
|
|
2384
|
-
* @param label Label used in validation errors.
|
|
2385
|
-
* @returns Filesystem path.
|
|
2386
|
-
*/
|
|
2387
|
-
fileUrlPath(url, label) {
|
|
2388
|
-
if (url.protocol !== "file:") {
|
|
2389
|
-
throw new Error(`${label} "${url.href}" must use the file: URL scheme.`);
|
|
2390
|
-
}
|
|
2391
|
-
if (url.search.length > 0 || url.hash.length > 0) {
|
|
2392
|
-
throw new Error(`${label} "${url.href}" must not include a query or hash.`);
|
|
2393
|
-
}
|
|
2394
|
-
return resolve(fileURLToPath(url));
|
|
2395
|
-
},
|
|
2396
|
-
/**
|
|
2397
|
-
* Parses a generated registry root string as a URL.
|
|
2398
|
-
*
|
|
2399
|
-
* @param root Registry root string.
|
|
2400
|
-
* @returns Parsed URL.
|
|
2401
|
-
*/
|
|
2402
|
-
parseRootUrl(root) {
|
|
2403
|
-
try {
|
|
2404
|
-
return new URL(root);
|
|
2405
|
-
}
|
|
2406
|
-
catch (error) {
|
|
2407
|
-
throw new Error(`Generated registry root "${root}" is not a valid URL.`, { cause: error });
|
|
2408
|
-
}
|
|
2409
|
-
},
|
|
2410
|
-
/**
|
|
2411
|
-
* Checks strings for a URL scheme, excluding Windows drive paths.
|
|
2412
|
-
*
|
|
2413
|
-
* @param value String to inspect.
|
|
2414
|
-
* @returns True when the string has a URL scheme.
|
|
2415
|
-
*/
|
|
2416
|
-
isUrlLike(value) {
|
|
2417
|
-
return moduleSchemeRe.test(value) && !/^[A-Za-z]:[\\/]/.test(value);
|
|
2418
|
-
},
|
|
2419
|
-
/**
|
|
2420
|
-
* Verifies registry-module readability and resolves its canonical path.
|
|
2421
|
-
*
|
|
2422
|
-
* @param registryPath Registry module filesystem path.
|
|
2423
|
-
* @returns Canonical readable path.
|
|
2424
|
-
*/
|
|
2425
|
-
async canonicalReadableRegistryPath(registryPath) {
|
|
2426
|
-
try {
|
|
2427
|
-
await access(registryPath, fsConstants.R_OK);
|
|
2428
|
-
return await realpath(registryPath);
|
|
2429
|
-
}
|
|
2430
|
-
catch (error) {
|
|
2431
|
-
throw new Error(`Generated handler registry module "${registryPath}" must exist and be readable.`, { cause: error });
|
|
2432
|
-
}
|
|
2433
|
-
},
|
|
2434
|
-
/**
|
|
2435
|
-
* Checks whether a canonical path escapes a canonical root.
|
|
2436
|
-
*
|
|
2437
|
-
* @param canonicalRoot Root directory.
|
|
2438
|
-
* @param canonicalPath Candidate path.
|
|
2439
|
-
* @returns True when the candidate escapes the root.
|
|
2440
|
-
*/
|
|
2441
|
-
resolvesOutsideRoot(canonicalRoot, canonicalPath) {
|
|
2442
|
-
const relativePath = relative(canonicalRoot, canonicalPath);
|
|
2443
|
-
return (relativePath.startsWith("..") ||
|
|
2444
|
-
relativePath === ".." ||
|
|
2445
|
-
relativePath.split(sep).includes("..") ||
|
|
2446
|
-
isAbsolute(relativePath));
|
|
2447
|
-
},
|
|
2448
|
-
/**
|
|
2449
|
-
* Creates a cache-bust query after a prior registry load failure.
|
|
2450
|
-
*
|
|
2451
|
-
* @param registryKey Canonical registry identifier.
|
|
2452
|
-
* @returns Retry query, or an empty object on the first attempt.
|
|
2453
|
-
*/
|
|
2454
|
-
generatedRegistryCacheBust(registryKey) {
|
|
2455
|
-
const attempt = generatedRegistryLoadAttempts.get(registryKey) ?? 0;
|
|
2456
|
-
return attempt === 0 ? {} : { cacheBust: `retry-${attempt.toString()}` };
|
|
2457
|
-
},
|
|
2458
|
-
/**
|
|
2459
|
-
* Records another failed load for a registry.
|
|
2460
|
-
*
|
|
2461
|
-
* @param registryKey Canonical registry identifier.
|
|
2462
|
-
*/
|
|
2463
|
-
recordGeneratedRegistryFailure(registryKey) {
|
|
2464
|
-
generatedRegistryLoadAttempts.set(registryKey, (generatedRegistryLoadAttempts.get(registryKey) ?? 0) + 1);
|
|
2465
|
-
},
|
|
2466
2421
|
/**
|
|
2467
2422
|
* Loads generated handler registries into a metadata registry.
|
|
2468
2423
|
*
|
|
@@ -3160,9 +3115,15 @@ const ContextParts = Object.freeze({
|
|
|
3160
3115
|
* @internal
|
|
3161
3116
|
*/
|
|
3162
3117
|
export const boundedContextIntegrationAccess = Object.freeze({
|
|
3118
|
+
/**
|
|
3119
|
+
* Publishes an imported Event through the context’s import path.
|
|
3120
|
+
*/
|
|
3163
3121
|
publishImported(context, event) {
|
|
3164
3122
|
return ContextParts.publishImported(context, event);
|
|
3165
3123
|
},
|
|
3124
|
+
/**
|
|
3125
|
+
* Signals that standalone context integration is ready.
|
|
3126
|
+
*/
|
|
3166
3127
|
ready(context) {
|
|
3167
3128
|
return ContextParts.integrationReady(context);
|
|
3168
3129
|
},
|