@reventlessdev/reventless-gwt 1.0.0-alpha.238 → 1.0.0-alpha.240

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 (37) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +6 -6
  3. package/src/Automation_GWT.res +130 -0
  4. package/src/Automation_GWT.res.mjs +193 -0
  5. package/src/Behavior_GWT.res +6 -6
  6. package/src/Behavior_GWT.res.mjs +5 -5
  7. package/src/Capabilities_Fake.res +157 -0
  8. package/src/Capabilities_Fake.res.mjs +254 -0
  9. package/src/Flow_GWT.res +112 -1
  10. package/src/Flow_GWT.res.mjs +165 -11
  11. package/src/InboundTranslation_GWT.res +112 -0
  12. package/src/InboundTranslation_GWT.res.mjs +190 -1
  13. package/src/OutboundTranslation_GWT.res +207 -4
  14. package/src/OutboundTranslation_GWT.res.mjs +257 -1
  15. package/src/StateChange/ExternalAddCategorySlice.res +1 -1
  16. package/src/StateChange/ExternalAddCategorySlice.res.mjs +2 -2
  17. package/src/StateChange/WithFixtures.res +1 -1
  18. package/src/StateChange/WithFixtures.res.mjs +2 -2
  19. package/src/StateChange/WithManualOpen.res +1 -1
  20. package/src/StateChange/WithManualOpen.res.mjs +2 -2
  21. package/tests/AutomationFromSliceGwtTest.res +145 -0
  22. package/tests/AutomationFromSliceGwtTest.res.mjs +353 -0
  23. package/tests/AutomationGwtTest.res.mjs +2 -2
  24. package/tests/DelegateGwtTest.res +5 -5
  25. package/tests/DelegateGwtTest.res.mjs +27 -27
  26. package/tests/FlowAggregateGwtTest.res.mjs +4 -4
  27. package/tests/FlowCrossPluginGwtTest.res +4 -4
  28. package/tests/FlowCrossPluginGwtTest.res.mjs +22 -22
  29. package/tests/FlowGwtTest.res.mjs +6 -6
  30. package/tests/InboundFromSliceGwtTest.res +63 -0
  31. package/tests/InboundFromSliceGwtTest.res.mjs +164 -0
  32. package/tests/InboundTranslationGwtTest.res.mjs +2 -7
  33. package/tests/MappingGwtTest.res.mjs +12 -12
  34. package/tests/OutboundFromSliceGwtTest.res +124 -0
  35. package/tests/OutboundFromSliceGwtTest.res.mjs +268 -0
  36. package/tests/StateChangeSliceAuthorizeGwtTest.res.mjs +20 -16
  37. package/tests/StateChangeSliceGwtTest.res.mjs +6 -6
@@ -0,0 +1,124 @@
1
+ // OutboundTranslation_GWT.FromSlice: the slice's real `translate`, run against
2
+ // recording capability fakes, and statuses counted as the runtime counts them.
3
+
4
+ module Welcome = {
5
+ let name = "Welcome"
6
+ let moduleUrl = ""
7
+
8
+ @schema
9
+ type consumedEvent = Registered({customerId: string, email: string})
10
+
11
+ @schema
12
+ type outboundItem = {email: string}
13
+
14
+ @schema
15
+ type inboundCommand = MarkWelcomed({customerId: string}) | MarkUnreachable({customerId: string})
16
+
17
+ let maxRetries = 2
18
+ let heartbeatInterval = 60
19
+ let targetName = Some("Customer")
20
+ let sourceNames = []
21
+ let externalSystem = None
22
+ let capabilityNeeds = []
23
+ let traits = []
24
+ }
25
+
26
+ module Welcome_Translation = {
27
+ let moduleUrl = ""
28
+
29
+ let collect = (event, ~sourceId) =>
30
+ switch event {
31
+ | Welcome.Registered({email, _}) => [(sourceId, ({email: email}: Welcome.outboundItem))]
32
+ }
33
+
34
+ let translate = async (
35
+ id,
36
+ item: Welcome.outboundItem,
37
+ ~capabilities: Reventless.Capabilities.t,
38
+ ) =>
39
+ switch await capabilities.messaging.send(
40
+ ~recipient=ToEmail(item.email),
41
+ ~message={subject: "Welcome", body: "Hello"},
42
+ ) {
43
+ | Ok(_) => Ok(Some((id, Welcome.MarkWelcomed({customerId: id}))))
44
+ | Error(failure) => Error(failure->Reventless.Messaging.failureReason)
45
+ }
46
+
47
+ let onExhausted = (id, _item, ~lastError as _) => Some((
48
+ id,
49
+ Welcome.MarkUnreachable({customerId: id}),
50
+ ))
51
+ }
52
+
53
+ open Welcome
54
+ include OutboundTranslation_GWT.FromSlice(Welcome, Welcome_Translation)
55
+
56
+ let down = Capabilities_Fake.make(
57
+ ~send=async (~recipient as _, ~message as _) => Error(Unavailable("smtp down")),
58
+ (),
59
+ )
60
+
61
+ let welcome: Capabilities_Fake.call = Sent({
62
+ recipient: ToEmail("a@b.c"),
63
+ message: {subject: "Welcome", body: "Hello"},
64
+ })
65
+
66
+ describe("OutboundTranslation_GWT.FromSlice", () => {
67
+ testSync("collect keys by the source id", () =>
68
+ givenEvent(Registered({customerId: "c1", email: "a@b.c"}))
69
+ ->whenCollect(~sourceId="c1")
70
+ ->thenTodos([("c1", {email: "a@b.c"})])
71
+ )
72
+
73
+ test("translate sends through the messaging capability", () =>
74
+ givenTodo("c1", {email: "a@b.c"})->whenTranslated->thenSent([welcome])
75
+ )
76
+
77
+ test("translate answers with a command", () =>
78
+ givenTodo("c1", {email: "a@b.c"})
79
+ ->whenTranslated
80
+ ->thenCommand("c1", MarkWelcomed({customerId: "c1"}))
81
+ )
82
+
83
+ test("a failed attempt leaves the row Failed", () =>
84
+ givenTodo("c1", {email: "a@b.c"})
85
+ ->givenCapabilities(down)
86
+ ->whenTranslated
87
+ ->thenTodoStatus("c1", #Failed)
88
+ )
89
+
90
+ test("#Pending still reads as #Failed", () =>
91
+ givenTodo("c1", {email: "a@b.c"})
92
+ ->givenCapabilities(down)
93
+ ->whenTranslated
94
+ ->thenTodoStatus("c1", #Pending)
95
+ )
96
+
97
+ test("maxRetries failed attempts abandon the row", () =>
98
+ givenTodo("c1", {email: "a@b.c"})
99
+ ->whenTranslateRetrying(async (_, _) => Error("down"))
100
+ ->thenTodoStatus("c1", #Abandoned)
101
+ )
102
+
103
+ test("maxRetries attempts in all, as the runtime makes them", () =>
104
+ givenTodo("c1", {email: "a@b.c"})
105
+ ->whenTranslateRetrying(async (_, _) => Error("down"))
106
+ ->thenRetryRecorded(2)
107
+ )
108
+
109
+ test("a throw is a failed attempt", () =>
110
+ givenTodo("c1", {email: "a@b.c"})
111
+ ->whenTranslateMocked(async (_, _) => JsError.throwWithMessage("boom"))
112
+ ->thenTodoStatus("c1", #Failed)
113
+ )
114
+
115
+ test("exhausted: onExhausted is what the domain hears", () =>
116
+ givenTodo("c1", {email: "a@b.c"})
117
+ ->whenExhausted(~lastError="smtp down")
118
+ ->thenCommand("c1", MarkUnreachable({customerId: "c1"}))
119
+ )
120
+
121
+ test("nothing sent when the slice is never translated", () =>
122
+ givenTodo("c1", {email: "a@b.c"})->whenExhausted->thenNothingSent
123
+ )
124
+ })
@@ -0,0 +1,268 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
5
+ import * as Messaging$Reventless from "@reventlessdev/reventless-spec/src/semantic/Messaging.res.mjs";
6
+ import * as Capabilities_Fake$ReventlessGwt from "../src/Capabilities_Fake.res.mjs";
7
+ import * as OutboundTranslation_GWT$ReventlessGwt from "../src/OutboundTranslation_GWT.res.mjs";
8
+
9
+ let consumedEventSchema = Sury.$schema(s => ({
10
+ TAG: "Registered",
11
+ customerId: s.m(Sury.string),
12
+ email: s.m(Sury.string)
13
+ }));
14
+
15
+ let outboundItemSchema = Sury.$schema(s => ({
16
+ email: s.m(Sury.string)
17
+ }));
18
+
19
+ let inboundCommandSchema = Sury.union([
20
+ Sury.$schema(s => ({
21
+ TAG: "MarkWelcomed",
22
+ customerId: s.m(Sury.string)
23
+ })),
24
+ Sury.$schema(s => ({
25
+ TAG: "MarkUnreachable",
26
+ customerId: s.m(Sury.string)
27
+ }))
28
+ ]);
29
+
30
+ let sourceNames = [];
31
+
32
+ let capabilityNeeds = [];
33
+
34
+ let traits = [];
35
+
36
+ let Welcome_targetName = "Customer";
37
+
38
+ let Welcome = {
39
+ name: "Welcome",
40
+ moduleUrl: "",
41
+ consumedEventSchema: consumedEventSchema,
42
+ outboundItemSchema: outboundItemSchema,
43
+ inboundCommandSchema: inboundCommandSchema,
44
+ maxRetries: 2,
45
+ heartbeatInterval: 60,
46
+ targetName: Welcome_targetName,
47
+ sourceNames: sourceNames,
48
+ externalSystem: undefined,
49
+ capabilityNeeds: capabilityNeeds,
50
+ traits: traits
51
+ };
52
+
53
+ let moduleUrl = "";
54
+
55
+ function collect(event, sourceId) {
56
+ return [[
57
+ sourceId,
58
+ {
59
+ email: event.email
60
+ }
61
+ ]];
62
+ }
63
+
64
+ async function translate(id, item, capabilities) {
65
+ let failure = await capabilities.messaging.send({
66
+ TAG: "ToEmail",
67
+ _0: item.email
68
+ }, {
69
+ subject: "Welcome",
70
+ body: "Hello"
71
+ });
72
+ if (failure.TAG === "Ok") {
73
+ return {
74
+ TAG: "Ok",
75
+ _0: [
76
+ id,
77
+ {
78
+ TAG: "MarkWelcomed",
79
+ customerId: id
80
+ }
81
+ ]
82
+ };
83
+ } else {
84
+ return {
85
+ TAG: "Error",
86
+ _0: Messaging$Reventless.failureReason(failure._0)
87
+ };
88
+ }
89
+ }
90
+
91
+ function onExhausted(id, _item, param) {
92
+ return [
93
+ id,
94
+ {
95
+ TAG: "MarkUnreachable",
96
+ customerId: id
97
+ }
98
+ ];
99
+ }
100
+
101
+ let Welcome_Translation = {
102
+ moduleUrl: moduleUrl,
103
+ collect: collect,
104
+ translate: translate,
105
+ onExhausted: onExhausted
106
+ };
107
+
108
+ let include = OutboundTranslation_GWT$ReventlessGwt.FromSlice(Welcome)({
109
+ collect: collect,
110
+ translate: translate,
111
+ onExhausted: onExhausted,
112
+ moduleUrl: moduleUrl
113
+ });
114
+
115
+ let describe = include.describe;
116
+
117
+ let test = include.test;
118
+
119
+ let testSync = include.testSync;
120
+
121
+ let givenEvent = include.givenEvent;
122
+
123
+ let whenCollect = include.whenCollect;
124
+
125
+ let thenTodos = include.thenTodos;
126
+
127
+ let givenTodo = include.givenTodo;
128
+
129
+ let givenCapabilities = include.givenCapabilities;
130
+
131
+ let whenTranslated = include.whenTranslated;
132
+
133
+ let whenTranslateMocked = include.whenTranslateMocked;
134
+
135
+ let whenTranslateRetrying = include.whenTranslateRetrying;
136
+
137
+ let whenExhausted = include.whenExhausted;
138
+
139
+ let thenCommand = include.thenCommand;
140
+
141
+ let thenSent = include.thenSent;
142
+
143
+ let thenNothingSent = include.thenNothingSent;
144
+
145
+ let thenRetryRecorded = include.thenRetryRecorded;
146
+
147
+ let thenTodoStatus = include.thenTodoStatus;
148
+
149
+ let down = Capabilities_Fake$ReventlessGwt.make(undefined, async (param, param$1) => ({
150
+ TAG: "Error",
151
+ _0: {
152
+ TAG: "Unavailable",
153
+ _0: "smtp down"
154
+ }
155
+ }), undefined, undefined, undefined, undefined, undefined, undefined, undefined);
156
+
157
+ let welcome = {
158
+ TAG: "Sent",
159
+ recipient: {
160
+ TAG: "ToEmail",
161
+ _0: "a@b.c"
162
+ },
163
+ message: {
164
+ subject: "Welcome",
165
+ body: "Hello"
166
+ }
167
+ };
168
+
169
+ describe("OutboundTranslation_GWT.FromSlice", () => {
170
+ testSync("collect keys by the source id", () => thenTodos(whenCollect(givenEvent({
171
+ TAG: "Registered",
172
+ customerId: "c1",
173
+ email: "a@b.c"
174
+ }), "c1"), [[
175
+ "c1",
176
+ {
177
+ email: "a@b.c"
178
+ }
179
+ ]]));
180
+ test("translate sends through the messaging capability", undefined, () => thenSent(whenTranslated(givenTodo("c1", {
181
+ email: "a@b.c"
182
+ })), [welcome]));
183
+ test("translate answers with a command", undefined, () => thenCommand(whenTranslated(givenTodo("c1", {
184
+ email: "a@b.c"
185
+ })), "c1", {
186
+ TAG: "MarkWelcomed",
187
+ customerId: "c1"
188
+ }));
189
+ test("a failed attempt leaves the row Failed", undefined, () => thenTodoStatus(whenTranslated(givenCapabilities(givenTodo("c1", {
190
+ email: "a@b.c"
191
+ }), down)), "c1", "Failed"));
192
+ test("#Pending still reads as #Failed", undefined, () => thenTodoStatus(whenTranslated(givenCapabilities(givenTodo("c1", {
193
+ email: "a@b.c"
194
+ }), down)), "c1", "Pending"));
195
+ test("maxRetries failed attempts abandon the row", undefined, () => thenTodoStatus(whenTranslateRetrying(givenTodo("c1", {
196
+ email: "a@b.c"
197
+ }), undefined, async (param, param$1) => ({
198
+ TAG: "Error",
199
+ _0: "down"
200
+ })), "c1", "Abandoned"));
201
+ test("maxRetries attempts in all, as the runtime makes them", undefined, () => thenRetryRecorded(whenTranslateRetrying(givenTodo("c1", {
202
+ email: "a@b.c"
203
+ }), undefined, async (param, param$1) => ({
204
+ TAG: "Error",
205
+ _0: "down"
206
+ })), 2));
207
+ test("a throw is a failed attempt", undefined, () => thenTodoStatus(whenTranslateMocked(givenTodo("c1", {
208
+ email: "a@b.c"
209
+ }), async (param, param$1) => Stdlib_JsError.throwWithMessage("boom")), "c1", "Failed"));
210
+ test("exhausted: onExhausted is what the domain hears", undefined, () => thenCommand(whenExhausted(givenTodo("c1", {
211
+ email: "a@b.c"
212
+ }), "smtp down"), "c1", {
213
+ TAG: "MarkUnreachable",
214
+ customerId: "c1"
215
+ }));
216
+ test("nothing sent when the slice is never translated", undefined, () => thenNothingSent(whenExhausted(givenTodo("c1", {
217
+ email: "a@b.c"
218
+ }), undefined)));
219
+ });
220
+
221
+ let encItems = include.encItems;
222
+
223
+ let commandPairJson = include.commandPairJson;
224
+
225
+ let errorOf = include.errorOf;
226
+
227
+ let fakes = include.fakes;
228
+
229
+ let attemptWith = include.attemptWith;
230
+
231
+ let attempts = include.attempts;
232
+
233
+ let thenNoCommand = include.thenNoCommand;
234
+
235
+ let statusName = include.statusName;
236
+
237
+ export {
238
+ Welcome,
239
+ Welcome_Translation,
240
+ describe,
241
+ test,
242
+ testSync,
243
+ encItems,
244
+ commandPairJson,
245
+ errorOf,
246
+ givenEvent,
247
+ whenCollect,
248
+ thenTodos,
249
+ givenTodo,
250
+ fakes,
251
+ givenCapabilities,
252
+ attemptWith,
253
+ attempts,
254
+ whenTranslated,
255
+ whenTranslateMocked,
256
+ whenTranslateRetrying,
257
+ whenExhausted,
258
+ thenCommand,
259
+ thenNoCommand,
260
+ thenSent,
261
+ thenNothingSent,
262
+ thenRetryRecorded,
263
+ statusName,
264
+ thenTodoStatus,
265
+ down,
266
+ welcome,
267
+ }
268
+ /* consumedEventSchema Not a pure module */
@@ -40,8 +40,12 @@ let eventSchema = Sury.$schema(s => ({
40
40
  shelfId: s.m(DcbTag$Reventless.string)
41
41
  }));
42
42
 
43
- function commandAuthorization(command) {
44
- switch (command.TAG) {
43
+ function authorizationOf(name) {
44
+ switch (name) {
45
+ case "Peek" :
46
+ return "AllowAnonymous";
47
+ case "Purge" :
48
+ return "DenyAll";
45
49
  case "Shelve" :
46
50
  return {
47
51
  TAG: "AllowRoles",
@@ -50,12 +54,8 @@ function commandAuthorization(command) {
50
54
  "Merchandiser"
51
55
  ]
52
56
  };
53
- case "Browse" :
57
+ default:
54
58
  return "AllowAuthenticated";
55
- case "Peek" :
56
- return "AllowAnonymous";
57
- case "Purge" :
58
- return "DenyAll";
59
59
  }
60
60
  }
61
61
 
@@ -72,7 +72,7 @@ let ShelveSlice = {
72
72
  commandSchema: commandSchema,
73
73
  errorSchema: errorSchema,
74
74
  eventSchema: eventSchema,
75
- commandAuthorization: commandAuthorization,
75
+ authorizationOf: authorizationOf,
76
76
  commandTransition: commandTransition,
77
77
  traits: traits,
78
78
  readConsistency: "EscalateOnRetry"
@@ -105,7 +105,7 @@ let include = Behavior_GWT$ReventlessGwt.Make({
105
105
  commandSchema: commandSchema,
106
106
  errorSchema: errorSchema,
107
107
  eventSchema: eventSchema,
108
- commandAuthorization: commandAuthorization
108
+ authorizationOf: authorizationOf
109
109
  })({
110
110
  initialState: undefined,
111
111
  evolve: evolve,
@@ -203,11 +203,15 @@ let eventSchema$1 = Sury.$schema(s => ({
203
203
  shelfId: s.m(DcbTag$Reventless.string)
204
204
  }));
205
205
 
206
- function commandAuthorization$1(command) {
207
- return {
208
- TAG: "AllowRoles",
209
- _0: ["Merchandiser"]
210
- };
206
+ function authorizationOf$1(name) {
207
+ if (name === "Shelve") {
208
+ return {
209
+ TAG: "AllowRoles",
210
+ _0: ["Merchandiser"]
211
+ };
212
+ } else {
213
+ return "AllowAuthenticated";
214
+ }
211
215
  }
212
216
 
213
217
  function commandTransition$1(param) {
@@ -223,7 +227,7 @@ let ClaimSlice = {
223
227
  commandSchema: commandSchema$1,
224
228
  errorSchema: errorSchema$1,
225
229
  eventSchema: eventSchema$1,
226
- commandAuthorization: commandAuthorization$1,
230
+ authorizationOf: authorizationOf$1,
227
231
  commandTransition: commandTransition$1,
228
232
  traits: traits$1,
229
233
  readConsistency: "EscalateOnRetry"
@@ -249,7 +253,7 @@ let Claim = Behavior_GWT$ReventlessGwt.Make({
249
253
  commandSchema: commandSchema$1,
250
254
  errorSchema: errorSchema$1,
251
255
  eventSchema: eventSchema$1,
252
- commandAuthorization: commandAuthorization$1
256
+ authorizationOf: authorizationOf$1
253
257
  })({
254
258
  initialState: undefined,
255
259
  evolve: evolve$1,
@@ -24,7 +24,7 @@ let eventSchema = Sury.$schema(s => ({
24
24
  name: s.m(Sury.string)
25
25
  }));
26
26
 
27
- function commandAuthorization(param) {
27
+ function authorizationOf(param) {
28
28
  return "AllowAuthenticated";
29
29
  }
30
30
 
@@ -40,7 +40,7 @@ let AddCategorySlice = {
40
40
  commandSchema: commandSchema,
41
41
  errorSchema: errorSchema,
42
42
  eventSchema: eventSchema,
43
- commandAuthorization: commandAuthorization,
43
+ authorizationOf: authorizationOf,
44
44
  commandTransition: commandTransition,
45
45
  traits: traits,
46
46
  readConsistency: "EscalateOnRetry"
@@ -173,7 +173,7 @@ let eventSchema$1 = Sury.$schema(s => ({
173
173
  id: s.m(Sury.string)
174
174
  }));
175
175
 
176
- function commandAuthorization$1(param) {
176
+ function authorizationOf$1(param) {
177
177
  return "AllowAuthenticated";
178
178
  }
179
179
 
@@ -189,7 +189,7 @@ let MissingTagSlice = {
189
189
  commandSchema: commandSchema$1,
190
190
  errorSchema: errorSchema$1,
191
191
  eventSchema: eventSchema$1,
192
- commandAuthorization: commandAuthorization$1,
192
+ authorizationOf: authorizationOf$1,
193
193
  commandTransition: commandTransition$1,
194
194
  traits: traits$1,
195
195
  readConsistency: "EscalateOnRetry"
@@ -288,7 +288,7 @@ let eventSchema$2 = Sury.$schema(s => ({
288
288
  carrierId: s.m(DcbTag$Reventless.string)
289
289
  }));
290
290
 
291
- function commandAuthorization$2(param) {
291
+ function authorizationOf$2(param) {
292
292
  return "AllowAuthenticated";
293
293
  }
294
294
 
@@ -304,7 +304,7 @@ let ShipOrderSlice = {
304
304
  commandSchema: commandSchema$2,
305
305
  errorSchema: errorSchema$2,
306
306
  eventSchema: eventSchema$2,
307
- commandAuthorization: commandAuthorization$2,
307
+ authorizationOf: authorizationOf$2,
308
308
  commandTransition: commandTransition$2,
309
309
  traits: traits$2,
310
310
  readConsistency: "EscalateOnRetry"