@spine-event-engine/server 2.0.0-snapshot.25 → 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 +104 -16
- package/REFERENCE.md +486 -57
- 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-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 +13 -2
- package/dist/agent/agent-live-read-runtime.d.ts.map +1 -1
- package/dist/agent/agent-live-read-runtime.js +6 -5
- package/dist/agent/agent-live-read-runtime.js.map +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 +171 -1
- package/dist/browser/browser-server.d.ts.map +1 -1
- package/dist/browser/browser-server.js +1027 -303
- 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/index.d.ts +1 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/options.d.ts +53 -2
- package/dist/browser/options.d.ts.map +1 -1
- package/dist/bus/command-bus.d.ts +9 -1
- package/dist/bus/command-bus.d.ts.map +1 -1
- package/dist/bus/command-bus.js +75 -10
- 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 +9 -1
- package/dist/bus/event-bus.d.ts.map +1 -1
- package/dist/bus/event-bus.js +136 -9
- package/dist/bus/event-bus.js.map +1 -1
- package/dist/context/bounded-context.d.ts +59 -39
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +277 -262
- 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/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 +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- 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 +61 -26
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +612 -306
- 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/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 +744 -108
- 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 +23 -5
- package/dist/server/server-environment.d.ts.map +1 -1
- package/dist/server/server-environment.js +89 -24
- 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 +112 -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/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/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 +42 -7
- package/dist/services/spine-services.d.ts.map +1 -1
- package/dist/services/spine-services.js +1005 -175
- package/dist/services/spine-services.js.map +1 -1
- package/dist/services/trusted-reader-ingress.d.ts +110 -0
- package/dist/services/trusted-reader-ingress.d.ts.map +1 -0
- package/dist/services/trusted-reader-ingress.js +102 -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 +81 -43
- package/dist/stand/stand.d.ts.map +1 -1
- package/dist/stand/stand.js +411 -55
- 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 +16 -14
package/dist/stand/stand.js
CHANGED
|
@@ -12,14 +12,23 @@
|
|
|
12
12
|
* the License.
|
|
13
13
|
*/
|
|
14
14
|
var _a;
|
|
15
|
-
import { clone } from "@bufbuild/protobuf";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { clone, create, toBinary } from "@bufbuild/protobuf";
|
|
16
|
+
import { AnySchema } from "@bufbuild/protobuf/wkt";
|
|
17
|
+
import { TypeRegistry, TypeUrls } from "@spine-event-engine/core";
|
|
18
|
+
import { registeredProtoModules } from "@spine-event-engine/proto/codegen";
|
|
19
|
+
import { ActorContextSchema, EventSchema, TenantIdSchema, VersionSchema, } from "@spine-event-engine/proto";
|
|
18
20
|
import { ColumnTypes, RecordColumn, RecordQuery, } from "@spine-event-engine/storage";
|
|
19
21
|
import { TenantBoundary } from "@spine-event-engine/storage/provider";
|
|
20
|
-
import { EntityRecords, standEntityStorageDescriptor, } from "../entity/entity-storage-descriptor.js";
|
|
22
|
+
import { EntityIds, EntityRecords, standEntityStorageDescriptor, } from "../entity/entity-storage-descriptor.js";
|
|
21
23
|
import { SubscriptionObservers } from "./subscription-observer.js";
|
|
24
|
+
import { ReadSideFilterEngine } from "./read-side-filter-engine.js";
|
|
25
|
+
import { SubscriptionReadFilters } from "./subscription-read-filters.js";
|
|
26
|
+
import { ReadSideMessages } from "./read-side-message.js";
|
|
27
|
+
import { StandDirectDelivery, } from "./stand-direct-delivery.js";
|
|
28
|
+
import { ServerEnvironment } from "../server/server-environment.js";
|
|
29
|
+
import { snapshotTrustedReader, } from "@spine-event-engine/core/spi/trusted-reader";
|
|
22
30
|
const HANDLE_CLOSE_ERROR_LIMIT = 16;
|
|
31
|
+
export { StandSubscriptionCapacityError } from "./stand-direct-delivery.js";
|
|
23
32
|
/**
|
|
24
33
|
* Error thrown when direct Stand access targets an unregistered state type.
|
|
25
34
|
*/
|
|
@@ -54,12 +63,14 @@ export class StandStateTypeError extends Error {
|
|
|
54
63
|
*/
|
|
55
64
|
export class Stand {
|
|
56
65
|
#context;
|
|
66
|
+
#subscriptionQueueCapacity;
|
|
57
67
|
#storageFactory;
|
|
58
68
|
#registrations = new Map();
|
|
59
69
|
#entityHandles = new Map();
|
|
60
70
|
#handleCloseErrors = [];
|
|
61
71
|
#omittedHandleCloseErrors = 0;
|
|
62
72
|
#inFlight = new Set();
|
|
73
|
+
#pendingUpdates = new Map();
|
|
63
74
|
#closing = false;
|
|
64
75
|
#closed = false;
|
|
65
76
|
#closedPromise;
|
|
@@ -69,10 +80,12 @@ export class Stand {
|
|
|
69
80
|
* @param options The storage context and factory used for state records.
|
|
70
81
|
*/
|
|
71
82
|
constructor(options) {
|
|
83
|
+
this.#subscriptionQueueCapacity = ServerEnvironment.instance().subscriptionQueueCapacity;
|
|
72
84
|
this.#context = _a.#cloneContext(options.context);
|
|
73
85
|
this.#storageFactory = options.storageFactory;
|
|
74
86
|
deferredUpdates.set(this, (schema, state, updateOptions, metadata) => this.#deferUpdate(schema, state, updateOptions, metadata));
|
|
75
87
|
currentReads.set(this, (schema, id, readOptions) => this.#readCurrent(schema, id, readOptions));
|
|
88
|
+
routedQueryPlans.set(this, (schema, plan, readOptions, readSide) => this.#queryPlanVersioned(schema, plan, readOptions, readSide));
|
|
76
89
|
}
|
|
77
90
|
/**
|
|
78
91
|
* Registers one entity state schema. Re-registering the same schema is idempotent.
|
|
@@ -146,24 +159,44 @@ export class Stand {
|
|
|
146
159
|
async readVersioned(schema, id, options = {}) {
|
|
147
160
|
const finish = this.#beginPublicOperation();
|
|
148
161
|
try {
|
|
162
|
+
const captured = _a.#snapshotRead(options);
|
|
163
|
+
const copiedId = ReadSideMessages.copy(id);
|
|
149
164
|
const registration = this.#registration(schema, "read");
|
|
150
|
-
const tenantId = await this.#checkedTenantId(
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
finally {
|
|
160
|
-
storage.release();
|
|
161
|
-
}
|
|
165
|
+
const tenantId = await this.#checkedTenantId(captured.tenantId);
|
|
166
|
+
const result = await this.#readStored(registration, copiedId, tenantId);
|
|
167
|
+
return await this.#filteredResult(registration.schema, result, {
|
|
168
|
+
...captured,
|
|
169
|
+
...(tenantId === undefined ? {} : { tenantId }),
|
|
170
|
+
}, {
|
|
171
|
+
kind: "direct",
|
|
172
|
+
read: { typeUrl: registration.typeUrl, id: copiedId },
|
|
173
|
+
});
|
|
162
174
|
}
|
|
163
175
|
finally {
|
|
164
176
|
finish();
|
|
165
177
|
}
|
|
166
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Captures a current record and releases its provider lease before policy awaits.
|
|
181
|
+
*
|
|
182
|
+
* @typeParam Schema Registered state schema.
|
|
183
|
+
* @param registration State metadata and storage descriptor.
|
|
184
|
+
* @param id Detached Entity identifier.
|
|
185
|
+
* @param tenantId Admitted tenant, if multitenant.
|
|
186
|
+
* @returns Detached live state and version, or undefined.
|
|
187
|
+
*/
|
|
188
|
+
async #readStored(registration, id, tenantId) {
|
|
189
|
+
const storage = this.#leaseCurrent(registration, tenantId);
|
|
190
|
+
try {
|
|
191
|
+
const stored = await storage.current.read(id);
|
|
192
|
+
if (stored === undefined || EntityRecords.unpack(registration.schema, stored).deleted)
|
|
193
|
+
return undefined;
|
|
194
|
+
return this.#currentResult(registration, stored);
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
storage.release();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
167
200
|
/**
|
|
168
201
|
* Reads all latest states and version metadata in storage query order.
|
|
169
202
|
*
|
|
@@ -187,17 +220,25 @@ export class Stand {
|
|
|
187
220
|
async queryVersioned(schema, query = {}, options = {}) {
|
|
188
221
|
const finish = this.#beginPublicOperation();
|
|
189
222
|
try {
|
|
223
|
+
const captured = _a.#snapshotRead(options);
|
|
224
|
+
const copiedQuery = ReadSideMessages.copy(query);
|
|
190
225
|
const registration = this.#registration(schema, "read");
|
|
191
|
-
const tenantId = await this.#checkedTenantId(
|
|
226
|
+
const tenantId = await this.#checkedTenantId(captured.tenantId);
|
|
192
227
|
const storage = this.#leaseCurrent(registration, tenantId);
|
|
228
|
+
let results;
|
|
193
229
|
try {
|
|
194
|
-
const stored = await storage.current.query(_a.#legacyPlan(
|
|
195
|
-
|
|
196
|
-
|
|
230
|
+
const stored = await storage.current.query(_a.#legacyPlan(copiedQuery));
|
|
231
|
+
results = stored
|
|
232
|
+
.map((entry) => this.#entryResult(registration, entry.record))
|
|
233
|
+
.filter((result) => result !== undefined);
|
|
197
234
|
}
|
|
198
235
|
finally {
|
|
199
236
|
storage.release();
|
|
200
237
|
}
|
|
238
|
+
return await this.#filteredResults(registration.schema, results, {
|
|
239
|
+
...captured,
|
|
240
|
+
...(tenantId === undefined ? {} : { tenantId }),
|
|
241
|
+
}, { kind: "direct", query: copiedQuery });
|
|
201
242
|
}
|
|
202
243
|
finally {
|
|
203
244
|
finish();
|
|
@@ -213,28 +254,121 @@ export class Stand {
|
|
|
213
254
|
* @returns The matching current states and versions.
|
|
214
255
|
*/
|
|
215
256
|
async queryPlanVersioned(schema, plan, options = {}) {
|
|
257
|
+
return this.#queryPlanVersioned(schema, plan, options);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Reads stored rows and applies the context's outward policy in one operation lifetime.
|
|
261
|
+
* @typeParam Schema Registered state schema.
|
|
262
|
+
* @param schema Registered Entity state schema.
|
|
263
|
+
* @param plan Normalized storage query plan.
|
|
264
|
+
* @param options Trusted read facts and tenant.
|
|
265
|
+
* @param readSide Actual routed Query context, if supplied internally.
|
|
266
|
+
* @returns Surviving versioned state records.
|
|
267
|
+
*/
|
|
268
|
+
async #queryPlanVersioned(schema, plan, options, readSide) {
|
|
216
269
|
const finish = this.#beginPublicOperation();
|
|
217
270
|
try {
|
|
271
|
+
const captured = _a.#snapshotRead(options, readSide);
|
|
272
|
+
const copiedPlan = ReadSideMessages.copy(plan);
|
|
218
273
|
const registration = this.#registration(schema, "read");
|
|
219
|
-
const tenantId = await this.#checkedTenantId(
|
|
274
|
+
const tenantId = await this.#checkedTenantId(captured.tenantId);
|
|
220
275
|
const storage = this.#leaseCurrent(registration, tenantId);
|
|
276
|
+
let results;
|
|
221
277
|
try {
|
|
222
|
-
const stored = await storage.current.query(
|
|
223
|
-
|
|
224
|
-
|
|
278
|
+
const stored = await storage.current.query(copiedPlan);
|
|
279
|
+
results = stored
|
|
280
|
+
.map((entry) => this.#entryResult(registration, entry.record))
|
|
281
|
+
.filter((result) => result !== undefined);
|
|
225
282
|
}
|
|
226
283
|
finally {
|
|
227
284
|
storage.release();
|
|
228
285
|
}
|
|
286
|
+
return await this.#filteredResults(registration.schema, results, {
|
|
287
|
+
...captured,
|
|
288
|
+
...(tenantId === undefined ? {} : { tenantId }),
|
|
289
|
+
}, { kind: "direct", plan: copiedPlan });
|
|
229
290
|
}
|
|
230
291
|
finally {
|
|
231
292
|
finish();
|
|
232
293
|
}
|
|
233
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Detaches mutable caller facts before storage admission can await.
|
|
297
|
+
*
|
|
298
|
+
* @param options Direct or service read options.
|
|
299
|
+
* @returns Stable tenant and invocation facts, retaining the live cancellation signal.
|
|
300
|
+
*/
|
|
301
|
+
static #snapshotRead(options, side) {
|
|
302
|
+
const { signal, producingContext, effectiveTenant, parent, field, ...facts } = side ?? {};
|
|
303
|
+
void producingContext;
|
|
304
|
+
void effectiveTenant;
|
|
305
|
+
void parent;
|
|
306
|
+
void field;
|
|
307
|
+
return {
|
|
308
|
+
...(options.tenantId === undefined
|
|
309
|
+
? {}
|
|
310
|
+
: { tenantId: clone(TenantIdSchema, options.tenantId) }),
|
|
311
|
+
readSide: {
|
|
312
|
+
...(side === undefined ? {} : ReadSideMessages.copy(facts)),
|
|
313
|
+
...(options.actorContext === undefined
|
|
314
|
+
? {}
|
|
315
|
+
: { actorContext: clone(ActorContextSchema, options.actorContext) }),
|
|
316
|
+
...(options.reader === undefined ? {} : snapshotTrustedReader(options.reader)),
|
|
317
|
+
...((signal ?? options.signal) === undefined ? {} : { signal: signal ?? options.signal }),
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Applies this context's outward read policy after storage has been released.
|
|
323
|
+
*
|
|
324
|
+
* @typeParam Schema Registered state schema.
|
|
325
|
+
* @param schema State schema selected by the read.
|
|
326
|
+
* @param result Captured state and durable version.
|
|
327
|
+
* @param options Tenant and service read facts.
|
|
328
|
+
* @param operation Actual direct operation when no service request is present.
|
|
329
|
+
* @returns Detached visible state with its unchanged version, or no state.
|
|
330
|
+
*/
|
|
331
|
+
async #filteredResult(schema, result, options, operation) {
|
|
332
|
+
if (result === undefined)
|
|
333
|
+
return undefined;
|
|
334
|
+
const filters = standReadFilters.get(this);
|
|
335
|
+
if (filters === undefined)
|
|
336
|
+
return result;
|
|
337
|
+
const producer = standProducingContexts.get(this);
|
|
338
|
+
const context = {
|
|
339
|
+
...(options.readSide ?? {}),
|
|
340
|
+
operation: options.readSide?.operation ?? operation,
|
|
341
|
+
...(producer === undefined ? {} : { producingContext: producer }),
|
|
342
|
+
...(options.tenantId === undefined ? {} : { effectiveTenant: options.tenantId }),
|
|
343
|
+
};
|
|
344
|
+
const state = await filters.apply(schema, result.state, context);
|
|
345
|
+
return state === null ? undefined : { ...result, state };
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Applies outward policy in stored query order without replenishing removed records.
|
|
349
|
+
*
|
|
350
|
+
* @typeParam Schema Registered state schema.
|
|
351
|
+
* @param schema State schema selected by the read.
|
|
352
|
+
* @param results Captured stored states and durable versions.
|
|
353
|
+
* @param options Tenant and service read facts.
|
|
354
|
+
* @param operation Actual direct query when no service request is present.
|
|
355
|
+
* @returns Surviving visible records in their original order.
|
|
356
|
+
*/
|
|
357
|
+
async #filteredResults(schema, results, options, operation) {
|
|
358
|
+
if (!standReadFilters.has(this))
|
|
359
|
+
return results;
|
|
360
|
+
const visible = [];
|
|
361
|
+
for (const result of results) {
|
|
362
|
+
const next = await this.#filteredResult(schema, result, options, operation);
|
|
363
|
+
if (next !== undefined)
|
|
364
|
+
visible.push(next);
|
|
365
|
+
}
|
|
366
|
+
return visible;
|
|
367
|
+
}
|
|
234
368
|
/**
|
|
235
369
|
* Clears all stored states and durable version metadata for one known state schema.
|
|
236
370
|
*
|
|
237
|
-
* The
|
|
371
|
+
* The local `BoundedContext.catchUpReadSide()` reset/dispatch
|
|
238
372
|
* helper uses this to reset one Projection state type for the selected tenant
|
|
239
373
|
* slice.
|
|
240
374
|
*
|
|
@@ -317,26 +451,77 @@ export class Stand {
|
|
|
317
451
|
* @returns Prepared write with cleanup actions.
|
|
318
452
|
*/
|
|
319
453
|
async #prepareUpdate(schema, state, options, metadata) {
|
|
320
|
-
const
|
|
454
|
+
const onFinish = this.#beginOperation();
|
|
321
455
|
let storage;
|
|
456
|
+
let releaseUpdate;
|
|
322
457
|
try {
|
|
323
458
|
const registration = this.#registration(schema, "update");
|
|
324
|
-
|
|
325
|
-
throw new Error("Repository metadata does not match the Entity state schema.");
|
|
459
|
+
_a.#requireUpdateMetadata(registration, metadata);
|
|
326
460
|
const snapshot = _a.#snapshotUpdateOptions(options);
|
|
327
461
|
const stateCopy = clone(schema, state);
|
|
328
462
|
const tenantId = await this.#checkedTenantId(options.tenantId);
|
|
329
463
|
const id = _a.#readStateId(stateCopy, registration);
|
|
464
|
+
releaseUpdate = await this.#reserveUpdate(registration, tenantId, id, metadata);
|
|
330
465
|
storage = this.#leaseCurrent(registration, tenantId);
|
|
331
466
|
const previousState = await this.#previousUpdateState(registration, tenantId, id, storage);
|
|
332
|
-
return this.#preparedUpdate(registration, { id, previousState, state: stateCopy, tenantId, version: snapshot.version }, snapshot, metadata, storage,
|
|
467
|
+
return this.#preparedUpdate(registration, { id, previousState, state: stateCopy, tenantId, version: snapshot.version }, snapshot, metadata, storage, () => {
|
|
468
|
+
_a.#finishUpdate(releaseUpdate, onFinish);
|
|
469
|
+
});
|
|
333
470
|
}
|
|
334
471
|
catch (error) {
|
|
335
472
|
storage?.release();
|
|
336
|
-
|
|
473
|
+
_a.#finishUpdate(releaseUpdate, onFinish);
|
|
337
474
|
throw error;
|
|
338
475
|
}
|
|
339
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Checks repository metadata before preparing the state update.
|
|
479
|
+
*
|
|
480
|
+
* @param registration Registered state metadata.
|
|
481
|
+
* @param metadata Repository metadata, when supplied.
|
|
482
|
+
*/
|
|
483
|
+
static #requireUpdateMetadata(registration, metadata) {
|
|
484
|
+
if (metadata !== undefined && metadata.schema !== registration.schema)
|
|
485
|
+
throw new Error("Repository metadata does not match the Entity state schema.");
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Releases the update reservation and completes its tracked Stand operation.
|
|
489
|
+
*
|
|
490
|
+
* @param onReleaseUpdate Per-Entity reservation release, when acquired.
|
|
491
|
+
* @param onFinish Completes the tracked Stand operation.
|
|
492
|
+
*/
|
|
493
|
+
static #finishUpdate(onReleaseUpdate, onFinish) {
|
|
494
|
+
onReleaseUpdate?.();
|
|
495
|
+
onFinish();
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Keeps one Entity's previous-state read and commit in notification order.
|
|
499
|
+
*
|
|
500
|
+
* @param registration State metadata.
|
|
501
|
+
* @param tenantId Tenant for the state.
|
|
502
|
+
* @param id Entity identifier.
|
|
503
|
+
* @param metadata Repository-validated identifier metadata, when available.
|
|
504
|
+
* @returns A release action for notification or cancellation.
|
|
505
|
+
*/
|
|
506
|
+
async #reserveUpdate(registration, tenantId, id, metadata) {
|
|
507
|
+
const packed = metadata === undefined
|
|
508
|
+
? EntityIds.pack(registration.schema, id)
|
|
509
|
+
: EntityIds.packField(metadata.idField.descriptor, id);
|
|
510
|
+
const key = JSON.stringify([
|
|
511
|
+
registration.typeUrl,
|
|
512
|
+
this.#tenantKey(tenantId),
|
|
513
|
+
Buffer.from(toBinary(AnySchema, packed)).toString("base64"),
|
|
514
|
+
]);
|
|
515
|
+
const previous = this.#pendingUpdates.get(key);
|
|
516
|
+
const settled = Promise.withResolvers();
|
|
517
|
+
this.#pendingUpdates.set(key, settled.promise);
|
|
518
|
+
await previous;
|
|
519
|
+
return () => {
|
|
520
|
+
if (this.#pendingUpdates.get(key) === settled.promise)
|
|
521
|
+
this.#pendingUpdates.delete(key);
|
|
522
|
+
settled.resolve(undefined);
|
|
523
|
+
};
|
|
524
|
+
}
|
|
340
525
|
/**
|
|
341
526
|
* Copies mutable Version and lifecycle input before update preparation awaits.
|
|
342
527
|
* @param options Update metadata supplied by the caller.
|
|
@@ -453,29 +638,74 @@ export class Stand {
|
|
|
453
638
|
*
|
|
454
639
|
* @typeParam Schema The registered state schema.
|
|
455
640
|
* @param schema The registered entity state schema.
|
|
456
|
-
* @param
|
|
457
|
-
* @param options
|
|
458
|
-
* @returns A handle that
|
|
641
|
+
* @param observer Receives serial visible updates and one terminal local fault.
|
|
642
|
+
* @param options Tenant, trusted facts, and cancellation.
|
|
643
|
+
* @returns A handle that invalidates pending and active delivery.
|
|
459
644
|
*/
|
|
460
|
-
subscribe(schema,
|
|
645
|
+
subscribe(schema, observer, options = {}) {
|
|
461
646
|
this.#requireOpen();
|
|
647
|
+
_a.#requireObserver(observer);
|
|
462
648
|
const registration = this.#registration(schema, "subscribe");
|
|
463
649
|
const tenantKey = this.#tenantKey(options.tenantId);
|
|
464
|
-
const
|
|
465
|
-
let closed = false;
|
|
466
|
-
registration.subscribers.add(subscriber);
|
|
650
|
+
const delivery = this.#subscribeDelivery(schema, observer, options, registration, tenantKey);
|
|
467
651
|
return Object.freeze({
|
|
652
|
+
/**
|
|
653
|
+
* Reports whether this subscription handle has stopped delivering.
|
|
654
|
+
*/
|
|
468
655
|
get closed() {
|
|
469
|
-
return closed;
|
|
656
|
+
return delivery.closed;
|
|
470
657
|
},
|
|
658
|
+
/**
|
|
659
|
+
* Detaches the subscriber and stops future local deliveries.
|
|
660
|
+
*/
|
|
471
661
|
unsubscribe() {
|
|
472
|
-
|
|
473
|
-
closed = true;
|
|
474
|
-
registration.subscribers.delete(subscriber);
|
|
475
|
-
}
|
|
662
|
+
delivery.close();
|
|
476
663
|
},
|
|
477
664
|
});
|
|
478
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* Rejects a raw callback or malformed JavaScript observer before registration.
|
|
668
|
+
*
|
|
669
|
+
* @param observer The runtime value supplied for direct delivery.
|
|
670
|
+
*/
|
|
671
|
+
static #requireObserver(observer) {
|
|
672
|
+
if (typeof observer !== "object" ||
|
|
673
|
+
observer === null ||
|
|
674
|
+
!("next" in observer) ||
|
|
675
|
+
typeof observer.next !== "function" ||
|
|
676
|
+
!("error" in observer) ||
|
|
677
|
+
typeof observer.error !== "function")
|
|
678
|
+
throw new TypeError("Stand.subscribe requires an observer with next and error callbacks.");
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Captures the subscriber's read facts and attaches its independent delivery queue.
|
|
682
|
+
*
|
|
683
|
+
* @typeParam Schema The registered state schema.
|
|
684
|
+
* @param schema The state schema selected by the caller.
|
|
685
|
+
* @param observer Receives visible updates or one terminal local fault.
|
|
686
|
+
* @param options Trusted reader, tenant, and cancellation at subscribe time.
|
|
687
|
+
* @param registration The Stand registration for this state schema.
|
|
688
|
+
* @param tenantKey The normalized tenant slice for delivery.
|
|
689
|
+
* @returns The subscriber's serial delivery queue.
|
|
690
|
+
*/
|
|
691
|
+
#subscribeDelivery(schema, observer, options, registration, tenantKey) {
|
|
692
|
+
const captured = _a.#snapshotRead(options);
|
|
693
|
+
const producingContext = standProducingContexts.get(this);
|
|
694
|
+
const attachment = {};
|
|
695
|
+
const delivery = new StandDirectDelivery(schema, observer, standReadFilters.get(this), {
|
|
696
|
+
...captured.readSide,
|
|
697
|
+
operation: { kind: "direct", subscription: { typeUrl: registration.typeUrl } },
|
|
698
|
+
...(captured.tenantId === undefined ? {} : { effectiveTenant: captured.tenantId }),
|
|
699
|
+
...(producingContext === undefined ? {} : { producingContext }),
|
|
700
|
+
}, this.#subscriptionQueueCapacity, () => {
|
|
701
|
+
if (attachment.subscriber !== undefined)
|
|
702
|
+
registration.subscribers.delete(attachment.subscriber);
|
|
703
|
+
}, options.signal);
|
|
704
|
+
attachment.subscriber = Object.freeze({ tenantKey, delivery });
|
|
705
|
+
if (!delivery.closed)
|
|
706
|
+
registration.subscribers.add(attachment.subscriber);
|
|
707
|
+
return delivery;
|
|
708
|
+
}
|
|
479
709
|
/**
|
|
480
710
|
* Closes direct subscriptions and rejects later Stand operations.
|
|
481
711
|
*
|
|
@@ -490,10 +720,15 @@ export class Stand {
|
|
|
490
720
|
this.#closedPromise ??= this.#closeOnce();
|
|
491
721
|
return this.#closedPromise;
|
|
492
722
|
}
|
|
723
|
+
/**
|
|
724
|
+
* Drains accepted Stand work, closes subscriptions, and releases Entity handles.
|
|
725
|
+
*/
|
|
493
726
|
async #closeOnce() {
|
|
494
727
|
this.#closing = true;
|
|
495
728
|
await Promise.all([...this.#inFlight]);
|
|
496
729
|
for (const registration of this.#registrations.values()) {
|
|
730
|
+
for (const subscriber of registration.subscribers)
|
|
731
|
+
subscriber.delivery.close();
|
|
497
732
|
registration.subscribers.clear();
|
|
498
733
|
}
|
|
499
734
|
const errors = this.#handleCloseErrors.splice(0);
|
|
@@ -535,6 +770,9 @@ export class Stand {
|
|
|
535
770
|
}
|
|
536
771
|
return registration;
|
|
537
772
|
}
|
|
773
|
+
/**
|
|
774
|
+
* Reuses single-tenant storage or opens a temporary multitenant Entity handle.
|
|
775
|
+
*/
|
|
538
776
|
#leaseCurrent(registration, tenantId) {
|
|
539
777
|
if (this.#context.multitenant) {
|
|
540
778
|
return this.#lease(_a.#openStorage(this.#storageFactory, standEntityStorageDescriptor(this.#storageContext(tenantId), registration.schema, registration.columns)), true);
|
|
@@ -547,6 +785,9 @@ export class Stand {
|
|
|
547
785
|
this.#entityHandles.set(key, handle);
|
|
548
786
|
return this.#lease(handle, false);
|
|
549
787
|
}
|
|
788
|
+
/**
|
|
789
|
+
* Returns a release callback for a current-state storage handle.
|
|
790
|
+
*/
|
|
550
791
|
#lease(handle, releaseAfterOperation) {
|
|
551
792
|
let released = false;
|
|
552
793
|
return {
|
|
@@ -611,28 +852,22 @@ export class Stand {
|
|
|
611
852
|
* @param captured Subscribers captured before persistence, if available.
|
|
612
853
|
*/
|
|
613
854
|
#notify(registration, input, captured) {
|
|
614
|
-
const errors = [];
|
|
615
855
|
const tenantKey = this.#tenantKey(input.tenantId);
|
|
616
856
|
const subscribers = captured ?? this.#tenantSubscribers(registration, tenantKey);
|
|
617
857
|
for (const subscriber of subscribers) {
|
|
618
|
-
|
|
619
|
-
subscriber.callback(_a.#createUpdate(registration, input));
|
|
620
|
-
}
|
|
621
|
-
catch (error) {
|
|
622
|
-
errors.push(error);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
if (errors.length === 1) {
|
|
626
|
-
throw errors[0];
|
|
627
|
-
}
|
|
628
|
-
if (errors.length > 1) {
|
|
629
|
-
throw new AggregateError(errors, "Stand subscriber delivery failed.");
|
|
858
|
+
subscriber.delivery.admit(_a.#createUpdate(registration, input));
|
|
630
859
|
}
|
|
631
860
|
}
|
|
861
|
+
/**
|
|
862
|
+
* Creates the subscription partition key for the selected tenant.
|
|
863
|
+
*/
|
|
632
864
|
#tenantKey(tenantId) {
|
|
633
865
|
const selected = this.#tenantId(tenantId);
|
|
634
866
|
return selected === undefined ? "__single__" : String(TenantBoundary.from(selected).key);
|
|
635
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* Checks whether a registered Entity state has subscribers in this tenant slice.
|
|
870
|
+
*/
|
|
636
871
|
#hasTenantSubscribers(registration, tenantId) {
|
|
637
872
|
const tenantKey = this.#tenantKey(tenantId);
|
|
638
873
|
for (const subscriber of registration.subscribers) {
|
|
@@ -653,6 +888,9 @@ export class Stand {
|
|
|
653
888
|
#tenantSubscribers(registration, tenantKey) {
|
|
654
889
|
return [...registration.subscribers].filter((subscriber) => subscriber.tenantKey === tenantKey);
|
|
655
890
|
}
|
|
891
|
+
/**
|
|
892
|
+
* Validates and detaches the tenant ID required by this Stand's tenancy mode.
|
|
893
|
+
*/
|
|
656
894
|
#tenantId(tenantId) {
|
|
657
895
|
if (!this.#context.multitenant) {
|
|
658
896
|
if (tenantId !== undefined) {
|
|
@@ -676,6 +914,9 @@ export class Stand {
|
|
|
676
914
|
await standAdmissions.get(this)?.(selected);
|
|
677
915
|
return selected;
|
|
678
916
|
}
|
|
917
|
+
/**
|
|
918
|
+
* Builds the provider storage scope for a validated tenant selection.
|
|
919
|
+
*/
|
|
679
920
|
#storageContext(tenantId) {
|
|
680
921
|
if (!this.#context.multitenant) {
|
|
681
922
|
this.#tenantId(tenantId);
|
|
@@ -690,11 +931,17 @@ export class Stand {
|
|
|
690
931
|
tenantId: TenantBoundary.from(tenantId).tenantId,
|
|
691
932
|
});
|
|
692
933
|
}
|
|
934
|
+
/**
|
|
935
|
+
* Rejects a new operation once Stand closing has begun.
|
|
936
|
+
*/
|
|
693
937
|
#requireOpen() {
|
|
694
938
|
if (this.#closing || this.#closed) {
|
|
695
939
|
throw new Error("Stand is closed.");
|
|
696
940
|
}
|
|
697
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* Tracks an accepted operation and returns its completion callback.
|
|
944
|
+
*/
|
|
698
945
|
#beginOperation() {
|
|
699
946
|
this.#requireOpen();
|
|
700
947
|
let finish;
|
|
@@ -737,6 +984,9 @@ export class Stand {
|
|
|
737
984
|
...(input.tenantId === undefined ? {} : { tenantId: clone(TenantIdSchema, input.tenantId) }),
|
|
738
985
|
});
|
|
739
986
|
}
|
|
987
|
+
/**
|
|
988
|
+
* Extracts the registered Entity ID field from a state update.
|
|
989
|
+
*/
|
|
740
990
|
static #readStateId(state, registration) {
|
|
741
991
|
const id = state[registration.idField];
|
|
742
992
|
if (id === undefined || id === null) {
|
|
@@ -744,9 +994,15 @@ export class Stand {
|
|
|
744
994
|
}
|
|
745
995
|
return id;
|
|
746
996
|
}
|
|
997
|
+
/**
|
|
998
|
+
* Detaches a structured storage value before returning it to a caller.
|
|
999
|
+
*/
|
|
747
1000
|
static #cloneValue(value) {
|
|
748
1001
|
return typeof value === "object" && value !== null ? globalThis.structuredClone(value) : value;
|
|
749
1002
|
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Translates a supported RecordQuery into the normalized storage query plan.
|
|
1005
|
+
*/
|
|
750
1006
|
static #legacyPlan(query) {
|
|
751
1007
|
RecordQuery.validate(query);
|
|
752
1008
|
if (query.after !== undefined) {
|
|
@@ -794,6 +1050,9 @@ export class Stand {
|
|
|
794
1050
|
}
|
|
795
1051
|
return candidate.createEntityStorage(input);
|
|
796
1052
|
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Freezes a detached name and tenancy mode for storage configuration.
|
|
1055
|
+
*/
|
|
797
1056
|
static #cloneContext(context) {
|
|
798
1057
|
return Object.freeze({ name: context.name, multitenant: context.multitenant });
|
|
799
1058
|
}
|
|
@@ -805,6 +1064,100 @@ _a = Stand;
|
|
|
805
1064
|
* @internal
|
|
806
1065
|
*/
|
|
807
1066
|
export const standAccess = Object.freeze({
|
|
1067
|
+
/**
|
|
1068
|
+
* Forwards trusted routed Query context to the private Stand read path.
|
|
1069
|
+
* @typeParam Schema Registered state schema.
|
|
1070
|
+
* @param stand Producing context's Stand.
|
|
1071
|
+
* @param schema Registered state schema.
|
|
1072
|
+
* @param plan Normalized routed query plan.
|
|
1073
|
+
* @param options Admitted tenant and trusted facts.
|
|
1074
|
+
* @param readSide Actual service or handler Query context.
|
|
1075
|
+
* @returns Surviving versioned states.
|
|
1076
|
+
*/
|
|
1077
|
+
queryPlanVersioned(stand, schema, plan, options, readSide) {
|
|
1078
|
+
const read = routedQueryPlans.get(stand);
|
|
1079
|
+
if (read === undefined)
|
|
1080
|
+
throw new Error("Stand routed read is unavailable.");
|
|
1081
|
+
return read(schema, plan, options, readSide);
|
|
1082
|
+
},
|
|
1083
|
+
/**
|
|
1084
|
+
* Associates actual context identity with direct and historical outward reads.
|
|
1085
|
+
*
|
|
1086
|
+
* @param stand Context Stand.
|
|
1087
|
+
* @param context Built Bounded Context.
|
|
1088
|
+
*/
|
|
1089
|
+
bindProducingContext(stand, context) {
|
|
1090
|
+
standProducingContexts.set(stand, context);
|
|
1091
|
+
},
|
|
1092
|
+
/**
|
|
1093
|
+
* Applies a history state policy after the physical history read.
|
|
1094
|
+
*
|
|
1095
|
+
* @typeParam Schema Registered domain schema.
|
|
1096
|
+
* @param stand Context read facade.
|
|
1097
|
+
* @param schema Historical state schema.
|
|
1098
|
+
* @param state Captured state.
|
|
1099
|
+
* @param context Actual history call.
|
|
1100
|
+
* @returns Filtered state or null.
|
|
1101
|
+
*/
|
|
1102
|
+
filterState(stand, schema, state, context) {
|
|
1103
|
+
const filters = standReadFilters.get(stand);
|
|
1104
|
+
const producer = standProducingContexts.get(stand);
|
|
1105
|
+
return filters === undefined
|
|
1106
|
+
? Promise.resolve(state)
|
|
1107
|
+
: filters.apply(schema, state, {
|
|
1108
|
+
...context,
|
|
1109
|
+
...(producer === undefined ? {} : { producingContext: producer }),
|
|
1110
|
+
});
|
|
1111
|
+
},
|
|
1112
|
+
/**
|
|
1113
|
+
* Filters a retained Event payload while retaining envelope identity and metadata.
|
|
1114
|
+
*
|
|
1115
|
+
* @param stand Context read facade.
|
|
1116
|
+
* @param event Retained Event envelope.
|
|
1117
|
+
* @param context Actual history call.
|
|
1118
|
+
* @returns Event with filtered payload, or null when removed.
|
|
1119
|
+
*/
|
|
1120
|
+
async filterEvent(stand, event, context) {
|
|
1121
|
+
const filters = standReadFilters.get(stand);
|
|
1122
|
+
if (filters === undefined)
|
|
1123
|
+
return event;
|
|
1124
|
+
if (event.message === undefined)
|
|
1125
|
+
throw new TypeError("Retained Event payload is missing.");
|
|
1126
|
+
const producer = standProducingContexts.get(stand);
|
|
1127
|
+
const message = await filters.applyPacked(event.message, {
|
|
1128
|
+
...context,
|
|
1129
|
+
...(producer === undefined ? {} : { producingContext: producer }),
|
|
1130
|
+
});
|
|
1131
|
+
return message === null ? null : create(EventSchema, { ...clone(EventSchema, event), message });
|
|
1132
|
+
},
|
|
1133
|
+
/**
|
|
1134
|
+
* Applies Bounded Context policy to one subscription update before delivery.
|
|
1135
|
+
*
|
|
1136
|
+
* @param stand Context read facade.
|
|
1137
|
+
* @param update Subscription update awaiting delivery.
|
|
1138
|
+
* @param context Actual subscription read facts.
|
|
1139
|
+
* @returns Visible update, or null when policy removes it.
|
|
1140
|
+
*/
|
|
1141
|
+
filterSubscription(stand, update, context) {
|
|
1142
|
+
const producer = standProducingContexts.get(stand);
|
|
1143
|
+
return SubscriptionReadFilters.apply(update, standReadFilters.get(stand), {
|
|
1144
|
+
...context,
|
|
1145
|
+
...(producer === undefined ? {} : { producingContext: producer }),
|
|
1146
|
+
});
|
|
1147
|
+
},
|
|
1148
|
+
/**
|
|
1149
|
+
* Attaches registered policies to this Stand without changing persistence reads.
|
|
1150
|
+
*
|
|
1151
|
+
* @param stand Context read facade.
|
|
1152
|
+
* @param filters Policies in registration order.
|
|
1153
|
+
*/
|
|
1154
|
+
installReadFilters(stand, filters) {
|
|
1155
|
+
if (!(stand instanceof Stand))
|
|
1156
|
+
throw new TypeError("Read filters require a Stand instance.");
|
|
1157
|
+
if (standReadFilters.has(stand))
|
|
1158
|
+
throw new TypeError("Stand read filters are already installed.");
|
|
1159
|
+
standReadFilters.set(stand, new ReadSideFilterEngine(filters, TypeRegistry.from(...registeredProtoModules())));
|
|
1160
|
+
},
|
|
808
1161
|
/**
|
|
809
1162
|
* Sets the immediate external read admission check.
|
|
810
1163
|
*
|
|
@@ -893,5 +1246,8 @@ export const standAccess = Object.freeze({
|
|
|
893
1246
|
const deferredUpdates = new WeakMap();
|
|
894
1247
|
const standAdmissions = new WeakMap();
|
|
895
1248
|
const standPublicAdmissions = new WeakMap();
|
|
1249
|
+
const standReadFilters = new WeakMap();
|
|
1250
|
+
const standProducingContexts = new WeakMap();
|
|
896
1251
|
const currentReads = new WeakMap();
|
|
1252
|
+
const routedQueryPlans = new WeakMap();
|
|
897
1253
|
//# sourceMappingURL=stand.js.map
|