@reventlessdev/reventless-core 3.0.0-alpha.251 → 3.0.0-alpha.253
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 +23 -0
- package/package.json +8 -8
- package/src/admin/Platform_Admin_Structure.res +4 -1
- package/src/admin/Platform_Admin_Structure.res.mjs +4 -2
- package/src/admin/Platform_BakedManifest.res.mjs +3 -1
- package/src/admin/Platform_PluginStructuresApi.res +43 -7
- package/src/admin/Platform_PluginStructuresApi.res.mjs +47 -1
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +8 -0
- package/src/components/Api/ApiNoApiHelpers.res +37 -3
- package/src/components/Api/ApiNoApiHelpers.res.mjs +29 -2
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +4 -4
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +3 -3
- package/src/plugin/api/PluginBaseFragment.res +3 -3
- package/src/plugin/component/Plugin_Structure.res +158 -25
- package/src/plugin/component/Plugin_Structure.res.mjs +82 -18
- package/src/plugin/connect/PluginConnectExtension_Mapping.res.mjs +3 -1
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +3 -1
- package/src/plugin/connect/PluginExtensionPoint_UiFragment.res.mjs +3 -1
- package/src/plugin/lifecycle/PluginBehavior.res +11 -11
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +11 -11
- package/src/plugin/lifecycle/PluginSpec.res +39 -16
- package/src/plugin/lifecycle/PluginSpec.res.mjs +54 -56
- package/tests/admin/AdminApiSchemaDriftTest.res +27 -1
- package/tests/admin/AdminApiSchemaDriftTest.res.mjs +22 -2
- package/tests/admin/Platform_Admin_StructureTest.res +8 -3
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +8 -2
- package/tests/admin/Platform_BakedManifestTest.res +2 -0
- package/tests/admin/Platform_BakedManifestTest.res.mjs +3 -1
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +4 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +21 -7
- package/tests/admin/Platform_PluginStructuresApiTest.res +16 -0
- package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +17 -3
- package/tests/aggregate/AggregateCacheTest.res.mjs +15 -3
- package/tests/aggregate/AggregateConflictTest.res.mjs +15 -3
- package/tests/aggregate/AggregateFixtures.res.mjs +15 -3
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +21 -5
- package/tests/api/ApiNoApiTest.res +46 -0
- package/tests/api/ApiNoApiTest.res.mjs +49 -1
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +27 -3
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +12 -2
- package/tests/commandtopic/CommandOutcomeHookTest.res.mjs +2 -0
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +12 -2
- package/tests/dcb/DcbFixtures.res.mjs +8 -0
- package/tests/dcb/DcbStateChangeSliceTest.res.mjs +18 -0
- package/tests/eventmapper/EventMapperFixtures.res.mjs +15 -3
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +9 -1
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -1
- package/tests/message/MessageTest.res +2 -0
- package/tests/message/MessageTest.res.mjs +3 -1
- package/tests/plugin/PluginStructureAccessTest.res.mjs +2 -0
- package/tests/plugin/PluginStructureTest.res +191 -12
- package/tests/plugin/PluginStructureTest.res.mjs +246 -6
- package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res +17 -7
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +12 -11
- package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsShipOrder.res +17 -13
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +17 -11
- package/tests/plugin/StateChangeSlice/PsTransitionSwitch.res +54 -0
- package/tests/plugin/StateChangeSlice/PsTransitionSwitch.res.mjs +104 -0
- package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +8 -0
- package/tests/plugin/StateViewSlice/PsShipmentsView.res +1 -1
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +18 -0
- package/tests/util/CommandPublisherTest.res.mjs +9 -1
- package/src/components/Api/ApiAllowedStatesHelpers.res +0 -18
- package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +0 -16
- package/src/components/Api/ApiTargetStateHelpers.res +0 -21
- package/src/components/Api/ApiTargetStateHelpers.res.mjs +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.253 (2026-09-01)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-core
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 3.0.0-alpha.252 (2026-09-01)
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **api:** [@no](https://github.com/no)Api was lost when a command variant was spliced into another type ([00403fb](https://github.com/ReventlessDev/reventless-core/commit/00403fb4b8873a68a69558829e598339a5012833))
|
|
19
|
+
* **automation:** a mapping is handed the envelope's id ([9ee482c](https://github.com/ReventlessDev/reventless-core/commit/9ee482c5ad0aae09efd1259eeb7f39b781867b91))
|
|
20
|
+
* **capabilities:** a plugin's geocoding need was declared nowhere and failed silently ([67917dd](https://github.com/ReventlessDev/reventless-core/commit/67917dd504b43fa78b7c6a51644c9eae656b7f6b))
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
* **plugin:** refuse two DCB slices that declare one command name ([8c6ec39](https://github.com/ReventlessDev/reventless-core/commit/8c6ec39cb3c6768446f46d0fc6dc04c256e2e9d9))
|
|
24
|
+
* **plugin:** the admin lifecycle commands name their argument ([ea552ec](https://github.com/ReventlessDev/reventless-core/commit/ea552ec64e5db0b3dc465c0d9a80cac89627f727))
|
|
25
|
+
* **spec:** a command declares its lifecycle edge as a value ([40eee9f](https://github.com/ReventlessDev/reventless-core/commit/40eee9f7723dc05e418be680528f01967d074da4))
|
|
26
|
+
* **spec:** a graft leaves a trace the deployed plugin can read ([c08ff6c](https://github.com/ReventlessDev/reventless-core/commit/c08ff6c0f6177d58603e7ae1e5cec392d9bac16a))
|
|
27
|
+
|
|
28
|
+
|
|
6
29
|
# 3.0.0-alpha.251 (2026-08-27)
|
|
7
30
|
|
|
8
31
|
* feat(spec)!: reflect the command direction across a port, both halves ([f2fe258](https://github.com/ReventlessDev/reventless-core/commit/f2fe258d195b74f4a61488edee305665341020ea))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.253",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -28,22 +28,22 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"sury": "11.0.0-rc.2",
|
|
30
30
|
"uuid": "^13.0.0",
|
|
31
|
-
"@reventlessdev/rescript-
|
|
31
|
+
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.8",
|
|
32
32
|
"@reventlessdev/rescript-node": "2.0.0-alpha.8",
|
|
33
|
-
"@reventlessdev/rescript-
|
|
33
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
34
34
|
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.14",
|
|
35
|
-
"@reventlessdev/rescript-
|
|
35
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
36
36
|
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.8",
|
|
37
|
-
"@reventlessdev/
|
|
37
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.154",
|
|
38
38
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
39
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.152",
|
|
40
39
|
"@reventlessdev/reventless-interop": "3.0.0-alpha.34",
|
|
41
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
40
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.126",
|
|
41
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.10"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "12.3.0",
|
|
45
45
|
"sury-ppx": "11.0.0-rc.2",
|
|
46
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
46
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.76"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"rescript": "12.3.0"
|
|
@@ -24,7 +24,7 @@ let commandSchema = PluginSpec.commandSchema->S.castToUnknown
|
|
|
24
24
|
// Every variant of `PluginSpec.command`, walked by the same `extractCommandDefs`
|
|
25
25
|
// an ordinary aggregate goes through. The hand-written alternative described the
|
|
26
26
|
// arguments with a local `{id}` schema while the generated SDL declared
|
|
27
|
-
// `Platform_Plugin_Activate(
|
|
27
|
+
// `Platform_Plugin_Activate(id: ID!, version: String!)`, so AutoUI built a mutation
|
|
28
28
|
// missing a required argument and every admin row action was rejected before it
|
|
29
29
|
// reached the aggregate. Deriving from `commandSchema` — the same schema the SDL
|
|
30
30
|
// is generated from — cannot reproduce that class of fault.
|
|
@@ -38,6 +38,7 @@ let pluginCommands: array<commandDef> = Plugin_Structure.extractCommandDefs(
|
|
|
38
38
|
~mutationFieldFor=variantName =>
|
|
39
39
|
Api_Naming.adminField(~name=PluginSpec.name ++ "_" ++ variantName),
|
|
40
40
|
~commandAuthorization=PluginSpec.commandAuthorization->Obj.magic,
|
|
41
|
+
~commandTransition=PluginSpec.commandTransition->Obj.magic,
|
|
41
42
|
commandSchema,
|
|
42
43
|
)
|
|
43
44
|
|
|
@@ -76,6 +77,8 @@ let structure: pluginStructure = {
|
|
|
76
77
|
extensionPoints: None,
|
|
77
78
|
requiredStores: None,
|
|
78
79
|
requiredStoreDeclarations: None,
|
|
80
|
+
requiredCapabilities: None,
|
|
81
|
+
traitDeclarations: None,
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
/** The definition the platform's own EventCollector ships as its
|
|
@@ -7,7 +7,7 @@ import * as PluginsReadModelSpec$ReventlessCore from "../plugin/lifecycle/Plugin
|
|
|
7
7
|
|
|
8
8
|
let pluginId = "Platform";
|
|
9
9
|
|
|
10
|
-
let pluginCommands = Plugin_Structure$ReventlessCore.extractCommandDefs(true, variantName => Api_Naming$ReventlessCore.adminField(PluginSpec$ReventlessCore.name + "_" + variantName), PluginSpec$ReventlessCore.commandAuthorization, PluginSpec$ReventlessCore.commandSchema);
|
|
10
|
+
let pluginCommands = Plugin_Structure$ReventlessCore.extractCommandDefs(true, variantName => Api_Naming$ReventlessCore.adminField(PluginSpec$ReventlessCore.name + "_" + variantName), PluginSpec$ReventlessCore.commandAuthorization, PluginSpec$ReventlessCore.commandTransition, PluginSpec$ReventlessCore.commandSchema);
|
|
11
11
|
|
|
12
12
|
let pluginAggregate_producedEventTypes = [];
|
|
13
13
|
|
|
@@ -60,7 +60,9 @@ let structure = {
|
|
|
60
60
|
extensions: structure_extensions,
|
|
61
61
|
extensionPoints: undefined,
|
|
62
62
|
requiredStores: undefined,
|
|
63
|
-
requiredStoreDeclarations: undefined
|
|
63
|
+
requiredStoreDeclarations: undefined,
|
|
64
|
+
requiredCapabilities: undefined,
|
|
65
|
+
traitDeclarations: undefined
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
let internalPluginDefinition = {
|
|
@@ -134,7 +134,9 @@ function curateStructure(pluginId, def, sel) {
|
|
|
134
134
|
extensions: def.extensions,
|
|
135
135
|
extensionPoints: def.extensionPoints,
|
|
136
136
|
requiredStores: def.requiredStores,
|
|
137
|
-
requiredStoreDeclarations: def.requiredStoreDeclarations
|
|
137
|
+
requiredStoreDeclarations: def.requiredStoreDeclarations,
|
|
138
|
+
requiredCapabilities: def.requiredCapabilities,
|
|
139
|
+
traitDeclarations: def.traitDeclarations
|
|
138
140
|
};
|
|
139
141
|
});
|
|
140
142
|
}
|
|
@@ -36,17 +36,35 @@ let sdlTypes: array<string> = [
|
|
|
36
36
|
// notification-only (`command = unit`) extension point — see `extensionPointDef`.
|
|
37
37
|
`type Platform_ExtensionPointDef {\n name: String!\n delegateNames: [String!]!\n sourceEventTypes: [String!]!\n commandTypes: [String!]\n publishedEvents: [Platform_PublishedEventDef!]\n acceptedCommands: [Platform_AcceptedCommandDef!]\n}`,
|
|
38
38
|
`type Platform_RequiredStoreDeclaration {\n store: String!\n component: String!\n field: String!\n annotation: String\n}`,
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
|
|
39
|
+
// The capability a component declares its translate reaches for. No `field`:
|
|
40
|
+
// unlike a store, this need is not expressible as an annotation on one.
|
|
41
|
+
`type Platform_RequiredCapabilityDeclaration {\n capability: String!\n component: String!\n}`,
|
|
42
|
+
// One graft's provenance. `posture` is a String rather than an enum for the
|
|
43
|
+
// reason the capability above is: a plugin built against a newer framework,
|
|
44
|
+
// naming a posture this schema has never heard of, still decodes.
|
|
45
|
+
//
|
|
46
|
+
// It records ORIGIN, never behaviour — a grafted file is the host's to edit
|
|
47
|
+
// afterwards — so a reader must not paint a declared graft as a verified one.
|
|
48
|
+
`type Platform_TraitDeclaration {\n trait: String!\n version: String!\n posture: String!\n component: String!\n}`,
|
|
49
|
+
// `extensionPoints` / `requiredStores` / `requiredStoreDeclarations` /
|
|
50
|
+
// `requiredCapabilities` / `traitDeclarations` are nullable lists, not `[T!]!`: all five are optional on
|
|
51
|
+
// `pluginStructure` so that plugin definitions persisted before the field existed
|
|
52
|
+
// still decode. A structure written by an older deploy sends null, and null is the
|
|
53
|
+
// honest answer — an empty list would claim the plugin has no extension points when
|
|
54
|
+
// the truth is that the deployment cannot say.
|
|
55
|
+
`type Platform_PluginStructureEntry {\n pluginId: String!\n readModels: [Platform_ReadSideDef!]!\n stateViewSlices: [Platform_ReadSideDef!]!\n stateChangeSlices: [Platform_WriteSideDef!]!\n aggregates: [Platform_WriteSideDef!]!\n automationSlices: [Platform_AutomationSliceDef!]!\n outboundTranslationSlices: [Platform_OutboundTranslationSliceDef!]!\n inboundTranslationSlices: [Platform_InboundTranslationSliceDef!]!\n extensions: [Platform_ExtensionDef!]!\n extensionPoints: [Platform_ExtensionPointDef!]\n requiredStores: [String!]\n requiredStoreDeclarations: [Platform_RequiredStoreDeclaration!]\n requiredCapabilities: [Platform_RequiredCapabilityDeclaration!]\n traitDeclarations: [Platform_TraitDeclaration!]\n}`,
|
|
46
56
|
]
|
|
47
57
|
|
|
48
58
|
let sdlQueryField: string = ` Platform_PluginStructures: [Platform_PluginStructureEntry!]!`
|
|
49
59
|
|
|
60
|
+
let encodeTraitDeclaration = (d: traitDeclaration): JSON.t =>
|
|
61
|
+
Dict.fromArray([
|
|
62
|
+
("trait", JSON.Encode.string(d.trait)),
|
|
63
|
+
("version", JSON.Encode.string(d.version)),
|
|
64
|
+
("posture", JSON.Encode.string(d.posture)),
|
|
65
|
+
("component", JSON.Encode.string(d.component)),
|
|
66
|
+
])->JSON.Encode.object
|
|
67
|
+
|
|
50
68
|
let encodeExtensionPointDef = (e: extensionPointDef): JSON.t =>
|
|
51
69
|
Dict.fromArray([
|
|
52
70
|
("name", JSON.Encode.string(e.name)),
|
|
@@ -98,6 +116,12 @@ let encodeRequiredStoreDeclaration = (d: requiredStoreDeclaration): JSON.t =>
|
|
|
98
116
|
("annotation", d.annotation->Option.mapOr(JSON.Encode.null, JSON.Encode.string)),
|
|
99
117
|
])->JSON.Encode.object
|
|
100
118
|
|
|
119
|
+
let encodeRequiredCapabilityDeclaration = (d: requiredCapabilityDeclaration): JSON.t =>
|
|
120
|
+
Dict.fromArray([
|
|
121
|
+
("capability", JSON.Encode.string(d.capability)),
|
|
122
|
+
("component", JSON.Encode.string(d.component)),
|
|
123
|
+
])->JSON.Encode.object
|
|
124
|
+
|
|
101
125
|
// Deliberately NOT filtered by `isPublicQueryable`: that filter is the AutoUI
|
|
102
126
|
// contract, and applying it here would silently drop Internal components from the
|
|
103
127
|
// graph a developer tool draws.
|
|
@@ -165,4 +189,16 @@ let encodePluginStructureEntry = (~pluginId: string, def: pluginStructure): JSON
|
|
|
165
189
|
ds->Array.map(encodeRequiredStoreDeclaration)->JSON.Encode.array
|
|
166
190
|
),
|
|
167
191
|
),
|
|
192
|
+
(
|
|
193
|
+
"requiredCapabilities",
|
|
194
|
+
def.requiredCapabilities->Option.mapOr(JSON.Encode.null, ds =>
|
|
195
|
+
ds->Array.map(encodeRequiredCapabilityDeclaration)->JSON.Encode.array
|
|
196
|
+
),
|
|
197
|
+
),
|
|
198
|
+
(
|
|
199
|
+
"traitDeclarations",
|
|
200
|
+
def.traitDeclarations->Option.mapOr(JSON.Encode.null, ds =>
|
|
201
|
+
ds->Array.map(encodeTraitDeclaration)->JSON.Encode.array
|
|
202
|
+
),
|
|
203
|
+
),
|
|
168
204
|
])->JSON.Encode.object
|
|
@@ -9,9 +9,32 @@ let sdlTypes = [
|
|
|
9
9
|
`type Platform_AcceptedCommandDef {\n name: String!\n toCommandTypes: [String!]!\n}`,
|
|
10
10
|
`type Platform_ExtensionPointDef {\n name: String!\n delegateNames: [String!]!\n sourceEventTypes: [String!]!\n commandTypes: [String!]\n publishedEvents: [Platform_PublishedEventDef!]\n acceptedCommands: [Platform_AcceptedCommandDef!]\n}`,
|
|
11
11
|
`type Platform_RequiredStoreDeclaration {\n store: String!\n component: String!\n field: String!\n annotation: String\n}`,
|
|
12
|
-
`type
|
|
12
|
+
`type Platform_RequiredCapabilityDeclaration {\n capability: String!\n component: String!\n}`,
|
|
13
|
+
`type Platform_TraitDeclaration {\n trait: String!\n version: String!\n posture: String!\n component: String!\n}`,
|
|
14
|
+
`type Platform_PluginStructureEntry {\n pluginId: String!\n readModels: [Platform_ReadSideDef!]!\n stateViewSlices: [Platform_ReadSideDef!]!\n stateChangeSlices: [Platform_WriteSideDef!]!\n aggregates: [Platform_WriteSideDef!]!\n automationSlices: [Platform_AutomationSliceDef!]!\n outboundTranslationSlices: [Platform_OutboundTranslationSliceDef!]!\n inboundTranslationSlices: [Platform_InboundTranslationSliceDef!]!\n extensions: [Platform_ExtensionDef!]!\n extensionPoints: [Platform_ExtensionPointDef!]\n requiredStores: [String!]\n requiredStoreDeclarations: [Platform_RequiredStoreDeclaration!]\n requiredCapabilities: [Platform_RequiredCapabilityDeclaration!]\n traitDeclarations: [Platform_TraitDeclaration!]\n}`
|
|
13
15
|
];
|
|
14
16
|
|
|
17
|
+
function encodeTraitDeclaration(d) {
|
|
18
|
+
return Object.fromEntries([
|
|
19
|
+
[
|
|
20
|
+
"trait",
|
|
21
|
+
d.trait
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
"version",
|
|
25
|
+
d.version
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
"posture",
|
|
29
|
+
d.posture
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
"component",
|
|
33
|
+
d.component
|
|
34
|
+
]
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
function encodeExtensionPointDef(e) {
|
|
16
39
|
return Object.fromEntries([
|
|
17
40
|
[
|
|
@@ -80,6 +103,19 @@ function encodeRequiredStoreDeclaration(d) {
|
|
|
80
103
|
]);
|
|
81
104
|
}
|
|
82
105
|
|
|
106
|
+
function encodeRequiredCapabilityDeclaration(d) {
|
|
107
|
+
return Object.fromEntries([
|
|
108
|
+
[
|
|
109
|
+
"capability",
|
|
110
|
+
d.capability
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
"component",
|
|
114
|
+
d.component
|
|
115
|
+
]
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
|
|
83
119
|
function encodePluginStructureEntry(pluginId, def) {
|
|
84
120
|
return Object.fromEntries([
|
|
85
121
|
[
|
|
@@ -129,6 +165,14 @@ function encodePluginStructureEntry(pluginId, def) {
|
|
|
129
165
|
[
|
|
130
166
|
"requiredStoreDeclarations",
|
|
131
167
|
Stdlib_Option.mapOr(def.requiredStoreDeclarations, null, ds => ds.map(encodeRequiredStoreDeclaration))
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
"requiredCapabilities",
|
|
171
|
+
Stdlib_Option.mapOr(def.requiredCapabilities, null, ds => ds.map(encodeRequiredCapabilityDeclaration))
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
"traitDeclarations",
|
|
175
|
+
Stdlib_Option.mapOr(def.traitDeclarations, null, ds => ds.map(encodeTraitDeclaration))
|
|
132
176
|
]
|
|
133
177
|
]);
|
|
134
178
|
}
|
|
@@ -138,8 +182,10 @@ let sdlQueryField = ` Platform_PluginStructures: [Platform_PluginStructureEntry
|
|
|
138
182
|
export {
|
|
139
183
|
sdlTypes,
|
|
140
184
|
sdlQueryField,
|
|
185
|
+
encodeTraitDeclaration,
|
|
141
186
|
encodeExtensionPointDef,
|
|
142
187
|
encodeRequiredStoreDeclaration,
|
|
188
|
+
encodeRequiredCapabilityDeclaration,
|
|
143
189
|
encodePluginStructureEntry,
|
|
144
190
|
}
|
|
145
191
|
/* No side effect */
|
|
@@ -46,6 +46,12 @@ function commandAuthorization(param) {
|
|
|
46
46
|
return "AllowAuthenticated";
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
function commandTransition(param) {
|
|
50
|
+
return "Unrestricted";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let traits = [];
|
|
54
|
+
|
|
49
55
|
let name = "UiFragmentRegistry";
|
|
50
56
|
|
|
51
57
|
let Id;
|
|
@@ -66,5 +72,7 @@ export {
|
|
|
66
72
|
moduleUrl,
|
|
67
73
|
commandAuthorization,
|
|
68
74
|
readConsistency,
|
|
75
|
+
commandTransition,
|
|
76
|
+
traits,
|
|
69
77
|
}
|
|
70
78
|
/* commandSchema Not a pure module */
|
|
@@ -3,11 +3,45 @@ open ReventlessInfra.Api
|
|
|
3
3
|
let isNoApi = (commandSchema: S.t<unknown>): bool =>
|
|
4
4
|
commandSchema->S.Metadata.get(~id=noApiId)->Option.getOr(false)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
// Variants excluded by a mark on the member itself. This is the half that
|
|
7
|
+
// survives a spread: splicing copies members, not the metadata of the union they
|
|
8
|
+
// came from, so a command a trait marked internal is only still recognisable here.
|
|
9
|
+
let excludedByMembers = (commandSchema: S.t<unknown>): array<string> =>
|
|
10
|
+
switch commandSchema {
|
|
11
|
+
| AnyOf({anyOf}) =>
|
|
12
|
+
anyOf->Array.filterMap(member =>
|
|
13
|
+
member->S.Metadata.get(~id=noApiVariantId)->Option.getOr(false)
|
|
14
|
+
? variantNameOf(member)
|
|
15
|
+
: None
|
|
16
|
+
)
|
|
17
|
+
| _ => []
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
Every variant excluded from the API, from both records of the fact.
|
|
22
|
+
|
|
23
|
+
The union's own set covers variants the schema's author declared; the members'
|
|
24
|
+
marks cover variants spliced in from another type, whose author's declaration is
|
|
25
|
+
in a file this one never mentions. A reader that consulted only the first
|
|
26
|
+
published someone else's internal commands.
|
|
27
|
+
|
|
28
|
+
`None` still means "nothing is excluded", so a caller's existing branch is
|
|
29
|
+
unchanged.
|
|
30
|
+
*/
|
|
31
|
+
let getExcludedVariants = (commandSchema: S.t<unknown>): option<Set.t<string>> => {
|
|
32
|
+
let fromMembers = excludedByMembers(commandSchema)
|
|
33
|
+
switch (commandSchema->S.Metadata.get(~id=noApiVariantsId), fromMembers) {
|
|
34
|
+
| (None, []) => None
|
|
35
|
+
| (None, members) => Some(Set.fromArray(members))
|
|
36
|
+
| (Some(declared), []) => Some(declared)
|
|
37
|
+
| (Some(declared), members) =>
|
|
38
|
+
let all = declared->Set.toArray->Array.concat(members)
|
|
39
|
+
Some(Set.fromArray(all))
|
|
40
|
+
}
|
|
41
|
+
}
|
|
8
42
|
|
|
9
43
|
let filterNoApiVariants = (fieldNames: array<string>, commandSchema: S.t<unknown>): array<string> =>
|
|
10
|
-
switch commandSchema
|
|
44
|
+
switch getExcludedVariants(commandSchema) {
|
|
11
45
|
| None => fieldNames
|
|
12
46
|
| Some(excluded) => fieldNames->Array.filter(name => !(excluded->Set.has(name)))
|
|
13
47
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
6
|
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
6
7
|
|
|
@@ -8,12 +9,37 @@ function isNoApi(commandSchema) {
|
|
|
8
9
|
return Stdlib_Option.getOr(Sury.$Metadata_get(commandSchema, Api$ReventlessInfra.noApiId), false);
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
function excludedByMembers(commandSchema) {
|
|
13
|
+
if (commandSchema.type === "anyOf") {
|
|
14
|
+
return Stdlib_Array.filterMap(commandSchema.anyOf, member => {
|
|
15
|
+
if (Stdlib_Option.getOr(Sury.$Metadata_get(member, Api$ReventlessInfra.noApiVariantId), false)) {
|
|
16
|
+
return Api$ReventlessInfra.variantNameOf(member);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
function getExcludedVariants(commandSchema) {
|
|
12
|
-
|
|
25
|
+
let fromMembers = excludedByMembers(commandSchema);
|
|
26
|
+
let match = Sury.$Metadata_get(commandSchema, Api$ReventlessInfra.noApiVariantsId);
|
|
27
|
+
if (match === undefined) {
|
|
28
|
+
if (fromMembers.length !== 0) {
|
|
29
|
+
return new Set(fromMembers);
|
|
30
|
+
} else {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (fromMembers.length === 0) {
|
|
35
|
+
return match;
|
|
36
|
+
}
|
|
37
|
+
let all = Array.from(match).concat(fromMembers);
|
|
38
|
+
return new Set(all);
|
|
13
39
|
}
|
|
14
40
|
|
|
15
41
|
function filterNoApiVariants(fieldNames, commandSchema) {
|
|
16
|
-
let excluded =
|
|
42
|
+
let excluded = getExcludedVariants(commandSchema);
|
|
17
43
|
if (excluded !== undefined) {
|
|
18
44
|
return fieldNames.filter(name => !excluded.has(name));
|
|
19
45
|
} else {
|
|
@@ -23,6 +49,7 @@ function filterNoApiVariants(fieldNames, commandSchema) {
|
|
|
23
49
|
|
|
24
50
|
export {
|
|
25
51
|
isNoApi,
|
|
52
|
+
excludedByMembers,
|
|
26
53
|
getExcludedVariants,
|
|
27
54
|
filterNoApiVariants,
|
|
28
55
|
}
|
|
@@ -169,19 +169,19 @@ module Make = (
|
|
|
169
169
|
// Per-source erased dispatch — pre-compile decoders once at module init.
|
|
170
170
|
type dispatch = {
|
|
171
171
|
sourceName: string,
|
|
172
|
-
handle: (JSON.t, Reventless.AutomationSlice.context) => unit,
|
|
172
|
+
handle: (JSON.t, ~sourceId: string, Reventless.AutomationSlice.context) => unit,
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
let dispatches: array<dispatch> = Automation.mappings->Array.map((
|
|
176
176
|
module(M: Automation.Mapping),
|
|
177
177
|
) => {
|
|
178
178
|
let decoder = Reventless.DcbDecode.makeDecoder(M.sourceEventSchema)
|
|
179
|
-
let handle = (json: JSON.t, ctx: Reventless.AutomationSlice.context) => {
|
|
179
|
+
let handle = (json: JSON.t, ~sourceId: string, ctx: Reventless.AutomationSlice.context) => {
|
|
180
180
|
let (eventType, dataDict) = json->Message.splitMessage
|
|
181
181
|
switch decoder.decode(~eventType, ~data=dataDict) {
|
|
182
182
|
| Some(event) =>
|
|
183
183
|
// Collect — append new items keyed by ID; first writer wins (idempotent).
|
|
184
|
-
M.collect(event, ctx)->Array.forEach(((id, item)) => {
|
|
184
|
+
M.collect(event, ~sourceId, ctx)->Array.forEach(((id, item)) => {
|
|
185
185
|
switch todoItems->Dict.get(id) {
|
|
186
186
|
| Some(_) => () // Already exists — skip
|
|
187
187
|
| None =>
|
|
@@ -225,7 +225,7 @@ module Make = (
|
|
|
225
225
|
// Multiple mappings can share a sourceName; all matching dispatches run.
|
|
226
226
|
dispatches->Array.forEach(d => {
|
|
227
227
|
if d.sourceName == sourceName {
|
|
228
|
-
d.handle(eventPayload, ctx)
|
|
228
|
+
d.handle(eventPayload, ~sourceId=context.id, ctx)
|
|
229
229
|
}
|
|
230
230
|
})
|
|
231
231
|
})
|
|
@@ -57,14 +57,14 @@ function Make(Spec) {
|
|
|
57
57
|
};
|
|
58
58
|
let dispatches = Automation.mappings.map(M => {
|
|
59
59
|
let decoder = DcbDecode$Reventless.makeDecoder(M.sourceEventSchema);
|
|
60
|
-
let handle = (json, ctx) => {
|
|
60
|
+
let handle = (json, sourceId, ctx) => {
|
|
61
61
|
let match = Message$ReventlessCore.splitMessage(json);
|
|
62
62
|
let event = decoder.decode(match[0], match[1]);
|
|
63
63
|
if (event === undefined) {
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
let event$1 = Primitive_option.valFromOption(event);
|
|
67
|
-
M.collect(event$1, ctx).forEach(param => {
|
|
67
|
+
M.collect(event$1, sourceId, ctx).forEach(param => {
|
|
68
68
|
let id = param[0];
|
|
69
69
|
let match = todoItems[id];
|
|
70
70
|
if (match !== undefined) {
|
|
@@ -105,7 +105,7 @@ function Make(Spec) {
|
|
|
105
105
|
let eventPayload = dict !== undefined ? Stdlib_Option.getOr(dict["event"], json) : json;
|
|
106
106
|
dispatches.forEach(d => {
|
|
107
107
|
if (d.sourceName === sourceName) {
|
|
108
|
-
return d.handle(eventPayload, ctx);
|
|
108
|
+
return d.handle(eventPayload, context.id, ctx);
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
111
|
});
|
|
@@ -50,9 +50,9 @@ let queryEntries: array<querySchemaEntry> = [
|
|
|
50
50
|
// Plugin aggregate admin mutations — derived statically from PluginSpec.command,
|
|
51
51
|
// so the generated SDL contains one field per non-`@noApi` variant carrying that
|
|
52
52
|
// variant's command fields as args. Since the admin commands are name-keyed and
|
|
53
|
-
// version-scoped (`Activate(version)`
|
|
54
|
-
// the fields are e.g. `Platform_Plugin_Activate(id: ID!,
|
|
55
|
-
// (`id` = plugin name = aggregate instance; `
|
|
53
|
+
// version-scoped (`Activate({version})` and the same for `Deactivate`/`Retire`),
|
|
54
|
+
// the fields are e.g. `Platform_Plugin_Activate(id: ID!, version: String!): CommandResult!`
|
|
55
|
+
// (`id` = plugin name = aggregate instance; `version` = target version). `Retire` is
|
|
56
56
|
// API-exposed (manual archive, §2.5). Internal-protocol variants (`Heartbeat`,
|
|
57
57
|
// `Connect`, `Disconnect`, `ReportIncompatibility`) carry `@noApi` and are filtered
|
|
58
58
|
// out by `ApiNoApiHelpers.filterNoApiVariants`. The same `commandSchema`-driven
|