@spine-event-engine/server 2.0.0-snapshot.2 → 2.0.0-snapshot.20
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 +225 -518
- package/REFERENCE.md +498 -49
- package/dist/browser/browser-server.d.ts +95 -0
- package/dist/browser/browser-server.d.ts.map +1 -0
- package/dist/{server → browser}/browser-server.js +93 -7
- package/dist/browser/browser-server.js.map +1 -0
- package/dist/browser/durable-subscription-bindings.d.ts.map +1 -0
- package/dist/browser/durable-subscription-bindings.js.map +1 -0
- package/dist/browser/index.d.ts +12 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +24 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/options.d.ts +183 -0
- package/dist/browser/options.d.ts.map +1 -0
- package/dist/browser/options.js +15 -0
- package/dist/browser/options.js.map +1 -0
- package/dist/bus/command-bus.d.ts +2 -0
- package/dist/bus/command-bus.d.ts.map +1 -1
- package/dist/bus/command-bus.js +36 -1
- package/dist/bus/command-bus.js.map +1 -1
- package/dist/bus/event-dispatcher-registry.d.ts +2 -2
- package/dist/bus/event-dispatcher-registry.js +3 -3
- package/dist/bus/event-dispatcher-registry.js.map +1 -1
- package/dist/context/bounded-context.d.ts +238 -83
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +1083 -286
- package/dist/context/bounded-context.js.map +1 -1
- package/dist/context/effective-tenant.d.ts +9 -0
- package/dist/context/effective-tenant.d.ts.map +1 -0
- package/dist/context/effective-tenant.js +58 -0
- package/dist/context/effective-tenant.js.map +1 -0
- package/dist/context/entity-inbox.d.ts.map +1 -1
- package/dist/context/entity-inbox.js +24 -17
- package/dist/context/entity-inbox.js.map +1 -1
- package/dist/context/local-inbox-handoff.d.ts +7 -3
- package/dist/context/local-inbox-handoff.d.ts.map +1 -1
- package/dist/context/local-inbox-handoff.js +32 -26
- package/dist/context/local-inbox-handoff.js.map +1 -1
- package/dist/context/projection-handoff.d.ts.map +1 -1
- package/dist/context/projection-handoff.js +36 -31
- package/dist/context/projection-handoff.js.map +1 -1
- package/dist/context/tenant-index.d.ts.map +1 -1
- package/dist/context/tenant-index.js +72 -2
- package/dist/context/tenant-index.js.map +1 -1
- package/dist/delivery/delivery-ports.d.ts +14 -4
- package/dist/delivery/delivery-ports.d.ts.map +1 -1
- package/dist/delivery/delivery.d.ts +19 -21
- package/dist/delivery/delivery.d.ts.map +1 -1
- package/dist/delivery/delivery.js +541 -158
- package/dist/delivery/delivery.js.map +1 -1
- package/dist/delivery/inbox-storage.d.ts +12 -3
- package/dist/delivery/inbox-storage.d.ts.map +1 -1
- package/dist/delivery/inbox-storage.js +160 -67
- package/dist/delivery/inbox-storage.js.map +1 -1
- package/dist/delivery/inbox.d.ts +9 -0
- package/dist/delivery/inbox.d.ts.map +1 -1
- package/dist/delivery/inbox.js +11 -0
- package/dist/delivery/inbox.js.map +1 -1
- package/dist/delivery/sharded-work-registry.d.ts.map +1 -1
- package/dist/delivery/sharded-work-registry.js +2 -1
- package/dist/delivery/sharded-work-registry.js.map +1 -1
- package/dist/entity/entity-metadata.d.ts +14 -5
- package/dist/entity/entity-metadata.d.ts.map +1 -1
- package/dist/entity/entity-metadata.js +38 -2
- package/dist/entity/entity-metadata.js.map +1 -1
- package/dist/entity/entity-storage-descriptor.d.ts +25 -5
- package/dist/entity/entity-storage-descriptor.d.ts.map +1 -1
- package/dist/entity/entity-storage-descriptor.js +69 -23
- package/dist/entity/entity-storage-descriptor.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 +243 -98
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +405 -226
- package/dist/entity/entity.js.map +1 -1
- package/dist/entity/spec-scanner.d.ts +13 -1
- package/dist/entity/spec-scanner.d.ts.map +1 -1
- package/dist/entity/spec-scanner.js +20 -3
- package/dist/entity/spec-scanner.js.map +1 -1
- package/dist/handler/command-registration-readiness.d.ts +6 -6
- package/dist/handler/command-registration-readiness.d.ts.map +1 -1
- package/dist/handler/command-registration-readiness.js +4 -2
- package/dist/handler/command-registration-readiness.js.map +1 -1
- package/dist/handler/declared-rejections.d.ts +11 -0
- package/dist/handler/declared-rejections.d.ts.map +1 -0
- package/dist/handler/declared-rejections.js +34 -0
- package/dist/handler/declared-rejections.js.map +1 -0
- 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 +72 -33
- package/dist/handler/generated-handler-registry.d.ts.map +1 -1
- package/dist/handler/generated-handler-registry.js +421 -43
- package/dist/handler/generated-handler-registry.js.map +1 -1
- package/dist/handler/generated-registry-discovery.d.ts.map +1 -1
- package/dist/handler/generated-registry-discovery.js +2 -4
- package/dist/handler/generated-registry-discovery.js.map +1 -1
- package/dist/handler/handler-decorators.d.ts +91 -37
- package/dist/handler/handler-decorators.d.ts.map +1 -1
- package/dist/handler/handler-decorators.js +124 -31
- package/dist/handler/handler-decorators.js.map +1 -1
- package/dist/handler/handler-metadata.d.ts +105 -60
- package/dist/handler/handler-metadata.d.ts.map +1 -1
- package/dist/handler/handler-metadata.js +275 -57
- 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 +84 -2
- package/dist/handler/registration-readiness-metadata.js.map +1 -1
- package/dist/handler/standalone.d.ts +25 -0
- package/dist/handler/standalone.d.ts.map +1 -0
- package/dist/handler/standalone.js +38 -0
- package/dist/handler/standalone.js.map +1 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/repository/command-routing.d.ts +63 -10
- package/dist/repository/command-routing.d.ts.map +1 -1
- package/dist/repository/command-routing.js +41 -8
- package/dist/repository/command-routing.js.map +1 -1
- package/dist/repository/event-routing.d.ts +64 -9
- package/dist/repository/event-routing.d.ts.map +1 -1
- package/dist/repository/event-routing.js +42 -7
- package/dist/repository/event-routing.js.map +1 -1
- package/dist/repository/primitive-id.d.ts +12 -23
- package/dist/repository/primitive-id.d.ts.map +1 -1
- package/dist/repository/primitive-id.js +2 -27
- package/dist/repository/primitive-id.js.map +1 -1
- package/dist/repository/repository.d.ts +317 -87
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +3746 -856
- package/dist/repository/repository.js.map +1 -1
- package/dist/repository/state-update-routing.d.ts +67 -8
- package/dist/repository/state-update-routing.d.ts.map +1 -1
- package/dist/repository/state-update-routing.js +45 -6
- package/dist/repository/state-update-routing.js.map +1 -1
- package/dist/runtime/runtime.js +1 -1
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/signal-metadata.d.ts +22 -47
- package/dist/runtime/signal-metadata.d.ts.map +1 -1
- package/dist/runtime/signal-metadata.js +34 -69
- package/dist/runtime/signal-metadata.js.map +1 -1
- package/dist/runtime/signal-publisher.d.ts +144 -0
- package/dist/runtime/signal-publisher.d.ts.map +1 -0
- package/dist/runtime/signal-publisher.js +248 -0
- package/dist/runtime/signal-publisher.js.map +1 -0
- package/dist/runtime/standalone-handler-runtime.d.ts +130 -0
- package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -0
- package/dist/runtime/standalone-handler-runtime.js +382 -0
- package/dist/runtime/standalone-handler-runtime.js.map +1 -0
- package/dist/server/environment-attachment.d.ts.map +1 -1
- package/dist/server/environment-attachment.js +2 -1
- package/dist/server/environment-attachment.js.map +1 -1
- package/dist/server/environment-delivery-worker.d.ts.map +1 -1
- package/dist/server/environment-delivery-worker.js +21 -12
- package/dist/server/environment-delivery-worker.js.map +1 -1
- package/dist/server/managed-server-application.d.ts +4 -1
- package/dist/server/managed-server-application.d.ts.map +1 -1
- package/dist/server/managed-server-application.js +2 -2
- package/dist/server/managed-server-application.js.map +1 -1
- package/dist/server/node-coordinator.js +2 -2
- package/dist/server/node-coordinator.js.map +1 -1
- package/dist/server/server-log.d.ts.map +1 -1
- package/dist/server/server-log.js +4 -0
- package/dist/server/server-log.js.map +1 -1
- package/dist/server/server.d.ts +9 -177
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +428 -178
- package/dist/server/server.js.map +1 -1
- package/dist/services/query-reader.d.ts +19 -0
- package/dist/services/query-reader.d.ts.map +1 -0
- package/dist/services/query-reader.js +43 -0
- package/dist/services/query-reader.js.map +1 -0
- package/dist/services/registered-targets.d.ts +73 -0
- package/dist/services/registered-targets.d.ts.map +1 -0
- package/dist/services/registered-targets.js +127 -0
- package/dist/services/registered-targets.js.map +1 -0
- package/dist/services/spine-services.d.ts +26 -12
- package/dist/services/spine-services.d.ts.map +1 -1
- package/dist/services/spine-services.js +1047 -969
- package/dist/services/spine-services.js.map +1 -1
- package/dist/spi/delivery.d.ts +5 -0
- package/dist/spi/delivery.d.ts.map +1 -0
- package/dist/spi/delivery.js +18 -0
- package/dist/spi/delivery.js.map +1 -0
- package/dist/spi/handler-registry.d.ts +8 -0
- package/dist/spi/handler-registry.d.ts.map +1 -0
- package/dist/spi/handler-registry.js +15 -0
- package/dist/spi/handler-registry.js.map +1 -0
- package/dist/stand/stand.d.ts +73 -1
- package/dist/stand/stand.d.ts.map +1 -1
- package/dist/stand/stand.js +221 -48
- package/dist/stand/stand.js.map +1 -1
- package/dist/stand/subscription-observer.d.ts.map +1 -1
- package/dist/stand/subscription-observer.js +5 -12
- package/dist/stand/subscription-observer.js.map +1 -1
- package/dist/stand/subscription-registry.js +1 -1
- package/dist/stand/subscription-registry.js.map +1 -1
- package/dist/testing/index.d.ts +25 -3
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +23 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +33 -23
- package/dist/handler/build-time-handler-analyzer.d.ts +0 -150
- package/dist/handler/build-time-handler-analyzer.d.ts.map +0 -1
- package/dist/handler/build-time-handler-analyzer.js +0 -1101
- package/dist/handler/build-time-handler-analyzer.js.map +0 -1
- package/dist/handler/generated-registry-writer.d.ts +0 -58
- package/dist/handler/generated-registry-writer.d.ts.map +0 -1
- package/dist/handler/generated-registry-writer.js +0 -458
- package/dist/handler/generated-registry-writer.js.map +0 -1
- package/dist/handler/handler-codegen.d.ts +0 -48
- package/dist/handler/handler-codegen.d.ts.map +0 -1
- package/dist/handler/handler-codegen.js +0 -214
- package/dist/handler/handler-codegen.js.map +0 -1
- package/dist/server/browser-server.d.ts +0 -49
- package/dist/server/browser-server.d.ts.map +0 -1
- package/dist/server/browser-server.js.map +0 -1
- package/dist/server/durable-subscription-bindings.d.ts.map +0 -1
- package/dist/server/durable-subscription-bindings.js.map +0 -1
- /package/dist/{server → browser}/durable-subscription-bindings.d.ts +0 -0
- /package/dist/{server → browser}/durable-subscription-bindings.js +0 -0
package/dist/entity/entity.js
CHANGED
|
@@ -11,10 +11,187 @@
|
|
|
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";
|
|
15
|
-
import {
|
|
14
|
+
import { clone, create, fromBinary, toBinary, } from "@bufbuild/protobuf";
|
|
15
|
+
import { EntityQuery, } from "@spine-event-engine/core";
|
|
16
|
+
import { EntityQueryDescription } from "@spine-event-engine/core/codegen";
|
|
17
|
+
import { VersionSchema, ActorContextSchema, ValidationErrorSchema, } from "@spine-event-engine/proto";
|
|
16
18
|
import { describeEntityMetadata, } from "./entity-metadata.js";
|
|
17
19
|
import { EntityTransaction, } from "./entity-transaction.js";
|
|
20
|
+
const processManagerQueries = new WeakMap();
|
|
21
|
+
/**
|
|
22
|
+
* Keeps Process Manager execution limits at the read boundary.
|
|
23
|
+
*/
|
|
24
|
+
const ProcessManagerQueryLimits = Object.freeze({
|
|
25
|
+
/**
|
|
26
|
+
* Rejects plans that exceed Process Manager result or explicit-ID limits.
|
|
27
|
+
*
|
|
28
|
+
* @param plan Compiled query plan to execute.
|
|
29
|
+
*/
|
|
30
|
+
check(plan) {
|
|
31
|
+
if (plan.limit !== undefined && plan.limit > 1_000) {
|
|
32
|
+
throw new TypeError("Process Manager query limit may be at most 1000.");
|
|
33
|
+
}
|
|
34
|
+
if (plan.predicate !== undefined && this.ids(plan.predicate) > 1_000) {
|
|
35
|
+
throw new TypeError("Process Manager query ID filter may contain at most 1000 IDs.");
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Returns the number of explicit IDs in a compiled predicate tree.
|
|
40
|
+
*
|
|
41
|
+
* @param predicate Compiled filter node.
|
|
42
|
+
* @returns Number of explicit IDs in that node.
|
|
43
|
+
*/
|
|
44
|
+
ids(predicate) {
|
|
45
|
+
if (predicate.kind === "ids")
|
|
46
|
+
return predicate.ids.length;
|
|
47
|
+
if (predicate.kind === "comparison")
|
|
48
|
+
return 0;
|
|
49
|
+
return predicate.predicates.reduce((total, child) => total + this.ids(child), 0);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Binds the repository-scoped query capability for one Process Manager invocation.
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
export const processManagerQueryAccess = Object.freeze({
|
|
58
|
+
/**
|
|
59
|
+
* Enables read-side queries for the duration of one handler invocation.
|
|
60
|
+
*
|
|
61
|
+
* @param entity Process Manager receiving the query capability.
|
|
62
|
+
* @param execute Repository operation that runs queries.
|
|
63
|
+
* @param actorContext Actor and tenant of the incoming signal.
|
|
64
|
+
* @returns A function that disables and removes this capability.
|
|
65
|
+
*/
|
|
66
|
+
bind(entity, execute, actorContext) {
|
|
67
|
+
const capability = {
|
|
68
|
+
execute,
|
|
69
|
+
actorContext: clone(ActorContextSchema, actorContext),
|
|
70
|
+
active: true,
|
|
71
|
+
};
|
|
72
|
+
processManagerQueries.set(entity, capability);
|
|
73
|
+
return () => {
|
|
74
|
+
capability.active = false;
|
|
75
|
+
processManagerQueries.delete(entity);
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Gets the query capability of a currently executing Process Manager.
|
|
80
|
+
*
|
|
81
|
+
* @param entity Process Manager attempting a query.
|
|
82
|
+
* @returns The active repository query capability.
|
|
83
|
+
*/
|
|
84
|
+
require(entity) {
|
|
85
|
+
const capability = processManagerQueries.get(entity);
|
|
86
|
+
if (capability?.active !== true) {
|
|
87
|
+
throw new Error("Process Manager queries are available only during repository handler execution.");
|
|
88
|
+
}
|
|
89
|
+
return capability;
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
/**
|
|
93
|
+
* A repository-scoped, read-only Entity query issued by a Process Manager.
|
|
94
|
+
*
|
|
95
|
+
* @typeParam Schema State schema read by the query.
|
|
96
|
+
* @typeParam Columns Registered descriptor-backed columns for `Schema`.
|
|
97
|
+
*/
|
|
98
|
+
export class ProcessManagerQuery {
|
|
99
|
+
#entity;
|
|
100
|
+
#schema;
|
|
101
|
+
#builder;
|
|
102
|
+
/**
|
|
103
|
+
* Creates the repository-scoped query facade.
|
|
104
|
+
*
|
|
105
|
+
* @internal
|
|
106
|
+
* @param entity Process Manager using this query capability.
|
|
107
|
+
* @param schema State schema read by this query.
|
|
108
|
+
* @param builder Typed query builder used to create the wire query.
|
|
109
|
+
*/
|
|
110
|
+
constructor(entity, schema, builder) {
|
|
111
|
+
this.#entity = entity;
|
|
112
|
+
this.#schema = schema;
|
|
113
|
+
this.#builder = builder;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Adds the supplied Entity IDs to the query target.
|
|
117
|
+
*
|
|
118
|
+
* @param ids Entity IDs to include.
|
|
119
|
+
* @returns This query for fluent configuration.
|
|
120
|
+
*/
|
|
121
|
+
byId(...ids) {
|
|
122
|
+
this.#builder.byId(...ids);
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Adds a typed state predicate to the query.
|
|
127
|
+
*
|
|
128
|
+
* @typeParam Predicate Comparison supported by the registered columns.
|
|
129
|
+
* @param predicate Predicate evaluated against registered state columns.
|
|
130
|
+
* @returns This query for fluent configuration.
|
|
131
|
+
*/
|
|
132
|
+
where(predicate) {
|
|
133
|
+
this.#builder.where(predicate);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Sets the ordering for matching states by one registered column.
|
|
138
|
+
*
|
|
139
|
+
* @typeParam Column Registered column supplying the ordered values.
|
|
140
|
+
* @param column Registered orderable column used for sorting.
|
|
141
|
+
* @param direction Optional sort direction, ascending by default.
|
|
142
|
+
* @returns This query for fluent configuration.
|
|
143
|
+
*/
|
|
144
|
+
orderBy(column, direction = "asc") {
|
|
145
|
+
this.#builder.orderBy(column, direction);
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Sets the returned-state limit to at most 1,000 entries.
|
|
150
|
+
*
|
|
151
|
+
* @param value Maximum number of states to return.
|
|
152
|
+
* @returns This query for fluent configuration.
|
|
153
|
+
*/
|
|
154
|
+
limit(value) {
|
|
155
|
+
if (value > 1_000) {
|
|
156
|
+
throw new TypeError("Process Manager query limit may be at most 1000.");
|
|
157
|
+
}
|
|
158
|
+
this.#builder.limit(value);
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Reads matching state snapshots from the eventually consistent query projection.
|
|
163
|
+
*
|
|
164
|
+
* @returns Readonly state snapshots, subject to the configured result limit.
|
|
165
|
+
*/
|
|
166
|
+
async read() {
|
|
167
|
+
const capability = processManagerQueryAccess.require(this.#entity);
|
|
168
|
+
const plan = this.#builder.buildPlan();
|
|
169
|
+
ProcessManagerQueryLimits.check(plan);
|
|
170
|
+
const states = await capability.execute(plan, this.#schema, this.#builder.build());
|
|
171
|
+
return Object.freeze(states.slice(0, 1_000));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Reads the first state snapshot for one Entity ID.
|
|
175
|
+
*
|
|
176
|
+
* @param id Entity ID to read.
|
|
177
|
+
* @returns The eventually consistent state snapshot, or `undefined` when it is absent.
|
|
178
|
+
*/
|
|
179
|
+
async findById(id) {
|
|
180
|
+
const states = await this.byId(id).read();
|
|
181
|
+
return states[0];
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Reads every matching state snapshot within the configured result limit.
|
|
185
|
+
*
|
|
186
|
+
* This can be more expensive than an ID-targeted read because the projection must evaluate all
|
|
187
|
+
* matching states.
|
|
188
|
+
*
|
|
189
|
+
* @returns Readonly eventually consistent state snapshots.
|
|
190
|
+
*/
|
|
191
|
+
async all() {
|
|
192
|
+
return await this.read();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
18
195
|
const rejectedCommits = new WeakMap();
|
|
19
196
|
/**
|
|
20
197
|
* Error thrown when a transactional entity draft helper is used outside its scope.
|
|
@@ -45,15 +222,15 @@ export class TransactionalEntityScopeError extends Error {
|
|
|
45
222
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
46
223
|
}
|
|
47
224
|
}
|
|
48
|
-
const isProxy = process.getBuiltinModule("node:util").types.isProxy;
|
|
49
225
|
/**
|
|
50
|
-
*
|
|
226
|
+
* Identity, state, version, and lifecycle of one server-side Entity.
|
|
227
|
+
*
|
|
228
|
+
* Keeps the Entity ID, state schema, state, Spine Version, and lifecycle flags.
|
|
229
|
+
* State and Version accessors return copies, and lifecycle access returns a
|
|
230
|
+
* separate flag object. Repositories run handlers and manage storage.
|
|
51
231
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* invoke handlers, create transactions, write repositories or storage, dispatch
|
|
55
|
-
* messages, increment versions, route IDs, query read models, start buses, or
|
|
56
|
-
* mutate process-wide runtime state.
|
|
232
|
+
* @typeParam Id Domain identifier type.
|
|
233
|
+
* @typeParam Schema Generated schema describing the Entity state.
|
|
57
234
|
*/
|
|
58
235
|
export class Entity {
|
|
59
236
|
#id;
|
|
@@ -64,7 +241,7 @@ export class Entity {
|
|
|
64
241
|
#lifecycle;
|
|
65
242
|
#lifecycleFlagsChanged = false;
|
|
66
243
|
/**
|
|
67
|
-
*
|
|
244
|
+
* Initializes an Entity from its ID, schema, state, Version, and lifecycle flags.
|
|
68
245
|
*
|
|
69
246
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
70
247
|
*/
|
|
@@ -73,7 +250,7 @@ export class Entity {
|
|
|
73
250
|
this.#schema = options.schema;
|
|
74
251
|
this.#metadata = describeEntityMetadata(options.schema);
|
|
75
252
|
this.#state = EntitySnapshots.clone(options.schema, options.state);
|
|
76
|
-
this.#version =
|
|
253
|
+
this.#version = clone(VersionSchema, options.version ?? create(VersionSchema));
|
|
77
254
|
this.#lifecycle = {
|
|
78
255
|
archived: options.lifecycle?.archived ?? false,
|
|
79
256
|
deleted: options.lifecycle?.deleted ?? false,
|
|
@@ -82,7 +259,7 @@ export class Entity {
|
|
|
82
259
|
/**
|
|
83
260
|
* Gets the stable entity identifier.
|
|
84
261
|
*
|
|
85
|
-
* @returns The
|
|
262
|
+
* @returns The domain identifier supplied during construction.
|
|
86
263
|
*/
|
|
87
264
|
get id() {
|
|
88
265
|
return this.#id;
|
|
@@ -112,12 +289,12 @@ export class Entity {
|
|
|
112
289
|
return EntitySnapshots.clone(this.#schema, this.#state);
|
|
113
290
|
}
|
|
114
291
|
/**
|
|
115
|
-
* Gets the
|
|
292
|
+
* Gets the current Spine Version without exposing the stored message.
|
|
116
293
|
*
|
|
117
|
-
* @returns A
|
|
294
|
+
* @returns A copy of the version number and timestamp.
|
|
118
295
|
*/
|
|
119
296
|
get version() {
|
|
120
|
-
return
|
|
297
|
+
return clone(VersionSchema, this.#version);
|
|
121
298
|
}
|
|
122
299
|
/**
|
|
123
300
|
* Gets the current lifecycle flag snapshot.
|
|
@@ -163,7 +340,7 @@ export class Entity {
|
|
|
163
340
|
return this.#lifecycleFlagsChanged;
|
|
164
341
|
}
|
|
165
342
|
/**
|
|
166
|
-
* Replaces stored state
|
|
343
|
+
* Replaces stored state when framework transaction code accepts a draft.
|
|
167
344
|
*
|
|
168
345
|
* @param state Next entity state snapshot.
|
|
169
346
|
*/
|
|
@@ -171,15 +348,15 @@ export class Entity {
|
|
|
171
348
|
this.#state = EntitySnapshots.clone(this.#schema, state);
|
|
172
349
|
}
|
|
173
350
|
/**
|
|
174
|
-
*
|
|
351
|
+
* Applies the Version calculated by a framework transaction.
|
|
175
352
|
*
|
|
176
|
-
* @param version
|
|
353
|
+
* @param version Accepted version number and timestamp.
|
|
177
354
|
*/
|
|
178
|
-
|
|
179
|
-
this.#version =
|
|
355
|
+
replaceVersion(version) {
|
|
356
|
+
this.#version = clone(VersionSchema, version);
|
|
180
357
|
}
|
|
181
358
|
/**
|
|
182
|
-
*
|
|
359
|
+
* Applies lifecycle flags accepted by framework transaction code.
|
|
183
360
|
*
|
|
184
361
|
* @param lifecycle Lifecycle flag changes to apply.
|
|
185
362
|
*/
|
|
@@ -229,21 +406,60 @@ const boundEntityHistories = new WeakMap();
|
|
|
229
406
|
* @internal
|
|
230
407
|
*/
|
|
231
408
|
export const entityHistoryAccess = Object.freeze({
|
|
409
|
+
/**
|
|
410
|
+
* Associates an Entity instance with its repository history operations.
|
|
411
|
+
*
|
|
412
|
+
* @param entity Entity instance loaded by the repository.
|
|
413
|
+
* @param binding Operations bound to that Entity's history.
|
|
414
|
+
*/
|
|
232
415
|
bind(entity, binding) {
|
|
233
416
|
boundEntityHistories.set(entity, binding);
|
|
234
417
|
},
|
|
418
|
+
/**
|
|
419
|
+
* Reads the most recent retained state no later than the requested time.
|
|
420
|
+
*
|
|
421
|
+
* @param entity Entity whose state is requested.
|
|
422
|
+
* @param time Latest allowed state timestamp.
|
|
423
|
+
* @returns The retained state, or undefined when none matches.
|
|
424
|
+
*/
|
|
235
425
|
stateAt(entity, time) {
|
|
236
426
|
return EntityHistory.require(entity).stateAt(time);
|
|
237
427
|
},
|
|
428
|
+
/**
|
|
429
|
+
* Reads retained states after checking the history read limit.
|
|
430
|
+
*
|
|
431
|
+
* @param entity Entity whose history is requested.
|
|
432
|
+
* @param depth Maximum number of states to return.
|
|
433
|
+
* @returns Retained states in descending version order.
|
|
434
|
+
*/
|
|
238
435
|
states(entity, depth) {
|
|
239
436
|
return EntityHistory.require(entity).states(EntityHistory.depth(depth));
|
|
240
437
|
},
|
|
438
|
+
/**
|
|
439
|
+
* Reads diagnostic Events after checking the history read limit.
|
|
440
|
+
*
|
|
441
|
+
* @param entity Entity that produced the Events.
|
|
442
|
+
* @param depth Maximum number of Events to return.
|
|
443
|
+
* @returns Retained Events in descending producer-version order.
|
|
444
|
+
*/
|
|
241
445
|
events(entity, depth) {
|
|
242
446
|
return EntityHistory.require(entity).events(EntityHistory.depth(depth));
|
|
243
447
|
},
|
|
448
|
+
/**
|
|
449
|
+
* Gets the state-history storage attached by the repository.
|
|
450
|
+
*
|
|
451
|
+
* @param entity Entity whose retained states are maintained.
|
|
452
|
+
* @returns Its state-history storage.
|
|
453
|
+
*/
|
|
244
454
|
stateMaintenance(entity) {
|
|
245
455
|
return EntityHistory.require(entity).stateMaintenance;
|
|
246
456
|
},
|
|
457
|
+
/**
|
|
458
|
+
* Gets diagnostic Event storage attached by the repository.
|
|
459
|
+
*
|
|
460
|
+
* @param entity Entity whose retained Events are maintained.
|
|
461
|
+
* @returns Its diagnostic Event storage.
|
|
462
|
+
*/
|
|
247
463
|
eventMaintenance(entity) {
|
|
248
464
|
return EntityHistory.require(entity).eventMaintenance;
|
|
249
465
|
},
|
|
@@ -252,6 +468,12 @@ export const entityHistoryAccess = Object.freeze({
|
|
|
252
468
|
* Validates repository-bound history lookups.
|
|
253
469
|
*/
|
|
254
470
|
const EntityHistory = Object.freeze({
|
|
471
|
+
/**
|
|
472
|
+
* Gets history operations installed during repository execution.
|
|
473
|
+
*
|
|
474
|
+
* @param entity Entity instance whose binding is required.
|
|
475
|
+
* @returns Its repository history operations.
|
|
476
|
+
*/
|
|
255
477
|
require(entity) {
|
|
256
478
|
const binding = boundEntityHistories.get(entity);
|
|
257
479
|
if (binding === undefined) {
|
|
@@ -259,6 +481,12 @@ const EntityHistory = Object.freeze({
|
|
|
259
481
|
}
|
|
260
482
|
return binding;
|
|
261
483
|
},
|
|
484
|
+
/**
|
|
485
|
+
* Rejects history read limits that are not positive safe integers.
|
|
486
|
+
*
|
|
487
|
+
* @param depth Requested history read limit.
|
|
488
|
+
* @returns The validated limit.
|
|
489
|
+
*/
|
|
262
490
|
depth(depth) {
|
|
263
491
|
if (!Number.isSafeInteger(depth) || depth <= 0) {
|
|
264
492
|
throw new RangeError("Entity history depth must be a positive safe integer.");
|
|
@@ -267,16 +495,15 @@ const EntityHistory = Object.freeze({
|
|
|
267
495
|
},
|
|
268
496
|
});
|
|
269
497
|
/**
|
|
270
|
-
*
|
|
498
|
+
* Entity base with one active transaction draft.
|
|
499
|
+
*
|
|
500
|
+
* Repository dispatch starts and finishes each transaction. Entity handlers
|
|
501
|
+
* change the draft state or lifecycle through protected helpers. A successful
|
|
502
|
+
* commit updates state, Spine Version, and lifecycle flags. A rejected commit
|
|
503
|
+
* leaves the draft active until the framework rolls it back.
|
|
271
504
|
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* helpers, and then commit or roll back the scope. Accepted commits replace this
|
|
275
|
-
* entity's in-memory state, explicit version metadata, and lifecycle flags.
|
|
276
|
-
* Rejected commits leave the transaction active so subclass code can correct the
|
|
277
|
-
* draft or roll it back explicitly. This base does not write repositories,
|
|
278
|
-
* emit events, dispatch handlers, increment versions, or manage global
|
|
279
|
-
* transaction state.
|
|
505
|
+
* @typeParam Id Domain identifier type.
|
|
506
|
+
* @typeParam Schema Generated schema describing the Entity state.
|
|
280
507
|
*/
|
|
281
508
|
export class TransactionalEntity extends Entity {
|
|
282
509
|
#transaction;
|
|
@@ -312,7 +539,7 @@ export class TransactionalEntity extends Entity {
|
|
|
312
539
|
previous: this.state,
|
|
313
540
|
version: {
|
|
314
541
|
previous: previousVersion,
|
|
315
|
-
draft:
|
|
542
|
+
draft: clone(VersionSchema, previousVersion),
|
|
316
543
|
},
|
|
317
544
|
lifecycle: this.lifecycle,
|
|
318
545
|
});
|
|
@@ -326,19 +553,6 @@ export class TransactionalEntity extends Entity {
|
|
|
326
553
|
currentDraft() {
|
|
327
554
|
return this.#requireTransaction("currentDraft").currentDraft;
|
|
328
555
|
}
|
|
329
|
-
/**
|
|
330
|
-
* Gets the current draft version metadata snapshot.
|
|
331
|
-
*
|
|
332
|
-
* @returns Cloned previous and draft version metadata.
|
|
333
|
-
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
334
|
-
*/
|
|
335
|
-
draftVersionMetadata() {
|
|
336
|
-
const version = this.#requireTransaction("draftVersionMetadata").version;
|
|
337
|
-
return {
|
|
338
|
-
previous: EntityVersions.clone(version.previous),
|
|
339
|
-
draft: EntityVersions.clone(version.draft),
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
556
|
/**
|
|
343
557
|
* Gets the current draft lifecycle flag snapshot.
|
|
344
558
|
*
|
|
@@ -371,17 +585,6 @@ export class TransactionalEntity extends Entity {
|
|
|
371
585
|
tryUpdate(mutator) {
|
|
372
586
|
return this.#requireTransaction("tryUpdate").tryUpdate(mutator);
|
|
373
587
|
}
|
|
374
|
-
/**
|
|
375
|
-
* Updates the buffered draft version metadata without computing version increments.
|
|
376
|
-
*
|
|
377
|
-
* @param draft Caller-owned version metadata for the active draft.
|
|
378
|
-
* @returns Cloned previous and draft version metadata.
|
|
379
|
-
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
380
|
-
*/
|
|
381
|
-
updateDraftVersionMetadata(draft) {
|
|
382
|
-
this.#requireTransaction("updateDraftVersionMetadata").updateVersionMetadata(EntityVersions.clone(draft));
|
|
383
|
-
return this.draftVersionMetadata();
|
|
384
|
-
}
|
|
385
588
|
/**
|
|
386
589
|
* Marks the buffered draft lifecycle as archived.
|
|
387
590
|
*
|
|
@@ -421,23 +624,24 @@ export class TransactionalEntity extends Entity {
|
|
|
421
624
|
/**
|
|
422
625
|
* Commits the active draft transaction.
|
|
423
626
|
*
|
|
424
|
-
* Accepted commits apply state,
|
|
627
|
+
* Accepted commits apply state, Spine Version, and lifecycle flags to this
|
|
425
628
|
* entity and close the transaction. Rejected commits do not apply anything and
|
|
426
629
|
* keep the transaction active for correction or explicit rollback.
|
|
427
630
|
*
|
|
631
|
+
* @param producedEvents Whether handling returned Events, requiring a version advance.
|
|
428
632
|
* @returns A cloned accepted or rejected transaction result.
|
|
429
633
|
* @throws {@link TransactionalEntityScopeError} when no transaction is active.
|
|
430
634
|
*/
|
|
431
|
-
commitTransaction() {
|
|
635
|
+
commitTransaction(producedEvents = false) {
|
|
432
636
|
const transaction = this.#requireTransaction("commitTransaction");
|
|
433
|
-
const result = transaction.commit();
|
|
637
|
+
const result = transaction.commit(producedEvents);
|
|
434
638
|
if (result.status === "accepted") {
|
|
435
639
|
if (result.previous === undefined ||
|
|
436
640
|
!EntitySnapshots.equal(this.schema, result.previous, result.next)) {
|
|
437
641
|
this.#stateChanged = true;
|
|
438
642
|
}
|
|
439
643
|
this.replaceState(result.next);
|
|
440
|
-
this.
|
|
644
|
+
this.replaceVersion(result.version.committed);
|
|
441
645
|
this.replaceLifecycleFlags(result.lifecycle);
|
|
442
646
|
this.#transaction = undefined;
|
|
443
647
|
rejectedCommits.delete(this);
|
|
@@ -458,6 +662,12 @@ export class TransactionalEntity extends Entity {
|
|
|
458
662
|
this.#transaction = undefined;
|
|
459
663
|
return result;
|
|
460
664
|
}
|
|
665
|
+
/**
|
|
666
|
+
* Gets the active transaction or rejects an out-of-scope operation.
|
|
667
|
+
*
|
|
668
|
+
* @param operation Draft operation being attempted.
|
|
669
|
+
* @returns The currently active transaction.
|
|
670
|
+
*/
|
|
461
671
|
#requireTransaction(operation) {
|
|
462
672
|
const transaction = this.#transaction;
|
|
463
673
|
if (transaction?.status !== "active") {
|
|
@@ -472,12 +682,29 @@ export class TransactionalEntity extends Entity {
|
|
|
472
682
|
* @internal
|
|
473
683
|
*/
|
|
474
684
|
export const transactionalEntityAccess = Object.freeze({
|
|
685
|
+
/**
|
|
686
|
+
* Starts the Entity's protected transaction before invoking its handler.
|
|
687
|
+
*
|
|
688
|
+
* @param entity Entity about to handle a signal.
|
|
689
|
+
*/
|
|
475
690
|
start(entity) {
|
|
476
691
|
TransactionAccess.call(entity, "startTransaction");
|
|
477
692
|
},
|
|
478
|
-
|
|
479
|
-
|
|
693
|
+
/**
|
|
694
|
+
* Commits the handler's draft and records whether it returned Events.
|
|
695
|
+
*
|
|
696
|
+
* @param entity Entity whose handler has completed.
|
|
697
|
+
* @param producedEvents Whether handling returned domain Events.
|
|
698
|
+
* @returns The accepted or validation-rejected transaction result.
|
|
699
|
+
*/
|
|
700
|
+
commit(entity, producedEvents = false) {
|
|
701
|
+
return TransactionAccess.call(entity, "commitTransaction", producedEvents);
|
|
480
702
|
},
|
|
703
|
+
/**
|
|
704
|
+
* Rolls back an active draft, ignoring a transaction that has already closed.
|
|
705
|
+
*
|
|
706
|
+
* @param entity Entity whose handling failed or was rejected.
|
|
707
|
+
*/
|
|
481
708
|
rollback(entity) {
|
|
482
709
|
try {
|
|
483
710
|
TransactionAccess.call(entity, "rollbackTransaction");
|
|
@@ -488,6 +715,12 @@ export const transactionalEntityAccess = Object.freeze({
|
|
|
488
715
|
}
|
|
489
716
|
}
|
|
490
717
|
},
|
|
718
|
+
/**
|
|
719
|
+
* Reads the validation failure retained for the Entity's latest rejected commit.
|
|
720
|
+
*
|
|
721
|
+
* @param entity Entity whose rejected result is requested.
|
|
722
|
+
* @returns A copy of the rejected result, or undefined when none is retained.
|
|
723
|
+
*/
|
|
491
724
|
rejectedCommit(entity) {
|
|
492
725
|
const rejected = rejectedCommits.get(entity);
|
|
493
726
|
return rejected === undefined
|
|
@@ -499,28 +732,44 @@ export const transactionalEntityAccess = Object.freeze({
|
|
|
499
732
|
* Bridges repository code to protected transactional entity methods.
|
|
500
733
|
*/
|
|
501
734
|
const TransactionAccess = Object.freeze({
|
|
502
|
-
|
|
735
|
+
/**
|
|
736
|
+
* Invokes a protected transaction method from repository code.
|
|
737
|
+
*
|
|
738
|
+
* @param entity Instance receiving the method call.
|
|
739
|
+
* @param methodName Transaction method to invoke.
|
|
740
|
+
* @param args Arguments passed to the transaction method.
|
|
741
|
+
* @returns The method's result.
|
|
742
|
+
*/
|
|
743
|
+
call(entity, methodName, ...args) {
|
|
503
744
|
const method = entity[methodName];
|
|
504
745
|
if (typeof method !== "function") {
|
|
505
746
|
throw new TypeError(`Transactional entity access requires "${methodName}".`);
|
|
506
747
|
}
|
|
507
|
-
return Reflect.apply(method, entity,
|
|
748
|
+
return Reflect.apply(method, entity, args);
|
|
508
749
|
},
|
|
750
|
+
/**
|
|
751
|
+
* Tests whether an operation failed because no transaction was active.
|
|
752
|
+
*
|
|
753
|
+
* @param error Failure returned by a transaction operation.
|
|
754
|
+
* @returns True only for a missing transaction scope.
|
|
755
|
+
*/
|
|
509
756
|
isMissing(error) {
|
|
510
757
|
return error instanceof TransactionalEntityScopeError && error.reason === "missing";
|
|
511
758
|
},
|
|
512
759
|
});
|
|
513
760
|
/**
|
|
514
|
-
*
|
|
761
|
+
* Base class for Aggregates with transactional state and Event-history access.
|
|
762
|
+
*
|
|
763
|
+
* Provides Aggregate family identity and protected repository-backed history
|
|
764
|
+
* methods. Repositories and bounded contexts handle dispatch, persistence, and
|
|
765
|
+
* Event publication; application handlers change state through draft helpers.
|
|
515
766
|
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* invocation. Repository-bound diagnostic event-history reads are declared
|
|
519
|
-
* below for the Aggregate family.
|
|
767
|
+
* @typeParam Id Domain identifier type.
|
|
768
|
+
* @typeParam Schema Generated schema describing the Aggregate state.
|
|
520
769
|
*/
|
|
521
770
|
export class Aggregate extends TransactionalEntity {
|
|
522
771
|
/**
|
|
523
|
-
* Creates an
|
|
772
|
+
* Creates an Aggregate from its identity, state, and metadata.
|
|
524
773
|
*
|
|
525
774
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
526
775
|
*/
|
|
@@ -557,15 +806,18 @@ export class Aggregate extends TransactionalEntity {
|
|
|
557
806
|
}
|
|
558
807
|
}
|
|
559
808
|
/**
|
|
560
|
-
*
|
|
809
|
+
* Base class for Projections with transactional state.
|
|
810
|
+
*
|
|
811
|
+
* Repositories and Bounded Contexts invoke Event handlers and persist state
|
|
812
|
+
* changes with the Projection's Version.
|
|
813
|
+
* Projections do not expose the diagnostic history methods of other families.
|
|
561
814
|
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
* clients, or handler invocation.
|
|
815
|
+
* @typeParam Id Domain identifier type.
|
|
816
|
+
* @typeParam Schema Generated schema describing the Projection state.
|
|
565
817
|
*/
|
|
566
818
|
export class Projection extends TransactionalEntity {
|
|
567
819
|
/**
|
|
568
|
-
* Creates a
|
|
820
|
+
* Creates a Projection from its identity, state, and metadata.
|
|
569
821
|
*
|
|
570
822
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
571
823
|
*/
|
|
@@ -575,15 +827,18 @@ export class Projection extends TransactionalEntity {
|
|
|
575
827
|
}
|
|
576
828
|
}
|
|
577
829
|
/**
|
|
578
|
-
*
|
|
830
|
+
* Base class for Process Managers coordinating a workflow through signals.
|
|
579
831
|
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
832
|
+
* Provides transactional state, protected Event-history access, and
|
|
833
|
+
* handler-scoped queryable Entity-state reads through `select()`. Repositories and bounded
|
|
834
|
+
* contexts invoke handlers, persist changes, and deliver returned signals.
|
|
835
|
+
*
|
|
836
|
+
* @typeParam Id Domain identifier type.
|
|
837
|
+
* @typeParam Schema Generated schema describing the Process Manager state.
|
|
583
838
|
*/
|
|
584
839
|
export class ProcessManager extends TransactionalEntity {
|
|
585
840
|
/**
|
|
586
|
-
* Creates a
|
|
841
|
+
* Creates a Process Manager from its identity, state, and metadata.
|
|
587
842
|
*
|
|
588
843
|
* @param options Identity, schema, state, version, and lifecycle inputs.
|
|
589
844
|
*/
|
|
@@ -618,11 +873,47 @@ export class ProcessManager extends TransactionalEntity {
|
|
|
618
873
|
eventStorage() {
|
|
619
874
|
return entityHistoryAccess.eventMaintenance(this);
|
|
620
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* Binds either query form to the active handler capability.
|
|
878
|
+
*
|
|
879
|
+
* @typeParam QuerySchema Queried Entity state schema.
|
|
880
|
+
* @typeParam Columns Registered columns for the legacy builder.
|
|
881
|
+
* @typeParam Id Identifier type of a detached query.
|
|
882
|
+
* @param schemaOrQuery State schema or built context-free query.
|
|
883
|
+
* @param columns Columns required with a state schema.
|
|
884
|
+
* @returns Legacy builder or detached-query read facade.
|
|
885
|
+
*/
|
|
886
|
+
select(schemaOrQuery, columns) {
|
|
887
|
+
const capability = processManagerQueryAccess.require(this);
|
|
888
|
+
if (schemaOrQuery instanceof EntityQueryDescription) {
|
|
889
|
+
const query = schemaOrQuery;
|
|
890
|
+
return Object.freeze({
|
|
891
|
+
read: async () => {
|
|
892
|
+
const active = processManagerQueryAccess.require(this);
|
|
893
|
+
const plan = query.buildPlan();
|
|
894
|
+
ProcessManagerQueryLimits.check(plan);
|
|
895
|
+
const wire = query.build();
|
|
896
|
+
wire.context = clone(ActorContextSchema, active.actorContext);
|
|
897
|
+
const states = await active.execute(plan, query.schema, wire);
|
|
898
|
+
return Object.freeze(states.slice(0, 1_000));
|
|
899
|
+
},
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
if (columns === undefined)
|
|
903
|
+
throw new TypeError("Process Manager query columns are required.");
|
|
904
|
+
return new ProcessManagerQuery(this, schemaOrQuery, EntityQuery.select({ schema: schemaOrQuery, columns, context: capability.actorContext }));
|
|
905
|
+
}
|
|
621
906
|
}
|
|
622
907
|
/**
|
|
623
908
|
* Marks immutable entity families.
|
|
624
909
|
*/
|
|
625
910
|
const EntityFamilies = Object.freeze({
|
|
911
|
+
/**
|
|
912
|
+
* Records whether an Entity is an Aggregate, Projection, or Process Manager.
|
|
913
|
+
*
|
|
914
|
+
* @param entity Instance being constructed.
|
|
915
|
+
* @param family Kind of Entity being constructed.
|
|
916
|
+
*/
|
|
626
917
|
mark(entity, family) {
|
|
627
918
|
Object.defineProperty(entity, "entityFamily", {
|
|
628
919
|
configurable: false,
|
|
@@ -636,9 +927,26 @@ const EntityFamilies = Object.freeze({
|
|
|
636
927
|
* Creates entity-state snapshots and compares state bytes.
|
|
637
928
|
*/
|
|
638
929
|
const EntitySnapshots = Object.freeze({
|
|
930
|
+
/**
|
|
931
|
+
* Copies state through its schema, discarding unknown wire fields.
|
|
932
|
+
*
|
|
933
|
+
* @typeParam Schema Generated schema describing the state.
|
|
934
|
+
* @param schema Schema used for encoding and decoding.
|
|
935
|
+
* @param state State snapshot to copy.
|
|
936
|
+
* @returns An independent state message containing known fields.
|
|
937
|
+
*/
|
|
639
938
|
clone(schema, state) {
|
|
640
939
|
return fromBinary(schema, toBinary(schema, state, { writeUnknownFields: false }));
|
|
641
940
|
},
|
|
941
|
+
/**
|
|
942
|
+
* Compares the encoded known fields of two state snapshots.
|
|
943
|
+
*
|
|
944
|
+
* @typeParam Schema Generated schema shared by both snapshots.
|
|
945
|
+
* @param schema Schema used to encode the states.
|
|
946
|
+
* @param previous State before handling.
|
|
947
|
+
* @param next State after handling.
|
|
948
|
+
* @returns True when their encoded known fields are identical.
|
|
949
|
+
*/
|
|
642
950
|
equal(schema, previous, next) {
|
|
643
951
|
const previousBinary = toBinary(schema, previous, { writeUnknownFields: false });
|
|
644
952
|
const nextBinary = toBinary(schema, next, { writeUnknownFields: false });
|
|
@@ -647,16 +955,23 @@ const EntitySnapshots = Object.freeze({
|
|
|
647
955
|
},
|
|
648
956
|
});
|
|
649
957
|
/**
|
|
650
|
-
*
|
|
958
|
+
* Copies transaction version, lifecycle, and validation snapshots.
|
|
651
959
|
*/
|
|
652
960
|
const EntityCommits = Object.freeze({
|
|
961
|
+
/**
|
|
962
|
+
* Copies version, lifecycle, and validation messages in a transaction result.
|
|
963
|
+
*
|
|
964
|
+
* @typeParam Schema Generated schema describing the transaction's state.
|
|
965
|
+
* @param result Accepted or rejected transaction result.
|
|
966
|
+
* @returns A result with independent version and validation metadata.
|
|
967
|
+
*/
|
|
653
968
|
clone(result) {
|
|
654
969
|
if (result.status === "accepted") {
|
|
655
970
|
return {
|
|
656
971
|
...result,
|
|
657
972
|
version: {
|
|
658
|
-
previous:
|
|
659
|
-
committed:
|
|
973
|
+
previous: clone(VersionSchema, result.version.previous),
|
|
974
|
+
committed: clone(VersionSchema, result.version.committed),
|
|
660
975
|
},
|
|
661
976
|
lifecycle: { archived: result.lifecycle.archived, deleted: result.lifecycle.deleted },
|
|
662
977
|
validation: this.validation(result.validation),
|
|
@@ -665,13 +980,19 @@ const EntityCommits = Object.freeze({
|
|
|
665
980
|
return {
|
|
666
981
|
...result,
|
|
667
982
|
version: {
|
|
668
|
-
previous:
|
|
669
|
-
draft:
|
|
983
|
+
previous: clone(VersionSchema, result.version.previous),
|
|
984
|
+
draft: clone(VersionSchema, result.version.draft),
|
|
670
985
|
},
|
|
671
986
|
lifecycle: { archived: result.lifecycle.archived, deleted: result.lifecycle.deleted },
|
|
672
987
|
validation: this.validation(result.validation),
|
|
673
988
|
};
|
|
674
989
|
},
|
|
990
|
+
/**
|
|
991
|
+
* Copies validation errors without exposing the stored violation messages.
|
|
992
|
+
*
|
|
993
|
+
* @param validation State-transition validation result.
|
|
994
|
+
* @returns An independent valid result or cloned validation error.
|
|
995
|
+
*/
|
|
675
996
|
validation(validation) {
|
|
676
997
|
if (validation.valid) {
|
|
677
998
|
return { valid: true, violations: [], error: undefined };
|
|
@@ -684,146 +1005,4 @@ const EntityCommits = Object.freeze({
|
|
|
684
1005
|
};
|
|
685
1006
|
},
|
|
686
1007
|
});
|
|
687
|
-
const maxVersionMetadataDepth = 1_000;
|
|
688
|
-
/**
|
|
689
|
-
* Validates and clones caller-provided plain version metadata.
|
|
690
|
-
*/
|
|
691
|
-
const EntityVersions = Object.freeze({
|
|
692
|
-
clone(version) {
|
|
693
|
-
return this.value(version, "$", new WeakSet(), 0);
|
|
694
|
-
},
|
|
695
|
-
value(value, path, stack, depth) {
|
|
696
|
-
if (depth > maxVersionMetadataDepth) {
|
|
697
|
-
throw this.error(path, "excessive nesting depth");
|
|
698
|
-
}
|
|
699
|
-
if (value === null) {
|
|
700
|
-
return value;
|
|
701
|
-
}
|
|
702
|
-
switch (typeof value) {
|
|
703
|
-
case "string":
|
|
704
|
-
case "number":
|
|
705
|
-
case "boolean":
|
|
706
|
-
case "bigint":
|
|
707
|
-
case "symbol":
|
|
708
|
-
case "undefined":
|
|
709
|
-
return value;
|
|
710
|
-
case "function":
|
|
711
|
-
throw this.error(path, "function");
|
|
712
|
-
case "object":
|
|
713
|
-
return this.object(value, path, stack, depth);
|
|
714
|
-
}
|
|
715
|
-
},
|
|
716
|
-
object(value, path, stack, depth) {
|
|
717
|
-
if (isProxy(value))
|
|
718
|
-
throw this.error(path, "Proxy");
|
|
719
|
-
if (ArrayBuffer.isView(value))
|
|
720
|
-
throw this.error(path, this.kind(value));
|
|
721
|
-
if (value instanceof ArrayBuffer || this.isSharedBuffer(value)) {
|
|
722
|
-
throw this.error(path, this.kind(value));
|
|
723
|
-
}
|
|
724
|
-
if (stack.has(value))
|
|
725
|
-
throw this.error(path, "cyclic object");
|
|
726
|
-
stack.add(value);
|
|
727
|
-
try {
|
|
728
|
-
if (Array.isArray(value))
|
|
729
|
-
return this.array(value, path, stack, depth);
|
|
730
|
-
if (!this.isPlainObject(value))
|
|
731
|
-
throw this.error(path, this.kind(value));
|
|
732
|
-
const clone = Object.create(this.prototype(value));
|
|
733
|
-
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
734
|
-
const [symbolKey] = Object.getOwnPropertySymbols(descriptors);
|
|
735
|
-
if (symbolKey !== undefined) {
|
|
736
|
-
throw this.error(`${path}[${String(symbolKey)}]`, "symbol-keyed property");
|
|
737
|
-
}
|
|
738
|
-
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
739
|
-
const childPath = `${path}.${key}`;
|
|
740
|
-
if (!descriptor.enumerable)
|
|
741
|
-
throw this.error(childPath, "non-enumerable property");
|
|
742
|
-
if (!("value" in descriptor))
|
|
743
|
-
throw this.error(childPath, "accessor property");
|
|
744
|
-
Object.defineProperty(clone, key, {
|
|
745
|
-
configurable: true,
|
|
746
|
-
enumerable: true,
|
|
747
|
-
value: this.value(descriptor.value, childPath, stack, depth + 1),
|
|
748
|
-
writable: true,
|
|
749
|
-
});
|
|
750
|
-
}
|
|
751
|
-
return clone;
|
|
752
|
-
}
|
|
753
|
-
finally {
|
|
754
|
-
stack.delete(value);
|
|
755
|
-
}
|
|
756
|
-
},
|
|
757
|
-
array(value, path, stack, depth) {
|
|
758
|
-
if (this.prototype(value) !== Array.prototype)
|
|
759
|
-
throw this.error(path, "Array");
|
|
760
|
-
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
761
|
-
const [symbolKey] = Object.getOwnPropertySymbols(descriptors);
|
|
762
|
-
if (symbolKey !== undefined) {
|
|
763
|
-
throw this.error(`${path}[${String(symbolKey)}]`, "symbol-keyed property");
|
|
764
|
-
}
|
|
765
|
-
const lengthDescriptor = descriptors.length;
|
|
766
|
-
if (lengthDescriptor === undefined || !("value" in lengthDescriptor)) {
|
|
767
|
-
throw this.error(path, "array without data length");
|
|
768
|
-
}
|
|
769
|
-
const length = lengthDescriptor.value;
|
|
770
|
-
const clone = new Array(length);
|
|
771
|
-
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
772
|
-
if (key === "length")
|
|
773
|
-
continue;
|
|
774
|
-
if (!this.isArrayKey(key, length))
|
|
775
|
-
throw this.error(`${path}.${key}`, "custom array property");
|
|
776
|
-
if (!descriptor.enumerable)
|
|
777
|
-
throw this.error(`${path}[${key}]`, "non-enumerable property");
|
|
778
|
-
if (!("value" in descriptor))
|
|
779
|
-
throw this.error(`${path}[${key}]`, "accessor property");
|
|
780
|
-
}
|
|
781
|
-
for (let index = 0; index < length; index += 1) {
|
|
782
|
-
const key = String(index);
|
|
783
|
-
const descriptor = descriptors[key];
|
|
784
|
-
if (descriptor === undefined || !("value" in descriptor)) {
|
|
785
|
-
throw this.error(`${path}[${key}]`, "sparse array element");
|
|
786
|
-
}
|
|
787
|
-
Object.defineProperty(clone, index, {
|
|
788
|
-
configurable: true,
|
|
789
|
-
enumerable: true,
|
|
790
|
-
value: this.value(descriptor.value, `${path}[${key}]`, stack, depth + 1),
|
|
791
|
-
writable: true,
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
return clone;
|
|
795
|
-
},
|
|
796
|
-
isArrayKey(key, length) {
|
|
797
|
-
const index = Number(key);
|
|
798
|
-
return Number.isInteger(index) && index >= 0 && index < length && String(index) === key;
|
|
799
|
-
},
|
|
800
|
-
isPlainObject(value) {
|
|
801
|
-
const prototype = this.prototype(value);
|
|
802
|
-
return prototype === Object.prototype || prototype === null;
|
|
803
|
-
},
|
|
804
|
-
prototype(value) {
|
|
805
|
-
return Object.getPrototypeOf(value);
|
|
806
|
-
},
|
|
807
|
-
kind(value) {
|
|
808
|
-
if (value instanceof Date)
|
|
809
|
-
return "Date";
|
|
810
|
-
if (value instanceof Map)
|
|
811
|
-
return "Map";
|
|
812
|
-
if (value instanceof Set)
|
|
813
|
-
return "Set";
|
|
814
|
-
if (ArrayBuffer.isView(value))
|
|
815
|
-
return "typed array";
|
|
816
|
-
if (value instanceof ArrayBuffer)
|
|
817
|
-
return "ArrayBuffer";
|
|
818
|
-
if (this.isSharedBuffer(value))
|
|
819
|
-
return "SharedArrayBuffer";
|
|
820
|
-
return "object";
|
|
821
|
-
},
|
|
822
|
-
isSharedBuffer(value) {
|
|
823
|
-
return typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
|
|
824
|
-
},
|
|
825
|
-
error(path, kind) {
|
|
826
|
-
return new TypeError(`Entity version metadata must be plain snapshot data; ${path} contains ${kind}.`);
|
|
827
|
-
},
|
|
828
|
-
});
|
|
829
1008
|
//# sourceMappingURL=entity.js.map
|