@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,264 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Offload$Reventless from "../semantic/Offload.res.mjs";
|
|
5
|
+
import * as SuryResMjs from "sury/src/Sury.res.mjs";
|
|
6
|
+
|
|
7
|
+
let pluginKindSchema = S.union([
|
|
8
|
+
S.literal("Domain"),
|
|
9
|
+
S.literal("PlatformInfrastructure"),
|
|
10
|
+
S.literal("Commercial"),
|
|
11
|
+
S.literal("Marketplace")
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
let extensionPointDefinitionSchema = S.schema(s => ({
|
|
15
|
+
name: s.m(S.string),
|
|
16
|
+
commandTopic: s.m(S.string),
|
|
17
|
+
eventTopic: s.m(S.string)
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
let extensionDefinitionSchema = S.schema(s => ({
|
|
21
|
+
name: s.m(S.string),
|
|
22
|
+
extensionPointName: s.m(S.string),
|
|
23
|
+
dcbSources: s.m(S.array(S.string))
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
let dcbEventLogDefinitionSchema = S.schema(s => ({
|
|
27
|
+
name: s.m(S.string),
|
|
28
|
+
eventTopicArn: s.m(S.string)
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
let extensionProtocolSchema = S.schema(s => ({
|
|
32
|
+
extensionPointName: s.m(S.string),
|
|
33
|
+
commandVersion: s.m(S.string),
|
|
34
|
+
eventVersion: s.m(S.string)
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
let apiSchemaFragmentSchema = S.schema(s => ({
|
|
38
|
+
encoded: s.m(S.string),
|
|
39
|
+
protocol: s.m(S.string)
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
let apiTargetSchema = S.union([
|
|
43
|
+
S.literal("Domain"),
|
|
44
|
+
S.literal("Platform")
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
let apiSchemaFragmentOffloadSchema = Offload$Reventless.optionSchema(undefined, "pluginApiFragments", undefined, apiSchemaFragmentSchema);
|
|
48
|
+
|
|
49
|
+
let dcbEventLogOptionSchema = SuryResMjs.js_nullable(dcbEventLogDefinitionSchema);
|
|
50
|
+
|
|
51
|
+
let stringOptionSchema = SuryResMjs.js_nullable(S.string);
|
|
52
|
+
|
|
53
|
+
let stringArrayOptionSchema = SuryResMjs.js_nullable(S.array(S.string));
|
|
54
|
+
|
|
55
|
+
let boolOptionSchema = SuryResMjs.js_nullable(S.bool);
|
|
56
|
+
|
|
57
|
+
let panelManifestEntrySchema = S.schema(s => ({
|
|
58
|
+
fragmentId: s.m(S.string),
|
|
59
|
+
title: s.m(S.string),
|
|
60
|
+
description: s.m(S.string),
|
|
61
|
+
positions: s.m(S.array(S.string)),
|
|
62
|
+
requiredAccess: s.m(stringOptionSchema)
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
let menuEntrySchema = S.schema(s => ({
|
|
66
|
+
label: s.m(S.string),
|
|
67
|
+
icon: s.m(stringOptionSchema),
|
|
68
|
+
group: s.m(stringOptionSchema),
|
|
69
|
+
sortOrder: s.m(S.int)
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
let pageManifestEntrySchema = S.schema(s => ({
|
|
73
|
+
fragmentId: s.m(S.string),
|
|
74
|
+
title: s.m(S.string),
|
|
75
|
+
menuEntry: s.m(menuEntrySchema),
|
|
76
|
+
requiredAccess: s.m(stringOptionSchema)
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
let uiFragmentManifestSchema = S.schema(s => ({
|
|
80
|
+
remoteEntryUrl: s.m(S.string),
|
|
81
|
+
panels: s.m(S.array(panelManifestEntrySchema)),
|
|
82
|
+
pages: s.m(S.array(pageManifestEntrySchema))
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
let uiFragmentManifestOptionSchema = SuryResMjs.js_nullable(uiFragmentManifestSchema);
|
|
86
|
+
|
|
87
|
+
let commandLevelSchema = S.union([
|
|
88
|
+
S.literal("Collection"),
|
|
89
|
+
S.literal("Instance")
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
let fieldReferenceSchema = S.schema(s => ({
|
|
93
|
+
fieldName: s.m(S.string),
|
|
94
|
+
entity: s.m(S.string),
|
|
95
|
+
plugin: s.m(stringOptionSchema)
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
let commandDefSchema = S.schema(s => ({
|
|
99
|
+
name: s.m(S.string),
|
|
100
|
+
schema: s.m(S.string),
|
|
101
|
+
level: s.m(commandLevelSchema),
|
|
102
|
+
aggregateIdField: s.m(stringOptionSchema),
|
|
103
|
+
mutationField: s.m(S.string),
|
|
104
|
+
references: s.m(S.array(fieldReferenceSchema)),
|
|
105
|
+
allowedStates: s.m(stringArrayOptionSchema),
|
|
106
|
+
targetState: s.m(stringOptionSchema),
|
|
107
|
+
apiExposed: s.m(boolOptionSchema)
|
|
108
|
+
}));
|
|
109
|
+
|
|
110
|
+
let queryableDefSchema = S.schema(s => ({
|
|
111
|
+
name: s.m(S.string),
|
|
112
|
+
queryField: s.m(S.string),
|
|
113
|
+
schema: s.m(S.string),
|
|
114
|
+
consumedEventTypes: s.m(S.array(S.string)),
|
|
115
|
+
linkedWriteSide: s.m(S.array(S.string)),
|
|
116
|
+
labelField: s.m(S.string),
|
|
117
|
+
searchableFields: s.m(S.array(S.string)),
|
|
118
|
+
labelFieldSource: s.m(stringOptionSchema),
|
|
119
|
+
statusField: s.m(stringOptionSchema),
|
|
120
|
+
visibility: s.m(stringOptionSchema),
|
|
121
|
+
chapter: s.m(stringOptionSchema)
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
let eventDefSchema = S.schema(s => ({
|
|
125
|
+
name: s.m(S.string),
|
|
126
|
+
schema: s.m(S.string),
|
|
127
|
+
references: s.m(S.array(fieldReferenceSchema))
|
|
128
|
+
}));
|
|
129
|
+
|
|
130
|
+
let writableDefSchema = S.schema(s => ({
|
|
131
|
+
name: s.m(S.string),
|
|
132
|
+
commands: s.m(S.array(commandDefSchema)),
|
|
133
|
+
producedEventTypes: s.m(S.array(S.string)),
|
|
134
|
+
consumedEventTypes: s.m(S.array(S.string)),
|
|
135
|
+
linkedViews: s.m(S.array(S.string)),
|
|
136
|
+
consistencyRead: s.m(stringOptionSchema),
|
|
137
|
+
events: s.m(S.array(eventDefSchema)),
|
|
138
|
+
chapter: s.m(stringOptionSchema)
|
|
139
|
+
}));
|
|
140
|
+
|
|
141
|
+
let automationSliceDefSchema = S.schema(s => ({
|
|
142
|
+
name: s.m(S.string),
|
|
143
|
+
consumedEventTypes: s.m(S.array(S.string)),
|
|
144
|
+
producedCommandTypes: s.m(S.array(S.string)),
|
|
145
|
+
targetName: s.m(S.string),
|
|
146
|
+
chapter: s.m(stringOptionSchema)
|
|
147
|
+
}));
|
|
148
|
+
|
|
149
|
+
let outboundTranslationSliceDefSchema = S.schema(s => ({
|
|
150
|
+
name: s.m(S.string),
|
|
151
|
+
consumedEventTypes: s.m(S.array(S.string)),
|
|
152
|
+
inboundCommandTypes: s.m(S.array(S.string)),
|
|
153
|
+
targetName: s.m(stringOptionSchema),
|
|
154
|
+
externalSystem: s.m(stringOptionSchema),
|
|
155
|
+
chapter: s.m(stringOptionSchema)
|
|
156
|
+
}));
|
|
157
|
+
|
|
158
|
+
let inboundTranslationSliceDefSchema = S.schema(s => ({
|
|
159
|
+
name: s.m(S.string),
|
|
160
|
+
commandTypes: s.m(S.array(S.string)),
|
|
161
|
+
targetName: s.m(S.string),
|
|
162
|
+
externalSystem: s.m(stringOptionSchema),
|
|
163
|
+
chapter: s.m(stringOptionSchema)
|
|
164
|
+
}));
|
|
165
|
+
|
|
166
|
+
let extensionDefSchema = S.schema(s => ({
|
|
167
|
+
name: s.m(S.string),
|
|
168
|
+
delegateNames: s.m(S.array(S.string)),
|
|
169
|
+
eventTypes: s.m(S.array(S.string)),
|
|
170
|
+
commandTypes: s.m(S.array(S.string))
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
let extensionPointDefSchema = S.schema(s => ({
|
|
174
|
+
name: s.m(S.string),
|
|
175
|
+
delegateNames: s.m(S.array(S.string)),
|
|
176
|
+
sourceEventTypes: s.m(S.array(S.string)),
|
|
177
|
+
commandTypes: s.m(stringArrayOptionSchema)
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
let extensionPointDefArrayOptionSchema = SuryResMjs.js_nullable(S.array(extensionPointDefSchema));
|
|
181
|
+
|
|
182
|
+
let requiredStoreDeclarationSchema = S.schema(s => ({
|
|
183
|
+
store: s.m(S.string),
|
|
184
|
+
component: s.m(S.string),
|
|
185
|
+
field: s.m(S.string),
|
|
186
|
+
annotation: s.m(stringOptionSchema)
|
|
187
|
+
}));
|
|
188
|
+
|
|
189
|
+
let requiredStoreDeclarationArrayOptionSchema = SuryResMjs.js_nullable(S.array(requiredStoreDeclarationSchema));
|
|
190
|
+
|
|
191
|
+
let pluginStructureSchema = S.schema(s => ({
|
|
192
|
+
readModels: s.m(S.array(queryableDefSchema)),
|
|
193
|
+
stateViewSlices: s.m(S.array(queryableDefSchema)),
|
|
194
|
+
stateChangeSlices: s.m(S.array(writableDefSchema)),
|
|
195
|
+
aggregates: s.m(S.array(writableDefSchema)),
|
|
196
|
+
automationSlices: s.m(S.array(automationSliceDefSchema)),
|
|
197
|
+
outboundTranslationSlices: s.m(S.array(outboundTranslationSliceDefSchema)),
|
|
198
|
+
inboundTranslationSlices: s.m(S.array(inboundTranslationSliceDefSchema)),
|
|
199
|
+
extensions: s.m(S.array(extensionDefSchema)),
|
|
200
|
+
extensionPoints: s.m(extensionPointDefArrayOptionSchema),
|
|
201
|
+
requiredStores: s.m(stringArrayOptionSchema),
|
|
202
|
+
requiredStoreDeclarations: s.m(requiredStoreDeclarationArrayOptionSchema)
|
|
203
|
+
}));
|
|
204
|
+
|
|
205
|
+
let pluginStructureOffloadSchema = Offload$Reventless.optionSchema(undefined, "pluginStructures", undefined, pluginStructureSchema);
|
|
206
|
+
|
|
207
|
+
let pluginDefinitionSchema = S.schema(s => ({
|
|
208
|
+
id: s.m(S.string),
|
|
209
|
+
name: s.m(S.string),
|
|
210
|
+
version: s.m(S.string),
|
|
211
|
+
extensionPoints: s.m(S.array(extensionPointDefinitionSchema)),
|
|
212
|
+
extensions: s.m(S.array(extensionDefinitionSchema)),
|
|
213
|
+
eventCollector: s.m(S.string),
|
|
214
|
+
extensionProtocols: s.m(S.array(extensionProtocolSchema)),
|
|
215
|
+
apiSchemaFragment: s.m(apiSchemaFragmentOffloadSchema),
|
|
216
|
+
apiTarget: s.m(stringOptionSchema),
|
|
217
|
+
structure: s.m(pluginStructureOffloadSchema),
|
|
218
|
+
dcbEventLog: s.m(dcbEventLogOptionSchema),
|
|
219
|
+
kind: s.m(pluginKindSchema)
|
|
220
|
+
}));
|
|
221
|
+
|
|
222
|
+
let nameSchema = S.string;
|
|
223
|
+
|
|
224
|
+
let versionSchema = S.string;
|
|
225
|
+
|
|
226
|
+
export {
|
|
227
|
+
nameSchema,
|
|
228
|
+
versionSchema,
|
|
229
|
+
pluginKindSchema,
|
|
230
|
+
extensionPointDefinitionSchema,
|
|
231
|
+
extensionDefinitionSchema,
|
|
232
|
+
dcbEventLogDefinitionSchema,
|
|
233
|
+
extensionProtocolSchema,
|
|
234
|
+
apiSchemaFragmentSchema,
|
|
235
|
+
apiTargetSchema,
|
|
236
|
+
apiSchemaFragmentOffloadSchema,
|
|
237
|
+
dcbEventLogOptionSchema,
|
|
238
|
+
stringOptionSchema,
|
|
239
|
+
stringArrayOptionSchema,
|
|
240
|
+
boolOptionSchema,
|
|
241
|
+
panelManifestEntrySchema,
|
|
242
|
+
menuEntrySchema,
|
|
243
|
+
pageManifestEntrySchema,
|
|
244
|
+
uiFragmentManifestSchema,
|
|
245
|
+
uiFragmentManifestOptionSchema,
|
|
246
|
+
commandLevelSchema,
|
|
247
|
+
fieldReferenceSchema,
|
|
248
|
+
commandDefSchema,
|
|
249
|
+
queryableDefSchema,
|
|
250
|
+
eventDefSchema,
|
|
251
|
+
writableDefSchema,
|
|
252
|
+
automationSliceDefSchema,
|
|
253
|
+
outboundTranslationSliceDefSchema,
|
|
254
|
+
inboundTranslationSliceDefSchema,
|
|
255
|
+
extensionDefSchema,
|
|
256
|
+
extensionPointDefSchema,
|
|
257
|
+
extensionPointDefArrayOptionSchema,
|
|
258
|
+
requiredStoreDeclarationSchema,
|
|
259
|
+
requiredStoreDeclarationArrayOptionSchema,
|
|
260
|
+
pluginStructureSchema,
|
|
261
|
+
pluginStructureOffloadSchema,
|
|
262
|
+
pluginDefinitionSchema,
|
|
263
|
+
}
|
|
264
|
+
/* pluginKindSchema Not a pure module */
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Single source of truth for deriving a plugin's PascalCase name from its npm
|
|
2
|
+
// package name, and for resolving the final plugin name from the (optional)
|
|
3
|
+
// plugin.json `name` and package.json `name`. The plugin generator
|
|
4
|
+
// (`generator/Config`) and the external tooling that reconstructs the domain
|
|
5
|
+
// graph (`reventless-gwt`'s `LocalHost`) both derive from this, so the two can't
|
|
6
|
+
// drift — a drift here silently breaks graph plugin keys (the graph would key
|
|
7
|
+
// plugins under names that don't match the ones the generator bakes into
|
|
8
|
+
// `Plugin.res`). See [[reference_ppx_spec_name_single_strip]] for the sibling
|
|
9
|
+
// spec-name derivation.
|
|
10
|
+
|
|
11
|
+
// "@scope/my-catalog" → "MyCatalog", "online-shop" → "OnlineShop".
|
|
12
|
+
let fromPackageName = (packageName: string): string => {
|
|
13
|
+
let base = switch packageName->String.split("/") {
|
|
14
|
+
| [_scope, local] => local
|
|
15
|
+
| [local] => local
|
|
16
|
+
| parts => parts->Array.getUnsafe(parts->Array.length - 1)
|
|
17
|
+
}
|
|
18
|
+
base
|
|
19
|
+
->String.split("-")
|
|
20
|
+
->Array.flatMap(part => part->String.split("_"))
|
|
21
|
+
->Array.map(word =>
|
|
22
|
+
if word === "" {
|
|
23
|
+
""
|
|
24
|
+
} else {
|
|
25
|
+
word->String.slice(~start=0, ~end=1)->String.toUpperCase ++
|
|
26
|
+
word->String.slice(~start=1, ~end=word->String.length)
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
->Array.join("")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// plugin.json `name` wins; else PascalCase(package.json `name`); else "Plugin".
|
|
33
|
+
// The two callers each read the raw fields with their own node bindings, then
|
|
34
|
+
// share this precedence so the resolution can never diverge.
|
|
35
|
+
let resolve = (~pluginJsonName: option<string>, ~packageJsonName: option<string>): string =>
|
|
36
|
+
switch pluginJsonName {
|
|
37
|
+
| Some(name) => name
|
|
38
|
+
| None => packageJsonName->Option.map(fromPackageName)->Option.getOr("Plugin")
|
|
39
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
|
|
5
|
+
function fromPackageName(packageName) {
|
|
6
|
+
let parts = packageName.split("/");
|
|
7
|
+
let len = parts.length;
|
|
8
|
+
let base;
|
|
9
|
+
if (len >= 3) {
|
|
10
|
+
base = parts[parts.length - 1 | 0];
|
|
11
|
+
} else {
|
|
12
|
+
switch (len) {
|
|
13
|
+
case 0 :
|
|
14
|
+
base = parts[parts.length - 1 | 0];
|
|
15
|
+
break;
|
|
16
|
+
case 1 :
|
|
17
|
+
base = parts[0];
|
|
18
|
+
break;
|
|
19
|
+
case 2 :
|
|
20
|
+
base = parts[1];
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return base.split("-").flatMap(part => part.split("_")).map(word => {
|
|
25
|
+
if (word === "") {
|
|
26
|
+
return "";
|
|
27
|
+
} else {
|
|
28
|
+
return word.slice(0, 1).toUpperCase() + word.slice(1, word.length);
|
|
29
|
+
}
|
|
30
|
+
}).join("");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolve(pluginJsonName, packageJsonName) {
|
|
34
|
+
if (pluginJsonName !== undefined) {
|
|
35
|
+
return pluginJsonName;
|
|
36
|
+
} else {
|
|
37
|
+
return Stdlib_Option.getOr(Stdlib_Option.map(packageJsonName, fromPackageName), "Plugin");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
fromPackageName,
|
|
43
|
+
resolve,
|
|
44
|
+
}
|
|
45
|
+
/* No side effect */
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Specifies how the sub-ID of a projected state row is supplied at query time.
|
|
3
|
+
|
|
4
|
+
- `Field(name)` — the sub-ID comes from a field in the query response
|
|
5
|
+
- `Argument(name)` — the sub-ID is passed as a GraphQL resolver argument
|
|
6
|
+
- `NoSubId` — the read model has no sub-ID dimension
|
|
7
|
+
*/
|
|
8
|
+
type subId =
|
|
9
|
+
| Field(string)
|
|
10
|
+
| Argument(string)
|
|
11
|
+
| NoSubId
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
Whether the GraphQL resolver field resolves to a single value or to a list.
|
|
15
|
+
|
|
16
|
+
- `Single(fieldName)` — returns one item by ID
|
|
17
|
+
- `Multi(fieldName)` — returns an array of items
|
|
18
|
+
*/
|
|
19
|
+
type resolvedField =
|
|
20
|
+
| Single(string)
|
|
21
|
+
| Multi(string)
|
|
22
|
+
|
|
23
|
+
/** Source configuration for a single-ID GraphQL resolver. */
|
|
24
|
+
type idResolverSourceConfig = {
|
|
25
|
+
idField: string,
|
|
26
|
+
subId: subId,
|
|
27
|
+
resolvedField: resolvedField,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
Specifies which DynamoDB table field serves as the primary key in the resolver target.
|
|
32
|
+
|
|
33
|
+
- `Index(indexName)` — resolve against an index using only the index ID
|
|
34
|
+
- `IndexWithId(indexName, idField)` — resolve against an index with an explicit ID field
|
|
35
|
+
- `Id` — resolve against the table's primary key
|
|
36
|
+
*/
|
|
37
|
+
type targetIdField =
|
|
38
|
+
| Index(string)
|
|
39
|
+
| IndexWithId(string, string)
|
|
40
|
+
| Id
|
|
41
|
+
|
|
42
|
+
/** Target configuration for a single-ID GraphQL resolver. */
|
|
43
|
+
type idResolverTargetConfig = {
|
|
44
|
+
pluginName?: string,
|
|
45
|
+
tableName: string,
|
|
46
|
+
idField: targetIdField,
|
|
47
|
+
subIdField?: string,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type resolveConfig<'source, 'target> = {
|
|
51
|
+
source: 'source,
|
|
52
|
+
target: 'target,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Configuration for a GraphQL resolver that resolves a single ID field. */
|
|
56
|
+
type idResolverConfig = resolveConfig<idResolverSourceConfig, idResolverTargetConfig>
|
|
57
|
+
|
|
58
|
+
/** Source configuration for a multi-ID (array) GraphQL resolver. */
|
|
59
|
+
type idsResolverSourceConfig = {
|
|
60
|
+
idsField: string,
|
|
61
|
+
resolvedField: string,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Target configuration for a multi-ID (array) GraphQL resolver. */
|
|
65
|
+
type idsResolverTargetConfig = {
|
|
66
|
+
pluginName?: string,
|
|
67
|
+
tableName: string,
|
|
68
|
+
subIdField?: string,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Configuration for a GraphQL resolver that resolves an array of ID fields. */
|
|
72
|
+
type idsResolverConfig = resolveConfig<idsResolverSourceConfig, idsResolverTargetConfig>
|
|
73
|
+
|
|
74
|
+
/** AppSync authorization rule associating a DynamoDB table with a Cognito group. */
|
|
75
|
+
type authorization = {
|
|
76
|
+
tableName: string,
|
|
77
|
+
group: string,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** How much of a DynamoDB global secondary index is projected into the index. */
|
|
81
|
+
type projectionType = KEYS_ONLY | ALL | INCLUDE(array<string>)
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
Configuration for a DynamoDB Global Secondary Index on a read model table.
|
|
85
|
+
|
|
86
|
+
- `index` — the index name
|
|
87
|
+
- `type_` — the DynamoDB attribute type of the index key (`"S"`, `"N"`, etc.)
|
|
88
|
+
- `idField` / `subIdField` — index key field overrides (set to synthetic `_name_pk`/`_name_sk` for composite keys)
|
|
89
|
+
- `pkFields` / `skFields` — source state field names for composite pk/sk; runtime uses these to compute synthetic attribute values
|
|
90
|
+
- `pkSep` / `skSep` — separator for composite pk/sk concatenation (default `"/"`)
|
|
91
|
+
- `projectionType` — which attributes are projected into the index
|
|
92
|
+
- `authorization` — optional AppSync authorization rule
|
|
93
|
+
*/
|
|
94
|
+
type indexConfig = {
|
|
95
|
+
index: string,
|
|
96
|
+
type_: string,
|
|
97
|
+
idField?: string,
|
|
98
|
+
subIdField?: string,
|
|
99
|
+
pkFields?: array<string>,
|
|
100
|
+
pkSep?: string,
|
|
101
|
+
skFields?: array<string>,
|
|
102
|
+
skSep?: string,
|
|
103
|
+
projectionType: projectionType,
|
|
104
|
+
authorization?: authorization,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
Composite-key configuration for a read model that has both a primary ID and a sub-ID.
|
|
109
|
+
|
|
110
|
+
- `subIdField` — the DynamoDB range-key attribute name
|
|
111
|
+
- `getSubId` — extracts the sub-ID string from a projected state value
|
|
112
|
+
*/
|
|
113
|
+
type subIdConfig<'state> = {
|
|
114
|
+
subIdField: string,
|
|
115
|
+
getSubId: 'state => string,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
Infrastructure configuration for a read model.
|
|
120
|
+
|
|
121
|
+
- `idResolvers` — GraphQL resolvers for single-ID lookups
|
|
122
|
+
- `idsResolvers` — GraphQL resolvers for multi-ID (array) lookups
|
|
123
|
+
- `indexes` — additional DynamoDB global secondary indexes
|
|
124
|
+
|
|
125
|
+
Use the `config` factory function to build this with defaults.
|
|
126
|
+
*/
|
|
127
|
+
type config = {
|
|
128
|
+
idResolvers: array<idResolverConfig>,
|
|
129
|
+
idsResolvers: array<idsResolverConfig>,
|
|
130
|
+
indexes: array<indexConfig>,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
Builds a `ReadModel.config` with all optional fields defaulting to empty arrays.
|
|
135
|
+
|
|
136
|
+
@example
|
|
137
|
+
```rescript
|
|
138
|
+
// CategoriesReadModel.res
|
|
139
|
+
let config = ReadModel.config()
|
|
140
|
+
```
|
|
141
|
+
*/
|
|
142
|
+
let config = (~idResolvers=[], ~idsResolvers=[], ~indexes=[]) => {
|
|
143
|
+
idResolvers,
|
|
144
|
+
idsResolvers,
|
|
145
|
+
indexes,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
Module type for a read model's identity and schema specification.
|
|
150
|
+
|
|
151
|
+
@example
|
|
152
|
+
```rescript
|
|
153
|
+
// CategoriesReadModel.res
|
|
154
|
+
module Id = Id.String
|
|
155
|
+
let name = "Categories"
|
|
156
|
+
|
|
157
|
+
@schema
|
|
158
|
+
type state = {categoryId: string, name: string, archived: bool}
|
|
159
|
+
|
|
160
|
+
let config = ReadModel.config()
|
|
161
|
+
let subIdConfig = None
|
|
162
|
+
```
|
|
163
|
+
*/
|
|
164
|
+
module type Spec = {
|
|
165
|
+
module Id: Id.T
|
|
166
|
+
|
|
167
|
+
/** Logical read model name, used as the DynamoDB table-name prefix. */
|
|
168
|
+
let name: string
|
|
169
|
+
let moduleUrl: string
|
|
170
|
+
|
|
171
|
+
/** The projected state type stored in the read model. Must carry `@schema`. */
|
|
172
|
+
@schema
|
|
173
|
+
type state
|
|
174
|
+
|
|
175
|
+
/** Sury schema for the state type — generated automatically by `@schema`. */
|
|
176
|
+
let stateSchema: S.t<state>
|
|
177
|
+
|
|
178
|
+
/** Infrastructure configuration (indexes, resolvers). */
|
|
179
|
+
let config: config
|
|
180
|
+
|
|
181
|
+
/** Optional composite-key configuration. `None` for single-key tables. */
|
|
182
|
+
let subIdConfig: option<subIdConfig<state>>
|
|
183
|
+
|
|
184
|
+
/** Authorization rule evaluated at the GraphQL resolver entry before any
|
|
185
|
+
query is resolved. Auto-injected by `@@reventless.spec` and on
|
|
186
|
+
structurally-detected inline spec modules — defaults to
|
|
187
|
+
`AllowAuthenticated`; override at the file/module level with
|
|
188
|
+
`@@reventless.authorize(<rule>)`. */
|
|
189
|
+
let authorization: Authorization.permission
|
|
190
|
+
|
|
191
|
+
/** AutoUI visibility hint. Auto-injected by `@@reventless.spec` and on
|
|
192
|
+
structurally-detected inline spec modules — defaults to
|
|
193
|
+
`Visibility.Public`; override at the file/module level with
|
|
194
|
+
`@@reventless.visibility(Internal)` to hide from the AutoUI manifest.
|
|
195
|
+
Does not affect GraphQL exposure, authorization, or resolver
|
|
196
|
+
provisioning. */
|
|
197
|
+
let visibility: Visibility.t
|
|
198
|
+
}
|
|
199
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function config(idResolversOpt, idsResolversOpt, indexesOpt) {
|
|
5
|
+
let idResolvers = idResolversOpt !== undefined ? idResolversOpt : [];
|
|
6
|
+
let idsResolvers = idsResolversOpt !== undefined ? idsResolversOpt : [];
|
|
7
|
+
let indexes = indexesOpt !== undefined ? indexesOpt : [];
|
|
8
|
+
return {
|
|
9
|
+
idResolvers: idResolvers,
|
|
10
|
+
idsResolvers: idsResolvers,
|
|
11
|
+
indexes: indexes
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
config,
|
|
17
|
+
}
|
|
18
|
+
/* No side effect */
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Identifies which entity a reference field points to. */
|
|
2
|
+
type target = Semantic.referenceTarget
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
A sury string schema annotated as an entity reference field.
|
|
6
|
+
|
|
7
|
+
Use with `@s.matches(Reference.to_("EntityName"))` on command/event fields that
|
|
8
|
+
carry a foreign-entity ID. Also implies DCB tag semantics so the field is
|
|
9
|
+
automatically queryable in DCB event logs.
|
|
10
|
+
|
|
11
|
+
Pass `~key` to override the DCB tag key (defaults to the field name). The
|
|
12
|
+
`@ref` ppx shorthand supplies it automatically for plural `*Ids: array<string>`
|
|
13
|
+
fields (singularizing, e.g. `productIds` → tag key `productId`) so they share a
|
|
14
|
+
tag key with their singular-named producer events.
|
|
15
|
+
|
|
16
|
+
Prefer the `@ref("EntityName")` ppx shorthand over writing `@s.matches(...)` by hand.
|
|
17
|
+
|
|
18
|
+
@example
|
|
19
|
+
```rescript
|
|
20
|
+
@schema type command =
|
|
21
|
+
| PlaceOrder({
|
|
22
|
+
orderId: @s.matches(DcbTag.string) string,
|
|
23
|
+
customerId: @s.matches(Reference.to_("Customer")) string,
|
|
24
|
+
})
|
|
25
|
+
```
|
|
26
|
+
*/
|
|
27
|
+
let to_ = (~plugin=?, ~key=?, entity: string): S.t<string> => {
|
|
28
|
+
// Reference-ness and DCB-tagged-ness are two independent facts that happen to
|
|
29
|
+
// co-occur here: this constructor declares both. `toWithoutDcbTag` declares
|
|
30
|
+
// only the first, and plain `DcbTag.string` only the second — so no consumer
|
|
31
|
+
// may infer either one from the other.
|
|
32
|
+
let base =
|
|
33
|
+
S.string
|
|
34
|
+
->S.Metadata.set(~id=DcbTag.dcbTagId, true)
|
|
35
|
+
->Semantic.mark(~id=Semantic.Id.reference, ~payload=ReferenceTo({entity, plugin}))
|
|
36
|
+
switch key {
|
|
37
|
+
| Some(k) => base->S.Metadata.set(~id=DcbTag.dcbTagKeyOverrideId, k)
|
|
38
|
+
| None => base
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Returns the reference target if the schema carries `Reference.to_(...)` metadata. */
|
|
43
|
+
let getTarget = (schema: S.t<unknown>): option<target> =>
|
|
44
|
+
switch Semantic.get(schema) {
|
|
45
|
+
| Some({payload: ReferenceTo(target)}) => Some(target)
|
|
46
|
+
| _ => None
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
Like `to_` but does not imply DCB tag semantics.
|
|
51
|
+
Use with `@ref("Entity") @noDcbTag` when the field references another entity
|
|
52
|
+
but should not participate in content-based event routing.
|
|
53
|
+
*/
|
|
54
|
+
let toWithoutDcbTag = (~plugin=?, entity: string): S.t<string> =>
|
|
55
|
+
S.string->Semantic.mark(~id=Semantic.Id.reference, ~payload=ReferenceTo({entity, plugin}))
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "./DcbTag.res.mjs";
|
|
5
|
+
import * as Semantic$Reventless from "../semantic/Semantic.res.mjs";
|
|
6
|
+
|
|
7
|
+
function to_(plugin, key, entity) {
|
|
8
|
+
let base = Semantic$Reventless.mark(S.Metadata.set(S.string, DcbTag$Reventless.dcbTagId, true), Semantic$Reventless.Id.reference, {
|
|
9
|
+
TAG: "ReferenceTo",
|
|
10
|
+
_0: {
|
|
11
|
+
entity: entity,
|
|
12
|
+
plugin: plugin
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
if (key !== undefined) {
|
|
16
|
+
return S.Metadata.set(base, DcbTag$Reventless.dcbTagKeyOverrideId, key);
|
|
17
|
+
} else {
|
|
18
|
+
return base;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getTarget(schema) {
|
|
23
|
+
let match = Semantic$Reventless.get(schema);
|
|
24
|
+
if (match === undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let target = match.payload;
|
|
28
|
+
if (typeof target !== "object" || target.TAG !== "ReferenceTo") {
|
|
29
|
+
return;
|
|
30
|
+
} else {
|
|
31
|
+
return target._0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function toWithoutDcbTag(plugin, entity) {
|
|
36
|
+
return Semantic$Reventless.mark(S.string, Semantic$Reventless.Id.reference, {
|
|
37
|
+
TAG: "ReferenceTo",
|
|
38
|
+
_0: {
|
|
39
|
+
entity: entity,
|
|
40
|
+
plugin: plugin
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
to_,
|
|
47
|
+
getTarget,
|
|
48
|
+
toWithoutDcbTag,
|
|
49
|
+
}
|
|
50
|
+
/* S Not a pure module */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Per-aggregate persisted-snapshot configuration
|
|
2
|
+
// (docs/plans/aggregate-snapshotting.md).
|
|
3
|
+
//
|
|
4
|
+
// Snapshotting is opt-in and lives on the Behavior module (where `state` is
|
|
5
|
+
// defined): `Behavior.T.snapshot = None` (the default, auto-injected by
|
|
6
|
+
// `@@reventless.behavior`) keeps full replay; `Some(config)` makes the
|
|
7
|
+
// aggregate write a keep-one snapshot every `interval` events and seed cold
|
|
8
|
+
// replays from the latest one. Snapshots are a read optimization only — the
|
|
9
|
+
// OCC append remains the sole consistency primitive, and a missing, corrupt,
|
|
10
|
+
// or schema-drifted snapshot degrades to full replay.
|
|
11
|
+
//
|
|
12
|
+
// Enable via the file-level attribute on a behavior file:
|
|
13
|
+
//
|
|
14
|
+
// @@reventless.snapshots(100)
|
|
15
|
+
//
|
|
16
|
+
// which injects `let snapshot = Some({interval: 100, stateSchema})` (requires
|
|
17
|
+
// `@schema type state` so sury generates the schema), or hand-write the
|
|
18
|
+
// binding for full control.
|
|
19
|
+
|
|
20
|
+
type config<'state> = {
|
|
21
|
+
/** Write a snapshot after every N appended events. Required — no default. */
|
|
22
|
+
interval: int,
|
|
23
|
+
/** Sury schema for the behavior's state — serializes the persisted snapshot
|
|
24
|
+
and (hashed) gates staleness across state-shape changes. */
|
|
25
|
+
stateSchema: S.t<'state>,
|
|
26
|
+
}
|