@reventlessdev/reventless-aws 3.0.0-alpha.263 → 3.0.0-alpha.265

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 (26) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.json +7 -7
  3. package/src/Platform.res +37 -6
  4. package/src/Platform.res.mjs +21 -6
  5. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +6 -1
  6. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res.mjs +4 -1
  7. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +5 -0
  8. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res.mjs +3 -0
  9. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +6 -1
  10. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res.mjs +4 -1
  11. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +6 -1
  12. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res.mjs +4 -1
  13. package/src/adapter/CommandTopic/CommandTopicRegistry.res +50 -0
  14. package/src/adapter/CommandTopic/CommandTopicRegistry.res.mjs +26 -0
  15. package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +21 -3
  16. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +230 -29
  17. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +124 -9
  18. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +188 -3
  19. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +107 -6
  20. package/src/components/AutomationSlice_Builder.res.mjs +1 -1
  21. package/src/components/OutboundTranslationSlice_Builder.res +20 -0
  22. package/src/components/OutboundTranslationSlice_Builder.res.mjs +12 -2
  23. package/src/plugin/runtime/PluginRuntime_Builder.res +26 -0
  24. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +26 -0
  25. package/tests/AutomationSliceEntryPoint_OpsTest.res +44 -3
  26. package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +65 -1
@@ -112,6 +112,7 @@ describe("AutomationSliceEntryPoint_Ops.makeAutomationJsonEventsHandler", () =>
112
112
  ~callback,
113
113
  ~publishJsons=noopPublish,
114
114
  ~syncTodoItems=async () => steps->Array.push("sync"),
115
+ ~loadTodoItems=async () => steps->Array.push("restore"),
115
116
  )
116
117
  let envelope = obj([("meta", obj([("service", str("Order"))])), ("event", str("Placed"))])
117
118
  await Stream.fromIterable([envelope, str("bare")])->handler->Effect.runPromise
@@ -120,7 +121,43 @@ describe("AutomationSliceEntryPoint_Ops.makeAutomationJsonEventsHandler", () =>
120
121
  expect(receivedCtx.contents->Option.map(c => c.Reventless.AutomationSlice.sliceName))->toEqual(
121
122
  Some("S"),
122
123
  )
123
- expect(steps)->toEqual(["phase1", "sync", "phase2", "sync"])
124
+ // `restore` first: rehydrating the TODO list after phase 1 would let a stored
125
+ // row overwrite one this batch just collected, and after phase 2 would leave
126
+ // the reloaded backlog unprocessed until another invocation.
127
+ expect(steps)->toEqual(["restore", "phase1", "sync", "phase2", "sync"])
128
+ })
129
+ })
130
+
131
+ describe("AutomationSliceEntryPoint_Ops.runSweeps", () => {
132
+ let dummyRegistered: StreamRoutedEntryPoint_Ops.registeredHandler = {
133
+ handler: (_event, _context) => Effect.succeed(),
134
+ }
135
+ let sliceThat = (~comp, ~run): AutomationSliceEntryPoint_Ops.builtSlice => {
136
+ registered: dummyRegistered,
137
+ sweep: run,
138
+ comp,
139
+ }
140
+
141
+ test("sweeps every slice", async () => {
142
+ let swept = []
143
+ await AutomationSliceEntryPoint_Ops.runSweeps([
144
+ sliceThat(~comp="A", ~run=async () => swept->Array.push("a")),
145
+ sliceThat(~comp="B", ~run=async () => swept->Array.push("b")),
146
+ ])
147
+ expect(swept)->toEqual(["a", "b"])
148
+ })
149
+
150
+ // A sweep exists to recover from a failing external call, so one slice whose
151
+ // geocoder is still down must not cost every other slice on the Lambda its
152
+ // turn — that would be a worse version of the problem being fixed.
153
+ test("a throwing slice does not stop the others", async () => {
154
+ let swept = []
155
+ await AutomationSliceEntryPoint_Ops.runSweeps([
156
+ sliceThat(~comp="A", ~run=async () => swept->Array.push("a")),
157
+ sliceThat(~comp="Boom", ~run=async () => JsError.throwWithMessage("gateway down")),
158
+ sliceThat(~comp="C", ~run=async () => swept->Array.push("c")),
159
+ ])
160
+ expect(swept)->toEqual(["a", "c"])
124
161
  })
125
162
  })
126
163
 
@@ -142,13 +179,14 @@ describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler", () => {
142
179
  received := events
143
180
  steps->Array.push("phase1")
144
181
  },
145
- phase2: async _publish => steps->Array.push("phase2"),
182
+ phase2: async (_publish, ~capabilities as _) => steps->Array.push("phase2"),
146
183
  }
147
184
  let handler = AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler(
148
185
  ~consumedEventSchema=outboundEventSchema,
149
186
  ~callback,
150
187
  ~publishJsons=noopPublish,
151
188
  ~syncTodoItems=async () => steps->Array.push("sync"),
189
+ ~loadTodoItems=async () => steps->Array.push("restore"),
152
190
  )
153
191
  // `id` is the envelope's subject — the entity the event was published for.
154
192
  // An Aggregate's event payload does not repeat it, so this is the only place
@@ -170,6 +208,9 @@ describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler", () => {
170
208
  ("ord-1", OrderPlaced({orderId: "ord-1"})),
171
209
  ("", OrderArchived),
172
210
  ])
173
- expect(steps)->toEqual(["phase1", "sync", "phase2", "sync"])
211
+ // `restore` first: rehydrating the TODO list after phase 1 would let a stored
212
+ // row overwrite one this batch just collected, and after phase 2 would leave
213
+ // the reloaded backlog unprocessed until another invocation.
214
+ expect(steps)->toEqual(["restore", "phase1", "sync", "phase2", "sync"])
174
215
  })
175
216
  })
@@ -153,6 +153,8 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeAutomationJsonEventsHandl
153
153
  sliceName: "S"
154
154
  }, callback, noopPublish, async () => {
155
155
  steps.push("sync");
156
+ }, async () => {
157
+ steps.push("restore");
156
158
  });
157
159
  let envelope = Object.fromEntries([
158
160
  [
@@ -177,6 +179,7 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeAutomationJsonEventsHandl
177
179
  ]);
178
180
  globalThis.expect(Stdlib_Option.map(receivedCtx.contents, c => c.sliceName)).toEqual("S");
179
181
  globalThis.expect(steps).toEqual([
182
+ "restore",
180
183
  "phase1",
181
184
  "sync",
182
185
  "phase2",
@@ -185,6 +188,64 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeAutomationJsonEventsHandl
185
188
  });
186
189
  });
187
190
 
191
+ globalThis.describe("AutomationSliceEntryPoint_Ops.runSweeps", () => {
192
+ let dummyRegistered_handler = (_event, _context) => Effect.succeed();
193
+ let dummyRegistered = {
194
+ handler: dummyRegistered_handler
195
+ };
196
+ globalThis.test("sweeps every slice", async () => {
197
+ let swept = [];
198
+ await AutomationSliceEntryPoint_Ops$ReventlessAws.runSweeps([
199
+ {
200
+ registered: dummyRegistered,
201
+ sweep: async () => {
202
+ swept.push("a");
203
+ },
204
+ comp: "A"
205
+ },
206
+ {
207
+ registered: dummyRegistered,
208
+ sweep: async () => {
209
+ swept.push("b");
210
+ },
211
+ comp: "B"
212
+ }
213
+ ]);
214
+ globalThis.expect(swept).toEqual([
215
+ "a",
216
+ "b"
217
+ ]);
218
+ });
219
+ globalThis.test("a throwing slice does not stop the others", async () => {
220
+ let swept = [];
221
+ await AutomationSliceEntryPoint_Ops$ReventlessAws.runSweeps([
222
+ {
223
+ registered: dummyRegistered,
224
+ sweep: async () => {
225
+ swept.push("a");
226
+ },
227
+ comp: "A"
228
+ },
229
+ {
230
+ registered: dummyRegistered,
231
+ sweep: async () => Stdlib_JsError.throwWithMessage("gateway down"),
232
+ comp: "Boom"
233
+ },
234
+ {
235
+ registered: dummyRegistered,
236
+ sweep: async () => {
237
+ swept.push("c");
238
+ },
239
+ comp: "C"
240
+ }
241
+ ]);
242
+ globalThis.expect(swept).toEqual([
243
+ "a",
244
+ "c"
245
+ ]);
246
+ });
247
+ });
248
+
188
249
  let outboundEventSchema = S.union([
189
250
  S.schema(s => ({
190
251
  TAG: "OrderPlaced",
@@ -204,7 +265,7 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler
204
265
  received.contents = events;
205
266
  steps.push("phase1");
206
267
  };
207
- let callback_phase2 = async _publish => {
268
+ let callback_phase2 = async (_publish, param) => {
208
269
  steps.push("phase2");
209
270
  };
210
271
  let callback = {
@@ -214,6 +275,8 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler
214
275
  };
215
276
  let handler = AutomationSliceEntryPoint_Ops$ReventlessAws.makeOutboundJsonEventsHandler(outboundEventSchema, callback, noopPublish, async () => {
216
277
  steps.push("sync");
278
+ }, async () => {
279
+ steps.push("restore");
217
280
  });
218
281
  let placed = Object.fromEntries([
219
282
  [
@@ -273,6 +336,7 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler
273
336
  ]
274
337
  ]);
275
338
  globalThis.expect(steps).toEqual([
339
+ "restore",
276
340
  "phase1",
277
341
  "sync",
278
342
  "phase2",