@reventlessdev/reventless-aws 3.0.0-alpha.418 → 3.0.0-alpha.419

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.419 (2026-11-01)
7
+
8
+ ### Features
9
+
10
+ * **core:** a command's outcome, the flow through automations, and each view change are told ([dcaeed2](https://github.com/ReventlessDev/reventless-core/commit/dcaeed2fabe2047a21797b459f2931618474dec3))
11
+
12
+
6
13
  # 3.0.0-alpha.418 (2026-11-01)
7
14
 
8
15
  **Note:** Version bump only for package @reventlessdev/reventless-aws
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-aws",
3
- "version": "3.0.0-alpha.418",
3
+ "version": "3.0.0-alpha.419",
4
4
  "description": "AWS adapters for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -22,19 +22,19 @@
22
22
  "sury": "11.0.0",
23
23
  "uuid": "^13.0.0",
24
24
  "yaml": "^2.8.3",
25
- "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.37",
25
+ "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.38",
26
26
  "@reventlessdev/rescript-effect": "1.0.0-alpha.1",
27
27
  "@reventlessdev/rescript-jest": "1.0.0-alpha.13",
28
- "@reventlessdev/rescript-node": "2.0.0-alpha.24",
29
- "@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.37",
28
+ "@reventlessdev/rescript-node": "2.0.0-alpha.25",
29
+ "@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.38",
30
30
  "@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
31
+ "@reventlessdev/rescript-web": "1.0.0-alpha.8",
31
32
  "@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
32
- "@reventlessdev/reventless-core": "3.0.0-alpha.325",
33
- "@reventlessdev/reventless-infra": "3.0.0-alpha.220",
34
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.189",
33
+ "@reventlessdev/reventless-core": "3.0.0-alpha.326",
35
34
  "@reventlessdev/reventless-interop": "3.0.0-alpha.42",
36
- "@reventlessdev/rescript-web": "1.0.0-alpha.8",
37
- "@reventlessdev/reventless-spec": "3.0.0-alpha.191"
35
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.190",
36
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.221",
37
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.192"
38
38
  },
39
39
  "devDependencies": {
40
40
  "rescript": "12.3.1",
@@ -539,7 +539,7 @@ let makeOutboundJsonEventsHandler = (
539
539
  ->Option.getOr("")
540
540
  let (eventType, dataDict) = rawEvent->ReventlessCore.Message.splitMessage
541
541
  switch decoder.decode(~eventType, ~data=dataDict) {
542
- | Some(event) => [(sourceId, event)]
542
+ | Some(event) => [(sourceId, event, ReventlessCore.Message.metaOfEnvelope(envelope))]
543
543
  | None => []
544
544
  }
545
545
  })
@@ -549,7 +549,11 @@ let makeOutboundJsonEventsHandler = (
549
549
  ->Effect.flatMap(events =>
550
550
  Effect.promise(async () => {
551
551
  await loadTodoItems()
552
- await callback.phase1(events, ~capabilities=capabilities())
552
+ await callback.phase1(
553
+ events->Array.map(((sourceId, event, _)) => (sourceId, event)),
554
+ ~metas=events->Array.map(((_, _, meta)) => meta),
555
+ ~capabilities=capabilities(),
556
+ )
553
557
  await syncTodoItems()
554
558
  await callback.phase2(publishJsons, ~capabilities=capabilities())
555
559
  await syncTodoItems()
@@ -323,14 +323,18 @@ function makeOutboundJsonEventsHandler(consumedEventSchema, callback, publishJso
323
323
  if (event !== undefined) {
324
324
  return [[
325
325
  sourceId,
326
- Primitive_option.valFromOption(event)
326
+ Primitive_option.valFromOption(event),
327
+ Message$ReventlessCore.metaOfEnvelope(envelope)
327
328
  ]];
328
329
  } else {
329
330
  return [];
330
331
  }
331
332
  })), events => Stream$1.fromIterable(events))), events => Effect.promise(async () => {
332
333
  await loadTodoItems();
333
- await callback.phase1(events, capabilities());
334
+ await callback.phase1(events.map(param => [
335
+ param[0],
336
+ param[1]
337
+ ]), events.map(param => param[2]), capabilities());
334
338
  await syncTodoItems();
335
339
  await callback.phase2(publishJsons, capabilities());
336
340
  return await syncTodoItems();
@@ -126,6 +126,20 @@ let decodeEnvelope = (json: JSON.t): envelope<'event> => {
126
126
 
127
127
  let exnMessage = StreamRoutedEntryPoint_Ops.exnMessage
128
128
 
129
+ // The event an envelope carries, as the source of the rows its actions change.
130
+ // Read off the JSON, like `producerTime`: an envelope without a meta yields none.
131
+ let sourcesOf = (json: JSON.t): array<ReventlessCore.Projection.changeSource> => {
132
+ let fields = json->JSON.Decode.object->Option.getOr(Dict.make())
133
+ let meta = fields->Dict.get("meta")->Option.flatMap(JSON.Decode.object)
134
+ let string = (d, k) => d->Option.flatMap(d => d->Dict.get(k))->Option.flatMap(JSON.Decode.string)
135
+ switch string(meta, "msgId") {
136
+ | Some(msgId) =>
137
+ let (entityId, entityType) = ReventlessCore.ViewChange.entityOfEnvelope(fields)
138
+ [{msgId, correlationId: ?string(meta, "correlationId"), ?entityId, ?entityType}]
139
+ | None => []
140
+ }
141
+ }
142
+
129
143
  // The typed core of buildJsonEventsHandler: decode each envelope, parse the
130
144
  // event against the slice's consumed-event schema, project, and run every
131
145
  // resulting action against the view table. A decode failure logs and yields no
@@ -140,7 +154,13 @@ let makeJsonEventsHandler = (
140
154
  ~queryDbOps: ReventlessCore.QueryDb_Adapter.operations,
141
155
  ~subIdConfig: option<Reventless.ReadModel.subIdConfig<JSON.t>>,
142
156
  ~stateSchema: option<S.t<unknown>>,
143
- ): ReventlessCore.EventCollector.jsonEventsHandler =>
157
+ ): ReventlessCore.EventCollector.jsonEventsHandler => {
158
+ // Each row the events change is logged; the states are already JSON.
159
+ let onChange = ReventlessCore.ViewChange.reporter(
160
+ ~comp=sliceName,
161
+ ~view=sliceName,
162
+ ~stateToJson=state => state,
163
+ )
144
164
  stream =>
145
165
  stream
146
166
  ->Stream.mapEffect(json =>
@@ -155,11 +175,14 @@ let makeJsonEventsHandler = (
155
175
  // The deployed slice assembles JSON-level operations rather than going
156
176
  // through the typed rewrite, so the trail is appended here — with this
157
177
  // envelope's own time, which the apply below no longer has.
158
- producerTime === ""
159
- ? actions
160
- : actions->Array.map(
161
- ReventlessCore.Projection.rewriteJsonAction(_, ~at=producerTime, ~stateSchema),
162
- )
178
+ let sources = sourcesOf(json)
179
+ let actions =
180
+ producerTime === ""
181
+ ? actions
182
+ : actions->Array.map(
183
+ ReventlessCore.Projection.rewriteJsonAction(_, ~at=producerTime, ~stateSchema),
184
+ )
185
+ actions->Array.map(action => (action, sources))
163
186
  } catch {
164
187
  | exn =>
165
188
  StreamRoutedEntryPoint_Ops.logError(
@@ -171,7 +194,7 @@ let makeJsonEventsHandler = (
171
194
  )
172
195
  )
173
196
  ->Stream.flatMap(actions => Stream.fromIterable(actions))
174
- ->Stream.runForEach(action =>
197
+ ->Stream.runForEach(((action, sources)) =>
175
198
  // Thread the slice's `subIdConfig` (generated from `@subId`) so
176
199
  // sub-id-dependent actions like `UpdateMultiState` can resolve the sort
177
200
  // key. Dropping it here made every such action hit the
@@ -181,9 +204,17 @@ let makeJsonEventsHandler = (
181
204
  // actions. `~comp` is the slice's spec name — attribution for
182
205
  // Projection.handleAction's debug-lazy action log.
183
206
  Effect.promise(() =>
184
- ReventlessCore.Projection.handleAction(~comp=sliceName, action, queryDbOps, subIdConfig)
207
+ ReventlessCore.Projection.handleAction(
208
+ ~comp=sliceName,
209
+ ~sources,
210
+ ~onChange,
211
+ action,
212
+ queryDbOps,
213
+ subIdConfig,
214
+ )
185
215
  )->Effect.map(_ => ())
186
216
  )
217
+ }
187
218
 
188
219
  // ── Handler assembly (called by the shell per HANDLER_CONFIG entry) ─────────
189
220
  // `sliceModules` types the shell's reads off the two dynamically imported
@@ -8,6 +8,7 @@ import * as Stream from "effect/Stream";
8
8
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
9
9
  import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
10
10
  import * as Projection$ReventlessCore from "@reventlessdev/reventless-core/src/Projection.res.mjs";
11
+ import * as ViewChange$ReventlessCore from "@reventlessdev/reventless-core/src/ViewChange.res.mjs";
11
12
  import * as ProjectionEntryPoint_Ops$ReventlessAws from "./ProjectionEntryPoint_Ops.res.mjs";
12
13
  import * as StreamRoutedEntryPoint_Ops$ReventlessAws from "./StreamRoutedEntryPoint_Ops.res.mjs";
13
14
 
@@ -64,7 +65,25 @@ function decodeEnvelope(json) {
64
65
  };
65
66
  }
66
67
 
68
+ function sourcesOf(json) {
69
+ let fields = Stdlib_Option.getOr(Stdlib_JSON.Decode.object(json), {});
70
+ let meta = Stdlib_Option.flatMap(fields["meta"], Stdlib_JSON.Decode.object);
71
+ let string = (d, k) => Stdlib_Option.flatMap(Stdlib_Option.flatMap(d, d => d[k]), Stdlib_JSON.Decode.string);
72
+ let msgId = string(meta, "msgId");
73
+ if (msgId === undefined) {
74
+ return [];
75
+ }
76
+ let match = ViewChange$ReventlessCore.entityOfEnvelope(fields);
77
+ return [{
78
+ msgId: msgId,
79
+ correlationId: string(meta, "correlationId"),
80
+ entityId: match[0],
81
+ entityType: match[1]
82
+ }];
83
+ }
84
+
67
85
  function makeJsonEventsHandler(sliceName, eventSchema, project, queryDbOps, subIdConfig, stateSchema) {
86
+ let onChange = ViewChange$ReventlessCore.reporter(sliceName, sliceName, state => state);
68
87
  return stream => Stream.runForEach(Stream.flatMap(Stream.mapEffect(stream, json => Effect.sync(() => {
69
88
  try {
70
89
  let match = decodeEnvelope(json);
@@ -74,11 +93,12 @@ function makeJsonEventsHandler(sliceName, eventSchema, project, queryDbOps, subI
74
93
  meta: match.meta,
75
94
  recordedAt: match.recordedAt
76
95
  });
77
- if (producerTime === "") {
78
- return actions;
79
- } else {
80
- return actions.map(__x => Projection$ReventlessCore.rewriteJsonAction(__x, producerTime, stateSchema));
81
- }
96
+ let sources = sourcesOf(json);
97
+ let actions$1 = producerTime === "" ? actions : actions.map(__x => Projection$ReventlessCore.rewriteJsonAction(__x, producerTime, stateSchema));
98
+ return actions$1.map(action => [
99
+ action,
100
+ sources
101
+ ]);
82
102
  } catch (raw_exn) {
83
103
  let exn = Primitive_exceptions.internalToException(raw_exn);
84
104
  StreamRoutedEntryPoint_Ops$ReventlessAws.logError("failed to decode event", {
@@ -87,7 +107,11 @@ function makeJsonEventsHandler(sliceName, eventSchema, project, queryDbOps, subI
87
107
  });
88
108
  return [];
89
109
  }
90
- })), actions => Stream.fromIterable(actions)), action => Effect.map(Effect.promise(() => Projection$ReventlessCore.handleAction(sliceName, action, queryDbOps, subIdConfig)), param => {}));
110
+ })), actions => Stream.fromIterable(actions)), param => {
111
+ let sources = param[1];
112
+ let action = param[0];
113
+ return Effect.map(Effect.promise(() => Projection$ReventlessCore.handleAction(sliceName, sources, onChange, action, queryDbOps, subIdConfig)), param => {});
114
+ });
91
115
  }
92
116
 
93
117
  function makeRegisteredHandler(entry, modules) {
@@ -106,6 +130,7 @@ export {
106
130
  parseHandlerConfig,
107
131
  decodeEnvelope,
108
132
  exnMessage,
133
+ sourcesOf,
109
134
  makeJsonEventsHandler,
110
135
  makeRegisteredHandler,
111
136
  }
@@ -388,7 +388,7 @@ describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler", () => {
388
388
  let received = ref([])
389
389
  let callback: AutomationSliceEntryPoint_Ops.outboundCallback<outboundEvent> = {
390
390
  todoItems: Dict.make(),
391
- phase1: async (events, ~capabilities as _) => {
391
+ phase1: async (events, ~metas as _=?, ~capabilities as _) => {
392
392
  received := events
393
393
  steps->Array.push("phase1")
394
394
  },
@@ -581,7 +581,7 @@ globalThis.describe("AutomationSliceEntryPoint_Ops.makeOutboundJsonEventsHandler
581
581
  contents: []
582
582
  };
583
583
  let callback_todoItems = {};
584
- let callback_phase1 = async (events, param) => {
584
+ let callback_phase1 = async (events, param, param$1) => {
585
585
  received.contents = events;
586
586
  steps.push("phase1");
587
587
  };