@reventlessdev/reventless-local 3.0.0-alpha.239 → 3.0.0-alpha.241

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 (32) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +11 -11
  3. package/src/Platform.res +10 -9
  4. package/src/Platform.res.mjs +18 -10
  5. package/src/adapter/LocalCapabilities.res +10 -7
  6. package/tests/adapter/InboundTranslationMutationTest.res.mjs +2 -1
  7. package/tests/components/aggregate/AggregateFixtures.res.mjs +12 -2
  8. package/tests/components/automationslice/AutomationSliceFixtures.res +2 -2
  9. package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +20 -4
  10. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +1 -1
  11. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +30 -2
  12. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +11 -2
  13. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +17 -3
  14. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +11 -0
  15. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res.mjs +9 -0
  16. package/tests/components/commandgenerator/CommandGeneratorFixtures.res.mjs +12 -2
  17. package/tests/components/commandtopic/CommandTopicFixtures.res.mjs +9 -1
  18. package/tests/components/commandtopic/CommandTopicStreamFixtures.res.mjs +9 -1
  19. package/tests/components/dcb/DcbCrossPartitionFixtures.res.mjs +10 -0
  20. package/tests/components/dcb/DcbFixtures.res.mjs +10 -0
  21. package/tests/components/extensionpoint/ExtensionPointFixtures.res.mjs +21 -3
  22. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +4 -0
  23. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +8 -3
  24. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +9 -1
  25. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +6 -2
  26. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +4 -0
  27. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +14 -2
  28. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +2 -0
  29. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res.mjs +17 -1
  30. package/tests/components/readmodel/DcbReadModelE2EFixtures.res.mjs +10 -0
  31. package/tests/plugin/PluginBehavior_GWT.res +5 -5
  32. package/tests/plugin/PluginBehavior_GWT.res.mjs +5 -5
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
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.241 (2026-09-01)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **automation:** a mapping is handed the envelope's id ([9ee482c](https://github.com/ReventlessDev/reventless-core/commit/9ee482c5ad0aae09efd1259eeb7f39b781867b91))
11
+ * **capabilities:** a plugin's geocoding need was declared nowhere and failed silently ([67917dd](https://github.com/ReventlessDev/reventless-core/commit/67917dd504b43fa78b7c6a51644c9eae656b7f6b))
12
+ ### Features
13
+
14
+ * **capabilities:** a plugin can send a message without naming a provider ([b001a1e](https://github.com/ReventlessDev/reventless-core/commit/b001a1e9361a0f4d0affe228cb4c08c38a5a995e))
15
+ * **plugin:** the admin lifecycle commands name their argument ([ea552ec](https://github.com/ReventlessDev/reventless-core/commit/ea552ec64e5db0b3dc465c0d9a80cac89627f727))
16
+ * **spec:** a command declares its lifecycle edge as a value ([40eee9f](https://github.com/ReventlessDev/reventless-core/commit/40eee9f7723dc05e418be680528f01967d074da4))
17
+ * **spec:** a graft leaves a trace the deployed plugin can read ([c08ff6c](https://github.com/ReventlessDev/reventless-core/commit/c08ff6c0f6177d58603e7ae1e5cec392d9bac16a))
18
+
19
+
20
+ # 3.0.0-alpha.240 (2026-08-27)
21
+
22
+ **Note:** Version bump only for package @reventlessdev/reventless-local
23
+
24
+
25
+
26
+
27
+
6
28
  # 3.0.0-alpha.239 (2026-08-27)
7
29
 
8
30
  **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.239",
3
+ "version": "3.0.0-alpha.241",
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": {
@@ -35,23 +35,23 @@
35
35
  "sury": "11.0.0-rc.2",
36
36
  "ws": "^8.18.0",
37
37
  "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
38
- "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.27",
39
38
  "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
40
- "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
39
+ "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.27",
41
40
  "@reventlessdev/rescript-node": "2.0.0-alpha.8",
42
- "@reventlessdev/reventless-core": "3.0.0-alpha.251",
43
- "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.99",
41
+ "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
44
42
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
45
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.198",
46
- "@reventlessdev/reventless-infra": "3.0.0-alpha.152",
47
- "@reventlessdev/reventless-spec": "3.0.0-alpha.124",
48
- "@reventlessdev/reventless-seed": "1.0.0-alpha.17",
49
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.115"
43
+ "@reventlessdev/reventless-core": "3.0.0-alpha.252",
44
+ "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.100",
45
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.199",
46
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.116",
47
+ "@reventlessdev/reventless-seed": "1.0.0-alpha.18",
48
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.153",
49
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.125"
50
50
  },
51
51
  "devDependencies": {
52
52
  "rescript": "12.3.0",
53
53
  "sury-ppx": "11.0.0-rc.2",
54
- "@reventlessdev/reventless-ppx": "1.0.0-alpha.74"
54
+ "@reventlessdev/reventless-ppx": "1.0.0-alpha.75"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "rescript": "12.3.0"
package/src/Platform.res CHANGED
@@ -1462,6 +1462,7 @@ module MakeWithConfig = (
1462
1462
  // signature; the in-memory platform provisions no infrastructure and
1463
1463
  // ignores them.
1464
1464
  geocoderPlaceIndex?: ReventlessInfra.Platform.geocoderIndex,
1465
+ messagingSender?: ReventlessInfra.Platform.messagingSender,
1465
1466
  uploadBucket?: ReventlessInfra.Platform.objectStore,
1466
1467
  // Still ignored: a mode is a shell *build* input locally, turned on in the
1467
1468
  // host-shell package's own `public/config.json`, where the AWS deploy has to
@@ -1942,15 +1943,15 @@ module MakeWithConfig = (
1942
1943
  )
1943
1944
  | None => None
1944
1945
  }
1945
- // The admin Plugin lifecycle SDL is `<field>(id: ID!, _0: String!)` — `id` is the
1946
- // plugin name (aggregate id) and `_0` is the target version (the command payload,
1947
- // e.g. `Activate(version)`). Use the caller-supplied `_0` when present; fall back
1948
- // to the plugin's current version from the Plugins read model for callers that
1949
- // omit it.
1946
+ // The admin Plugin lifecycle SDL is `<field>(id: ID!, version: String!)` — `id`
1947
+ // is the plugin name (aggregate id) and `version` is the target version (the
1948
+ // command payload, e.g. `Activate({version})`). Use the caller-supplied version
1949
+ // when present; fall back to the plugin's current version from the Plugins read
1950
+ // model for callers that omit it.
1950
1951
  let argVersion = (args: JSON.t) =>
1951
1952
  args
1952
1953
  ->JSON.Decode.object
1953
- ->Option.flatMap(d => d->Dict.get("_0"))
1954
+ ->Option.flatMap(d => d->Dict.get("version"))
1954
1955
  ->Option.flatMap(JSON.Decode.string)
1955
1956
  let dispatchLifecycle = (
1956
1957
  ~field: string,
@@ -1976,13 +1977,13 @@ module MakeWithConfig = (
1976
1977
  let retireField = ReventlessCore.Api_Naming.adminField(~name="Plugin_Retire")
1977
1978
  let mutationResolvers = Dict.make()
1978
1979
  mutationResolvers->Dict.set(activateField, async (_root, args, _ctx): JSON.t =>
1979
- dispatchLifecycle(~field=activateField, args, v => ReventlessCore.PluginSpec.Activate(v))
1980
+ dispatchLifecycle(~field=activateField, args, v => ReventlessCore.PluginSpec.Activate({version: v}))
1980
1981
  )
1981
1982
  mutationResolvers->Dict.set(deactivateField, async (_root, args, _ctx): JSON.t =>
1982
- dispatchLifecycle(~field=deactivateField, args, v => ReventlessCore.PluginSpec.Deactivate(v))
1983
+ dispatchLifecycle(~field=deactivateField, args, v => ReventlessCore.PluginSpec.Deactivate({version: v}))
1983
1984
  )
1984
1985
  mutationResolvers->Dict.set(retireField, async (_root, args, _ctx): JSON.t =>
1985
- dispatchLifecycle(~field=retireField, args, v => ReventlessCore.PluginSpec.Retire(v))
1986
+ dispatchLifecycle(~field=retireField, args, v => ReventlessCore.PluginSpec.Retire({version: v}))
1986
1987
  )
1987
1988
  // Remaining admin mutations (e.g., Clone) are no-ops in-memory.
1988
1989
  adminMutationFieldNames->Array.forEach(field =>
@@ -640,6 +640,8 @@ function MakeWithConfig(Config) {
640
640
  eventSchema: UiFragmentRegistry$ReventlessCore.eventSchema,
641
641
  commandSchema: UiFragmentRegistry$ReventlessCore.commandSchema,
642
642
  commandAuthorization: UiFragmentRegistry$ReventlessCore.commandAuthorization,
643
+ commandTransition: UiFragmentRegistry$ReventlessCore.commandTransition,
644
+ traits: UiFragmentRegistry$ReventlessCore.traits,
643
645
  readConsistency: UiFragmentRegistry$ReventlessCore.readConsistency
644
646
  };
645
647
  let Behavior = {
@@ -741,7 +743,9 @@ function MakeWithConfig(Config) {
741
743
  errorSchema: PluginSpec$ReventlessCore.errorSchema,
742
744
  commandSchema: PluginSpec$ReventlessCore.commandSchema,
743
745
  moduleUrl: PluginSpec$ReventlessCore.moduleUrl,
744
- commandAuthorization: PluginSpec$ReventlessCore.commandAuthorization
746
+ commandAuthorization: PluginSpec$ReventlessCore.commandAuthorization,
747
+ commandTransition: PluginSpec$ReventlessCore.commandTransition,
748
+ traits: PluginSpec$ReventlessCore.traits
745
749
  })({
746
750
  initialState: PluginBehavior$ReventlessCore.initialState,
747
751
  evolve: PluginBehavior$ReventlessCore.evolve,
@@ -1486,7 +1490,7 @@ function MakeWithConfig(Config) {
1486
1490
  });
1487
1491
  }
1488
1492
  };
1489
- let argVersion = args => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["_0"]), Stdlib_JSON.Decode.string);
1493
+ let argVersion = args => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["version"]), Stdlib_JSON.Decode.string);
1490
1494
  let dispatchLifecycle = (field, args, makeCommand) => {
1491
1495
  let msgId = Message$ReventlessCore.uuid();
1492
1496
  let pluginName = argId(args);
@@ -1506,15 +1510,15 @@ function MakeWithConfig(Config) {
1506
1510
  let mutationResolvers = {};
1507
1511
  mutationResolvers[activateField] = async (_root, args, _ctx) => dispatchLifecycle(activateField, args, v => ({
1508
1512
  TAG: "Activate",
1509
- _0: v
1513
+ version: v
1510
1514
  }));
1511
1515
  mutationResolvers[deactivateField] = async (_root, args, _ctx) => dispatchLifecycle(deactivateField, args, v => ({
1512
1516
  TAG: "Deactivate",
1513
- _0: v
1517
+ version: v
1514
1518
  }));
1515
1519
  mutationResolvers[retireField] = async (_root, args, _ctx) => dispatchLifecycle(retireField, args, v => ({
1516
1520
  TAG: "Retire",
1517
- _0: v
1521
+ version: v
1518
1522
  }));
1519
1523
  adminMutationFieldNames.forEach(field => {
1520
1524
  if (Stdlib_Option.isNone(mutationResolvers[field])) {
@@ -2370,6 +2374,8 @@ function Make($star) {
2370
2374
  eventSchema: UiFragmentRegistry$ReventlessCore.eventSchema,
2371
2375
  commandSchema: UiFragmentRegistry$ReventlessCore.commandSchema,
2372
2376
  commandAuthorization: UiFragmentRegistry$ReventlessCore.commandAuthorization,
2377
+ commandTransition: UiFragmentRegistry$ReventlessCore.commandTransition,
2378
+ traits: UiFragmentRegistry$ReventlessCore.traits,
2373
2379
  readConsistency: UiFragmentRegistry$ReventlessCore.readConsistency
2374
2380
  };
2375
2381
  let Behavior = {
@@ -2471,7 +2477,9 @@ function Make($star) {
2471
2477
  errorSchema: PluginSpec$ReventlessCore.errorSchema,
2472
2478
  commandSchema: PluginSpec$ReventlessCore.commandSchema,
2473
2479
  moduleUrl: PluginSpec$ReventlessCore.moduleUrl,
2474
- commandAuthorization: PluginSpec$ReventlessCore.commandAuthorization
2480
+ commandAuthorization: PluginSpec$ReventlessCore.commandAuthorization,
2481
+ commandTransition: PluginSpec$ReventlessCore.commandTransition,
2482
+ traits: PluginSpec$ReventlessCore.traits
2475
2483
  })({
2476
2484
  initialState: PluginBehavior$ReventlessCore.initialState,
2477
2485
  evolve: PluginBehavior$ReventlessCore.evolve,
@@ -3211,7 +3219,7 @@ function Make($star) {
3211
3219
  });
3212
3220
  }
3213
3221
  };
3214
- let argVersion = args => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["_0"]), Stdlib_JSON.Decode.string);
3222
+ let argVersion = args => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["version"]), Stdlib_JSON.Decode.string);
3215
3223
  let dispatchLifecycle = (field, args, makeCommand) => {
3216
3224
  let msgId = Message$ReventlessCore.uuid();
3217
3225
  let pluginName = argId(args);
@@ -3231,15 +3239,15 @@ function Make($star) {
3231
3239
  let mutationResolvers = {};
3232
3240
  mutationResolvers[activateField] = async (_root, args, _ctx) => dispatchLifecycle(activateField, args, v => ({
3233
3241
  TAG: "Activate",
3234
- _0: v
3242
+ version: v
3235
3243
  }));
3236
3244
  mutationResolvers[deactivateField] = async (_root, args, _ctx) => dispatchLifecycle(deactivateField, args, v => ({
3237
3245
  TAG: "Deactivate",
3238
- _0: v
3246
+ version: v
3239
3247
  }));
3240
3248
  mutationResolvers[retireField] = async (_root, args, _ctx) => dispatchLifecycle(retireField, args, v => ({
3241
3249
  TAG: "Retire",
3242
- _0: v
3250
+ version: v
3243
3251
  }));
3244
3252
  adminMutationFieldNames.forEach(field => {
3245
3253
  if (Stdlib_Option.isNone(mutationResolvers[field])) {
@@ -1,13 +1,16 @@
1
1
  // What the local platform hands a slice's `translate`.
2
2
  //
3
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.
4
+ // local platform provisions neither a geocoder nor a mailer (a place index and a
5
+ // verified sender identity are each an account and a bill), so
6
+ // `Capabilities.none` reports `Unavailable`, which `translate` maps to a
7
+ // retryable `Error` and the sweep surfaces. A dev running a geocoding slice sees
8
+ // its items stay queued, which is true, instead of seeing them written off as
9
+ // unresolvable addresses, which would not be. Messaging additionally publishes an
10
+ // empty channel list, so a preference surface offers nothing rather than offering
11
+ // a channel that cannot deliver.
9
12
  //
10
13
  // 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.
14
+ // stub keyed by address, Nominatim, a mailbox on disk. Slices reach them through
15
+ // the injected record, so nothing in a plugin moves on that day.
13
16
  let capabilities = () => Reventless.Capabilities.none
@@ -26,7 +26,8 @@ let Callback = InboundTranslationSlice_Callback$ReventlessCore.Make({
26
26
  commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandSchema,
27
27
  targetName: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.targetName,
28
28
  externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.externalSystem,
29
- commandAuthorization: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandAuthorization
29
+ commandAuthorization: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandAuthorization,
30
+ commandTransition: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandTransition
30
31
  })(PaymentWebhookTranslation);
31
32
 
32
33
  let scope = "Payments";
@@ -27,6 +27,12 @@ function commandAuthorization(param) {
27
27
  return "AllowAuthenticated";
28
28
  }
29
29
 
30
+ function commandTransition(param) {
31
+ return "Unrestricted";
32
+ }
33
+
34
+ let traits = [];
35
+
30
36
  let ItemSpec = {
31
37
  Id: undefined,
32
38
  name: name,
@@ -34,7 +40,9 @@ let ItemSpec = {
34
40
  eventSchema: eventSchema,
35
41
  errorSchema: errorSchema,
36
42
  moduleUrl: moduleUrl,
37
- commandAuthorization: commandAuthorization
43
+ commandAuthorization: commandAuthorization,
44
+ commandTransition: commandTransition,
45
+ traits: traits
38
46
  };
39
47
 
40
48
  let moduleUrl$1 = import.meta.url;
@@ -89,7 +97,9 @@ let ItemAgg = ItemAggregateMaker.Make({
89
97
  errorSchema: errorSchema,
90
98
  commandSchema: commandSchema,
91
99
  moduleUrl: moduleUrl,
92
- commandAuthorization: commandAuthorization
100
+ commandAuthorization: commandAuthorization,
101
+ commandTransition: commandTransition,
102
+ traits: traits
93
103
  })(ItemBehavior)(NoEventMappings$ReventlessInfra.Make({
94
104
  name: name,
95
105
  Id: Id$Reventless.$$String,
@@ -74,7 +74,7 @@ module ShipOrderMapping = Reventless.AutomationSlice.Mapping.Make(
74
74
  ShipOrderSource,
75
75
  ShipOrderSpec,
76
76
  {
77
- let collect = (event: ShipOrderSource.event, _ctx) =>
77
+ let collect = (event: ShipOrderSource.event, ~sourceId as _, _ctx) =>
78
78
  switch event {
79
79
  | OrderPlaced({orderId, address}) => [(orderId, ({orderId, address}: ShipOrderSpec.todoItem))]
80
80
  | ShipmentCreated(_) => []
@@ -91,7 +91,7 @@ module SkipProcessMapping = Reventless.AutomationSlice.Mapping.Make(
91
91
  SkipProcessSource,
92
92
  SkipProcessSpec,
93
93
  {
94
- let collect = (event: SkipProcessSource.event, _ctx) =>
94
+ let collect = (event: SkipProcessSource.event, ~sourceId as _, _ctx) =>
95
95
  switch event {
96
96
  | OrderPlaced({orderId}) => [(orderId, ({orderId: orderId}: SkipProcessSpec.todoItem))]
97
97
  | ShipmentCreated(_) => []
@@ -63,6 +63,12 @@ function commandAuthorization(param) {
63
63
  return "AllowAuthenticated";
64
64
  }
65
65
 
66
+ function commandTransition(param) {
67
+ return "Unrestricted";
68
+ }
69
+
70
+ let traits = [];
71
+
66
72
  let ShipOrderSpec = {
67
73
  name: "ShipOrder",
68
74
  moduleUrl: moduleUrl,
@@ -71,7 +77,9 @@ let ShipOrderSpec = {
71
77
  maxRetries: 3,
72
78
  heartbeatInterval: 60,
73
79
  targetName: "CreateShipment",
74
- commandAuthorization: commandAuthorization
80
+ commandAuthorization: commandAuthorization,
81
+ commandTransition: commandTransition,
82
+ traits: traits
75
83
  };
76
84
 
77
85
  let moduleUrl$1 = import.meta.url;
@@ -86,6 +94,12 @@ function commandAuthorization$1(param) {
86
94
  return "AllowAuthenticated";
87
95
  }
88
96
 
97
+ function commandTransition$1(param) {
98
+ return "Unrestricted";
99
+ }
100
+
101
+ let traits$1 = [];
102
+
89
103
  let SkipProcessSpec = {
90
104
  name: "SkipProcess",
91
105
  moduleUrl: moduleUrl$1,
@@ -94,10 +108,12 @@ let SkipProcessSpec = {
94
108
  maxRetries: 0,
95
109
  heartbeatInterval: 60,
96
110
  targetName: "Noop",
97
- commandAuthorization: commandAuthorization$1
111
+ commandAuthorization: commandAuthorization$1,
112
+ commandTransition: commandTransition$1,
113
+ traits: traits$1
98
114
  };
99
115
 
100
- function collect(event, _ctx) {
116
+ function collect(event, param, _ctx) {
101
117
  if (event.TAG !== "OrderPlaced") {
102
118
  return [];
103
119
  }
@@ -128,7 +144,7 @@ let ShipOrderMapping = AutomationSlice$Reventless.Mapping.Make({
128
144
  resolve: resolve
129
145
  });
130
146
 
131
- function collect$1(event, _ctx) {
147
+ function collect$1(event, param, _ctx) {
132
148
  if (event.TAG !== "OrderPlaced") {
133
149
  return [];
134
150
  }
@@ -142,7 +142,7 @@ module FromDcb = AutomationSlice.Mapping.Make(
142
142
  DcbSource,
143
143
  AutoShipSpec,
144
144
  {
145
- let collect = (event: DcbSource.event, _ctx) =>
145
+ let collect = (event: DcbSource.event, ~sourceId as _, _ctx) =>
146
146
  switch event {
147
147
  | Placed({orderId}) => [(orderId, ({orderId: orderId}: AutoShipSpec.todoItem))]
148
148
  | Shipped(_) => []
@@ -41,6 +41,12 @@ function commandAuthorization(param) {
41
41
  return "AllowAuthenticated";
42
42
  }
43
43
 
44
+ function commandTransition(param) {
45
+ return "Unrestricted";
46
+ }
47
+
48
+ let traits = [];
49
+
44
50
  let PlaceSpec = {
45
51
  name: name,
46
52
  Id: undefined,
@@ -50,6 +56,8 @@ let PlaceSpec = {
50
56
  errorSchema: errorSchema,
51
57
  commandSchema: commandSchema,
52
58
  commandAuthorization: commandAuthorization,
59
+ commandTransition: commandTransition,
60
+ traits: traits,
53
61
  readConsistency: "EscalateOnRetry"
54
62
  };
55
63
 
@@ -112,6 +120,12 @@ function commandAuthorization$1(param) {
112
120
  return "AllowAuthenticated";
113
121
  }
114
122
 
123
+ function commandTransition$1(param) {
124
+ return "Unrestricted";
125
+ }
126
+
127
+ let traits$1 = [];
128
+
115
129
  let ShipSpec = {
116
130
  name: name$1,
117
131
  Id: undefined,
@@ -121,6 +135,8 @@ let ShipSpec = {
121
135
  errorSchema: errorSchema$1,
122
136
  commandSchema: commandSchema$1,
123
137
  commandAuthorization: commandAuthorization$1,
138
+ commandTransition: commandTransition$1,
139
+ traits: traits$1,
124
140
  readConsistency: "EscalateOnRetry"
125
141
  };
126
142
 
@@ -213,6 +229,12 @@ function commandAuthorization$2(param) {
213
229
  return "AllowAuthenticated";
214
230
  }
215
231
 
232
+ function commandTransition$2(param) {
233
+ return "Unrestricted";
234
+ }
235
+
236
+ let traits$2 = [];
237
+
216
238
  let AutoShipSpec = {
217
239
  name: name$3,
218
240
  moduleUrl: moduleUrl$4,
@@ -221,10 +243,12 @@ let AutoShipSpec = {
221
243
  maxRetries: 3,
222
244
  heartbeatInterval: 60,
223
245
  targetName: "Ship",
224
- commandAuthorization: commandAuthorization$2
246
+ commandAuthorization: commandAuthorization$2,
247
+ commandTransition: commandTransition$2,
248
+ traits: traits$2
225
249
  };
226
250
 
227
- function collect(event, _ctx) {
251
+ function collect(event, param, _ctx) {
228
252
  if (event.TAG !== "Placed") {
229
253
  return [];
230
254
  }
@@ -340,6 +364,8 @@ let PlaceMaker = StateChangeSlice_Builder$ReventlessLocal.Make({
340
364
  eventSchema: eventSchema,
341
365
  commandSchema: commandSchema,
342
366
  commandAuthorization: commandAuthorization,
367
+ commandTransition: commandTransition,
368
+ traits: traits,
343
369
  readConsistency: "EscalateOnRetry"
344
370
  })({
345
371
  initialState: false,
@@ -359,6 +385,8 @@ let ShipMaker = StateChangeSlice_Builder$ReventlessLocal.Make({
359
385
  eventSchema: eventSchema$1,
360
386
  commandSchema: commandSchema$1,
361
387
  commandAuthorization: commandAuthorization$1,
388
+ commandTransition: commandTransition$1,
389
+ traits: traits$1,
362
390
  readConsistency: "EscalateOnRetry"
363
391
  })({
364
392
  initialState: initialState,
@@ -65,11 +65,19 @@ module AutoFulfillSpec = {
65
65
  // Mapping 1: Aggregate source → todoItem (with `fromAggregate=true`)
66
66
  // ─────────────────────────────────────────────────────────────
67
67
 
68
+ // What `collect` was handed as `~sourceId`. Recorded rather than keyed on,
69
+ // because the envelope id and this payload's own `orderId` are deliberately
70
+ // different here — so a test can assert the ENVELOPE's id arrived, which is the
71
+ // whole point of the argument for an aggregate source whose payload does not
72
+ // repeat it.
73
+ let lastAggregateSourceId: ref<string> = ref("")
74
+
68
75
  module FromOrderAggregate = AutomationSlice.Mapping.Make(
69
76
  OrderAggregateSource,
70
77
  AutoFulfillSpec,
71
78
  {
72
- let collect = (event: OrderAggregateSource.event, _ctx) =>
79
+ let collect = (event: OrderAggregateSource.event, ~sourceId, _ctx) => {
80
+ lastAggregateSourceId := sourceId
73
81
  switch event {
74
82
  | OrderShipped({orderId, productId}) => [
75
83
  (
@@ -78,6 +86,7 @@ module FromOrderAggregate = AutomationSlice.Mapping.Make(
78
86
  ),
79
87
  ]
80
88
  }
89
+ }
81
90
  let resolve = (_event: OrderAggregateSource.event) => None
82
91
  },
83
92
  )
@@ -91,7 +100,7 @@ module FromInventoryDcb = AutomationSlice.Mapping.Make(
91
100
  InventoryDcbSource,
92
101
  AutoFulfillSpec,
93
102
  {
94
- let collect = (event: InventoryDcbSource.event, _ctx) =>
103
+ let collect = (event: InventoryDcbSource.event, ~sourceId as _, _ctx) =>
95
104
  switch event {
96
105
  | StockReserved({orderId, productId}) => [
97
106
  (
@@ -68,6 +68,12 @@ function commandAuthorization(param) {
68
68
  return "AllowAuthenticated";
69
69
  }
70
70
 
71
+ function commandTransition(param) {
72
+ return "Unrestricted";
73
+ }
74
+
75
+ let traits = [];
76
+
71
77
  let AutoFulfillSpec = {
72
78
  name: name$2,
73
79
  moduleUrl: moduleUrl,
@@ -76,10 +82,17 @@ let AutoFulfillSpec = {
76
82
  maxRetries: 3,
77
83
  heartbeatInterval: 60,
78
84
  targetName: "MarkFulfilled",
79
- commandAuthorization: commandAuthorization
85
+ commandAuthorization: commandAuthorization,
86
+ commandTransition: commandTransition,
87
+ traits: traits
88
+ };
89
+
90
+ let lastAggregateSourceId = {
91
+ contents: ""
80
92
  };
81
93
 
82
- function collect(event, _ctx) {
94
+ function collect(event, sourceId, _ctx) {
95
+ lastAggregateSourceId.contents = sourceId;
83
96
  let productId = event.productId;
84
97
  let orderId = event.orderId;
85
98
  return [[
@@ -105,7 +118,7 @@ let FromOrderAggregate = AutomationSlice$Reventless.Mapping.Make({
105
118
  resolve: resolve
106
119
  });
107
120
 
108
- function collect$1(event, _ctx) {
121
+ function collect$1(event, param, _ctx) {
109
122
  if (event.TAG !== "StockReserved") {
110
123
  return [];
111
124
  }
@@ -255,6 +268,7 @@ export {
255
268
  OrderAggregateSource,
256
269
  InventoryDcbSource,
257
270
  AutoFulfillSpec,
271
+ lastAggregateSourceId,
258
272
  FromOrderAggregate,
259
273
  FromInventoryDcb,
260
274
  AutoFulfillAutomation,
@@ -39,6 +39,17 @@ describe("MixedSource AutomationSlice", () => {
39
39
  expect(cmd.id)->toBe("o1:p1")
40
40
  })
41
41
 
42
+ // The argument an aggregate mapping cannot work without. `OrderShipped` names
43
+ // its own subject, so this fixture keys on the payload — but an aggregate's
44
+ // event generally does not, and then the envelope's id is the only thing that
45
+ // says which entity the todo row belongs to. Asserted against `"env-a1"`,
46
+ // which is deliberately not any value in the payload.
47
+ testPromise("collect is handed the envelope's id, not just the payload", async () => {
48
+ lastAggregateSourceId := ""
49
+ let _ = await publishAggregateEvent("env-a1", OrderShipped({orderId: "o1", productId: "p1"}))
50
+ expect(lastAggregateSourceId.contents)->toBe("env-a1")
51
+ })
52
+
42
53
  testPromise("DCB-source StockReserved creates a TODO and produces a command", async () => {
43
54
  publishedCommands := []
44
55
  let _ = await publishDcbEvent(
@@ -28,6 +28,15 @@ globalThis.describe("MixedSource AutomationSlice", () => {
28
28
  let cmd = MixedSourceAutomationSliceFixtures$ReventlessLocal.publishedCommands.contents[0];
29
29
  globalThis.expect(cmd.id).toBe("o1:p1");
30
30
  });
31
+ globalThis.test("collect is handed the envelope's id, not just the payload", async () => {
32
+ MixedSourceAutomationSliceFixtures$ReventlessLocal.lastAggregateSourceId.contents = "";
33
+ await MixedSourceAutomationSliceFixtures$ReventlessLocal.publishAggregateEvent("env-a1", {
34
+ TAG: "OrderShipped",
35
+ orderId: "o1",
36
+ productId: "p1"
37
+ });
38
+ globalThis.expect(MixedSourceAutomationSliceFixtures$ReventlessLocal.lastAggregateSourceId.contents).toBe("env-a1");
39
+ });
31
40
  globalThis.test("DCB-source StockReserved creates a TODO and produces a command", async () => {
32
41
  MixedSourceAutomationSliceFixtures$ReventlessLocal.publishedCommands.contents = [];
33
42
  await MixedSourceAutomationSliceFixtures$ReventlessLocal.publishDcbEvent("env-d1", {
@@ -28,6 +28,12 @@ function commandAuthorization(param) {
28
28
  return "AllowAuthenticated";
29
29
  }
30
30
 
31
+ function commandTransition(param) {
32
+ return "Unrestricted";
33
+ }
34
+
35
+ let traits = [];
36
+
31
37
  let CGSpec = {
32
38
  Id: undefined,
33
39
  name: name,
@@ -35,7 +41,9 @@ let CGSpec = {
35
41
  eventSchema: eventSchema,
36
42
  errorSchema: errorSchema,
37
43
  moduleUrl: moduleUrl,
38
- commandAuthorization: commandAuthorization
44
+ commandAuthorization: commandAuthorization,
45
+ commandTransition: commandTransition,
46
+ traits: traits
39
47
  };
40
48
 
41
49
  let moduleUrl$1 = import.meta.url;
@@ -81,7 +89,9 @@ let CGMaker = CommandGenerator_Builder$ReventlessCore.Make({
81
89
  errorSchema: errorSchema,
82
90
  commandSchema: commandSchema,
83
91
  moduleUrl: moduleUrl,
84
- commandAuthorization: commandAuthorization
92
+ commandAuthorization: commandAuthorization,
93
+ commandTransition: commandTransition,
94
+ traits: traits
85
95
  })(LocalCommandGeneratorResolvers$ReventlessLocal);
86
96
 
87
97
  let capturedCmds = {
@@ -33,6 +33,12 @@ function commandAuthorization(param) {
33
33
  return "AllowAuthenticated";
34
34
  }
35
35
 
36
+ function commandTransition(param) {
37
+ return "Unrestricted";
38
+ }
39
+
40
+ let traits = [];
41
+
36
42
  let ItemSpec = {
37
43
  Id: undefined,
38
44
  name: name,
@@ -40,7 +46,9 @@ let ItemSpec = {
40
46
  eventSchema: eventSchema,
41
47
  errorSchema: errorSchema,
42
48
  moduleUrl: moduleUrl,
43
- commandAuthorization: commandAuthorization
49
+ commandAuthorization: commandAuthorization,
50
+ commandTransition: commandTransition,
51
+ traits: traits
44
52
  };
45
53
 
46
54
  let Bus = LocalBus$ReventlessLocal.Make({});
@@ -35,6 +35,12 @@ function commandAuthorization(param) {
35
35
  return "AllowAuthenticated";
36
36
  }
37
37
 
38
+ function commandTransition(param) {
39
+ return "Unrestricted";
40
+ }
41
+
42
+ let traits = [];
43
+
38
44
  let ItemSpec = {
39
45
  Id: undefined,
40
46
  name: name,
@@ -42,7 +48,9 @@ let ItemSpec = {
42
48
  eventSchema: eventSchema,
43
49
  errorSchema: errorSchema,
44
50
  moduleUrl: moduleUrl,
45
- commandAuthorization: commandAuthorization
51
+ commandAuthorization: commandAuthorization,
52
+ commandTransition: commandTransition,
53
+ traits: traits
46
54
  };
47
55
 
48
56
  let StreamBus = LocalBus$ReventlessLocal.Make({});
@@ -73,6 +73,12 @@ function commandAuthorization(param) {
73
73
  return "AllowAuthenticated";
74
74
  }
75
75
 
76
+ function commandTransition(param) {
77
+ return "Unrestricted";
78
+ }
79
+
80
+ let traits = [];
81
+
76
82
  let AddProductSpec = {
77
83
  name: name,
78
84
  Id: undefined,
@@ -82,6 +88,8 @@ let AddProductSpec = {
82
88
  errorSchema: errorSchema,
83
89
  commandSchema: commandSchema,
84
90
  commandAuthorization: commandAuthorization,
91
+ commandTransition: commandTransition,
92
+ traits: traits,
85
93
  readConsistency: "EscalateOnRetry"
86
94
  };
87
95
 
@@ -172,6 +180,8 @@ let AddProductMaker = StateChangeSlice_Builder$ReventlessLocal.Make({
172
180
  eventSchema: eventSchema$1,
173
181
  commandSchema: commandSchema,
174
182
  commandAuthorization: commandAuthorization,
183
+ commandTransition: commandTransition,
184
+ traits: traits,
175
185
  readConsistency: "EscalateOnRetry"
176
186
  })({
177
187
  initialState: initialState,
@@ -50,6 +50,12 @@ function commandAuthorization(param) {
50
50
  return "AllowAuthenticated";
51
51
  }
52
52
 
53
+ function commandTransition(param) {
54
+ return "Unrestricted";
55
+ }
56
+
57
+ let traits = [];
58
+
53
59
  let AddItemSpec = {
54
60
  name: name,
55
61
  Id: undefined,
@@ -59,6 +65,8 @@ let AddItemSpec = {
59
65
  errorSchema: errorSchema,
60
66
  commandSchema: commandSchema,
61
67
  commandAuthorization: commandAuthorization,
68
+ commandTransition: commandTransition,
69
+ traits: traits,
62
70
  readConsistency: "EscalateOnRetry"
63
71
  };
64
72
 
@@ -124,6 +132,8 @@ let AddItemMaker = StateChangeSlice_Builder$ReventlessLocal.Make({
124
132
  eventSchema: eventSchema$1,
125
133
  commandSchema: commandSchema,
126
134
  commandAuthorization: commandAuthorization,
135
+ commandTransition: commandTransition,
136
+ traits: traits,
127
137
  readConsistency: "EscalateOnRetry"
128
138
  })({
129
139
  initialState: false,
@@ -29,13 +29,21 @@ function commandAuthorization(param) {
29
29
  return "AllowAuthenticated";
30
30
  }
31
31
 
32
+ function commandTransition(param) {
33
+ return "Unrestricted";
34
+ }
35
+
36
+ let traits = [];
37
+
32
38
  let TestEPSpec = {
33
39
  name: name,
34
40
  commandSchema: commandSchema,
35
41
  eventSchema: eventSchema,
36
42
  directiveSchema: directiveSchema,
37
43
  moduleUrl: moduleUrl,
38
- commandAuthorization: commandAuthorization
44
+ commandAuthorization: commandAuthorization,
45
+ commandTransition: commandTransition,
46
+ traits: traits
39
47
  };
40
48
 
41
49
  let name$1 = "TargetAgg";
@@ -58,6 +66,12 @@ function commandAuthorization$1(param) {
58
66
  return "AllowAuthenticated";
59
67
  }
60
68
 
69
+ function commandTransition$1(param) {
70
+ return "Unrestricted";
71
+ }
72
+
73
+ let traits$1 = [];
74
+
61
75
  let DelegateAggSpec = {
62
76
  Id: undefined,
63
77
  name: name$1,
@@ -65,7 +79,9 @@ let DelegateAggSpec = {
65
79
  eventSchema: eventSchema$1,
66
80
  errorSchema: errorSchema,
67
81
  moduleUrl: moduleUrl$1,
68
- commandAuthorization: commandAuthorization$1
82
+ commandAuthorization: commandAuthorization$1,
83
+ commandTransition: commandTransition$1,
84
+ traits: traits$1
69
85
  };
70
86
 
71
87
  let moduleUrl$2 = "test:ExtensionPointFixtures:ForwardMapping";
@@ -121,7 +137,9 @@ let TestEPMapping1 = ExtensionPointMapping$ReventlessInfra.Make({
121
137
  errorSchema: errorSchema,
122
138
  commandSchema: commandSchema$1,
123
139
  moduleUrl: moduleUrl$1,
124
- commandAuthorization: commandAuthorization$1
140
+ commandAuthorization: commandAuthorization$1,
141
+ commandTransition: commandTransition$1,
142
+ traits: traits$1
125
143
  },
126
144
  moduleUrl: moduleUrl$2,
127
145
  mapIncomingCommand: mapIncomingCommand,
@@ -208,6 +208,8 @@ describe("InboundTranslationSlice Callback", () => {
208
208
 
209
209
  let commandAuthorization = (_: command): Reventless.Authorization.permission =>
210
210
  AllowAuthenticated
211
+ type lifecycleState = unit
212
+ let commandTransition = (_: command): Reventless.Transition.t<lifecycleState> => Unrestricted
211
213
  }
212
214
 
213
215
  module MultiTranslation = {
@@ -269,6 +271,8 @@ describe("InboundTranslationSlice Callback", () => {
269
271
 
270
272
  let commandAuthorization = (_: command): Reventless.Authorization.permission =>
271
273
  AllowAuthenticated
274
+ type lifecycleState = unit
275
+ let commandTransition = (_: command): Reventless.Transition.t<lifecycleState> => Unrestricted
272
276
  }
273
277
 
274
278
  module EmptyTranslation = {
@@ -24,7 +24,8 @@ let Callback = InboundTranslationSlice_Callback$ReventlessCore.Make({
24
24
  commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandSchema,
25
25
  targetName: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.targetName,
26
26
  externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.externalSystem,
27
- commandAuthorization: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandAuthorization
27
+ commandAuthorization: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandAuthorization,
28
+ commandTransition: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandTransition
28
29
  })(PaymentWebhookTranslation);
29
30
 
30
31
  globalThis.describe("InboundTranslationSlice Callback", () => {
@@ -185,6 +186,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
185
186
  ])
186
187
  });
187
188
  let commandAuthorization = param => "AllowAuthenticated";
189
+ let commandTransition = param => "Unrestricted";
188
190
  let MultiTranslation = {
189
191
  translate: translate,
190
192
  moduleUrl: moduleUrl
@@ -196,7 +198,8 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
196
198
  commandSchema: commandSchema,
197
199
  targetName: "ConfirmPayment",
198
200
  externalSystem: undefined,
199
- commandAuthorization: commandAuthorization
201
+ commandAuthorization: commandAuthorization,
202
+ commandTransition: commandTransition
200
203
  })(MultiTranslation);
201
204
  let publishedCommands = {
202
205
  contents: []
@@ -247,6 +250,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
247
250
  _0: []
248
251
  });
249
252
  let commandAuthorization = param => "AllowAuthenticated";
253
+ let commandTransition = param => "Unrestricted";
250
254
  let EmptyTranslation = {
251
255
  translate: translate,
252
256
  moduleUrl: moduleUrl
@@ -258,7 +262,8 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
258
262
  commandSchema: commandSchema,
259
263
  targetName: "ConfirmPayment",
260
264
  externalSystem: undefined,
261
- commandAuthorization: commandAuthorization
265
+ commandAuthorization: commandAuthorization,
266
+ commandTransition: commandTransition
262
267
  })(EmptyTranslation);
263
268
  let publishedCommands = {
264
269
  contents: []
@@ -56,6 +56,12 @@ function commandAuthorization(param) {
56
56
  return "AllowAuthenticated";
57
57
  }
58
58
 
59
+ function commandTransition(param) {
60
+ return "Unrestricted";
61
+ }
62
+
63
+ let traits = [];
64
+
59
65
  let PaymentWebhookSpec = {
60
66
  name: "PaymentWebhook",
61
67
  moduleUrl: moduleUrl$1,
@@ -64,7 +70,9 @@ let PaymentWebhookSpec = {
64
70
  targetName: "ConfirmPayment",
65
71
  externalSystem: undefined,
66
72
  translate: translate,
67
- commandAuthorization: commandAuthorization
73
+ commandAuthorization: commandAuthorization,
74
+ commandTransition: commandTransition,
75
+ traits: traits
68
76
  };
69
77
 
70
78
  export {
@@ -47,7 +47,9 @@ let FireForgetCallback = OutboundTranslationSlice_Callback$ReventlessCore.Make({
47
47
  heartbeatInterval: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.heartbeatInterval,
48
48
  targetName: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.targetName,
49
49
  sourceNames: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.sourceNames,
50
- externalSystem: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.externalSystem
50
+ externalSystem: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.externalSystem,
51
+ capabilityNeeds: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.capabilityNeeds,
52
+ traits: OutboundTranslationSliceFixtures$ReventlessLocal.SendTrackingEmailSpec.traits
51
53
  })(SendTrackingEmailTranslation);
52
54
 
53
55
  let CommandBackCallback = OutboundTranslationSlice_Callback$ReventlessCore.Make({
@@ -60,7 +62,9 @@ let CommandBackCallback = OutboundTranslationSlice_Callback$ReventlessCore.Make(
60
62
  heartbeatInterval: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.heartbeatInterval,
61
63
  targetName: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.targetName,
62
64
  sourceNames: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.sourceNames,
63
- externalSystem: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.externalSystem
65
+ externalSystem: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.externalSystem,
66
+ capabilityNeeds: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.capabilityNeeds,
67
+ traits: OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.traits
64
68
  })(ProcessPaymentTranslation);
65
69
 
66
70
  globalThis.describe("OutboundTranslationSlice Callback", () => {
@@ -43,6 +43,8 @@ module SendTrackingEmailSpec = {
43
43
  let targetName = None
44
44
  let sourceNames: array<string> = []
45
45
  let externalSystem = None
46
+ let capabilityNeeds: array<Reventless.CapabilityNeed.t> = []
47
+ let traits: array<Reventless.Trait.t> = []
46
48
  }
47
49
 
48
50
  // ─────────────────────────────────────────────────────────────
@@ -90,4 +92,6 @@ module ProcessPaymentSpec = {
90
92
  let targetName = Some("ConfirmPayment")
91
93
  let sourceNames: array<string> = []
92
94
  let externalSystem = None
95
+ let capabilityNeeds: array<Reventless.CapabilityNeed.t> = []
96
+ let traits: array<Reventless.Trait.t> = []
93
97
  }
@@ -62,6 +62,10 @@ function onExhausted(_id, _item, param) {
62
62
 
63
63
  let sourceNames = [];
64
64
 
65
+ let capabilityNeeds = [];
66
+
67
+ let traits = [];
68
+
65
69
  let SendTrackingEmailSpec = {
66
70
  name: "SendTrackingEmail",
67
71
  moduleUrl: moduleUrl$1,
@@ -75,7 +79,9 @@ let SendTrackingEmailSpec = {
75
79
  heartbeatInterval: 60,
76
80
  targetName: undefined,
77
81
  sourceNames: sourceNames,
78
- externalSystem: undefined
82
+ externalSystem: undefined,
83
+ capabilityNeeds: capabilityNeeds,
84
+ traits: traits
79
85
  };
80
86
 
81
87
  let moduleUrl$2 = import.meta.url;
@@ -134,6 +140,10 @@ function onExhausted$1(id, item, lastError) {
134
140
 
135
141
  let sourceNames$1 = [];
136
142
 
143
+ let capabilityNeeds$1 = [];
144
+
145
+ let traits$1 = [];
146
+
137
147
  let ProcessPaymentSpec_targetName = "ConfirmPayment";
138
148
 
139
149
  let ProcessPaymentSpec = {
@@ -151,7 +161,9 @@ let ProcessPaymentSpec = {
151
161
  heartbeatInterval: 30,
152
162
  targetName: ProcessPaymentSpec_targetName,
153
163
  sourceNames: sourceNames$1,
154
- externalSystem: undefined
164
+ externalSystem: undefined,
165
+ capabilityNeeds: capabilityNeeds$1,
166
+ traits: traits$1
155
167
  };
156
168
 
157
169
  export {
@@ -88,6 +88,8 @@ module SendConfirmSpec = {
88
88
  let targetName = None
89
89
  let sourceNames: array<string> = []
90
90
  let externalSystem = Some("EmailService")
91
+ let capabilityNeeds: array<Reventless.CapabilityNeed.t> = []
92
+ let traits: array<Reventless.Trait.t> = []
91
93
  }
92
94
 
93
95
  // Two separate records so a failure says which phase stalled: `collectCalls`
@@ -42,6 +42,12 @@ function commandAuthorization(param) {
42
42
  return "AllowAuthenticated";
43
43
  }
44
44
 
45
+ function commandTransition(param) {
46
+ return "Unrestricted";
47
+ }
48
+
49
+ let traits = [];
50
+
45
51
  let PlaceSpec = {
46
52
  name: name,
47
53
  Id: undefined,
@@ -51,6 +57,8 @@ let PlaceSpec = {
51
57
  errorSchema: errorSchema,
52
58
  commandSchema: commandSchema,
53
59
  commandAuthorization: commandAuthorization,
60
+ commandTransition: commandTransition,
61
+ traits: traits,
54
62
  readConsistency: "EscalateOnRetry"
55
63
  };
56
64
 
@@ -101,6 +109,10 @@ let inboundCommandSchema = Sury.$unit;
101
109
 
102
110
  let sourceNames = [];
103
111
 
112
+ let capabilityNeeds = [];
113
+
114
+ let traits$1 = [];
115
+
104
116
  let SendConfirmSpec_externalSystem = "EmailService";
105
117
 
106
118
  let SendConfirmSpec = {
@@ -113,7 +125,9 @@ let SendConfirmSpec = {
113
125
  heartbeatInterval: 60,
114
126
  targetName: undefined,
115
127
  sourceNames: sourceNames,
116
- externalSystem: SendConfirmSpec_externalSystem
128
+ externalSystem: SendConfirmSpec_externalSystem,
129
+ capabilityNeeds: capabilityNeeds,
130
+ traits: traits$1
117
131
  };
118
132
 
119
133
  let collectCalls = [];
@@ -211,6 +225,8 @@ let PlaceMaker = StateChangeSlice_Builder$ReventlessLocal.Make({
211
225
  eventSchema: eventSchema,
212
226
  commandSchema: commandSchema,
213
227
  commandAuthorization: commandAuthorization,
228
+ commandTransition: commandTransition,
229
+ traits: traits,
214
230
  readConsistency: "EscalateOnRetry"
215
231
  })({
216
232
  initialState: false,
@@ -45,6 +45,12 @@ function commandAuthorization(param) {
45
45
  return "AllowAuthenticated";
46
46
  }
47
47
 
48
+ function commandTransition(param) {
49
+ return "Unrestricted";
50
+ }
51
+
52
+ let traits = [];
53
+
48
54
  let AddProductSpec = {
49
55
  name: name,
50
56
  Id: undefined,
@@ -54,6 +60,8 @@ let AddProductSpec = {
54
60
  errorSchema: errorSchema,
55
61
  commandSchema: commandSchema,
56
62
  commandAuthorization: commandAuthorization,
63
+ commandTransition: commandTransition,
64
+ traits: traits,
57
65
  readConsistency: "EscalateOnRetry"
58
66
  };
59
67
 
@@ -189,6 +197,8 @@ let AddProductMaker = StateChangeSlice_Builder$ReventlessLocal.Make({
189
197
  eventSchema: eventSchema,
190
198
  commandSchema: commandSchema,
191
199
  commandAuthorization: commandAuthorization,
200
+ commandTransition: commandTransition,
201
+ traits: traits,
192
202
  readConsistency: "EscalateOnRetry"
193
203
  })({
194
204
  initialState: false,
@@ -120,24 +120,24 @@ describe("PluginBehavior:", () => {
120
120
  // ── Admin deactivate / activate ─────────────────────────────────────────────
121
121
  test("Deactivate the current version", () =>
122
122
  givenEvents([VersionConnected(pluginDefinition)])
123
- ->whenCmd(Deactivate("1"))
123
+ ->whenCmd(Deactivate({version: "1"}))
124
124
  ->thenEvents([VersionDeactivated(pluginDefinition)])
125
125
  )
126
126
 
127
127
  test("Activate a deactivated version", () =>
128
128
  givenEvents([VersionConnected(pluginDefinition), VersionDeactivated(pluginDefinition)])
129
- ->whenCmd(Activate("1"))
129
+ ->whenCmd(Activate({version: "1"}))
130
130
  ->thenEvents([VersionActivated(pluginDefinition)])
131
131
  )
132
132
 
133
133
  test("Activate an unknown version errors", () =>
134
- givenEvents([])->whenCmd(Activate("9"))->thenError(UnknownVersion)
134
+ givenEvents([])->whenCmd(Activate({version: "9"}))->thenError(UnknownVersion)
135
135
  )
136
136
 
137
137
  // ── Manual retire + un-retire (decision A) ─────────────────────────────────
138
138
  test("Retire the current version", () =>
139
139
  givenEvents([VersionConnected(pluginDefinition)])
140
- ->whenCmd(Retire("1"))
140
+ ->whenCmd(Retire({version: "1"}))
141
141
  ->thenEvents([VersionRetired(pluginDefinition)])
142
142
  )
143
143
 
@@ -149,7 +149,7 @@ describe("PluginBehavior:", () => {
149
149
 
150
150
  test("Un-retire: admin Activate revives a retired version", () =>
151
151
  givenEvents([VersionConnected(pluginDefinition), VersionRetired(pluginDefinition)])
152
- ->whenCmd(Activate("1"))
152
+ ->whenCmd(Activate({version: "1"}))
153
153
  ->thenEvents([VersionActivated(pluginDefinition)])
154
154
  )
155
155
 
@@ -218,7 +218,7 @@ PluginTest.describe("PluginBehavior:", () => {
218
218
  _0: Plugin_Fixtures$ReventlessLocal.pluginDefinition
219
219
  }]), {
220
220
  TAG: "Deactivate",
221
- _0: "1"
221
+ version: "1"
222
222
  }), [{
223
223
  TAG: "VersionDeactivated",
224
224
  _0: Plugin_Fixtures$ReventlessLocal.pluginDefinition
@@ -234,21 +234,21 @@ PluginTest.describe("PluginBehavior:", () => {
234
234
  }
235
235
  ]), {
236
236
  TAG: "Activate",
237
- _0: "1"
237
+ version: "1"
238
238
  }), [{
239
239
  TAG: "VersionActivated",
240
240
  _0: Plugin_Fixtures$ReventlessLocal.pluginDefinition
241
241
  }]));
242
242
  PluginTest.test("Activate an unknown version errors", () => PluginTest.thenError(PluginTest.whenCmd(PluginTest.givenEvents([]), {
243
243
  TAG: "Activate",
244
- _0: "9"
244
+ version: "9"
245
245
  }), "UnknownVersion"));
246
246
  PluginTest.test("Retire the current version", () => PluginTest.thenEvents(PluginTest.whenCmd(PluginTest.givenEvents([{
247
247
  TAG: "VersionConnected",
248
248
  _0: Plugin_Fixtures$ReventlessLocal.pluginDefinition
249
249
  }]), {
250
250
  TAG: "Retire",
251
- _0: "1"
251
+ version: "1"
252
252
  }), [{
253
253
  TAG: "VersionRetired",
254
254
  _0: Plugin_Fixtures$ReventlessLocal.pluginDefinition
@@ -277,7 +277,7 @@ PluginTest.describe("PluginBehavior:", () => {
277
277
  }
278
278
  ]), {
279
279
  TAG: "Activate",
280
- _0: "1"
280
+ version: "1"
281
281
  }), [{
282
282
  TAG: "VersionActivated",
283
283
  _0: Plugin_Fixtures$ReventlessLocal.pluginDefinition