@reventlessdev/reventless-infra 3.0.0-alpha.100
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 +853 -0
- package/LICENSE +202 -0
- package/README.md +92 -0
- package/package.json +46 -0
- package/rescript.json +34 -0
- package/src/adapter/Adapter.res +88 -0
- package/src/adapter/Adapter.res.mjs +29 -0
- package/src/components/Aggregate.res +73 -0
- package/src/components/Aggregate.res.mjs +2 -0
- package/src/components/Api.res +120 -0
- package/src/components/Api.res.mjs +31 -0
- package/src/components/Api_Adapter.res +29 -0
- package/src/components/Api_Adapter.res.mjs +2 -0
- package/src/components/AutomationSlice.res +48 -0
- package/src/components/AutomationSlice.res.mjs +2 -0
- package/src/components/CommandGenerator.res +8 -0
- package/src/components/CommandGenerator.res.mjs +2 -0
- package/src/components/CommandTopic.res +70 -0
- package/src/components/CommandTopic.res.mjs +2 -0
- package/src/components/Component.js +56 -0
- package/src/components/Component.mjs +10 -0
- package/src/components/Component.res +90 -0
- package/src/components/Component.res.mjs +57 -0
- package/src/components/Component.resi +21 -0
- package/src/components/Counter.res +81 -0
- package/src/components/Counter.res.mjs +2 -0
- package/src/components/DcbEventLog.res +130 -0
- package/src/components/DcbEventLog.res.mjs +2 -0
- package/src/components/DeployBootstrap.res +83 -0
- package/src/components/DeployBootstrap.res.mjs +69 -0
- package/src/components/EventCollector.res +19 -0
- package/src/components/EventCollector.res.mjs +2 -0
- package/src/components/EventLog.res +24 -0
- package/src/components/EventLog.res.mjs +2 -0
- package/src/components/EventMapper.res +37 -0
- package/src/components/EventMapper.res.mjs +2 -0
- package/src/components/EventTopic.res +51 -0
- package/src/components/EventTopic.res.mjs +2 -0
- package/src/components/Extension.res +64 -0
- package/src/components/Extension.res.mjs +2 -0
- package/src/components/ExtensionPoint.res +62 -0
- package/src/components/ExtensionPoint.res.mjs +2 -0
- package/src/components/Heartbeat.res +7 -0
- package/src/components/Heartbeat.res.mjs +2 -0
- package/src/components/InboundTranslationSlice.res +41 -0
- package/src/components/InboundTranslationSlice.res.mjs +2 -0
- package/src/components/OutboundTranslationSlice.res +44 -0
- package/src/components/OutboundTranslationSlice.res.mjs +2 -0
- package/src/components/Plugin.res +93 -0
- package/src/components/Plugin.res.mjs +2 -0
- package/src/components/QueryDb.res +48 -0
- package/src/components/QueryDb.res.mjs +33 -0
- package/src/components/ReadModel.res +56 -0
- package/src/components/ReadModel.res.mjs +2 -0
- package/src/components/Scheduler.res +32 -0
- package/src/components/Scheduler.res.mjs +2 -0
- package/src/components/StateChangeSlice.res +45 -0
- package/src/components/StateChangeSlice.res.mjs +2 -0
- package/src/components/StateViewSlice.res +38 -0
- package/src/components/StateViewSlice.res.mjs +2 -0
- package/src/components/Task.res +89 -0
- package/src/components/Task.res.mjs +2 -0
- package/src/types/ExtensionMapping.res +448 -0
- package/src/types/ExtensionMapping.res.mjs +252 -0
- package/src/types/ExtensionPointMapping.res +303 -0
- package/src/types/ExtensionPointMapping.res.mjs +116 -0
- package/src/types/Message.res +3 -0
- package/src/types/Message.res.mjs +2 -0
- package/src/types/NoEventMappings.res +25 -0
- package/src/types/NoEventMappings.res.mjs +17 -0
- package/src/types/Platform.res +269 -0
- package/src/types/Platform.res.mjs +2 -0
- package/src/types/PluginExtensionPointSpec.res +55 -0
- package/src/types/PluginExtensionPointSpec.res.mjs +209 -0
- package/src/types/ResourceNaming.res +12 -0
- package/src/types/ResourceNaming.res.mjs +2 -0
- package/tests/DeployBootstrapTest.res +72 -0
- package/tests/DeployBootstrapTest.res.mjs +100 -0
|
@@ -0,0 +1,448 @@
|
|
|
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
|
+
*/
|
|
6
|
+
type forwardCommand = {
|
|
7
|
+
extensionPointName: string,
|
|
8
|
+
id: string,
|
|
9
|
+
commandJson: JSON.t,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type id = string
|
|
13
|
+
|
|
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
|
+
*/
|
|
26
|
+
type incomingCommandAction<'aggregateCommand, 'extensionPointCommand, 'directive> =
|
|
27
|
+
| PublishAggregateCommand(id, 'aggregateCommand)
|
|
28
|
+
| PublishAggregateCommandAsync(promise<(id, 'aggregateCommand)>)
|
|
29
|
+
| PublishAggregateCommandsAsync(promise<array<(id, 'aggregateCommand)>>)
|
|
30
|
+
| PublishStateChangeSliceCommand('aggregateCommand)
|
|
31
|
+
| PublishStateChangeSliceCommandAsync(promise<'aggregateCommand>)
|
|
32
|
+
| PublishStateChangeSliceCommandsAsync(promise<array<'aggregateCommand>>)
|
|
33
|
+
| PublishExtensionPointCommand(id, 'extensionPointCommand)
|
|
34
|
+
| ForwardCommand(forwardCommand)
|
|
35
|
+
| HandleDirective(Reventless.Handler.handler<'directive>, 'directive)
|
|
36
|
+
|
|
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
|
+
*/
|
|
45
|
+
type outgoingCommandAction<'extensionPointCommand, 'directive> =
|
|
46
|
+
| PublishExtensionPointCommand(id, 'extensionPointCommand)
|
|
47
|
+
| ForwardCommand(forwardCommand)
|
|
48
|
+
| HandleDirective(Reventless.Handler.handler<'directive>, 'directive)
|
|
49
|
+
|
|
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
|
+
*/
|
|
57
|
+
type mapIncomingEvent<
|
|
58
|
+
'extensionPointEvent,
|
|
59
|
+
'aggregateCommand,
|
|
60
|
+
'extensionPointCommand,
|
|
61
|
+
'extensionPointDirective,
|
|
62
|
+
> = (
|
|
63
|
+
string,
|
|
64
|
+
'extensionPointEvent,
|
|
65
|
+
Reventless.Message.meta,
|
|
66
|
+
Reventless.Plugin.pluginDefinition,
|
|
67
|
+
Reventless.QueryEngine.operations,
|
|
68
|
+
) => array<
|
|
69
|
+
incomingCommandAction<'aggregateCommand, 'extensionPointCommand, 'extensionPointDirective>,
|
|
70
|
+
>
|
|
71
|
+
|
|
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
|
+
*/
|
|
78
|
+
type mapOutgoingEvent<'aggregateEvent, 'extensionPointCommand, 'extensionPointDirective> = (
|
|
79
|
+
string,
|
|
80
|
+
'aggregateEvent,
|
|
81
|
+
Reventless.Message.meta,
|
|
82
|
+
Reventless.Plugin.pluginDefinition,
|
|
83
|
+
) => array<outgoingCommandAction<'extensionPointCommand, 'extensionPointDirective>>
|
|
84
|
+
|
|
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
|
+
*/
|
|
90
|
+
module type Spec = {
|
|
91
|
+
let name: string
|
|
92
|
+
let moduleUrl: string
|
|
93
|
+
|
|
94
|
+
@schema
|
|
95
|
+
type command
|
|
96
|
+
@schema
|
|
97
|
+
type event
|
|
98
|
+
@schema
|
|
99
|
+
type directive
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
Application-level implementation of an extension's bidirectional mapping.
|
|
104
|
+
|
|
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
|
+
*/
|
|
110
|
+
module type Mapping = {
|
|
111
|
+
module ExtensionPoint: Spec
|
|
112
|
+
module Delegate: Reventless.Aggregate.Spec
|
|
113
|
+
|
|
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.
|
|
119
|
+
let moduleUrl: string
|
|
120
|
+
|
|
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`.
|
|
126
|
+
let delegateModuleUrl: string
|
|
127
|
+
|
|
128
|
+
let mapIncomingEvent: mapIncomingEvent<
|
|
129
|
+
ExtensionPoint.event,
|
|
130
|
+
Delegate.command,
|
|
131
|
+
ExtensionPoint.command,
|
|
132
|
+
ExtensionPoint.directive,
|
|
133
|
+
>
|
|
134
|
+
|
|
135
|
+
let mapOutgoingEvent: option<
|
|
136
|
+
mapOutgoingEvent<Delegate.event, ExtensionPoint.command, ExtensionPoint.directive>,
|
|
137
|
+
>
|
|
138
|
+
}
|
|
139
|
+
|
|
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
|
+
*/
|
|
144
|
+
module NoDelegate = {
|
|
145
|
+
let name = "NoDelegate"
|
|
146
|
+
|
|
147
|
+
module Id = {
|
|
148
|
+
@schema
|
|
149
|
+
type t = string
|
|
150
|
+
type input = string
|
|
151
|
+
external make: t => t = "%identity"
|
|
152
|
+
external makeFromString: string => t = "%identity"
|
|
153
|
+
external toString: t => t = "%identity"
|
|
154
|
+
let cmp = String.compare
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@schema
|
|
158
|
+
type command = unit
|
|
159
|
+
|
|
160
|
+
@schema
|
|
161
|
+
type event = unit
|
|
162
|
+
|
|
163
|
+
@schema
|
|
164
|
+
type error = unit
|
|
165
|
+
|
|
166
|
+
let commandSchema = S.unit
|
|
167
|
+
let moduleUrl: string = %raw(`import.meta.url`)
|
|
168
|
+
let commandAuthorization = (_: command): Reventless.Authorization.permission =>
|
|
169
|
+
AllowAuthenticated
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
open PluginExtensionPointSpec
|
|
174
|
+
|
|
175
|
+
type extensionPointName = string
|
|
176
|
+
|
|
177
|
+
/* these actions are internal to the Mapping Functor */
|
|
178
|
+
type abstractIncomingCommandAction =
|
|
179
|
+
| AbstractPublishAggregateCommand(string, Reventless.Message.commandJson)
|
|
180
|
+
| AbstractPublishAggregateCommandAsync(promise<(string, Reventless.Message.commandJson)>)
|
|
181
|
+
| AbstractPublishAggregateCommandsAsync(promise<array<(string, Reventless.Message.commandJson)>>)
|
|
182
|
+
| AbstractPublishPluginExtensionPointCommand(Reventless.Message.commandJson)
|
|
183
|
+
| AbstractPublishExtensionPointCommand(extensionPointName, Reventless.Message.commandJson)
|
|
184
|
+
| AbstractHandleDirective(Reventless.Handler.handler<unit>)
|
|
185
|
+
|
|
186
|
+
type abstractOutgoingCommandAction =
|
|
187
|
+
| AbstractPublishPluginExtensionPointCommand(Reventless.Message.commandJson)
|
|
188
|
+
| AbstractPublishExtensionPointCommand(extensionPointName, Reventless.Message.commandJson)
|
|
189
|
+
| AbstractHandleDirective(Reventless.Handler.handler<unit>)
|
|
190
|
+
|
|
191
|
+
module type T = {
|
|
192
|
+
module ExtensionPoint: Spec
|
|
193
|
+
|
|
194
|
+
let delegateName: string
|
|
195
|
+
|
|
196
|
+
let mapIncomingEvent: (
|
|
197
|
+
Reventless.Message.event'<string, ExtensionPoint.event>,
|
|
198
|
+
pluginDefinition,
|
|
199
|
+
Reventless.QueryEngine.operations,
|
|
200
|
+
) => array<abstractIncomingCommandAction>
|
|
201
|
+
|
|
202
|
+
let mapOutgoingEvent: option<(JSON.t, pluginDefinition) => array<abstractOutgoingCommandAction>>
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
module type Mappings = {
|
|
206
|
+
module Spec: Spec
|
|
207
|
+
module type Mapping = T with module ExtensionPoint := Spec
|
|
208
|
+
let name: string
|
|
209
|
+
let moduleUrl: string
|
|
210
|
+
let mappings: array<module(Mapping)>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
module Make = (MappingImpl: Mapping): (
|
|
214
|
+
T with module ExtensionPoint := MappingImpl.ExtensionPoint
|
|
215
|
+
) => {
|
|
216
|
+
module Spec = MappingImpl.ExtensionPoint
|
|
217
|
+
module Delegate = MappingImpl.Delegate
|
|
218
|
+
let delegateName = Delegate.name
|
|
219
|
+
let extensionPointName = Spec.name
|
|
220
|
+
|
|
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.
|
|
228
|
+
let acceptedTags = Reventless.DcbTag.extractAllVariantNames(Delegate.eventSchema)
|
|
229
|
+
|
|
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).
|
|
235
|
+
let derivedPartitionTagLazy = ref(None)
|
|
236
|
+
let getDerivedPartitionTag = () =>
|
|
237
|
+
switch derivedPartitionTagLazy.contents {
|
|
238
|
+
| Some(d) => d
|
|
239
|
+
| None =>
|
|
240
|
+
let d = Reventless.DcbTag.derivePartitionTag([
|
|
241
|
+
(Delegate.name, Delegate.moduleUrl, Delegate.commandSchema->S.castToUnknown),
|
|
242
|
+
])
|
|
243
|
+
derivedPartitionTagLazy := Some(d)
|
|
244
|
+
d
|
|
245
|
+
}
|
|
246
|
+
let derivePartitionId = (targetCmd: Delegate.command): string =>
|
|
247
|
+
switch getDerivedPartitionTag() {
|
|
248
|
+
| Simple(pt) =>
|
|
249
|
+
let tags = Reventless.DcbTag.extractTags(Delegate.commandSchema, targetCmd)
|
|
250
|
+
Reventless.DcbTag.getPartitionTagValue([{tags: tags}], pt)->Option.getOr("")
|
|
251
|
+
| Composite(spec) =>
|
|
252
|
+
let tags = Reventless.DcbTag.extractTags(Delegate.commandSchema, targetCmd)
|
|
253
|
+
Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec)
|
|
254
|
+
}
|
|
255
|
+
|
|
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.
|
|
260
|
+
let compLog = (comp, msg) =>
|
|
261
|
+
Effect.logInfo(msg)->Effect.annotateLogs("comp", comp)->Effect.runSync
|
|
262
|
+
|
|
263
|
+
let encodeMeta = (meta: Reventless.Message.meta, service) => {
|
|
264
|
+
...meta,
|
|
265
|
+
service,
|
|
266
|
+
msgId: Message.uuid(),
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
let doMapIncomingEvent = (
|
|
270
|
+
mapIncomingEventImpl,
|
|
271
|
+
{Reventless.Message.id: id, event, meta},
|
|
272
|
+
pluginDef,
|
|
273
|
+
queryEngine,
|
|
274
|
+
) => {
|
|
275
|
+
let encodeTargetCommandJson = (targetCmd, targetId) => {
|
|
276
|
+
let cmdJson = targetCmd->Reventless.Message.encode(Delegate.commandSchema)
|
|
277
|
+
{
|
|
278
|
+
Reventless.Message.id: targetId,
|
|
279
|
+
meta: encodeMeta(meta, delegateName),
|
|
280
|
+
commandJson: cmdJson,
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let encodeExtensionPointCommandJson = (commandJson, ~id, ~extensionPointName, ~action) => {
|
|
285
|
+
compLog(`Extension(${extensionPointName})`, `${action}: ${commandJson->Reventless.Message.variantNameOfJson->Reventless.AnsiStyle.bold}(${id})`)
|
|
286
|
+
{
|
|
287
|
+
Reventless.Message.id,
|
|
288
|
+
meta: encodeMeta(meta, extensionPointName),
|
|
289
|
+
commandJson,
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
let encodeExtensionPointCommand = (command, ~id, ~extensionPointName, ~action) =>
|
|
294
|
+
command
|
|
295
|
+
->Reventless.Message.encode(Spec.commandSchema)
|
|
296
|
+
->encodeExtensionPointCommandJson(~id, ~extensionPointName, ~action)
|
|
297
|
+
|
|
298
|
+
mapIncomingEventImpl(id, event, meta, pluginDef, queryEngine)->Array.map(x =>
|
|
299
|
+
switch x {
|
|
300
|
+
| PublishAggregateCommand(targetId, targetCmd) =>
|
|
301
|
+
AbstractPublishAggregateCommand(
|
|
302
|
+
delegateName,
|
|
303
|
+
targetCmd->encodeTargetCommandJson(targetId),
|
|
304
|
+
)
|
|
305
|
+
| PublishAggregateCommandAsync(promise) =>
|
|
306
|
+
let toCommandJson = async promise => {
|
|
307
|
+
let (targetId, targetCmd) = await promise
|
|
308
|
+
(delegateName, targetCmd->encodeTargetCommandJson(targetId))
|
|
309
|
+
}
|
|
310
|
+
AbstractPublishAggregateCommandAsync(promise->toCommandJson)
|
|
311
|
+
| PublishAggregateCommandsAsync(promise) =>
|
|
312
|
+
let toCommandJsons = async promise =>
|
|
313
|
+
(await promise)->Array.map(((targetId, targetCmd)) => (
|
|
314
|
+
delegateName,
|
|
315
|
+
targetCmd->encodeTargetCommandJson(targetId),
|
|
316
|
+
))
|
|
317
|
+
AbstractPublishAggregateCommandsAsync(promise->toCommandJsons)
|
|
318
|
+
| PublishStateChangeSliceCommand(targetCmd) =>
|
|
319
|
+
AbstractPublishAggregateCommand(
|
|
320
|
+
delegateName,
|
|
321
|
+
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd)),
|
|
322
|
+
)
|
|
323
|
+
| PublishStateChangeSliceCommandAsync(promise) =>
|
|
324
|
+
let toCommandJson = async promise => {
|
|
325
|
+
let targetCmd = await promise
|
|
326
|
+
(delegateName, targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd)))
|
|
327
|
+
}
|
|
328
|
+
AbstractPublishAggregateCommandAsync(promise->toCommandJson)
|
|
329
|
+
| PublishStateChangeSliceCommandsAsync(promise) =>
|
|
330
|
+
let toCommandJsons = async promise =>
|
|
331
|
+
(await promise)->Array.map(targetCmd => (
|
|
332
|
+
delegateName,
|
|
333
|
+
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd)),
|
|
334
|
+
))
|
|
335
|
+
AbstractPublishAggregateCommandsAsync(promise->toCommandJsons)
|
|
336
|
+
| PublishExtensionPointCommand(id, command)
|
|
337
|
+
if Spec.name == PluginExtensionPointSpec.name =>
|
|
338
|
+
AbstractPublishPluginExtensionPointCommand(
|
|
339
|
+
command->encodeExtensionPointCommand(
|
|
340
|
+
~id,
|
|
341
|
+
~extensionPointName,
|
|
342
|
+
~action="Publish PluginExtensionPoint command",
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
| PublishExtensionPointCommand(id, command) =>
|
|
346
|
+
AbstractPublishExtensionPointCommand(
|
|
347
|
+
extensionPointName,
|
|
348
|
+
command->encodeExtensionPointCommand(
|
|
349
|
+
~id,
|
|
350
|
+
~extensionPointName,
|
|
351
|
+
~action="Publish ExtensionPoint command",
|
|
352
|
+
),
|
|
353
|
+
)
|
|
354
|
+
| ForwardCommand({extensionPointName, id, commandJson}) =>
|
|
355
|
+
AbstractPublishExtensionPointCommand(
|
|
356
|
+
extensionPointName,
|
|
357
|
+
commandJson->encodeExtensionPointCommandJson(
|
|
358
|
+
~id,
|
|
359
|
+
~extensionPointName,
|
|
360
|
+
~action="Forward ExtensionPoint command",
|
|
361
|
+
),
|
|
362
|
+
)
|
|
363
|
+
| HandleDirective(handler, directive) =>
|
|
364
|
+
compLog(`Extension(${extensionPointName})`, "incoming directive")
|
|
365
|
+
AbstractHandleDirective(() => handler(directive))
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let mapIncomingEvent = doMapIncomingEvent(MappingImpl.mapIncomingEvent, ...)
|
|
371
|
+
|
|
372
|
+
let variantTagOfEnvelope = json =>
|
|
373
|
+
json
|
|
374
|
+
->JSON.Decode.object
|
|
375
|
+
->Option.flatMap(d => d->Dict.get("event"))
|
|
376
|
+
->Option.map(Reventless.Message.variantNameOfJson)
|
|
377
|
+
->Option.getOr("unknown")
|
|
378
|
+
|
|
379
|
+
let doMapOutgoingEvent = (mapOutgoingEventImpl, targetEvent'Json, pluginDef) => {
|
|
380
|
+
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.
|
|
384
|
+
if !(acceptedTags->Array.includes(tag)) {
|
|
385
|
+
[]
|
|
386
|
+
} else {
|
|
387
|
+
let {id, meta, event} =
|
|
388
|
+
targetEvent'Json->Reventless.Message.decodeEvent'(
|
|
389
|
+
Delegate.Id.schema,
|
|
390
|
+
Delegate.eventSchema,
|
|
391
|
+
)
|
|
392
|
+
let encodeExtensionPointCommandJson = (commandJson, ~id, ~extensionPointName, ~action) => {
|
|
393
|
+
compLog(`Extension(${delegateName})`, `${action}: ${commandJson->Reventless.Message.variantNameOfJson->Reventless.AnsiStyle.bold}(${id})`)
|
|
394
|
+
{
|
|
395
|
+
Reventless.Message.id,
|
|
396
|
+
meta: encodeMeta(meta, extensionPointName),
|
|
397
|
+
commandJson,
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
let encodeExtensionPointCommand = (command, ~id, ~extensionPointName, ~action) =>
|
|
402
|
+
command
|
|
403
|
+
->Reventless.Message.encode(Spec.commandSchema)
|
|
404
|
+
->encodeExtensionPointCommandJson(~id, ~extensionPointName, ~action)
|
|
405
|
+
|
|
406
|
+
mapOutgoingEventImpl(id->Delegate.Id.toString, event, meta, pluginDef)->Array.map(x =>
|
|
407
|
+
switch x {
|
|
408
|
+
| PublishExtensionPointCommand(id, command)
|
|
409
|
+
if Spec.name == PluginExtensionPointSpec.name =>
|
|
410
|
+
AbstractPublishPluginExtensionPointCommand(
|
|
411
|
+
command->encodeExtensionPointCommand(
|
|
412
|
+
~id,
|
|
413
|
+
~extensionPointName,
|
|
414
|
+
~action="Publish PluginExtensionPoint command",
|
|
415
|
+
),
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
| PublishExtensionPointCommand(id, command) =>
|
|
419
|
+
AbstractPublishExtensionPointCommand(
|
|
420
|
+
extensionPointName,
|
|
421
|
+
command->encodeExtensionPointCommand(
|
|
422
|
+
~id,
|
|
423
|
+
~extensionPointName,
|
|
424
|
+
~action="Publish ExtensionPoint command",
|
|
425
|
+
),
|
|
426
|
+
)
|
|
427
|
+
| ForwardCommand({extensionPointName, id, commandJson}) =>
|
|
428
|
+
AbstractPublishExtensionPointCommand(
|
|
429
|
+
extensionPointName,
|
|
430
|
+
commandJson->encodeExtensionPointCommandJson(
|
|
431
|
+
~id,
|
|
432
|
+
~extensionPointName,
|
|
433
|
+
~action="Forward ExtensionPoint command",
|
|
434
|
+
),
|
|
435
|
+
)
|
|
436
|
+
| HandleDirective(handler, directive) =>
|
|
437
|
+
compLog(`Extension(${delegateName})`, "outgoing directive")
|
|
438
|
+
AbstractHandleDirective(() => handler(directive))
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
let mapOutgoingEvent =
|
|
445
|
+
MappingImpl.mapOutgoingEvent->Option.map(mapOutgoingEventImpl =>
|
|
446
|
+
doMapOutgoingEvent(mapOutgoingEventImpl, ...)
|
|
447
|
+
)
|
|
448
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Uuid from "uuid";
|
|
5
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
9
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
10
|
+
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
11
|
+
import * as AnsiStyle$Reventless from "@reventlessdev/reventless-spec/src/AnsiStyle.res.mjs";
|
|
12
|
+
import * as PluginExtensionPointSpec$ReventlessInfra from "./PluginExtensionPointSpec.res.mjs";
|
|
13
|
+
|
|
14
|
+
let cmp = Primitive_string.compare;
|
|
15
|
+
|
|
16
|
+
let Id = {
|
|
17
|
+
schema: S.string,
|
|
18
|
+
cmp: cmp
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
let moduleUrl = import.meta.url;
|
|
22
|
+
|
|
23
|
+
function commandAuthorization() {
|
|
24
|
+
return "AllowAuthenticated";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let NoDelegate = {
|
|
28
|
+
name: "NoDelegate",
|
|
29
|
+
Id: Id,
|
|
30
|
+
eventSchema: S.unit,
|
|
31
|
+
errorSchema: S.unit,
|
|
32
|
+
commandSchema: S.unit,
|
|
33
|
+
moduleUrl: moduleUrl,
|
|
34
|
+
commandAuthorization: commandAuthorization
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function Make(MappingImpl) {
|
|
38
|
+
let Spec = MappingImpl.ExtensionPoint;
|
|
39
|
+
let Delegate = MappingImpl.Delegate;
|
|
40
|
+
let delegateName = Delegate.name;
|
|
41
|
+
let extensionPointName = Spec.name;
|
|
42
|
+
let acceptedTags = DcbTag$Reventless.extractAllVariantNames(Delegate.eventSchema);
|
|
43
|
+
let derivedPartitionTagLazy = {
|
|
44
|
+
contents: undefined
|
|
45
|
+
};
|
|
46
|
+
let getDerivedPartitionTag = () => {
|
|
47
|
+
let d = derivedPartitionTagLazy.contents;
|
|
48
|
+
if (d !== undefined) {
|
|
49
|
+
return d;
|
|
50
|
+
}
|
|
51
|
+
let d$1 = DcbTag$Reventless.derivePartitionTag([[
|
|
52
|
+
Delegate.name,
|
|
53
|
+
Delegate.moduleUrl,
|
|
54
|
+
Delegate.commandSchema
|
|
55
|
+
]]);
|
|
56
|
+
derivedPartitionTagLazy.contents = d$1;
|
|
57
|
+
return d$1;
|
|
58
|
+
};
|
|
59
|
+
let derivePartitionId = targetCmd => {
|
|
60
|
+
let pt = getDerivedPartitionTag();
|
|
61
|
+
if (pt.TAG === "Simple") {
|
|
62
|
+
let tags = DcbTag$Reventless.extractTags(Delegate.commandSchema, targetCmd);
|
|
63
|
+
return Stdlib_Option.getOr(DcbTag$Reventless.getPartitionTagValue([{
|
|
64
|
+
tags: tags
|
|
65
|
+
}], pt._0), "");
|
|
66
|
+
}
|
|
67
|
+
let tags$1 = DcbTag$Reventless.extractTags(Delegate.commandSchema, targetCmd);
|
|
68
|
+
return DcbTag$Reventless.getCompositePartitionKeyValue(tags$1, pt._0);
|
|
69
|
+
};
|
|
70
|
+
let compLog = (comp, msg) => Effect.runSync(Effect.annotateLogs(Effect.logInfo(msg), "comp", comp));
|
|
71
|
+
let encodeMeta = (meta, service) => {
|
|
72
|
+
let newrecord = {...meta};
|
|
73
|
+
newrecord.msgId = Uuid.v4();
|
|
74
|
+
newrecord.service = service;
|
|
75
|
+
return newrecord;
|
|
76
|
+
};
|
|
77
|
+
let mapIncomingEvent = (extra, extra$1, extra$2) => {
|
|
78
|
+
let mapIncomingEventImpl = MappingImpl.mapIncomingEvent;
|
|
79
|
+
let meta = extra.meta;
|
|
80
|
+
let encodeTargetCommandJson = (targetCmd, targetId) => {
|
|
81
|
+
let cmdJson = Message$Reventless.encode(targetCmd, Delegate.commandSchema);
|
|
82
|
+
return {
|
|
83
|
+
id: targetId,
|
|
84
|
+
meta: encodeMeta(meta, delegateName),
|
|
85
|
+
commandJson: cmdJson
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
let encodeExtensionPointCommandJson = (commandJson, id, extensionPointName, action) => {
|
|
89
|
+
compLog(`Extension(` + extensionPointName + `)`, action + `: ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(commandJson)) + `(` + id + `)`);
|
|
90
|
+
return {
|
|
91
|
+
id: id,
|
|
92
|
+
meta: encodeMeta(meta, extensionPointName),
|
|
93
|
+
commandJson: commandJson
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
let encodeExtensionPointCommand = (command, id, extensionPointName, action) => encodeExtensionPointCommandJson(Message$Reventless.encode(command, Spec.commandSchema), id, extensionPointName, action);
|
|
97
|
+
return mapIncomingEventImpl(extra.id, extra.event, meta, extra$1, extra$2).map(x => {
|
|
98
|
+
switch (x.TAG) {
|
|
99
|
+
case "PublishAggregateCommand" :
|
|
100
|
+
return {
|
|
101
|
+
TAG: "AbstractPublishAggregateCommand",
|
|
102
|
+
_0: delegateName,
|
|
103
|
+
_1: encodeTargetCommandJson(x._1, x._0)
|
|
104
|
+
};
|
|
105
|
+
case "PublishAggregateCommandAsync" :
|
|
106
|
+
let toCommandJson = async promise => {
|
|
107
|
+
let match = await promise;
|
|
108
|
+
return [
|
|
109
|
+
delegateName,
|
|
110
|
+
encodeTargetCommandJson(match[1], match[0])
|
|
111
|
+
];
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
TAG: "AbstractPublishAggregateCommandAsync",
|
|
115
|
+
_0: toCommandJson(x._0)
|
|
116
|
+
};
|
|
117
|
+
case "PublishAggregateCommandsAsync" :
|
|
118
|
+
let toCommandJsons = async promise => (await promise).map(param => [
|
|
119
|
+
delegateName,
|
|
120
|
+
encodeTargetCommandJson(param[1], param[0])
|
|
121
|
+
]);
|
|
122
|
+
return {
|
|
123
|
+
TAG: "AbstractPublishAggregateCommandsAsync",
|
|
124
|
+
_0: toCommandJsons(x._0)
|
|
125
|
+
};
|
|
126
|
+
case "PublishStateChangeSliceCommand" :
|
|
127
|
+
let targetCmd = x._0;
|
|
128
|
+
return {
|
|
129
|
+
TAG: "AbstractPublishAggregateCommand",
|
|
130
|
+
_0: delegateName,
|
|
131
|
+
_1: encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd))
|
|
132
|
+
};
|
|
133
|
+
case "PublishStateChangeSliceCommandAsync" :
|
|
134
|
+
let toCommandJson$1 = async promise => {
|
|
135
|
+
let targetCmd = await promise;
|
|
136
|
+
return [
|
|
137
|
+
delegateName,
|
|
138
|
+
encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd))
|
|
139
|
+
];
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
TAG: "AbstractPublishAggregateCommandAsync",
|
|
143
|
+
_0: toCommandJson$1(x._0)
|
|
144
|
+
};
|
|
145
|
+
case "PublishStateChangeSliceCommandsAsync" :
|
|
146
|
+
let toCommandJsons$1 = async promise => (await promise).map(targetCmd => [
|
|
147
|
+
delegateName,
|
|
148
|
+
encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd))
|
|
149
|
+
]);
|
|
150
|
+
return {
|
|
151
|
+
TAG: "AbstractPublishAggregateCommandsAsync",
|
|
152
|
+
_0: toCommandJsons$1(x._0)
|
|
153
|
+
};
|
|
154
|
+
case "PublishExtensionPointCommand" :
|
|
155
|
+
let command = x._1;
|
|
156
|
+
let id = x._0;
|
|
157
|
+
if (Spec.name === PluginExtensionPointSpec$ReventlessInfra.name) {
|
|
158
|
+
return {
|
|
159
|
+
TAG: "AbstractPublishPluginExtensionPointCommand",
|
|
160
|
+
_0: encodeExtensionPointCommand(command, id, extensionPointName, "Publish PluginExtensionPoint command")
|
|
161
|
+
};
|
|
162
|
+
} else {
|
|
163
|
+
return {
|
|
164
|
+
TAG: "AbstractPublishExtensionPointCommand",
|
|
165
|
+
_0: extensionPointName,
|
|
166
|
+
_1: encodeExtensionPointCommand(command, id, extensionPointName, "Publish ExtensionPoint command")
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
case "ForwardCommand" :
|
|
170
|
+
let match = x._0;
|
|
171
|
+
let extensionPointName$1 = match.extensionPointName;
|
|
172
|
+
return {
|
|
173
|
+
TAG: "AbstractPublishExtensionPointCommand",
|
|
174
|
+
_0: extensionPointName$1,
|
|
175
|
+
_1: encodeExtensionPointCommandJson(match.commandJson, match.id, extensionPointName$1, "Forward ExtensionPoint command")
|
|
176
|
+
};
|
|
177
|
+
case "HandleDirective" :
|
|
178
|
+
let directive = x._1;
|
|
179
|
+
let handler = x._0;
|
|
180
|
+
compLog(`Extension(` + extensionPointName + `)`, "incoming directive");
|
|
181
|
+
return {
|
|
182
|
+
TAG: "AbstractHandleDirective",
|
|
183
|
+
_0: () => handler(directive)
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
let variantTagOfEnvelope = json => Stdlib_Option.getOr(Stdlib_Option.map(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(json), d => d["event"]), Message$Reventless.variantNameOfJson), "unknown");
|
|
189
|
+
let mapOutgoingEvent = Stdlib_Option.map(MappingImpl.mapOutgoingEvent, mapOutgoingEventImpl => ((extra, extra$1) => {
|
|
190
|
+
let tag = variantTagOfEnvelope(extra);
|
|
191
|
+
if (!acceptedTags.includes(tag)) {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
let match = Message$Reventless.decodeEvent$p(extra, Delegate.Id.schema, Delegate.eventSchema);
|
|
195
|
+
let meta = match.meta;
|
|
196
|
+
let encodeExtensionPointCommandJson = (commandJson, id, extensionPointName, action) => {
|
|
197
|
+
compLog(`Extension(` + delegateName + `)`, action + `: ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(commandJson)) + `(` + id + `)`);
|
|
198
|
+
return {
|
|
199
|
+
id: id,
|
|
200
|
+
meta: encodeMeta(meta, extensionPointName),
|
|
201
|
+
commandJson: commandJson
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
let encodeExtensionPointCommand = (command, id, extensionPointName, action) => encodeExtensionPointCommandJson(Message$Reventless.encode(command, Spec.commandSchema), id, extensionPointName, action);
|
|
205
|
+
return mapOutgoingEventImpl(Delegate.Id.toString(match.id), match.event, meta, extra$1).map(x => {
|
|
206
|
+
switch (x.TAG) {
|
|
207
|
+
case "PublishExtensionPointCommand" :
|
|
208
|
+
let command = x._1;
|
|
209
|
+
let id = x._0;
|
|
210
|
+
if (Spec.name === PluginExtensionPointSpec$ReventlessInfra.name) {
|
|
211
|
+
return {
|
|
212
|
+
TAG: "AbstractPublishPluginExtensionPointCommand",
|
|
213
|
+
_0: encodeExtensionPointCommand(command, id, extensionPointName, "Publish PluginExtensionPoint command")
|
|
214
|
+
};
|
|
215
|
+
} else {
|
|
216
|
+
return {
|
|
217
|
+
TAG: "AbstractPublishExtensionPointCommand",
|
|
218
|
+
_0: extensionPointName,
|
|
219
|
+
_1: encodeExtensionPointCommand(command, id, extensionPointName, "Publish ExtensionPoint command")
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
case "ForwardCommand" :
|
|
223
|
+
let match = x._0;
|
|
224
|
+
let extensionPointName$1 = match.extensionPointName;
|
|
225
|
+
return {
|
|
226
|
+
TAG: "AbstractPublishExtensionPointCommand",
|
|
227
|
+
_0: extensionPointName$1,
|
|
228
|
+
_1: encodeExtensionPointCommandJson(match.commandJson, match.id, extensionPointName$1, "Forward ExtensionPoint command")
|
|
229
|
+
};
|
|
230
|
+
case "HandleDirective" :
|
|
231
|
+
let directive = x._1;
|
|
232
|
+
let handler = x._0;
|
|
233
|
+
compLog(`Extension(` + delegateName + `)`, "outgoing directive");
|
|
234
|
+
return {
|
|
235
|
+
TAG: "AbstractHandleDirective",
|
|
236
|
+
_0: () => handler(directive)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}));
|
|
241
|
+
return {
|
|
242
|
+
delegateName: delegateName,
|
|
243
|
+
mapIncomingEvent: mapIncomingEvent,
|
|
244
|
+
mapOutgoingEvent: mapOutgoingEvent
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export {
|
|
249
|
+
NoDelegate,
|
|
250
|
+
Make,
|
|
251
|
+
}
|
|
252
|
+
/* moduleUrl Not a pure module */
|