@reventlessdev/reventless-gwt 1.0.0-alpha.74

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 (172) hide show
  1. package/CHANGELOG.md +698 -0
  2. package/LICENSE +202 -0
  3. package/bin/reventless-dev.mjs +21 -0
  4. package/package.json +54 -0
  5. package/rescript.json +36 -0
  6. package/src/.gwtignore +10 -0
  7. package/src/Automation_GWT.res +207 -0
  8. package/src/Automation_GWT.res.mjs +160 -0
  9. package/src/Behavior_GWT.res +603 -0
  10. package/src/Behavior_GWT.res.mjs +426 -0
  11. package/src/Bind.res +29 -0
  12. package/src/Bind.res.mjs +22 -0
  13. package/src/BuildClassifier.res +137 -0
  14. package/src/BuildClassifier.res.mjs +136 -0
  15. package/src/Cancellation.res +31 -0
  16. package/src/Cancellation.res.mjs +45 -0
  17. package/src/ChildProcess.res +84 -0
  18. package/src/ChildProcess.res.mjs +92 -0
  19. package/src/Cli.res +671 -0
  20. package/src/Cli.res.mjs +754 -0
  21. package/src/Collector.res +201 -0
  22. package/src/Collector.res.mjs +215 -0
  23. package/src/ComponentMeta.res +104 -0
  24. package/src/ComponentMeta.res.mjs +120 -0
  25. package/src/ComponentScan.res +103 -0
  26. package/src/ComponentScan.res.mjs +105 -0
  27. package/src/Delegate_GWT.res +303 -0
  28. package/src/Delegate_GWT.res.mjs +372 -0
  29. package/src/Diff.res +91 -0
  30. package/src/Diff.res.mjs +98 -0
  31. package/src/Discovery.res +105 -0
  32. package/src/Discovery.res.mjs +103 -0
  33. package/src/DomainDeadCode.res +93 -0
  34. package/src/DomainDeadCode.res.mjs +69 -0
  35. package/src/DomainGraph.res +0 -0
  36. package/src/DomainGraph.res.mjs +0 -0
  37. package/src/EventMapping_GWT.res +29 -0
  38. package/src/EventMapping_GWT.res.mjs +44 -0
  39. package/src/Filter.res +36 -0
  40. package/src/Filter.res.mjs +40 -0
  41. package/src/Flow_GWT.res +664 -0
  42. package/src/Flow_GWT.res.mjs +604 -0
  43. package/src/FormatterHuman.res +138 -0
  44. package/src/FormatterHuman.res.mjs +122 -0
  45. package/src/FormatterJson.res +257 -0
  46. package/src/FormatterJson.res.mjs +320 -0
  47. package/src/FormatterJunit.res +93 -0
  48. package/src/FormatterJunit.res.mjs +90 -0
  49. package/src/FormatterTap.res +139 -0
  50. package/src/FormatterTap.res.mjs +149 -0
  51. package/src/FormatterVsCode.res +362 -0
  52. package/src/FormatterVsCode.res.mjs +564 -0
  53. package/src/Hint.res +119 -0
  54. package/src/Hint.res.mjs +124 -0
  55. package/src/InboundTranslation_GWT.res +83 -0
  56. package/src/InboundTranslation_GWT.res.mjs +94 -0
  57. package/src/JestBind.res +70 -0
  58. package/src/JestBind.res.mjs +63 -0
  59. package/src/Loader.res +24 -0
  60. package/src/Loader.res.mjs +23 -0
  61. package/src/LocalHost.res +135 -0
  62. package/src/LocalHost.res.mjs +127 -0
  63. package/src/Mapping_GWT.res +474 -0
  64. package/src/Mapping_GWT.res.mjs +322 -0
  65. package/src/MultiSourceProjection_GWT.res +316 -0
  66. package/src/MultiSourceProjection_GWT.res.mjs +354 -0
  67. package/src/OutboundTranslation_GWT.res +238 -0
  68. package/src/OutboundTranslation_GWT.res.mjs +186 -0
  69. package/src/Outcome.res +161 -0
  70. package/src/Outcome.res.mjs +140 -0
  71. package/src/PackageScan.res +80 -0
  72. package/src/PackageScan.res.mjs +81 -0
  73. package/src/PlatformRunner.res +160 -0
  74. package/src/PlatformRunner.res.mjs +155 -0
  75. package/src/PlatformScan.res +138 -0
  76. package/src/PlatformScan.res.mjs +131 -0
  77. package/src/ProcessManager.res +91 -0
  78. package/src/ProcessManager.res.mjs +80 -0
  79. package/src/Projection_GWT.res +312 -0
  80. package/src/Projection_GWT.res.mjs +332 -0
  81. package/src/Query_GWT.res +379 -0
  82. package/src/Query_GWT.res.mjs +367 -0
  83. package/src/RenderRescript.res +125 -0
  84. package/src/RenderRescript.res.mjs +141 -0
  85. package/src/RunnerTypes.res +68 -0
  86. package/src/RunnerTypes.res.mjs +60 -0
  87. package/src/SideEffect_GWT.res +157 -0
  88. package/src/SideEffect_GWT.res.mjs +113 -0
  89. package/src/StateChange/ExternalAddCategorySlice.res +25 -0
  90. package/src/StateChange/ExternalAddCategorySlice.res.mjs +34 -0
  91. package/src/StateChange/ExternalAddCategorySlice_Behavior.res +19 -0
  92. package/src/StateChange/ExternalAddCategorySlice_Behavior.res.mjs +46 -0
  93. package/src/StateChange/WithFixtures.res +22 -0
  94. package/src/StateChange/WithFixtures.res.mjs +31 -0
  95. package/src/StateChange/WithFixtures_Behavior.res +17 -0
  96. package/src/StateChange/WithFixtures_Behavior.res.mjs +37 -0
  97. package/src/StateChange/WithManualOpen.res +23 -0
  98. package/src/StateChange/WithManualOpen.res.mjs +31 -0
  99. package/src/StateChange/WithManualOpen_Behavior.res +17 -0
  100. package/src/StateChange/WithManualOpen_Behavior.res.mjs +37 -0
  101. package/src/StubRuntime.res +53 -0
  102. package/src/StubRuntime.res.mjs +54 -0
  103. package/src/TestFixtures.res +16 -0
  104. package/src/TestFixtures.res.mjs +34 -0
  105. package/src/Watch.res +92 -0
  106. package/src/Watch.res.mjs +83 -0
  107. package/src/WatcherProbe.res +48 -0
  108. package/src/WatcherProbe.res.mjs +46 -0
  109. package/tests/AutomationGwtTest.res +71 -0
  110. package/tests/AutomationGwtTest.res.mjs +189 -0
  111. package/tests/BuildClassifierTest.res +94 -0
  112. package/tests/BuildClassifierTest.res.mjs +132 -0
  113. package/tests/ComponentMetaTest.res +52 -0
  114. package/tests/ComponentMetaTest.res.mjs +57 -0
  115. package/tests/DelegateGwtTest.res +487 -0
  116. package/tests/DelegateGwtTest.res.mjs +891 -0
  117. package/tests/DiscoveryTest.res +42 -0
  118. package/tests/DiscoveryTest.res.mjs +43 -0
  119. package/tests/DomainDeadCodeTest.res +116 -0
  120. package/tests/DomainDeadCodeTest.res.mjs +155 -0
  121. package/tests/DomainGraphTest.res +365 -0
  122. package/tests/DomainGraphTest.res.mjs +413 -0
  123. package/tests/FlowAggregateGwtTest.res +169 -0
  124. package/tests/FlowAggregateGwtTest.res.mjs +269 -0
  125. package/tests/FlowCrossPluginGwtTest.res +340 -0
  126. package/tests/FlowCrossPluginGwtTest.res.mjs +798 -0
  127. package/tests/FlowGwtTest.res +222 -0
  128. package/tests/FlowGwtTest.res.mjs +432 -0
  129. package/tests/FormatterVsCodeMessageTest.res +41 -0
  130. package/tests/FormatterVsCodeMessageTest.res.mjs +42 -0
  131. package/tests/InboundTranslationGwtTest.res +34 -0
  132. package/tests/InboundTranslationGwtTest.res.mjs +98 -0
  133. package/tests/LocalHostIntegration.res +70 -0
  134. package/tests/LocalHostIntegration.res.mjs +64 -0
  135. package/tests/LocalHostTest.res +71 -0
  136. package/tests/LocalHostTest.res.mjs +63 -0
  137. package/tests/MappingGwtTest.res +348 -0
  138. package/tests/MappingGwtTest.res.mjs +592 -0
  139. package/tests/OutboundTranslationGwtTest.res +59 -0
  140. package/tests/OutboundTranslationGwtTest.res.mjs +138 -0
  141. package/tests/PlatformRunnerTest.res +66 -0
  142. package/tests/PlatformRunnerTest.res.mjs +85 -0
  143. package/tests/PlatformScanTest.res +61 -0
  144. package/tests/PlatformScanTest.res.mjs +56 -0
  145. package/tests/QueryGwtTest.res +161 -0
  146. package/tests/QueryGwtTest.res.mjs +314 -0
  147. package/tests/QueryResolverGwtTest.res +71 -0
  148. package/tests/QueryResolverGwtTest.res.mjs +136 -0
  149. package/tests/RunnerUnitTest.res +219 -0
  150. package/tests/RunnerUnitTest.res.mjs +244 -0
  151. package/tests/SideEffect/FakeOrderNotification.res +23 -0
  152. package/tests/SideEffect/FakeOrderNotification.res.mjs +36 -0
  153. package/tests/SideEffect/FakeOrderNotificationGwtTest.res +35 -0
  154. package/tests/SideEffect/FakeOrderNotificationGwtTest.res.mjs +73 -0
  155. package/tests/SideEffect/MockEmail.res +18 -0
  156. package/tests/SideEffect/MockEmail.res.mjs +47 -0
  157. package/tests/StateChange/ExternalAddCategorySlice_GWT.res +27 -0
  158. package/tests/StateChange/ExternalAddCategorySlice_GWT.res.mjs +70 -0
  159. package/tests/StateChange/WithFixtures_Fixtures.res +9 -0
  160. package/tests/StateChange/WithFixtures_Fixtures.res.mjs +20 -0
  161. package/tests/StateChange/WithFixtures_GWT.res +23 -0
  162. package/tests/StateChange/WithFixtures_GWT.res.mjs +56 -0
  163. package/tests/StateChange/WithManualOpen_Fixtures.res +7 -0
  164. package/tests/StateChange/WithManualOpen_Fixtures.res.mjs +20 -0
  165. package/tests/StateChange/WithManualOpen_GWT.res +17 -0
  166. package/tests/StateChange/WithManualOpen_GWT.res.mjs +56 -0
  167. package/tests/StateChangeSliceGwtTest.res +160 -0
  168. package/tests/StateChangeSliceGwtTest.res.mjs +280 -0
  169. package/tests/StateViewSliceGwtTest.res +64 -0
  170. package/tests/StateViewSliceGwtTest.res.mjs +161 -0
  171. package/tests/WatchDebounceTest.res +78 -0
  172. package/tests/WatchDebounceTest.res.mjs +97 -0
@@ -0,0 +1,592 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
5
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
6
+ import * as Mapping_GWT$ReventlessGwt from "../src/Mapping_GWT.res.mjs";
7
+
8
+ S.enableJson();
9
+
10
+ let name = "Category";
11
+
12
+ let commandSchema = S.schema(s => ({
13
+ TAG: "AddCategory",
14
+ categoryId: s.m(S.string),
15
+ name: s.m(S.string)
16
+ }));
17
+
18
+ let eventSchema = S.schema(s => ({
19
+ TAG: "CategoryAdded",
20
+ categoryId: s.m(S.string),
21
+ name: s.m(S.string)
22
+ }));
23
+
24
+ let errorSchema = S.literal("CategoryAlreadyExists");
25
+
26
+ let moduleUrl = "";
27
+
28
+ function commandAuthorization(param) {
29
+ return "AllowAuthenticated";
30
+ }
31
+
32
+ let CategorySpec = {
33
+ Id: undefined,
34
+ name: name,
35
+ commandSchema: commandSchema,
36
+ eventSchema: eventSchema,
37
+ errorSchema: errorSchema,
38
+ moduleUrl: moduleUrl,
39
+ commandAuthorization: commandAuthorization
40
+ };
41
+
42
+ function evolve(_state, event) {
43
+ return "Created";
44
+ }
45
+
46
+ function decide(state, cmd) {
47
+ if (state === "NotCreated") {
48
+ return {
49
+ TAG: "Ok",
50
+ _0: [{
51
+ TAG: "CategoryAdded",
52
+ categoryId: cmd.categoryId,
53
+ name: cmd.name
54
+ }]
55
+ };
56
+ } else {
57
+ return {
58
+ TAG: "Error",
59
+ _0: "CategoryAlreadyExists"
60
+ };
61
+ }
62
+ }
63
+
64
+ let moduleUrl$1 = "";
65
+
66
+ let CategoryBehavior = {
67
+ Spec: undefined,
68
+ initialState: "NotCreated",
69
+ evolve: evolve,
70
+ decide: decide,
71
+ moduleUrl: moduleUrl$1
72
+ };
73
+
74
+ let name$1 = "Product";
75
+
76
+ let commandSchema$1 = S.schema(s => ({
77
+ TAG: "MirrorCategory",
78
+ productId: s.m(S.string),
79
+ categoryId: s.m(S.string),
80
+ name: s.m(S.string)
81
+ }));
82
+
83
+ let eventSchema$1 = S.schema(s => ({
84
+ TAG: "ProductCategoryMirrored",
85
+ productId: s.m(S.string),
86
+ categoryId: s.m(S.string),
87
+ name: s.m(S.string)
88
+ }));
89
+
90
+ let errorSchema$1 = S.literal("ProductAlreadyMirrored");
91
+
92
+ let moduleUrl$2 = "";
93
+
94
+ function commandAuthorization$1(param) {
95
+ return "AllowAuthenticated";
96
+ }
97
+
98
+ let ProductSpec = {
99
+ Id: undefined,
100
+ name: name$1,
101
+ commandSchema: commandSchema$1,
102
+ eventSchema: eventSchema$1,
103
+ errorSchema: errorSchema$1,
104
+ moduleUrl: moduleUrl$2,
105
+ commandAuthorization: commandAuthorization$1
106
+ };
107
+
108
+ function evolve$1(_state, event) {
109
+ return "Mirrored";
110
+ }
111
+
112
+ function decide$1(state, cmd) {
113
+ if (state === "Pristine") {
114
+ return {
115
+ TAG: "Ok",
116
+ _0: [{
117
+ TAG: "ProductCategoryMirrored",
118
+ productId: cmd.productId,
119
+ categoryId: cmd.categoryId,
120
+ name: cmd.name
121
+ }]
122
+ };
123
+ } else {
124
+ return {
125
+ TAG: "Error",
126
+ _0: "ProductAlreadyMirrored"
127
+ };
128
+ }
129
+ }
130
+
131
+ let moduleUrl$3 = "";
132
+
133
+ let ProductBehavior = {
134
+ Spec: undefined,
135
+ initialState: "Pristine",
136
+ evolve: evolve$1,
137
+ decide: decide$1,
138
+ moduleUrl: moduleUrl$3
139
+ };
140
+
141
+ let consumedEventSchema = S.schema(s => ({
142
+ TAG: "NotificationSent",
143
+ notificationId: s.m(DcbTag$Reventless.string)
144
+ }));
145
+
146
+ function evolve$2(_state, event) {
147
+ return {
148
+ sent: true
149
+ };
150
+ }
151
+
152
+ let commandSchema$2 = S.schema(s => ({
153
+ TAG: "SendNotification",
154
+ notificationId: s.m(DcbTag$Reventless.string),
155
+ message: s.m(S.string)
156
+ }));
157
+
158
+ let errorSchema$2 = S.literal("NotificationAlreadySent");
159
+
160
+ let eventSchema$2 = S.schema(s => ({
161
+ TAG: "NotificationSent",
162
+ notificationId: s.m(DcbTag$Reventless.string),
163
+ message: s.m(S.string)
164
+ }));
165
+
166
+ function decide$2(state, command) {
167
+ if (state.sent) {
168
+ return {
169
+ TAG: "Error",
170
+ _0: "NotificationAlreadySent"
171
+ };
172
+ } else {
173
+ return {
174
+ TAG: "Ok",
175
+ _0: [{
176
+ TAG: "NotificationSent",
177
+ notificationId: command.notificationId,
178
+ message: command.message
179
+ }]
180
+ };
181
+ }
182
+ }
183
+
184
+ function commandAuthorization$2(param) {
185
+ return "AllowAuthenticated";
186
+ }
187
+
188
+ let NotificationSlice_initialState = {
189
+ sent: false
190
+ };
191
+
192
+ let NotificationSlice = {
193
+ name: "Notification",
194
+ initialState: NotificationSlice_initialState,
195
+ consumedEventSchema: consumedEventSchema,
196
+ evolve: evolve$2,
197
+ commandSchema: commandSchema$2,
198
+ errorSchema: errorSchema$2,
199
+ eventSchema: eventSchema$2,
200
+ decide: decide$2,
201
+ commandAuthorization: commandAuthorization$2,
202
+ readConsistency: "EscalateOnRetry"
203
+ };
204
+
205
+ let consumedEventSchema$1 = S.schema(s => ({
206
+ TAG: "StockReserved",
207
+ itemId: s.m(DcbTag$Reventless.string)
208
+ }));
209
+
210
+ function evolve$3(_state, event) {
211
+ return {
212
+ reserved: true
213
+ };
214
+ }
215
+
216
+ let commandSchema$3 = S.schema(s => ({
217
+ TAG: "ReserveStock",
218
+ itemId: s.m(DcbTag$Reventless.string),
219
+ quantity: s.m(S.int)
220
+ }));
221
+
222
+ let errorSchema$3 = S.literal("OutOfStock");
223
+
224
+ let eventSchema$3 = S.schema(s => ({
225
+ TAG: "StockReserved",
226
+ itemId: s.m(DcbTag$Reventless.string),
227
+ quantity: s.m(S.int)
228
+ }));
229
+
230
+ function decide$3(state, command) {
231
+ if (state.reserved) {
232
+ return {
233
+ TAG: "Error",
234
+ _0: "OutOfStock"
235
+ };
236
+ } else {
237
+ return {
238
+ TAG: "Ok",
239
+ _0: [{
240
+ TAG: "StockReserved",
241
+ itemId: command.itemId,
242
+ quantity: command.quantity
243
+ }]
244
+ };
245
+ }
246
+ }
247
+
248
+ function commandAuthorization$3(param) {
249
+ return "AllowAuthenticated";
250
+ }
251
+
252
+ let InventorySlice_initialState = {
253
+ reserved: false
254
+ };
255
+
256
+ let InventorySlice = {
257
+ name: "Inventory",
258
+ initialState: InventorySlice_initialState,
259
+ consumedEventSchema: consumedEventSchema$1,
260
+ evolve: evolve$3,
261
+ commandSchema: commandSchema$3,
262
+ errorSchema: errorSchema$3,
263
+ eventSchema: eventSchema$3,
264
+ decide: decide$3,
265
+ commandAuthorization: commandAuthorization$3,
266
+ readConsistency: "EscalateOnRetry"
267
+ };
268
+
269
+ let CategorySource = Mapping_GWT$ReventlessGwt.FromBehavior({
270
+ Id: {
271
+ schema: Id$Reventless.StringPure.schema,
272
+ make: prim => prim,
273
+ makeFromString: prim => prim,
274
+ toString: prim => prim,
275
+ cmp: Id$Reventless.StringPure.cmp
276
+ },
277
+ name: name,
278
+ eventSchema: eventSchema,
279
+ errorSchema: errorSchema,
280
+ commandSchema: commandSchema,
281
+ moduleUrl: moduleUrl,
282
+ commandAuthorization: commandAuthorization
283
+ })({
284
+ Spec: {
285
+ Id: {
286
+ schema: Id$Reventless.StringPure.schema,
287
+ make: prim => prim,
288
+ makeFromString: prim => prim,
289
+ toString: prim => prim,
290
+ cmp: Id$Reventless.StringPure.cmp
291
+ },
292
+ name: name,
293
+ eventSchema: eventSchema,
294
+ errorSchema: errorSchema,
295
+ commandSchema: commandSchema,
296
+ moduleUrl: moduleUrl,
297
+ commandAuthorization: commandAuthorization
298
+ },
299
+ initialState: "NotCreated",
300
+ evolve: evolve,
301
+ decide: decide,
302
+ moduleUrl: moduleUrl$1
303
+ });
304
+
305
+ let ProductTarget = Mapping_GWT$ReventlessGwt.FromBehavior({
306
+ Id: {
307
+ schema: Id$Reventless.StringPure.schema,
308
+ make: prim => prim,
309
+ makeFromString: prim => prim,
310
+ toString: prim => prim,
311
+ cmp: Id$Reventless.StringPure.cmp
312
+ },
313
+ name: name$1,
314
+ eventSchema: eventSchema$1,
315
+ errorSchema: errorSchema$1,
316
+ commandSchema: commandSchema$1,
317
+ moduleUrl: moduleUrl$2,
318
+ commandAuthorization: commandAuthorization$1
319
+ })({
320
+ Spec: {
321
+ Id: {
322
+ schema: Id$Reventless.StringPure.schema,
323
+ make: prim => prim,
324
+ makeFromString: prim => prim,
325
+ toString: prim => prim,
326
+ cmp: Id$Reventless.StringPure.cmp
327
+ },
328
+ name: name$1,
329
+ eventSchema: eventSchema$1,
330
+ errorSchema: errorSchema$1,
331
+ commandSchema: commandSchema$1,
332
+ moduleUrl: moduleUrl$2,
333
+ commandAuthorization: commandAuthorization$1
334
+ },
335
+ initialState: "Pristine",
336
+ evolve: evolve$1,
337
+ decide: decide$1,
338
+ moduleUrl: moduleUrl$3
339
+ });
340
+
341
+ let NotificationSource = Mapping_GWT$ReventlessGwt.FromStateChangeSlice(NotificationSlice);
342
+
343
+ let NotificationTarget = Mapping_GWT$ReventlessGwt.FromStateChangeSlice(NotificationSlice);
344
+
345
+ let InventoryTarget = Mapping_GWT$ReventlessGwt.FromStateChangeSlice(InventorySlice);
346
+
347
+ function map(_sourceId, event, _q) {
348
+ let categoryId = event.categoryId;
349
+ return [{
350
+ TAG: "Publish",
351
+ _0: "prod-for-" + categoryId,
352
+ _1: {
353
+ TAG: "MirrorCategory",
354
+ productId: "prod-for-" + categoryId,
355
+ categoryId: categoryId,
356
+ name: event.name
357
+ }
358
+ }];
359
+ }
360
+
361
+ let AggrToAggrMapping = {
362
+ Source: undefined,
363
+ Target: undefined,
364
+ map: map
365
+ };
366
+
367
+ let AggrToAggrGwt = Mapping_GWT$ReventlessGwt.Make({
368
+ Source: CategorySource,
369
+ Target: ProductTarget,
370
+ map: map
371
+ });
372
+
373
+ AggrToAggrGwt.describe("Category → Product (Aggr → Aggr)", () => AggrToAggrGwt.test("AddCategory produces ProductCategoryMirrored on product", undefined, () => AggrToAggrGwt.thenTargetEvent(AggrToAggrGwt.whenSourceCmd(AggrToAggrGwt.andTargetEvents(AggrToAggrGwt.givenSourceEvents([]), []), "c1", {
374
+ TAG: "AddCategory",
375
+ categoryId: "c1",
376
+ name: "Books"
377
+ }), "prod-for-c1", {
378
+ TAG: "ProductCategoryMirrored",
379
+ productId: "prod-for-c1",
380
+ categoryId: "c1",
381
+ name: "Books"
382
+ })));
383
+
384
+ function map$1(_sourceId, event, _q) {
385
+ let categoryId = event.categoryId;
386
+ return [{
387
+ TAG: "Publish",
388
+ _0: "notif-" + categoryId,
389
+ _1: {
390
+ TAG: "SendNotification",
391
+ notificationId: "notif-" + categoryId,
392
+ message: `Category ` + event.name + ` was created`
393
+ }
394
+ }];
395
+ }
396
+
397
+ let AggrToDcbMapping = {
398
+ Source: undefined,
399
+ Target: undefined,
400
+ map: map$1
401
+ };
402
+
403
+ let AggrToDcbGwt = Mapping_GWT$ReventlessGwt.Make({
404
+ Source: CategorySource,
405
+ Target: {
406
+ name: NotificationTarget.name,
407
+ Id: {
408
+ schema: Id$Reventless.StringPure.schema,
409
+ make: prim => prim,
410
+ makeFromString: prim => prim,
411
+ toString: prim => prim,
412
+ cmp: Id$Reventless.StringPure.cmp
413
+ },
414
+ initialState: NotificationTarget.initialState,
415
+ consumedEventSchema: NotificationTarget.consumedEventSchema,
416
+ evolve: NotificationTarget.evolve,
417
+ commandSchema: NotificationTarget.commandSchema,
418
+ eventSchema: NotificationTarget.eventSchema,
419
+ errorSchema: NotificationTarget.errorSchema,
420
+ decide: NotificationTarget.decide
421
+ },
422
+ map: map$1
423
+ });
424
+
425
+ AggrToDcbGwt.describe("Category → Notification (Aggr → DCB)", () => AggrToDcbGwt.test("AddCategory triggers NotificationSent on the DCB slice", undefined, () => AggrToDcbGwt.thenTargetEvent(AggrToDcbGwt.whenSourceCmd(AggrToDcbGwt.andTargetEvents(AggrToDcbGwt.givenSourceEvents([]), []), "c2", {
426
+ TAG: "AddCategory",
427
+ categoryId: "c2",
428
+ name: "Media"
429
+ }), "notif-c2", {
430
+ TAG: "NotificationSent",
431
+ notificationId: "notif-c2",
432
+ message: "Category Media was created"
433
+ })));
434
+
435
+ let InventorySource = Mapping_GWT$ReventlessGwt.FromStateChangeSlice(InventorySlice);
436
+
437
+ function map$2(_sourceId, event, _q) {
438
+ let itemId = event.itemId;
439
+ return [{
440
+ TAG: "Publish",
441
+ _0: "prod-" + itemId,
442
+ _1: {
443
+ TAG: "MirrorCategory",
444
+ productId: "prod-" + itemId,
445
+ categoryId: itemId,
446
+ name: itemId
447
+ }
448
+ }];
449
+ }
450
+
451
+ let DcbToAggrMapping = {
452
+ Source: undefined,
453
+ Target: undefined,
454
+ map: map$2
455
+ };
456
+
457
+ let DcbToAggrGwt = Mapping_GWT$ReventlessGwt.Make({
458
+ Source: {
459
+ name: InventorySource.name,
460
+ Id: {
461
+ schema: Id$Reventless.StringPure.schema,
462
+ make: prim => prim,
463
+ makeFromString: prim => prim,
464
+ toString: prim => prim,
465
+ cmp: Id$Reventless.StringPure.cmp
466
+ },
467
+ initialState: InventorySource.initialState,
468
+ consumedEventSchema: InventorySource.consumedEventSchema,
469
+ evolve: InventorySource.evolve,
470
+ commandSchema: InventorySource.commandSchema,
471
+ eventSchema: InventorySource.eventSchema,
472
+ errorSchema: InventorySource.errorSchema,
473
+ decide: InventorySource.decide
474
+ },
475
+ Target: ProductTarget,
476
+ map: map$2
477
+ });
478
+
479
+ DcbToAggrGwt.describe("Inventory → Product (DCB → Aggr)", () => DcbToAggrGwt.test("ReserveStock triggers ProductCategoryMirrored", undefined, () => DcbToAggrGwt.thenTargetEvent(DcbToAggrGwt.whenSourceCmd(DcbToAggrGwt.andTargetEvents(DcbToAggrGwt.givenSourceEvents([]), []), "i1", {
480
+ TAG: "ReserveStock",
481
+ itemId: "i1",
482
+ quantity: 5
483
+ }), "prod-i1", {
484
+ TAG: "ProductCategoryMirrored",
485
+ productId: "prod-i1",
486
+ categoryId: "i1",
487
+ name: "i1"
488
+ })));
489
+
490
+ function map$3(_sourceId, event, _q) {
491
+ let itemId = event.itemId;
492
+ return [{
493
+ TAG: "Publish",
494
+ _0: "reserved-" + itemId,
495
+ _1: {
496
+ TAG: "SendNotification",
497
+ notificationId: "reserved-" + itemId,
498
+ message: `Reserved ` + event.quantity.toString() + ` of ` + itemId
499
+ }
500
+ }];
501
+ }
502
+
503
+ let DcbToDcbMapping = {
504
+ Source: undefined,
505
+ Target: undefined,
506
+ map: map$3
507
+ };
508
+
509
+ let DcbToDcbGwt = Mapping_GWT$ReventlessGwt.Make({
510
+ Source: {
511
+ name: InventorySource.name,
512
+ Id: {
513
+ schema: Id$Reventless.StringPure.schema,
514
+ make: prim => prim,
515
+ makeFromString: prim => prim,
516
+ toString: prim => prim,
517
+ cmp: Id$Reventless.StringPure.cmp
518
+ },
519
+ initialState: InventorySource.initialState,
520
+ consumedEventSchema: InventorySource.consumedEventSchema,
521
+ evolve: InventorySource.evolve,
522
+ commandSchema: InventorySource.commandSchema,
523
+ eventSchema: InventorySource.eventSchema,
524
+ errorSchema: InventorySource.errorSchema,
525
+ decide: InventorySource.decide
526
+ },
527
+ Target: {
528
+ name: NotificationTarget.name,
529
+ Id: {
530
+ schema: Id$Reventless.StringPure.schema,
531
+ make: prim => prim,
532
+ makeFromString: prim => prim,
533
+ toString: prim => prim,
534
+ cmp: Id$Reventless.StringPure.cmp
535
+ },
536
+ initialState: NotificationTarget.initialState,
537
+ consumedEventSchema: NotificationTarget.consumedEventSchema,
538
+ evolve: NotificationTarget.evolve,
539
+ commandSchema: NotificationTarget.commandSchema,
540
+ eventSchema: NotificationTarget.eventSchema,
541
+ errorSchema: NotificationTarget.errorSchema,
542
+ decide: NotificationTarget.decide
543
+ },
544
+ map: map$3
545
+ });
546
+
547
+ DcbToDcbGwt.describe("Inventory → Notification (DCB → DCB)", () => {
548
+ DcbToDcbGwt.test("ReserveStock triggers NotificationSent", undefined, () => DcbToDcbGwt.thenTargetEvent(DcbToDcbGwt.whenSourceCmd(DcbToDcbGwt.andTargetEvents(DcbToDcbGwt.givenSourceEvents([]), []), "i7", {
549
+ TAG: "ReserveStock",
550
+ itemId: "i7",
551
+ quantity: 2
552
+ }), "reserved-i7", {
553
+ TAG: "NotificationSent",
554
+ notificationId: "reserved-i7",
555
+ message: "Reserved 2 of i7"
556
+ }));
557
+ DcbToDcbGwt.test("existing NotificationSent causes target decide to reject", undefined, () => DcbToDcbGwt.thenTargetError(DcbToDcbGwt.whenSourceCmd(DcbToDcbGwt.andTargetEvents(DcbToDcbGwt.givenSourceEvents([]), [[
558
+ "reserved-i7",
559
+ [{
560
+ TAG: "NotificationSent",
561
+ notificationId: "reserved-i7"
562
+ }]
563
+ ]]), "i7", {
564
+ TAG: "ReserveStock",
565
+ itemId: "i7",
566
+ quantity: 2
567
+ }), "NotificationAlreadySent"));
568
+ });
569
+
570
+ export {
571
+ CategorySpec,
572
+ CategoryBehavior,
573
+ ProductSpec,
574
+ ProductBehavior,
575
+ NotificationSlice,
576
+ InventorySlice,
577
+ CategorySource,
578
+ ProductTarget,
579
+ NotificationSource,
580
+ NotificationTarget,
581
+ InventoryTarget,
582
+ AggrToAggrMapping,
583
+ AggrToAggrGwt,
584
+ AggrToDcbMapping,
585
+ AggrToDcbGwt,
586
+ InventorySource,
587
+ DcbToAggrMapping,
588
+ DcbToAggrGwt,
589
+ DcbToDcbMapping,
590
+ DcbToDcbGwt,
591
+ }
592
+ /* Not a pure module */
@@ -0,0 +1,59 @@
1
+ // Worked example for OutboundTranslationSlice_GWT — a "send tracking email"
2
+ // slice. Collect builds a TODO from OrderShipped; translate is mocked to
3
+ // exercise both happy path (fire-and-forget success) and failure (retry).
4
+
5
+ @@reventless.gwt
6
+
7
+ module SendTrackingEmailSlice = {
8
+ let name = "SendTrackingEmail"
9
+
10
+ @schema
11
+ type consumedEvent = OrderShipped({orderId: string, email: string})
12
+
13
+ @schema
14
+ type outboundItem = {orderId: string, email: string}
15
+
16
+ @schema
17
+ type inboundCommand = NoOp
18
+
19
+ let collect = event =>
20
+ switch event {
21
+ | OrderShipped({orderId, email}) => [(orderId, {orderId, email})]
22
+ }
23
+ }
24
+
25
+ describe("SendTrackingEmail OutboundTranslationSlice", () => {
26
+ test("collect: OrderShipped queues an outbound TODO", async () =>
27
+ givenEvent(OrderShipped({orderId: "o1", email: "x@y"}))
28
+ ->whenCollect
29
+ ->thenTodos([("o1", {orderId: "o1", email: "x@y"})])
30
+ )
31
+
32
+ test("translate success is fire-and-forget → #Completed", () =>
33
+ givenTodo("o1", {orderId: "o1", email: "x@y"})
34
+ ->whenTranslateMocked((_id, _item) => Promise.resolve(Ok(None)))
35
+ ->thenTodoStatus("o1", #Completed)
36
+ )
37
+
38
+ test("translate failure records a retry → #Pending", () =>
39
+ givenTodo("o1", {orderId: "o1", email: "x@y"})
40
+ ->whenTranslateMocked((_id, _item) => Promise.resolve(Error("smtp down")))
41
+ ->thenTodoStatus("o1", #Pending)
42
+ )
43
+
44
+ test("retrying translate succeeds on the third attempt → 2 retries recorded", () => {
45
+ let calls = ref(0)
46
+ givenTodo("o1", {orderId: "o1", email: "x@y"})
47
+ ->whenTranslateRetrying(~maxRetries=3, (_id, _item) => {
48
+ calls := calls.contents + 1
49
+ Promise.resolve(calls.contents < 3 ? Error("smtp down") : Ok(None))
50
+ })
51
+ ->thenRetryRecorded(2)
52
+ })
53
+
54
+ test("translate that keeps failing exhausts maxRetries", () =>
55
+ givenTodo("o1", {orderId: "o1", email: "x@y"})
56
+ ->whenTranslateRetrying(~maxRetries=3, (_id, _item) => Promise.resolve(Error("smtp down")))
57
+ ->thenRetryRecorded(3)
58
+ )
59
+ })