@reventlessdev/reventless-core 3.0.0-alpha.156 → 3.0.0-alpha.158
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 +22 -0
- package/package.json +6 -6
- package/src/admin/AdminApi.res +80 -10
- package/src/admin/AdminApi.res.mjs +45 -7
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry.res +65 -0
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry.res.mjs +87 -0
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry_Behavior.res +58 -0
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry_Behavior.res.mjs +135 -0
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments.res +44 -0
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments.res.mjs +74 -0
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments_Projection.res +50 -0
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments_Projection.res.mjs +80 -0
- package/src/admin/Platform_Admin.res +46 -1
- package/src/admin/Platform_Admin.res.mjs +20 -6
- package/src/admin/Platform_ApiFragmentsApi.res +32 -0
- package/src/admin/Platform_ApiFragmentsApi.res.mjs +52 -0
- package/src/admin/Platform_UIFragmentsApi.res +1 -1
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res +50 -0
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +70 -0
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry_Behavior.res +33 -0
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry_Behavior.res.mjs +80 -0
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res +33 -0
- package/src/admin/{UIFragmentRegistryReadModelSpec.res.mjs → UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs} +24 -2
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res +34 -0
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res.mjs +54 -0
- package/src/components/Api/Api_Naming.res +1 -1
- package/src/components/Api/GraphQL_FragmentGenerator.res +7 -11
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +8 -22
- package/src/components/Api/GraphQL_PushPlanner.res +65 -0
- package/src/components/Api/GraphQL_PushPlanner.res.mjs +46 -0
- package/src/components/Api/GraphQL_Stitcher.res +72 -1
- package/src/components/Api/GraphQL_Stitcher.res.mjs +53 -2
- package/src/components/Dcb/Dcb_Builder.res +16 -6
- package/src/components/Dcb/Dcb_Builder.res.mjs +10 -7
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +6 -1
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +1 -1
- package/src/plugin/api/PluginBaseFragment.res +5 -6
- package/src/plugin/api/PluginBaseFragment.res.mjs +0 -1
- package/src/plugin/component/Plugin_Builder.res +4 -1
- package/src/plugin/component/Plugin_Builder.res.mjs +7 -6
- package/src/plugin/component/Plugin_Helpers.res +30 -0
- package/src/plugin/component/Plugin_Helpers.res.mjs +13 -3
- package/src/plugin/component/Plugin_SubscriptionSchema.res +19 -9
- package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +23 -14
- package/src/plugin/connect/PluginConnectExtension_Mapping.res +28 -6
- package/src/plugin/connect/PluginConnectExtension_Mapping.res.mjs +34 -14
- package/src/plugin/connect/PluginExtensionPoint_Builder.res +7 -1
- package/src/plugin/connect/PluginExtensionPoint_Builder.res.mjs +5 -1
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res +3 -1
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +4 -2
- package/src/plugin/connect/PluginExtensionPoint_UiFragment.res +52 -0
- package/src/plugin/connect/PluginExtensionPoint_UiFragment.res.mjs +74 -0
- package/src/plugin/lifecycle/PluginBehavior.res +9 -51
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +39 -68
- package/src/plugin/lifecycle/PluginSpec.res +0 -18
- package/src/plugin/lifecycle/PluginSpec.res.mjs +0 -30
- package/src/plugin/lifecycle/PluginsProjection.res +2 -6
- package/src/plugin/lifecycle/PluginsProjection.res.mjs +0 -2
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +0 -2
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +0 -1
- package/tests/admin/Platform_ApiFragmentsApiTest.res +66 -0
- package/tests/admin/Platform_ApiFragmentsApiTest.res.mjs +68 -0
- package/tests/admin/Platform_UIFragmentsApiTest.res +1 -1
- package/tests/api/GraphQL_PushPlannerTest.res +62 -0
- package/tests/api/GraphQL_PushPlannerTest.res.mjs +80 -0
- package/tests/api/GraphQL_StitcherTest.res +63 -0
- package/tests/api/GraphQL_StitcherTest.res.mjs +75 -0
- package/tests/logger/LogFormatTest.res +1 -2
- package/tests/logger/LogFormatTest.res.mjs +1 -2
- package/tests/message/MessageTest.res +0 -3
- package/tests/message/MessageTest.res.mjs +0 -3
- package/src/admin/UIFragmentRegistryProjection.res +0 -43
- package/src/admin/UIFragmentRegistryProjection.res.mjs +0 -81
- package/src/admin/UIFragmentRegistryReadModelSpec.res +0 -13
|
@@ -8,22 +8,42 @@ function Make(Spec) {
|
|
|
8
8
|
let mapIncomingEvent = (pluginId, event, _meta, _pluginDef, _queryEngine) => {
|
|
9
9
|
let pluginDefinition = Spec.pluginDefinition;
|
|
10
10
|
let id = pluginDefinition.id;
|
|
11
|
-
if (typeof event
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
_0: id,
|
|
16
|
-
_1: {
|
|
17
|
-
TAG: "ConnectPlugin",
|
|
18
|
-
_0: pluginDefinition
|
|
19
|
-
}
|
|
20
|
-
}];
|
|
21
|
-
} else {
|
|
22
|
-
return [];
|
|
23
|
-
}
|
|
24
|
-
} else {
|
|
11
|
+
if (typeof event === "object") {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
if (pluginId !== id) {
|
|
25
15
|
return [];
|
|
26
16
|
}
|
|
17
|
+
let manifest = Spec.uiFragments;
|
|
18
|
+
if (manifest !== undefined) {
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
TAG: "PublishExtensionPointCommand",
|
|
22
|
+
_0: id,
|
|
23
|
+
_1: {
|
|
24
|
+
TAG: "ConnectPlugin",
|
|
25
|
+
_0: pluginDefinition
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
TAG: "PublishExtensionPointCommand",
|
|
30
|
+
_0: id,
|
|
31
|
+
_1: {
|
|
32
|
+
TAG: "RegisterUiFragment",
|
|
33
|
+
_0: manifest
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
} else {
|
|
38
|
+
return [{
|
|
39
|
+
TAG: "PublishExtensionPointCommand",
|
|
40
|
+
_0: id,
|
|
41
|
+
_1: {
|
|
42
|
+
TAG: "ConnectPlugin",
|
|
43
|
+
_0: pluginDefinition
|
|
44
|
+
}
|
|
45
|
+
}];
|
|
46
|
+
}
|
|
27
47
|
};
|
|
28
48
|
let $$let = ExtensionMapping$ReventlessInfra.NoDelegate.Id;
|
|
29
49
|
let ConnectPluginMapping = ExtensionMapping$ReventlessInfra.Make({
|
|
@@ -26,7 +26,13 @@ module Make = (
|
|
|
26
26
|
|
|
27
27
|
let name = PluginMappingInstance.Mapping.delegateName
|
|
28
28
|
let moduleUrl = PluginExtensionPointSpec.moduleUrl
|
|
29
|
-
|
|
29
|
+
// The UI-fragment mapping routes RegisterUiFragment / (Disconnect →) DeregisterUiFragment to
|
|
30
|
+
// the admin UiFragmentRegistry slice; the Plugin mapping keeps the lifecycle. Both run per
|
|
31
|
+
// incoming command (ExtensionPoint_Callback fans commands through all mappings).
|
|
32
|
+
let mappings: array<module(Mapping)> = [
|
|
33
|
+
module(PluginMappingInstance.Mapping),
|
|
34
|
+
module(PluginExtensionPoint_UiFragment.Mapping),
|
|
35
|
+
]
|
|
30
36
|
}
|
|
31
37
|
include ExtensionPoint_Builder.Make(
|
|
32
38
|
PluginExtensionPointSpec,
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
import * as ExtensionPoint_Builder$ReventlessCore from "../../components/ExtensionPoint/ExtensionPoint_Builder.res.mjs";
|
|
4
4
|
import * as PluginExtensionPointSpec$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/PluginExtensionPointSpec.res.mjs";
|
|
5
5
|
import * as PluginExtensionPoint_Plugin$ReventlessCore from "./PluginExtensionPoint_Plugin.res.mjs";
|
|
6
|
+
import * as PluginExtensionPoint_UiFragment$ReventlessCore from "./PluginExtensionPoint_UiFragment.res.mjs";
|
|
6
7
|
|
|
7
8
|
function Make(Spec) {
|
|
8
9
|
return RuntimeEnvironment => (CommandTopicChannel => (EventTopicAdapter => (ExtensionPointRuntimeBuilder => {
|
|
9
10
|
let PluginMappingInstance = PluginExtensionPoint_Plugin$ReventlessCore.Make(Spec);
|
|
10
11
|
let name = PluginMappingInstance.Mapping.delegateName;
|
|
11
|
-
let mappings = [
|
|
12
|
+
let mappings = [
|
|
13
|
+
PluginMappingInstance.Mapping,
|
|
14
|
+
PluginExtensionPoint_UiFragment$ReventlessCore.Mapping
|
|
15
|
+
];
|
|
12
16
|
let Mappings = {
|
|
13
17
|
name: name,
|
|
14
18
|
moduleUrl: PluginExtensionPointSpec$ReventlessInfra.moduleUrl,
|
|
@@ -191,6 +191,9 @@ module Make = (Spec: Spec) => {
|
|
|
191
191
|
HandleDirective(directiveHandler, DeleteDisconnectSchedule(id)),
|
|
192
192
|
]
|
|
193
193
|
| ForwardCommand(forwardCommand) => [HandleDirective(directiveHandler, ForwardCommand(forwardCommand))]
|
|
194
|
+
// Routed to the UiFragmentRegistry slice by the sibling UI-fragment mapping, not the
|
|
195
|
+
// Plugin aggregate — a no-op here.
|
|
196
|
+
| RegisterUiFragment(_) => []
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
let mapOutgoingEvent = Some(
|
|
@@ -230,7 +233,6 @@ module Make = (Spec: Spec) => {
|
|
|
230
233
|
| IncompatiblePluginDetected(pluginDefinition) => [
|
|
231
234
|
PublishEvent(pluginDefinition.id, IncompatiblePlugin(pluginDefinition)),
|
|
232
235
|
]
|
|
233
|
-
| UIFragmentRegistered(_) | UIFragmentUpdated(_) | UIFragmentDeregistered(_) => []
|
|
234
236
|
},
|
|
235
237
|
)
|
|
236
238
|
}
|
|
@@ -183,6 +183,8 @@ function Make(Spec) {
|
|
|
183
183
|
_0: cmd._0
|
|
184
184
|
}
|
|
185
185
|
}];
|
|
186
|
+
case "RegisterUiFragment" :
|
|
187
|
+
return [];
|
|
186
188
|
case "RedetectPlugin" :
|
|
187
189
|
return [
|
|
188
190
|
{
|
|
@@ -213,6 +215,8 @@ function Make(Spec) {
|
|
|
213
215
|
_0: Plugin$ReventlessCore.makeId(id, event._0),
|
|
214
216
|
_1: "UnknownPluginDetected"
|
|
215
217
|
}];
|
|
218
|
+
case "VersionSuperseded" :
|
|
219
|
+
return [];
|
|
216
220
|
case "VersionConnected" :
|
|
217
221
|
case "VersionPromoted" :
|
|
218
222
|
break;
|
|
@@ -296,8 +300,6 @@ function Make(Spec) {
|
|
|
296
300
|
_0: pluginDefinition$4
|
|
297
301
|
}
|
|
298
302
|
}];
|
|
299
|
-
default:
|
|
300
|
-
return [];
|
|
301
303
|
}
|
|
302
304
|
let pluginDefinition$5 = event._0;
|
|
303
305
|
return [
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Second mapping on the admin PluginExtensionPoint, routing UI-fragment lifecycle to the
|
|
2
|
+
// admin UiFragmentRegistry StateChangeSlice (docs/plans/event-sourced-fragment-registries.md).
|
|
3
|
+
//
|
|
4
|
+
// The EP runtime fans every incoming command through ALL mappings and flattens the results
|
|
5
|
+
// (ExtensionPoint_Callback.mapIncomingCommands). This mapping's Delegate is the slice, so its
|
|
6
|
+
// PublishCommand encodes with the slice's commandSchema and routes to the slice's command
|
|
7
|
+
// topic via publishToAggregates["UiFragmentRegistry"] (registered by Platform_Admin's merge).
|
|
8
|
+
// The sibling PluginExtensionPoint_Plugin mapping keeps handling lifecycle for the Plugin
|
|
9
|
+
// aggregate; the two run side by side on the same EP.
|
|
10
|
+
//
|
|
11
|
+
// A StateChangeSlice Spec structurally satisfies Reventless.Aggregate.Spec (name, Id,
|
|
12
|
+
// command/event/error + schemas, commandSchema, commandAuthorization, moduleUrl), which is all
|
|
13
|
+
// ExtensionPointMapping.Make consumes from a Delegate.
|
|
14
|
+
|
|
15
|
+
open ReventlessInfra.ExtensionPointMapping
|
|
16
|
+
|
|
17
|
+
module PluginExtensionPointSpec = ReventlessInfra.PluginExtensionPointSpec
|
|
18
|
+
|
|
19
|
+
module UiFragmentMapping = {
|
|
20
|
+
module ExtensionPoint = PluginExtensionPointSpec
|
|
21
|
+
module Delegate = UiFragmentRegistry
|
|
22
|
+
|
|
23
|
+
let moduleUrl: string = %raw(`import.meta.url`)
|
|
24
|
+
|
|
25
|
+
// `id` is the EP transport id (`name@version`); the registry is keyed by bare plugin name,
|
|
26
|
+
// so route on `Plugin.name(id)`. `at` carries the incoming command's producer time (the
|
|
27
|
+
// StateViewSlice projection has no event meta).
|
|
28
|
+
let mapIncomingCommand = (id, cmd, meta: Reventless.Message.meta) =>
|
|
29
|
+
switch cmd {
|
|
30
|
+
| PluginExtensionPointSpec.RegisterUiFragment(manifest) => [
|
|
31
|
+
PublishCommand(
|
|
32
|
+
Plugin.name(id),
|
|
33
|
+
Delegate.RegisterUiFragment({
|
|
34
|
+
pluginId: Plugin.name(id),
|
|
35
|
+
manifest,
|
|
36
|
+
at: meta.time,
|
|
37
|
+
}),
|
|
38
|
+
),
|
|
39
|
+
]
|
|
40
|
+
// Deregistration rides DisconnectPlugin, which the admin disconnect schedule also sends on
|
|
41
|
+
// heartbeat timeout — so both graceful and timeout disconnects deregister the fragment.
|
|
42
|
+
| DisconnectPlugin => [
|
|
43
|
+
PublishCommand(Plugin.name(id), Delegate.DeregisterUiFragment({pluginId: Plugin.name(id)})),
|
|
44
|
+
]
|
|
45
|
+
| Heartbeat(_) | ConnectPlugin(_) | RedetectPlugin(_) | ForwardCommand(_) => []
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// This mapping never reflects slice events back through the EP.
|
|
49
|
+
let mapOutgoingEvent = None
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module Mapping = ReventlessInfra.ExtensionPointMapping.Make(UiFragmentMapping)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
4
|
+
import * as Plugin$ReventlessCore from "../component/Plugin.res.mjs";
|
|
5
|
+
import * as UiFragmentRegistry$ReventlessCore from "../../admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs";
|
|
6
|
+
import * as ExtensionPointMapping$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/ExtensionPointMapping.res.mjs";
|
|
7
|
+
import * as PluginExtensionPointSpec$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/PluginExtensionPointSpec.res.mjs";
|
|
8
|
+
|
|
9
|
+
let moduleUrl = import.meta.url;
|
|
10
|
+
|
|
11
|
+
function mapIncomingCommand(id, cmd, meta) {
|
|
12
|
+
if (typeof cmd !== "object") {
|
|
13
|
+
return [{
|
|
14
|
+
TAG: "PublishCommand",
|
|
15
|
+
_0: Plugin$ReventlessCore.name(id),
|
|
16
|
+
_1: {
|
|
17
|
+
TAG: "DeregisterUiFragment",
|
|
18
|
+
pluginId: Plugin$ReventlessCore.name(id)
|
|
19
|
+
}
|
|
20
|
+
}];
|
|
21
|
+
} else if (cmd.TAG === "RegisterUiFragment") {
|
|
22
|
+
return [{
|
|
23
|
+
TAG: "PublishCommand",
|
|
24
|
+
_0: Plugin$ReventlessCore.name(id),
|
|
25
|
+
_1: {
|
|
26
|
+
TAG: "RegisterUiFragment",
|
|
27
|
+
pluginId: Plugin$ReventlessCore.name(id),
|
|
28
|
+
manifest: cmd._0,
|
|
29
|
+
at: meta.time
|
|
30
|
+
}
|
|
31
|
+
}];
|
|
32
|
+
} else {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let UiFragmentMapping = {
|
|
38
|
+
ExtensionPoint: undefined,
|
|
39
|
+
Delegate: undefined,
|
|
40
|
+
moduleUrl: moduleUrl,
|
|
41
|
+
mapIncomingCommand: mapIncomingCommand,
|
|
42
|
+
mapOutgoingEvent: undefined
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
let Mapping = ExtensionPointMapping$ReventlessInfra.Make({
|
|
46
|
+
ExtensionPoint: {
|
|
47
|
+
name: PluginExtensionPointSpec$ReventlessInfra.name,
|
|
48
|
+
moduleUrl: PluginExtensionPointSpec$ReventlessInfra.moduleUrl,
|
|
49
|
+
commandSchema: PluginExtensionPointSpec$ReventlessInfra.commandSchema,
|
|
50
|
+
eventSchema: PluginExtensionPointSpec$ReventlessInfra.eventSchema,
|
|
51
|
+
directiveSchema: PluginExtensionPointSpec$ReventlessInfra.directiveSchema
|
|
52
|
+
},
|
|
53
|
+
Delegate: {
|
|
54
|
+
Id: Id$Reventless.$$String,
|
|
55
|
+
name: UiFragmentRegistry$ReventlessCore.name,
|
|
56
|
+
eventSchema: UiFragmentRegistry$ReventlessCore.eventSchema,
|
|
57
|
+
errorSchema: UiFragmentRegistry$ReventlessCore.errorSchema,
|
|
58
|
+
commandSchema: UiFragmentRegistry$ReventlessCore.commandSchema,
|
|
59
|
+
moduleUrl: UiFragmentRegistry$ReventlessCore.moduleUrl,
|
|
60
|
+
commandAuthorization: UiFragmentRegistry$ReventlessCore.commandAuthorization
|
|
61
|
+
},
|
|
62
|
+
moduleUrl: moduleUrl,
|
|
63
|
+
mapIncomingCommand: mapIncomingCommand,
|
|
64
|
+
mapOutgoingEvent: undefined
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
let PluginExtensionPointSpec;
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
PluginExtensionPointSpec,
|
|
71
|
+
UiFragmentMapping,
|
|
72
|
+
Mapping,
|
|
73
|
+
}
|
|
74
|
+
/* moduleUrl Not a pure module */
|
|
@@ -38,18 +38,6 @@ let snapshot = None
|
|
|
38
38
|
|
|
39
39
|
let atomicCounter = None
|
|
40
40
|
|
|
41
|
-
let uiRegisterEvents = (pluginId, manifest) =>
|
|
42
|
-
switch manifest {
|
|
43
|
-
| None => []
|
|
44
|
-
| Some(manifest) => [(UIFragmentRegistered({pluginId, manifest}): event)]
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let uiDeregisterEvents = (pluginId, manifest) =>
|
|
48
|
-
switch manifest {
|
|
49
|
-
| None => []
|
|
50
|
-
| Some(_) => [(UIFragmentDeregistered({pluginId: pluginId}): event)]
|
|
51
|
-
}
|
|
52
|
-
|
|
53
41
|
// Highest version with status Connected, or None.
|
|
54
42
|
let highestConnected = (known: dict<knownVersion>): option<version> =>
|
|
55
43
|
known
|
|
@@ -93,11 +81,11 @@ let currentAfterConnect = (known, v) =>
|
|
|
93
81
|
| Some(h) => Plugin.compareVersions(v, h) >= 0 ? v : h
|
|
94
82
|
}
|
|
95
83
|
|
|
96
|
-
// Events emitted when `v` (with `def`) becomes Connected: the VersionConnected
|
|
97
|
-
//
|
|
84
|
+
// Events emitted when `v` (with `def`) becomes Connected: the VersionConnected,
|
|
85
|
+
// plus a VersionSuperseded record when `v` takes over from a
|
|
98
86
|
// different current version.
|
|
99
87
|
let connectEvents = (state: state, v: version, def: pluginDefinition): array<event> => {
|
|
100
|
-
let base =
|
|
88
|
+
let base = [VersionConnected(def)]
|
|
101
89
|
let supersede = if currentAfterConnect(state.known, v) == v {
|
|
102
90
|
switch state.current {
|
|
103
91
|
| Some(c) if c != v =>
|
|
@@ -159,7 +147,7 @@ let decide = (state, command) =>
|
|
|
159
147
|
let v = def.version
|
|
160
148
|
switch state.known->Dict.get(v) {
|
|
161
149
|
// Idempotent when the definition is unchanged; when a redeploy carries a changed
|
|
162
|
-
// definition (e.g. a newly added `kind`, updated
|
|
150
|
+
// definition (e.g. a newly added `kind`, updated protocols) re-emit
|
|
163
151
|
// VersionConnected to overwrite the stored def and re-project the row. The version
|
|
164
152
|
// is already current, so connectEvents' supersede stays empty — a bare refresh.
|
|
165
153
|
| Some({status: Connected, definition}) => definition == def ? Ok([]) : Ok([VersionConnected(def)])
|
|
@@ -168,24 +156,13 @@ let decide = (state, command) =>
|
|
|
168
156
|
| Disconnect(v) =>
|
|
169
157
|
switch state.known->Dict.get(v) {
|
|
170
158
|
| Some({status: Connected, definition}) =>
|
|
171
|
-
Ok(
|
|
172
|
-
Array.concat(
|
|
173
|
-
Array.concat(
|
|
174
|
-
[VersionDisconnected(definition)],
|
|
175
|
-
uiDeregisterEvents(definition.id, definition.uiFragments),
|
|
176
|
-
),
|
|
177
|
-
promoteEvents(state, v),
|
|
178
|
-
),
|
|
179
|
-
)
|
|
159
|
+
Ok(Array.concat([VersionDisconnected(definition)], promoteEvents(state, v)))
|
|
180
160
|
| _ => Ok([]) // not connected / unknown → tolerate stray disconnect
|
|
181
161
|
}
|
|
182
162
|
| Activate(v) =>
|
|
183
163
|
switch state.known->Dict.get(v) {
|
|
184
164
|
| Some({status: Inactive | Retired, definition}) =>
|
|
185
|
-
let base =
|
|
186
|
-
[VersionActivated(definition)],
|
|
187
|
-
uiRegisterEvents(definition.id, definition.uiFragments),
|
|
188
|
-
)
|
|
165
|
+
let base = [VersionActivated(definition)]
|
|
189
166
|
let supersede = if currentAfterConnect(state.known, v) == v {
|
|
190
167
|
switch state.current {
|
|
191
168
|
| Some(c) if c != v =>
|
|
@@ -213,15 +190,7 @@ let decide = (state, command) =>
|
|
|
213
190
|
| Deactivate(v) =>
|
|
214
191
|
switch state.known->Dict.get(v) {
|
|
215
192
|
| Some({status: Connected | Disconnected, definition}) =>
|
|
216
|
-
Ok(
|
|
217
|
-
Array.concat(
|
|
218
|
-
Array.concat(
|
|
219
|
-
[VersionDeactivated(definition)],
|
|
220
|
-
uiDeregisterEvents(definition.id, definition.uiFragments),
|
|
221
|
-
),
|
|
222
|
-
promoteEvents(state, v),
|
|
223
|
-
),
|
|
224
|
-
)
|
|
193
|
+
Ok(Array.concat([VersionDeactivated(definition)], promoteEvents(state, v)))
|
|
225
194
|
| Some({status: Inactive | Retired}) => Ok([]) // idempotent / archived no-op
|
|
226
195
|
| None => Error(UnknownVersion)
|
|
227
196
|
}
|
|
@@ -229,15 +198,7 @@ let decide = (state, command) =>
|
|
|
229
198
|
switch state.known->Dict.get(v) {
|
|
230
199
|
| Some({status: Retired}) => Ok([]) // idempotent
|
|
231
200
|
| Some({definition}) =>
|
|
232
|
-
Ok(
|
|
233
|
-
Array.concat(
|
|
234
|
-
Array.concat(
|
|
235
|
-
[VersionRetired(definition)],
|
|
236
|
-
uiDeregisterEvents(definition.id, definition.uiFragments),
|
|
237
|
-
),
|
|
238
|
-
promoteEvents(state, v),
|
|
239
|
-
),
|
|
240
|
-
)
|
|
201
|
+
Ok(Array.concat([VersionRetired(definition)], promoteEvents(state, v)))
|
|
241
202
|
| None => Error(UnknownVersion)
|
|
242
203
|
}
|
|
243
204
|
| ReportIncompatibility(def) => Ok([IncompatiblePluginDetected(def)])
|
|
@@ -262,9 +223,6 @@ let evolve = (state: state, event) => {
|
|
|
262
223
|
| VersionDetected(_)
|
|
263
224
|
| VersionSuperseded(_)
|
|
264
225
|
| VersionPromoted(_)
|
|
265
|
-
| IncompatiblePluginDetected(_)
|
|
266
|
-
| UIFragmentRegistered(_)
|
|
267
|
-
| UIFragmentUpdated(_)
|
|
268
|
-
| UIFragmentDeregistered(_) => state
|
|
226
|
+
| IncompatiblePluginDetected(_) => state
|
|
269
227
|
}
|
|
270
228
|
}
|
|
@@ -30,33 +30,6 @@ let initialState = {
|
|
|
30
30
|
known: initialState_known
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
function uiRegisterEvents(pluginId, manifest) {
|
|
34
|
-
if (manifest !== undefined) {
|
|
35
|
-
return [{
|
|
36
|
-
TAG: "UIFragmentRegistered",
|
|
37
|
-
_0: {
|
|
38
|
-
pluginId: pluginId,
|
|
39
|
-
manifest: manifest
|
|
40
|
-
}
|
|
41
|
-
}];
|
|
42
|
-
} else {
|
|
43
|
-
return [];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function uiDeregisterEvents(pluginId, manifest) {
|
|
48
|
-
if (manifest !== undefined) {
|
|
49
|
-
return [{
|
|
50
|
-
TAG: "UIFragmentDeregistered",
|
|
51
|
-
_0: {
|
|
52
|
-
pluginId: pluginId
|
|
53
|
-
}
|
|
54
|
-
}];
|
|
55
|
-
} else {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
33
|
function highestConnected(known) {
|
|
61
34
|
return Stdlib_Array.reduce(Object.entries(known), undefined, (acc, param) => {
|
|
62
35
|
let v = param[0];
|
|
@@ -97,7 +70,7 @@ function connectEvents(state, v, def) {
|
|
|
97
70
|
let base = [{
|
|
98
71
|
TAG: "VersionConnected",
|
|
99
72
|
_0: def
|
|
100
|
-
}]
|
|
73
|
+
}];
|
|
101
74
|
let supersede;
|
|
102
75
|
if (currentAfterConnect(state.known, v) === v) {
|
|
103
76
|
let c = state.current;
|
|
@@ -229,26 +202,27 @@ function decide(state, command) {
|
|
|
229
202
|
case "Disconnect" :
|
|
230
203
|
let v$3 = command._0;
|
|
231
204
|
let match$3 = state.known[v$3];
|
|
232
|
-
if (match$3
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
205
|
+
if (match$3 !== undefined) {
|
|
206
|
+
if (match$3.status === "Connected") {
|
|
207
|
+
return {
|
|
208
|
+
TAG: "Ok",
|
|
209
|
+
_0: [{
|
|
210
|
+
TAG: "VersionDisconnected",
|
|
211
|
+
_0: match$3.definition
|
|
212
|
+
}].concat(promoteEvents(state, v$3))
|
|
213
|
+
};
|
|
214
|
+
} else {
|
|
215
|
+
return {
|
|
216
|
+
TAG: "Ok",
|
|
217
|
+
_0: []
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
239
221
|
return {
|
|
240
222
|
TAG: "Ok",
|
|
241
223
|
_0: []
|
|
242
224
|
};
|
|
243
225
|
}
|
|
244
|
-
let definition = match$3.definition;
|
|
245
|
-
return {
|
|
246
|
-
TAG: "Ok",
|
|
247
|
-
_0: [{
|
|
248
|
-
TAG: "VersionDisconnected",
|
|
249
|
-
_0: definition
|
|
250
|
-
}].concat(uiDeregisterEvents(definition.id, definition.uiFragments)).concat(promoteEvents(state, v$3))
|
|
251
|
-
};
|
|
252
226
|
case "Activate" :
|
|
253
227
|
let v$4 = command._0;
|
|
254
228
|
let match$4 = state.known[v$4];
|
|
@@ -258,7 +232,7 @@ function decide(state, command) {
|
|
|
258
232
|
_0: "UnknownVersion"
|
|
259
233
|
};
|
|
260
234
|
}
|
|
261
|
-
let definition
|
|
235
|
+
let definition = match$4.definition;
|
|
262
236
|
switch (match$4.status) {
|
|
263
237
|
case "Connected" :
|
|
264
238
|
return {
|
|
@@ -276,8 +250,8 @@ function decide(state, command) {
|
|
|
276
250
|
}
|
|
277
251
|
let base = [{
|
|
278
252
|
TAG: "VersionActivated",
|
|
279
|
-
_0: definition
|
|
280
|
-
}]
|
|
253
|
+
_0: definition
|
|
254
|
+
}];
|
|
281
255
|
let supersede;
|
|
282
256
|
if (currentAfterConnect(state.known, v$4) === v$4) {
|
|
283
257
|
let c = state.current;
|
|
@@ -290,7 +264,7 @@ function decide(state, command) {
|
|
|
290
264
|
supersededVersion: c,
|
|
291
265
|
supersededDefinition: match$5.definition,
|
|
292
266
|
newVersion: v$4,
|
|
293
|
-
newDefinition: definition
|
|
267
|
+
newDefinition: definition
|
|
294
268
|
}
|
|
295
269
|
}] : [];
|
|
296
270
|
} else {
|
|
@@ -316,7 +290,6 @@ function decide(state, command) {
|
|
|
316
290
|
_0: "UnknownVersion"
|
|
317
291
|
};
|
|
318
292
|
}
|
|
319
|
-
let definition$2 = match$6.definition;
|
|
320
293
|
switch (match$6.status) {
|
|
321
294
|
case "Connected" :
|
|
322
295
|
case "Disconnected" :
|
|
@@ -332,8 +305,8 @@ function decide(state, command) {
|
|
|
332
305
|
TAG: "Ok",
|
|
333
306
|
_0: [{
|
|
334
307
|
TAG: "VersionDeactivated",
|
|
335
|
-
_0: definition
|
|
336
|
-
}].concat(
|
|
308
|
+
_0: match$6.definition
|
|
309
|
+
}].concat(promoteEvents(state, v$5))
|
|
337
310
|
};
|
|
338
311
|
break;
|
|
339
312
|
case "ReportIncompatibility" :
|
|
@@ -347,27 +320,27 @@ function decide(state, command) {
|
|
|
347
320
|
case "Retire" :
|
|
348
321
|
let v$6 = command._0;
|
|
349
322
|
let match$7 = state.known[v$6];
|
|
350
|
-
if (match$7
|
|
323
|
+
if (match$7 !== undefined) {
|
|
324
|
+
if (match$7.status === "Retired") {
|
|
325
|
+
return {
|
|
326
|
+
TAG: "Ok",
|
|
327
|
+
_0: []
|
|
328
|
+
};
|
|
329
|
+
} else {
|
|
330
|
+
return {
|
|
331
|
+
TAG: "Ok",
|
|
332
|
+
_0: [{
|
|
333
|
+
TAG: "VersionRetired",
|
|
334
|
+
_0: match$7.definition
|
|
335
|
+
}].concat(promoteEvents(state, v$6))
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
351
339
|
return {
|
|
352
340
|
TAG: "Error",
|
|
353
341
|
_0: "UnknownVersion"
|
|
354
342
|
};
|
|
355
343
|
}
|
|
356
|
-
let definition$3 = match$7.definition;
|
|
357
|
-
if (match$7.status === "Retired") {
|
|
358
|
-
return {
|
|
359
|
-
TAG: "Ok",
|
|
360
|
-
_0: []
|
|
361
|
-
};
|
|
362
|
-
} else {
|
|
363
|
-
return {
|
|
364
|
-
TAG: "Ok",
|
|
365
|
-
_0: [{
|
|
366
|
-
TAG: "VersionRetired",
|
|
367
|
-
_0: definition$3
|
|
368
|
-
}].concat(uiDeregisterEvents(definition$3.id, definition$3.uiFragments)).concat(promoteEvents(state, v$6))
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
344
|
}
|
|
372
345
|
}
|
|
373
346
|
|
|
@@ -419,8 +392,6 @@ export {
|
|
|
419
392
|
initialState,
|
|
420
393
|
snapshot,
|
|
421
394
|
atomicCounter,
|
|
422
|
-
uiRegisterEvents,
|
|
423
|
-
uiDeregisterEvents,
|
|
424
395
|
highestConnected,
|
|
425
396
|
highestConnectedExcluding,
|
|
426
397
|
currentAfterConnect,
|
|
@@ -26,19 +26,6 @@ type command =
|
|
|
26
26
|
// automatic `Superseded` transition (which is decided, not commanded).
|
|
27
27
|
| Retire(version)
|
|
28
28
|
|
|
29
|
-
@schema
|
|
30
|
-
type uiFragmentRegisteredData = {pluginId: string, manifest: uiFragmentManifest}
|
|
31
|
-
|
|
32
|
-
@schema
|
|
33
|
-
type uiFragmentUpdatedData = {
|
|
34
|
-
pluginId: string,
|
|
35
|
-
previousManifest: uiFragmentManifest,
|
|
36
|
-
newManifest: uiFragmentManifest,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@schema
|
|
40
|
-
type uiFragmentDeregisteredData = {pluginId: string}
|
|
41
|
-
|
|
42
29
|
// Carries both the superseded and the superseding version's full definition —
|
|
43
30
|
// a deterministic trigger for version-to-version schema/data migrations
|
|
44
31
|
// (analysis §6.2.4).
|
|
@@ -72,11 +59,6 @@ type event =
|
|
|
72
59
|
| VersionRetired(pluginDefinition)
|
|
73
60
|
// Protocol incompatibility recorded at connect; connection still proceeds.
|
|
74
61
|
| IncompatiblePluginDetected(pluginDefinition)
|
|
75
|
-
// UI fragment lifecycle events — emitted alongside connect/disconnect/(de)activate
|
|
76
|
-
// when the plugin's pluginDefinition.uiFragments is set.
|
|
77
|
-
| UIFragmentRegistered(uiFragmentRegisteredData)
|
|
78
|
-
| UIFragmentUpdated(uiFragmentUpdatedData)
|
|
79
|
-
| UIFragmentDeregistered(uiFragmentDeregisteredData)
|
|
80
62
|
|
|
81
63
|
@schema
|
|
82
64
|
type error =
|
|
@@ -39,21 +39,6 @@ let commandSchema = S.union([
|
|
|
39
39
|
}))
|
|
40
40
|
]);
|
|
41
41
|
|
|
42
|
-
let uiFragmentRegisteredDataSchema = S.schema(s => ({
|
|
43
|
-
pluginId: s.m(S.string),
|
|
44
|
-
manifest: s.m(Plugin$Reventless.uiFragmentManifestSchema)
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
let uiFragmentUpdatedDataSchema = S.schema(s => ({
|
|
48
|
-
pluginId: s.m(S.string),
|
|
49
|
-
previousManifest: s.m(Plugin$Reventless.uiFragmentManifestSchema),
|
|
50
|
-
newManifest: s.m(Plugin$Reventless.uiFragmentManifestSchema)
|
|
51
|
-
}));
|
|
52
|
-
|
|
53
|
-
let uiFragmentDeregisteredDataSchema = S.schema(s => ({
|
|
54
|
-
pluginId: s.m(S.string)
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
42
|
let versionSupersededDataSchema = S.schema(s => ({
|
|
58
43
|
supersededVersion: s.m(Plugin$Reventless.versionSchema),
|
|
59
44
|
supersededDefinition: s.m(Plugin$Reventless.pluginDefinitionSchema),
|
|
@@ -97,18 +82,6 @@ let eventSchema = S.union([
|
|
|
97
82
|
S.schema(s => ({
|
|
98
83
|
TAG: "IncompatiblePluginDetected",
|
|
99
84
|
_0: s.m(Plugin$Reventless.pluginDefinitionSchema)
|
|
100
|
-
})),
|
|
101
|
-
S.schema(s => ({
|
|
102
|
-
TAG: "UIFragmentRegistered",
|
|
103
|
-
_0: s.m(uiFragmentRegisteredDataSchema)
|
|
104
|
-
})),
|
|
105
|
-
S.schema(s => ({
|
|
106
|
-
TAG: "UIFragmentUpdated",
|
|
107
|
-
_0: s.m(uiFragmentUpdatedDataSchema)
|
|
108
|
-
})),
|
|
109
|
-
S.schema(s => ({
|
|
110
|
-
TAG: "UIFragmentDeregistered",
|
|
111
|
-
_0: s.m(uiFragmentDeregisteredDataSchema)
|
|
112
85
|
}))
|
|
113
86
|
]);
|
|
114
87
|
|
|
@@ -140,9 +113,6 @@ let moduleUrl = "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginSpec.
|
|
|
140
113
|
export {
|
|
141
114
|
name,
|
|
142
115
|
Id,
|
|
143
|
-
uiFragmentRegisteredDataSchema,
|
|
144
|
-
uiFragmentUpdatedDataSchema,
|
|
145
|
-
uiFragmentDeregisteredDataSchema,
|
|
146
116
|
versionSupersededDataSchema,
|
|
147
117
|
eventSchema,
|
|
148
118
|
errorSchema,
|
|
@@ -55,7 +55,6 @@ let displayState = (
|
|
|
55
55
|
status,
|
|
56
56
|
statusChange,
|
|
57
57
|
apiSchemaFragment: def.apiSchemaFragment,
|
|
58
|
-
uiFragments: def.uiFragments,
|
|
59
58
|
structure: def.structure,
|
|
60
59
|
dcbEventLog: def.dcbEventLog,
|
|
61
60
|
// A freshly projected row always knows its kind (the definition carries it as a
|
|
@@ -78,14 +77,11 @@ module PluginMapping = Reventless.Projection.Mapping.Make(
|
|
|
78
77
|
let project = ({event, id, meta: {time, user: ?user}}) => {
|
|
79
78
|
let statusChange = {at: time, by: user->Option.getOr("")}
|
|
80
79
|
switch event {
|
|
81
|
-
// Handshake trigger, supersession record
|
|
80
|
+
// Handshake trigger, supersession record and incompatibility
|
|
82
81
|
// events do not change which version is current.
|
|
83
82
|
| PluginSpec.VersionDetected(_)
|
|
84
83
|
| VersionSuperseded(_)
|
|
85
|
-
| IncompatiblePluginDetected(_)
|
|
86
|
-
| UIFragmentRegistered(_)
|
|
87
|
-
| UIFragmentUpdated(_)
|
|
88
|
-
| UIFragmentDeregistered(_) =>
|
|
84
|
+
| IncompatiblePluginDetected(_) =>
|
|
89
85
|
Reventless.Projection.Ignore
|
|
90
86
|
|
|
91
87
|
// A version became live. It becomes current iff it is the highest
|
|
@@ -71,7 +71,6 @@ function displayState(def, status, statusChange, otherConnectedVersions) {
|
|
|
71
71
|
let base_extensionNames = def.extensions.map(extension => extension.extensionPointName);
|
|
72
72
|
let base_extensions = def.extensions;
|
|
73
73
|
let base_apiSchemaFragment = def.apiSchemaFragment;
|
|
74
|
-
let base_uiFragments = def.uiFragments;
|
|
75
74
|
let base_structure = def.structure;
|
|
76
75
|
let base_dcbEventLog = def.dcbEventLog;
|
|
77
76
|
let base_kind = def.kind;
|
|
@@ -87,7 +86,6 @@ function displayState(def, status, statusChange, otherConnectedVersions) {
|
|
|
87
86
|
status: status,
|
|
88
87
|
statusChange: statusChange,
|
|
89
88
|
apiSchemaFragment: base_apiSchemaFragment,
|
|
90
|
-
uiFragments: base_uiFragments,
|
|
91
89
|
structure: base_structure,
|
|
92
90
|
dcbEventLog: base_dcbEventLog,
|
|
93
91
|
kind: base_kind,
|