@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
|
@@ -117,7 +117,7 @@ let checkRetiredValue = (~entityName: string, stateSchema: S.t<unknown>): retire
|
|
|
117
117
|
->Option.map(f => ` (that is "${f}")`)
|
|
118
118
|
->Option.getOr(
|
|
119
119
|
" (it declares none)",
|
|
120
|
-
)}. A retirement state no command's
|
|
120
|
+
)}. A retirement state no command's declared edge can name loses the command filtering the state form exists for.`,
|
|
121
121
|
)
|
|
122
122
|
}
|
|
123
123
|
let declared = switch stateSchema {
|
|
@@ -179,8 +179,9 @@ let reportRetiredStates = (
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
// The states a record's lifecycle field can hold — the field
|
|
183
|
-
// written in terms of. `None`: no lifecycle; `Some([])`: one
|
|
182
|
+
// The states a record's lifecycle field can hold — the field a command's
|
|
183
|
+
// declared edge is written in terms of. `None`: no lifecycle; `Some([])`: one
|
|
184
|
+
// with no cases.
|
|
184
185
|
let lifecycleStatesFromStateSchema = (
|
|
185
186
|
~entityName: string,
|
|
186
187
|
stateSchema: S.t<unknown>,
|
|
@@ -373,12 +374,17 @@ let reportTranslationTables = (
|
|
|
373
374
|
}
|
|
374
375
|
}
|
|
375
376
|
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
//
|
|
377
|
+
// A command's declared edge names states belonging to another component's enum,
|
|
378
|
+
// and nothing forces a spec to pick the one its linked view declares. Both sides
|
|
379
|
+
// are in hand here. A state the linked views do not declare raises (this runs at assembly,
|
|
380
|
+
// never in a Lambda, so that is a failed deploy); no resolvable view only warns.
|
|
381
|
+
// Checked against the UNION of the linked views: a slice feeding two is not
|
|
382
|
+
// claiming which one.
|
|
383
|
+
//
|
|
384
|
+
// The compiler has already resolved the switch's constructors, so what survives
|
|
385
|
+
// to here is a component naming the wrong lifecycle enum rather than misspelling
|
|
386
|
+
// a state — the half of the check `lifecycleState` cannot make, since nothing
|
|
387
|
+
// forces a spec to pick its linked view's enum.
|
|
382
388
|
let checkDeclaredTransitions = (
|
|
383
389
|
~pluginName: string,
|
|
384
390
|
~writables: array<Reventless.Plugin.writableDef>,
|
|
@@ -412,7 +418,7 @@ let checkDeclaredTransitions = (
|
|
|
412
418
|
->Array.forEach(state =>
|
|
413
419
|
failures
|
|
414
420
|
->Array.push(
|
|
415
|
-
`${w.name}.${cmd.name}
|
|
421
|
+
`${w.name}.${cmd.name} declares state "${state}", which none of its ` ++
|
|
416
422
|
`linked views declare — ${w.linkedViews->Array.join(
|
|
417
423
|
", ",
|
|
418
424
|
)} know ${known->Array.join(", ")}.`,
|
|
@@ -430,14 +436,14 @@ let checkDeclaredTransitions = (
|
|
|
430
436
|
if unvalidated.contents > 0 {
|
|
431
437
|
log.warn(
|
|
432
438
|
~comp="Plugin_Structure",
|
|
433
|
-
`${pluginName}: ${unvalidated.contents->Int.toString} command(s) declare a
|
|
439
|
+
`${pluginName}: ${unvalidated.contents->Int.toString} command(s) declare a transition ` ++
|
|
434
440
|
`but no linked view declares a lifecycle to check it against.`,
|
|
435
441
|
)
|
|
436
442
|
}
|
|
437
443
|
|
|
438
444
|
if Array.length(failures) > 0 {
|
|
439
445
|
JsError.throwWithMessage(
|
|
440
|
-
`${pluginName}:
|
|
446
|
+
`${pluginName}: a declared transition names states that do not exist.\n` ++
|
|
441
447
|
failures->Array.join("\n"),
|
|
442
448
|
)
|
|
443
449
|
}
|
|
@@ -707,6 +713,17 @@ let toCommandDef = (
|
|
|
707
713
|
// one aggregate carries commands with very different audiences, and a
|
|
708
714
|
// component-level shortcut would gate `AddProduct` and `PlaceOrder` alike.
|
|
709
715
|
~commandAuthorization: unknown => Reventless.Authorization.permission,
|
|
716
|
+
// The spec's `command => Transition.t<_>`, evaluated per variant the same way
|
|
717
|
+
// `commandAuthorization` is, and the only declaration of an edge there is —
|
|
718
|
+
// the PPX injects `Unrestricted` for a spec that writes no switch.
|
|
719
|
+
//
|
|
720
|
+
// Read at `t<string>` because this is the erasure boundary: the spec declares
|
|
721
|
+
// its edges over the linked view's own lifecycle enum, whose arms are
|
|
722
|
+
// payload-less and therefore ARE their own names at run time. The one cast
|
|
723
|
+
// that says so is the same `->Obj.magic` every spec member arrives through
|
|
724
|
+
// (see the call sites below), so `Transition` itself asserts nothing about
|
|
725
|
+
// representation and stays parameterised all the way down.
|
|
726
|
+
~commandTransition: unknown => Reventless.Transition.t<string>,
|
|
710
727
|
v: S.t<unknown>,
|
|
711
728
|
): option<Reventless.Plugin.commandDef> => {
|
|
712
729
|
// Build a commandDef for one variant. `properties` is the variant's field dict —
|
|
@@ -715,12 +732,22 @@ let toCommandDef = (
|
|
|
715
732
|
let mkDef = (~variantName, ~properties) => {
|
|
716
733
|
let (level, aggregateIdField) = commandLevelAndId(~isAggregate, ~variantName, properties)
|
|
717
734
|
let references = extractReferences(properties)
|
|
718
|
-
//
|
|
719
|
-
|
|
720
|
-
//
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
735
|
+
// Evaluated against a synthetic value per constructor, the same shape the
|
|
736
|
+
// resolver builds at call time: a payload-bearing variant compiles to
|
|
737
|
+
// `{TAG, ...}`, a payload-less one to a bare string.
|
|
738
|
+
let syntheticCommand: unknown =
|
|
739
|
+
Reventless.DcbTag.isVariantPayloadBearing(parentSchema, variantName)
|
|
740
|
+
? {"TAG": variantName}->Obj.magic
|
|
741
|
+
: variantName->Obj.magic
|
|
742
|
+
// The spec's own switch, which is exhaustive — so it also speaks for a
|
|
743
|
+
// constructor the host did not declare but spliced from a trait.
|
|
744
|
+
//
|
|
745
|
+
// An edge is ONE declaration, so the two fields are read off it together.
|
|
746
|
+
// `targetState: None` ⇒ AutoUI's board resolver falls back to its name-stem
|
|
747
|
+
// heuristic.
|
|
748
|
+
let declared = commandTransition(syntheticCommand)
|
|
749
|
+
let allowedStates = Reventless.Transition.allowedStates(declared)
|
|
750
|
+
let targetState = Reventless.Transition.targetState(declared)
|
|
724
751
|
// API-exposed iff the whole command isn't @noApi and this variant
|
|
725
752
|
// isn't in its @noApi-variants set — mirrors the API-generation filter
|
|
726
753
|
// (Plugin_Helpers / PluginBaseFragment). Drives the event-graph API badge.
|
|
@@ -730,13 +757,6 @@ let toCommandDef = (
|
|
|
730
757
|
| Some(excluded) => !(excluded->Set.has(variantName))
|
|
731
758
|
| None => true
|
|
732
759
|
}
|
|
733
|
-
// Evaluated against a synthetic value per constructor, the same shape the
|
|
734
|
-
// resolver builds at call time: a payload-bearing variant compiles to
|
|
735
|
-
// `{TAG, ...}`, a payload-less one to a bare string.
|
|
736
|
-
let syntheticCommand: unknown =
|
|
737
|
-
Reventless.DcbTag.isVariantPayloadBearing(parentSchema, variantName)
|
|
738
|
-
? {"TAG": variantName}->Obj.magic
|
|
739
|
-
: variantName->Obj.magic
|
|
740
760
|
let requiredAccess = accessKeysFor(commandAuthorization(syntheticCommand))
|
|
741
761
|
// See the note on the record's `mutationField` for why a non-exposed
|
|
742
762
|
// variant gets the empty sentinel. It has no callable field, and the
|
|
@@ -796,6 +816,7 @@ let extractCommandDefs = (
|
|
|
796
816
|
~isAggregate,
|
|
797
817
|
~mutationFieldFor: string => string,
|
|
798
818
|
~commandAuthorization: unknown => Reventless.Authorization.permission,
|
|
819
|
+
~commandTransition: unknown => Reventless.Transition.t<string>,
|
|
799
820
|
commandSchema: S.t<unknown>,
|
|
800
821
|
): array<Reventless.Plugin.commandDef> =>
|
|
801
822
|
switch commandSchema {
|
|
@@ -806,6 +827,7 @@ let extractCommandDefs = (
|
|
|
806
827
|
~mutationFieldFor,
|
|
807
828
|
~parentSchema=commandSchema,
|
|
808
829
|
~commandAuthorization,
|
|
830
|
+
~commandTransition,
|
|
809
831
|
v,
|
|
810
832
|
)
|
|
811
833
|
)
|
|
@@ -816,6 +838,7 @@ let extractCommandDefs = (
|
|
|
816
838
|
~mutationFieldFor,
|
|
817
839
|
~parentSchema=commandSchema,
|
|
818
840
|
~commandAuthorization,
|
|
841
|
+
~commandTransition,
|
|
819
842
|
commandSchema,
|
|
820
843
|
)->Option.mapOr([], def => [def])
|
|
821
844
|
}
|
|
@@ -1061,6 +1084,49 @@ let make = (
|
|
|
1061
1084
|
}
|
|
1062
1085
|
}
|
|
1063
1086
|
|
|
1087
|
+
// ── One command name, one handler ──────────────────────────────────────────
|
|
1088
|
+
//
|
|
1089
|
+
// A DCB plugin routes a command by its bare type name: the runtime builds
|
|
1090
|
+
// `handlersByType[typeName]` across every StateChangeSlice in the plugin and
|
|
1091
|
+
// dispatches on the incoming command's TAG alone. Two slices declaring one name
|
|
1092
|
+
// therefore have one handler between them — the second registration overwrites
|
|
1093
|
+
// the first, and the plugin deploys.
|
|
1094
|
+
//
|
|
1095
|
+
// Refused here rather than logged there. The runtime notices only when it goes
|
|
1096
|
+
// to stamp owner fields, by which point the deploy has succeeded and the losing
|
|
1097
|
+
// slice is silently unreachable; a name is a compile-time fact and this is the
|
|
1098
|
+
// last place that can see all of them at once.
|
|
1099
|
+
//
|
|
1100
|
+
// Aggregates are exempt and are not checked: their commands are addressed per
|
|
1101
|
+
// component channel, so two aggregates sharing a command name is ordinary.
|
|
1102
|
+
let dcbCommandOwners: dict<array<string>> = Dict.make()
|
|
1103
|
+
stateChangeSlices->Array.forEach((module(SCS: ReventlessInfra.StateChangeSlice.T)) =>
|
|
1104
|
+
Reventless.DcbTag.extractAllVariantNames(
|
|
1105
|
+
SCS.Spec.commandSchema->S.castToUnknown,
|
|
1106
|
+
)->Array.forEach(cmd => {
|
|
1107
|
+
let owners = dcbCommandOwners->Dict.get(cmd)->Option.getOr([])
|
|
1108
|
+
dcbCommandOwners->Dict.set(cmd, Array.concat(owners, [SCS.Spec.name]))
|
|
1109
|
+
})
|
|
1110
|
+
)
|
|
1111
|
+
let clashes =
|
|
1112
|
+
dcbCommandOwners
|
|
1113
|
+
->Dict.toArray
|
|
1114
|
+
->Array.filter(((_, owners)) => owners->Array.length > 1)
|
|
1115
|
+
->Array.toSorted((((a, _)), ((b, _))) => String.compare(a, b))
|
|
1116
|
+
if clashes->Array.length > 0 {
|
|
1117
|
+
JsError.throwWithMessage(
|
|
1118
|
+
`${name}: ` ++
|
|
1119
|
+
clashes
|
|
1120
|
+
->Array.map((((cmd, owners))) =>
|
|
1121
|
+
`${owners->Array.join(" and ")} both declare the command "${cmd}"`
|
|
1122
|
+
)
|
|
1123
|
+
->Array.join("; ") ++
|
|
1124
|
+
`.\n A DCB plugin routes a command by its bare name, so one of these would never run. ` ++
|
|
1125
|
+
`Qualify them — the shipped traits' emitters prefix every name with the host they are ` ++
|
|
1126
|
+
`grafted onto, for exactly this reason.`,
|
|
1127
|
+
)
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1064
1130
|
// One list feeds both the store collection and the lint below, so a field is
|
|
1065
1131
|
// read exactly once by either.
|
|
1066
1132
|
let storeDeclarationSites: array<(string, S.t<unknown>)> =
|
|
@@ -1118,6 +1184,69 @@ let make = (
|
|
|
1118
1184
|
)
|
|
1119
1185
|
}
|
|
1120
1186
|
|
|
1187
|
+
// Capabilities a slice declares its `translate` reaches for. Sorted and
|
|
1188
|
+
// deduplicated for the same reason the store declarations are: the manifest is
|
|
1189
|
+
// committed, so it must not churn on a re-build. Only outbound translation
|
|
1190
|
+
// slices are handed `Capabilities.t`, so only they can declare.
|
|
1191
|
+
let requiredCapabilities =
|
|
1192
|
+
outboundTranslationSlices
|
|
1193
|
+
->Array.flatMap((module(OTS: ReventlessInfra.OutboundTranslationSlice.T)) =>
|
|
1194
|
+
OTS.Spec.capabilityNeeds->Array.map(need => (
|
|
1195
|
+
{
|
|
1196
|
+
Reventless.Plugin.capability: Reventless.CapabilityNeed.toString(need),
|
|
1197
|
+
component: OTS.Spec.name,
|
|
1198
|
+
}: Reventless.Plugin.requiredCapabilityDeclaration
|
|
1199
|
+
))
|
|
1200
|
+
)
|
|
1201
|
+
->Array.toSorted((a, b) =>
|
|
1202
|
+
a.capability == b.capability
|
|
1203
|
+
? String.compare(a.component, b.component)
|
|
1204
|
+
: String.compare(a.capability, b.capability)
|
|
1205
|
+
)
|
|
1206
|
+
->Array.reduce([], (acc, d) =>
|
|
1207
|
+
switch acc->Array.last {
|
|
1208
|
+
| Some(prev) if prev == d => acc
|
|
1209
|
+
| _ => acc->Array.concat([d])
|
|
1210
|
+
}
|
|
1211
|
+
)
|
|
1212
|
+
|
|
1213
|
+
// The traits grafted into this plugin, one entry per declaring component. The
|
|
1214
|
+
// component name is added here rather than declared: a trait cannot know which
|
|
1215
|
+
// component a host grafted it onto, and a host writing it down would be the one
|
|
1216
|
+
// hand-typed string this whole mechanism exists to avoid. Sorted and
|
|
1217
|
+
// deduplicated for the same reason the two declarations above are.
|
|
1218
|
+
let traitDeclarations = {
|
|
1219
|
+
let entry = (~component, decl: Reventless.Trait.t) => (
|
|
1220
|
+
{
|
|
1221
|
+
Reventless.Plugin.trait: decl.trait,
|
|
1222
|
+
version: decl.version,
|
|
1223
|
+
posture: Reventless.Trait.postureToString(decl.posture),
|
|
1224
|
+
component,
|
|
1225
|
+
}: Reventless.Plugin.traitDeclaration
|
|
1226
|
+
)
|
|
1227
|
+
[
|
|
1228
|
+
aggregates->Array.flatMap((module(A: ReventlessInfra.Aggregate.T with type api = api)) =>
|
|
1229
|
+
A.Spec.traits->Array.map(entry(~component=A.Spec.name, ...))
|
|
1230
|
+
),
|
|
1231
|
+
stateChangeSlices->Array.flatMap((module(SCS: ReventlessInfra.StateChangeSlice.T)) =>
|
|
1232
|
+
SCS.Spec.traits->Array.map(entry(~component=SCS.Spec.name, ...))
|
|
1233
|
+
),
|
|
1234
|
+
outboundTranslationSlices->Array.flatMap((
|
|
1235
|
+
module(OTS: ReventlessInfra.OutboundTranslationSlice.T),
|
|
1236
|
+
) => OTS.Spec.traits->Array.map(entry(~component=OTS.Spec.name, ...))),
|
|
1237
|
+
]
|
|
1238
|
+
->Array.flat
|
|
1239
|
+
->Array.toSorted((a, b) =>
|
|
1240
|
+
a.trait == b.trait ? String.compare(a.component, b.component) : String.compare(a.trait, b.trait)
|
|
1241
|
+
)
|
|
1242
|
+
->Array.reduce([], (acc, d) =>
|
|
1243
|
+
switch acc->Array.last {
|
|
1244
|
+
| Some(prev) if prev == d => acc
|
|
1245
|
+
| _ => acc->Array.concat([d])
|
|
1246
|
+
}
|
|
1247
|
+
)
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1121
1250
|
// Heuristic-only matches — a field *named* like a stored-object ref with no
|
|
1122
1251
|
// `@storageRef` — warn and provision nothing. Declaration outranks inference;
|
|
1123
1252
|
// the warning names the annotation that would settle it.
|
|
@@ -1252,6 +1381,7 @@ let make = (
|
|
|
1252
1381
|
~variant=variantName,
|
|
1253
1382
|
),
|
|
1254
1383
|
~commandAuthorization=SCS.Spec.commandAuthorization->Obj.magic,
|
|
1384
|
+
~commandTransition=SCS.Spec.commandTransition->Obj.magic,
|
|
1255
1385
|
SCS.Spec.commandSchema->S.castToUnknown,
|
|
1256
1386
|
),
|
|
1257
1387
|
producedEventTypes: produced,
|
|
@@ -1276,6 +1406,7 @@ let make = (
|
|
|
1276
1406
|
~isAggregate=true,
|
|
1277
1407
|
~mutationFieldFor=variantName => Api_Naming.aggregateMutationField(~plugin=name, ~aggregate=A.Spec.name, ~command=variantName),
|
|
1278
1408
|
~commandAuthorization=A.Spec.commandAuthorization->Obj.magic,
|
|
1409
|
+
~commandTransition=A.Spec.commandTransition->Obj.magic,
|
|
1279
1410
|
A.Spec.commandSchema->S.castToUnknown,
|
|
1280
1411
|
),
|
|
1281
1412
|
producedEventTypes: produced,
|
|
@@ -1747,5 +1878,7 @@ let make = (
|
|
|
1747
1878
|
extensionPoints: Some(extensionPointDefs),
|
|
1748
1879
|
requiredStores: Some(requiredStores),
|
|
1749
1880
|
requiredStoreDeclarations: Some(requiredStoreDeclarations),
|
|
1881
|
+
traitDeclarations: Some(traitDeclarations),
|
|
1882
|
+
requiredCapabilities: Some(requiredCapabilities),
|
|
1750
1883
|
}
|
|
1751
1884
|
}
|
|
@@ -9,21 +9,22 @@ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
|
9
9
|
import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
|
|
10
10
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
11
11
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
12
|
+
import * as Trait$Reventless from "@reventlessdev/reventless-spec/src/types/Trait.res.mjs";
|
|
12
13
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
13
14
|
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
14
15
|
import * as Reference$Reventless from "@reventlessdev/reventless-spec/src/components/Reference.res.mjs";
|
|
15
16
|
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
16
17
|
import * as Logger$ReventlessCore from "../../util/Logger.res.mjs";
|
|
17
18
|
import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
|
|
19
|
+
import * as Transition$Reventless from "@reventlessdev/reventless-spec/src/types/Transition.res.mjs";
|
|
18
20
|
import * as DisplayName$Reventless from "@reventlessdev/reventless-spec/src/components/DisplayName.res.mjs";
|
|
19
21
|
import * as Api_Naming$ReventlessCore from "../../components/Api/Api_Naming.res.mjs";
|
|
22
|
+
import * as CapabilityNeed$Reventless from "@reventlessdev/reventless-spec/src/semantic/CapabilityNeed.res.mjs";
|
|
20
23
|
import * as SchemaType$ReventlessCore from "../../components/Api/SchemaType.res.mjs";
|
|
21
24
|
import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
|
|
22
25
|
import * as ApiNoApiHelpers$ReventlessCore from "../../components/Api/ApiNoApiHelpers.res.mjs";
|
|
23
26
|
import * as SuryToJsonSchema$ReventlessCore from "../../components/Api/SuryToJsonSchema.res.mjs";
|
|
24
27
|
import * as Capability_Inference$ReventlessCore from "./Capability_Inference.res.mjs";
|
|
25
|
-
import * as ApiTargetStateHelpers$ReventlessCore from "../../components/Api/ApiTargetStateHelpers.res.mjs";
|
|
26
|
-
import * as ApiAllowedStatesHelpers$ReventlessCore from "../../components/Api/ApiAllowedStatesHelpers.res.mjs";
|
|
27
28
|
import * as GraphQL_FragmentGenerator$ReventlessCore from "../../components/Api/GraphQL_FragmentGenerator.res.mjs";
|
|
28
29
|
|
|
29
30
|
let log = Logger$ReventlessCore.fromEnv();
|
|
@@ -119,7 +120,7 @@ function checkRetiredValue(entityName, stateSchema) {
|
|
|
119
120
|
let named = values.join(", ");
|
|
120
121
|
let lifecycle = lifecycleFieldFromStateSchema(entityName, stateSchema);
|
|
121
122
|
if (Primitive_object.notequal(lifecycle, field)) {
|
|
122
|
-
log.warn("Plugin_Structure", undefined, entityName + `: @retired(` + named + `) is on "` + field + `", which is not this record's lifecycle field` + Stdlib_Option.getOr(Stdlib_Option.map(lifecycle, f => ` (that is "` + f + `")`), " (it declares none)") + `. A retirement state no command's
|
|
123
|
+
log.warn("Plugin_Structure", undefined, entityName + `: @retired(` + named + `) is on "` + field + `", which is not this record's lifecycle field` + Stdlib_Option.getOr(Stdlib_Option.map(lifecycle, f => ` (that is "` + f + `")`), " (it declares none)") + `. A retirement state no command's declared edge can name loses the command filtering the state form exists for.`);
|
|
123
124
|
}
|
|
124
125
|
let declared;
|
|
125
126
|
declared = stateSchema.type === "object" ? Stdlib_Option.getOr(Stdlib_Option.map(stateSchema.properties[field], schema => {
|
|
@@ -343,16 +344,16 @@ function checkDeclaredTransitions(pluginName, writables, lifecycleStatesByView)
|
|
|
343
344
|
unvalidated.contents = unvalidated.contents + 1 | 0;
|
|
344
345
|
} else {
|
|
345
346
|
declared.filter(state => !known.includes(state)).forEach(state => {
|
|
346
|
-
failures.push(w.name + `.` + cmd.name +
|
|
347
|
+
failures.push(w.name + `.` + cmd.name + ` declares state "` + state + `", which none of its ` + (`linked views declare — ` + w.linkedViews.join(", ") + ` know ` + known.join(", ") + `.`));
|
|
347
348
|
});
|
|
348
349
|
}
|
|
349
350
|
});
|
|
350
351
|
});
|
|
351
352
|
if (unvalidated.contents > 0) {
|
|
352
|
-
log.warn("Plugin_Structure", undefined, pluginName + `: ` + unvalidated.contents.toString() + ` command(s) declare a
|
|
353
|
+
log.warn("Plugin_Structure", undefined, pluginName + `: ` + unvalidated.contents.toString() + ` command(s) declare a transition but no linked view declares a lifecycle to check it against.`);
|
|
353
354
|
}
|
|
354
355
|
if (failures.length !== 0) {
|
|
355
|
-
return Stdlib_JsError.throwWithMessage(pluginName + `:
|
|
356
|
+
return Stdlib_JsError.throwWithMessage(pluginName + `: a declared transition names states that do not exist.\n` + failures.join("\n"));
|
|
356
357
|
}
|
|
357
358
|
}
|
|
358
359
|
|
|
@@ -591,20 +592,21 @@ function annotateArgTypes(schema, argTypes) {
|
|
|
591
592
|
return schema;
|
|
592
593
|
}
|
|
593
594
|
|
|
594
|
-
function toCommandDef(isAggregate, mutationFieldFor, parentSchema, commandAuthorization, v) {
|
|
595
|
+
function toCommandDef(isAggregate, mutationFieldFor, parentSchema, commandAuthorization, commandTransition, v) {
|
|
595
596
|
let mkDef = (variantName, properties) => {
|
|
596
597
|
let match = commandLevelAndId(isAggregate, variantName, properties);
|
|
597
598
|
let references = extractReferences(properties);
|
|
598
|
-
let
|
|
599
|
-
|
|
599
|
+
let syntheticCommand = DcbTag$Reventless.isVariantPayloadBearing(parentSchema, variantName) ? ({
|
|
600
|
+
TAG: variantName
|
|
601
|
+
}) : variantName;
|
|
602
|
+
let declared = commandTransition(syntheticCommand);
|
|
603
|
+
let allowedStates = Transition$Reventless.allowedStates(declared);
|
|
604
|
+
let targetState = Transition$Reventless.targetState(declared);
|
|
600
605
|
let apiExposed = false;
|
|
601
606
|
if (!ApiNoApiHelpers$ReventlessCore.isNoApi(parentSchema)) {
|
|
602
607
|
let excluded = ApiNoApiHelpers$ReventlessCore.getExcludedVariants(parentSchema);
|
|
603
608
|
apiExposed = excluded !== undefined ? !excluded.has(variantName) : true;
|
|
604
609
|
}
|
|
605
|
-
let syntheticCommand = DcbTag$Reventless.isVariantPayloadBearing(parentSchema, variantName) ? ({
|
|
606
|
-
TAG: variantName
|
|
607
|
-
}) : variantName;
|
|
608
610
|
let requiredAccess = accessKeysFor(commandAuthorization(syntheticCommand));
|
|
609
611
|
let mutationField = apiExposed ? mutationFieldFor(variantName) : "";
|
|
610
612
|
let jsonSchema = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(v);
|
|
@@ -647,11 +649,11 @@ function toCommandDef(isAggregate, mutationFieldFor, parentSchema, commandAuthor
|
|
|
647
649
|
}
|
|
648
650
|
}
|
|
649
651
|
|
|
650
|
-
function extractCommandDefs(isAggregate, mutationFieldFor, commandAuthorization, commandSchema) {
|
|
652
|
+
function extractCommandDefs(isAggregate, mutationFieldFor, commandAuthorization, commandTransition, commandSchema) {
|
|
651
653
|
if (commandSchema.type === "anyOf") {
|
|
652
|
-
return Stdlib_Array.filterMap(commandSchema.anyOf, v => toCommandDef(isAggregate, mutationFieldFor, commandSchema, commandAuthorization, v));
|
|
654
|
+
return Stdlib_Array.filterMap(commandSchema.anyOf, v => toCommandDef(isAggregate, mutationFieldFor, commandSchema, commandAuthorization, commandTransition, v));
|
|
653
655
|
} else {
|
|
654
|
-
return Stdlib_Option.mapOr(toCommandDef(isAggregate, mutationFieldFor, commandSchema, commandAuthorization, commandSchema), [], def => [def]);
|
|
656
|
+
return Stdlib_Option.mapOr(toCommandDef(isAggregate, mutationFieldFor, commandSchema, commandAuthorization, commandTransition, commandSchema), [], def => [def]);
|
|
655
657
|
}
|
|
656
658
|
}
|
|
657
659
|
|
|
@@ -791,6 +793,17 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
791
793
|
return Primitive_string.compare(a.field, b.field);
|
|
792
794
|
}
|
|
793
795
|
};
|
|
796
|
+
let dcbCommandOwners = {};
|
|
797
|
+
stateChangeSlices.forEach(SCS => {
|
|
798
|
+
DcbTag$Reventless.extractAllVariantNames(SCS.Spec.commandSchema).forEach(cmd => {
|
|
799
|
+
let owners = Stdlib_Option.getOr(dcbCommandOwners[cmd], []);
|
|
800
|
+
dcbCommandOwners[cmd] = owners.concat([SCS.Spec.name]);
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
let clashes = Object.entries(dcbCommandOwners).filter(param => param[1].length > 1).toSorted((param, param$1) => Primitive_string.compare(param[0], param$1[0]));
|
|
804
|
+
if (clashes.length !== 0) {
|
|
805
|
+
Stdlib_JsError.throwWithMessage(name + `: ` + clashes.map(param => param[1].join(" and ") + ` both declare the command "` + param[0] + `"`).join("; ") + `.\n A DCB plugin routes a command by its bare name, so one of these would never run. Qualify them — the shipped traits' emitters prefix every name with the host they are grafted onto, for exactly this reason.`);
|
|
806
|
+
}
|
|
794
807
|
let storeDeclarationSites = [
|
|
795
808
|
aggregates.flatMap(A => [
|
|
796
809
|
[
|
|
@@ -874,6 +887,55 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
874
887
|
if (found.length !== 0) {
|
|
875
888
|
Stdlib_JsError.throwWithMessage(name + `: two declared object stores look like one store misspelled.\n` + found.map(Capability_Inference$ReventlessCore.collisionMessage).join("\n"));
|
|
876
889
|
}
|
|
890
|
+
let requiredCapabilities = Stdlib_Array.reduce(outboundTranslationSlices.flatMap(OTS => OTS.Spec.capabilityNeeds.map(need => ({
|
|
891
|
+
capability: CapabilityNeed$Reventless.toString(need),
|
|
892
|
+
component: OTS.Spec.name
|
|
893
|
+
}))).toSorted((a, b) => {
|
|
894
|
+
if (a.capability === b.capability) {
|
|
895
|
+
return Primitive_string.compare(a.component, b.component);
|
|
896
|
+
} else {
|
|
897
|
+
return Primitive_string.compare(a.capability, b.capability);
|
|
898
|
+
}
|
|
899
|
+
}), [], (acc, d) => {
|
|
900
|
+
let prev = Stdlib_Array.last(acc);
|
|
901
|
+
if (prev !== undefined) {
|
|
902
|
+
if (Primitive_object.equal(prev, d)) {
|
|
903
|
+
return acc;
|
|
904
|
+
} else {
|
|
905
|
+
return acc.concat([d]);
|
|
906
|
+
}
|
|
907
|
+
} else {
|
|
908
|
+
return acc.concat([d]);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
let entry = (component, decl) => ({
|
|
912
|
+
trait: decl.trait,
|
|
913
|
+
version: decl.version,
|
|
914
|
+
posture: Trait$Reventless.postureToString(decl.posture),
|
|
915
|
+
component: component
|
|
916
|
+
});
|
|
917
|
+
let traitDeclarations = Stdlib_Array.reduce([
|
|
918
|
+
aggregates.flatMap(A => A.Spec.traits.map(extra => entry(A.Spec.name, extra))),
|
|
919
|
+
stateChangeSlices.flatMap(SCS => SCS.Spec.traits.map(extra => entry(SCS.Spec.name, extra))),
|
|
920
|
+
outboundTranslationSlices.flatMap(OTS => OTS.Spec.traits.map(extra => entry(OTS.Spec.name, extra)))
|
|
921
|
+
].flat().toSorted((a, b) => {
|
|
922
|
+
if (a.trait === b.trait) {
|
|
923
|
+
return Primitive_string.compare(a.component, b.component);
|
|
924
|
+
} else {
|
|
925
|
+
return Primitive_string.compare(a.trait, b.trait);
|
|
926
|
+
}
|
|
927
|
+
}), [], (acc, d) => {
|
|
928
|
+
let prev = Stdlib_Array.last(acc);
|
|
929
|
+
if (prev !== undefined) {
|
|
930
|
+
if (Primitive_object.equal(prev, d)) {
|
|
931
|
+
return acc;
|
|
932
|
+
} else {
|
|
933
|
+
return acc.concat([d]);
|
|
934
|
+
}
|
|
935
|
+
} else {
|
|
936
|
+
return acc.concat([d]);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
877
939
|
storeDeclarationSites.forEach(param => {
|
|
878
940
|
Capability_Inference$ReventlessCore.scanSchema(param[0], param[1]).forEach(w => log.warn("Plugin_Structure", undefined, Capability_Inference$ReventlessCore.message(w)));
|
|
879
941
|
});
|
|
@@ -968,7 +1030,7 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
968
1030
|
let consumed = match$1[1];
|
|
969
1031
|
return {
|
|
970
1032
|
name: SCS.Spec.name,
|
|
971
|
-
commands: extractCommandDefs(false, variantName => Api_Naming$ReventlessCore.sliceMutationFieldFor(name, SCS.Spec.name, SCS.Spec.commandSchema, variantName), SCS.Spec.commandAuthorization, SCS.Spec.commandSchema),
|
|
1033
|
+
commands: extractCommandDefs(false, variantName => Api_Naming$ReventlessCore.sliceMutationFieldFor(name, SCS.Spec.name, SCS.Spec.commandSchema, variantName), SCS.Spec.commandAuthorization, SCS.Spec.commandTransition, SCS.Spec.commandSchema),
|
|
972
1034
|
producedEventTypes: produced,
|
|
973
1035
|
consumedEventTypes: consumed,
|
|
974
1036
|
linkedViews: linkedSvsFor(produced),
|
|
@@ -983,7 +1045,7 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
983
1045
|
let produced = match[1];
|
|
984
1046
|
return {
|
|
985
1047
|
name: A.Spec.name,
|
|
986
|
-
commands: extractCommandDefs(true, variantName => Api_Naming$ReventlessCore.aggregateMutationField(name, A.Spec.name, variantName), A.Spec.commandAuthorization, A.Spec.commandSchema),
|
|
1048
|
+
commands: extractCommandDefs(true, variantName => Api_Naming$ReventlessCore.aggregateMutationField(name, A.Spec.name, variantName), A.Spec.commandAuthorization, A.Spec.commandTransition, A.Spec.commandSchema),
|
|
987
1049
|
producedEventTypes: produced,
|
|
988
1050
|
consumedEventTypes: [],
|
|
989
1051
|
linkedViews: linkedSvsFor(produced).concat(linkedReadModelsFor(A.Spec.name)),
|
|
@@ -1268,7 +1330,9 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
1268
1330
|
extensions: extensionDefs,
|
|
1269
1331
|
extensionPoints: extensionPointDefs,
|
|
1270
1332
|
requiredStores: requiredStores,
|
|
1271
|
-
requiredStoreDeclarations: requiredStoreDeclarations
|
|
1333
|
+
requiredStoreDeclarations: requiredStoreDeclarations,
|
|
1334
|
+
requiredCapabilities: requiredCapabilities,
|
|
1335
|
+
traitDeclarations: traitDeclarations
|
|
1272
1336
|
};
|
|
1273
1337
|
}
|
|
1274
1338
|
|
|
@@ -75,7 +75,9 @@ function Make(Spec) {
|
|
|
75
75
|
errorSchema: ExtensionMapping$ReventlessInfra.NoDelegate.errorSchema,
|
|
76
76
|
commandSchema: ExtensionMapping$ReventlessInfra.NoDelegate.commandSchema,
|
|
77
77
|
moduleUrl: ExtensionMapping$ReventlessInfra.NoDelegate.moduleUrl,
|
|
78
|
-
commandAuthorization: ExtensionMapping$ReventlessInfra.NoDelegate.commandAuthorization
|
|
78
|
+
commandAuthorization: ExtensionMapping$ReventlessInfra.NoDelegate.commandAuthorization,
|
|
79
|
+
commandTransition: ExtensionMapping$ReventlessInfra.NoDelegate.commandTransition,
|
|
80
|
+
traits: ExtensionMapping$ReventlessInfra.NoDelegate.traits
|
|
79
81
|
},
|
|
80
82
|
moduleUrl: PluginExtensionPointSpec$ReventlessInfra.moduleUrl,
|
|
81
83
|
delegateModuleUrl: delegateModuleUrl,
|
|
@@ -405,7 +405,9 @@ function Make(Spec) {
|
|
|
405
405
|
errorSchema: PluginSpec$ReventlessCore.errorSchema,
|
|
406
406
|
commandSchema: PluginSpec$ReventlessCore.commandSchema,
|
|
407
407
|
moduleUrl: PluginSpec$ReventlessCore.moduleUrl,
|
|
408
|
-
commandAuthorization: PluginSpec$ReventlessCore.commandAuthorization
|
|
408
|
+
commandAuthorization: PluginSpec$ReventlessCore.commandAuthorization,
|
|
409
|
+
commandTransition: PluginSpec$ReventlessCore.commandTransition,
|
|
410
|
+
traits: PluginSpec$ReventlessCore.traits
|
|
409
411
|
},
|
|
410
412
|
moduleUrl: PluginExtensionPointSpec$ReventlessInfra.moduleUrl,
|
|
411
413
|
mapIncomingCommand: mapIncomingCommand,
|
|
@@ -72,7 +72,9 @@ let Mapping = ExtensionPointMapping$ReventlessInfra.Make({
|
|
|
72
72
|
errorSchema: UiFragmentRegistry$ReventlessCore.errorSchema,
|
|
73
73
|
commandSchema: UiFragmentRegistry$ReventlessCore.commandSchema,
|
|
74
74
|
moduleUrl: UiFragmentRegistry$ReventlessCore.moduleUrl,
|
|
75
|
-
commandAuthorization: UiFragmentRegistry$ReventlessCore.commandAuthorization
|
|
75
|
+
commandAuthorization: UiFragmentRegistry$ReventlessCore.commandAuthorization,
|
|
76
|
+
commandTransition: UiFragmentRegistry$ReventlessCore.commandTransition,
|
|
77
|
+
traits: UiFragmentRegistry$ReventlessCore.traits
|
|
76
78
|
},
|
|
77
79
|
moduleUrl: moduleUrl,
|
|
78
80
|
mapIncomingCommand: mapIncomingCommand,
|
|
@@ -159,19 +159,19 @@ let decide = (state, command) =>
|
|
|
159
159
|
Ok(Array.concat([VersionDisconnected(definition)], promoteEvents(state, v)))
|
|
160
160
|
| _ => Ok([]) // not connected / unknown → tolerate stray disconnect
|
|
161
161
|
}
|
|
162
|
-
| Activate(
|
|
163
|
-
switch state.known->Dict.get(
|
|
162
|
+
| Activate({version}) =>
|
|
163
|
+
switch state.known->Dict.get(version) {
|
|
164
164
|
| Some({status: Inactive | Retired, definition}) =>
|
|
165
165
|
let base = [VersionActivated(definition)]
|
|
166
|
-
let supersede = if currentAfterConnect(state.known,
|
|
166
|
+
let supersede = if currentAfterConnect(state.known, version) == version {
|
|
167
167
|
switch state.current {
|
|
168
|
-
| Some(c) if c !=
|
|
168
|
+
| Some(c) if c != version =>
|
|
169
169
|
switch state.known->Dict.get(c) {
|
|
170
170
|
| Some({definition: defC}) => [
|
|
171
171
|
VersionSuperseded({
|
|
172
172
|
supersededVersion: c,
|
|
173
173
|
supersededDefinition: defC,
|
|
174
|
-
newVersion:
|
|
174
|
+
newVersion: version,
|
|
175
175
|
newDefinition: definition,
|
|
176
176
|
}),
|
|
177
177
|
]
|
|
@@ -187,18 +187,18 @@ let decide = (state, command) =>
|
|
|
187
187
|
| Some({status: Disconnected}) => Error(IsDisconnected)
|
|
188
188
|
| None => Error(UnknownVersion)
|
|
189
189
|
}
|
|
190
|
-
| Deactivate(
|
|
191
|
-
switch state.known->Dict.get(
|
|
190
|
+
| Deactivate({version}) =>
|
|
191
|
+
switch state.known->Dict.get(version) {
|
|
192
192
|
| Some({status: Connected | Disconnected, definition}) =>
|
|
193
|
-
Ok(Array.concat([VersionDeactivated(definition)], promoteEvents(state,
|
|
193
|
+
Ok(Array.concat([VersionDeactivated(definition)], promoteEvents(state, version)))
|
|
194
194
|
| Some({status: Inactive | Retired}) => Ok([]) // idempotent / archived no-op
|
|
195
195
|
| None => Error(UnknownVersion)
|
|
196
196
|
}
|
|
197
|
-
| Retire(
|
|
198
|
-
switch state.known->Dict.get(
|
|
197
|
+
| Retire({version}) =>
|
|
198
|
+
switch state.known->Dict.get(version) {
|
|
199
199
|
| Some({status: Retired}) => Ok([]) // idempotent
|
|
200
200
|
| Some({definition}) =>
|
|
201
|
-
Ok(Array.concat([VersionRetired(definition)], promoteEvents(state,
|
|
201
|
+
Ok(Array.concat([VersionRetired(definition)], promoteEvents(state, version)))
|
|
202
202
|
| None => Error(UnknownVersion)
|
|
203
203
|
}
|
|
204
204
|
| ReportIncompatibility(def) => Ok([IncompatiblePluginDetected(def)])
|
|
@@ -232,8 +232,8 @@ function decide(state, command) {
|
|
|
232
232
|
};
|
|
233
233
|
}
|
|
234
234
|
case "Activate" :
|
|
235
|
-
let
|
|
236
|
-
let match$4 = state.known[
|
|
235
|
+
let version = command.version;
|
|
236
|
+
let match$4 = state.known[version];
|
|
237
237
|
if (match$4 === undefined) {
|
|
238
238
|
return {
|
|
239
239
|
TAG: "Error",
|
|
@@ -261,17 +261,17 @@ function decide(state, command) {
|
|
|
261
261
|
_0: definition
|
|
262
262
|
}];
|
|
263
263
|
let supersede;
|
|
264
|
-
if (currentAfterConnect(state.known,
|
|
264
|
+
if (currentAfterConnect(state.known, version) === version) {
|
|
265
265
|
let c = state.current;
|
|
266
266
|
if (c !== undefined) {
|
|
267
|
-
if (c !==
|
|
267
|
+
if (c !== version) {
|
|
268
268
|
let match$5 = state.known[c];
|
|
269
269
|
supersede = match$5 !== undefined ? [{
|
|
270
270
|
TAG: "VersionSuperseded",
|
|
271
271
|
_0: {
|
|
272
272
|
supersededVersion: c,
|
|
273
273
|
supersededDefinition: match$5.definition,
|
|
274
|
-
newVersion:
|
|
274
|
+
newVersion: version,
|
|
275
275
|
newDefinition: definition
|
|
276
276
|
}
|
|
277
277
|
}] : [];
|
|
@@ -290,8 +290,8 @@ function decide(state, command) {
|
|
|
290
290
|
};
|
|
291
291
|
break;
|
|
292
292
|
case "Deactivate" :
|
|
293
|
-
let
|
|
294
|
-
let match$6 = state.known[
|
|
293
|
+
let version$1 = command.version;
|
|
294
|
+
let match$6 = state.known[version$1];
|
|
295
295
|
if (match$6 === undefined) {
|
|
296
296
|
return {
|
|
297
297
|
TAG: "Error",
|
|
@@ -314,12 +314,12 @@ function decide(state, command) {
|
|
|
314
314
|
_0: [{
|
|
315
315
|
TAG: "VersionDeactivated",
|
|
316
316
|
_0: match$6.definition
|
|
317
|
-
}].concat(promoteEvents(state,
|
|
317
|
+
}].concat(promoteEvents(state, version$1))
|
|
318
318
|
};
|
|
319
319
|
break;
|
|
320
320
|
case "Retire" :
|
|
321
|
-
let
|
|
322
|
-
let match$7 = state.known[
|
|
321
|
+
let version$2 = command.version;
|
|
322
|
+
let match$7 = state.known[version$2];
|
|
323
323
|
if (match$7 !== undefined) {
|
|
324
324
|
if (match$7.status === "Retired") {
|
|
325
325
|
return {
|
|
@@ -332,7 +332,7 @@ function decide(state, command) {
|
|
|
332
332
|
_0: [{
|
|
333
333
|
TAG: "VersionRetired",
|
|
334
334
|
_0: match$7.definition
|
|
335
|
-
}].concat(promoteEvents(state,
|
|
335
|
+
}].concat(promoteEvents(state, version$2))
|
|
336
336
|
};
|
|
337
337
|
}
|
|
338
338
|
} else {
|