@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.
Files changed (78) hide show
  1. package/CHANGELOG.md +853 -0
  2. package/LICENSE +202 -0
  3. package/README.md +92 -0
  4. package/package.json +46 -0
  5. package/rescript.json +34 -0
  6. package/src/adapter/Adapter.res +88 -0
  7. package/src/adapter/Adapter.res.mjs +29 -0
  8. package/src/components/Aggregate.res +73 -0
  9. package/src/components/Aggregate.res.mjs +2 -0
  10. package/src/components/Api.res +120 -0
  11. package/src/components/Api.res.mjs +31 -0
  12. package/src/components/Api_Adapter.res +29 -0
  13. package/src/components/Api_Adapter.res.mjs +2 -0
  14. package/src/components/AutomationSlice.res +48 -0
  15. package/src/components/AutomationSlice.res.mjs +2 -0
  16. package/src/components/CommandGenerator.res +8 -0
  17. package/src/components/CommandGenerator.res.mjs +2 -0
  18. package/src/components/CommandTopic.res +70 -0
  19. package/src/components/CommandTopic.res.mjs +2 -0
  20. package/src/components/Component.js +56 -0
  21. package/src/components/Component.mjs +10 -0
  22. package/src/components/Component.res +90 -0
  23. package/src/components/Component.res.mjs +57 -0
  24. package/src/components/Component.resi +21 -0
  25. package/src/components/Counter.res +81 -0
  26. package/src/components/Counter.res.mjs +2 -0
  27. package/src/components/DcbEventLog.res +130 -0
  28. package/src/components/DcbEventLog.res.mjs +2 -0
  29. package/src/components/DeployBootstrap.res +83 -0
  30. package/src/components/DeployBootstrap.res.mjs +69 -0
  31. package/src/components/EventCollector.res +19 -0
  32. package/src/components/EventCollector.res.mjs +2 -0
  33. package/src/components/EventLog.res +24 -0
  34. package/src/components/EventLog.res.mjs +2 -0
  35. package/src/components/EventMapper.res +37 -0
  36. package/src/components/EventMapper.res.mjs +2 -0
  37. package/src/components/EventTopic.res +51 -0
  38. package/src/components/EventTopic.res.mjs +2 -0
  39. package/src/components/Extension.res +64 -0
  40. package/src/components/Extension.res.mjs +2 -0
  41. package/src/components/ExtensionPoint.res +62 -0
  42. package/src/components/ExtensionPoint.res.mjs +2 -0
  43. package/src/components/Heartbeat.res +7 -0
  44. package/src/components/Heartbeat.res.mjs +2 -0
  45. package/src/components/InboundTranslationSlice.res +41 -0
  46. package/src/components/InboundTranslationSlice.res.mjs +2 -0
  47. package/src/components/OutboundTranslationSlice.res +44 -0
  48. package/src/components/OutboundTranslationSlice.res.mjs +2 -0
  49. package/src/components/Plugin.res +93 -0
  50. package/src/components/Plugin.res.mjs +2 -0
  51. package/src/components/QueryDb.res +48 -0
  52. package/src/components/QueryDb.res.mjs +33 -0
  53. package/src/components/ReadModel.res +56 -0
  54. package/src/components/ReadModel.res.mjs +2 -0
  55. package/src/components/Scheduler.res +32 -0
  56. package/src/components/Scheduler.res.mjs +2 -0
  57. package/src/components/StateChangeSlice.res +45 -0
  58. package/src/components/StateChangeSlice.res.mjs +2 -0
  59. package/src/components/StateViewSlice.res +38 -0
  60. package/src/components/StateViewSlice.res.mjs +2 -0
  61. package/src/components/Task.res +89 -0
  62. package/src/components/Task.res.mjs +2 -0
  63. package/src/types/ExtensionMapping.res +448 -0
  64. package/src/types/ExtensionMapping.res.mjs +252 -0
  65. package/src/types/ExtensionPointMapping.res +303 -0
  66. package/src/types/ExtensionPointMapping.res.mjs +116 -0
  67. package/src/types/Message.res +3 -0
  68. package/src/types/Message.res.mjs +2 -0
  69. package/src/types/NoEventMappings.res +25 -0
  70. package/src/types/NoEventMappings.res.mjs +17 -0
  71. package/src/types/Platform.res +269 -0
  72. package/src/types/Platform.res.mjs +2 -0
  73. package/src/types/PluginExtensionPointSpec.res +55 -0
  74. package/src/types/PluginExtensionPointSpec.res.mjs +209 -0
  75. package/src/types/ResourceNaming.res +12 -0
  76. package/src/types/ResourceNaming.res.mjs +2 -0
  77. package/tests/DeployBootstrapTest.res +72 -0
  78. 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 */