@reventlessdev/reventless-infra 3.0.0-alpha.151 → 3.0.0-alpha.152

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,31 @@
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.152 (2026-08-27)
7
+
8
+ * feat(spec)!: reflect the command direction across a port, both halves ([f2fe258](https://github.com/ReventlessDev/reventless-core/commit/f2fe258d195b74f4a61488edee305665341020ea))
9
+ * feat(spec)!: drop the plugin protocol's reconnect event, which nothing published ([7549db6](https://github.com/ReventlessDev/reventless-core/commit/7549db6aac6ad3f94dbb8d72dac4b4e783756ad1))
10
+ * feat(spec)!: read the port's translation table off the mapping's arms ([956348a](https://github.com/ReventlessDev/reventless-core/commit/956348a9fcb256cfff9db51809bdc27d73360e6c))
11
+
12
+ ### BREAKING CHANGES
13
+
14
+ * `ExtensionPointMapping.Mapping` gains `acceptedCommands` and
15
+ `ExtensionMapping.Mapping` gains `issuedCommands`; both are derived, so a
16
+ mapping the ppx can read needs no source change, and one it cannot names itself
17
+ at compile time. Definitions persisted before the two new def fields must be
18
+ re-emitted before a consumer can read them as present — and until then they
19
+ decode as None, which means unknown, not "issues nothing".
20
+ * `PluginExtensionPointSpec.event` no longer declares
21
+ `PluginReconnected`. An extension matching on it was matching an event it could
22
+ never receive; drop the arm.
23
+ * `ExtensionPointMapping.Mapping` requires `publishedEvents` and
24
+ `ExtensionMapping.Mapping` requires `handledEvents`; the ppx injects both for
25
+ mappings it can read, so app code must build against the matching ppx. Plugin
26
+ definitions persisted before the new fields must be re-emitted before a consumer
27
+ reads them as present.
28
+
29
+
30
+
6
31
  # 3.0.0-alpha.151 (2026-08-23)
7
32
 
8
33
  **Note:** Version bump only for package @reventlessdev/reventless-infra
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-infra",
3
- "version": "3.0.0-alpha.151",
3
+ "version": "3.0.0-alpha.152",
4
4
  "description": "Infrastructure types for Reventless framework",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -18,8 +18,8 @@
18
18
  "uuid": "^13.0.0",
19
19
  "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
20
20
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
21
- "@reventlessdev/reventless-spec": "3.0.0-alpha.123",
22
- "@reventlessdev/rescript-uuid": "2.0.0-alpha.0"
21
+ "@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
22
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.124"
23
23
  },
24
24
  "devDependencies": {
25
25
  "rescript": "12.3.0",
@@ -1,8 +1,5 @@
1
- /**
2
- A pre-serialized command routed to a foreign extension point.
3
- Used when an extension needs to dispatch to an extension point it does not
4
- own — the command JSON is forwarded opaquely without re-encoding.
5
- */
1
+ /** A command routed to an extension point this extension does not own —
2
+ forwarded opaquely, without re-encoding. */
6
3
  type forwardCommand = {
7
4
  extensionPointName: string,
8
5
  id: string,
@@ -11,18 +8,9 @@ type forwardCommand = {
11
8
 
12
9
  type id = string
13
10
 
14
- /**
15
- Actions returned by an extension's `mapIncomingEvent` function.
16
-
17
- When an extension point emits an event, the extension's mapping can:
18
- - publish a command to the aggregate it wraps (`PublishAggregateCommand`)
19
- - publish a command to the StateChangeSlice it wraps (`PublishStateChangeSliceCommand`)
20
- — no id argument; the framework derives the FIFO grouping id from the command's
21
- `@partitionTag` (or `@compositePartitionTag`) field.
22
- - publish a command back to the extension point (`PublishExtensionPointCommand`)
23
- - forward a command to another extension point opaquely (`ForwardCommand`)
24
- - handle an extension-point-defined directive via an async handler (`HandleDirective`)
25
- */
11
+ /** What `mapIncomingEvent` can do with a published event: command the wrapped
12
+ aggregate or slice, command the extension point, forward, or run a directive.
13
+ The slice forms take no id — the FIFO group comes from `@partitionTag`. */
26
14
  type incomingCommandAction<'aggregateCommand, 'extensionPointCommand, 'directive> =
27
15
  | PublishAggregateCommand(id, 'aggregateCommand)
28
16
  | PublishAggregateCommandAsync(promise<(id, 'aggregateCommand)>)
@@ -34,26 +22,14 @@ type incomingCommandAction<'aggregateCommand, 'extensionPointCommand, 'directive
34
22
  | ForwardCommand(forwardCommand)
35
23
  | HandleDirective(Reventless.Handler.handler<'directive>, 'directive)
36
24
 
37
- /**
38
- Actions returned by an extension's `mapOutgoingEvent` function.
39
-
40
- When the wrapped aggregate emits an event, the extension can:
41
- - publish a command to the extension point (`PublishExtensionPointCommand`)
42
- - forward a command to another extension point opaquely (`ForwardCommand`)
43
- - handle an extension-point-defined directive via an async handler (`HandleDirective`)
44
- */
25
+ /** What `mapOutgoingEvent` can do with a delegate event: command the extension
26
+ point, forward, or run a directive. */
45
27
  type outgoingCommandAction<'extensionPointCommand, 'directive> =
46
28
  | PublishExtensionPointCommand(id, 'extensionPointCommand)
47
29
  | ForwardCommand(forwardCommand)
48
30
  | HandleDirective(Reventless.Handler.handler<'directive>, 'directive)
49
31
 
50
- /**
51
- Maps an extension point event to actions on the wrapped aggregate or extension point.
52
-
53
- Called when the extension point emits an event that this extension handles.
54
- Receives the entity ID, the event, message metadata, the plugin definition,
55
- and the query engine.
56
- */
32
+ /** Maps a published event to actions on the wrapped delegate or the extension point. */
57
33
  type mapIncomingEvent<
58
34
  'extensionPointEvent,
59
35
  'aggregateCommand,
@@ -69,12 +45,8 @@ type mapIncomingEvent<
69
45
  incomingCommandAction<'aggregateCommand, 'extensionPointCommand, 'extensionPointDirective>,
70
46
  >
71
47
 
72
- /**
73
- Maps an aggregate event to actions on the extension point.
74
-
75
- Optionally defined — return `None` if the aggregate's outgoing events do not
76
- need to be reflected back through the extension point.
77
- */
48
+ /** Maps a delegate event back to actions on the extension point. `None` when
49
+ nothing flows back. */
78
50
  type mapOutgoingEvent<'aggregateEvent, 'extensionPointCommand, 'extensionPointDirective> = (
79
51
  string,
80
52
  'aggregateEvent,
@@ -82,11 +54,8 @@ type mapOutgoingEvent<'aggregateEvent, 'extensionPointCommand, 'extensionPointDi
82
54
  Reventless.Plugin.pluginDefinition,
83
55
  ) => array<outgoingCommandAction<'extensionPointCommand, 'extensionPointDirective>>
84
56
 
85
- /**
86
- The extension point protocol that this `Extension` connects to.
87
- Mirrors `ExtensionPoint.Spec` so the extension can be type-checked
88
- against the extension point's command / event / directive types.
89
- */
57
+ /** The extension point protocol this `Extension` connects to — mirrors
58
+ `ExtensionPoint.Spec` so the mapping type-checks against it. */
90
59
  module type Spec = {
91
60
  let name: string
92
61
  let moduleUrl: string
@@ -99,30 +68,35 @@ module type Spec = {
99
68
  type directive
100
69
  }
101
70
 
102
- /**
103
- Application-level implementation of an extension's bidirectional mapping.
71
+ /** One published event this extension handles and the commands it routes to —
72
+ the subscriber's half of `ExtensionPointMapping.publishedEvent`. Bare names,
73
+ resolved against the `Delegate`'s commands first, the EP's second. */
74
+ type handledEvent = {
75
+ name: string,
76
+ toCommandTypes: array<string>,
77
+ }
104
78
 
105
- - `ExtensionPoint` the extension point protocol this extension connects to
106
- - `Delegate` — the component this extension delegates to (aggregate or DCB slice)
107
- - `mapIncomingEvent` routes extension point events to delegate commands
108
- - `mapOutgoingEvent` optionally routes delegate events back to the EP
109
- */
79
+ /** One command this extension sends back to the port and the `Delegate` events
80
+ producing it — the subscriber's half of `ExtensionPointMapping.acceptedCommand`.
81
+ Read off `mapOutgoingEvent` only: an EP command published from an arm of
82
+ `mapIncomingEvent` is an event→command edge and stays in `handledEvent`. */
83
+ type issuedCommand = {
84
+ name: string,
85
+ fromEventTypes: array<string>,
86
+ }
87
+
88
+ /** An extension's bidirectional mapping between one extension point and one
89
+ delegate (aggregate or DCB slice). */
110
90
  module type Mapping = {
111
91
  module ExtensionPoint: Spec
112
92
  module Delegate: Reventless.Aggregate.Spec
113
93
 
114
- // npm-style specifier of the user extension file (the module exporting this
115
- // Mapping). Used by Plugin_Helpers + the bundled Plugin EventCollector entry
116
- // point to dynamic-import the user mapping for runtime reconstruction of
117
- // mapIncomingEvent / mapOutgoingEvent. PPX-injected on @@reventless.extension
118
- // files as the same specifier as the file-level moduleUrl.
94
+ // The extension file's own url dynamic-imported at runtime to reconstruct the
95
+ // two mapping functions. Injected by `@@reventless.extension`.
119
96
  let moduleUrl: string
120
97
 
121
- // npm-style specifier of the Delegate's source module. Used by the bundled
122
- // Plugin EventCollector entry point to dynamic-import the Delegate spec at
123
- // cold start (Mapping.ExtensionPoint and Mapping.Delegate are erased in the
124
- // compiled .res.mjs export). PPX-injected on @@reventless.extension files
125
- // as `Delegate.moduleUrl`.
98
+ // The Delegate's url the EventCollector imports its spec at cold start, since
99
+ // the compiled export erases `Mapping.Delegate`.
126
100
  let delegateModuleUrl: string
127
101
 
128
102
  let mapIncomingEvent: mapIncomingEvent<
@@ -135,12 +109,18 @@ module type Mapping = {
135
109
  let mapOutgoingEvent: option<
136
110
  mapOutgoingEvent<Delegate.event, ExtensionPoint.command, ExtensionPoint.directive>,
137
111
  >
112
+
113
+ /** Which published event routes to which commands — see `handledEvent`. Derived
114
+ by the PPX from `mapIncomingEvent`'s arms; hand-written only where it says
115
+ it cannot read them. */
116
+ let handledEvents: array<handledEvent>
117
+
118
+ /** Which commands travel back to the port — see `issuedCommand`. Derived from
119
+ `mapOutgoingEvent`'s arms, under the same rule. */
120
+ let issuedCommands: array<issuedCommand>
138
121
  }
139
122
 
140
- /**
141
- A dummy target used when an extension does not wrap a real aggregate or slice.
142
- Satisfies `Aggregate.Spec` with unit command / event / error types.
143
- */
123
+ /** A stand-in for an extension that wraps no aggregate or slice. */
144
124
  module NoDelegate = {
145
125
  let name = "NoDelegate"
146
126
 
@@ -193,6 +173,14 @@ module type T = {
193
173
 
194
174
  let delegateName: string
195
175
 
176
+ // All carried through the functor: `Plugin_Structure` sees an extension only
177
+ // compiled, and `T` erases the Delegate's types, so the checks against the two
178
+ // tables need its command and event names rather than its schemas.
179
+ let handledEvents: array<handledEvent>
180
+ let issuedCommands: array<issuedCommand>
181
+ let delegateCommandNames: array<string>
182
+ let delegateEventNames: array<string>
183
+
196
184
  let mapIncomingEvent: (
197
185
  Reventless.Message.event'<string, ExtensionPoint.event>,
198
186
  pluginDefinition,
@@ -217,21 +205,18 @@ module Make = (MappingImpl: Mapping): (
217
205
  module Delegate = MappingImpl.Delegate
218
206
  let delegateName = Delegate.name
219
207
  let extensionPointName = Spec.name
208
+ let handledEvents = MappingImpl.handledEvents
209
+ let issuedCommands = MappingImpl.issuedCommands
210
+ let delegateCommandNames = Reventless.DcbTag.extractAllVariantNames(Delegate.commandSchema)
220
211
 
221
- // Variant TAGs the Delegate cares about — derived from the Delegate's event
222
- // schema at functor instantiation. Used to pre-filter incoming envelopes:
223
- // sibling variants on the source log (events the Delegate did not declare)
224
- // are silently skipped without any decode attempt.
225
- // extractAllVariantNames keeps payload-less variants (sury-compiled bare
226
- // `S.literal("Name")` strings) — the JSON envelope's `event` TAG still
227
- // carries the literal name, so the filter would otherwise drop them.
212
+ // Pre-filter for incoming envelopes: sibling variants the Delegate did not
213
+ // declare are skipped undecoded. Payload-less variants included the
214
+ // envelope's `event` TAG still carries their name.
228
215
  let acceptedTags = Reventless.DcbTag.extractAllVariantNames(Delegate.eventSchema)
216
+ let delegateEventNames = acceptedTags
229
217
 
230
- // Lazily-computed partition-tag derivation for `PublishStateChangeSliceCommand*`.
231
- // Derived from the Delegate's command schema; throws if no `@partitionTag` /
232
- // `@compositePartitionTag` annotation exists (i.e. the Delegate is an Aggregate,
233
- // not a StateChangeSlice — in which case the user should use
234
- // `PublishAggregateCommand` instead).
218
+ // Partition tag for `PublishStateChangeSliceCommand*`. Throws when the Delegate
219
+ // declares none an Aggregate, where `PublishAggregateCommand` is the right form.
235
220
  let derivedPartitionTagLazy = ref(None)
236
221
  let getDerivedPartitionTag = () =>
237
222
  switch derivedPartitionTagLazy.contents {
@@ -253,10 +238,8 @@ module Make = (MappingImpl: Mapping): (
253
238
  Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec)
254
239
  }
255
240
 
256
- // Carry `comp` as a structured Effect log annotation EffectLogger.install
257
- // (in reventless-core, wired at Lambda startup) lifts it to the top-level
258
- // JSON `comp` field. Without the unified logger installed, Effect's default
259
- // logger still renders the annotation, just less prettily.
241
+ // `comp` as an Effect log annotation; EffectLogger.install lifts it to the
242
+ // top-level JSON field.
260
243
  let compLog = (comp, msg) =>
261
244
  Effect.logInfo(msg)->Effect.annotateLogs("comp", comp)->Effect.runSync
262
245
 
@@ -378,9 +361,7 @@ module Make = (MappingImpl: Mapping): (
378
361
 
379
362
  let doMapOutgoingEvent = (mapOutgoingEventImpl, targetEvent'Json, pluginDef) => {
380
363
  let tag = variantTagOfEnvelope(targetEvent'Json)
381
- // Pre-filter by TAG: sibling variants from the source log that the Delegate
382
- // did not declare are not this mapping's concern — skip silently with no
383
- // decode attempt.
364
+ // Not this mapping's concern skip without decoding.
384
365
  if !(acceptedTags->Array.includes(tag)) {
385
366
  []
386
367
  } else {
@@ -47,6 +47,7 @@ function Make(MappingImpl) {
47
47
  let Delegate = MappingImpl.Delegate;
48
48
  let delegateName = Delegate.name;
49
49
  let extensionPointName = Spec.name;
50
+ let delegateCommandNames = DcbTag$Reventless.extractAllVariantNames(Delegate.commandSchema);
50
51
  let acceptedTags = DcbTag$Reventless.extractAllVariantNames(Delegate.eventSchema);
51
52
  let derivedPartitionTagLazy = {
52
53
  contents: undefined
@@ -248,6 +249,10 @@ function Make(MappingImpl) {
248
249
  }));
249
250
  return {
250
251
  delegateName: delegateName,
252
+ handledEvents: MappingImpl.handledEvents,
253
+ issuedCommands: MappingImpl.issuedCommands,
254
+ delegateCommandNames: delegateCommandNames,
255
+ delegateEventNames: acceptedTags,
251
256
  mapIncomingEvent: mapIncomingEvent,
252
257
  mapOutgoingEvent: mapOutgoingEvent
253
258
  };
@@ -1,10 +1,7 @@
1
1
  type extensionPointName = string
2
2
 
3
- /**
4
- An async handler for a typed extension-point directive. May call the scheduler
5
- or query engine as a side effect. Used as the handler argument in `HandleDirective`
6
- on both `commandAction` and `eventAction`.
7
- */
3
+ /** An async handler for a typed directive, used by `HandleDirective` on both
4
+ `commandAction` and `eventAction`. */
8
5
  type directiveHandler<'directive> = (
9
6
  Reventless.Schedule.create,
10
7
  Reventless.Schedule.delete,
@@ -12,37 +9,20 @@ type directiveHandler<'directive> = (
12
9
  'directive,
13
10
  ) => promise<unit>
14
11
 
15
- /**
16
- Actions returned by `mapIncomingCommand` what to do when the extension point
17
- receives a command from an extension.
18
-
19
- - `PublishCommand(id, cmd)` — publish a command to the wrapped aggregate
20
- - `HandleDirective(handler, directive)` — invoke an async handler for an
21
- extension-point-defined directive
22
- */
23
- /* these actions are needed for Mapping */
12
+ /** What `mapIncomingCommand` can do with a command an extension published:
13
+ publish one to the wrapped aggregate, or run a directive handler. */
24
14
  type commandAction<'command, 'directive> =
25
15
  | PublishCommand(string, 'command)
26
16
  | HandleDirective(directiveHandler<'directive>, 'directive)
27
17
 
28
- /**
29
- Actions returned by `mapOutgoingEvent` what to do when the wrapped aggregate
30
- emits an event that should be reflected through the extension point.
31
-
32
- - `PublishEvent(id, event)` — synchronously emit an extension point event
33
- - `PublishEventAsync(promise)` — resolve a promise and emit the resulting event
34
- - `HandleDirective(handler, directive)` — invoke an async handler for an
35
- extension-point-defined directive
36
- */
18
+ /** What `mapOutgoingEvent` can do with a Delegate event: publish an EP event,
19
+ publish one behind a promise, or run a directive handler. */
37
20
  type eventAction<'event, 'directive> =
38
21
  | PublishEvent(string, 'event)
39
22
  | PublishEventAsync(promise<(string, 'event)>)
40
23
  | HandleDirective(directiveHandler<'directive>, 'directive)
41
24
 
42
- /**
43
- The extension point protocol — defines the command, event, and directive types
44
- that extensions and aggregates exchange through this extension point.
45
- */
25
+ /** The extension point protocol: the command, event and directive types crossing it. */
46
26
  module type Spec = {
47
27
  let name: string
48
28
  let moduleUrl: string
@@ -55,26 +35,14 @@ module type Spec = {
55
35
  type directive
56
36
  }
57
37
 
58
- /**
59
- Maps an incoming extension point command to zero or more aggregate commands
60
- (or side-effect calls).
61
-
62
- Called when an extension publishes a command to this extension point.
63
- Receives the entity ID, the command, and the message metadata.
64
- */
38
+ /** Maps a command an extension published to zero or more aggregate commands. */
65
39
  type mapIncomingCommand<'extensionPointCommand, 'aggregateCommand, 'extensionPointDirective> = (
66
40
  string,
67
41
  'extensionPointCommand,
68
42
  Reventless.Message.meta,
69
43
  ) => array<commandAction<'aggregateCommand, 'extensionPointDirective>>
70
44
 
71
- /**
72
- Maps an aggregate outgoing event to zero or more extension point events
73
- (or side-effect calls).
74
-
75
- Called when the wrapped aggregate emits an event. Receives the entity ID,
76
- the event, message metadata, and the query engine.
77
- */
45
+ /** Maps an aggregate event to zero or more extension point events. */
78
46
  type mapOutgoingEvent<'aggregateEvent, 'extensionPointEvent, 'extensionPointDirective> = (
79
47
  string,
80
48
  'aggregateEvent,
@@ -82,22 +50,30 @@ type mapOutgoingEvent<'aggregateEvent, 'extensionPointEvent, 'extensionPointDire
82
50
  Reventless.QueryEngine.operations,
83
51
  ) => array<eventAction<'extensionPointEvent, 'extensionPointDirective>>
84
52
 
85
- /**
86
- Application-level implementation of the command / event mapping for one
87
- aggregate connected to an extension point.
53
+ /** One published event of this port and the `Delegate` events producing it. Bare
54
+ constructor names, qualified downstream by `Plugin_Structure`. Per published
55
+ event, so many-to-one the case a port exists for — reads naturally. */
56
+ type publishedEvent = {
57
+ name: string,
58
+ fromEventTypes: array<string>,
59
+ }
60
+
61
+ /** The port's inbound half: one command this port takes and the `Delegate`
62
+ commands it routes to. Keyed by the arriving command, mirroring
63
+ `ExtensionMapping.handledEvent`. */
64
+ type acceptedCommand = {
65
+ name: string,
66
+ toCommandTypes: array<string>,
67
+ }
88
68
 
89
- Pass this to `ExtensionPointMapping.Make(Spec, Mapping)` to produce a compiled
90
- `ExtensionPointMapping.T` module.
91
- */
69
+ /** One aggregate's mapping to an extension point. Pass to
70
+ `ExtensionPointMapping.Make` for the compiled `T`. */
92
71
  module type Mapping = {
93
72
  module ExtensionPoint: Spec
94
73
  module Delegate: Reventless.Aggregate.Spec
95
74
 
96
- // Module URL of the mapping file (e.g. catalog/src/ExtensionPoint/
97
- // Products_ExtensionPointMapping.res.mjs). Distinct from ExtensionPoint.moduleUrl
98
- // (the spec, in catalog-spec). Auto-injected by `@@reventless.spec` on
99
- // ExtensionPointMapping files. The EventCollector runtime needs THIS url
100
- // (not the spec's) to dynamic-import the mapping file's mapOutgoingEvent.
75
+ // The mapping file's own url, not the spec's the EventCollector runtime
76
+ // dynamic-imports mapOutgoingEvent from it. Injected by `@@reventless.spec`.
101
77
  let moduleUrl: string
102
78
 
103
79
  let mapIncomingCommand: mapIncomingCommand<
@@ -109,10 +85,17 @@ module type Mapping = {
109
85
  let mapOutgoingEvent: option<
110
86
  mapOutgoingEvent<Delegate.event, ExtensionPoint.event, ExtensionPoint.directive>,
111
87
  >
88
+
89
+ /** The port's translation table — see `publishedEvent`. Derived by the PPX from
90
+ `mapOutgoingEvent`'s own arms; write it by hand only where it says it cannot. */
91
+ let publishedEvents: array<publishedEvent>
92
+
93
+ /** The same for the command direction — see `acceptedCommand`. Derived from
94
+ `mapIncomingCommand`'s arms, under the same rule. */
95
+ let acceptedCommands: array<acceptedCommand>
112
96
  }
113
97
 
114
- // Internal pre-compiled action types used by the ExtensionPoint runtime.
115
- // Created by ExtensionPointMapping.Make (in reventless); consumed by ExtensionPoint_Callback
98
+ // Pre-compiled action types: made by Make, consumed by ExtensionPoint_Callback
116
99
  // and ExtensionPoint_Operations.
117
100
 
118
101
  /** Internal runtime action produced after pre-encoding a `commandAction`. Not for direct use. */
@@ -126,25 +109,15 @@ type abstractEventAction<'extensionPointEvent> =
126
109
  | AbstractPublishEventAsync(promise<(string, Reventless.Message.meta, JSON.t)>)
127
110
  | AbstractHandleDirective(unit => promise<unit>)
128
111
 
129
- /**
130
- A pre-compiled mapping module produced by `ExtensionPointMapping.Make(Spec, Mapping)`.
131
-
132
- The runtime uses `mapIncomingCommands` and `mapOutgoingEvent` to dispatch commands
133
- and events without knowing the concrete extension point or aggregate types.
134
- Application developers call `Make` themselves; the result satisfies this type.
135
- */
136
- // Pre-compiled mapping module type. Created by ExtensionPointMapping.Make(Spec, Mapping).
137
- // App developers call Make themselves; the result satisfies this type.
112
+ /** A compiled mapping, produced by `Make`. Lets the runtime dispatch without
113
+ knowing the concrete extension point or aggregate types. */
138
114
  module type T = {
139
115
  module ExtensionPoint: Spec
140
116
 
141
117
  /** Name of the target this mapping connects to the extension point. */
142
118
  let delegateName: string
143
119
 
144
- /**
145
- Converts a batch of typed extension point commands into pre-encoded abstract actions.
146
- Called by the extension point runtime for each incoming command batch.
147
- */
120
+ /** Pre-encodes a batch of typed EP commands for the runtime. */
148
121
  let mapIncomingCommands: (
149
122
  array<CommandTopic.topicItem<Reventless.Message.command'<Reventless.Id.String.t, ExtensionPoint.command>>>,
150
123
  Reventless.Schedule.create,
@@ -152,10 +125,7 @@ module type T = {
152
125
  Reventless.QueryEngine.operations,
153
126
  ) => array<abstractCommandAction>
154
127
 
155
- /**
156
- Converts a raw aggregate event JSON into pre-encoded abstract event actions.
157
- `None` if this mapping does not produce outgoing extension point events.
158
- */
128
+ /** Pre-encodes a raw aggregate event JSON. `None` if nothing is published out. */
159
129
  let mapOutgoingEvent: option<
160
130
  (
161
131
  JSON.t,
@@ -174,20 +144,13 @@ module Make = (MappingImpl: Mapping): (
174
144
  let delegateName = Delegate.name
175
145
  let extensionPointName = Spec.name
176
146
 
177
- // Variant TAGs the Delegate cares about — derived from the Delegate's event
178
- // schema at functor instantiation. Used to pre-filter incoming envelopes:
179
- // sibling variants on the source log (events the Delegate did not declare)
180
- // are silently skipped without any decode attempt.
181
- // Pre-filter incoming envelopes against the Delegate's full constructor
182
- // set — includes payload-less variants (e.g. UnknownPluginDetected
183
- // compiled to `S.literal("…")`) since the JSON envelope's `event` TAG
184
- // still carries the literal name even when the variant has no payload.
147
+ // Pre-filter for incoming envelopes: sibling variants the Delegate did not
148
+ // declare are skipped undecoded. Payload-less variants included the
149
+ // envelope's `event` TAG still carries their name.
185
150
  let acceptedTags = Reventless.DcbTag.extractAllVariantNames(Delegate.eventSchema)
186
151
 
187
- // Carry `comp` as a structured Effect log annotation EffectLogger.install
188
- // (in reventless-core, wired at Lambda startup) lifts it to the top-level
189
- // JSON `comp` field. Without the unified logger installed, Effect's default
190
- // logger still renders the annotation, just less prettily.
152
+ // `comp` as an Effect log annotation; EffectLogger.install lifts it to the
153
+ // top-level JSON field.
191
154
  let compLog = (comp, msg) =>
192
155
  Effect.logInfo(msg)->Effect.annotateLogs("comp", comp)->Effect.runSync
193
156
 
@@ -248,9 +211,7 @@ module Make = (MappingImpl: Mapping): (
248
211
  queryEngine,
249
212
  ) => {
250
213
  let tag = variantTagOfEnvelope(targetEventJson')
251
- // Pre-filter by TAG: sibling variants from the source log that the Delegate
252
- // did not declare are not this mapping's concern — skip silently with no
253
- // decode attempt.
214
+ // Not this mapping's concern skip without decoding.
254
215
  if !(acceptedTags->Array.includes(tag)) {
255
216
  []
256
217
  } else {
@@ -37,8 +37,10 @@ type event =
37
37
  // Emitted when a connecting plugin declared incompatible protocol versions.
38
38
  // The plugin is still connected; this event gives operators visibility.
39
39
  | IncompatiblePlugin(pluginDefinition)
40
+ // One fact for both arrivals, because the Plugin aggregate has one: per-version
41
+ // tracking made `VersionConnected` replace Connected/Reconnected, and a
42
+ // subscriber does the same work either way.
40
43
  | PluginConnected(pluginDefinition)
41
- | PluginReconnected(pluginDefinition)
42
44
  | PluginDisconnected(pluginDefinition)
43
45
  | PluginDeactivated(pluginDefinition)
44
46
  | PluginActivated(pluginDefinition)
@@ -45,10 +45,6 @@ let eventSchema = Sury.union([
45
45
  TAG: "PluginConnected",
46
46
  _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
47
47
  })),
48
- Sury.$schema(s => ({
49
- TAG: "PluginReconnected",
50
- _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
51
- })),
52
48
  Sury.$schema(s => ({
53
49
  TAG: "PluginDisconnected",
54
50
  _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
@@ -153,6 +149,22 @@ let outboundTranslationSliceDefSchema = Plugin$Reventless.outboundTranslationSli
153
149
 
154
150
  let inboundTranslationSliceDefSchema = Plugin$Reventless.inboundTranslationSliceDefSchema;
155
151
 
152
+ let publishedEventDefSchema = Plugin$Reventless.publishedEventDefSchema;
153
+
154
+ let publishedEventDefArrayOptionSchema = Plugin$Reventless.publishedEventDefArrayOptionSchema;
155
+
156
+ let acceptedCommandDefSchema = Plugin$Reventless.acceptedCommandDefSchema;
157
+
158
+ let acceptedCommandDefArrayOptionSchema = Plugin$Reventless.acceptedCommandDefArrayOptionSchema;
159
+
160
+ let handledEventDefSchema = Plugin$Reventless.handledEventDefSchema;
161
+
162
+ let handledEventDefArrayOptionSchema = Plugin$Reventless.handledEventDefArrayOptionSchema;
163
+
164
+ let issuedCommandDefSchema = Plugin$Reventless.issuedCommandDefSchema;
165
+
166
+ let issuedCommandDefArrayOptionSchema = Plugin$Reventless.issuedCommandDefArrayOptionSchema;
167
+
156
168
  let extensionDefSchema = Plugin$Reventless.extensionDefSchema;
157
169
 
158
170
  let extensionPointDefSchema = Plugin$Reventless.extensionPointDefSchema;
@@ -200,6 +212,14 @@ export {
200
212
  automationSliceDefSchema,
201
213
  outboundTranslationSliceDefSchema,
202
214
  inboundTranslationSliceDefSchema,
215
+ publishedEventDefSchema,
216
+ publishedEventDefArrayOptionSchema,
217
+ acceptedCommandDefSchema,
218
+ acceptedCommandDefArrayOptionSchema,
219
+ handledEventDefSchema,
220
+ handledEventDefArrayOptionSchema,
221
+ issuedCommandDefSchema,
222
+ issuedCommandDefArrayOptionSchema,
203
223
  extensionDefSchema,
204
224
  extensionPointDefSchema,
205
225
  extensionPointDefArrayOptionSchema,