@spine-event-engine/server 2.0.0-snapshot.12 → 2.0.0-snapshot.15
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 +18 -0
- package/REFERENCE.md +93 -7
- 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 +132 -84
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +213 -217
- 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 +137 -20
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +2589 -282
- 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 -13
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,17 @@ 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.
|
|
188
203
|
*
|
|
189
204
|
* The shell exposes identity, descriptor-derived metadata, cloned state
|
|
190
|
-
* snapshots,
|
|
205
|
+
* snapshots, Spine Version snapshots, and lifecycle flags. It does not
|
|
191
206
|
* invoke handlers, create transactions, write repositories or storage, dispatch
|
|
192
207
|
* messages, increment versions, route IDs, query read models, start buses, or
|
|
193
208
|
* mutate process-wide runtime state.
|
|
209
|
+
*
|
|
210
|
+
* @typeParam Id Domain identifier type.
|
|
211
|
+
* @typeParam Schema Generated schema describing the Entity state.
|
|
194
212
|
*/
|
|
195
213
|
export class Entity {
|
|
196
214
|
#id;
|
|
@@ -210,7 +228,7 @@ export class Entity {
|
|
|
210
228
|
this.#schema = options.schema;
|
|
211
229
|
this.#metadata = describeEntityMetadata(options.schema);
|
|
212
230
|
this.#state = EntitySnapshots.clone(options.schema, options.state);
|
|
213
|
-
this.#version =
|
|
231
|
+
this.#version = clone(VersionSchema, options.version ?? create(VersionSchema));
|
|
214
232
|
this.#lifecycle = {
|
|
215
233
|
archived: options.lifecycle?.archived ?? false,
|
|
216
234
|
deleted: options.lifecycle?.deleted ?? false,
|
|
@@ -219,7 +237,7 @@ export class Entity {
|
|
|
219
237
|
/**
|
|
220
238
|
* Gets the stable entity identifier.
|
|
221
239
|
*
|
|
222
|
-
* @returns The
|
|
240
|
+
* @returns The domain identifier supplied during construction.
|
|
223
241
|
*/
|
|
224
242
|
get id() {
|
|
225
243
|
return this.#id;
|
|
@@ -249,12 +267,12 @@ export class Entity {
|
|
|
249
267
|
return EntitySnapshots.clone(this.#schema, this.#state);
|
|
250
268
|
}
|
|
251
269
|
/**
|
|
252
|
-
* Gets the
|
|
270
|
+
* Gets the current Spine Version without exposing the stored message.
|
|
253
271
|
*
|
|
254
|
-
* @returns A
|
|
272
|
+
* @returns A copy of the version number and timestamp.
|
|
255
273
|
*/
|
|
256
274
|
get version() {
|
|
257
|
-
return
|
|
275
|
+
return clone(VersionSchema, this.#version);
|
|
258
276
|
}
|
|
259
277
|
/**
|
|
260
278
|
* Gets the current lifecycle flag snapshot.
|
|
@@ -300,7 +318,7 @@ export class Entity {
|
|
|
300
318
|
return this.#lifecycleFlagsChanged;
|
|
301
319
|
}
|
|
302
320
|
/**
|
|
303
|
-
* Replaces stored state
|
|
321
|
+
* Replaces stored state when framework transaction code accepts a draft.
|
|
304
322
|
*
|
|
305
323
|
* @param state Next entity state snapshot.
|
|
306
324
|
*/
|
|
@@ -308,15 +326,15 @@ export class Entity {
|
|
|
308
326
|
this.#state = EntitySnapshots.clone(this.#schema, state);
|
|
309
327
|
}
|
|
310
328
|
/**
|
|
311
|
-
*
|
|
329
|
+
* Applies the Version calculated by a framework transaction.
|
|
312
330
|
*
|
|
313
|
-
* @param version
|
|
331
|
+
* @param version Accepted version number and timestamp.
|
|
314
332
|
*/
|
|
315
|
-
|
|
316
|
-
this.#version =
|
|
333
|
+
replaceVersion(version) {
|
|
334
|
+
this.#version = clone(VersionSchema, version);
|
|
317
335
|
}
|
|
318
336
|
/**
|
|
319
|
-
*
|
|
337
|
+
* Applies lifecycle flags accepted by framework transaction code.
|
|
320
338
|
*
|
|
321
339
|
* @param lifecycle Lifecycle flag changes to apply.
|
|
322
340
|
*/
|
|
@@ -366,21 +384,60 @@ const boundEntityHistories = new WeakMap();
|
|
|
366
384
|
* @internal
|
|
367
385
|
*/
|
|
368
386
|
export const entityHistoryAccess = Object.freeze({
|
|
387
|
+
/**
|
|
388
|
+
* Associates an Entity instance with its repository history operations.
|
|
389
|
+
*
|
|
390
|
+
* @param entity Entity instance loaded by the repository.
|
|
391
|
+
* @param binding Operations bound to that Entity's history.
|
|
392
|
+
*/
|
|
369
393
|
bind(entity, binding) {
|
|
370
394
|
boundEntityHistories.set(entity, binding);
|
|
371
395
|
},
|
|
396
|
+
/**
|
|
397
|
+
* Reads the most recent retained state no later than the requested time.
|
|
398
|
+
*
|
|
399
|
+
* @param entity Entity whose state is requested.
|
|
400
|
+
* @param time Latest allowed state timestamp.
|
|
401
|
+
* @returns The retained state, or undefined when none matches.
|
|
402
|
+
*/
|
|
372
403
|
stateAt(entity, time) {
|
|
373
404
|
return EntityHistory.require(entity).stateAt(time);
|
|
374
405
|
},
|
|
406
|
+
/**
|
|
407
|
+
* Reads retained states after checking the history read limit.
|
|
408
|
+
*
|
|
409
|
+
* @param entity Entity whose history is requested.
|
|
410
|
+
* @param depth Maximum number of states to return.
|
|
411
|
+
* @returns Retained states in descending version order.
|
|
412
|
+
*/
|
|
375
413
|
states(entity, depth) {
|
|
376
414
|
return EntityHistory.require(entity).states(EntityHistory.depth(depth));
|
|
377
415
|
},
|
|
416
|
+
/**
|
|
417
|
+
* Reads diagnostic Events after checking the history read limit.
|
|
418
|
+
*
|
|
419
|
+
* @param entity Entity that produced the Events.
|
|
420
|
+
* @param depth Maximum number of Events to return.
|
|
421
|
+
* @returns Retained Events in descending producer-version order.
|
|
422
|
+
*/
|
|
378
423
|
events(entity, depth) {
|
|
379
424
|
return EntityHistory.require(entity).events(EntityHistory.depth(depth));
|
|
380
425
|
},
|
|
426
|
+
/**
|
|
427
|
+
* Gets the state-history storage attached by the repository.
|
|
428
|
+
*
|
|
429
|
+
* @param entity Entity whose retained states are maintained.
|
|
430
|
+
* @returns Its state-history storage.
|
|
431
|
+
*/
|
|
381
432
|
stateMaintenance(entity) {
|
|
382
433
|
return EntityHistory.require(entity).stateMaintenance;
|
|
383
434
|
},
|
|
435
|
+
/**
|
|
436
|
+
* Gets diagnostic Event storage attached by the repository.
|
|
437
|
+
*
|
|
438
|
+
* @param entity Entity whose retained Events are maintained.
|
|
439
|
+
* @returns Its diagnostic Event storage.
|
|
440
|
+
*/
|
|
384
441
|
eventMaintenance(entity) {
|
|
385
442
|
return EntityHistory.require(entity).eventMaintenance;
|
|
386
443
|
},
|
|
@@ -389,6 +446,12 @@ export const entityHistoryAccess = Object.freeze({
|
|
|
389
446
|
* Validates repository-bound history lookups.
|
|
390
447
|
*/
|
|
391
448
|
const EntityHistory = Object.freeze({
|
|
449
|
+
/**
|
|
450
|
+
* Gets history operations installed during repository execution.
|
|
451
|
+
*
|
|
452
|
+
* @param entity Entity instance whose binding is required.
|
|
453
|
+
* @returns Its repository history operations.
|
|
454
|
+
*/
|
|
392
455
|
require(entity) {
|
|
393
456
|
const binding = boundEntityHistories.get(entity);
|
|
394
457
|
if (binding === undefined) {
|
|
@@ -396,6 +459,12 @@ const EntityHistory = Object.freeze({
|
|
|
396
459
|
}
|
|
397
460
|
return binding;
|
|
398
461
|
},
|
|
462
|
+
/**
|
|
463
|
+
* Rejects history read limits that are not positive safe integers.
|
|
464
|
+
*
|
|
465
|
+
* @param depth Requested history read limit.
|
|
466
|
+
* @returns The validated limit.
|
|
467
|
+
*/
|
|
399
468
|
depth(depth) {
|
|
400
469
|
if (!Number.isSafeInteger(depth) || depth <= 0) {
|
|
401
470
|
throw new RangeError("Entity history depth must be a positive safe integer.");
|
|
@@ -404,16 +473,19 @@ const EntityHistory = Object.freeze({
|
|
|
404
473
|
},
|
|
405
474
|
});
|
|
406
475
|
/**
|
|
407
|
-
*
|
|
476
|
+
* Entity base with one active transaction draft.
|
|
408
477
|
*
|
|
409
478
|
* The transaction scope is backed by {@link EntityTransaction}. Subclasses can
|
|
410
|
-
* start one active draft, mutate draft state
|
|
479
|
+
* start one active draft, mutate draft state and lifecycle through protected
|
|
411
480
|
* helpers, and then commit or roll back the scope. Accepted commits replace this
|
|
412
|
-
*
|
|
481
|
+
* Entity's state, framework-calculated Spine Version, and lifecycle flags.
|
|
413
482
|
* Rejected commits leave the transaction active so subclass code can correct the
|
|
414
483
|
* draft or roll it back explicitly. This base does not write repositories,
|
|
415
|
-
* emit events, dispatch handlers,
|
|
484
|
+
* emit events, dispatch handlers, or manage global
|
|
416
485
|
* transaction state.
|
|
486
|
+
*
|
|
487
|
+
* @typeParam Id Domain identifier type.
|
|
488
|
+
* @typeParam Schema Generated schema describing the Entity state.
|
|
417
489
|
*/
|
|
418
490
|
export class TransactionalEntity extends Entity {
|
|
419
491
|
#transaction;
|
|
@@ -449,7 +521,7 @@ export class TransactionalEntity extends Entity {
|
|
|
449
521
|
previous: this.state,
|
|
450
522
|
version: {
|
|
451
523
|
previous: previousVersion,
|
|
452
|
-
draft:
|
|
524
|
+
draft: clone(VersionSchema, previousVersion),
|
|
453
525
|
},
|
|
454
526
|
lifecycle: this.lifecycle,
|
|
455
527
|
});
|
|
@@ -463,19 +535,6 @@ export class TransactionalEntity extends Entity {
|
|
|
463
535
|
currentDraft() {
|
|
464
536
|
return this.#requireTransaction("currentDraft").currentDraft;
|
|
465
537
|
}
|
|
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
538
|
/**
|
|
480
539
|
* Gets the current draft lifecycle flag snapshot.
|
|
481
540
|
*
|
|
@@ -508,17 +567,6 @@ export class TransactionalEntity extends Entity {
|
|
|
508
567
|
tryUpdate(mutator) {
|
|
509
568
|
return this.#requireTransaction("tryUpdate").tryUpdate(mutator);
|
|
510
569
|
}
|
|
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
570
|
/**
|
|
523
571
|
* Marks the buffered draft lifecycle as archived.
|
|
524
572
|
*
|
|
@@ -558,23 +606,24 @@ export class TransactionalEntity extends Entity {
|
|
|
558
606
|
/**
|
|
559
607
|
* Commits the active draft transaction.
|
|
560
608
|
*
|
|
561
|
-
* Accepted commits apply state,
|
|
609
|
+
* Accepted commits apply state, Spine Version, and lifecycle flags to this
|
|
562
610
|
* entity and close the transaction. Rejected commits do not apply anything and
|
|
563
611
|
* keep the transaction active for correction or explicit rollback.
|
|
564
612
|
*
|
|
613
|
+
* @param producedEvents Whether handling returned Events, requiring a version advance.
|
|
565
614
|
* @returns A cloned accepted or rejected transaction result.
|
|
566
615
|
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
567
616
|
*/
|
|
568
|
-
commitTransaction() {
|
|
617
|
+
commitTransaction(producedEvents = false) {
|
|
569
618
|
const transaction = this.#requireTransaction("commitTransaction");
|
|
570
|
-
const result = transaction.commit();
|
|
619
|
+
const result = transaction.commit(producedEvents);
|
|
571
620
|
if (result.status === "accepted") {
|
|
572
621
|
if (result.previous === undefined ||
|
|
573
622
|
!EntitySnapshots.equal(this.schema, result.previous, result.next)) {
|
|
574
623
|
this.#stateChanged = true;
|
|
575
624
|
}
|
|
576
625
|
this.replaceState(result.next);
|
|
577
|
-
this.
|
|
626
|
+
this.replaceVersion(result.version.committed);
|
|
578
627
|
this.replaceLifecycleFlags(result.lifecycle);
|
|
579
628
|
this.#transaction = undefined;
|
|
580
629
|
rejectedCommits.delete(this);
|
|
@@ -595,6 +644,12 @@ export class TransactionalEntity extends Entity {
|
|
|
595
644
|
this.#transaction = undefined;
|
|
596
645
|
return result;
|
|
597
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* Gets the active transaction or rejects an out-of-scope operation.
|
|
649
|
+
*
|
|
650
|
+
* @param operation Draft operation being attempted.
|
|
651
|
+
* @returns The currently active transaction.
|
|
652
|
+
*/
|
|
598
653
|
#requireTransaction(operation) {
|
|
599
654
|
const transaction = this.#transaction;
|
|
600
655
|
if (transaction?.status !== "active") {
|
|
@@ -609,12 +664,29 @@ export class TransactionalEntity extends Entity {
|
|
|
609
664
|
* @internal
|
|
610
665
|
*/
|
|
611
666
|
export const transactionalEntityAccess = Object.freeze({
|
|
667
|
+
/**
|
|
668
|
+
* Starts the Entity's protected transaction before invoking its handler.
|
|
669
|
+
*
|
|
670
|
+
* @param entity Entity about to handle a signal.
|
|
671
|
+
*/
|
|
612
672
|
start(entity) {
|
|
613
673
|
TransactionAccess.call(entity, "startTransaction");
|
|
614
674
|
},
|
|
615
|
-
|
|
616
|
-
|
|
675
|
+
/**
|
|
676
|
+
* Commits the handler's draft and records whether it returned Events.
|
|
677
|
+
*
|
|
678
|
+
* @param entity Entity whose handler has completed.
|
|
679
|
+
* @param producedEvents Whether handling returned domain Events.
|
|
680
|
+
* @returns The accepted or validation-rejected transaction result.
|
|
681
|
+
*/
|
|
682
|
+
commit(entity, producedEvents = false) {
|
|
683
|
+
return TransactionAccess.call(entity, "commitTransaction", producedEvents);
|
|
617
684
|
},
|
|
685
|
+
/**
|
|
686
|
+
* Rolls back an active draft, ignoring a transaction that has already closed.
|
|
687
|
+
*
|
|
688
|
+
* @param entity Entity whose handling failed or was rejected.
|
|
689
|
+
*/
|
|
618
690
|
rollback(entity) {
|
|
619
691
|
try {
|
|
620
692
|
TransactionAccess.call(entity, "rollbackTransaction");
|
|
@@ -625,6 +697,12 @@ export const transactionalEntityAccess = Object.freeze({
|
|
|
625
697
|
}
|
|
626
698
|
}
|
|
627
699
|
},
|
|
700
|
+
/**
|
|
701
|
+
* Reads the validation failure retained for the Entity's latest rejected commit.
|
|
702
|
+
*
|
|
703
|
+
* @param entity Entity whose rejected result is requested.
|
|
704
|
+
* @returns A copy of the rejected result, or undefined when none is retained.
|
|
705
|
+
*/
|
|
628
706
|
rejectedCommit(entity) {
|
|
629
707
|
const rejected = rejectedCommits.get(entity);
|
|
630
708
|
return rejected === undefined
|
|
@@ -636,28 +714,44 @@ export const transactionalEntityAccess = Object.freeze({
|
|
|
636
714
|
* Bridges repository code to protected transactional entity methods.
|
|
637
715
|
*/
|
|
638
716
|
const TransactionAccess = Object.freeze({
|
|
639
|
-
|
|
717
|
+
/**
|
|
718
|
+
* Invokes a protected transaction method from repository code.
|
|
719
|
+
*
|
|
720
|
+
* @param entity Instance receiving the method call.
|
|
721
|
+
* @param methodName Transaction method to invoke.
|
|
722
|
+
* @param args Arguments passed to the transaction method.
|
|
723
|
+
* @returns The method's result.
|
|
724
|
+
*/
|
|
725
|
+
call(entity, methodName, ...args) {
|
|
640
726
|
const method = entity[methodName];
|
|
641
727
|
if (typeof method !== "function") {
|
|
642
728
|
throw new TypeError(`Transactional entity access requires "${methodName}".`);
|
|
643
729
|
}
|
|
644
|
-
return Reflect.apply(method, entity,
|
|
730
|
+
return Reflect.apply(method, entity, args);
|
|
645
731
|
},
|
|
732
|
+
/**
|
|
733
|
+
* Tests whether an operation failed because no transaction was active.
|
|
734
|
+
*
|
|
735
|
+
* @param error Failure returned by a transaction operation.
|
|
736
|
+
* @returns True only for a missing transaction scope.
|
|
737
|
+
*/
|
|
646
738
|
isMissing(error) {
|
|
647
739
|
return error instanceof TransactionalEntityScopeError && error.reason === "missing";
|
|
648
740
|
},
|
|
649
741
|
});
|
|
650
742
|
/**
|
|
651
|
-
*
|
|
743
|
+
* Base class for Aggregates with transactional state and Event-history access.
|
|
744
|
+
*
|
|
745
|
+
* Provides Aggregate family identity and protected repository-backed history
|
|
746
|
+
* methods. Repositories and bounded contexts handle dispatch, persistence, and
|
|
747
|
+
* Event publication; application handlers change state through draft helpers.
|
|
652
748
|
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* invocation. Repository-bound diagnostic event-history reads are declared
|
|
656
|
-
* below for the Aggregate family.
|
|
749
|
+
* @typeParam Id Domain identifier type.
|
|
750
|
+
* @typeParam Schema Generated schema describing the Aggregate state.
|
|
657
751
|
*/
|
|
658
752
|
export class Aggregate extends TransactionalEntity {
|
|
659
753
|
/**
|
|
660
|
-
* Creates an
|
|
754
|
+
* Creates an Aggregate from its identity, state, and metadata.
|
|
661
755
|
*
|
|
662
756
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
663
757
|
*/
|
|
@@ -694,15 +788,18 @@ export class Aggregate extends TransactionalEntity {
|
|
|
694
788
|
}
|
|
695
789
|
}
|
|
696
790
|
/**
|
|
697
|
-
*
|
|
791
|
+
* Base class for Projections with transactional state.
|
|
698
792
|
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
793
|
+
* Provides Projection family identity. Repositories and bounded contexts invoke
|
|
794
|
+
* Event handlers and persist their state changes with the Projection's Version.
|
|
795
|
+
* Projections do not expose the diagnostic history methods of other families.
|
|
796
|
+
*
|
|
797
|
+
* @typeParam Id Domain identifier type.
|
|
798
|
+
* @typeParam Schema Generated schema describing the Projection state.
|
|
702
799
|
*/
|
|
703
800
|
export class Projection extends TransactionalEntity {
|
|
704
801
|
/**
|
|
705
|
-
* Creates a
|
|
802
|
+
* Creates a Projection from its identity, state, and metadata.
|
|
706
803
|
*
|
|
707
804
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
708
805
|
*/
|
|
@@ -712,15 +809,18 @@ export class Projection extends TransactionalEntity {
|
|
|
712
809
|
}
|
|
713
810
|
}
|
|
714
811
|
/**
|
|
715
|
-
*
|
|
812
|
+
* Base class for Process Managers coordinating a workflow through signals.
|
|
813
|
+
*
|
|
814
|
+
* Provides transactional state, protected Event-history access, and
|
|
815
|
+
* handler-scoped Projection reads through `select()`. Repositories and bounded
|
|
816
|
+
* contexts invoke handlers, persist changes, and deliver returned signals.
|
|
716
817
|
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
* injection, or handler invocation.
|
|
818
|
+
* @typeParam Id Domain identifier type.
|
|
819
|
+
* @typeParam Schema Generated schema describing the Process Manager state.
|
|
720
820
|
*/
|
|
721
821
|
export class ProcessManager extends TransactionalEntity {
|
|
722
822
|
/**
|
|
723
|
-
* Creates a
|
|
823
|
+
* Creates a Process Manager from its identity, state, and metadata.
|
|
724
824
|
*
|
|
725
825
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
726
826
|
*/
|
|
@@ -762,6 +862,8 @@ export class ProcessManager extends TransactionalEntity {
|
|
|
762
862
|
* handler. Reads use that signal's actor and tenant; they cannot mutate state
|
|
763
863
|
* or select a different tenant.
|
|
764
864
|
*
|
|
865
|
+
* @typeParam QuerySchema Generated Projection state schema to query.
|
|
866
|
+
* @typeParam Columns Descriptor-backed columns available for that schema.
|
|
765
867
|
* @param schema Projection state schema to query.
|
|
766
868
|
* @param columns Generated descriptor-backed columns for `schema`.
|
|
767
869
|
* @returns A read-only Entity query.
|
|
@@ -775,6 +877,12 @@ export class ProcessManager extends TransactionalEntity {
|
|
|
775
877
|
* Marks immutable entity families.
|
|
776
878
|
*/
|
|
777
879
|
const EntityFamilies = Object.freeze({
|
|
880
|
+
/**
|
|
881
|
+
* Sets an immutable family marker on an Entity instance.
|
|
882
|
+
*
|
|
883
|
+
* @param entity Instance being constructed.
|
|
884
|
+
* @param family Aggregate, Projection, or Process Manager family marker.
|
|
885
|
+
*/
|
|
778
886
|
mark(entity, family) {
|
|
779
887
|
Object.defineProperty(entity, "entityFamily", {
|
|
780
888
|
configurable: false,
|
|
@@ -788,9 +896,26 @@ const EntityFamilies = Object.freeze({
|
|
|
788
896
|
* Creates entity-state snapshots and compares state bytes.
|
|
789
897
|
*/
|
|
790
898
|
const EntitySnapshots = Object.freeze({
|
|
899
|
+
/**
|
|
900
|
+
* Copies state through its schema, discarding unknown wire fields.
|
|
901
|
+
*
|
|
902
|
+
* @typeParam Schema Generated schema describing the state.
|
|
903
|
+
* @param schema Schema used for encoding and decoding.
|
|
904
|
+
* @param state State snapshot to copy.
|
|
905
|
+
* @returns An independent state message containing known fields.
|
|
906
|
+
*/
|
|
791
907
|
clone(schema, state) {
|
|
792
908
|
return fromBinary(schema, toBinary(schema, state, { writeUnknownFields: false }));
|
|
793
909
|
},
|
|
910
|
+
/**
|
|
911
|
+
* Compares the encoded known fields of two state snapshots.
|
|
912
|
+
*
|
|
913
|
+
* @typeParam Schema Generated schema shared by both snapshots.
|
|
914
|
+
* @param schema Schema used to encode the states.
|
|
915
|
+
* @param previous State before handling.
|
|
916
|
+
* @param next State after handling.
|
|
917
|
+
* @returns True when their encoded known fields are identical.
|
|
918
|
+
*/
|
|
794
919
|
equal(schema, previous, next) {
|
|
795
920
|
const previousBinary = toBinary(schema, previous, { writeUnknownFields: false });
|
|
796
921
|
const nextBinary = toBinary(schema, next, { writeUnknownFields: false });
|
|
@@ -799,16 +924,23 @@ const EntitySnapshots = Object.freeze({
|
|
|
799
924
|
},
|
|
800
925
|
});
|
|
801
926
|
/**
|
|
802
|
-
*
|
|
927
|
+
* Copies transaction version, lifecycle, and validation snapshots.
|
|
803
928
|
*/
|
|
804
929
|
const EntityCommits = Object.freeze({
|
|
930
|
+
/**
|
|
931
|
+
* Copies version, lifecycle, and validation messages in a transaction result.
|
|
932
|
+
*
|
|
933
|
+
* @typeParam Schema Generated schema describing the transaction's state.
|
|
934
|
+
* @param result Accepted or rejected transaction result.
|
|
935
|
+
* @returns A result with independent version and validation metadata.
|
|
936
|
+
*/
|
|
805
937
|
clone(result) {
|
|
806
938
|
if (result.status === "accepted") {
|
|
807
939
|
return {
|
|
808
940
|
...result,
|
|
809
941
|
version: {
|
|
810
|
-
previous:
|
|
811
|
-
committed:
|
|
942
|
+
previous: clone(VersionSchema, result.version.previous),
|
|
943
|
+
committed: clone(VersionSchema, result.version.committed),
|
|
812
944
|
},
|
|
813
945
|
lifecycle: { archived: result.lifecycle.archived, deleted: result.lifecycle.deleted },
|
|
814
946
|
validation: this.validation(result.validation),
|
|
@@ -817,13 +949,19 @@ const EntityCommits = Object.freeze({
|
|
|
817
949
|
return {
|
|
818
950
|
...result,
|
|
819
951
|
version: {
|
|
820
|
-
previous:
|
|
821
|
-
draft:
|
|
952
|
+
previous: clone(VersionSchema, result.version.previous),
|
|
953
|
+
draft: clone(VersionSchema, result.version.draft),
|
|
822
954
|
},
|
|
823
955
|
lifecycle: { archived: result.lifecycle.archived, deleted: result.lifecycle.deleted },
|
|
824
956
|
validation: this.validation(result.validation),
|
|
825
957
|
};
|
|
826
958
|
},
|
|
959
|
+
/**
|
|
960
|
+
* Copies validation errors without exposing the stored violation messages.
|
|
961
|
+
*
|
|
962
|
+
* @param validation State-transition validation result.
|
|
963
|
+
* @returns An independent valid result or cloned validation error.
|
|
964
|
+
*/
|
|
827
965
|
validation(validation) {
|
|
828
966
|
if (validation.valid) {
|
|
829
967
|
return { valid: true, violations: [], error: undefined };
|
|
@@ -836,146 +974,4 @@ const EntityCommits = Object.freeze({
|
|
|
836
974
|
};
|
|
837
975
|
},
|
|
838
976
|
});
|
|
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
977
|
//# sourceMappingURL=entity.js.map
|