@reventlessdev/reventless-core 3.0.0-alpha.179 → 3.0.0-alpha.181

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 (118) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +8 -8
  3. package/src/Message.res +2 -1
  4. package/src/Message.res.mjs +5 -1
  5. package/src/adapter/Monitoring/Monitoring.res +14 -2
  6. package/src/adapter/Monitoring/Monitoring.res.mjs +4 -2
  7. package/src/admin/Platform_Admin_Structure.res +2 -0
  8. package/src/admin/Platform_Admin_Structure.res.mjs +2 -0
  9. package/src/admin/Platform_ComponentDefinitionsApi.res +2 -1
  10. package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
  11. package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res +1 -1
  12. package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res.mjs +2 -1
  13. package/src/components/Api/ApiTargetStateHelpers.res +20 -0
  14. package/src/components/Api/ApiTargetStateHelpers.res.mjs +16 -0
  15. package/src/components/Api/GraphQL_FragmentGenerator.res +1 -0
  16. package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +1 -0
  17. package/src/components/Api/SchemaType.res +3 -0
  18. package/src/components/Api/SchemaType.res.mjs +10 -2
  19. package/src/components/Api/SuryToJsonSchema.res +16 -0
  20. package/src/components/Api/SuryToJsonSchema.res.mjs +28 -0
  21. package/src/components/Dcb/Dcb_Builder.res +4 -5
  22. package/src/components/Dcb/Dcb_Builder.res.mjs +3 -5
  23. package/src/components/DcbEventLog/DcbEventLog_Operations.res +6 -1
  24. package/src/components/DcbEventLog/DcbEventLog_Operations.res.mjs +2 -1
  25. package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +25 -0
  26. package/src/components/InboundTranslationSlice/InboundTranslationSlice.res.mjs +31 -0
  27. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +8 -8
  28. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +26 -6
  29. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +44 -37
  30. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res.mjs +17 -25
  31. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +27 -2
  32. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -0
  33. package/src/components/StateViewSlice/StateViewSlice_Builder.res +20 -6
  34. package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +23 -5
  35. package/src/components/StateViewSlice/StateViewSlice_Callback.res +1 -1
  36. package/src/components/StateViewSlice/StateViewSlice_Callback.res.mjs +5 -1
  37. package/src/plugin/component/Plugin_Helpers.res +4 -1
  38. package/src/plugin/component/Plugin_Structure.res +15 -1
  39. package/src/plugin/component/Plugin_Structure.res.mjs +4 -1
  40. package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +2 -0
  41. package/tests/IdentityTest.res.mjs +174 -0
  42. package/tests/ResourceAttributionTest.res.mjs +75 -0
  43. package/tests/adapter/MonitoringTest.res +32 -2
  44. package/tests/adapter/MonitoringTest.res.mjs +116 -0
  45. package/tests/admin/Platform_ComponentDefinitionsApiTest.res +10 -0
  46. package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +365 -0
  47. package/tests/admin/Platform_UIFragmentsApiTest.res.mjs +101 -0
  48. package/tests/aggregate/AggregateCacheTest.res.mjs +433 -0
  49. package/tests/aggregate/AggregateCallbackTest.res.mjs +143 -0
  50. package/tests/aggregate/AggregateCausationTest.res.mjs +47 -0
  51. package/tests/aggregate/AggregateConflictTest.res.mjs +386 -0
  52. package/tests/aggregate/AggregateFixtures.res.mjs +308 -0
  53. package/tests/aggregate/AggregateRejectionTest.res.mjs +166 -0
  54. package/tests/aggregate/AggregateSnapshotTest.res.mjs +645 -0
  55. package/tests/api/ApiNoApiTest.res.mjs +90 -0
  56. package/tests/api/GraphQL_StitcherTest.res.mjs +112 -0
  57. package/tests/api/SimpleTest.res.mjs +10 -0
  58. package/tests/api/SuryToJsonSchemaTest.res +68 -0
  59. package/tests/api/SuryToJsonSchemaTest.res.mjs +843 -0
  60. package/tests/commandgenerator/CommandGeneratorCallbackTest.res.mjs +160 -0
  61. package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +197 -0
  62. package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +152 -0
  63. package/tests/commandtopic/CommandTopicCallbackTest.res.mjs +106 -0
  64. package/tests/commandtopic/CommandTopicHelpersRejectionTest.res.mjs +109 -0
  65. package/tests/counter/CounterCallbackTest.res.mjs +140 -0
  66. package/tests/counter/CounterFixtures.res.mjs +67 -0
  67. package/tests/dcb/DcbDecodeTest.res.mjs +194 -0
  68. package/tests/dcb/DcbEventLogOperationsTest.res.mjs +268 -0
  69. package/tests/dcb/DcbFixtures.res.mjs +534 -0
  70. package/tests/dcb/DcbScopeInferenceTest.res.mjs +480 -0
  71. package/tests/dcb/DcbStateChangeSliceTest.res.mjs +540 -0
  72. package/tests/dcb/DcbTagTest.res.mjs +867 -0
  73. package/tests/dcb/DcbValidationTest.res.mjs +476 -0
  74. package/tests/eventlog/EventLogFixtures.res.mjs +196 -0
  75. package/tests/eventlog/EventLogOperationsTest.res.mjs +192 -0
  76. package/tests/eventlog/EventLogRetryTest.res.mjs +195 -0
  77. package/tests/eventmapper/EventMapperCallbackTest.res.mjs +141 -0
  78. package/tests/eventmapper/EventMapperFixtures.res.mjs +440 -0
  79. package/tests/eventmapper/EventMapperTest.res.mjs +83 -0
  80. package/tests/eventtopic/EventTopicFixtures.res.mjs +65 -0
  81. package/tests/eventtopic/EventTopicOperationsTest.res.mjs +71 -0
  82. package/tests/extensionpoint/ExtensionPointCallbackTest.res.mjs +94 -0
  83. package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +205 -0
  84. package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +304 -0
  85. package/tests/extensionpoint/PluginDisconnectScheduleTest.res.mjs +92 -0
  86. package/tests/ftp/FTPTest.res.mjs +88 -0
  87. package/tests/logger/LogFormatTest.res.mjs +329 -0
  88. package/tests/logger/LoggerLazyTest.res.mjs +40 -0
  89. package/tests/message/MessageTest.res.mjs +218 -0
  90. package/tests/message/MetaEnvelopeTest.res.mjs +188 -0
  91. package/tests/plugin/HeartbeatDisconnectGraceTest.res.mjs +91 -0
  92. package/tests/plugin/ManifestVisibilityTest.res.mjs +215 -0
  93. package/tests/plugin/PluginSpecExperiment.res.mjs +31 -0
  94. package/tests/plugin/PluginStructureTest.res +55 -0
  95. package/tests/plugin/PluginStructureTest.res.mjs +467 -0
  96. package/tests/plugin/PluginVersionTest.res.mjs +30 -0
  97. package/tests/plugin/SchemaWalkerTest.res.mjs +160 -0
  98. package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +62 -0
  99. package/tests/plugin/StateChangeSlice/PsShipOrder.res +4 -1
  100. package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +77 -0
  101. package/tests/plugin/StateViewSlice/PsAnnotatedView.res +5 -4
  102. package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +110 -0
  103. package/tests/plugin/StateViewSlice/PsAvailableProductsView.res +1 -1
  104. package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +70 -0
  105. package/tests/plugin/StateViewSlice/PsCustomersView.res +1 -1
  106. package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +70 -0
  107. package/tests/plugin/StateViewSlice/PsOrdersView.res +1 -1
  108. package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +82 -0
  109. package/tests/poc/StructuralSubtypingPoc.res.mjs +61 -0
  110. package/tests/projection/ProjectionOptimizeTest.res.mjs +75 -0
  111. package/tests/querydb/QueryDbFixtures.res.mjs +135 -0
  112. package/tests/querydb/QueryDbOperationsTest.res.mjs +168 -0
  113. package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res.mjs +77 -0
  114. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +139 -0
  115. package/tests/util/CommandPublisherTest.res.mjs +78 -0
  116. package/tests/util/CsvStreamTest.res.mjs +51 -0
  117. package/tests/util/LruTest.res.mjs +105 -0
  118. package/tests/util/MetricsTest.res.mjs +53 -0
@@ -0,0 +1,480 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
+ import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
5
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
6
+ import * as DcbValidation$Reventless from "@reventlessdev/reventless-spec/src/components/DcbValidation.res.mjs";
7
+ import * as DcbFixtures$ReventlessCore from "./DcbFixtures.res.mjs";
8
+ import * as DcbScopeInference$Reventless from "@reventlessdev/reventless-spec/src/components/DcbScopeInference.res.mjs";
9
+
10
+ function scal(name) {
11
+ return {
12
+ name: name,
13
+ isList: false
14
+ };
15
+ }
16
+
17
+ function arr(name) {
18
+ return {
19
+ name: name,
20
+ isList: true
21
+ };
22
+ }
23
+
24
+ function ev(eventType, idFields) {
25
+ return {
26
+ eventType: eventType,
27
+ idFields: idFields
28
+ };
29
+ }
30
+
31
+ function slice(sliceName, commandOpt, consumedOpt, producedOpt, partitionHint) {
32
+ let command = commandOpt !== undefined ? commandOpt : [];
33
+ let consumed = consumedOpt !== undefined ? consumedOpt : [];
34
+ let produced = producedOpt !== undefined ? producedOpt : [];
35
+ return {
36
+ sliceName: sliceName,
37
+ command: command,
38
+ consumed: consumed,
39
+ produced: produced,
40
+ partitionHint: partitionHint
41
+ };
42
+ }
43
+
44
+ let addProduct = slice("AddProduct", [
45
+ {
46
+ name: "productId",
47
+ isList: false
48
+ },
49
+ {
50
+ name: "categoryId",
51
+ isList: false
52
+ }
53
+ ], [
54
+ {
55
+ eventType: "ProductAdded",
56
+ idFields: [{
57
+ name: "productId",
58
+ isList: false
59
+ }]
60
+ },
61
+ {
62
+ eventType: "CategoryAdded",
63
+ idFields: [{
64
+ name: "categoryId",
65
+ isList: false
66
+ }]
67
+ },
68
+ {
69
+ eventType: "CategoryArchived",
70
+ idFields: [{
71
+ name: "categoryId",
72
+ isList: false
73
+ }]
74
+ }
75
+ ], [{
76
+ eventType: "ProductAdded",
77
+ idFields: [
78
+ {
79
+ name: "productId",
80
+ isList: false
81
+ },
82
+ {
83
+ name: "categoryId",
84
+ isList: false
85
+ }
86
+ ]
87
+ }], undefined);
88
+
89
+ let addCategory = slice("AddCategory", [{
90
+ name: "categoryId",
91
+ isList: false
92
+ }], [
93
+ {
94
+ eventType: "CategoryAdded",
95
+ idFields: []
96
+ },
97
+ {
98
+ eventType: "CategoryArchived",
99
+ idFields: []
100
+ }
101
+ ], [{
102
+ eventType: "CategoryAdded",
103
+ idFields: [{
104
+ name: "categoryId",
105
+ isList: false
106
+ }]
107
+ }], undefined);
108
+
109
+ let renameCategory = slice("RenameCategory", [{
110
+ name: "categoryId",
111
+ isList: false
112
+ }], [
113
+ {
114
+ eventType: "CategoryAdded",
115
+ idFields: []
116
+ },
117
+ {
118
+ eventType: "CategoryRenamed",
119
+ idFields: []
120
+ },
121
+ {
122
+ eventType: "CategoryArchived",
123
+ idFields: []
124
+ }
125
+ ], [{
126
+ eventType: "CategoryRenamed",
127
+ idFields: [{
128
+ name: "categoryId",
129
+ isList: false
130
+ }]
131
+ }], undefined);
132
+
133
+ let archiveCategory = slice("ArchiveCategory", [{
134
+ name: "categoryId",
135
+ isList: false
136
+ }], [
137
+ {
138
+ eventType: "CategoryAdded",
139
+ idFields: []
140
+ },
141
+ {
142
+ eventType: "CategoryArchived",
143
+ idFields: []
144
+ }
145
+ ], [{
146
+ eventType: "CategoryArchived",
147
+ idFields: [{
148
+ name: "categoryId",
149
+ isList: false
150
+ }]
151
+ }], undefined);
152
+
153
+ let catalog = [
154
+ addProduct,
155
+ addCategory,
156
+ renameCategory,
157
+ archiveCategory
158
+ ];
159
+
160
+ globalThis.describe("DcbScopeInference:", () => {
161
+ globalThis.describe("tagKeyOf", () => {
162
+ globalThis.test("scalar *Id uses the field name", () => {
163
+ globalThis.expect(DcbScopeInference$Reventless.tagKeyOf({
164
+ name: "categoryId",
165
+ isList: false
166
+ })).toBe("categoryId");
167
+ });
168
+ globalThis.test("plural *Ids strips the trailing s", () => {
169
+ globalThis.expect(DcbScopeInference$Reventless.tagKeyOf({
170
+ name: "productIds",
171
+ isList: true
172
+ })).toBe("productId");
173
+ });
174
+ });
175
+ globalThis.describe("hybrid catalog (no annotations)", () => {
176
+ let d = DcbScopeInference$Reventless.infer(catalog);
177
+ globalThis.test("derives categoryId as the only cross-partition key — without any @crossPartition", () => {
178
+ globalThis.expect(d.crossPartitionTagKeys).toEqual(["categoryId"]);
179
+ });
180
+ globalThis.test("AddProduct partition = productId (foreign categoryId eliminated)", () => {
181
+ globalThis.expect(d.partitionBySlice["AddProduct"]).toEqual("productId");
182
+ });
183
+ globalThis.test("Category slices partition = categoryId", () => {
184
+ globalThis.expect(d.partitionBySlice["AddCategory"]).toEqual("categoryId");
185
+ globalThis.expect(d.partitionBySlice["RenameCategory"]).toEqual("categoryId");
186
+ globalThis.expect(d.partitionBySlice["ArchiveCategory"]).toEqual("categoryId");
187
+ });
188
+ globalThis.test("ProductAdded indexes productId only — categoryId is payload (no sibling leak)", () => {
189
+ globalThis.expect(d.tagKeysByEventType["ProductAdded"]).toEqual(["productId"]);
190
+ });
191
+ globalThis.test("CategoryAdded indexes its own categoryId", () => {
192
+ globalThis.expect(d.tagKeysByEventType["CategoryAdded"]).toEqual(["categoryId"]);
193
+ });
194
+ globalThis.test("no ambiguities for a well-formed boundary", () => {
195
+ globalThis.expect(d.ambiguities).toEqual([]);
196
+ });
197
+ globalThis.test("ownerByKey points categoryId at a Category slice, productId at Product", () => {
198
+ globalThis.expect(d.ownerByKey["productId"]).toEqual("AddProduct");
199
+ globalThis.expect(Stdlib_Option.isSome(d.ownerByKey["categoryId"])).toBe(true);
200
+ });
201
+ });
202
+ globalThis.describe("own composite read + @partitionTag hint (RecordProductDemand shape)", () => {
203
+ let recordDemand = slice("RecordProductDemand", undefined, [
204
+ {
205
+ eventType: "ProductDemandRecorded",
206
+ idFields: [{
207
+ name: "orderId",
208
+ isList: false
209
+ }]
210
+ },
211
+ {
212
+ eventType: "ProductDemandRevoked",
213
+ idFields: [{
214
+ name: "orderId",
215
+ isList: false
216
+ }]
217
+ }
218
+ ], [
219
+ {
220
+ eventType: "ProductDemandRecorded",
221
+ idFields: [
222
+ {
223
+ name: "productId",
224
+ isList: false
225
+ },
226
+ {
227
+ name: "orderId",
228
+ isList: false
229
+ }
230
+ ]
231
+ },
232
+ {
233
+ eventType: "ProductDemandRevoked",
234
+ idFields: [
235
+ {
236
+ name: "productId",
237
+ isList: false
238
+ },
239
+ {
240
+ name: "orderId",
241
+ isList: false
242
+ }
243
+ ]
244
+ }
245
+ ], "productId");
246
+ let d = DcbScopeInference$Reventless.infer([recordDemand]);
247
+ globalThis.test("the @partitionTag hint resolves the partition (no ambiguity)", () => {
248
+ globalThis.expect(d.partitionBySlice["RecordProductDemand"]).toEqual("productId");
249
+ globalThis.expect(d.ambiguities).toEqual([]);
250
+ });
251
+ globalThis.test("orderId stays indexed — it is an own-stream read key, not a foreign ref", () => {
252
+ globalThis.expect(d.tagKeysByEventType["ProductDemandRecorded"]).toEqual([
253
+ "orderId",
254
+ "productId"
255
+ ]);
256
+ });
257
+ globalThis.test("orderId is not cross-partition (no Order entity owns it in this boundary)", () => {
258
+ globalThis.expect(d.crossPartitionTagKeys).toEqual([]);
259
+ });
260
+ });
261
+ globalThis.describe("array foreign reference (productIds) stays partition-scoped", () => {
262
+ let placeOrder = slice("PlaceOrder", [
263
+ {
264
+ name: "orderId",
265
+ isList: false
266
+ },
267
+ {
268
+ name: "productIds",
269
+ isList: true
270
+ }
271
+ ], [
272
+ {
273
+ eventType: "OrderPlaced",
274
+ idFields: [{
275
+ name: "orderId",
276
+ isList: false
277
+ }]
278
+ },
279
+ {
280
+ eventType: "CatalogProductSynced",
281
+ idFields: [{
282
+ name: "productId",
283
+ isList: false
284
+ }]
285
+ }
286
+ ], [{
287
+ eventType: "OrderPlaced",
288
+ idFields: [
289
+ {
290
+ name: "orderId",
291
+ isList: false
292
+ },
293
+ {
294
+ name: "productIds",
295
+ isList: true
296
+ }
297
+ ]
298
+ }], undefined);
299
+ let productEntity = slice("SyncCatalogProduct", [{
300
+ name: "productId",
301
+ isList: false
302
+ }], [{
303
+ eventType: "CatalogProductSynced",
304
+ idFields: []
305
+ }], [{
306
+ eventType: "CatalogProductSynced",
307
+ idFields: [{
308
+ name: "productId",
309
+ isList: false
310
+ }]
311
+ }], undefined);
312
+ let d = DcbScopeInference$Reventless.infer([
313
+ placeOrder,
314
+ productEntity
315
+ ]);
316
+ globalThis.test("an array-only foreign read is NOT cross-partition (auto-fans, partition-scoped)", () => {
317
+ globalThis.expect(d.crossPartitionTagKeys).toEqual([]);
318
+ });
319
+ globalThis.test("PlaceOrder partition = orderId", () => {
320
+ globalThis.expect(d.partitionBySlice["PlaceOrder"]).toEqual("orderId");
321
+ });
322
+ globalThis.test("OrderPlaced indexes orderId only (productIds is a foreign payload ref)", () => {
323
+ globalThis.expect(d.tagKeysByEventType["OrderPlaced"]).toEqual(["orderId"]);
324
+ });
325
+ });
326
+ globalThis.describe("schema adapter ⇄ inference parity", () => {
327
+ let shapes = DcbTag$Reventless.eventShapesOfSchema(DcbFixtures$ReventlessCore.subscriptionEventSchema);
328
+ globalThis.test("eventShapesOfSchema extracts *Id fields by name (tag flags ignored)", () => {
329
+ globalThis.expect(shapes.length).toBe(1);
330
+ let arm = shapes[0];
331
+ globalThis.expect(arm.eventType).toBe("StudentSubscribed");
332
+ let names = arm.idFields.map(f => f.name).toSorted(Primitive_string.compare);
333
+ globalThis.expect(names).toEqual([
334
+ "courseId",
335
+ "studentId"
336
+ ]);
337
+ });
338
+ globalThis.test("inference reproduces extractCrossPartitionTagKeys ⇒ [\"studentId\"]", () => {
339
+ let studentEntity = slice("RegisterStudent", undefined, undefined, [{
340
+ eventType: "StudentRegistered",
341
+ idFields: [{
342
+ name: "studentId",
343
+ isList: false
344
+ }]
345
+ }], undefined);
346
+ let subscribe_command = [
347
+ {
348
+ name: "courseId",
349
+ isList: false
350
+ },
351
+ {
352
+ name: "studentId",
353
+ isList: false
354
+ }
355
+ ];
356
+ let subscribe_consumed = [{
357
+ eventType: "StudentRegistered",
358
+ idFields: [{
359
+ name: "studentId",
360
+ isList: false
361
+ }]
362
+ }];
363
+ let subscribe = {
364
+ sliceName: "SubscribeStudent",
365
+ command: subscribe_command,
366
+ consumed: subscribe_consumed,
367
+ produced: shapes,
368
+ partitionHint: undefined
369
+ };
370
+ let d = DcbScopeInference$Reventless.infer([
371
+ studentEntity,
372
+ subscribe
373
+ ]);
374
+ globalThis.expect(d.crossPartitionTagKeys).toEqual(DcbTag$Reventless.extractCrossPartitionTagKeys(DcbFixtures$ReventlessCore.subscriptionEventSchema));
375
+ globalThis.expect(d.partitionBySlice["SubscribeStudent"]).toEqual("courseId");
376
+ });
377
+ });
378
+ globalThis.describe("validateScopeVsInference (annotation ⇄ inference)", () => {
379
+ let d = DcbScopeInference$Reventless.infer(catalog);
380
+ globalThis.test("flags @crossPartition on a slice's OWN partition as a contradiction", () => {
381
+ let issues = DcbValidation$Reventless.validateScopeVsInference([[
382
+ "AddCategory",
383
+ ["categoryId"]
384
+ ]], d);
385
+ globalThis.expect(issues.contradictions.length).toBe(1);
386
+ globalThis.expect(issues.contradictions[0].sliceName).toBe("AddCategory");
387
+ globalThis.expect(issues.redundancies).toEqual([]);
388
+ });
389
+ globalThis.test("flags @crossPartition that inference already derives as redundant", () => {
390
+ let issues = DcbValidation$Reventless.validateScopeVsInference([[
391
+ "AddProduct",
392
+ ["categoryId"]
393
+ ]], d);
394
+ globalThis.expect(issues.contradictions).toEqual([]);
395
+ globalThis.expect(issues.redundancies.length).toBe(1);
396
+ });
397
+ globalThis.test("no annotations ⇒ no issues (the migrated catalog)", () => {
398
+ let issues = DcbValidation$Reventless.validateScopeVsInference(catalog.map(s => [
399
+ s.sliceName,
400
+ []
401
+ ]), d);
402
+ globalThis.expect(issues.contradictions).toEqual([]);
403
+ globalThis.expect(issues.redundancies).toEqual([]);
404
+ });
405
+ });
406
+ globalThis.describe("ambiguity surfacing", () => {
407
+ let aOwner = slice("A", undefined, undefined, [{
408
+ eventType: "AHappened",
409
+ idFields: [{
410
+ name: "aId",
411
+ isList: false
412
+ }]
413
+ }], undefined);
414
+ let bOwner = slice("B", undefined, undefined, [{
415
+ eventType: "BHappened",
416
+ idFields: [{
417
+ name: "bId",
418
+ isList: false
419
+ }]
420
+ }], undefined);
421
+ let join = slice("Join", undefined, [
422
+ {
423
+ eventType: "AHappened",
424
+ idFields: [{
425
+ name: "aId",
426
+ isList: false
427
+ }]
428
+ },
429
+ {
430
+ eventType: "BHappened",
431
+ idFields: [{
432
+ name: "bId",
433
+ isList: false
434
+ }]
435
+ }
436
+ ], [{
437
+ eventType: "Joined",
438
+ idFields: [
439
+ {
440
+ name: "aId",
441
+ isList: false
442
+ },
443
+ {
444
+ name: "bId",
445
+ isList: false
446
+ }
447
+ ]
448
+ }], undefined);
449
+ let d = DcbScopeInference$Reventless.infer([
450
+ aOwner,
451
+ bOwner,
452
+ join
453
+ ]);
454
+ globalThis.test("a pure-join slice with no own key is reported ambiguous", () => {
455
+ let names = d.ambiguities.map(param => param[0]);
456
+ globalThis.expect(names.includes("Join")).toBe(true);
457
+ });
458
+ globalThis.test("the well-formed owners are not ambiguous", () => {
459
+ let names = d.ambiguities.map(param => param[0]);
460
+ globalThis.expect(names.includes("A")).toBe(false);
461
+ globalThis.expect(names.includes("B")).toBe(false);
462
+ });
463
+ });
464
+ });
465
+
466
+ let DSI;
467
+
468
+ export {
469
+ DSI,
470
+ scal,
471
+ arr,
472
+ ev,
473
+ slice,
474
+ addProduct,
475
+ addCategory,
476
+ renameCategory,
477
+ archiveCategory,
478
+ catalog,
479
+ }
480
+ /* addProduct Not a pure module */