@spine-event-engine/server 2.0.0-snapshot.14 → 2.0.0-snapshot.16
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 +53 -0
- package/REFERENCE.md +146 -23
- package/dist/context/bounded-context.d.ts +131 -20
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +647 -48
- package/dist/context/bounded-context.js.map +1 -1
- package/dist/entity/entity-metadata.d.ts +12 -3
- package/dist/entity/entity-metadata.d.ts.map +1 -1
- package/dist/entity/entity-metadata.js +37 -1
- package/dist/entity/entity-metadata.js.map +1 -1
- package/dist/entity/entity-transaction.d.ts +46 -42
- package/dist/entity/entity-transaction.d.ts.map +1 -1
- package/dist/entity/entity-transaction.js +130 -35
- package/dist/entity/entity-transaction.js.map +1 -1
- package/dist/entity/entity.d.ts +138 -100
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +217 -227
- package/dist/entity/entity.js.map +1 -1
- package/dist/handler/event-registration-readiness.d.ts +13 -56
- package/dist/handler/event-registration-readiness.d.ts.map +1 -1
- package/dist/handler/event-registration-readiness.js +23 -43
- package/dist/handler/event-registration-readiness.js.map +1 -1
- package/dist/handler/generated-handler-registry.d.ts +8 -0
- package/dist/handler/generated-handler-registry.d.ts.map +1 -1
- package/dist/handler/generated-handler-registry.js +165 -3
- package/dist/handler/generated-handler-registry.js.map +1 -1
- package/dist/handler/handler-decorators.d.ts +70 -33
- package/dist/handler/handler-decorators.d.ts.map +1 -1
- package/dist/handler/handler-decorators.js +88 -31
- package/dist/handler/handler-decorators.js.map +1 -1
- package/dist/handler/handler-metadata.d.ts +53 -51
- package/dist/handler/handler-metadata.d.ts.map +1 -1
- package/dist/handler/handler-metadata.js +214 -42
- package/dist/handler/handler-metadata.js.map +1 -1
- package/dist/handler/registration-readiness-metadata.d.ts +4 -0
- package/dist/handler/registration-readiness-metadata.d.ts.map +1 -1
- package/dist/handler/registration-readiness-metadata.js +82 -1
- package/dist/handler/registration-readiness-metadata.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/repository/repository.d.ts +217 -70
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +2728 -354
- package/dist/repository/repository.js.map +1 -1
- package/dist/runtime/standalone-handler-runtime.d.ts +16 -0
- package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -1
- package/dist/runtime/standalone-handler-runtime.js +93 -18
- package/dist/runtime/standalone-handler-runtime.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -12
package/dist/entity/entity.js
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
12
|
* the License.
|
|
13
13
|
*/
|
|
14
|
-
import { clone, fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
14
|
+
import { clone, create, fromBinary, toBinary, } from "@bufbuild/protobuf";
|
|
15
15
|
import { EntityQuery, } from "@spine-event-engine/core";
|
|
16
|
-
import { ActorContextSchema, ValidationErrorSchema, } from "@spine-event-engine/proto";
|
|
16
|
+
import { VersionSchema, ActorContextSchema, ValidationErrorSchema, } from "@spine-event-engine/proto";
|
|
17
17
|
import { describeEntityMetadata, } from "./entity-metadata.js";
|
|
18
18
|
import { EntityTransaction, } from "./entity-transaction.js";
|
|
19
19
|
const processManagerQueries = new WeakMap();
|
|
@@ -23,6 +23,14 @@ const processManagerQueries = new WeakMap();
|
|
|
23
23
|
* @internal
|
|
24
24
|
*/
|
|
25
25
|
export const processManagerQueryAccess = Object.freeze({
|
|
26
|
+
/**
|
|
27
|
+
* Enables read-side queries for the duration of one handler invocation.
|
|
28
|
+
*
|
|
29
|
+
* @param entity Process Manager receiving the query capability.
|
|
30
|
+
* @param execute Repository operation that runs queries.
|
|
31
|
+
* @param actorContext Actor and tenant of the incoming signal.
|
|
32
|
+
* @returns A function that disables and removes this capability.
|
|
33
|
+
*/
|
|
26
34
|
bind(entity, execute, actorContext) {
|
|
27
35
|
const capability = {
|
|
28
36
|
execute,
|
|
@@ -35,6 +43,12 @@ export const processManagerQueryAccess = Object.freeze({
|
|
|
35
43
|
processManagerQueries.delete(entity);
|
|
36
44
|
};
|
|
37
45
|
},
|
|
46
|
+
/**
|
|
47
|
+
* Gets the query capability of a currently executing Process Manager.
|
|
48
|
+
*
|
|
49
|
+
* @param entity Process Manager attempting a query.
|
|
50
|
+
* @returns The active repository query capability.
|
|
51
|
+
*/
|
|
38
52
|
require(entity) {
|
|
39
53
|
const capability = processManagerQueries.get(entity);
|
|
40
54
|
if (capability?.active !== true) {
|
|
@@ -57,7 +71,7 @@ export class ProcessManagerQuery {
|
|
|
57
71
|
* Creates the repository-scoped query facade.
|
|
58
72
|
*
|
|
59
73
|
* @internal
|
|
60
|
-
* @param entity Process Manager
|
|
74
|
+
* @param entity Process Manager using this query capability.
|
|
61
75
|
* @param schema State schema read by this query.
|
|
62
76
|
* @param builder Typed query builder used to create the wire query.
|
|
63
77
|
*/
|
|
@@ -79,6 +93,7 @@ export class ProcessManagerQuery {
|
|
|
79
93
|
/**
|
|
80
94
|
* Adds a typed state predicate to the query.
|
|
81
95
|
*
|
|
96
|
+
* @typeParam Predicate Comparison supported by the registered columns.
|
|
82
97
|
* @param predicate Predicate evaluated against registered state columns.
|
|
83
98
|
* @returns This query for fluent configuration.
|
|
84
99
|
*/
|
|
@@ -99,6 +114,7 @@ export class ProcessManagerQuery {
|
|
|
99
114
|
/**
|
|
100
115
|
* Sets the ordering for matching states by one registered column.
|
|
101
116
|
*
|
|
117
|
+
* @typeParam Column Registered column supplying the ordered values.
|
|
102
118
|
* @param column Registered orderable column used for sorting.
|
|
103
119
|
* @param direction Optional sort direction, ascending by default.
|
|
104
120
|
* @returns This query for fluent configuration.
|
|
@@ -182,15 +198,15 @@ export class TransactionalEntityScopeError extends Error {
|
|
|
182
198
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
183
199
|
}
|
|
184
200
|
}
|
|
185
|
-
const isProxy = process.getBuiltinModule("node:util").types.isProxy;
|
|
186
201
|
/**
|
|
187
|
-
*
|
|
202
|
+
* Identity, state, version, and lifecycle of one server-side Entity.
|
|
203
|
+
*
|
|
204
|
+
* Keeps the Entity ID, state schema, state, Spine Version, and lifecycle flags.
|
|
205
|
+
* State and Version accessors return copies, and lifecycle access returns a
|
|
206
|
+
* separate flag object. Repositories run handlers and manage storage.
|
|
188
207
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* invoke handlers, create transactions, write repositories or storage, dispatch
|
|
192
|
-
* messages, increment versions, route IDs, query read models, start buses, or
|
|
193
|
-
* mutate process-wide runtime state.
|
|
208
|
+
* @typeParam Id Domain identifier type.
|
|
209
|
+
* @typeParam Schema Generated schema describing the Entity state.
|
|
194
210
|
*/
|
|
195
211
|
export class Entity {
|
|
196
212
|
#id;
|
|
@@ -201,7 +217,7 @@ export class Entity {
|
|
|
201
217
|
#lifecycle;
|
|
202
218
|
#lifecycleFlagsChanged = false;
|
|
203
219
|
/**
|
|
204
|
-
*
|
|
220
|
+
* Initializes an Entity from its ID, schema, state, Version, and lifecycle flags.
|
|
205
221
|
*
|
|
206
222
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
207
223
|
*/
|
|
@@ -210,7 +226,7 @@ export class Entity {
|
|
|
210
226
|
this.#schema = options.schema;
|
|
211
227
|
this.#metadata = describeEntityMetadata(options.schema);
|
|
212
228
|
this.#state = EntitySnapshots.clone(options.schema, options.state);
|
|
213
|
-
this.#version =
|
|
229
|
+
this.#version = clone(VersionSchema, options.version ?? create(VersionSchema));
|
|
214
230
|
this.#lifecycle = {
|
|
215
231
|
archived: options.lifecycle?.archived ?? false,
|
|
216
232
|
deleted: options.lifecycle?.deleted ?? false,
|
|
@@ -219,7 +235,7 @@ export class Entity {
|
|
|
219
235
|
/**
|
|
220
236
|
* Gets the stable entity identifier.
|
|
221
237
|
*
|
|
222
|
-
* @returns The
|
|
238
|
+
* @returns The domain identifier supplied during construction.
|
|
223
239
|
*/
|
|
224
240
|
get id() {
|
|
225
241
|
return this.#id;
|
|
@@ -249,12 +265,12 @@ export class Entity {
|
|
|
249
265
|
return EntitySnapshots.clone(this.#schema, this.#state);
|
|
250
266
|
}
|
|
251
267
|
/**
|
|
252
|
-
* Gets the
|
|
268
|
+
* Gets the current Spine Version without exposing the stored message.
|
|
253
269
|
*
|
|
254
|
-
* @returns A
|
|
270
|
+
* @returns A copy of the version number and timestamp.
|
|
255
271
|
*/
|
|
256
272
|
get version() {
|
|
257
|
-
return
|
|
273
|
+
return clone(VersionSchema, this.#version);
|
|
258
274
|
}
|
|
259
275
|
/**
|
|
260
276
|
* Gets the current lifecycle flag snapshot.
|
|
@@ -300,7 +316,7 @@ export class Entity {
|
|
|
300
316
|
return this.#lifecycleFlagsChanged;
|
|
301
317
|
}
|
|
302
318
|
/**
|
|
303
|
-
* Replaces stored state
|
|
319
|
+
* Replaces stored state when framework transaction code accepts a draft.
|
|
304
320
|
*
|
|
305
321
|
* @param state Next entity state snapshot.
|
|
306
322
|
*/
|
|
@@ -308,15 +324,15 @@ export class Entity {
|
|
|
308
324
|
this.#state = EntitySnapshots.clone(this.#schema, state);
|
|
309
325
|
}
|
|
310
326
|
/**
|
|
311
|
-
*
|
|
327
|
+
* Applies the Version calculated by a framework transaction.
|
|
312
328
|
*
|
|
313
|
-
* @param version
|
|
329
|
+
* @param version Accepted version number and timestamp.
|
|
314
330
|
*/
|
|
315
|
-
|
|
316
|
-
this.#version =
|
|
331
|
+
replaceVersion(version) {
|
|
332
|
+
this.#version = clone(VersionSchema, version);
|
|
317
333
|
}
|
|
318
334
|
/**
|
|
319
|
-
*
|
|
335
|
+
* Applies lifecycle flags accepted by framework transaction code.
|
|
320
336
|
*
|
|
321
337
|
* @param lifecycle Lifecycle flag changes to apply.
|
|
322
338
|
*/
|
|
@@ -366,21 +382,60 @@ const boundEntityHistories = new WeakMap();
|
|
|
366
382
|
* @internal
|
|
367
383
|
*/
|
|
368
384
|
export const entityHistoryAccess = Object.freeze({
|
|
385
|
+
/**
|
|
386
|
+
* Associates an Entity instance with its repository history operations.
|
|
387
|
+
*
|
|
388
|
+
* @param entity Entity instance loaded by the repository.
|
|
389
|
+
* @param binding Operations bound to that Entity's history.
|
|
390
|
+
*/
|
|
369
391
|
bind(entity, binding) {
|
|
370
392
|
boundEntityHistories.set(entity, binding);
|
|
371
393
|
},
|
|
394
|
+
/**
|
|
395
|
+
* Reads the most recent retained state no later than the requested time.
|
|
396
|
+
*
|
|
397
|
+
* @param entity Entity whose state is requested.
|
|
398
|
+
* @param time Latest allowed state timestamp.
|
|
399
|
+
* @returns The retained state, or undefined when none matches.
|
|
400
|
+
*/
|
|
372
401
|
stateAt(entity, time) {
|
|
373
402
|
return EntityHistory.require(entity).stateAt(time);
|
|
374
403
|
},
|
|
404
|
+
/**
|
|
405
|
+
* Reads retained states after checking the history read limit.
|
|
406
|
+
*
|
|
407
|
+
* @param entity Entity whose history is requested.
|
|
408
|
+
* @param depth Maximum number of states to return.
|
|
409
|
+
* @returns Retained states in descending version order.
|
|
410
|
+
*/
|
|
375
411
|
states(entity, depth) {
|
|
376
412
|
return EntityHistory.require(entity).states(EntityHistory.depth(depth));
|
|
377
413
|
},
|
|
414
|
+
/**
|
|
415
|
+
* Reads diagnostic Events after checking the history read limit.
|
|
416
|
+
*
|
|
417
|
+
* @param entity Entity that produced the Events.
|
|
418
|
+
* @param depth Maximum number of Events to return.
|
|
419
|
+
* @returns Retained Events in descending producer-version order.
|
|
420
|
+
*/
|
|
378
421
|
events(entity, depth) {
|
|
379
422
|
return EntityHistory.require(entity).events(EntityHistory.depth(depth));
|
|
380
423
|
},
|
|
424
|
+
/**
|
|
425
|
+
* Gets the state-history storage attached by the repository.
|
|
426
|
+
*
|
|
427
|
+
* @param entity Entity whose retained states are maintained.
|
|
428
|
+
* @returns Its state-history storage.
|
|
429
|
+
*/
|
|
381
430
|
stateMaintenance(entity) {
|
|
382
431
|
return EntityHistory.require(entity).stateMaintenance;
|
|
383
432
|
},
|
|
433
|
+
/**
|
|
434
|
+
* Gets diagnostic Event storage attached by the repository.
|
|
435
|
+
*
|
|
436
|
+
* @param entity Entity whose retained Events are maintained.
|
|
437
|
+
* @returns Its diagnostic Event storage.
|
|
438
|
+
*/
|
|
384
439
|
eventMaintenance(entity) {
|
|
385
440
|
return EntityHistory.require(entity).eventMaintenance;
|
|
386
441
|
},
|
|
@@ -389,6 +444,12 @@ export const entityHistoryAccess = Object.freeze({
|
|
|
389
444
|
* Validates repository-bound history lookups.
|
|
390
445
|
*/
|
|
391
446
|
const EntityHistory = Object.freeze({
|
|
447
|
+
/**
|
|
448
|
+
* Gets history operations installed during repository execution.
|
|
449
|
+
*
|
|
450
|
+
* @param entity Entity instance whose binding is required.
|
|
451
|
+
* @returns Its repository history operations.
|
|
452
|
+
*/
|
|
392
453
|
require(entity) {
|
|
393
454
|
const binding = boundEntityHistories.get(entity);
|
|
394
455
|
if (binding === undefined) {
|
|
@@ -396,6 +457,12 @@ const EntityHistory = Object.freeze({
|
|
|
396
457
|
}
|
|
397
458
|
return binding;
|
|
398
459
|
},
|
|
460
|
+
/**
|
|
461
|
+
* Rejects history read limits that are not positive safe integers.
|
|
462
|
+
*
|
|
463
|
+
* @param depth Requested history read limit.
|
|
464
|
+
* @returns The validated limit.
|
|
465
|
+
*/
|
|
399
466
|
depth(depth) {
|
|
400
467
|
if (!Number.isSafeInteger(depth) || depth <= 0) {
|
|
401
468
|
throw new RangeError("Entity history depth must be a positive safe integer.");
|
|
@@ -404,16 +471,15 @@ const EntityHistory = Object.freeze({
|
|
|
404
471
|
},
|
|
405
472
|
});
|
|
406
473
|
/**
|
|
407
|
-
*
|
|
474
|
+
* Entity base with one active transaction draft.
|
|
475
|
+
*
|
|
476
|
+
* Repository dispatch starts and finishes each transaction. Entity handlers
|
|
477
|
+
* change the draft state or lifecycle through protected helpers. A successful
|
|
478
|
+
* commit updates state, Spine Version, and lifecycle flags. A rejected commit
|
|
479
|
+
* leaves the draft active until the framework rolls it back.
|
|
408
480
|
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
* helpers, and then commit or roll back the scope. Accepted commits replace this
|
|
412
|
-
* entity's in-memory state, explicit version metadata, and lifecycle flags.
|
|
413
|
-
* Rejected commits leave the transaction active so subclass code can correct the
|
|
414
|
-
* draft or roll it back explicitly. This base does not write repositories,
|
|
415
|
-
* emit events, dispatch handlers, increment versions, or manage global
|
|
416
|
-
* transaction state.
|
|
481
|
+
* @typeParam Id Domain identifier type.
|
|
482
|
+
* @typeParam Schema Generated schema describing the Entity state.
|
|
417
483
|
*/
|
|
418
484
|
export class TransactionalEntity extends Entity {
|
|
419
485
|
#transaction;
|
|
@@ -449,7 +515,7 @@ export class TransactionalEntity extends Entity {
|
|
|
449
515
|
previous: this.state,
|
|
450
516
|
version: {
|
|
451
517
|
previous: previousVersion,
|
|
452
|
-
draft:
|
|
518
|
+
draft: clone(VersionSchema, previousVersion),
|
|
453
519
|
},
|
|
454
520
|
lifecycle: this.lifecycle,
|
|
455
521
|
});
|
|
@@ -463,19 +529,6 @@ export class TransactionalEntity extends Entity {
|
|
|
463
529
|
currentDraft() {
|
|
464
530
|
return this.#requireTransaction("currentDraft").currentDraft;
|
|
465
531
|
}
|
|
466
|
-
/**
|
|
467
|
-
* Gets the current draft version metadata snapshot.
|
|
468
|
-
*
|
|
469
|
-
* @returns Cloned previous and draft version metadata.
|
|
470
|
-
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
471
|
-
*/
|
|
472
|
-
draftVersionMetadata() {
|
|
473
|
-
const version = this.#requireTransaction("draftVersionMetadata").version;
|
|
474
|
-
return {
|
|
475
|
-
previous: EntityVersions.clone(version.previous),
|
|
476
|
-
draft: EntityVersions.clone(version.draft),
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
532
|
/**
|
|
480
533
|
* Gets the current draft lifecycle flag snapshot.
|
|
481
534
|
*
|
|
@@ -508,17 +561,6 @@ export class TransactionalEntity extends Entity {
|
|
|
508
561
|
tryUpdate(mutator) {
|
|
509
562
|
return this.#requireTransaction("tryUpdate").tryUpdate(mutator);
|
|
510
563
|
}
|
|
511
|
-
/**
|
|
512
|
-
* Updates the buffered draft version metadata without computing version increments.
|
|
513
|
-
*
|
|
514
|
-
* @param draft Caller-owned version metadata for the active draft.
|
|
515
|
-
* @returns Cloned previous and draft version metadata.
|
|
516
|
-
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
517
|
-
*/
|
|
518
|
-
updateDraftVersionMetadata(draft) {
|
|
519
|
-
this.#requireTransaction("updateDraftVersionMetadata").updateVersionMetadata(EntityVersions.clone(draft));
|
|
520
|
-
return this.draftVersionMetadata();
|
|
521
|
-
}
|
|
522
564
|
/**
|
|
523
565
|
* Marks the buffered draft lifecycle as archived.
|
|
524
566
|
*
|
|
@@ -558,23 +600,24 @@ export class TransactionalEntity extends Entity {
|
|
|
558
600
|
/**
|
|
559
601
|
* Commits the active draft transaction.
|
|
560
602
|
*
|
|
561
|
-
* Accepted commits apply state,
|
|
603
|
+
* Accepted commits apply state, Spine Version, and lifecycle flags to this
|
|
562
604
|
* entity and close the transaction. Rejected commits do not apply anything and
|
|
563
605
|
* keep the transaction active for correction or explicit rollback.
|
|
564
606
|
*
|
|
607
|
+
* @param producedEvents Whether handling returned Events, requiring a version advance.
|
|
565
608
|
* @returns A cloned accepted or rejected transaction result.
|
|
566
609
|
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
567
610
|
*/
|
|
568
|
-
commitTransaction() {
|
|
611
|
+
commitTransaction(producedEvents = false) {
|
|
569
612
|
const transaction = this.#requireTransaction("commitTransaction");
|
|
570
|
-
const result = transaction.commit();
|
|
613
|
+
const result = transaction.commit(producedEvents);
|
|
571
614
|
if (result.status === "accepted") {
|
|
572
615
|
if (result.previous === undefined ||
|
|
573
616
|
!EntitySnapshots.equal(this.schema, result.previous, result.next)) {
|
|
574
617
|
this.#stateChanged = true;
|
|
575
618
|
}
|
|
576
619
|
this.replaceState(result.next);
|
|
577
|
-
this.
|
|
620
|
+
this.replaceVersion(result.version.committed);
|
|
578
621
|
this.replaceLifecycleFlags(result.lifecycle);
|
|
579
622
|
this.#transaction = undefined;
|
|
580
623
|
rejectedCommits.delete(this);
|
|
@@ -595,6 +638,12 @@ export class TransactionalEntity extends Entity {
|
|
|
595
638
|
this.#transaction = undefined;
|
|
596
639
|
return result;
|
|
597
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* Gets the active transaction or rejects an out-of-scope operation.
|
|
643
|
+
*
|
|
644
|
+
* @param operation Draft operation being attempted.
|
|
645
|
+
* @returns The currently active transaction.
|
|
646
|
+
*/
|
|
598
647
|
#requireTransaction(operation) {
|
|
599
648
|
const transaction = this.#transaction;
|
|
600
649
|
if (transaction?.status !== "active") {
|
|
@@ -609,12 +658,29 @@ export class TransactionalEntity extends Entity {
|
|
|
609
658
|
* @internal
|
|
610
659
|
*/
|
|
611
660
|
export const transactionalEntityAccess = Object.freeze({
|
|
661
|
+
/**
|
|
662
|
+
* Starts the Entity's protected transaction before invoking its handler.
|
|
663
|
+
*
|
|
664
|
+
* @param entity Entity about to handle a signal.
|
|
665
|
+
*/
|
|
612
666
|
start(entity) {
|
|
613
667
|
TransactionAccess.call(entity, "startTransaction");
|
|
614
668
|
},
|
|
615
|
-
|
|
616
|
-
|
|
669
|
+
/**
|
|
670
|
+
* Commits the handler's draft and records whether it returned Events.
|
|
671
|
+
*
|
|
672
|
+
* @param entity Entity whose handler has completed.
|
|
673
|
+
* @param producedEvents Whether handling returned domain Events.
|
|
674
|
+
* @returns The accepted or validation-rejected transaction result.
|
|
675
|
+
*/
|
|
676
|
+
commit(entity, producedEvents = false) {
|
|
677
|
+
return TransactionAccess.call(entity, "commitTransaction", producedEvents);
|
|
617
678
|
},
|
|
679
|
+
/**
|
|
680
|
+
* Rolls back an active draft, ignoring a transaction that has already closed.
|
|
681
|
+
*
|
|
682
|
+
* @param entity Entity whose handling failed or was rejected.
|
|
683
|
+
*/
|
|
618
684
|
rollback(entity) {
|
|
619
685
|
try {
|
|
620
686
|
TransactionAccess.call(entity, "rollbackTransaction");
|
|
@@ -625,6 +691,12 @@ export const transactionalEntityAccess = Object.freeze({
|
|
|
625
691
|
}
|
|
626
692
|
}
|
|
627
693
|
},
|
|
694
|
+
/**
|
|
695
|
+
* Reads the validation failure retained for the Entity's latest rejected commit.
|
|
696
|
+
*
|
|
697
|
+
* @param entity Entity whose rejected result is requested.
|
|
698
|
+
* @returns A copy of the rejected result, or undefined when none is retained.
|
|
699
|
+
*/
|
|
628
700
|
rejectedCommit(entity) {
|
|
629
701
|
const rejected = rejectedCommits.get(entity);
|
|
630
702
|
return rejected === undefined
|
|
@@ -636,28 +708,44 @@ export const transactionalEntityAccess = Object.freeze({
|
|
|
636
708
|
* Bridges repository code to protected transactional entity methods.
|
|
637
709
|
*/
|
|
638
710
|
const TransactionAccess = Object.freeze({
|
|
639
|
-
|
|
711
|
+
/**
|
|
712
|
+
* Invokes a protected transaction method from repository code.
|
|
713
|
+
*
|
|
714
|
+
* @param entity Instance receiving the method call.
|
|
715
|
+
* @param methodName Transaction method to invoke.
|
|
716
|
+
* @param args Arguments passed to the transaction method.
|
|
717
|
+
* @returns The method's result.
|
|
718
|
+
*/
|
|
719
|
+
call(entity, methodName, ...args) {
|
|
640
720
|
const method = entity[methodName];
|
|
641
721
|
if (typeof method !== "function") {
|
|
642
722
|
throw new TypeError(`Transactional entity access requires "${methodName}".`);
|
|
643
723
|
}
|
|
644
|
-
return Reflect.apply(method, entity,
|
|
724
|
+
return Reflect.apply(method, entity, args);
|
|
645
725
|
},
|
|
726
|
+
/**
|
|
727
|
+
* Tests whether an operation failed because no transaction was active.
|
|
728
|
+
*
|
|
729
|
+
* @param error Failure returned by a transaction operation.
|
|
730
|
+
* @returns True only for a missing transaction scope.
|
|
731
|
+
*/
|
|
646
732
|
isMissing(error) {
|
|
647
733
|
return error instanceof TransactionalEntityScopeError && error.reason === "missing";
|
|
648
734
|
},
|
|
649
735
|
});
|
|
650
736
|
/**
|
|
651
|
-
*
|
|
737
|
+
* Base class for Aggregates with transactional state and Event-history access.
|
|
738
|
+
*
|
|
739
|
+
* Provides Aggregate family identity and protected repository-backed history
|
|
740
|
+
* methods. Repositories and bounded contexts handle dispatch, persistence, and
|
|
741
|
+
* Event publication; application handlers change state through draft helpers.
|
|
652
742
|
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* invocation. Repository-bound diagnostic event-history reads are declared
|
|
656
|
-
* below for the Aggregate family.
|
|
743
|
+
* @typeParam Id Domain identifier type.
|
|
744
|
+
* @typeParam Schema Generated schema describing the Aggregate state.
|
|
657
745
|
*/
|
|
658
746
|
export class Aggregate extends TransactionalEntity {
|
|
659
747
|
/**
|
|
660
|
-
* Creates an
|
|
748
|
+
* Creates an Aggregate from its identity, state, and metadata.
|
|
661
749
|
*
|
|
662
750
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
663
751
|
*/
|
|
@@ -694,15 +782,18 @@ export class Aggregate extends TransactionalEntity {
|
|
|
694
782
|
}
|
|
695
783
|
}
|
|
696
784
|
/**
|
|
697
|
-
*
|
|
785
|
+
* Base class for Projections with transactional state.
|
|
698
786
|
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
787
|
+
* Repositories and Bounded Contexts invoke Event handlers and persist state
|
|
788
|
+
* changes with the Projection's Version.
|
|
789
|
+
* Projections do not expose the diagnostic history methods of other families.
|
|
790
|
+
*
|
|
791
|
+
* @typeParam Id Domain identifier type.
|
|
792
|
+
* @typeParam Schema Generated schema describing the Projection state.
|
|
702
793
|
*/
|
|
703
794
|
export class Projection extends TransactionalEntity {
|
|
704
795
|
/**
|
|
705
|
-
* Creates a
|
|
796
|
+
* Creates a Projection from its identity, state, and metadata.
|
|
706
797
|
*
|
|
707
798
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
708
799
|
*/
|
|
@@ -712,15 +803,18 @@ export class Projection extends TransactionalEntity {
|
|
|
712
803
|
}
|
|
713
804
|
}
|
|
714
805
|
/**
|
|
715
|
-
*
|
|
806
|
+
* Base class for Process Managers coordinating a workflow through signals.
|
|
807
|
+
*
|
|
808
|
+
* Provides transactional state, protected Event-history access, and
|
|
809
|
+
* handler-scoped Projection reads through `select()`. Repositories and bounded
|
|
810
|
+
* contexts invoke handlers, persist changes, and deliver returned signals.
|
|
716
811
|
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
* injection, or handler invocation.
|
|
812
|
+
* @typeParam Id Domain identifier type.
|
|
813
|
+
* @typeParam Schema Generated schema describing the Process Manager state.
|
|
720
814
|
*/
|
|
721
815
|
export class ProcessManager extends TransactionalEntity {
|
|
722
816
|
/**
|
|
723
|
-
* Creates a
|
|
817
|
+
* Creates a Process Manager from its identity, state, and metadata.
|
|
724
818
|
*
|
|
725
819
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
726
820
|
*/
|
|
@@ -762,6 +856,8 @@ export class ProcessManager extends TransactionalEntity {
|
|
|
762
856
|
* handler. Reads use that signal's actor and tenant; they cannot mutate state
|
|
763
857
|
* or select a different tenant.
|
|
764
858
|
*
|
|
859
|
+
* @typeParam QuerySchema Generated Projection state schema to query.
|
|
860
|
+
* @typeParam Columns Descriptor-backed columns available for that schema.
|
|
765
861
|
* @param schema Projection state schema to query.
|
|
766
862
|
* @param columns Generated descriptor-backed columns for `schema`.
|
|
767
863
|
* @returns A read-only Entity query.
|
|
@@ -775,6 +871,12 @@ export class ProcessManager extends TransactionalEntity {
|
|
|
775
871
|
* Marks immutable entity families.
|
|
776
872
|
*/
|
|
777
873
|
const EntityFamilies = Object.freeze({
|
|
874
|
+
/**
|
|
875
|
+
* Records whether an Entity is an Aggregate, Projection, or Process Manager.
|
|
876
|
+
*
|
|
877
|
+
* @param entity Instance being constructed.
|
|
878
|
+
* @param family Kind of Entity being constructed.
|
|
879
|
+
*/
|
|
778
880
|
mark(entity, family) {
|
|
779
881
|
Object.defineProperty(entity, "entityFamily", {
|
|
780
882
|
configurable: false,
|
|
@@ -788,9 +890,26 @@ const EntityFamilies = Object.freeze({
|
|
|
788
890
|
* Creates entity-state snapshots and compares state bytes.
|
|
789
891
|
*/
|
|
790
892
|
const EntitySnapshots = Object.freeze({
|
|
893
|
+
/**
|
|
894
|
+
* Copies state through its schema, discarding unknown wire fields.
|
|
895
|
+
*
|
|
896
|
+
* @typeParam Schema Generated schema describing the state.
|
|
897
|
+
* @param schema Schema used for encoding and decoding.
|
|
898
|
+
* @param state State snapshot to copy.
|
|
899
|
+
* @returns An independent state message containing known fields.
|
|
900
|
+
*/
|
|
791
901
|
clone(schema, state) {
|
|
792
902
|
return fromBinary(schema, toBinary(schema, state, { writeUnknownFields: false }));
|
|
793
903
|
},
|
|
904
|
+
/**
|
|
905
|
+
* Compares the encoded known fields of two state snapshots.
|
|
906
|
+
*
|
|
907
|
+
* @typeParam Schema Generated schema shared by both snapshots.
|
|
908
|
+
* @param schema Schema used to encode the states.
|
|
909
|
+
* @param previous State before handling.
|
|
910
|
+
* @param next State after handling.
|
|
911
|
+
* @returns True when their encoded known fields are identical.
|
|
912
|
+
*/
|
|
794
913
|
equal(schema, previous, next) {
|
|
795
914
|
const previousBinary = toBinary(schema, previous, { writeUnknownFields: false });
|
|
796
915
|
const nextBinary = toBinary(schema, next, { writeUnknownFields: false });
|
|
@@ -799,16 +918,23 @@ const EntitySnapshots = Object.freeze({
|
|
|
799
918
|
},
|
|
800
919
|
});
|
|
801
920
|
/**
|
|
802
|
-
*
|
|
921
|
+
* Copies transaction version, lifecycle, and validation snapshots.
|
|
803
922
|
*/
|
|
804
923
|
const EntityCommits = Object.freeze({
|
|
924
|
+
/**
|
|
925
|
+
* Copies version, lifecycle, and validation messages in a transaction result.
|
|
926
|
+
*
|
|
927
|
+
* @typeParam Schema Generated schema describing the transaction's state.
|
|
928
|
+
* @param result Accepted or rejected transaction result.
|
|
929
|
+
* @returns A result with independent version and validation metadata.
|
|
930
|
+
*/
|
|
805
931
|
clone(result) {
|
|
806
932
|
if (result.status === "accepted") {
|
|
807
933
|
return {
|
|
808
934
|
...result,
|
|
809
935
|
version: {
|
|
810
|
-
previous:
|
|
811
|
-
committed:
|
|
936
|
+
previous: clone(VersionSchema, result.version.previous),
|
|
937
|
+
committed: clone(VersionSchema, result.version.committed),
|
|
812
938
|
},
|
|
813
939
|
lifecycle: { archived: result.lifecycle.archived, deleted: result.lifecycle.deleted },
|
|
814
940
|
validation: this.validation(result.validation),
|
|
@@ -817,13 +943,19 @@ const EntityCommits = Object.freeze({
|
|
|
817
943
|
return {
|
|
818
944
|
...result,
|
|
819
945
|
version: {
|
|
820
|
-
previous:
|
|
821
|
-
draft:
|
|
946
|
+
previous: clone(VersionSchema, result.version.previous),
|
|
947
|
+
draft: clone(VersionSchema, result.version.draft),
|
|
822
948
|
},
|
|
823
949
|
lifecycle: { archived: result.lifecycle.archived, deleted: result.lifecycle.deleted },
|
|
824
950
|
validation: this.validation(result.validation),
|
|
825
951
|
};
|
|
826
952
|
},
|
|
953
|
+
/**
|
|
954
|
+
* Copies validation errors without exposing the stored violation messages.
|
|
955
|
+
*
|
|
956
|
+
* @param validation State-transition validation result.
|
|
957
|
+
* @returns An independent valid result or cloned validation error.
|
|
958
|
+
*/
|
|
827
959
|
validation(validation) {
|
|
828
960
|
if (validation.valid) {
|
|
829
961
|
return { valid: true, violations: [], error: undefined };
|
|
@@ -836,146 +968,4 @@ const EntityCommits = Object.freeze({
|
|
|
836
968
|
};
|
|
837
969
|
},
|
|
838
970
|
});
|
|
839
|
-
const maxVersionMetadataDepth = 1_000;
|
|
840
|
-
/**
|
|
841
|
-
* Validates and clones caller-provided plain version metadata.
|
|
842
|
-
*/
|
|
843
|
-
const EntityVersions = Object.freeze({
|
|
844
|
-
clone(version) {
|
|
845
|
-
return this.value(version, "$", new WeakSet(), 0);
|
|
846
|
-
},
|
|
847
|
-
value(value, path, stack, depth) {
|
|
848
|
-
if (depth > maxVersionMetadataDepth) {
|
|
849
|
-
throw this.error(path, "excessive nesting depth");
|
|
850
|
-
}
|
|
851
|
-
if (value === null) {
|
|
852
|
-
return value;
|
|
853
|
-
}
|
|
854
|
-
switch (typeof value) {
|
|
855
|
-
case "string":
|
|
856
|
-
case "number":
|
|
857
|
-
case "boolean":
|
|
858
|
-
case "bigint":
|
|
859
|
-
case "symbol":
|
|
860
|
-
case "undefined":
|
|
861
|
-
return value;
|
|
862
|
-
case "function":
|
|
863
|
-
throw this.error(path, "function");
|
|
864
|
-
case "object":
|
|
865
|
-
return this.object(value, path, stack, depth);
|
|
866
|
-
}
|
|
867
|
-
},
|
|
868
|
-
object(value, path, stack, depth) {
|
|
869
|
-
if (isProxy(value))
|
|
870
|
-
throw this.error(path, "Proxy");
|
|
871
|
-
if (ArrayBuffer.isView(value))
|
|
872
|
-
throw this.error(path, this.kind(value));
|
|
873
|
-
if (value instanceof ArrayBuffer || this.isSharedBuffer(value)) {
|
|
874
|
-
throw this.error(path, this.kind(value));
|
|
875
|
-
}
|
|
876
|
-
if (stack.has(value))
|
|
877
|
-
throw this.error(path, "cyclic object");
|
|
878
|
-
stack.add(value);
|
|
879
|
-
try {
|
|
880
|
-
if (Array.isArray(value))
|
|
881
|
-
return this.array(value, path, stack, depth);
|
|
882
|
-
if (!this.isPlainObject(value))
|
|
883
|
-
throw this.error(path, this.kind(value));
|
|
884
|
-
const clone = Object.create(this.prototype(value));
|
|
885
|
-
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
886
|
-
const [symbolKey] = Object.getOwnPropertySymbols(descriptors);
|
|
887
|
-
if (symbolKey !== undefined) {
|
|
888
|
-
throw this.error(`${path}[${String(symbolKey)}]`, "symbol-keyed property");
|
|
889
|
-
}
|
|
890
|
-
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
891
|
-
const childPath = `${path}.${key}`;
|
|
892
|
-
if (!descriptor.enumerable)
|
|
893
|
-
throw this.error(childPath, "non-enumerable property");
|
|
894
|
-
if (!("value" in descriptor))
|
|
895
|
-
throw this.error(childPath, "accessor property");
|
|
896
|
-
Object.defineProperty(clone, key, {
|
|
897
|
-
configurable: true,
|
|
898
|
-
enumerable: true,
|
|
899
|
-
value: this.value(descriptor.value, childPath, stack, depth + 1),
|
|
900
|
-
writable: true,
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
return clone;
|
|
904
|
-
}
|
|
905
|
-
finally {
|
|
906
|
-
stack.delete(value);
|
|
907
|
-
}
|
|
908
|
-
},
|
|
909
|
-
array(value, path, stack, depth) {
|
|
910
|
-
if (this.prototype(value) !== Array.prototype)
|
|
911
|
-
throw this.error(path, "Array");
|
|
912
|
-
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
913
|
-
const [symbolKey] = Object.getOwnPropertySymbols(descriptors);
|
|
914
|
-
if (symbolKey !== undefined) {
|
|
915
|
-
throw this.error(`${path}[${String(symbolKey)}]`, "symbol-keyed property");
|
|
916
|
-
}
|
|
917
|
-
const lengthDescriptor = descriptors.length;
|
|
918
|
-
if (lengthDescriptor === undefined || !("value" in lengthDescriptor)) {
|
|
919
|
-
throw this.error(path, "array without data length");
|
|
920
|
-
}
|
|
921
|
-
const length = lengthDescriptor.value;
|
|
922
|
-
const clone = new Array(length);
|
|
923
|
-
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
924
|
-
if (key === "length")
|
|
925
|
-
continue;
|
|
926
|
-
if (!this.isArrayKey(key, length))
|
|
927
|
-
throw this.error(`${path}.${key}`, "custom array property");
|
|
928
|
-
if (!descriptor.enumerable)
|
|
929
|
-
throw this.error(`${path}[${key}]`, "non-enumerable property");
|
|
930
|
-
if (!("value" in descriptor))
|
|
931
|
-
throw this.error(`${path}[${key}]`, "accessor property");
|
|
932
|
-
}
|
|
933
|
-
for (let index = 0; index < length; index += 1) {
|
|
934
|
-
const key = String(index);
|
|
935
|
-
const descriptor = descriptors[key];
|
|
936
|
-
if (descriptor === undefined || !("value" in descriptor)) {
|
|
937
|
-
throw this.error(`${path}[${key}]`, "sparse array element");
|
|
938
|
-
}
|
|
939
|
-
Object.defineProperty(clone, index, {
|
|
940
|
-
configurable: true,
|
|
941
|
-
enumerable: true,
|
|
942
|
-
value: this.value(descriptor.value, `${path}[${key}]`, stack, depth + 1),
|
|
943
|
-
writable: true,
|
|
944
|
-
});
|
|
945
|
-
}
|
|
946
|
-
return clone;
|
|
947
|
-
},
|
|
948
|
-
isArrayKey(key, length) {
|
|
949
|
-
const index = Number(key);
|
|
950
|
-
return Number.isInteger(index) && index >= 0 && index < length && String(index) === key;
|
|
951
|
-
},
|
|
952
|
-
isPlainObject(value) {
|
|
953
|
-
const prototype = this.prototype(value);
|
|
954
|
-
return prototype === Object.prototype || prototype === null;
|
|
955
|
-
},
|
|
956
|
-
prototype(value) {
|
|
957
|
-
return Object.getPrototypeOf(value);
|
|
958
|
-
},
|
|
959
|
-
kind(value) {
|
|
960
|
-
if (value instanceof Date)
|
|
961
|
-
return "Date";
|
|
962
|
-
if (value instanceof Map)
|
|
963
|
-
return "Map";
|
|
964
|
-
if (value instanceof Set)
|
|
965
|
-
return "Set";
|
|
966
|
-
if (ArrayBuffer.isView(value))
|
|
967
|
-
return "typed array";
|
|
968
|
-
if (value instanceof ArrayBuffer)
|
|
969
|
-
return "ArrayBuffer";
|
|
970
|
-
if (this.isSharedBuffer(value))
|
|
971
|
-
return "SharedArrayBuffer";
|
|
972
|
-
return "object";
|
|
973
|
-
},
|
|
974
|
-
isSharedBuffer(value) {
|
|
975
|
-
return typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
|
|
976
|
-
},
|
|
977
|
-
error(path, kind) {
|
|
978
|
-
return new TypeError(`Entity version metadata must be plain snapshot data; ${path} contains ${kind}.`);
|
|
979
|
-
},
|
|
980
|
-
});
|
|
981
971
|
//# sourceMappingURL=entity.js.map
|