@reventlessdev/reventless-local 3.0.0-alpha.318 → 3.0.0-alpha.319

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,14 @@
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.319 (2026-11-01)
7
+
8
+ ### Features
9
+
10
+ * **core:** a component's log line carries the ids of the message it is about ([9c26267](https://github.com/ReventlessDev/reventless-core/commit/9c26267ca6d03ff66b8406caa32243e205e29b5a))
11
+ * **local:** the registry entry names the platform API, and a command's outcome names its cause ([51717c4](https://github.com/ReventlessDev/reventless-core/commit/51717c441820c19dc59e595559b037b808ca716a))
12
+
13
+
6
14
  # 3.0.0-alpha.318 (2026-11-01)
7
15
 
8
16
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-local",
3
- "version": "3.0.0-alpha.318",
3
+ "version": "3.0.0-alpha.319",
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,19 +34,19 @@
34
34
  "graphql-yoga": "^5.21.0",
35
35
  "sury": "11.0.0",
36
36
  "ws": "^8.18.0",
37
- "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.30",
38
37
  "@reventlessdev/rescript-effect": "1.0.0-alpha.1",
38
+ "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.30",
39
39
  "@reventlessdev/rescript-jest": "1.0.0-alpha.13",
40
- "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.24",
41
40
  "@reventlessdev/rescript-node": "2.0.0-alpha.25",
41
+ "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.24",
42
+ "@reventlessdev/reventless-core": "3.0.0-alpha.327",
43
+ "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.175",
42
44
  "@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
43
- "@reventlessdev/reventless-core": "3.0.0-alpha.326",
44
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.275",
45
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.276",
45
46
  "@reventlessdev/reventless-infra": "3.0.0-alpha.221",
46
- "@reventlessdev/reventless-seed": "1.0.0-alpha.40",
47
- "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.174",
47
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.191",
48
48
  "@reventlessdev/reventless-spec": "3.0.0-alpha.192",
49
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.190"
49
+ "@reventlessdev/reventless-seed": "1.0.0-alpha.40"
50
50
  },
51
51
  "devDependencies": {
52
52
  "rescript": "12.3.1",
@@ -30,6 +30,9 @@ type entry = {
30
30
  // Where the log feed is served, when it is: the platform's recent and live log
31
31
  // records. Optional for the same reason as `tapPort`.
32
32
  logPort?: int,
33
+ // Where the platform API is served: its own port when the platform serves two
34
+ // APIs, else the same endpoint as `endpoint`. Optional for the same reason.
35
+ platformEndpoint?: string,
33
36
  }
34
37
 
35
38
  // Threaded rather than read at each use, so tests need not move the process.
@@ -115,6 +118,7 @@ let write = (
115
118
  ~loginEndpoint: string,
116
119
  ~store: store,
117
120
  ~tapPort: option<int>=?,
121
+ ~platformEndpoint: option<string>=?,
118
122
  ~pid: int=NodeProcess.pid,
119
123
  ~cwd: string=NodeProcess.cwd(),
120
124
  ): string => {
@@ -128,6 +132,7 @@ let write = (
128
132
  store,
129
133
  startedAt: Date.make()->Date.toISOString,
130
134
  ?tapPort,
135
+ ?platformEndpoint,
131
136
  }
132
137
  try {
133
138
  NodeFs.mkdirSync(runningDir(~cwd, ()), {recursive: true})
@@ -187,8 +192,9 @@ let register = (
187
192
  ~loginEndpoint: string,
188
193
  ~store: store,
189
194
  ~tapPort: option<int>=?,
195
+ ~platformEndpoint: option<string>=?,
190
196
  ): unit => {
191
- let path = write(~port, ~endpoint, ~loginEndpoint, ~store, ~tapPort?)
197
+ let path = write(~port, ~endpoint, ~loginEndpoint, ~store, ~tapPort?, ~platformEndpoint?)
192
198
  NodeProcess.onExit(_ => removeQuietly(path))
193
199
  NodeProcess.onSignal(SIGINT, () => {
194
200
  removeQuietly(path)
@@ -23,7 +23,8 @@ let entrySchema = Sury.$schema(s => ({
23
23
  store: s.m(storeSchema),
24
24
  startedAt: s.m(Sury.string),
25
25
  tapPort: s.m(Sury.$option(Sury.int32)),
26
- logPort: s.m(Sury.$option(Sury.int32))
26
+ logPort: s.m(Sury.$option(Sury.int32)),
27
+ platformEndpoint: s.m(Sury.$option(Sury.string))
27
28
  }));
28
29
 
29
30
  function runningDir(cwdOpt, param) {
@@ -110,7 +111,7 @@ function list(cwdOpt, param) {
110
111
  }).toSorted((a, b) => Primitive_int.compare(a.port, b.port));
111
112
  }
112
113
 
113
- function write(port, endpoint, loginEndpoint, store, tapPort, pidOpt, cwdOpt) {
114
+ function write(port, endpoint, loginEndpoint, store, tapPort, platformEndpoint, pidOpt, cwdOpt) {
114
115
  let pid = pidOpt !== undefined ? pidOpt : process.pid;
115
116
  let cwd = cwdOpt !== undefined ? cwdOpt : process.cwd();
116
117
  let path = entryPath(port, cwd);
@@ -124,7 +125,8 @@ function write(port, endpoint, loginEndpoint, store, tapPort, pidOpt, cwdOpt) {
124
125
  loginEndpoint: loginEndpoint,
125
126
  store: store,
126
127
  startedAt: entry_startedAt,
127
- tapPort: tapPort
128
+ tapPort: tapPort,
129
+ platformEndpoint: platformEndpoint
128
130
  };
129
131
  try {
130
132
  Nodefs.mkdirSync(runningDir(cwd, undefined), {
@@ -169,8 +171,8 @@ function publishLogPort(port, logPort, cwdOpt) {
169
171
  }
170
172
  }
171
173
 
172
- function register(port, endpoint, loginEndpoint, store, tapPort) {
173
- let path = write(port, endpoint, loginEndpoint, store, tapPort, undefined, undefined);
174
+ function register(port, endpoint, loginEndpoint, store, tapPort, platformEndpoint) {
175
+ let path = write(port, endpoint, loginEndpoint, store, tapPort, platformEndpoint, undefined, undefined);
174
176
  process.on("exit", param => removeQuietly(path));
175
177
  process.on("SIGINT", () => {
176
178
  removeQuietly(path);
package/src/Platform.res CHANGED
@@ -1422,6 +1422,9 @@ module MakeWithConfig = (
1422
1422
  ~endpoint=`http://localhost:${domainPort->Int.toString}/graphql`,
1423
1423
  ~loginEndpoint=`http://localhost:${domainPort->Int.toString}/__inmemory/login`,
1424
1424
  ~store={kind, ?path},
1425
+ ~platformEndpoint=Config.splitApi
1426
+ ? `http://localhost:${platformPort->Int.toString}/graphql`
1427
+ : `http://localhost:${domainPort->Int.toString}/graphql`,
1425
1428
  )
1426
1429
  // After the register, and it fills the tap port in once the socket is bound:
1427
1430
  // the port is ephemeral by default, so it is not known until `listen` calls
@@ -1176,7 +1176,7 @@ function MakeWithConfig(Config) {
1176
1176
  LocalPlatformRegistry$ReventlessLocal.register(domainPort, `http://localhost:` + domainPort.toString() + `/graphql`, `http://localhost:` + domainPort.toString() + `/__inmemory/login`, {
1177
1177
  kind: match[0],
1178
1178
  path: match[1]
1179
- }, undefined);
1179
+ }, undefined, Config.splitApi ? `http://localhost:` + platformPort.toString() + `/graphql` : `http://localhost:` + domainPort.toString() + `/graphql`);
1180
1180
  LocalEventTap$ReventlessLocal.start(undefined, tapPort => LocalPlatformRegistry$ReventlessLocal.publishTapPort(domainPort, tapPort, undefined), undefined);
1181
1181
  LocalLogFeed$ReventlessLocal.start(undefined, logPort => LocalPlatformRegistry$ReventlessLocal.publishLogPort(domainPort, logPort, undefined), undefined);
1182
1182
  Plugin_Helpers$ReventlessCore.firePlatformDeployedHook({
@@ -2973,7 +2973,7 @@ function Make($star) {
2973
2973
  LocalPlatformRegistry$ReventlessLocal.register(domainPort, `http://localhost:` + domainPort.toString() + `/graphql`, `http://localhost:` + domainPort.toString() + `/__inmemory/login`, {
2974
2974
  kind: match[0],
2975
2975
  path: match[1]
2976
- }, undefined);
2976
+ }, undefined, `http://localhost:` + platformPort.toString() + `/graphql`);
2977
2977
  LocalEventTap$ReventlessLocal.start(undefined, tapPort => LocalPlatformRegistry$ReventlessLocal.publishTapPort(domainPort, tapPort, undefined), undefined);
2978
2978
  LocalLogFeed$ReventlessLocal.start(undefined, logPort => LocalPlatformRegistry$ReventlessLocal.publishLogPort(domainPort, logPort, undefined), undefined);
2979
2979
  Plugin_Helpers$ReventlessCore.firePlatformDeployedHook({
@@ -34,6 +34,7 @@ let outcomeLine = (r: Outcome.commandOutcomeReport): string => {
34
34
  ->Array.concat(optional("plugin", plugin))
35
35
  ->Array.concat([("msgId", str(r.reference))])
36
36
  ->Array.concat(optional("correlationId", r.correlationId))
37
+ ->Array.concat(optional("causationId", r.causationId))
37
38
  let body = switch r.outcome {
38
39
  | OutcomeAccepted({entityId, eventCount}) =>
39
40
  [("outcome", str("accepted"))]
@@ -69,6 +70,7 @@ let rejectionRecord = (r: Outcome.commandOutcomeReport): option<Logger.record> =
69
70
  }
70
71
  let annotations = Dict.fromArray([("msgId", r.reference)])
71
72
  r.correlationId->Option.forEach(id => annotations->Dict.set("correlationId", id))
73
+ r.causationId->Option.forEach(id => annotations->Dict.set("causationId", id))
72
74
  Some({
73
75
  time: now(),
74
76
  level,
@@ -50,7 +50,7 @@ function outcomeLine(r) {
50
50
  ].concat(optional("plugin", plugin)).concat([[
51
51
  "msgId",
52
52
  r.reference
53
- ]]).concat(optional("correlationId", r.correlationId));
53
+ ]]).concat(optional("correlationId", r.correlationId)).concat(optional("causationId", r.causationId));
54
54
  let match = r.outcome;
55
55
  let body;
56
56
  body = match.TAG === "OutcomeAccepted" ? [[
@@ -118,6 +118,9 @@ function rejectionRecord(r) {
118
118
  Stdlib_Option.forEach(r.correlationId, id => {
119
119
  annotations["correlationId"] = id;
120
120
  });
121
+ Stdlib_Option.forEach(r.causationId, id => {
122
+ annotations["causationId"] = id;
123
+ });
121
124
  return {
122
125
  time: new Date().toISOString(),
123
126
  level: level,
@@ -273,7 +273,7 @@ async function runCatchup(db, upperBound, dcbUpperBound, handlers) {
273
273
  if (checkpoint < bound) {
274
274
  let rows = missedRows(db, axis, checkpoint, bound);
275
275
  if (rows.length !== 0) {
276
- Effect.runSync(EffectLogger$ReventlessCore.logInfo(comp, undefined, `catch-up: delivering ` + rows.length.toString() + ` missed ` + axisLabel(axis) + ` event(s) (positions ` + checkpoint.toString() + `..` + bound.toString() + `] to ` + name));
276
+ Effect.runSync(EffectLogger$ReventlessCore.logInfo(comp, undefined, undefined, `catch-up: delivering ` + rows.length.toString() + ` missed ` + axisLabel(axis) + ` event(s) (positions ` + checkpoint.toString() + `..` + bound.toString() + `] to ` + name));
277
277
  }
278
278
  for (let j = 0, j_finish = rows.length; j < j_finish; ++j) {
279
279
  let match$2 = rows[j];
@@ -283,10 +283,10 @@ async function runCatchup(db, upperBound, dcbUpperBound, handlers) {
283
283
  try {
284
284
  await handler(envelope, undefined);
285
285
  } catch (exn) {
286
- Effect.runSync(EffectLogger$ReventlessCore.logWarn(comp, undefined, `catch-up: ` + name + ` failed on stored ` + axisLabel(axis) + ` event at position ` + pos.toString() + ` — skipped`));
286
+ Effect.runSync(EffectLogger$ReventlessCore.logWarn(comp, undefined, undefined, `catch-up: ` + name + ` failed on stored ` + axisLabel(axis) + ` event at position ` + pos.toString() + ` — skipped`));
287
287
  }
288
288
  } else {
289
- Effect.runSync(EffectLogger$ReventlessCore.logWarn(comp, undefined, `catch-up: unreadable stored ` + axisLabel(axis) + ` event at position ` + pos.toString() + ` — skipped`));
289
+ Effect.runSync(EffectLogger$ReventlessCore.logWarn(comp, undefined, undefined, `catch-up: unreadable stored ` + axisLabel(axis) + ` event at position ` + pos.toString() + ` — skipped`));
290
290
  }
291
291
  }
292
292
  }
@@ -59,7 +59,7 @@ function Make(Bus) {
59
59
  return await ops.tick(key, at);
60
60
  });
61
61
  Stdlib_Promise.$$catch(TestRunner$ReventlessLocal.resolve(Component$ReventlessCore.operations(component)).then(ops => ops.reconcileSchedules()), exn => {
62
- Effect.runSync(EffectLogger$ReventlessCore.logError(`AutomationSlice(` + Spec.name + `)`, undefined, `the schedules could not be reconciled: ` + Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown")));
62
+ Effect.runSync(EffectLogger$ReventlessCore.logError(`AutomationSlice(` + Spec.name + `)`, undefined, undefined, `the schedules could not be reconciled: ` + Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown")));
63
63
  return Promise.resolve();
64
64
  });
65
65
  return component;
@@ -18,7 +18,7 @@ function timerName(slice, key) {
18
18
  }
19
19
 
20
20
  function tickFailed(slice, key, message) {
21
- Effect.runSync(EffectLogger$ReventlessCore.logError("LocalAutomationSchedules", undefined, `tick ` + key + ` of ` + slice + ` failed: ` + message));
21
+ Effect.runSync(EffectLogger$ReventlessCore.logError("LocalAutomationSchedules", undefined, undefined, `tick ` + key + ` of ` + slice + ` failed: ` + message));
22
22
  }
23
23
 
24
24
  function register(slice, tick) {
@@ -40,7 +40,7 @@ async function sweepOnce() {
40
40
  } catch (raw_exn) {
41
41
  let exn = Primitive_exceptions.internalToException(raw_exn);
42
42
  let message = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown");
43
- return Effect.runSync(EffectLogger$ReventlessCore.logError("LocalAutomationSweep", undefined, `sweep of ` + param[0] + ` failed: ` + message));
43
+ return Effect.runSync(EffectLogger$ReventlessCore.logError("LocalAutomationSweep", undefined, undefined, `sweep of ` + param[0] + ` failed: ` + message));
44
44
  }
45
45
  });
46
46
  running.contents = false;
@@ -199,4 +199,21 @@ describe("LocalPlatformRegistry.tapPort", () => {
199
199
 
200
200
  expect(LocalPlatformRegistry.list(~cwd, ())->Array.map(e => e.tapPort))->toEqual([Some(4100)])
201
201
  })
202
+
203
+ testSync("names where the platform API is served, and keeps it when a port is published", () => {
204
+ let cwd = tempRoot()
205
+ let _ = LocalPlatformRegistry.write(
206
+ ~port=4000,
207
+ ~endpoint="http://localhost:4000/graphql",
208
+ ~loginEndpoint="http://localhost:4000/__inmemory/login",
209
+ ~store=memoryStore,
210
+ ~platformEndpoint="http://localhost:4001/graphql",
211
+ ~cwd,
212
+ )
213
+ LocalPlatformRegistry.publishTapPort(~port=4000, ~tapPort=4100, ~cwd)
214
+
215
+ expect(
216
+ LocalPlatformRegistry.list(~cwd, ())->Array.map(e => (e.platformEndpoint, e.tapPort)),
217
+ )->toEqual([(Some("http://localhost:4001/graphql"), Some(4100))])
218
+ })
202
219
  })
@@ -24,7 +24,7 @@ let memoryStore = {
24
24
 
25
25
  function writeAt(cwd, port, store, pidOpt) {
26
26
  let pid = pidOpt !== undefined ? pidOpt : process.pid;
27
- return LocalPlatformRegistry$ReventlessLocal.write(port, `http://localhost:` + port.toString() + `/graphql`, `http://localhost:` + port.toString() + `/__inmemory/login`, store, undefined, pid, cwd);
27
+ return LocalPlatformRegistry$ReventlessLocal.write(port, `http://localhost:` + port.toString() + `/graphql`, `http://localhost:` + port.toString() + `/__inmemory/login`, store, undefined, undefined, pid, cwd);
28
28
  }
29
29
 
30
30
  globalThis.describe("LocalPlatformRegistry", () => {
@@ -173,9 +173,21 @@ globalThis.describe("LocalPlatformRegistry.tapPort", () => {
173
173
  globalThis.test("ignores a platform that never published an entry", () => LocalPlatformRegistry$ReventlessLocal.publishTapPort(4000, 1, tempRoot()));
174
174
  globalThis.test("round-trips the port a platform serving a tap publishes", () => {
175
175
  let cwd = tempRoot();
176
- LocalPlatformRegistry$ReventlessLocal.write(4000, "http://localhost:4000/graphql", "http://localhost:4000/__inmemory/login", memoryStore, 4100, undefined, cwd);
176
+ LocalPlatformRegistry$ReventlessLocal.write(4000, "http://localhost:4000/graphql", "http://localhost:4000/__inmemory/login", memoryStore, 4100, undefined, undefined, cwd);
177
177
  globalThis.expect(LocalPlatformRegistry$ReventlessLocal.list(cwd, undefined).map(e => e.tapPort)).toEqual([4100]);
178
178
  });
179
+ globalThis.test("names where the platform API is served, and keeps it when a port is published", () => {
180
+ let cwd = tempRoot();
181
+ LocalPlatformRegistry$ReventlessLocal.write(4000, "http://localhost:4000/graphql", "http://localhost:4000/__inmemory/login", memoryStore, undefined, "http://localhost:4001/graphql", undefined, cwd);
182
+ LocalPlatformRegistry$ReventlessLocal.publishTapPort(4000, 4100, cwd);
183
+ globalThis.expect(LocalPlatformRegistry$ReventlessLocal.list(cwd, undefined).map(e => [
184
+ e.platformEndpoint,
185
+ e.tapPort
186
+ ])).toEqual([[
187
+ "http://localhost:4001/graphql",
188
+ 4100
189
+ ]]);
190
+ });
179
191
  });
180
192
 
181
193
  let deadPid = 2147483646;
@@ -28,7 +28,7 @@ let memoryStore = {
28
28
 
29
29
  function writeAt(cwd, port, store, pidOpt) {
30
30
  let pid = pidOpt !== undefined ? pidOpt : process.pid;
31
- return LocalPlatformRegistry$ReventlessLocal.write(port, `http://localhost:` + port.toString() + `/graphql`, `http://localhost:` + port.toString() + `/__inmemory/login`, store, undefined, pid, cwd);
31
+ return LocalPlatformRegistry$ReventlessLocal.write(port, `http://localhost:` + port.toString() + `/graphql`, `http://localhost:` + port.toString() + `/__inmemory/login`, store, undefined, undefined, pid, cwd);
32
32
  }
33
33
 
34
34
  function withoutBypass(f) {
@@ -180,3 +180,28 @@ describe("LocalTapLines", () => {
180
180
  await disconnect(tap)
181
181
  })
182
182
  })
183
+
184
+ describe("the outcome line names its cause", () => {
185
+ testSync("a command an automation sent says which event it acted on", () => {
186
+ let line = LocalTapLines.outcomeLine({
187
+ component: "Notice",
188
+ reference: "cmd-2",
189
+ correlationId: "flow-1",
190
+ causationId: "evt-7",
191
+ outcome: OutcomeAccepted({entityId: Some("n-1"), eventCount: 1}),
192
+ })
193
+ let d = line->JSON.parseOrThrow->JSON.Decode.object->Option.getOrThrow
194
+ expect(d->Dict.get("causationId"))->toEqual(Some(JSON.String("evt-7")))
195
+ expect(d->Dict.get("msgId"))->toEqual(Some(JSON.String("cmd-2")))
196
+ })
197
+
198
+ testSync("a command sent from outside has none", () => {
199
+ let line = LocalTapLines.outcomeLine({
200
+ component: "Order",
201
+ reference: "cmd-1",
202
+ outcome: OutcomeAccepted({entityId: None, eventCount: 1}),
203
+ })
204
+ let d = line->JSON.parseOrThrow->JSON.Decode.object->Option.getOrThrow
205
+ expect(d->Dict.get("causationId"))->toEqual(None)
206
+ })
207
+ })
@@ -93,11 +93,11 @@ async function disconnect(tap) {
93
93
  globalThis.describe("LocalTapLines", () => {
94
94
  globalThis.test("an accepted and a rejected command each appear once on the tap", async () => {
95
95
  let tap = await connectTap();
96
- CommandTopic_Helpers$ReventlessCore.reportAccepted("Order", "flow-1", "m-1", {
96
+ CommandTopic_Helpers$ReventlessCore.reportAccepted("Order", "flow-1", undefined, "m-1", {
97
97
  entityId: "o-1",
98
98
  eventCount: 2
99
99
  });
100
- CommandTopic_Helpers$ReventlessCore.reportRejected("Order", "DomainRejection", "flow-1", "m-2", {
100
+ CommandTopic_Helpers$ReventlessCore.reportRejected("Order", "DomainRejection", "flow-1", undefined, "m-2", {
101
101
  errorCode: "AlreadyExists",
102
102
  errorDetail: `{"name":"Widget"}`
103
103
  });
@@ -181,7 +181,7 @@ globalThis.describe("LocalTapLines", () => {
181
181
  });
182
182
  globalThis.test("an infrastructure failure is kept as an error", async () => {
183
183
  let tap = await connectTap();
184
- CommandTopic_Helpers$ReventlessCore.reportRejected("Order", "InfrastructureFailure", undefined, "m-3", {
184
+ CommandTopic_Helpers$ReventlessCore.reportRejected("Order", "InfrastructureFailure", undefined, undefined, "m-3", {
185
185
  errorCode: "AppendFailed",
186
186
  errorDetail: "store down"
187
187
  });
@@ -224,6 +224,38 @@ globalThis.describe("LocalTapLines", () => {
224
224
  });
225
225
  });
226
226
 
227
+ globalThis.describe("the outcome line names its cause", () => {
228
+ globalThis.test("a command an automation sent says which event it acted on", () => {
229
+ let line = LocalTapLines$ReventlessLocal.outcomeLine({
230
+ component: "Notice",
231
+ reference: "cmd-2",
232
+ correlationId: "flow-1",
233
+ causationId: "evt-7",
234
+ outcome: {
235
+ TAG: "OutcomeAccepted",
236
+ entityId: "n-1",
237
+ eventCount: 1
238
+ }
239
+ });
240
+ let d = Stdlib_Option.getOrThrow(Stdlib_JSON.Decode.object(JSON.parse(line)), undefined);
241
+ globalThis.expect(d["causationId"]).toEqual("evt-7");
242
+ globalThis.expect(d["msgId"]).toEqual("cmd-2");
243
+ });
244
+ globalThis.test("a command sent from outside has none", () => {
245
+ let line = LocalTapLines$ReventlessLocal.outcomeLine({
246
+ component: "Order",
247
+ reference: "cmd-1",
248
+ outcome: {
249
+ TAG: "OutcomeAccepted",
250
+ entityId: undefined,
251
+ eventCount: 1
252
+ }
253
+ });
254
+ let d = Stdlib_Option.getOrThrow(Stdlib_JSON.Decode.object(JSON.parse(line)), undefined);
255
+ globalThis.expect(d["causationId"]).toEqual(undefined);
256
+ });
257
+ });
258
+
227
259
  let Outcome;
228
260
 
229
261
  let ViewChange;