@reventlessdev/reventless-core 3.0.0-alpha.283 → 3.0.0-alpha.285

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.
@@ -0,0 +1,1018 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Stream from "effect/Stream";
8
+ import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
9
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
10
+ import * as Identity$Reventless from "@reventlessdev/reventless-spec/src/types/Identity.res.mjs";
11
+ import * as OwnerScope$Reventless from "@reventlessdev/reventless-spec/src/types/OwnerScope.res.mjs";
12
+ import * as Message$ReventlessCore from "../../src/Message.res.mjs";
13
+ import * as DcbFixtures$ReventlessCore from "../dcb/DcbFixtures.res.mjs";
14
+ import * as Aggregate_Callback$ReventlessCore from "../../src/components/Aggregate/Aggregate_Callback.res.mjs";
15
+ import * as CommandTopic_Helpers$ReventlessCore from "../../src/components/CommandTopic/CommandTopic_Helpers.res.mjs";
16
+ import * as DcbEventLog_Operations$ReventlessCore from "../../src/components/DcbEventLog/DcbEventLog_Operations.res.mjs";
17
+ import * as CommandGenerator_Callback$ReventlessCore from "../../src/components/CommandGenerator/CommandGenerator_Callback.res.mjs";
18
+ import * as StateChangeSlice_Callback$ReventlessCore from "../../src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs";
19
+
20
+ let name = "OwnedOrders";
21
+
22
+ let moduleUrl = import.meta.url;
23
+
24
+ let eventSchema = Sury.union([
25
+ Sury.$schema(s => ({
26
+ TAG: "OrderPlaced",
27
+ orderId: s.m(DcbTag$Reventless.string),
28
+ customerId: s.m(Sury.string)
29
+ })),
30
+ Sury.$schema(s => ({
31
+ TAG: "OrderCancelled",
32
+ orderId: s.m(DcbTag$Reventless.string)
33
+ }))
34
+ ]);
35
+
36
+ let consumedEventSchema = Sury.union([
37
+ Sury.$schema(s => ({
38
+ TAG: "OrderPlaced",
39
+ orderId: s.m(DcbTag$Reventless.string),
40
+ customerId: s.m(Owner$Reventless.string)
41
+ })),
42
+ Sury.$schema(s => ({
43
+ TAG: "OrderCancelled",
44
+ orderId: s.m(DcbTag$Reventless.string)
45
+ })),
46
+ Sury.$schema(s => ({
47
+ TAG: "ProductListed",
48
+ productId: s.m(DcbTag$Reventless.string),
49
+ sellerId: s.m(Owner$Reventless.string)
50
+ }))
51
+ ]);
52
+
53
+ let commandSchema = Sury.union([
54
+ Sury.$schema(s => ({
55
+ TAG: "PlaceOrder",
56
+ orderId: s.m(DcbTag$Reventless.string),
57
+ customerId: s.m(Owner$Reventless.string)
58
+ })),
59
+ Sury.$schema(s => ({
60
+ TAG: "CancelOrder",
61
+ orderId: s.m(DcbTag$Reventless.string)
62
+ })),
63
+ Sury.$schema(s => ({
64
+ TAG: "ReviewOrder",
65
+ orderId: s.m(DcbTag$Reventless.string),
66
+ productId: s.m(DcbTag$Reventless.string)
67
+ }))
68
+ ]);
69
+
70
+ let errorSchema = Sury.union([
71
+ Sury.literal("OrderAlreadyPlaced"),
72
+ Sury.literal("OrderNotFound")
73
+ ]);
74
+
75
+ function commandAuthorization(param) {
76
+ return "AllowAuthenticated";
77
+ }
78
+
79
+ function commandTransition(param) {
80
+ return "Undeclared";
81
+ }
82
+
83
+ let traits = [];
84
+
85
+ let OrderSlice = {
86
+ name: name,
87
+ Id: undefined,
88
+ moduleUrl: moduleUrl,
89
+ eventSchema: eventSchema,
90
+ consumedEventSchema: consumedEventSchema,
91
+ commandSchema: commandSchema,
92
+ errorSchema: errorSchema,
93
+ commandAuthorization: commandAuthorization,
94
+ commandTransition: commandTransition,
95
+ traits: traits,
96
+ readConsistency: "EscalateOnRetry"
97
+ };
98
+
99
+ let initialState = {
100
+ placed: false,
101
+ cancelled: false
102
+ };
103
+
104
+ function evolve(state, event) {
105
+ switch (event.TAG) {
106
+ case "OrderPlaced" :
107
+ return {
108
+ placed: true,
109
+ cancelled: state.cancelled
110
+ };
111
+ case "OrderCancelled" :
112
+ return {
113
+ placed: state.placed,
114
+ cancelled: true
115
+ };
116
+ case "ProductListed" :
117
+ return state;
118
+ }
119
+ }
120
+
121
+ function decide(state, command) {
122
+ switch (command.TAG) {
123
+ case "PlaceOrder" :
124
+ if (state.placed) {
125
+ return {
126
+ TAG: "Error",
127
+ _0: "OrderAlreadyPlaced"
128
+ };
129
+ } else {
130
+ return {
131
+ TAG: "Ok",
132
+ _0: [{
133
+ TAG: "OrderPlaced",
134
+ orderId: command.orderId,
135
+ customerId: command.customerId
136
+ }]
137
+ };
138
+ }
139
+ case "CancelOrder" :
140
+ let match = state.placed;
141
+ let match$1 = state.cancelled;
142
+ if (match) {
143
+ if (match$1) {
144
+ return {
145
+ TAG: "Ok",
146
+ _0: []
147
+ };
148
+ } else {
149
+ return {
150
+ TAG: "Ok",
151
+ _0: [{
152
+ TAG: "OrderCancelled",
153
+ orderId: command.orderId
154
+ }]
155
+ };
156
+ }
157
+ } else {
158
+ return {
159
+ TAG: "Error",
160
+ _0: "OrderNotFound"
161
+ };
162
+ }
163
+ case "ReviewOrder" :
164
+ if (state.placed) {
165
+ return {
166
+ TAG: "Ok",
167
+ _0: []
168
+ };
169
+ } else {
170
+ return {
171
+ TAG: "Error",
172
+ _0: "OrderNotFound"
173
+ };
174
+ }
175
+ }
176
+ }
177
+
178
+ let OrderBehavior = {
179
+ initialState: initialState,
180
+ moduleUrl: moduleUrl,
181
+ evolve: evolve,
182
+ decide: decide
183
+ };
184
+
185
+ let OrderHandler = StateChangeSlice_Callback$ReventlessCore.Make({
186
+ name: name,
187
+ moduleUrl: moduleUrl,
188
+ consumedEventSchema: consumedEventSchema,
189
+ errorSchema: errorSchema,
190
+ eventSchema: eventSchema,
191
+ commandSchema: commandSchema,
192
+ commandAuthorization: commandAuthorization,
193
+ commandTransition: commandTransition,
194
+ traits: traits,
195
+ readConsistency: "EscalateOnRetry"
196
+ })({
197
+ initialState: initialState,
198
+ evolve: evolve,
199
+ decide: decide,
200
+ moduleUrl: moduleUrl
201
+ });
202
+
203
+ let dcbMock = DcbFixtures$ReventlessCore.makeMockStorage();
204
+
205
+ let storage = dcbMock.operations;
206
+
207
+ let publishJson = dcbMock.mockPublishJson;
208
+
209
+ let DcbOps = {
210
+ name: "OwnedOrdersEventLog",
211
+ serviceName: "OwnedOrdersEventLog",
212
+ storage: storage,
213
+ publishJson: publishJson
214
+ };
215
+
216
+ let DcbLog = DcbEventLog_Operations$ReventlessCore.Make(DcbOps);
217
+
218
+ let dcbEventLog_read = DcbLog.read;
219
+
220
+ let dcbEventLog_append = DcbLog.append;
221
+
222
+ let dcbEventLog_readStream = DcbLog.readStream;
223
+
224
+ let dcbEventLog_appendStream = DcbLog.appendStream;
225
+
226
+ let dcbEventLog = {
227
+ read: dcbEventLog_read,
228
+ append: dcbEventLog_append,
229
+ readStream: dcbEventLog_readStream,
230
+ appendStream: dcbEventLog_appendStream
231
+ };
232
+
233
+ let orderPartition = {
234
+ TAG: "Simple",
235
+ _0: {
236
+ key: "orderId"
237
+ }
238
+ };
239
+
240
+ let name$1 = "OwnedAccount";
241
+
242
+ let commandSchema$1 = Sury.union([
243
+ Sury.$schema(s => ({
244
+ TAG: "Open",
245
+ holderId: s.m(Owner$Reventless.string),
246
+ name: s.m(Sury.string)
247
+ })),
248
+ Sury.$schema(s => ({
249
+ TAG: "Rename",
250
+ newName: s.m(Sury.string)
251
+ }))
252
+ ]);
253
+
254
+ let eventSchema$1 = Sury.union([
255
+ Sury.$schema(s => ({
256
+ TAG: "Opened",
257
+ holderId: s.m(Owner$Reventless.string),
258
+ name: s.m(Sury.string)
259
+ })),
260
+ Sury.$schema(s => ({
261
+ TAG: "Renamed",
262
+ newName: s.m(Sury.string)
263
+ }))
264
+ ]);
265
+
266
+ let errorSchema$1 = Sury.union([
267
+ Sury.literal("AlreadyOpen"),
268
+ Sury.literal("NotFound")
269
+ ]);
270
+
271
+ let moduleUrl$1 = import.meta.url;
272
+
273
+ function commandAuthorization$1(param) {
274
+ return "AllowAuthenticated";
275
+ }
276
+
277
+ function commandTransition$1(param) {
278
+ return "Undeclared";
279
+ }
280
+
281
+ let traits$1 = [];
282
+
283
+ let AccountSpec = {
284
+ Id: undefined,
285
+ name: name$1,
286
+ commandSchema: commandSchema$1,
287
+ eventSchema: eventSchema$1,
288
+ errorSchema: errorSchema$1,
289
+ moduleUrl: moduleUrl$1,
290
+ commandAuthorization: commandAuthorization$1,
291
+ commandTransition: commandTransition$1,
292
+ traits: traits$1
293
+ };
294
+
295
+ let stateSchema = Sury.union([
296
+ Sury.literal("NotOpen"),
297
+ Sury.$schema(s => ({
298
+ TAG: "Active",
299
+ name: s.m(Sury.string)
300
+ }))
301
+ ]);
302
+
303
+ let snapshot = {
304
+ interval: 1,
305
+ stateSchema: stateSchema
306
+ };
307
+
308
+ function evolve$1(_state, event) {
309
+ if (event.TAG === "Opened") {
310
+ return {
311
+ TAG: "Active",
312
+ name: event.name
313
+ };
314
+ } else {
315
+ return {
316
+ TAG: "Active",
317
+ name: event.newName
318
+ };
319
+ }
320
+ }
321
+
322
+ function decide$1(state, command) {
323
+ if (typeof state !== "object") {
324
+ if (command.TAG === "Open") {
325
+ return {
326
+ TAG: "Ok",
327
+ _0: [{
328
+ TAG: "Opened",
329
+ holderId: command.holderId,
330
+ name: command.name
331
+ }]
332
+ };
333
+ } else {
334
+ return {
335
+ TAG: "Error",
336
+ _0: "NotFound"
337
+ };
338
+ }
339
+ } else if (command.TAG === "Open") {
340
+ return {
341
+ TAG: "Error",
342
+ _0: "AlreadyOpen"
343
+ };
344
+ } else {
345
+ return {
346
+ TAG: "Ok",
347
+ _0: [{
348
+ TAG: "Renamed",
349
+ newName: command.newName
350
+ }]
351
+ };
352
+ }
353
+ }
354
+
355
+ let AccountBehavior = {
356
+ Spec: undefined,
357
+ stateSchema: stateSchema,
358
+ initialState: "NotOpen",
359
+ snapshot: snapshot,
360
+ moduleUrl: moduleUrl$1,
361
+ evolve: evolve$1,
362
+ decide: decide$1
363
+ };
364
+
365
+ let accountEvents = {
366
+ contents: []
367
+ };
368
+
369
+ let snapshotReads = {
370
+ contents: 0
371
+ };
372
+
373
+ let name$2 = "OwnedAccountEventLog";
374
+
375
+ let Spec = {
376
+ Id: undefined,
377
+ name: name$2,
378
+ eventSchema: eventSchema$1
379
+ };
380
+
381
+ function make(param, param$1, param$2) {
382
+ return 0;
383
+ }
384
+
385
+ let EventLog = {
386
+ Spec: Spec,
387
+ make: make
388
+ };
389
+
390
+ function ofId(id) {
391
+ return accountEvents.contents.filter(e => e.id === id).map(e => e.event);
392
+ }
393
+
394
+ async function eventLog_append(_seqNr, _id, newEvents) {
395
+ accountEvents.contents = accountEvents.contents.concat(newEvents);
396
+ return {
397
+ TAG: "Ok",
398
+ _0: undefined
399
+ };
400
+ }
401
+
402
+ let eventLog_replay = ofId;
403
+
404
+ function eventLog_replayStream(id, param) {
405
+ return Stream.fromIterable(ofId(id));
406
+ }
407
+
408
+ function eventLog_appendStream(_seqNr, _id, stream) {
409
+ return Stream.runDrain(stream);
410
+ }
411
+
412
+ async function eventLog_latestSnapshot(param) {
413
+ snapshotReads.contents = snapshotReads.contents + 1 | 0;
414
+ return {
415
+ TAG: "Ok",
416
+ _0: undefined
417
+ };
418
+ }
419
+
420
+ async function eventLog_writeSnapshot(param, param$1) {
421
+ return {
422
+ TAG: "Ok",
423
+ _0: undefined
424
+ };
425
+ }
426
+
427
+ let eventLog = {
428
+ append: eventLog_append,
429
+ replay: eventLog_replay,
430
+ replayStream: eventLog_replayStream,
431
+ appendStream: eventLog_appendStream,
432
+ latestSnapshot: eventLog_latestSnapshot,
433
+ writeSnapshot: eventLog_writeSnapshot
434
+ };
435
+
436
+ let AccountOps = {
437
+ Spec: undefined,
438
+ EventLog: EventLog,
439
+ ofId: ofId,
440
+ eventLog: eventLog
441
+ };
442
+
443
+ let AccountHandler = Aggregate_Callback$ReventlessCore.Make({
444
+ Id: {
445
+ schema: Id$Reventless.StringPure.schema,
446
+ make: prim => prim,
447
+ makeFromString: prim => prim,
448
+ toString: prim => prim,
449
+ cmp: Id$Reventless.StringPure.cmp
450
+ },
451
+ name: name$1,
452
+ eventSchema: eventSchema$1,
453
+ errorSchema: errorSchema$1,
454
+ commandSchema: commandSchema$1,
455
+ moduleUrl: moduleUrl$1,
456
+ commandAuthorization: commandAuthorization$1,
457
+ commandTransition: commandTransition$1,
458
+ traits: traits$1
459
+ })({
460
+ initialState: "NotOpen",
461
+ evolve: evolve$1,
462
+ decide: decide$1,
463
+ snapshot: snapshot,
464
+ moduleUrl: moduleUrl$1
465
+ })({
466
+ Spec: {
467
+ Id: {
468
+ schema: Id$Reventless.StringPure.schema,
469
+ make: prim => prim,
470
+ makeFromString: prim => prim,
471
+ toString: prim => prim,
472
+ cmp: Id$Reventless.StringPure.cmp
473
+ },
474
+ name: name$1,
475
+ eventSchema: eventSchema$1,
476
+ errorSchema: errorSchema$1,
477
+ commandSchema: commandSchema$1,
478
+ moduleUrl: moduleUrl$1,
479
+ commandAuthorization: commandAuthorization$1,
480
+ commandTransition: commandTransition$1,
481
+ traits: traits$1
482
+ },
483
+ EventLog: {
484
+ Spec: {
485
+ Id: {
486
+ schema: Id$Reventless.StringPure.schema,
487
+ make: prim => prim,
488
+ makeFromString: prim => prim,
489
+ toString: prim => prim,
490
+ cmp: Id$Reventless.StringPure.cmp
491
+ },
492
+ name: name$2,
493
+ eventSchema: eventSchema$1
494
+ },
495
+ make: make
496
+ },
497
+ eventLog: eventLog
498
+ });
499
+
500
+ function cognito(userId, groups) {
501
+ return {
502
+ userId: userId,
503
+ username: userId,
504
+ groups: groups,
505
+ provider: "Cognito"
506
+ };
507
+ }
508
+
509
+ let owner = cognito("cust-A", ["User"]);
510
+
511
+ let stranger = cognito("cust-B", ["User"]);
512
+
513
+ let operator = cognito("ops-1", ["Admin"]);
514
+
515
+ let iam = {
516
+ userArn: "arn:aws:sts::1:assumed-role/Ingester",
517
+ accountId: "1",
518
+ username: "Ingester",
519
+ provider: "IAM"
520
+ };
521
+
522
+ function cross(hop, cmd) {
523
+ if (hop === "Inline") {
524
+ return CommandTopic_Helpers$ReventlessCore.encodeCommandJson(cmd);
525
+ } else {
526
+ return JSON.parse(Message$ReventlessCore.toMessageBody(cmd));
527
+ }
528
+ }
529
+
530
+ let observed = {
531
+ contents: []
532
+ };
533
+
534
+ function outcomeOf(reference) {
535
+ let match = observed.contents.findLast(r => r.reference === reference);
536
+ if (match === undefined) {
537
+ return "Lost";
538
+ }
539
+ let match$1 = match.outcome;
540
+ if (match$1.TAG === "OutcomeAccepted") {
541
+ return "Accepted";
542
+ } else {
543
+ return {
544
+ TAG: "Refused",
545
+ _0: match$1.errorCode,
546
+ _1: match$1.cause
547
+ };
548
+ }
549
+ }
550
+
551
+ let generated = {
552
+ contents: []
553
+ };
554
+
555
+ function generator(serviceName, commandSchema, componentKind) {
556
+ return CommandGenerator_Callback$ReventlessCore.makeGenerateCommand(async cmds => {
557
+ generated.contents = generated.contents.concat(cmds);
558
+ }, undefined, serviceName, commandSchema, componentKind, componentKind === "Aggregate", undefined);
559
+ }
560
+
561
+ async function generateOne(generate, command, args, identity) {
562
+ generated.contents = [];
563
+ let p = {
564
+ command: command,
565
+ arguments: Object.fromEntries(args),
566
+ meta: {
567
+ ip: [],
568
+ user: "test",
569
+ info: ""
570
+ },
571
+ identity: identity
572
+ };
573
+ await Effect.runPromise(generate(p));
574
+ return generated.contents[0];
575
+ }
576
+
577
+ function withoutClaim(cmd) {
578
+ let newrecord = {...cmd};
579
+ let newrecord$1 = {...cmd.meta};
580
+ newrecord$1.callerClaim = undefined;
581
+ newrecord.meta = newrecord$1;
582
+ return newrecord;
583
+ }
584
+
585
+ function str(prim) {
586
+ return prim;
587
+ }
588
+
589
+ let dcbGenerate = generator(name, commandSchema, "StateChangeSlice");
590
+
591
+ async function deliverDcb(crossPartitionTagKeysOpt, partitionTagOpt, hop, cmd) {
592
+ let crossPartitionTagKeys = crossPartitionTagKeysOpt !== undefined ? crossPartitionTagKeysOpt : [];
593
+ let partitionTag = partitionTagOpt !== undefined ? partitionTagOpt : orderPartition;
594
+ let command$p = Message$ReventlessCore.decodeCommand$p(cross(hop, cmd), Id$Reventless.$$String.schema, commandSchema);
595
+ await Effect.runPromise(OrderHandler.handleCommands(undefined, crossPartitionTagKeys, partitionTag, dcbEventLog, Stream.fromIterable([{
596
+ command: command$p,
597
+ reference: cmd.meta.msgId
598
+ }])));
599
+ return command$p.meta.msgId;
600
+ }
601
+
602
+ function makeDcbPath(hop) {
603
+ let label = `DCB slice, ` + (
604
+ hop === "Inline" ? "inline" : "queued"
605
+ ) + ` envelope`;
606
+ let reset = () => {
607
+ dcbMock.reset();
608
+ OrderHandler.resetCache();
609
+ };
610
+ let deliver = cmd => deliverDcb(undefined, undefined, hop, cmd);
611
+ let seed = async () => {
612
+ await deliver(await generateOne(dcbGenerate, "PlaceOrder", [
613
+ [
614
+ "orderId",
615
+ "o-1"
616
+ ],
617
+ [
618
+ "customerId",
619
+ "cust-A"
620
+ ]
621
+ ], owner));
622
+ };
623
+ let act = identity => generateOne(dcbGenerate, "CancelOrder", [[
624
+ "orderId",
625
+ "o-1"
626
+ ]], identity);
627
+ let historyLength = () => dcbMock.getEvents().length;
628
+ return {
629
+ label: label,
630
+ reset: reset,
631
+ seed: seed,
632
+ act: act,
633
+ deliver: deliver,
634
+ historyLength: historyLength
635
+ };
636
+ }
637
+
638
+ let aggregateGenerate = generator(name$1, commandSchema$1, "Aggregate");
639
+
640
+ async function deliverAggregate(hop, cmds) {
641
+ let items = cmds.map(cmd => ({
642
+ command: Message$ReventlessCore.decodeCommand$p(cross(hop, cmd), Id$Reventless.StringPure.schema, commandSchema$1),
643
+ reference: cmd.meta.msgId
644
+ }));
645
+ await Effect.runPromise(AccountHandler.handleCommands(Stream.fromIterable(items)));
646
+ }
647
+
648
+ function makeAggregatePath(hop) {
649
+ let label = `aggregate, ` + (
650
+ hop === "Inline" ? "inline" : "queued"
651
+ ) + ` envelope`;
652
+ let reset = () => {
653
+ accountEvents.contents = [];
654
+ snapshotReads.contents = 0;
655
+ AccountHandler.resetCache();
656
+ };
657
+ let deliver = async cmd => {
658
+ await deliverAggregate(hop, [cmd]);
659
+ return cmd.meta.msgId;
660
+ };
661
+ let seed = async () => {
662
+ await deliver(await generateOne(aggregateGenerate, "Open", [
663
+ [
664
+ "id",
665
+ "acc-1"
666
+ ],
667
+ [
668
+ "holderId",
669
+ "cust-A"
670
+ ],
671
+ [
672
+ "name",
673
+ "Main"
674
+ ]
675
+ ], owner));
676
+ };
677
+ let act = identity => generateOne(aggregateGenerate, "Rename", [
678
+ [
679
+ "id",
680
+ "acc-1"
681
+ ],
682
+ [
683
+ "newName",
684
+ "Renamed"
685
+ ]
686
+ ], identity);
687
+ let historyLength = () => accountEvents.contents.length;
688
+ return {
689
+ label: label,
690
+ reset: reset,
691
+ seed: seed,
692
+ act: act,
693
+ deliver: deliver,
694
+ historyLength: historyLength
695
+ };
696
+ }
697
+
698
+ let paths = [
699
+ makeDcbPath("Inline"),
700
+ makeDcbPath("Queued"),
701
+ makeAggregatePath("Inline"),
702
+ makeAggregatePath("Queued")
703
+ ];
704
+
705
+ globalThis.beforeEach(() => {
706
+ OwnerScope$Reventless.setElevatedGroups(["Admin"]);
707
+ observed.contents = [];
708
+ CommandTopic_Helpers$ReventlessCore.registerCommandOutcome(r => {
709
+ observed.contents = observed.contents.concat([r]);
710
+ });
711
+ });
712
+
713
+ globalThis.afterEach(() => CommandTopic_Helpers$ReventlessCore.clearCommandOutcome());
714
+
715
+ let forbidden = {
716
+ TAG: "Refused",
717
+ _0: "Forbidden",
718
+ _1: "AccessRefusal"
719
+ };
720
+
721
+ let table = [
722
+ [
723
+ "the owner",
724
+ owner,
725
+ false,
726
+ "Accepted"
727
+ ],
728
+ [
729
+ "another owner",
730
+ stranger,
731
+ false,
732
+ forbidden
733
+ ],
734
+ [
735
+ "an operator, on the owner's behalf",
736
+ operator,
737
+ false,
738
+ "Accepted"
739
+ ],
740
+ [
741
+ "the platform's own IAM traffic",
742
+ iam,
743
+ false,
744
+ "Accepted"
745
+ ],
746
+ [
747
+ "an anonymous caller",
748
+ Identity$Reventless.anonymous,
749
+ false,
750
+ forbidden
751
+ ],
752
+ [
753
+ "an internal route, with no claim",
754
+ stranger,
755
+ true,
756
+ "Accepted"
757
+ ]
758
+ ];
759
+
760
+ paths.forEach(path => {
761
+ globalThis.describe(`acting on an owned thing — ` + path.label + `:`, () => {
762
+ globalThis.beforeEach(() => path.reset());
763
+ table.forEach(param => {
764
+ let expected = param[3];
765
+ let internal = param[2];
766
+ let identity = param[1];
767
+ globalThis.test(param[0] + `: ` + (
768
+ expected === "Accepted" ? "accepted" : "refused before decide"
769
+ ), async () => {
770
+ await path.seed();
771
+ let before = path.historyLength();
772
+ let cmd = await path.act(identity);
773
+ let cmd$1 = internal ? withoutClaim(cmd) : cmd;
774
+ let received = await path.deliver(cmd$1);
775
+ globalThis.expect([
776
+ outcomeOf(received),
777
+ path.historyLength() > before
778
+ ]).toEqual([
779
+ expected,
780
+ expected === "Accepted"
781
+ ]);
782
+ });
783
+ });
784
+ globalThis.test("the owner's own creating command is accepted on an empty history", async () => {
785
+ await path.seed();
786
+ globalThis.expect(path.historyLength()).toBe(1);
787
+ });
788
+ });
789
+ });
790
+
791
+ globalThis.describe("acting on an owned thing — DCB specifics:", () => {
792
+ globalThis.beforeEach(() => {
793
+ dcbMock.reset();
794
+ OrderHandler.resetCache();
795
+ });
796
+ let seedOrder = async () => {
797
+ await deliverDcb(undefined, undefined, "Inline", await generateOne(dcbGenerate, "PlaceOrder", [
798
+ [
799
+ "orderId",
800
+ "o-1"
801
+ ],
802
+ [
803
+ "customerId",
804
+ "cust-A"
805
+ ]
806
+ ], owner));
807
+ };
808
+ let rawEvent = (eventType, fields, tags) => ({
809
+ eventType: eventType,
810
+ data: Object.fromEntries(fields),
811
+ tags: tags.map(param => ({
812
+ key: param[0],
813
+ value: param[1]
814
+ })),
815
+ meta: DcbFixtures$ReventlessCore.testMeta
816
+ });
817
+ globalThis.test("an owner recorded in another partition does not count", async () => {
818
+ await seedOrder();
819
+ await dcbMock.operations.append([rawEvent("ProductListed", [
820
+ [
821
+ "productId",
822
+ "p-1"
823
+ ],
824
+ [
825
+ "sellerId",
826
+ "seller-Z"
827
+ ]
828
+ ], [[
829
+ "productId",
830
+ "p-1"
831
+ ]])], undefined);
832
+ let review = await generateOne(dcbGenerate, "ReviewOrder", [
833
+ [
834
+ "orderId",
835
+ "o-1"
836
+ ],
837
+ [
838
+ "productId",
839
+ "p-1"
840
+ ]
841
+ ], owner);
842
+ await deliverDcb(["productId"], undefined, "Inline", review);
843
+ globalThis.expect(outcomeOf(review.meta.msgId)).toEqual("Accepted");
844
+ });
845
+ globalThis.test("a warm, delta-read command is still checked against the owner", async () => {
846
+ await seedOrder();
847
+ let mine = await generateOne(dcbGenerate, "CancelOrder", [[
848
+ "orderId",
849
+ "o-1"
850
+ ]], owner);
851
+ await deliverDcb(undefined, undefined, "Inline", mine);
852
+ dcbMock.readAfters.contents = [];
853
+ let theirs = await generateOne(dcbGenerate, "CancelOrder", [[
854
+ "orderId",
855
+ "o-1"
856
+ ]], stranger);
857
+ await deliverDcb(undefined, undefined, "Inline", theirs);
858
+ globalThis.expect([
859
+ dcbMock.readAfters.contents.some(Stdlib_Option.isSome),
860
+ outcomeOf(theirs.meta.msgId)
861
+ ]).toEqual([
862
+ true,
863
+ forbidden
864
+ ]);
865
+ });
866
+ globalThis.test("two owners in one partition refuse even an operator", async () => {
867
+ await seedOrder();
868
+ await dcbMock.operations.append([rawEvent("OrderPlaced", [
869
+ [
870
+ "orderId",
871
+ "o-1"
872
+ ],
873
+ [
874
+ "customerId",
875
+ "cust-B"
876
+ ]
877
+ ], [[
878
+ "orderId",
879
+ "o-1"
880
+ ]])], undefined);
881
+ let cmd = await generateOne(dcbGenerate, "CancelOrder", [[
882
+ "orderId",
883
+ "o-1"
884
+ ]], operator);
885
+ await deliverDcb(undefined, undefined, "Inline", cmd);
886
+ globalThis.expect(outcomeOf(cmd.meta.msgId)).toEqual(forbidden);
887
+ });
888
+ globalThis.test("an unnameable partition refuses an owner and admits an operator", async () => {
889
+ await seedOrder();
890
+ let unnamed = {
891
+ TAG: "ByEventType",
892
+ _0: {}
893
+ };
894
+ let mine = await generateOne(dcbGenerate, "CancelOrder", [[
895
+ "orderId",
896
+ "o-1"
897
+ ]], owner);
898
+ await deliverDcb(undefined, unnamed, "Inline", mine);
899
+ let ops = await generateOne(dcbGenerate, "CancelOrder", [[
900
+ "orderId",
901
+ "o-1"
902
+ ]], operator);
903
+ await deliverDcb(undefined, unnamed, "Inline", ops);
904
+ globalThis.expect([
905
+ outcomeOf(mine.meta.msgId),
906
+ outcomeOf(ops.meta.msgId)
907
+ ]).toEqual([
908
+ forbidden,
909
+ "Accepted"
910
+ ]);
911
+ });
912
+ });
913
+
914
+ globalThis.describe("acting on an owned thing — aggregate specifics:", () => {
915
+ globalThis.beforeEach(() => {
916
+ accountEvents.contents = [];
917
+ snapshotReads.contents = 0;
918
+ AccountHandler.resetCache();
919
+ });
920
+ globalThis.test("a command later in the same batch is checked against an owner just recorded", async () => {
921
+ let opened = await generateOne(aggregateGenerate, "Open", [
922
+ [
923
+ "id",
924
+ "acc-1"
925
+ ],
926
+ [
927
+ "holderId",
928
+ "cust-A"
929
+ ],
930
+ [
931
+ "name",
932
+ "Main"
933
+ ]
934
+ ], owner);
935
+ let renamed = await generateOne(aggregateGenerate, "Rename", [
936
+ [
937
+ "id",
938
+ "acc-1"
939
+ ],
940
+ [
941
+ "newName",
942
+ "Mine now"
943
+ ]
944
+ ], stranger);
945
+ await deliverAggregate("Inline", [
946
+ opened,
947
+ renamed
948
+ ]);
949
+ globalThis.expect([
950
+ outcomeOf(opened.meta.msgId),
951
+ outcomeOf(renamed.meta.msgId)
952
+ ]).toEqual([
953
+ "Accepted",
954
+ forbidden
955
+ ]);
956
+ });
957
+ globalThis.test("an owner-marked aggregate never seeds from a snapshot", async () => {
958
+ let opened = await generateOne(aggregateGenerate, "Open", [
959
+ [
960
+ "id",
961
+ "acc-1"
962
+ ],
963
+ [
964
+ "holderId",
965
+ "cust-A"
966
+ ],
967
+ [
968
+ "name",
969
+ "Main"
970
+ ]
971
+ ], owner);
972
+ await deliverAggregate("Inline", [opened]);
973
+ globalThis.expect(snapshotReads.contents).toBe(0);
974
+ });
975
+ });
976
+
977
+ let OuterEventLog;
978
+
979
+ export {
980
+ OrderSlice,
981
+ OrderBehavior,
982
+ OrderHandler,
983
+ dcbMock,
984
+ DcbOps,
985
+ DcbLog,
986
+ dcbEventLog,
987
+ orderPartition,
988
+ AccountSpec,
989
+ AccountBehavior,
990
+ accountEvents,
991
+ snapshotReads,
992
+ OuterEventLog,
993
+ AccountOps,
994
+ AccountHandler,
995
+ cognito,
996
+ owner,
997
+ stranger,
998
+ operator,
999
+ iam,
1000
+ cross,
1001
+ observed,
1002
+ outcomeOf,
1003
+ generated,
1004
+ generator,
1005
+ generateOne,
1006
+ withoutClaim,
1007
+ str,
1008
+ dcbGenerate,
1009
+ deliverDcb,
1010
+ makeDcbPath,
1011
+ aggregateGenerate,
1012
+ deliverAggregate,
1013
+ makeAggregatePath,
1014
+ paths,
1015
+ forbidden,
1016
+ table,
1017
+ }
1018
+ /* moduleUrl Not a pure module */