@reventlessdev/reventless-local 3.0.0-alpha.196 → 3.0.0-alpha.198

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,24 @@
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.198 (2026-08-04)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **core:** tag a slice's published command with its target, not itself ([bb2b063](https://github.com/ReventlessDev/reventless-core/commit/bb2b063f914e45fb8efcba28e0b691713cf93d8a))
11
+ ### Features
12
+
13
+ * **outbound:** hand translate its geocoder instead of making it fetch one ([fb18312](https://github.com/ReventlessDev/reventless-core/commit/fb1831216b37c9562868c46e1a09054e69418c67))
14
+
15
+
16
+ # 3.0.0-alpha.197 (2026-08-03)
17
+
18
+ **Note:** Version bump only for package @reventlessdev/reventless-local
19
+
20
+
21
+
22
+
23
+
6
24
  # 3.0.0-alpha.196 (2026-08-03)
7
25
 
8
26
  **Note:** Version bump only for package @reventlessdev/reventless-local
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-local",
3
- "version": "3.0.0-alpha.196",
3
+ "version": "3.0.0-alpha.198",
4
4
  "description": "Local platform for Reventless (in-memory or SQLite backend, for development and testing without AWS)",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -34,18 +34,18 @@
34
34
  "graphql-yoga": "^5.21.0",
35
35
  "sury": "11.0.0-alpha.4",
36
36
  "ws": "^8.18.0",
37
- "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
38
37
  "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.26",
39
- "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
40
- "@reventlessdev/rescript-node": "2.0.0-alpha.1",
38
+ "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
41
39
  "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
40
+ "@reventlessdev/rescript-node": "2.0.0-alpha.1",
41
+ "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
42
42
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
43
- "@reventlessdev/reventless-core": "3.0.0-alpha.208",
44
- "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.56",
45
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.155",
46
- "@reventlessdev/reventless-infra": "3.0.0-alpha.124",
47
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.72",
48
- "@reventlessdev/reventless-spec": "3.0.0-alpha.99"
43
+ "@reventlessdev/reventless-core": "3.0.0-alpha.210",
44
+ "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.58",
45
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.157",
46
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.125",
47
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.100",
48
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.74"
49
49
  },
50
50
  "devDependencies": {
51
51
  "rescript": "12.3.0",
@@ -0,0 +1,13 @@
1
+ // What the local platform hands a slice's `translate`.
2
+ //
3
+ // Nothing, today — and that is the honest answer rather than a placeholder. The
4
+ // local platform provisions no geocoder (a deployed stack's place index is an
5
+ // account and a bill), so `Capabilities.none` reports `Unavailable`, which
6
+ // `translate` maps to a retryable `Error` and the sweep surfaces. A dev running
7
+ // a geocoding slice sees its items stay queued, which is true, instead of seeing
8
+ // them written off as unresolvable addresses, which would not be.
9
+ //
10
+ // This is the one place to change when local grows a real one — a fixture, a
11
+ // stub keyed by address, or Nominatim. Slices reach it through the injected
12
+ // record, so nothing in a plugin moves on that day.
13
+ let capabilities = () => Reventless.Capabilities.none
@@ -0,0 +1,12 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
4
+
5
+ function capabilities() {
6
+ return Capabilities$Reventless.none;
7
+ }
8
+
9
+ export {
10
+ capabilities,
11
+ }
12
+ /* No side effect */
@@ -24,6 +24,7 @@ module Make = (Bus: LocalBus.T) => {
24
24
  EventCollectorChannel,
25
25
  EventCollectorRuntimeBuilder,
26
26
  Api,
27
+ LocalCapabilities,
27
28
  )
28
29
 
29
30
  module Make = (
@@ -1,6 +1,7 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Component$ReventlessCore from "@reventlessdev/reventless-core/src/components/Component.res.mjs";
4
+ import * as LocalCapabilities$ReventlessLocal from "../adapter/LocalCapabilities.res.mjs";
4
5
  import * as LocalQueryDbStorage$ReventlessLocal from "../adapter/QueryDb/LocalQueryDbStorage.res.mjs";
5
6
  import * as LocalRuntimeEnvironment$ReventlessLocal from "../adapter/Runtime/LocalRuntimeEnvironment.res.mjs";
6
7
  import * as QueryDbResolvers_GraphQL$ReventlessLocal from "../adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs";
@@ -32,7 +33,7 @@ function Make(Bus) {
32
33
  make: QueryDbStorage.make
33
34
  })({
34
35
  make: QueryDbResolvers.make
35
- })(EventCollectorChannel)(EventCollectorRuntimeBuilder)(Api);
36
+ })(EventCollectorChannel)(EventCollectorRuntimeBuilder)(Api)(LocalCapabilities$ReventlessLocal);
36
37
  let Make$1 = Spec => (Translation => {
37
38
  let Inner = CoreMaker.Make(Spec)(Translation);
38
39
  return {
@@ -70,7 +70,7 @@ describe("OutboundTranslationSlice Callback", () => {
70
70
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
71
71
  publishedCommands := cmds
72
72
  }
73
- await FireForgetCallback.phase2(mockPublish)
73
+ await FireForgetCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
74
74
  expect(publishedCommands.contents->Array.length)->toBe(0)
75
75
  let row = FireForgetCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
76
76
  expect(row.status)->toBe(Completed)
@@ -81,7 +81,7 @@ describe("OutboundTranslationSlice Callback", () => {
81
81
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
82
82
  publishedCommands := cmds
83
83
  }
84
- await FireForgetCallback.phase2(mockPublish)
84
+ await FireForgetCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
85
85
  expect(publishedCommands.contents->Array.length)->toBe(0)
86
86
  })
87
87
  })
@@ -93,7 +93,7 @@ describe("OutboundTranslationSlice Callback", () => {
93
93
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
94
94
  publishedCommands := Array.concat(publishedCommands.contents, cmds)
95
95
  }
96
- await CommandBackCallback.phase2(mockPublish)
96
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
97
97
  expect(publishedCommands.contents->Array.length)->toBe(1)
98
98
  let cmd = publishedCommands.contents->Array.getUnsafe(0)
99
99
  expect(cmd.id)->toBe("ord-1")
@@ -101,12 +101,28 @@ describe("OutboundTranslationSlice Callback", () => {
101
101
  expect(row.status)->toBe(Completed)
102
102
  })
103
103
 
104
+ // The published command's `meta.service` must name the TARGET, not this
105
+ // slice. An aggregate derives its event's meta from the command's, and
106
+ // ReadModel/AutomationSlice callbacks dispatch mappings on `meta.service` —
107
+ // so a slice that stamps its own name here makes the target's events match
108
+ // no mapping and project as zero actions, with no error anywhere.
109
+ testPromise("published command is tagged with the target's name", async () => {
110
+ CommandBackCallback.phase1([("evt", PaymentReceived({orderId: "ord-1", amount: 50.0}))])
111
+ let publishedCommands = ref([])
112
+ let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
113
+ publishedCommands := Array.concat(publishedCommands.contents, cmds)
114
+ }
115
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
116
+ let cmd = publishedCommands.contents->Array.getUnsafe(0)
117
+ expect(cmd.meta.service)->toBe("ConfirmPayment")
118
+ })
119
+
104
120
  testPromise("Error marks item as Failed with incremented retryCount", async () => {
105
121
  ProcessPaymentSpec.translateFn := (async (_id, _item) => Error("gateway timeout"))
106
122
 
107
123
  CommandBackCallback.phase1([("evt", PaymentReceived({orderId: "ord-1", amount: 50.0}))])
108
124
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
109
- await CommandBackCallback.phase2(mockPublish)
125
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
110
126
 
111
127
  let row = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
112
128
  expect(row.status)->toBe(Failed)
@@ -118,7 +134,7 @@ describe("OutboundTranslationSlice Callback", () => {
118
134
  ProcessPaymentSpec.translateFn := (async (_id, _item) => Error("timeout"))
119
135
  CommandBackCallback.phase1([("evt", PaymentReceived({orderId: "ord-1", amount: 50.0}))])
120
136
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
121
- await CommandBackCallback.phase2(mockPublish)
137
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
122
138
  let row1 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
123
139
  expect(row1.retryCount)->toBe(1)
124
140
 
@@ -129,7 +145,7 @@ describe("OutboundTranslationSlice Callback", () => {
129
145
  let successPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
130
146
  publishedCommands := cmds
131
147
  }
132
- await CommandBackCallback.phase2(successPublish)
148
+ await CommandBackCallback.phase2(successPublish, ~capabilities=Reventless.Capabilities.none)
133
149
  expect(publishedCommands.contents->Array.length)->toBe(1)
134
150
  let row2 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
135
151
  expect(row2.status)->toBe(Completed)
@@ -142,8 +158,8 @@ describe("OutboundTranslationSlice Callback", () => {
142
158
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
143
159
 
144
160
  // Fail twice
145
- await CommandBackCallback.phase2(mockPublish)
146
- await CommandBackCallback.phase2(mockPublish)
161
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
162
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
147
163
  let row = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
148
164
  expect(row.retryCount)->toBe(2)
149
165
 
@@ -152,7 +168,7 @@ describe("OutboundTranslationSlice Callback", () => {
152
168
  let trackPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
153
169
  publishedCommands := cmds
154
170
  }
155
- await CommandBackCallback.phase2(trackPublish)
171
+ await CommandBackCallback.phase2(trackPublish, ~capabilities=Reventless.Capabilities.none)
156
172
  expect(publishedCommands.contents->Array.length)->toBe(0)
157
173
  let row2 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
158
174
  // retryCount should still be 2 — not retried
@@ -178,7 +194,7 @@ describe("OutboundTranslationSlice Callback", () => {
178
194
  let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
179
195
  publishedCommands := Array.concat(publishedCommands.contents, cmds)
180
196
  }
181
- await CommandBackCallback.phase2(mockPublish)
197
+ await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
182
198
 
183
199
  // ord-1 should be Failed, ord-2 should be Completed
184
200
  let row1 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
4
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
5
6
  import * as OutboundTranslationSliceFixtures$ReventlessLocal from "./OutboundTranslationSliceFixtures.res.mjs";
6
7
  import * as OutboundTranslationSlice_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
7
8
 
@@ -145,7 +146,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
145
146
  let mockPublish = async cmds => {
146
147
  publishedCommands.contents = cmds;
147
148
  };
148
- await FireForgetCallback.phase2(mockPublish);
149
+ await FireForgetCallback.phase2(mockPublish, Capabilities$Reventless.none);
149
150
  globalThis.expect(publishedCommands.contents.length).toBe(0);
150
151
  let row = Stdlib_Option.getOrThrow(FireForgetCallback.todoItems["ord-1"], undefined);
151
152
  globalThis.expect(row.status).toBe("Completed");
@@ -157,7 +158,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
157
158
  let mockPublish = async cmds => {
158
159
  publishedCommands.contents = cmds;
159
160
  };
160
- await FireForgetCallback.phase2(mockPublish);
161
+ await FireForgetCallback.phase2(mockPublish, Capabilities$Reventless.none);
161
162
  globalThis.expect(publishedCommands.contents.length).toBe(0);
162
163
  });
163
164
  });
@@ -177,13 +178,32 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
177
178
  let mockPublish = async cmds => {
178
179
  publishedCommands.contents = publishedCommands.contents.concat(cmds);
179
180
  };
180
- await CommandBackCallback.phase2(mockPublish);
181
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
181
182
  globalThis.expect(publishedCommands.contents.length).toBe(1);
182
183
  let cmd = publishedCommands.contents[0];
183
184
  globalThis.expect(cmd.id).toBe("ord-1");
184
185
  let row = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
185
186
  globalThis.expect(row.status).toBe("Completed");
186
187
  });
188
+ globalThis.test("published command is tagged with the target's name", async () => {
189
+ CommandBackCallback.phase1([[
190
+ "evt",
191
+ {
192
+ TAG: "PaymentReceived",
193
+ orderId: "ord-1",
194
+ amount: 50.0
195
+ }
196
+ ]]);
197
+ let publishedCommands = {
198
+ contents: []
199
+ };
200
+ let mockPublish = async cmds => {
201
+ publishedCommands.contents = publishedCommands.contents.concat(cmds);
202
+ };
203
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
204
+ let cmd = publishedCommands.contents[0];
205
+ globalThis.expect(cmd.meta.service).toBe("ConfirmPayment");
206
+ });
187
207
  globalThis.test("Error marks item as Failed with incremented retryCount", async () => {
188
208
  OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.translateFn.contents = async (_id, _item) => ({
189
209
  TAG: "Error",
@@ -198,7 +218,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
198
218
  }
199
219
  ]]);
200
220
  let mockPublish = async _cmds => {};
201
- await CommandBackCallback.phase2(mockPublish);
221
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
202
222
  let row = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
203
223
  globalThis.expect(row.status).toBe("Failed");
204
224
  globalThis.expect(row.retryCount).toBe(1);
@@ -217,7 +237,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
217
237
  }
218
238
  ]]);
219
239
  let mockPublish = async _cmds => {};
220
- await CommandBackCallback.phase2(mockPublish);
240
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
221
241
  let row1 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
222
242
  globalThis.expect(row1.retryCount).toBe(1);
223
243
  OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.translateFn.contents = async (id, _item) => ({
@@ -236,7 +256,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
236
256
  let successPublish = async cmds => {
237
257
  publishedCommands.contents = cmds;
238
258
  };
239
- await CommandBackCallback.phase2(successPublish);
259
+ await CommandBackCallback.phase2(successPublish, Capabilities$Reventless.none);
240
260
  globalThis.expect(publishedCommands.contents.length).toBe(1);
241
261
  let row2 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
242
262
  globalThis.expect(row2.status).toBe("Completed");
@@ -255,8 +275,8 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
255
275
  }
256
276
  ]]);
257
277
  let mockPublish = async _cmds => {};
258
- await CommandBackCallback.phase2(mockPublish);
259
- await CommandBackCallback.phase2(mockPublish);
278
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
279
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
260
280
  let row = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
261
281
  globalThis.expect(row.retryCount).toBe(2);
262
282
  let publishedCommands = {
@@ -265,7 +285,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
265
285
  let trackPublish = async cmds => {
266
286
  publishedCommands.contents = cmds;
267
287
  };
268
- await CommandBackCallback.phase2(trackPublish);
288
+ await CommandBackCallback.phase2(trackPublish, Capabilities$Reventless.none);
269
289
  globalThis.expect(publishedCommands.contents.length).toBe(0);
270
290
  let row2 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
271
291
  globalThis.expect(row2.retryCount).toBe(2);
@@ -318,7 +338,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
318
338
  let mockPublish = async cmds => {
319
339
  publishedCommands.contents = publishedCommands.contents.concat(cmds);
320
340
  };
321
- await CommandBackCallback.phase2(mockPublish);
341
+ await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
322
342
  let row1 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
323
343
  globalThis.expect(row1.status).toBe("Failed");
324
344
  let row2 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-2"], undefined);
@@ -35,7 +35,7 @@ module SendTrackingEmailSpec = {
35
35
  | OrderShipped({orderId, email}) => [(orderId, {orderId, email})]
36
36
  }
37
37
 
38
- let translate = async (_id, _item) => Ok(None)
38
+ let translate = async (_id, _item, ~capabilities as _) => Ok(None)
39
39
 
40
40
  let maxRetries = 3
41
41
  let heartbeatInterval = 60
@@ -72,7 +72,10 @@ module ProcessPaymentSpec = {
72
72
  async (id, _item) => Ok(Some((id, ConfirmPayment({orderId: id}))))
73
73
  )
74
74
 
75
- let translate = (id, item) => translateFn.contents(id, item)
75
+ // The mock stays two-arg: a test that wants to vary behaviour varies it on
76
+ // the item, and threading capabilities into every fixture would make each
77
+ // one restate a type it does not use.
78
+ let translate = (id, item, ~capabilities as _) => translateFn.contents(id, item)
76
79
 
77
80
  let maxRetries = 2
78
81
  let heartbeatInterval = 30
@@ -47,7 +47,7 @@ function collect(event, param) {
47
47
  ]];
48
48
  }
49
49
 
50
- async function translate(_id, _item) {
50
+ async function translate(_id, _item, param) {
51
51
  return {
52
52
  TAG: "Ok",
53
53
  _0: undefined
@@ -113,7 +113,7 @@ let translateFn = {
113
113
  })
114
114
  };
115
115
 
116
- function translate$1(id, item) {
116
+ function translate$1(id, item, param) {
117
117
  return translateFn.contents(id, item);
118
118
  }
119
119
 
@@ -107,7 +107,7 @@ module SendConfirmTranslation: OutboundTranslationSlice.Translation
107
107
  [(orderId, ({orderId: orderId}: SendConfirmSpec.outboundItem))]
108
108
  }
109
109
 
110
- let translate = async (_id, item: SendConfirmSpec.outboundItem) => {
110
+ let translate = async (_id, item: SendConfirmSpec.outboundItem, ~capabilities as _) => {
111
111
  externalCalls->Array.push(item.orderId)
112
112
  Ok(None)
113
113
  }
@@ -130,7 +130,7 @@ function collect(event, param) {
130
130
  ]];
131
131
  }
132
132
 
133
- async function translate(_id, item) {
133
+ async function translate(_id, item, param) {
134
134
  externalCalls.push(item.orderId);
135
135
  return {
136
136
  TAG: "Ok",