@photon-grove/evt 0.0.0 → 0.1.1
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/LICENSE +176 -0
- package/README.md +164 -1
- package/dist/aggregate.d.ts +83 -0
- package/dist/aggregate.d.ts.map +1 -0
- package/dist/aggregate.js +92 -0
- package/dist/aggregate.js.map +1 -0
- package/dist/base64.d.ts +8 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/base64.js +67 -0
- package/dist/base64.js.map +1 -0
- package/dist/codec.d.ts +56 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +90 -0
- package/dist/codec.js.map +1 -0
- package/dist/commit-id.d.ts +3 -0
- package/dist/commit-id.d.ts.map +1 -0
- package/dist/commit-id.js +43 -0
- package/dist/commit-id.js.map +1 -0
- package/dist/dynamodb/client.d.ts +83 -0
- package/dist/dynamodb/client.d.ts.map +1 -0
- package/dist/dynamodb/client.js +6 -0
- package/dist/dynamodb/client.js.map +1 -0
- package/dist/dynamodb/head.d.ts +34 -0
- package/dist/dynamodb/head.d.ts.map +1 -0
- package/dist/dynamodb/head.js +62 -0
- package/dist/dynamodb/head.js.map +1 -0
- package/dist/dynamodb/index.d.ts +6 -0
- package/dist/dynamodb/index.d.ts.map +1 -0
- package/dist/dynamodb/index.js +8 -0
- package/dist/dynamodb/index.js.map +1 -0
- package/dist/dynamodb/item.d.ts +70 -0
- package/dist/dynamodb/item.d.ts.map +1 -0
- package/dist/dynamodb/item.js +264 -0
- package/dist/dynamodb/item.js.map +1 -0
- package/dist/dynamodb/marker.d.ts +11 -0
- package/dist/dynamodb/marker.d.ts.map +1 -0
- package/dist/dynamodb/marker.js +56 -0
- package/dist/dynamodb/marker.js.map +1 -0
- package/dist/dynamodb/repository.d.ts +61 -0
- package/dist/dynamodb/repository.d.ts.map +1 -0
- package/dist/dynamodb/repository.js +731 -0
- package/dist/dynamodb/repository.js.map +1 -0
- package/dist/dynamodb/requests.d.ts +65 -0
- package/dist/dynamodb/requests.d.ts.map +1 -0
- package/dist/dynamodb/requests.js +179 -0
- package/dist/dynamodb/requests.js.map +1 -0
- package/dist/envelope.d.ts +15 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +59 -0
- package/dist/envelope.js.map +1 -0
- package/dist/errors.d.ts +205 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +240 -0
- package/dist/errors.js.map +1 -0
- package/dist/event.d.ts +47 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +64 -0
- package/dist/event.js.map +1 -0
- package/dist/features.d.ts +55 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/features.js +126 -0
- package/dist/features.js.map +1 -0
- package/dist/fields.d.ts +31 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +105 -0
- package/dist/fields.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +47 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +458 -0
- package/dist/json.js.map +1 -0
- package/dist/memory/index.d.ts +2 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +3 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/repository.d.ts +70 -0
- package/dist/memory/repository.d.ts.map +1 -0
- package/dist/memory/repository.js +308 -0
- package/dist/memory/repository.js.map +1 -0
- package/dist/metadata.d.ts +47 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +75 -0
- package/dist/metadata.js.map +1 -0
- package/dist/repository.d.ts +131 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +130 -0
- package/dist/repository.js.map +1 -0
- package/dist/retry.d.ts +25 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +50 -0
- package/dist/retry.js.map +1 -0
- package/dist/snapshots.d.ts +21 -0
- package/dist/snapshots.d.ts.map +1 -0
- package/dist/snapshots.js +35 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/store.d.ts +103 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +246 -0
- package/dist/store.js.map +1 -0
- package/dist/testing/equal.d.ts +22 -0
- package/dist/testing/equal.d.ts.map +1 -0
- package/dist/testing/equal.js +121 -0
- package/dist/testing/equal.js.map +1 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenario.d.ts +136 -0
- package/dist/testing/scenario.d.ts.map +1 -0
- package/dist/testing/scenario.js +307 -0
- package/dist/testing/scenario.js.map +1 -0
- package/dist/utf8.d.ts +17 -0
- package/dist/utf8.d.ts.map +1 -0
- package/dist/utf8.js +82 -0
- package/dist/utf8.js.map +1 -0
- package/package.json +58 -2
- package/src/aggregate.ts +196 -0
- package/src/base64.ts +80 -0
- package/src/codec.ts +139 -0
- package/src/commit-id.ts +50 -0
- package/src/dynamodb/client.ts +102 -0
- package/src/dynamodb/head.ts +93 -0
- package/src/dynamodb/index.ts +45 -0
- package/src/dynamodb/item.ts +334 -0
- package/src/dynamodb/marker.ts +64 -0
- package/src/dynamodb/repository.ts +1030 -0
- package/src/dynamodb/requests.ts +256 -0
- package/src/envelope.ts +67 -0
- package/src/errors.ts +365 -0
- package/src/event.ts +117 -0
- package/src/features.ts +175 -0
- package/src/fields.ts +134 -0
- package/src/globals.d.ts +39 -0
- package/src/index.ts +98 -0
- package/src/json.ts +546 -0
- package/src/memory/index.ts +11 -0
- package/src/memory/repository.ts +463 -0
- package/src/metadata.ts +120 -0
- package/src/repository.ts +275 -0
- package/src/retry.ts +74 -0
- package/src/snapshots.ts +42 -0
- package/src/store.ts +377 -0
- package/src/testing/equal.ts +146 -0
- package/src/testing/index.ts +14 -0
- package/src/testing/scenario.ts +406 -0
- package/src/utf8.ts +92 -0
package/dist/store.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// The Store: loads aggregates, runs commands, and commits their events with the snapshots the
|
|
2
|
+
// snapshot policy calls for.
|
|
3
|
+
import { encodeEventData, replayEvent, } from './aggregate.js';
|
|
4
|
+
import { commitIds } from './commit-id.js';
|
|
5
|
+
import { EvtError, SequenceGapError, SnapshotError, isConflict, isRetryable } from './errors.js';
|
|
6
|
+
import { eventId } from './event.js';
|
|
7
|
+
import { emptyMetadata } from './metadata.js';
|
|
8
|
+
import { DEFAULT_RETRY_POLICY, checkRetryPolicy, retryDelay, sleep, } from './retry.js';
|
|
9
|
+
import { MAX_COMMIT_ITEM_BYTES, snapshotCommitSize, snapshotEventsDue } from './snapshots.js';
|
|
10
|
+
/** The default number of events between snapshots, as in Go and Rust. */
|
|
11
|
+
export const DEFAULT_SNAPSHOT_INTERVAL = 5;
|
|
12
|
+
// How many times a load reads the stream when it finds a sequence gap.
|
|
13
|
+
const LOAD_ATTEMPTS = 3;
|
|
14
|
+
const INT64_MAX = 2n ** 63n - 1n;
|
|
15
|
+
export class Store {
|
|
16
|
+
repository;
|
|
17
|
+
#region;
|
|
18
|
+
#clock;
|
|
19
|
+
#snapshotInterval;
|
|
20
|
+
#commitId;
|
|
21
|
+
constructor(repository, options = {}) {
|
|
22
|
+
const interval = options.snapshotInterval ?? DEFAULT_SNAPSHOT_INTERVAL;
|
|
23
|
+
if (!Number.isSafeInteger(interval) || interval < 0) {
|
|
24
|
+
throw new EvtError('invalidArgument', `the snapshot interval must be a whole number of events: ${interval}`);
|
|
25
|
+
}
|
|
26
|
+
this.repository = repository;
|
|
27
|
+
this.#region = options.region ?? '';
|
|
28
|
+
this.#clock = options.clock ?? Date.now;
|
|
29
|
+
this.#snapshotInterval = interval;
|
|
30
|
+
this.#commitId = options.commitId ?? commitIds(this.#clock);
|
|
31
|
+
}
|
|
32
|
+
/** The number of events between snapshots of `aggregate`: its own interval, or the store's. */
|
|
33
|
+
snapshotInterval(aggregate) {
|
|
34
|
+
return aggregate.snapshotInterval ?? this.#snapshotInterval;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Loads an aggregate from its snapshot and the events after it, or from every event when it has
|
|
38
|
+
* no snapshot. An entity with no events loads as the initial state at sequence 0.
|
|
39
|
+
*
|
|
40
|
+
* The events must continue the sequence. A gap means another writer snapshotted and compacted
|
|
41
|
+
* the stream between the two reads, so the load starts over, up to three times, and then fails
|
|
42
|
+
* with a {@link SequenceGapError}. When no events follow, the snapshot is read again to rule out
|
|
43
|
+
* a compaction that left no gap to see.
|
|
44
|
+
*/
|
|
45
|
+
async load(aggregate, entityId, options = {}) {
|
|
46
|
+
// Each attempt waits for the one before it.
|
|
47
|
+
/* oxlint-disable no-await-in-loop */
|
|
48
|
+
for (let attempt = 1;; attempt++) {
|
|
49
|
+
try {
|
|
50
|
+
return await this.#loadOnce(aggregate, entityId, options);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!isConflict(error) || attempt >= LOAD_ATTEMPTS) {
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/* oxlint-enable no-await-in-loop */
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Loads the aggregate, runs the command, and commits its events, with a snapshot when the
|
|
62
|
+
* commit reaches the snapshot interval. A snapshot whose item is over the per-item commit budget
|
|
63
|
+
* is left out, so the commit still succeeds and later loads replay from the one before.
|
|
64
|
+
*
|
|
65
|
+
* A command ID already carried by an event folded in since the latest snapshot makes the
|
|
66
|
+
* command a `duplicate`, and the handler doesn't run. A conflict with another writer throws;
|
|
67
|
+
* {@link executeWithRetry} runs the command again.
|
|
68
|
+
*/
|
|
69
|
+
async execute(aggregate, entityId, command, options = {}) {
|
|
70
|
+
const metadata = this.#metadata(options.metadata);
|
|
71
|
+
const loaded = await this.load(aggregate, entityId, options);
|
|
72
|
+
const commandId = metadata.commandId;
|
|
73
|
+
if (commandId !== null && commandId !== '' && loaded.seenCommandIds.has(commandId)) {
|
|
74
|
+
return { kind: 'duplicate', commandId };
|
|
75
|
+
}
|
|
76
|
+
const decision = await aggregate.handle(loaded.state, command);
|
|
77
|
+
if (decision.kind === 'reject') {
|
|
78
|
+
return { kind: 'rejected', rejection: decision.rejection, state: loaded };
|
|
79
|
+
}
|
|
80
|
+
if (decision.events.length === 0) {
|
|
81
|
+
return { kind: 'committed', state: loaded, events: [] };
|
|
82
|
+
}
|
|
83
|
+
const { state, events, snapshot } = this.#stage(aggregate, loaded, decision.events, metadata);
|
|
84
|
+
await this.repository.commit({ entityId, events, snapshot }, options);
|
|
85
|
+
return { kind: 'committed', state, events };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Like {@link execute}, but loads and runs the command again after a retryable error (see
|
|
89
|
+
* {@link isRetryable}), waiting {@link retryDelay} between attempts. When the attempts run out,
|
|
90
|
+
* the last error is thrown. A rejection or a duplicate is a result, never retried.
|
|
91
|
+
*/
|
|
92
|
+
async executeWithRetry(aggregate, entityId, command, options = {}) {
|
|
93
|
+
const policy = options.policy ?? DEFAULT_RETRY_POLICY;
|
|
94
|
+
checkRetryPolicy(policy);
|
|
95
|
+
const wait = options.sleep ?? sleep;
|
|
96
|
+
// Each attempt waits for the one before it.
|
|
97
|
+
/* oxlint-disable no-await-in-loop */
|
|
98
|
+
for (let retry = 0;; retry++) {
|
|
99
|
+
try {
|
|
100
|
+
return await this.execute(aggregate, entityId, command, options);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (!isRetryable(error) || retry + 1 >= policy.maxAttempts) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
await wait(retryDelay(policy, retry), options.signal);
|
|
108
|
+
}
|
|
109
|
+
/* oxlint-enable no-await-in-loop */
|
|
110
|
+
}
|
|
111
|
+
async #loadOnce(aggregate, entityId, options) {
|
|
112
|
+
const snapshot = await this.repository.snapshot(entityId, options);
|
|
113
|
+
let state = aggregate.initial();
|
|
114
|
+
let sequence = 0n;
|
|
115
|
+
let snapshotSequence = 0n;
|
|
116
|
+
if (snapshot) {
|
|
117
|
+
try {
|
|
118
|
+
state = aggregate.state.decode(snapshot.payload ?? new Uint8Array());
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw new SnapshotError(entityId, error);
|
|
122
|
+
}
|
|
123
|
+
sequence = snapshot.eventSequence;
|
|
124
|
+
snapshotSequence = snapshot.sequence;
|
|
125
|
+
}
|
|
126
|
+
const events = snapshot
|
|
127
|
+
? await this.repository.eventsAfter(entityId, sequence, options)
|
|
128
|
+
: await this.repository.events(entityId, options);
|
|
129
|
+
// With no events after it, a snapshot and a compaction between the two reads would leave no
|
|
130
|
+
// gap to see, so the snapshot is read again: a newer one means the stream moved past it.
|
|
131
|
+
if (events.length === 0) {
|
|
132
|
+
const covered = (await this.repository.snapshot(entityId, options))?.eventSequence ?? 0n;
|
|
133
|
+
if (covered > sequence) {
|
|
134
|
+
throw new SequenceGapError(entityId, sequence, covered + 1n);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const seenCommandIds = new Set();
|
|
138
|
+
for (const stored of events) {
|
|
139
|
+
if (stored.sequence !== sequence + 1n) {
|
|
140
|
+
throw new SequenceGapError(entityId, sequence, stored.sequence);
|
|
141
|
+
}
|
|
142
|
+
state = aggregate.apply(state, replayEvent(aggregate.events, stored));
|
|
143
|
+
sequence = stored.sequence;
|
|
144
|
+
const commandId = stored.metadata.commandId;
|
|
145
|
+
if (commandId !== null && commandId !== '') {
|
|
146
|
+
seenCommandIds.add(commandId);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return { entityId, state, sequence, snapshotSequence, seenCommandIds };
|
|
150
|
+
}
|
|
151
|
+
// Applies the decided events, and builds the stored events and the snapshot the policy calls
|
|
152
|
+
// for. The state is only used once the commit succeeds.
|
|
153
|
+
#stage(aggregate, loaded, decided, metadata) {
|
|
154
|
+
const entityId = loaded.entityId;
|
|
155
|
+
let sequence = loaded.sequence;
|
|
156
|
+
let state = loaded.state;
|
|
157
|
+
const events = [];
|
|
158
|
+
for (const event of decided) {
|
|
159
|
+
if (sequence >= INT64_MAX) {
|
|
160
|
+
throw new EvtError('invalidCommit', `invalid commit: entity ${entityId} is at the maximum event sequence`);
|
|
161
|
+
}
|
|
162
|
+
sequence++;
|
|
163
|
+
const { version, payload } = encodeEventData(aggregate.events, event);
|
|
164
|
+
events.push({
|
|
165
|
+
id: eventId(entityId, sequence),
|
|
166
|
+
sequence,
|
|
167
|
+
type: event.type,
|
|
168
|
+
version,
|
|
169
|
+
entityId,
|
|
170
|
+
entityType: aggregate.type,
|
|
171
|
+
payload,
|
|
172
|
+
metadata: copyMetadata(metadata),
|
|
173
|
+
});
|
|
174
|
+
state = aggregate.apply(state, event);
|
|
175
|
+
}
|
|
176
|
+
const interval = this.snapshotInterval(aggregate);
|
|
177
|
+
let snapshot = null;
|
|
178
|
+
if (snapshotEventsDue(loaded.sequence, decided.length, interval) > 0) {
|
|
179
|
+
snapshot = {
|
|
180
|
+
entityType: aggregate.type,
|
|
181
|
+
sequence: loaded.snapshotSequence + 1n,
|
|
182
|
+
payload: aggregate.state.encode(state),
|
|
183
|
+
};
|
|
184
|
+
// A snapshot over the per-item budget would fail every commit that carries it.
|
|
185
|
+
const size = snapshotCommitSize({ ...snapshot, entityId, eventSequence: sequence });
|
|
186
|
+
if (size > MAX_COMMIT_ITEM_BYTES) {
|
|
187
|
+
snapshot = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const seenCommandIds = new Set(loaded.seenCommandIds);
|
|
191
|
+
if (metadata.commandId !== null && metadata.commandId !== '') {
|
|
192
|
+
seenCommandIds.add(metadata.commandId);
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
state: {
|
|
196
|
+
entityId,
|
|
197
|
+
state,
|
|
198
|
+
sequence,
|
|
199
|
+
snapshotSequence: snapshot ? snapshot.sequence : loaded.snapshotSequence,
|
|
200
|
+
seenCommandIds,
|
|
201
|
+
},
|
|
202
|
+
events,
|
|
203
|
+
snapshot,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// The command's metadata with the store's region and the clock's timestamp where it has none,
|
|
207
|
+
// and the commit ID the engine stamps: the command ID, else the caller's, else a generated one.
|
|
208
|
+
// Field by field, so a field an untyped caller set to undefined is empty too, and every key is
|
|
209
|
+
// written.
|
|
210
|
+
#metadata(partial = {}) {
|
|
211
|
+
const empty = emptyMetadata();
|
|
212
|
+
const metadata = {
|
|
213
|
+
commandId: partial.commandId ?? empty.commandId,
|
|
214
|
+
trace: partial.trace ? new Map(partial.trace) : empty.trace,
|
|
215
|
+
origin: partial.origin ? { ...partial.origin } : empty.origin,
|
|
216
|
+
address: partial.address ?? empty.address,
|
|
217
|
+
region: partial.region || this.#region,
|
|
218
|
+
timestamp: partial.timestamp || rfc3339Seconds(this.#clock()),
|
|
219
|
+
principalId: partial.principalId ?? empty.principalId,
|
|
220
|
+
causationId: partial.causationId ?? empty.causationId,
|
|
221
|
+
extensions: partial.extensions ? new Map(partial.extensions) : empty.extensions,
|
|
222
|
+
commitId: partial.commitId ?? empty.commitId,
|
|
223
|
+
};
|
|
224
|
+
if (metadata.commandId !== null && metadata.commandId !== '') {
|
|
225
|
+
metadata.commitId = metadata.commandId;
|
|
226
|
+
}
|
|
227
|
+
else if (metadata.commitId === '') {
|
|
228
|
+
metadata.commitId = this.#commitId();
|
|
229
|
+
}
|
|
230
|
+
return metadata;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Each stored event gets its own metadata, so changing one changes no other.
|
|
234
|
+
function copyMetadata(metadata) {
|
|
235
|
+
return {
|
|
236
|
+
...metadata,
|
|
237
|
+
trace: metadata.trace && new Map(metadata.trace),
|
|
238
|
+
origin: metadata.origin && { ...metadata.origin },
|
|
239
|
+
extensions: new Map(metadata.extensions),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// RFC 3339 in UTC, to the second, as Go's time.RFC3339 formats a UTC time.
|
|
243
|
+
function rfc3339Seconds(ms) {
|
|
244
|
+
return new Date(ms).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A failed assertion. It carries `actual` and `expected` the way Node's `assert` does, so runners
|
|
3
|
+
* such as Vitest and Jest show a diff, and `node:test` prints both.
|
|
4
|
+
*/
|
|
5
|
+
export declare class AssertionError extends Error {
|
|
6
|
+
readonly name = "AssertionError";
|
|
7
|
+
readonly actual: unknown;
|
|
8
|
+
readonly expected: unknown;
|
|
9
|
+
constructor(message: string, actual?: unknown, expected?: unknown);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Whether two values have the same structure: objects of the same prototype by their own
|
|
13
|
+
* enumerable string and symbol keys (a key whose value is `undefined` counts as absent), arrays by
|
|
14
|
+
* their elements, holes included, `Map`s by their entries and `Set`s by their members, buffers and
|
|
15
|
+
* typed arrays by their bytes, dates by their time, regular expressions by their source and flags,
|
|
16
|
+
* and everything else with `Object.is`. `Map` keys and `Set` members match by identity, and
|
|
17
|
+
* `#private` fields aren't seen.
|
|
18
|
+
*/
|
|
19
|
+
export declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
20
|
+
/** Prints a value for an assertion message, with `bigint`s, `Map`s and byte arrays legible. */
|
|
21
|
+
export declare function show(value: unknown): string;
|
|
22
|
+
//# sourceMappingURL=equal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"equal.d.ts","sourceRoot":"","sources":["../../src/testing/equal.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAkB,IAAI,oBAAmB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAE1B,YAAY,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,EAIhE;CACF;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CA2DzD;AAqBD,+FAA+F;AAC/F,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAsC3C"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Structural equality and printing for test assertions, so /testing depends on no test framework.
|
|
2
|
+
/**
|
|
3
|
+
* A failed assertion. It carries `actual` and `expected` the way Node's `assert` does, so runners
|
|
4
|
+
* such as Vitest and Jest show a diff, and `node:test` prints both.
|
|
5
|
+
*/
|
|
6
|
+
export class AssertionError extends Error {
|
|
7
|
+
name = 'AssertionError';
|
|
8
|
+
actual;
|
|
9
|
+
expected;
|
|
10
|
+
constructor(message, actual, expected) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.actual = actual;
|
|
13
|
+
this.expected = expected;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether two values have the same structure: objects of the same prototype by their own
|
|
18
|
+
* enumerable string and symbol keys (a key whose value is `undefined` counts as absent), arrays by
|
|
19
|
+
* their elements, holes included, `Map`s by their entries and `Set`s by their members, buffers and
|
|
20
|
+
* typed arrays by their bytes, dates by their time, regular expressions by their source and flags,
|
|
21
|
+
* and everything else with `Object.is`. `Map` keys and `Set` members match by identity, and
|
|
22
|
+
* `#private` fields aren't seen.
|
|
23
|
+
*/
|
|
24
|
+
export function deepEqual(a, b) {
|
|
25
|
+
if (Object.is(a, b)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(a)) {
|
|
35
|
+
const other = b;
|
|
36
|
+
if (a.length !== other.length) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
// An index loop, since every() skips holes.
|
|
40
|
+
for (let i = 0; i < a.length; i++) {
|
|
41
|
+
if (i in a !== i in other || !deepEqual(a[i], other[i])) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (a instanceof ArrayBuffer || ArrayBuffer.isView(a)) {
|
|
48
|
+
const left = bytes(a);
|
|
49
|
+
const right = bytes(b);
|
|
50
|
+
return left.length === right.length && left.every((byte, i) => byte === right[i]);
|
|
51
|
+
}
|
|
52
|
+
if (a instanceof Map) {
|
|
53
|
+
const other = b;
|
|
54
|
+
return (a.size === other.size &&
|
|
55
|
+
[...a].every(([key, entry]) => other.has(key) && deepEqual(entry, other.get(key))));
|
|
56
|
+
}
|
|
57
|
+
if (a instanceof Set) {
|
|
58
|
+
const other = b;
|
|
59
|
+
return a.size === other.size && [...a].every((entry) => other.has(entry));
|
|
60
|
+
}
|
|
61
|
+
if (a instanceof Date) {
|
|
62
|
+
return Object.is(a.getTime(), b.getTime());
|
|
63
|
+
}
|
|
64
|
+
if (a instanceof RegExp) {
|
|
65
|
+
return a.source === b.source && a.flags === b.flags;
|
|
66
|
+
}
|
|
67
|
+
const left = definedKeys(a);
|
|
68
|
+
const right = definedKeys(b);
|
|
69
|
+
return (left.length === right.length &&
|
|
70
|
+
left.every((key) => Object.hasOwn(b, key) && deepEqual(field(a, key), field(b, key))));
|
|
71
|
+
}
|
|
72
|
+
function bytes(value) {
|
|
73
|
+
return value instanceof ArrayBuffer
|
|
74
|
+
? new Uint8Array(value)
|
|
75
|
+
: new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
76
|
+
}
|
|
77
|
+
// The own enumerable keys, symbols included, whose values aren't undefined.
|
|
78
|
+
function definedKeys(value) {
|
|
79
|
+
const symbols = Object.getOwnPropertySymbols(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));
|
|
80
|
+
return [...Object.keys(value), ...symbols].filter((key) => field(value, key) !== undefined);
|
|
81
|
+
}
|
|
82
|
+
function field(value, key) {
|
|
83
|
+
return value[key];
|
|
84
|
+
}
|
|
85
|
+
/** Prints a value for an assertion message, with `bigint`s, `Map`s and byte arrays legible. */
|
|
86
|
+
export function show(value) {
|
|
87
|
+
if (typeof value === 'string') {
|
|
88
|
+
return JSON.stringify(value);
|
|
89
|
+
}
|
|
90
|
+
if (typeof value === 'bigint') {
|
|
91
|
+
return `${value}n`;
|
|
92
|
+
}
|
|
93
|
+
if (Object.is(value, -0)) {
|
|
94
|
+
return '-0';
|
|
95
|
+
}
|
|
96
|
+
if (typeof value !== 'object' || value === null) {
|
|
97
|
+
return String(value);
|
|
98
|
+
}
|
|
99
|
+
if (Array.isArray(value)) {
|
|
100
|
+
return `[${value.map(show).join(', ')}]`;
|
|
101
|
+
}
|
|
102
|
+
if (value instanceof Uint8Array) {
|
|
103
|
+
return `Uint8Array [${value.join(', ')}]`;
|
|
104
|
+
}
|
|
105
|
+
if (value instanceof Map) {
|
|
106
|
+
const entries = [...value].map(([key, entry]) => `${show(key)} => ${show(entry)}`);
|
|
107
|
+
return `Map {${entries.join(', ')}}`;
|
|
108
|
+
}
|
|
109
|
+
if (value instanceof Set) {
|
|
110
|
+
return `Set {${[...value].map(show).join(', ')}}`;
|
|
111
|
+
}
|
|
112
|
+
if (value instanceof Date) {
|
|
113
|
+
return Number.isNaN(value.getTime()) ? 'Invalid Date' : `Date ${value.toISOString()}`;
|
|
114
|
+
}
|
|
115
|
+
if (value instanceof Error) {
|
|
116
|
+
return `${value.name}: ${value.message}`;
|
|
117
|
+
}
|
|
118
|
+
const entries = Object.entries(value).map(([key, entry]) => `${show(key)}: ${show(entry)}`);
|
|
119
|
+
return `{${entries.join(', ')}}`;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=equal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"equal.js","sourceRoot":"","sources":["../../src/testing/equal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,cAAc,EAAE,SAAS,EAAC,MAAM,YAAY,CAAA;AACpD,OAAO,EACL,KAAK,SAAS,EACd,iBAAiB,EACjB,OAAO,EACP,OAAO,EACP,QAAQ,EACR,KAAK,aAAa,EAClB,IAAI,EACJ,QAAQ,GACT,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @photon-grove/evt/testing: given/when/then helpers over MemRepository. They throw an
|
|
2
|
+
// AssertionError on failure, so they work in any test runner.
|
|
3
|
+
export { AssertionError, deepEqual } from './equal.js';
|
|
4
|
+
export { DEFAULT_ENTITY_ID, Fixture, Outcome, Scenario, When, scenario, } from './scenario.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,8DAA8D;AAE9D,OAAO,EAAC,cAAc,EAAE,SAAS,EAAC,MAAM,YAAY,CAAA;AACpD,OAAO,EAEL,iBAAiB,EACjB,OAAO,EACP,OAAO,EACP,QAAQ,EAER,IAAI,EACJ,QAAQ,GACT,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { type Aggregate, type EventDefinitions, type EventOf, type Rejection } from '../aggregate.js';
|
|
2
|
+
import { type SerializedEvent } from '../event.js';
|
|
3
|
+
import { MemRepository } from '../memory/repository.js';
|
|
4
|
+
import { type Metadata } from '../metadata.js';
|
|
5
|
+
import { type ExecuteResult, type Loaded, Store, type StoreOptions } from '../store.js';
|
|
6
|
+
/** The entity ID a {@link Scenario} runs against unless {@link Scenario.entity} sets one. */
|
|
7
|
+
export declare const DEFAULT_ENTITY_ID = "entity-1";
|
|
8
|
+
/**
|
|
9
|
+
* A {@link MemRepository} with helpers to seed and read streams of any aggregate. Hand its
|
|
10
|
+
* `repository` to the code under test, or run several {@link Scenario}s on it with
|
|
11
|
+
* {@link Scenario.on} so they build on each other.
|
|
12
|
+
*/
|
|
13
|
+
export declare class Fixture {
|
|
14
|
+
readonly repository: MemRepository;
|
|
15
|
+
constructor(repository?: MemRepository);
|
|
16
|
+
/** A store over the fixture's repository. */
|
|
17
|
+
store(options?: StoreOptions): Store;
|
|
18
|
+
/**
|
|
19
|
+
* Appends events to a stream as if earlier commands had committed them. On a stream that
|
|
20
|
+
* already has events, it continues the sequence from the loaded aggregate, which is where the
|
|
21
|
+
* snapshot leaves off after a compaction. It writes no snapshot, and its metadata is empty but
|
|
22
|
+
* for a commit ID.
|
|
23
|
+
*/
|
|
24
|
+
given<S, C, D extends EventDefinitions>(aggregate: Aggregate<S, C, D>, entityId: string, events: readonly EventOf<D>[]): Promise<void>;
|
|
25
|
+
/** The stream's stored events, upcast and decoded, oldest first. */
|
|
26
|
+
events<S, C, D extends EventDefinitions>(aggregate: Aggregate<S, C, D>, entityId: string): Promise<EventOf<D>[]>;
|
|
27
|
+
/** The aggregate loaded from its stream, from the snapshot like {@link Store.load}. */
|
|
28
|
+
load<S, C, D extends EventDefinitions>(aggregate: Aggregate<S, C, D>, entityId: string): Promise<Loaded<S>>;
|
|
29
|
+
/** Asserts that the stream holds exactly these events, decoded. */
|
|
30
|
+
assertEvents<S, C, D extends EventDefinitions>(aggregate: Aggregate<S, C, D>, entityId: string, expected: readonly EventOf<D>[]): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Starts a given/when/then test of one command against one stream:
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* await scenario(account)
|
|
37
|
+
* .given({type: 'account:opened', data: {owner: 'ada'}})
|
|
38
|
+
* .when({type: 'deposit', amountCents: 5})
|
|
39
|
+
* .thenEvents({type: 'account:deposited', data: {amountCents: 5}})
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* Each `then` method runs the command through a real {@link Store} over a {@link MemRepository}
|
|
43
|
+
* and throws an {@link AssertionError} when the outcome differs, which fails the surrounding test
|
|
44
|
+
* in any runner. {@link When.run} gives the {@link Outcome} to inspect further.
|
|
45
|
+
*/
|
|
46
|
+
export declare function scenario<S, C, D extends EventDefinitions>(aggregate: Aggregate<S, C, D>): Scenario<S, C, D>;
|
|
47
|
+
/** What a {@link Scenario} runs with. Build one with {@link scenario}. */
|
|
48
|
+
export interface ScenarioSetup<D extends EventDefinitions> {
|
|
49
|
+
readonly fixture: Fixture | null;
|
|
50
|
+
readonly entityId: string;
|
|
51
|
+
readonly given: readonly EventOf<D>[];
|
|
52
|
+
readonly metadata: Partial<Metadata>;
|
|
53
|
+
readonly options: StoreOptions;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A command's setting: the aggregate, the stream and its prior events, and how the store runs.
|
|
57
|
+
* Each method returns a new scenario, so one can be the base of several tests. Without
|
|
58
|
+
* {@link Scenario.on}, each run gets a fixture of its own.
|
|
59
|
+
*/
|
|
60
|
+
export declare class Scenario<S, C, D extends EventDefinitions> {
|
|
61
|
+
#private;
|
|
62
|
+
readonly aggregate: Aggregate<S, C, D>;
|
|
63
|
+
constructor(aggregate: Aggregate<S, C, D>, setup: ScenarioSetup<D>);
|
|
64
|
+
/** Adds events the stream holds before the command. */
|
|
65
|
+
given(...events: EventOf<D>[]): Scenario<S, C, D>;
|
|
66
|
+
/** Sets the stream's entity ID ({@link DEFAULT_ENTITY_ID} by default). */
|
|
67
|
+
entity(entityId: string): Scenario<S, C, D>;
|
|
68
|
+
/** Sets the metadata the command runs with, such as a command ID to test duplicates. */
|
|
69
|
+
metadata(metadata: Partial<Metadata>): Scenario<S, C, D>;
|
|
70
|
+
/** Sets the store's options: its clock, region, snapshot interval or commit IDs. */
|
|
71
|
+
options(options: StoreOptions): Scenario<S, C, D>;
|
|
72
|
+
/**
|
|
73
|
+
* Runs on an existing fixture, so the streams it holds are visible and several scenarios build
|
|
74
|
+
* on each other. Each run seeds the given events and runs the command again, so on a shared
|
|
75
|
+
* fixture, running a scenario twice writes it twice. Each run gets a new fixture otherwise.
|
|
76
|
+
*/
|
|
77
|
+
on(fixture: Fixture): Scenario<S, C, D>;
|
|
78
|
+
/** Names the command to run. */
|
|
79
|
+
when(command: C): When<S, C, D>;
|
|
80
|
+
}
|
|
81
|
+
/** A {@link Scenario} with its command, ready to run. */
|
|
82
|
+
export declare class When<S, C, D extends EventDefinitions> {
|
|
83
|
+
#private;
|
|
84
|
+
constructor(aggregate: Aggregate<S, C, D>, setup: ScenarioSetup<D>, command: C);
|
|
85
|
+
/**
|
|
86
|
+
* Seeds the given events, runs the command, and resolves to its {@link Outcome}. Each call does
|
|
87
|
+
* both again. Invalid store options or a failure to seed throw; a failure of the command is the
|
|
88
|
+
* outcome's.
|
|
89
|
+
*/
|
|
90
|
+
run(): Promise<Outcome<S, C, D>>;
|
|
91
|
+
/** Asserts that the command commits exactly these events. */
|
|
92
|
+
thenEvents(...expected: EventOf<D>[]): Promise<void>;
|
|
93
|
+
/** Asserts that the command commits and emits nothing. */
|
|
94
|
+
thenNoEvents(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Asserts that the handler rejects the command, with this code or a rejection `matches`
|
|
97
|
+
* accepts.
|
|
98
|
+
*/
|
|
99
|
+
thenRejected(matches?: string | ((rejection: Rejection) => boolean)): Promise<void>;
|
|
100
|
+
/** Asserts that the command is a duplicate of one already in the dedupe window. */
|
|
101
|
+
thenDuplicate(): Promise<void>;
|
|
102
|
+
/** Asserts that the store throws, with an error `matches` accepts. */
|
|
103
|
+
thenError(matches?: (error: unknown) => boolean): Promise<void>;
|
|
104
|
+
/** Asserts that the command commits, then hands `check` the state after it. */
|
|
105
|
+
thenState(check: (state: S) => void | Promise<void>): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
/** The result of a command that committed. */
|
|
108
|
+
export type Committed<S> = Extract<ExecuteResult<S>, {
|
|
109
|
+
kind: 'committed';
|
|
110
|
+
}>;
|
|
111
|
+
/** What running a {@link Scenario} did. */
|
|
112
|
+
export declare class Outcome<S, C, D extends EventDefinitions> {
|
|
113
|
+
#private;
|
|
114
|
+
readonly aggregate: Aggregate<S, C, D>;
|
|
115
|
+
/** The fixture the scenario ran on, to inspect other streams. */
|
|
116
|
+
readonly fixture: Fixture;
|
|
117
|
+
readonly entityId: string;
|
|
118
|
+
/** What {@link Store.execute} resolved to, or the error it threw. */
|
|
119
|
+
readonly settled: PromiseSettledResult<ExecuteResult<S>>;
|
|
120
|
+
constructor(aggregate: Aggregate<S, C, D>, fixture: Fixture, entityId: string, settled: PromiseSettledResult<ExecuteResult<S>>);
|
|
121
|
+
/** The events as stored, if the command committed. */
|
|
122
|
+
get storedEvents(): SerializedEvent[] | null;
|
|
123
|
+
/** The aggregate after the command. Throws unless it committed. */
|
|
124
|
+
get state(): Loaded<S>;
|
|
125
|
+
/** Asserts that the command committed, and returns what it did. */
|
|
126
|
+
assertCommitted(): Committed<S>;
|
|
127
|
+
/** Asserts that the command committed exactly these events, decoded. */
|
|
128
|
+
assertEvents(...expected: EventOf<D>[]): void;
|
|
129
|
+
/** Asserts that the handler rejected the command, with this code or as `matches` accepts. */
|
|
130
|
+
assertRejected(matches?: string | ((rejection: Rejection) => boolean)): Rejection;
|
|
131
|
+
/** Asserts that the command was a duplicate, and returns its command ID. */
|
|
132
|
+
assertDuplicate(): string;
|
|
133
|
+
/** Asserts that the store threw, with an error `matches` accepts, and returns the error. */
|
|
134
|
+
assertError(matches?: (error: unknown) => boolean): unknown;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=scenario.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../src/testing/scenario.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,OAAO,EACZ,KAAK,SAAS,EAGf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAC,KAAK,eAAe,EAAU,MAAM,aAAa,CAAA;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAC,KAAK,QAAQ,EAAgB,MAAM,gBAAgB,CAAA;AAC3D,OAAO,EAAC,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,YAAY,EAAC,MAAM,aAAa,CAAA;AAGrF,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,aAAa,CAAA;AAE3C;;;;GAIG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAA;IAElC,YAAY,UAAU,GAAE,aAAmC,EAE1D;IAED,6CAA6C;IAC7C,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,KAAK,CAEvC;IAED;;;;;OAKG;IACG,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB,EAC1C,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CAyBf;IAED,oEAAoE;IAC9D,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB,EAC3C,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAIvB;IAED,uFAAuF;IACvF,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB,EACnC,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC7B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAEpB;IAED,mEAAmE;IAC7D,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB,EACjD,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CAIf;CACF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB,EACvD,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC5B,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAQnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,gBAAgB;IACvD,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;CAC/B;AAED;;;;GAIG;AACH,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB;;IACpD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAGtC,YAAY,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAGjE;IAED,uDAAuD;IACvD,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAEhD;IAED,0EAA0E;IAC1E,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAE1C;IAED,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAEvD;IAED,oFAAoF;IACpF,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAEhD;IAED;;;;OAIG;IACH,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAEtC;IAED,gCAAgC;IAChC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAE9B;CAKF;AAED,yDAAyD;AACzD,qBAAa,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB;;IAKhD,YAAY,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAI7E;IAED;;;;OAIG;IACG,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAerC;IAED,6DAA6D;IACvD,UAAU,CAAC,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzD;IAED,0DAA0D;IACpD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAGlC;IAED;;;OAGG;IACG,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxF;IAED,mFAAmF;IAC7E,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAGnC;IAED,sEAAsE;IAChE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE;IAED,+EAA+E;IACzE,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxE;CACF;AAED,8CAA8C;AAC9C,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;IAAC,IAAI,EAAE,WAAW,CAAA;CAAC,CAAC,CAAA;AAEzE,2CAA2C;AAC3C,qBAAa,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,gBAAgB;;IACnD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACtC,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IAExD,YACE,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC7B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,oBAAoB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAMhD;IAED,sDAAsD;IACtD,IAAI,YAAY,IAAI,eAAe,EAAE,GAAG,IAAI,CAM3C;IAED,mEAAmE;IACnE,IAAI,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,CAErB;IAED,mEAAmE;IACnE,eAAe,IAAI,SAAS,CAAC,CAAC,CAAC,CAS9B;IAED,wEAAwE;IACxE,YAAY,CAAC,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAK5C;IAED,6FAA6F;IAC7F,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,GAAG,SAAS,CAoBhF;IAED,4EAA4E;IAC5E,eAAe,IAAI,MAAM,CAOxB;IAED,4FAA4F;IAC5F,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAU1D;CAkBF"}
|