@reventlessdev/reventless-core 3.0.0-alpha.170 → 3.0.0-alpha.172

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.
Files changed (83) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +14 -14
  3. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +5 -2
  4. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res.mjs +3 -3
  5. package/src/components/Heartbeat/Heartbeat.res +2 -2
  6. package/src/components/Heartbeat/Heartbeat_Builder.res +2 -2
  7. package/src/components/Heartbeat/Heartbeat_Builder.res.mjs +2 -4
  8. package/src/components/Task/Task_Builder.res +6 -4
  9. package/src/components/Task/Task_Builder.res.mjs +4 -4
  10. package/src/plugin/component/Plugin_Builder.res +5 -1
  11. package/src/plugin/component/Plugin_Builder.res.mjs +1 -1
  12. package/src/plugin/component/Plugin_Helpers.res +6 -1
  13. package/src/plugin/connect/PluginExtensionPoint_Builder.res +2 -0
  14. package/src/plugin/connect/PluginExtensionPoint_Builder.res.mjs +3 -3
  15. package/src/plugin/connect/PluginExtensionPoint_Plugin.res +12 -5
  16. package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +8 -2
  17. package/tests/plugin/HeartbeatDisconnectGraceTest.res +98 -0
  18. package/tests/IdentityTest.res.mjs +0 -174
  19. package/tests/adapter/MonitoringTest.res.mjs +0 -82
  20. package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +0 -356
  21. package/tests/admin/Platform_UIFragmentsApiTest.res.mjs +0 -101
  22. package/tests/aggregate/AggregateCacheTest.res.mjs +0 -433
  23. package/tests/aggregate/AggregateCallbackTest.res.mjs +0 -143
  24. package/tests/aggregate/AggregateCausationTest.res.mjs +0 -47
  25. package/tests/aggregate/AggregateConflictTest.res.mjs +0 -386
  26. package/tests/aggregate/AggregateFixtures.res.mjs +0 -308
  27. package/tests/aggregate/AggregateRejectionTest.res.mjs +0 -166
  28. package/tests/aggregate/AggregateSnapshotTest.res.mjs +0 -645
  29. package/tests/api/ApiNoApiTest.res.mjs +0 -90
  30. package/tests/api/GraphQL_StitcherTest.res.mjs +0 -112
  31. package/tests/api/SimpleTest.res.mjs +0 -10
  32. package/tests/api/SuryToJsonSchemaTest.res.mjs +0 -674
  33. package/tests/commandgenerator/CommandGeneratorCallbackTest.res.mjs +0 -160
  34. package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +0 -197
  35. package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +0 -152
  36. package/tests/commandtopic/CommandTopicCallbackTest.res.mjs +0 -106
  37. package/tests/commandtopic/CommandTopicHelpersRejectionTest.res.mjs +0 -109
  38. package/tests/counter/CounterCallbackTest.res.mjs +0 -140
  39. package/tests/counter/CounterFixtures.res.mjs +0 -67
  40. package/tests/dcb/DcbDecodeTest.res.mjs +0 -194
  41. package/tests/dcb/DcbEventLogOperationsTest.res.mjs +0 -268
  42. package/tests/dcb/DcbFixtures.res.mjs +0 -534
  43. package/tests/dcb/DcbScopeInferenceTest.res.mjs +0 -480
  44. package/tests/dcb/DcbStateChangeSliceTest.res.mjs +0 -540
  45. package/tests/dcb/DcbTagTest.res.mjs +0 -867
  46. package/tests/dcb/DcbValidationTest.res.mjs +0 -476
  47. package/tests/eventlog/EventLogFixtures.res.mjs +0 -196
  48. package/tests/eventlog/EventLogOperationsTest.res.mjs +0 -192
  49. package/tests/eventlog/EventLogRetryTest.res.mjs +0 -195
  50. package/tests/eventmapper/EventMapperCallbackTest.res.mjs +0 -141
  51. package/tests/eventmapper/EventMapperFixtures.res.mjs +0 -440
  52. package/tests/eventmapper/EventMapperTest.res.mjs +0 -83
  53. package/tests/eventtopic/EventTopicFixtures.res.mjs +0 -65
  54. package/tests/eventtopic/EventTopicOperationsTest.res.mjs +0 -71
  55. package/tests/extensionpoint/ExtensionPointCallbackTest.res.mjs +0 -94
  56. package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +0 -205
  57. package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +0 -304
  58. package/tests/ftp/FTPTest.res.mjs +0 -88
  59. package/tests/logger/LogFormatTest.res.mjs +0 -309
  60. package/tests/logger/LoggerLazyTest.res.mjs +0 -40
  61. package/tests/message/MessageTest.res.mjs +0 -218
  62. package/tests/message/MetaEnvelopeTest.res.mjs +0 -188
  63. package/tests/plugin/ManifestVisibilityTest.res.mjs +0 -215
  64. package/tests/plugin/PluginSpecExperiment.res.mjs +0 -31
  65. package/tests/plugin/PluginStructureTest.res.mjs +0 -419
  66. package/tests/plugin/PluginVersionTest.res.mjs +0 -30
  67. package/tests/plugin/SchemaWalkerTest.res.mjs +0 -160
  68. package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +0 -62
  69. package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +0 -69
  70. package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +0 -95
  71. package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +0 -69
  72. package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +0 -69
  73. package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +0 -81
  74. package/tests/poc/StructuralSubtypingPoc.res.mjs +0 -61
  75. package/tests/projection/ProjectionOptimizeTest.res.mjs +0 -75
  76. package/tests/querydb/QueryDbFixtures.res.mjs +0 -135
  77. package/tests/querydb/QueryDbOperationsTest.res.mjs +0 -168
  78. package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res.mjs +0 -77
  79. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +0 -139
  80. package/tests/util/CommandPublisherTest.res.mjs +0 -78
  81. package/tests/util/CsvStreamTest.res.mjs +0 -51
  82. package/tests/util/LruTest.res.mjs +0 -105
  83. package/tests/util/MetricsTest.res.mjs +0 -53
@@ -1,540 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
4
- import * as Effect from "effect/Effect";
5
- import * as Stream from "effect/Stream";
6
- import * as DcbFixtures$ReventlessCore from "./DcbFixtures.res.mjs";
7
- import * as DcbEventLog_Operations$ReventlessCore from "../../src/components/DcbEventLog/DcbEventLog_Operations.res.mjs";
8
- import * as StateChangeSlice_Callback$ReventlessCore from "../../src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs";
9
-
10
- let mock = DcbFixtures$ReventlessCore.makeMockStorage();
11
-
12
- let storage = mock.operations;
13
-
14
- let publishJson = mock.mockPublishJson;
15
-
16
- let TestDcbOps = {
17
- name: "TestDcbEventLog",
18
- serviceName: "TestDcbEventLog",
19
- storage: storage,
20
- publishJson: publishJson
21
- };
22
-
23
- let EventLogOps = DcbEventLog_Operations$ReventlessCore.Make(TestDcbOps);
24
-
25
- let testDcbEventLog_read = EventLogOps.read;
26
-
27
- let testDcbEventLog_append = EventLogOps.append;
28
-
29
- let testDcbEventLog_readStream = EventLogOps.readStream;
30
-
31
- let testDcbEventLog_appendStream = EventLogOps.appendStream;
32
-
33
- let testDcbEventLog = {
34
- read: testDcbEventLog_read,
35
- append: testDcbEventLog_append,
36
- readStream: testDcbEventLog_readStream,
37
- appendStream: testDcbEventLog_appendStream
38
- };
39
-
40
- let initialState = DcbFixtures$ReventlessCore.TestCommandSpec.initialState;
41
-
42
- let evolve = DcbFixtures$ReventlessCore.TestCommandSpec.evolve;
43
-
44
- let decide = DcbFixtures$ReventlessCore.TestCommandSpec.decide;
45
-
46
- let moduleUrl = DcbFixtures$ReventlessCore.TestCommandSpec.moduleUrl;
47
-
48
- let TestCommandBehavior = {
49
- initialState: initialState,
50
- evolve: evolve,
51
- decide: decide,
52
- moduleUrl: moduleUrl
53
- };
54
-
55
- let TestHandler = StateChangeSlice_Callback$ReventlessCore.Make({
56
- name: DcbFixtures$ReventlessCore.TestCommandSpec.name,
57
- moduleUrl: DcbFixtures$ReventlessCore.TestCommandSpec.moduleUrl,
58
- Id: Id$Reventless.$$String,
59
- consumedEventSchema: DcbFixtures$ReventlessCore.TestCommandSpec.consumedEventSchema,
60
- errorSchema: DcbFixtures$ReventlessCore.TestCommandSpec.errorSchema,
61
- eventSchema: DcbFixtures$ReventlessCore.TestCommandSpec.eventSchema,
62
- commandSchema: DcbFixtures$ReventlessCore.TestCommandSpec.commandSchema,
63
- commandAuthorization: DcbFixtures$ReventlessCore.TestCommandSpec.commandAuthorization,
64
- readConsistency: DcbFixtures$ReventlessCore.TestCommandSpec.readConsistency
65
- })(TestCommandBehavior);
66
-
67
- let name = DcbFixtures$ReventlessCore.TestCommandSpec.name;
68
-
69
- let moduleUrl$1 = DcbFixtures$ReventlessCore.TestCommandSpec.moduleUrl;
70
-
71
- let eventSchema = DcbFixtures$ReventlessCore.TestCommandSpec.eventSchema;
72
-
73
- let consumedEventSchema = DcbFixtures$ReventlessCore.TestCommandSpec.consumedEventSchema;
74
-
75
- let commandSchema = DcbFixtures$ReventlessCore.TestCommandSpec.commandSchema;
76
-
77
- let errorSchema = DcbFixtures$ReventlessCore.TestCommandSpec.errorSchema;
78
-
79
- let commandAuthorization = DcbFixtures$ReventlessCore.TestCommandSpec.commandAuthorization;
80
-
81
- let StrongSpec_Id = DcbFixtures$ReventlessCore.TestCommandSpec.Id;
82
-
83
- let StrongSpec_initialState = DcbFixtures$ReventlessCore.TestCommandSpec.initialState;
84
-
85
- let StrongSpec_evolve = DcbFixtures$ReventlessCore.TestCommandSpec.evolve;
86
-
87
- let StrongSpec_decide = DcbFixtures$ReventlessCore.TestCommandSpec.decide;
88
-
89
- let StrongSpec = {
90
- name: name,
91
- Id: StrongSpec_Id,
92
- moduleUrl: moduleUrl$1,
93
- eventSchema: eventSchema,
94
- consumedEventSchema: consumedEventSchema,
95
- commandSchema: commandSchema,
96
- errorSchema: errorSchema,
97
- initialState: StrongSpec_initialState,
98
- evolve: StrongSpec_evolve,
99
- decide: StrongSpec_decide,
100
- commandAuthorization: commandAuthorization,
101
- readConsistency: "AlwaysStrong"
102
- };
103
-
104
- let name$1 = DcbFixtures$ReventlessCore.TestCommandSpec.name;
105
-
106
- let moduleUrl$2 = DcbFixtures$ReventlessCore.TestCommandSpec.moduleUrl;
107
-
108
- let eventSchema$1 = DcbFixtures$ReventlessCore.TestCommandSpec.eventSchema;
109
-
110
- let consumedEventSchema$1 = DcbFixtures$ReventlessCore.TestCommandSpec.consumedEventSchema;
111
-
112
- let commandSchema$1 = DcbFixtures$ReventlessCore.TestCommandSpec.commandSchema;
113
-
114
- let errorSchema$1 = DcbFixtures$ReventlessCore.TestCommandSpec.errorSchema;
115
-
116
- let commandAuthorization$1 = DcbFixtures$ReventlessCore.TestCommandSpec.commandAuthorization;
117
-
118
- let EventualSpec_Id = DcbFixtures$ReventlessCore.TestCommandSpec.Id;
119
-
120
- let EventualSpec_initialState = DcbFixtures$ReventlessCore.TestCommandSpec.initialState;
121
-
122
- let EventualSpec_evolve = DcbFixtures$ReventlessCore.TestCommandSpec.evolve;
123
-
124
- let EventualSpec_decide = DcbFixtures$ReventlessCore.TestCommandSpec.decide;
125
-
126
- let EventualSpec = {
127
- name: name$1,
128
- Id: EventualSpec_Id,
129
- moduleUrl: moduleUrl$2,
130
- eventSchema: eventSchema$1,
131
- consumedEventSchema: consumedEventSchema$1,
132
- commandSchema: commandSchema$1,
133
- errorSchema: errorSchema$1,
134
- initialState: EventualSpec_initialState,
135
- evolve: EventualSpec_evolve,
136
- decide: EventualSpec_decide,
137
- commandAuthorization: commandAuthorization$1,
138
- readConsistency: "AlwaysEventual"
139
- };
140
-
141
- let StrongHandler = StateChangeSlice_Callback$ReventlessCore.Make({
142
- name: name,
143
- moduleUrl: moduleUrl$1,
144
- Id: Id$Reventless.$$String,
145
- consumedEventSchema: consumedEventSchema,
146
- errorSchema: errorSchema,
147
- eventSchema: eventSchema,
148
- commandSchema: commandSchema,
149
- commandAuthorization: commandAuthorization,
150
- readConsistency: "AlwaysStrong"
151
- })(TestCommandBehavior);
152
-
153
- let EventualHandler = StateChangeSlice_Callback$ReventlessCore.Make({
154
- name: name$1,
155
- moduleUrl: moduleUrl$2,
156
- Id: Id$Reventless.$$String,
157
- consumedEventSchema: consumedEventSchema$1,
158
- errorSchema: errorSchema$1,
159
- eventSchema: eventSchema$1,
160
- commandSchema: commandSchema$1,
161
- commandAuthorization: commandAuthorization$1,
162
- readConsistency: "AlwaysEventual"
163
- })(TestCommandBehavior);
164
-
165
- function makeTopicItem(reference, command) {
166
- return {
167
- command: {
168
- id: Id$Reventless.$$String.makeFromString("cmd-" + reference),
169
- meta: DcbFixtures$ReventlessCore.testMeta,
170
- command: command
171
- },
172
- reference: reference
173
- };
174
- }
175
-
176
- globalThis.beforeEach(() => {
177
- mock.reset();
178
- TestHandler.resetCache();
179
- StrongHandler.resetCache();
180
- EventualHandler.resetCache();
181
- });
182
-
183
- globalThis.describe("StateChangeSlice_Callback:", () => {
184
- globalThis.describe("handleCommands - happy path", () => {
185
- globalThis.test("CreateItem on empty log succeeds", async () => {
186
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
187
- TAG: "CreateItem",
188
- itemId: "item-1",
189
- name: "Test"
190
- })])));
191
- globalThis.expect([
192
- results,
193
- mock.getEvents().length,
194
- mock.publishedEvents.contents.length
195
- ]).toEqual([
196
- [{
197
- TAG: "Ok",
198
- _0: "ref-1"
199
- }],
200
- 1,
201
- 1
202
- ]);
203
- });
204
- globalThis.test("stored event carries only its entity tags (no framework provenance tag)", async () => {
205
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
206
- TAG: "CreateItem",
207
- itemId: "item-1",
208
- name: "Test"
209
- })])));
210
- let storedEvent = mock.getEvents()[0];
211
- globalThis.expect(storedEvent.tags).toEqual([{
212
- key: "itemId",
213
- value: "item-1"
214
- }]);
215
- });
216
- });
217
- globalThis.describe("handleCommands - decide returns Ok([])", () => {
218
- globalThis.test("NoOp returns Ok without storing events", async () => {
219
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-noop", "NoOp")])));
220
- globalThis.expect([
221
- results,
222
- mock.getEvents().length
223
- ]).toEqual([
224
- [{
225
- TAG: "Ok",
226
- _0: "ref-noop"
227
- }],
228
- 0
229
- ]);
230
- });
231
- });
232
- globalThis.describe("handleCommands - decide returns Error", () => {
233
- globalThis.test("CreateItem when item exists returns Ok (business-rule violations ACK, not NACK)", async () => {
234
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
235
- TAG: "CreateItem",
236
- itemId: "item-1",
237
- name: "Test"
238
- })])));
239
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-2", {
240
- TAG: "CreateItem",
241
- itemId: "item-1",
242
- name: "Duplicate"
243
- })])));
244
- globalThis.expect(results).toEqual([{
245
- TAG: "Ok",
246
- _0: "ref-2"
247
- }]);
248
- });
249
- });
250
- globalThis.describe("handleCommands - retry on conflict", () => {
251
- globalThis.test("retries and succeeds after 1 append failure", async () => {
252
- mock.failNextAppends.contents = 1;
253
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
254
- TAG: "CreateItem",
255
- itemId: "item-1",
256
- name: "Test"
257
- })])));
258
- globalThis.expect([
259
- results,
260
- mock.getEvents().length
261
- ]).toEqual([
262
- [{
263
- TAG: "Ok",
264
- _0: "ref-1"
265
- }],
266
- 1
267
- ]);
268
- });
269
- globalThis.test("returns Error after retries exhausted (4 failures)", async () => {
270
- mock.failNextAppends.contents = 4;
271
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
272
- TAG: "CreateItem",
273
- itemId: "item-1",
274
- name: "Test"
275
- })])));
276
- globalThis.expect([
277
- results,
278
- mock.getEvents().length
279
- ]).toEqual([
280
- [{
281
- TAG: "Error",
282
- _0: "ref-1"
283
- }],
284
- 0
285
- ]);
286
- });
287
- });
288
- globalThis.describe("handleCommands - read consistency (eventual-first, strong-on-retry)", () => {
289
- globalThis.test("a conflict-free command reads eventually-consistent (no strong read)", async () => {
290
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
291
- TAG: "CreateItem",
292
- itemId: "item-1",
293
- name: "Test"
294
- })])));
295
- globalThis.expect(mock.readStrongConsistency.contents).toEqual([false]);
296
- });
297
- globalThis.test("escalates to strong consistency on retry after a conflict", async () => {
298
- mock.failNextAppends.contents = 1;
299
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
300
- TAG: "CreateItem",
301
- itemId: "item-1",
302
- name: "Test"
303
- })])));
304
- globalThis.expect(mock.readStrongConsistency.contents).toEqual([
305
- false,
306
- true
307
- ]);
308
- });
309
- globalThis.test("every retry after the first is strong (2 failures)", async () => {
310
- mock.failNextAppends.contents = 2;
311
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
312
- TAG: "CreateItem",
313
- itemId: "item-1",
314
- name: "Test"
315
- })])));
316
- globalThis.expect(mock.readStrongConsistency.contents).toEqual([
317
- false,
318
- true,
319
- true
320
- ]);
321
- });
322
- });
323
- globalThis.describe("handleCommands - read consistency (per-slice override)", () => {
324
- globalThis.test("AlwaysStrong reads strong on the first attempt", async () => {
325
- await Effect.runPromise(StrongHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
326
- TAG: "CreateItem",
327
- itemId: "item-1",
328
- name: "Test"
329
- })])));
330
- globalThis.expect(mock.readStrongConsistency.contents).toEqual([true]);
331
- });
332
- globalThis.test("AlwaysStrong stays strong across retries (2 failures)", async () => {
333
- mock.failNextAppends.contents = 2;
334
- await Effect.runPromise(StrongHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
335
- TAG: "CreateItem",
336
- itemId: "item-1",
337
- name: "Test"
338
- })])));
339
- globalThis.expect(mock.readStrongConsistency.contents).toEqual([
340
- true,
341
- true,
342
- true
343
- ]);
344
- });
345
- globalThis.test("AlwaysEventual never reads strong, even on retry (2 failures)", async () => {
346
- mock.failNextAppends.contents = 2;
347
- await Effect.runPromise(EventualHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
348
- TAG: "CreateItem",
349
- itemId: "item-1",
350
- name: "Test"
351
- })])));
352
- globalThis.expect(mock.readStrongConsistency.contents).toEqual([
353
- false,
354
- false,
355
- false
356
- ]);
357
- });
358
- });
359
- globalThis.describe("handleCommands - conditional append", () => {
360
- globalThis.test("RenameItem after CreateItem uses headPosition in condition", async () => {
361
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-1", {
362
- TAG: "CreateItem",
363
- itemId: "item-1",
364
- name: "Test"
365
- })])));
366
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-2", {
367
- TAG: "RenameItem",
368
- itemId: "item-1",
369
- newName: "Updated"
370
- })])));
371
- globalThis.expect([
372
- results,
373
- mock.getEvents().length
374
- ]).toEqual([
375
- [{
376
- TAG: "Ok",
377
- _0: "ref-2"
378
- }],
379
- 2
380
- ]);
381
- });
382
- });
383
- globalThis.describe("handleCommands - batch", () => {
384
- globalThis.test("multiple successful commands", async () => {
385
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([
386
- makeTopicItem("ref-1", {
387
- TAG: "CreateItem",
388
- itemId: "item-1",
389
- name: "First"
390
- }),
391
- makeTopicItem("ref-2", {
392
- TAG: "CreateItem",
393
- itemId: "item-2",
394
- name: "Second"
395
- })
396
- ])));
397
- globalThis.expect(results).toEqual([
398
- {
399
- TAG: "Ok",
400
- _0: "ref-1"
401
- },
402
- {
403
- TAG: "Ok",
404
- _0: "ref-2"
405
- }
406
- ]);
407
- });
408
- globalThis.test("mixed: new item succeeds, duplicate item ACKs as Ok (business-rule violation)", async () => {
409
- await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem("ref-0", {
410
- TAG: "CreateItem",
411
- itemId: "item-1",
412
- name: "Existing"
413
- })])));
414
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([
415
- makeTopicItem("ref-1", {
416
- TAG: "CreateItem",
417
- itemId: "item-2",
418
- name: "New"
419
- }),
420
- makeTopicItem("ref-2", {
421
- TAG: "CreateItem",
422
- itemId: "item-1",
423
- name: "Duplicate"
424
- })
425
- ])));
426
- globalThis.expect(results).toEqual([
427
- {
428
- TAG: "Ok",
429
- _0: "ref-1"
430
- },
431
- {
432
- TAG: "Ok",
433
- _0: "ref-2"
434
- }
435
- ]);
436
- });
437
- globalThis.test("empty batch returns empty array", async () => {
438
- let results = await Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([])));
439
- globalThis.expect(results).toEqual([]);
440
- });
441
- });
442
- globalThis.describe("handleCommands - projection cache", () => {
443
- globalThis.test("a third same-entity command reads only the delta", async () => {
444
- let run = (reference, command) => Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem(reference, command)])));
445
- await run("ref-1", {
446
- TAG: "CreateItem",
447
- itemId: "item-1",
448
- name: "A"
449
- });
450
- await run("ref-2", {
451
- TAG: "RenameItem",
452
- itemId: "item-1",
453
- newName: "B"
454
- });
455
- let r3 = await run("ref-3", {
456
- TAG: "RenameItem",
457
- itemId: "item-1",
458
- newName: "C"
459
- });
460
- globalThis.expect([
461
- r3,
462
- mock.readAfters.contents,
463
- mock.getEvents().length
464
- ]).toEqual([
465
- [{
466
- TAG: "Ok",
467
- _0: "ref-3"
468
- }],
469
- [
470
- undefined,
471
- undefined,
472
- "1"
473
- ],
474
- 3
475
- ]);
476
- });
477
- globalThis.test("a different entity does not hit another entity's cache (full read)", async () => {
478
- let run = (reference, command) => Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem(reference, command)])));
479
- await run("ref-1", {
480
- TAG: "CreateItem",
481
- itemId: "item-1",
482
- name: "A"
483
- });
484
- await run("ref-2", {
485
- TAG: "CreateItem",
486
- itemId: "item-2",
487
- name: "B"
488
- });
489
- globalThis.expect(mock.readAfters.contents).toEqual([
490
- undefined,
491
- undefined
492
- ]);
493
- });
494
- globalThis.test("conflict re-seeds the cache so the retry reads the delta", async () => {
495
- let run = (reference, command) => Effect.runPromise(TestHandler.handleCommands(undefined, undefined, testDcbEventLog, Stream.fromIterable([makeTopicItem(reference, command)])));
496
- await run("ref-1", {
497
- TAG: "CreateItem",
498
- itemId: "item-1",
499
- name: "A"
500
- });
501
- mock.failNextAppends.contents = 1;
502
- let r2 = await run("ref-2", {
503
- TAG: "RenameItem",
504
- itemId: "item-1",
505
- newName: "B"
506
- });
507
- globalThis.expect([
508
- r2,
509
- mock.readAfters.contents,
510
- mock.getEvents().length
511
- ]).toEqual([
512
- [{
513
- TAG: "Ok",
514
- _0: "ref-2"
515
- }],
516
- [
517
- undefined,
518
- undefined,
519
- "1"
520
- ],
521
- 2
522
- ]);
523
- });
524
- });
525
- });
526
-
527
- export {
528
- mock,
529
- TestDcbOps,
530
- EventLogOps,
531
- testDcbEventLog,
532
- TestCommandBehavior,
533
- TestHandler,
534
- StrongSpec,
535
- EventualSpec,
536
- StrongHandler,
537
- EventualHandler,
538
- makeTopicItem,
539
- }
540
- /* mock Not a pure module */