@reventlessdev/reventless-spec 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 +931 -0
- package/LICENSE +202 -0
- package/README.md +109 -0
- package/package.json +49 -0
- package/rescript.json +32 -0
- package/run-generator.mjs +2 -0
- package/run-platform-generator.mjs +2 -0
- package/scripts/generate-currency.mjs +215 -0
- package/scripts/iso-4217-list-one.xml +1956 -0
- package/src/AnsiStyle.res +40 -0
- package/src/AnsiStyle.res.mjs +54 -0
- package/src/LogPrefix.res +192 -0
- package/src/LogPrefix.res.mjs +159 -0
- package/src/PackageVersion.res +67 -0
- package/src/PackageVersion.res.mjs +81 -0
- package/src/components/Aggregate.res +64 -0
- package/src/components/Aggregate.res.mjs +2 -0
- package/src/components/AutomationSlice.res +279 -0
- package/src/components/AutomationSlice.res.mjs +30 -0
- package/src/components/CapabilityManifest.res +74 -0
- package/src/components/CapabilityManifest.res.mjs +61 -0
- package/src/components/ComponentKind.res +99 -0
- package/src/components/ComponentKind.res.mjs +125 -0
- package/src/components/Counter.res +24 -0
- package/src/components/Counter.res.mjs +2 -0
- package/src/components/DcbDecode.res +118 -0
- package/src/components/DcbDecode.res.mjs +100 -0
- package/src/components/DcbScopeInference.res +244 -0
- package/src/components/DcbScopeInference.res.mjs +177 -0
- package/src/components/DcbTag.res +1335 -0
- package/src/components/DcbTag.res.mjs +898 -0
- package/src/components/DcbValidation.res +427 -0
- package/src/components/DcbValidation.res.mjs +423 -0
- package/src/components/DisplayName.res +40 -0
- package/src/components/DisplayName.res.mjs +26 -0
- package/src/components/ExtensionPoint.res +27 -0
- package/src/components/ExtensionPoint.res.mjs +2 -0
- package/src/components/InboundTranslationSlice.res +85 -0
- package/src/components/InboundTranslationSlice.res.mjs +2 -0
- package/src/components/OutboundTranslationSlice.res +153 -0
- package/src/components/OutboundTranslationSlice.res.mjs +2 -0
- package/src/components/Plugin.res +538 -0
- package/src/components/Plugin.res.mjs +264 -0
- package/src/components/PluginName.res +39 -0
- package/src/components/PluginName.res.mjs +45 -0
- package/src/components/ReadModel.res +199 -0
- package/src/components/ReadModel.res.mjs +18 -0
- package/src/components/Reference.res +55 -0
- package/src/components/Reference.res.mjs +50 -0
- package/src/components/Snapshot.res +26 -0
- package/src/components/Snapshot.res.mjs +2 -0
- package/src/components/StateAnnotations.res +97 -0
- package/src/components/StateAnnotations.res.mjs +15 -0
- package/src/components/StateChangeSlice.res +131 -0
- package/src/components/StateChangeSlice.res.mjs +2 -0
- package/src/components/StateViewSlice.res +123 -0
- package/src/components/StateViewSlice.res.mjs +2 -0
- package/src/components/Task.res +62 -0
- package/src/components/Task.res.mjs +2 -0
- package/src/generator/Codegen.res +842 -0
- package/src/generator/Codegen.res.mjs +565 -0
- package/src/generator/Config.res +106 -0
- package/src/generator/Config.res.mjs +69 -0
- package/src/generator/Discovery.res +230 -0
- package/src/generator/Discovery.res.mjs +198 -0
- package/src/generator/Generator_Node.res +14 -0
- package/src/generator/Generator_Node.res.mjs +18 -0
- package/src/generator/Pairing.res +460 -0
- package/src/generator/Pairing.res.mjs +415 -0
- package/src/generator/PlatformCodegen.res +207 -0
- package/src/generator/PlatformCodegen.res.mjs +154 -0
- package/src/generator/PlatformGenerator.res +126 -0
- package/src/generator/PlatformGenerator.res.mjs +114 -0
- package/src/generator/PlatformManifests.res +203 -0
- package/src/generator/PlatformManifests.res.mjs +212 -0
- package/src/generator/PluginGenerator.res +57 -0
- package/src/generator/PluginGenerator.res.mjs +73 -0
- package/src/semantic/Bytes.res +54 -0
- package/src/semantic/Bytes.res.mjs +38 -0
- package/src/semantic/Capabilities.res +43 -0
- package/src/semantic/Capabilities.res.mjs +17 -0
- package/src/semantic/Color.res +51 -0
- package/src/semantic/Color.res.mjs +29 -0
- package/src/semantic/Currency.res +598 -0
- package/src/semantic/Currency.res.mjs +743 -0
- package/src/semantic/DateRange.res +148 -0
- package/src/semantic/DateRange.res.mjs +74 -0
- package/src/semantic/Duration.res +53 -0
- package/src/semantic/Duration.res.mjs +26 -0
- package/src/semantic/Email.res +51 -0
- package/src/semantic/Email.res.mjs +31 -0
- package/src/semantic/GeoPoint.res +226 -0
- package/src/semantic/GeoPoint.res.mjs +190 -0
- package/src/semantic/Geocoding.res +127 -0
- package/src/semantic/Geocoding.res.mjs +36 -0
- package/src/semantic/Money.res +196 -0
- package/src/semantic/Money.res.mjs +138 -0
- package/src/semantic/Offload.res +294 -0
- package/src/semantic/Offload.res.mjs +191 -0
- package/src/semantic/Percent.res +53 -0
- package/src/semantic/Percent.res.mjs +33 -0
- package/src/semantic/Phone.res +55 -0
- package/src/semantic/Phone.res.mjs +29 -0
- package/src/semantic/Semantic.res +162 -0
- package/src/semantic/Semantic.res.mjs +95 -0
- package/src/semantic/StorageRef.res +164 -0
- package/src/semantic/StorageRef.res.mjs +111 -0
- package/src/semantic/Url.res +66 -0
- package/src/semantic/Url.res.mjs +48 -0
- package/src/types/Authorization.res +23 -0
- package/src/types/Authorization.res.mjs +33 -0
- package/src/types/Behavior.res +86 -0
- package/src/types/Behavior.res.mjs +2 -0
- package/src/types/DateTime.res +29 -0
- package/src/types/DateTime.res.mjs +16 -0
- package/src/types/EventMapping.res +100 -0
- package/src/types/EventMapping.res.mjs +15 -0
- package/src/types/Handler.res +30 -0
- package/src/types/Handler.res.mjs +2 -0
- package/src/types/Id.res +75 -0
- package/src/types/Id.res.mjs +37 -0
- package/src/types/Identity.res +46 -0
- package/src/types/Identity.res.mjs +51 -0
- package/src/types/Message.res +326 -0
- package/src/types/Message.res.mjs +186 -0
- package/src/types/Projection.res +220 -0
- package/src/types/Projection.res.mjs +44 -0
- package/src/types/QueryEngine.res +123 -0
- package/src/types/QueryEngine.res.mjs +12 -0
- package/src/types/ReadConsistency.res +38 -0
- package/src/types/ReadConsistency.res.mjs +29 -0
- package/src/types/Schedule.res +65 -0
- package/src/types/Schedule.res.mjs +68 -0
- package/src/types/SideEffect.res +45 -0
- package/src/types/SideEffect.res.mjs +2 -0
- package/src/types/StoredEvent.res +46 -0
- package/src/types/StoredEvent.res.mjs +32 -0
- package/src/types/Visibility.res +24 -0
- package/src/types/Visibility.res.mjs +25 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Module types for a DCB outbound translation slice.
|
|
3
|
+
|
|
4
|
+
An `OutboundTranslationSlice` listens to the shared `DcbEventLog` event topic,
|
|
5
|
+
collects outbound items (TODO list), and calls an external service for each one.
|
|
6
|
+
The translate function may optionally return a command to publish back into the
|
|
7
|
+
system, closing the loop.
|
|
8
|
+
|
|
9
|
+
Replaces fire-and-forget `SideEffectHandler` with tracked, retryable external calls.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Event(s) -> TODO List (read model) -> Translator -> External Service
|
|
13
|
+
-> Command (optional)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Plan 02 splits the merged spec into two module types:
|
|
17
|
+
|
|
18
|
+
- `Spec` — types, identity, schemas, sweep config. Per D2, `outboundItem`
|
|
19
|
+
lives here (persisted TODO state with schema).
|
|
20
|
+
- `Translation` — `collect` (sync, observable in tests) and `translate`
|
|
21
|
+
(async, mocked in tests via `whenTranslateMocked`).
|
|
22
|
+
|
|
23
|
+
@example
|
|
24
|
+
```rescript
|
|
25
|
+
// SendTrackingEmail.res
|
|
26
|
+
let name = "SendTrackingEmail"
|
|
27
|
+
|
|
28
|
+
@schema type outboundItem = {orderId: string, email: string}
|
|
29
|
+
@schema type inboundCommand = unit
|
|
30
|
+
|
|
31
|
+
let collect = event => switch event {
|
|
32
|
+
| OrderShipped({orderId, email}) => [(orderId, {orderId, email})]
|
|
33
|
+
| _ => []
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// `~capabilities` is ignored here: this slice calls a service the framework
|
|
37
|
+
// does not broker. A geocoding slice would use `capabilities.geocode`.
|
|
38
|
+
let translate = async (_id, item, ~capabilities as _) => {
|
|
39
|
+
await EmailService.send(item.email, ~orderId=item.orderId)
|
|
40
|
+
Ok(None) // fire-and-forget: no command back
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let maxRetries = 3
|
|
44
|
+
let heartbeatInterval = 60
|
|
45
|
+
```
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
The lean Spec for an OutboundTranslationSlice — types, identity, schemas, sweep config.
|
|
50
|
+
*/
|
|
51
|
+
module type Spec = {
|
|
52
|
+
/** Logical name of this outbound translation slice (used as a component prefix). */
|
|
53
|
+
let name: string
|
|
54
|
+
let moduleUrl: string
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
Events this outbound translation slice consumes for collect.
|
|
58
|
+
Only needs the fields required — no tag annotations needed.
|
|
59
|
+
Must carry `@schema`.
|
|
60
|
+
*/
|
|
61
|
+
@schema
|
|
62
|
+
type consumedEvent
|
|
63
|
+
|
|
64
|
+
/** The outbound item state — what data is accumulated for each pending external call. Must carry `@schema`. */
|
|
65
|
+
@schema
|
|
66
|
+
type outboundItem
|
|
67
|
+
|
|
68
|
+
/** The command type optionally produced after a successful translate call. Must carry `@schema`. */
|
|
69
|
+
@schema
|
|
70
|
+
type inboundCommand
|
|
71
|
+
|
|
72
|
+
/** Maximum number of retries for a failed translate attempt. */
|
|
73
|
+
let maxRetries: int
|
|
74
|
+
|
|
75
|
+
/** Heartbeat interval in seconds for sweeping pending/failed items. */
|
|
76
|
+
let heartbeatInterval: int
|
|
77
|
+
|
|
78
|
+
/** Name of the aggregate or StateChangeSlice that receives the inbound command, or None for fire-and-forget. */
|
|
79
|
+
let targetName: option<string>
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
Event sources this slice subscribes to, by topic key.
|
|
83
|
+
|
|
84
|
+
`[]` — the default and the historical behaviour — means this plugin's own DCB
|
|
85
|
+
event log. Naming sources explicitly subscribes to them instead: an Aggregate's
|
|
86
|
+
`Spec.name`, or a DCB source name (conventionally `"<pluginName>DcbEventLog"`),
|
|
87
|
+
matching the keys `AutomationSlice` mappings already use.
|
|
88
|
+
|
|
89
|
+
This exists because an outbound slice is the framework's one component for
|
|
90
|
+
*calling an external service and feeding the answer back*, and that job is not
|
|
91
|
+
specific to DCB-modelled entities. An Aggregate whose events should trigger an
|
|
92
|
+
outbound call had no route to one while this list was hard-wired.
|
|
93
|
+
|
|
94
|
+
Unlike `AutomationSlice`, the sources are a flat list rather than per-source
|
|
95
|
+
`Mapping` modules. An automation needs a `resolve` per source (a different
|
|
96
|
+
event completes the item depending on where it came from); an outbound item is
|
|
97
|
+
resolved by its own `translate` succeeding, so the only thing that varies per
|
|
98
|
+
source is the decode — and the one `consumedEvent` union already covers that.
|
|
99
|
+
The cost of the flat form is that two sources sharing an event-type name are
|
|
100
|
+
indistinguishable; declare only the sources whose events you mean.
|
|
101
|
+
*/
|
|
102
|
+
let sourceNames: array<string>
|
|
103
|
+
|
|
104
|
+
/** Optional display name of the foreign system this anti-corruption slice publishes
|
|
105
|
+
to (e.g. `"EmailService"`). Drives the **external box** drawn outside the plugin
|
|
106
|
+
in the Event Graph / Context Map (see docs/plans/translation-external-boxes.md).
|
|
107
|
+
Auto-injected by `@@reventless.spec` defaulting to `None` — set it to name the box. */
|
|
108
|
+
let externalSystem: option<string>
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
The Translation — `collect` and async `translate`. Both functions are
|
|
113
|
+
distinguished from the Inbound shape (which has only a sync `translate`).
|
|
114
|
+
*/
|
|
115
|
+
module type Translation = {
|
|
116
|
+
module Spec: Spec
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
Collect: map an incoming event to zero or more new outbound items.
|
|
120
|
+
Each item has an `id` (deduplication key) and the `outboundItem` payload.
|
|
121
|
+
Returns empty array if this event is not relevant.
|
|
122
|
+
|
|
123
|
+
`~sourceId` is the id of the entity the event was published for — the envelope's
|
|
124
|
+
`id`, not part of the event payload. A DCB event usually names its own subject
|
|
125
|
+
in the payload (`OrderPlaced({orderId, …})`) and can ignore this; an Aggregate's
|
|
126
|
+
event generally does not, because the aggregate id is what addressed it in the
|
|
127
|
+
first place. Without this the outbound item for `Registered({email, address})`
|
|
128
|
+
would have no way to say *which customer* it is for.
|
|
129
|
+
*/
|
|
130
|
+
let collect: (Spec.consumedEvent, ~sourceId: string) => array<(string, Spec.outboundItem)>
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
Translate: call the external service for a single outbound item.
|
|
134
|
+
Returns:
|
|
135
|
+
- `Ok(Some((targetId, cmd)))` to publish a command back into the system
|
|
136
|
+
- `Ok(None)` for fire-and-forget (no command back)
|
|
137
|
+
- `Error(msg)` on failure (item will be retried up to maxRetries)
|
|
138
|
+
|
|
139
|
+
`~capabilities` carries what the platform provisioned — a geocoder today. It is
|
|
140
|
+
how a provider-agnostic plugin reaches a provider-specific service without
|
|
141
|
+
naming one: the deployment decides what is behind `capabilities.geocode`, and
|
|
142
|
+
the call site does not change when that answer does. A slice calling a service
|
|
143
|
+
the framework knows nothing about still reaches it directly and simply ignores
|
|
144
|
+
this argument.
|
|
145
|
+
*/
|
|
146
|
+
let translate: (string, Spec.outboundItem, ~capabilities: Capabilities.t) => promise<
|
|
147
|
+
result<option<(string, Spec.inboundCommand)>, string>,
|
|
148
|
+
>
|
|
149
|
+
|
|
150
|
+
/** File URL of this Translation module (`import.meta.url`). */
|
|
151
|
+
let moduleUrl: string
|
|
152
|
+
}
|
|
153
|
+
|