@reventlessdev/reventless-core 3.0.0-alpha.260 → 3.0.0-alpha.261
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 +8 -0
- package/package.json +9 -9
- package/src/Behavior.res +1 -4
- package/src/Message.res +17 -14
- package/src/Projection.res +51 -25
- package/src/RequestContext.res +8 -9
- package/src/ResourceAttribution.res +28 -14
- package/src/adapter/Adapter.res +48 -4
- package/src/adapter/EventLogProvisioning/EventLogProvisioning.res +5 -5
- package/src/adapter/Messaging/Messaging_Log_Backend.res +10 -7
- package/src/adapter/Messaging/Messaging_Log_Backend.res.mjs +2 -4
- package/src/adapter/Monitoring/Monitoring.res +16 -17
- package/src/adapter/QueryInterception/QueryInterception.res +0 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +12 -5
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +11 -7
- package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +1 -7
- package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +1 -7
- package/src/adapter/RuntimeExtension/RuntimeExtension.res +0 -1
- package/src/admin/Platform_Admin.res +17 -6
- package/src/admin/Platform_AdminApi.res +14 -9
- package/src/admin/Platform_Admin_Callback.res +1 -1
- package/src/admin/Platform_BakedManifest.res +34 -34
- package/src/admin/Platform_ComponentDefinitionsApi.res +9 -21
- package/src/admin/Platform_PluginStructuresApi.res +15 -12
- package/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res +1 -1
- package/src/components/Aggregate/Aggregate.res +13 -12
- package/src/components/Aggregate/Aggregate_Builder.res +22 -21
- package/src/components/Aggregate/Aggregate_Callback.res +91 -86
- package/src/components/Api/ApiNoApiHelpers.res +1 -3
- package/src/components/Api/Api_Ids.res +0 -1
- package/src/components/Api/Api_Naming.res +41 -18
- package/src/components/Api/GraphQL_FragmentGenerator.res +38 -51
- package/src/components/Api/GraphQL_SchemaInspector.res +5 -3
- package/src/components/Api/GraphQL_Stitcher.res +9 -10
- package/src/components/Api/MCP_SchemaGenerator.res +8 -12
- package/src/components/Api/OwnerScopeDiagnostics.res +1 -2
- package/src/components/Api/QueryDbListQuery.res +13 -6
- package/src/components/Api/SchemaType.res +28 -23
- package/src/components/Api/SuryToJsonSchema.res +9 -10
- package/src/components/AutomationSlice/AutomationSlice.res +4 -4
- package/src/components/AutomationSlice/AutomationSlice_Builder.res +15 -14
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -3
- package/src/components/Builder_Helpers.res +12 -23
- package/src/components/CommandGenerator/CommandGenerator.res +6 -1
- package/src/components/CommandGenerator/CommandGenerator_Builder.res +29 -21
- package/src/components/CommandGenerator/CommandGenerator_Callback.res +17 -21
- package/src/components/CommandTopic/CommandTopic.res +3 -3
- package/src/components/CommandTopic/CommandTopic_Builder.res +10 -10
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -2
- package/src/components/Counter/Counter_Builder.res +1 -6
- package/src/components/Counter/Counter_Callback.res +3 -3
- package/src/components/Dcb/Dcb_Builder.res +970 -956
- package/src/components/DcbEventLog/DcbEventLog.res +4 -4
- package/src/components/DcbEventLog/DcbEventLog_Builder.res +0 -1
- package/src/components/DcbEventLog/DcbEventLog_Operations.res +17 -18
- package/src/components/EventCollector/EventCollector_Builder.res +2 -1
- package/src/components/EventLog/EventLog.res +5 -1
- package/src/components/EventLog/EventLog_Operations.res +12 -8
- package/src/components/EventMapper/EventMapper.res +8 -10
- package/src/components/EventMapper/EventMapper_Builder.res +4 -1
- package/src/components/EventMapper/EventMapper_Callback.res +46 -31
- package/src/components/EventTopic/EventTopic.res +3 -3
- package/src/components/EventTopic/EventTopic_Builder.res +1 -1
- package/src/components/Extension/Extension.res +4 -1
- package/src/components/Extension/Extension_Operations.res +11 -3
- package/src/components/ExtensionPoint/ExtensionPoint.res +3 -3
- package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +9 -10
- package/src/components/ExtensionPoint/ExtensionPoint_Callback.res +2 -6
- package/src/components/ExtensionPoint/ExtensionPoint_Operations.res +13 -5
- package/src/components/Heartbeat/Heartbeat_Callback.res +3 -3
- package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +4 -4
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +7 -10
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res +4 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +15 -14
- package/src/components/QueryDb/QueryDb_Adapter.res +1 -3
- package/src/components/QueryDb/QueryDb_Operations.res +10 -10
- package/src/components/ReadModel/ReadModel.res +3 -3
- package/src/components/ReadModel/ReadModel_Builder.res +1 -2
- package/src/components/ReadModel/ReadModel_Callback.res +2 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +5 -2
- package/src/components/StateChangeSlice/StateChangeSlice.res +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Builder.res +23 -4
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +22 -6
- package/src/components/StateTopic.res +1 -3
- package/src/components/StateViewSlice/StateViewSlice.res +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +79 -68
- package/src/components/StateViewSlice/StateViewSlice_Callback.res +3 -1
- package/src/components/Task/Task.res +3 -3
- package/src/components/Task/Task_Adapter.res +4 -1
- package/src/components/Task/Task_Builder.res +24 -21
- package/src/plugin/api/PluginBaseFragment.res +9 -3
- package/src/plugin/component/Capability_Inference.res +8 -10
- package/src/plugin/component/Plugin.res +6 -6
- package/src/plugin/component/Plugin_Builder.res +54 -50
- package/src/plugin/component/Plugin_Callback.res +10 -6
- package/src/plugin/component/Plugin_Helpers.res +264 -230
- package/src/plugin/component/Plugin_Structure.res +370 -324
- package/src/plugin/component/Plugin_SubscriptionSchema.res +8 -6
- package/src/plugin/component/SchemaWalker.res +11 -12
- package/src/plugin/connect/PluginConnectExtension_Mapping.res +45 -50
- package/src/plugin/lifecycle/PluginBehavior.res +3 -4
- package/src/plugin/lifecycle/PluginSpec.res +1 -2
- package/src/plugin/lifecycle/PluginsProjection.res +16 -5
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +0 -2
- package/src/util/CommandPublisher.res +9 -2
- package/src/util/CsvStream.res +3 -3
- package/src/util/Interstack.res +7 -15
- package/src/util/Interstack.resi +3 -3
- package/src/util/LogFormat.res +5 -9
- package/src/util/Logger.res +1 -2
- package/src/util/Lru.res +2 -1
- package/src/util/Lru.resi +2 -3
- package/src/util/ScheduleOps.res +24 -27
- package/src/util/StorePrefixCollision.res +6 -9
- package/src/util/Util_Promise.res +4 -1
- package/src/util/Util_Promise.res.mjs +1 -1
- package/tests/IdentityTest.res +166 -113
- package/tests/ResourceAttributionTest.res +28 -25
- package/tests/StorePrefixCollisionTest.res +2 -1
- package/tests/TaskBucketNamingTest.res +3 -2
- package/tests/adapter/EventLogProvisioningTest.res +51 -48
- package/tests/adapter/MonitoringTest.res +81 -38
- package/tests/adapter/QueryInterceptionTest.res +2 -2
- package/tests/adapter/RefusalVocabularyTest.res +31 -23
- package/tests/adapter/RuntimeExtensionHookReachTest.res +9 -8
- package/tests/adapter/RuntimeExtensionTest.res +5 -3
- package/tests/admin/AdminApiSchemaDriftTest.res +22 -16
- package/tests/admin/Platform_Admin_StructureTest.res +10 -11
- package/tests/admin/Platform_BakedManifestTest.res +31 -35
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +18 -15
- package/tests/admin/Platform_PluginStructuresApiTest.res +5 -3
- package/tests/admin/Platform_UIFragmentsApiTest.res +6 -3
- package/tests/aggregate/AggregateCacheTest.res +10 -12
- package/tests/aggregate/AggregateCallbackTest.res +75 -46
- package/tests/aggregate/AggregateCausationTest.res +19 -20
- package/tests/aggregate/AggregateConflictTest.res +41 -19
- package/tests/aggregate/AggregateFixtures.res +15 -5
- package/tests/aggregate/AggregateRejectionTest.res +97 -80
- package/tests/aggregate/AggregateSnapshotTest.res +44 -16
- package/tests/api/Api_IdsTest.res +10 -4
- package/tests/api/BrandedMarkerCompositionTest.res +48 -36
- package/tests/api/GeolocationSemanticTest.res +3 -3
- package/tests/api/GraphQL_FragmentGeneratorTest.res +66 -54
- package/tests/api/OwnerScopeDiagnosticsTest.res +31 -27
- package/tests/api/StorageRefFieldsTest.res +30 -18
- package/tests/api/SuryToJsonSchemaTest.res +1315 -1014
- package/tests/api/TaggedUnionSchemaTest.res +17 -24
- package/tests/commandgenerator/CommandGeneratorCallbackTest.res +235 -179
- package/tests/commandgenerator/CommandGeneratorFixtures.res +8 -13
- package/tests/commandgenerator/OwnerStampingTest.res +91 -76
- package/tests/commandtopic/CommandOutcomeHookTest.res +198 -155
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +5 -4
- package/tests/commandtopic/CommandTopicCallbackTest.res +61 -43
- package/tests/commandtopic/CommandTopicHelpersRejectionTest.res +70 -55
- package/tests/counter/CounterCallbackTest.res +40 -34
- package/tests/counter/CounterFixtures.res +4 -4
- package/tests/dcb/DcbDecodeTest.res +115 -84
- package/tests/dcb/DcbEventLogOperationsTest.res +194 -143
- package/tests/dcb/DcbEventLogSchemaTest.res +13 -13
- package/tests/dcb/DcbFixtures.res +4 -5
- package/tests/dcb/DcbScopeInferenceTest.res +173 -114
- package/tests/dcb/DcbStateChangeSliceTest.res +391 -262
- package/tests/dcb/DcbTagTest.res +22 -11
- package/tests/dcb/DcbValidationTest.res +288 -218
- package/tests/eventlog/EventLogFixtures.res +4 -4
- package/tests/eventlog/EventLogOperationsTest.res +102 -67
- package/tests/eventlog/EventLogRetryTest.res +104 -65
- package/tests/eventmapper/EventMapperCallbackTest.res +118 -83
- package/tests/eventmapper/EventMapperFixtures.res +15 -23
- package/tests/eventmapper/EventMapperTest.res +54 -38
- package/tests/eventtopic/EventTopicFixtures.res +3 -4
- package/tests/eventtopic/EventTopicOperationsTest.res +41 -29
- package/tests/extensionpoint/ExtensionPointCallbackTest.res +58 -45
- package/tests/extensionpoint/ExtensionPointFixtures.res +16 -20
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +70 -49
- package/tests/extensionpoint/PluginDisconnectScheduleTest.res +2 -1
- package/tests/logger/LogFormatTest.res +104 -82
- package/tests/logger/LoggerLazyTest.res +21 -12
- package/tests/message/MessageTest.res +96 -93
- package/tests/message/MetaEnvelopeTest.res +26 -30
- package/tests/plugin/HeartbeatDisconnectGraceTest.res +31 -25
- package/tests/plugin/ManifestVisibilityTest.res +20 -12
- package/tests/plugin/PluginDefinitionScalars.res +1 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +15 -12
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginStructureTest.res +1529 -1045
- package/tests/plugin/Plugin_EventQuerySchemaTest.res +21 -10
- package/tests/plugin/SchemaWalkerTest.res +116 -70
- package/tests/plugin/StateChange/PsReserveStock.res +4 -4
- package/tests/plugin/StateView/PsAnnotatedView.res +4 -4
- package/tests/plugin/StateView/PsCustomersView.res +4 -4
- package/tests/plugin/StateView/PsShipmentsView.res +3 -2
- package/tests/projection/LifecycleTrailTest.res +1 -4
- package/tests/projection/ProjectionOptimizeTest.res +13 -9
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbOperationsTest.res +99 -64
- package/tests/querydb/TaggedUnionStampTest.res +10 -8
- package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res +50 -35
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +4 -10
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CsvStreamTest.res +3 -3
- package/tests/util/LruTest.res +84 -56
|
@@ -24,9 +24,10 @@ open ReventlessInfra.Api
|
|
|
24
24
|
// CommandAccepted | CommandRejected | CommandPending). AppSync requires the
|
|
25
25
|
// subscription return type to be a strict subset of the linked mutation's
|
|
26
26
|
// return type, so the subscription field has to declare CommandResult as well.
|
|
27
|
-
let sourceCFields = (
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
let sourceCFields = (~mutationEntries: array<mutationSchemaEntry>): (
|
|
28
|
+
array<string>,
|
|
29
|
+
array<GraphQL_Stitcher.subscriptionSource>,
|
|
30
|
+
) => {
|
|
30
31
|
let fields: array<string> = []
|
|
31
32
|
let sources: array<GraphQL_Stitcher.subscriptionSource> = []
|
|
32
33
|
let pushField = (fieldName: string) => {
|
|
@@ -77,9 +78,10 @@ let sourceCFields = (
|
|
|
77
78
|
// Returns (subscriptionFields, supportingTypes) — the supporting type is the
|
|
78
79
|
// {DisplayName}EventLogEvent type that carries position, eventType, and payload.
|
|
79
80
|
|
|
80
|
-
let sourceAFieldsAndTypes = (
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
let sourceAFieldsAndTypes = (~eventLogEntries: array<eventLogSchemaEntry>): (
|
|
82
|
+
array<string>,
|
|
83
|
+
array<string>,
|
|
84
|
+
) => {
|
|
83
85
|
let seen: Set.t<string> = Set.make()
|
|
84
86
|
let fields: array<string> = []
|
|
85
87
|
let types: array<string> = []
|
|
@@ -160,22 +160,21 @@ let walkSchema = (typeName: string, schema: S.t<unknown>): typeSchema =>
|
|
|
160
160
|
// It's an optional/nullable scalar at the top level, treat as unknown.
|
|
161
161
|
{typeName, kind: "unknown", fields: [], structuralHash: ""}
|
|
162
162
|
} else {
|
|
163
|
-
let constructors =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
)
|
|
163
|
+
let constructors = anyOf->Array.filterMap(variantSchema =>
|
|
164
|
+
switch variantSchema {
|
|
165
|
+
| Object({properties}) =>
|
|
166
|
+
tagConstOf(properties)->Option.map(name => {
|
|
167
|
+
name,
|
|
168
|
+
fields: extractFields(properties),
|
|
169
|
+
})
|
|
170
|
+
| _ => None
|
|
171
|
+
}
|
|
172
|
+
)
|
|
174
173
|
{
|
|
175
174
|
typeName,
|
|
176
175
|
kind: "variant",
|
|
177
176
|
fields: [],
|
|
178
|
-
constructors
|
|
177
|
+
constructors,
|
|
179
178
|
structuralHash: hashConstructors(constructors),
|
|
180
179
|
}
|
|
181
180
|
}
|
|
@@ -27,63 +27,58 @@ module type Spec = {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
module Make = (Spec: Spec) => {
|
|
30
|
-
module ConnectPluginMapping = ExtensionMapping.Make(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
module Delegate = ReventlessInfra.ExtensionMapping.NoDelegate
|
|
30
|
+
module ConnectPluginMapping = ExtensionMapping.Make({
|
|
31
|
+
module ExtensionPoint = PluginExtensionPointSpec
|
|
32
|
+
module Delegate = ReventlessInfra.ExtensionMapping.NoDelegate
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
// Unused by ExtensionMapping.Make (it reads Delegate.moduleUrl, not the
|
|
35
|
+
// arg's); present only to satisfy the input module type. The actually
|
|
36
|
+
// dynamic-imported specifier is the file-level `moduleUrl` (@@reventless.spec
|
|
37
|
+
// injected, move-safe) referenced from Plugin_Helpers.
|
|
38
|
+
let moduleUrl = PluginExtensionPointSpec.moduleUrl
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
let delegateModuleUrl = Delegate.moduleUrl
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
let mapIncomingEvent: ReventlessInfra.ExtensionMapping.mapIncomingEvent<
|
|
43
|
+
PluginExtensionPointSpec.event,
|
|
44
|
+
Delegate.command,
|
|
45
|
+
PluginExtensionPointSpec.command,
|
|
46
|
+
PluginExtensionPointSpec.directive,
|
|
47
|
+
> = (pluginId, event, _meta, _pluginDef, _queryEngine) => {
|
|
48
|
+
let pluginDefinition = Spec.pluginDefinition
|
|
49
|
+
let id = pluginDefinition.id
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
PluginExtensionPointSpec.ConnectPlugin(pluginDefinition),
|
|
74
|
-
),
|
|
75
|
-
]
|
|
76
|
-
}
|
|
77
|
-
// A peer's PluginConnected / PluginDeactivated used to subscribe or
|
|
78
|
-
// unsubscribe this plugin's own queue to peer EP topics. Admin owns that
|
|
79
|
-
// now (manageSubscriptions), so these drop to no-ops.
|
|
80
|
-
| _ => []
|
|
51
|
+
switch event {
|
|
52
|
+
// Answer the handshake, and — when this plugin ships a UI-fragment manifest — register
|
|
53
|
+
// it with the admin UiFragmentRegistry slice in the same step (the admin EP's
|
|
54
|
+
// UI-fragment mapping routes RegisterUiFragment to the slice). Nested switch (not
|
|
55
|
+
// Array.concat) so the outer branch's expected type disambiguates the bare
|
|
56
|
+
// PublishExtensionPointCommand constructor.
|
|
57
|
+
| PluginExtensionPointSpec.UnknownPluginDetected if pluginId == id =>
|
|
58
|
+
switch Spec.uiFragments {
|
|
59
|
+
| Some(manifest) => [
|
|
60
|
+
PublishExtensionPointCommand(
|
|
61
|
+
id,
|
|
62
|
+
PluginExtensionPointSpec.ConnectPlugin(pluginDefinition),
|
|
63
|
+
),
|
|
64
|
+
PublishExtensionPointCommand(id, PluginExtensionPointSpec.RegisterUiFragment(manifest)),
|
|
65
|
+
]
|
|
66
|
+
| None => [
|
|
67
|
+
PublishExtensionPointCommand(
|
|
68
|
+
id,
|
|
69
|
+
PluginExtensionPointSpec.ConnectPlugin(pluginDefinition),
|
|
70
|
+
),
|
|
71
|
+
]
|
|
81
72
|
}
|
|
73
|
+
// A peer's PluginConnected / PluginDeactivated used to subscribe or
|
|
74
|
+
// unsubscribe this plugin's own queue to peer EP topics. Admin owns that
|
|
75
|
+
// now (manageSubscriptions), so these drop to no-ops.
|
|
76
|
+
| _ => []
|
|
82
77
|
}
|
|
78
|
+
}
|
|
83
79
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
80
|
+
let mapOutgoingEvent = None
|
|
81
|
+
})
|
|
87
82
|
|
|
88
83
|
module ConnectPluginMappings = {
|
|
89
84
|
module Spec = PluginExtensionPointSpec
|
|
@@ -54,9 +54,7 @@ let highestConnected = (known: dict<knownVersion>): option<version> =>
|
|
|
54
54
|
)
|
|
55
55
|
|
|
56
56
|
// Highest Connected version other than `exclude`.
|
|
57
|
-
let highestConnectedExcluding = (known: dict<knownVersion>, exclude: version): option<
|
|
58
|
-
version,
|
|
59
|
-
> =>
|
|
57
|
+
let highestConnectedExcluding = (known: dict<knownVersion>, exclude: version): option<version> =>
|
|
60
58
|
known
|
|
61
59
|
->Dict.toArray
|
|
62
60
|
->Array.reduce(None, (acc, (v, kv)) =>
|
|
@@ -150,7 +148,8 @@ let decide = (state, command) =>
|
|
|
150
148
|
// definition (e.g. a newly added `kind`, updated protocols) re-emit
|
|
151
149
|
// VersionConnected to overwrite the stored def and re-project the row. The version
|
|
152
150
|
// is already current, so connectEvents' supersede stays empty — a bare refresh.
|
|
153
|
-
| Some({status: Connected, definition}) =>
|
|
151
|
+
| Some({status: Connected, definition}) =>
|
|
152
|
+
definition == def ? Ok([]) : Ok([VersionConnected(def)])
|
|
154
153
|
| _ => Ok(connectEvents(state, v, def))
|
|
155
154
|
}
|
|
156
155
|
| Disconnect(v) =>
|
|
@@ -102,7 +102,6 @@ let commandTransition = (command: command): Reventless.Transition.t<lifecycleSta
|
|
|
102
102
|
| Disconnect(_) => Moves([Plugins.Connected], Plugins.Disconnected)
|
|
103
103
|
| Activate(_) => Moves([Plugins.Inactive, Plugins.Retired], Plugins.Connected)
|
|
104
104
|
| Deactivate(_) => Moves([Plugins.Connected, Plugins.Disconnected], Plugins.Inactive)
|
|
105
|
-
| Retire(_) =>
|
|
106
|
-
Moves([Plugins.Connected, Plugins.Disconnected, Plugins.Inactive], Plugins.Retired)
|
|
105
|
+
| Retire(_) => Moves([Plugins.Connected, Plugins.Disconnected, Plugins.Inactive], Plugins.Retired)
|
|
107
106
|
}
|
|
108
107
|
}
|
|
@@ -24,7 +24,9 @@ module Util = {
|
|
|
24
24
|
// Every version this row knows to be currently Connected — the `other` set
|
|
25
25
|
// plus the row's own version when its status is Connected.
|
|
26
26
|
let connectedVersions = (state: PluginsReadModelSpec.state): array<Reventless.Plugin.version> =>
|
|
27
|
-
isConnected(state.status)
|
|
27
|
+
isConnected(state.status)
|
|
28
|
+
? state.otherConnectedVersions->withVersion(state.version)
|
|
29
|
+
: state.otherConnectedVersions
|
|
28
30
|
|
|
29
31
|
// Highest version (compareVersions) in the set, or None for an empty set.
|
|
30
32
|
let highest = (versions: array<Reventless.Plugin.version>): option<Reventless.Plugin.version> =>
|
|
@@ -83,7 +85,7 @@ module PluginMapping = Reventless.Projection.Mapping.Make(
|
|
|
83
85
|
PluginSpec,
|
|
84
86
|
PluginsReadModelSpec,
|
|
85
87
|
{
|
|
86
|
-
let project = ({event, id, meta: {time,
|
|
88
|
+
let project = ({event, id, meta: {time, ?user}}) => {
|
|
87
89
|
let statusChange = {at: time, by: user->Option.getOr("")}
|
|
88
90
|
switch event {
|
|
89
91
|
// Handshake trigger, supersession record and incompatibility
|
|
@@ -133,7 +135,10 @@ module PluginMapping = Reventless.Projection.Mapping.Make(
|
|
|
133
135
|
state =>
|
|
134
136
|
state.version == def.version
|
|
135
137
|
? {...state, status: Disconnected, statusChange}
|
|
136
|
-
: {
|
|
138
|
+
: {
|
|
139
|
+
...state,
|
|
140
|
+
otherConnectedVersions: state.otherConnectedVersions->Util.without(def.version),
|
|
141
|
+
},
|
|
137
142
|
)
|
|
138
143
|
| VersionDeactivated(def) =>
|
|
139
144
|
Reventless.Projection.UpdateWithDefault(
|
|
@@ -142,7 +147,10 @@ module PluginMapping = Reventless.Projection.Mapping.Make(
|
|
|
142
147
|
state =>
|
|
143
148
|
state.version == def.version
|
|
144
149
|
? {...state, status: Inactive, statusChange}
|
|
145
|
-
: {
|
|
150
|
+
: {
|
|
151
|
+
...state,
|
|
152
|
+
otherConnectedVersions: state.otherConnectedVersions->Util.without(def.version),
|
|
153
|
+
},
|
|
146
154
|
)
|
|
147
155
|
| VersionRetired(def) =>
|
|
148
156
|
Reventless.Projection.UpdateWithDefault(
|
|
@@ -151,7 +159,10 @@ module PluginMapping = Reventless.Projection.Mapping.Make(
|
|
|
151
159
|
state =>
|
|
152
160
|
state.version == def.version
|
|
153
161
|
? {...state, status: Retired, statusChange}
|
|
154
|
-
: {
|
|
162
|
+
: {
|
|
163
|
+
...state,
|
|
164
|
+
otherConnectedVersions: state.otherConnectedVersions->Util.without(def.version),
|
|
165
|
+
},
|
|
155
166
|
)
|
|
156
167
|
}
|
|
157
168
|
}
|
|
@@ -26,7 +26,10 @@ module Make = (Spec: Spec, Config: Config) => {
|
|
|
26
26
|
try await promise catch {
|
|
27
27
|
| JsExn(e) =>
|
|
28
28
|
let errMsg = e->JsExn.message->Option.getOr("unknown")
|
|
29
|
-
EffectLogger.logError(
|
|
29
|
+
EffectLogger.logError(
|
|
30
|
+
~comp="CommandPublisher",
|
|
31
|
+
`Couldn't publish commands: ${errMsg}`,
|
|
32
|
+
)->Effect.runSync
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -72,7 +75,11 @@ module Make = (Spec: Spec, Config: Config) => {
|
|
|
72
75
|
let promise = Config.publishCommands(Spec.name, commandsToSend->toJsons)
|
|
73
76
|
running := Some(promise)
|
|
74
77
|
switch await promise {
|
|
75
|
-
| () =>
|
|
78
|
+
| () =>
|
|
79
|
+
EffectLogger.logDebug(
|
|
80
|
+
~comp="CommandPublisher",
|
|
81
|
+
`send: finished chunk ${chunkCountStr}: ${sizeStr}`,
|
|
82
|
+
)->Effect.runSync
|
|
76
83
|
| exception JsExn(e) =>
|
|
77
84
|
let errorMessage = e->JsExn.message->Option.getOr("unknown Error")
|
|
78
85
|
EffectLogger.logError(
|
package/src/util/CsvStream.res
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
let parseRows = (~path: string): Stream.t<CSV.row, string, unit> =>
|
|
18
18
|
Queue.unbounded()
|
|
19
19
|
->Effect.flatMap(queue => {
|
|
20
|
-
let _ =
|
|
20
|
+
let _ =
|
|
21
|
+
CSV.parseFile(~path, ~options={headers: CSV.Options.Bool(true)})
|
|
21
22
|
->CSV.onData(row => Queue.offer(queue, Ok(row))->Effect.runSyncExit->ignore)
|
|
22
23
|
->CSV.onEnd(_ => Queue.shutdown(queue)->Effect.runSyncExit->ignore)
|
|
23
24
|
->CSV.onError(err => {
|
|
@@ -29,8 +30,7 @@ let parseRows = (~path: string): Stream.t<CSV.row, string, unit> =>
|
|
|
29
30
|
})
|
|
30
31
|
->Stream.fromEffect
|
|
31
32
|
->Stream.flatMap(queue =>
|
|
32
|
-
Stream.fromQueue(queue)
|
|
33
|
-
->Stream.mapEffect(item =>
|
|
33
|
+
Stream.fromQueue(queue)->Stream.mapEffect(item =>
|
|
34
34
|
switch item {
|
|
35
35
|
| Ok(row) => Effect.succeed(row)
|
|
36
36
|
| Error(msg) => Effect.fail(msg)
|
package/src/util/Interstack.res
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
let platformStackReference =
|
|
2
2
|
Pulumi.Config.make(Some("platform"))
|
|
3
3
|
->Pulumi.Config.get("stack")
|
|
4
|
-
->Option.map(stack =>
|
|
5
|
-
Pulumi.StackReference.makeWithName(stack ++ "-interstack", {"name": stack})
|
|
6
|
-
)
|
|
4
|
+
->Option.map(stack => Pulumi.StackReference.makeWithName(stack ++ "-interstack", {"name": stack}))
|
|
7
5
|
|
|
8
6
|
// -----------------------------------------------------------------------
|
|
9
7
|
// Typed, validated cross-stack queries using the reventless-interop engine.
|
|
@@ -21,11 +19,9 @@ module DefaultTaskQuery = ReventlessInterop.Query.Task.Make({
|
|
|
21
19
|
let requiredFields = ["name"]
|
|
22
20
|
let optionalFields = ["bucketNames", "sideEffectSources"]
|
|
23
21
|
let fromJson = (json: JSON.t) =>
|
|
24
|
-
try Ok(json->S.parseOrThrow(~to=ReventlessInterop.Task.resolvedOutputsSchema))
|
|
25
|
-
catch {
|
|
22
|
+
try Ok(json->S.parseOrThrow(~to=ReventlessInterop.Task.resolvedOutputsSchema)) catch {
|
|
26
23
|
| exn =>
|
|
27
|
-
let msg =
|
|
28
|
-
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("parse error")
|
|
24
|
+
let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("parse error")
|
|
29
25
|
Error(msg)
|
|
30
26
|
}
|
|
31
27
|
})
|
|
@@ -35,11 +31,9 @@ module DefaultEventMapperQuery = ReventlessInterop.Query.EventMapper.Make({
|
|
|
35
31
|
let requiredFields = ["name", "eventCollector"]
|
|
36
32
|
let optionalFields = ["counter"]
|
|
37
33
|
let fromJson = (json: JSON.t) =>
|
|
38
|
-
try Ok(json->S.parseOrThrow(~to=ReventlessInterop.EventMapper.resolvedOutputsSchema))
|
|
39
|
-
catch {
|
|
34
|
+
try Ok(json->S.parseOrThrow(~to=ReventlessInterop.EventMapper.resolvedOutputsSchema)) catch {
|
|
40
35
|
| exn =>
|
|
41
|
-
let msg =
|
|
42
|
-
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("parse error")
|
|
36
|
+
let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("parse error")
|
|
43
37
|
Error(msg)
|
|
44
38
|
}
|
|
45
39
|
})
|
|
@@ -54,11 +48,9 @@ module DefaultExtensionPointQuery = ReventlessInterop.Query.ExtensionPoint.Make(
|
|
|
54
48
|
let requiredFields = ["name", "commandTopic", "eventTopic"]
|
|
55
49
|
let optionalFields = []
|
|
56
50
|
let fromJson = (json: JSON.t) =>
|
|
57
|
-
try Ok(json->S.parseOrThrow(~to=ReventlessInterop.ExtensionPoint.resolvedOutputsSchema))
|
|
58
|
-
catch {
|
|
51
|
+
try Ok(json->S.parseOrThrow(~to=ReventlessInterop.ExtensionPoint.resolvedOutputsSchema)) catch {
|
|
59
52
|
| exn =>
|
|
60
|
-
let msg =
|
|
61
|
-
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("parse error")
|
|
53
|
+
let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("parse error")
|
|
62
54
|
Error(msg)
|
|
63
55
|
}
|
|
64
56
|
})
|
package/src/util/Interstack.resi
CHANGED
|
@@ -20,6 +20,6 @@ let mergeEventMappers: array<ReventlessInterop.EventMapper.resolvedOutputs> => P
|
|
|
20
20
|
array<ReventlessInterop.EventMapper.resolvedOutputs>,
|
|
21
21
|
>
|
|
22
22
|
|
|
23
|
-
let mergeExtensionPoints: array<
|
|
24
|
-
|
|
25
|
-
>
|
|
23
|
+
let mergeExtensionPoints: array<
|
|
24
|
+
ReventlessInterop.ExtensionPoint.resolvedOutputs,
|
|
25
|
+
> => Pulumi.Output.t<array<ReventlessInterop.ExtensionPoint.resolvedOutputs>>
|
package/src/util/LogFormat.res
CHANGED
|
@@ -59,23 +59,21 @@ let truncate = (s: string): string => {
|
|
|
59
59
|
s
|
|
60
60
|
} else {
|
|
61
61
|
`${s->String.slice(~start=0, ~end=maxValueChars)}…(+${(len - maxValueChars)
|
|
62
|
-
|
|
62
|
+
->Int.toString} chars)`
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
67
67
|
|
|
68
68
|
// "Add" (bold)
|
|
69
|
-
let cmdName = (msg: Message.commandJson): string =>
|
|
70
|
-
msg.commandJson->Message.variantNameOfJson->bold
|
|
69
|
+
let cmdName = (msg: Message.commandJson): string => msg.commandJson->Message.variantNameOfJson->bold
|
|
71
70
|
|
|
72
71
|
// "[Add,Remove]"
|
|
73
72
|
let cmdNames = (msgs: array<Message.commandJson>): string =>
|
|
74
73
|
`[${msgs->Array.map(cmdName)->Array.join(",")}]`
|
|
75
74
|
|
|
76
75
|
// "Add(1)"
|
|
77
|
-
let cmdSummary = (msg: Message.commandJson): string =>
|
|
78
|
-
`${msg->cmdName}(${msg.id})`
|
|
76
|
+
let cmdSummary = (msg: Message.commandJson): string => `${msg->cmdName}(${msg.id})`
|
|
79
77
|
|
|
80
78
|
// "[Add(1),Remove(2)]"
|
|
81
79
|
let cmdSummaries = (msgs: array<Message.commandJson>): string =>
|
|
@@ -150,8 +148,7 @@ let cmdFulls = (msgs: array<Message.commandJson>): string =>
|
|
|
150
148
|
// ─── Events (JSON.t event' envelope) ─────────────────────────────────────────
|
|
151
149
|
|
|
152
150
|
// "Added" (bold)
|
|
153
|
-
let eventName = (j: JSON.t): string =>
|
|
154
|
-
j->Message.eventNameOfEvent'Json->bold
|
|
151
|
+
let eventName = (j: JSON.t): string => j->Message.eventNameOfEvent'Json->bold
|
|
155
152
|
|
|
156
153
|
// "[Added,Removed]"
|
|
157
154
|
let eventNames = (events: array<JSON.t>): string =>
|
|
@@ -260,8 +257,7 @@ let commandJsonsToLogMessages: array<Message.commandJson> => array<string> = cmd
|
|
|
260
257
|
`${idx}/${count}: ${cmdJson->cmdSummary}: ${cmdJson->cmdFull}`
|
|
261
258
|
})
|
|
262
259
|
}
|
|
263
|
-
let event'JsonToLogMessage = (j: JSON.t): string =>
|
|
264
|
-
`${j->eventSummary}: ${j->eventFull}`
|
|
260
|
+
let event'JsonToLogMessage = (j: JSON.t): string => `${j->eventSummary}: ${j->eventFull}`
|
|
265
261
|
|
|
266
262
|
// Legacy concise aliases
|
|
267
263
|
let fmtCmd = cmdSummary
|
package/src/util/Logger.res
CHANGED
|
@@ -196,8 +196,7 @@ let makeLoggerWith = (shouldLog: level => bool): t => {
|
|
|
196
196
|
|
|
197
197
|
// Fixed-level logger — the level is baked at creation. Used by tests that assert
|
|
198
198
|
// a specific minimum regardless of env/platform default.
|
|
199
|
-
let makeLogger = (~minLevel=Info): t =>
|
|
200
|
-
makeLoggerWith(l => levelToInt(l) >= levelToInt(minLevel))
|
|
199
|
+
let makeLogger = (~minLevel=Info): t => makeLoggerWith(l => levelToInt(l) >= levelToInt(minLevel))
|
|
201
200
|
|
|
202
201
|
let silent: t = {
|
|
203
202
|
debug: (~comp as _=?, ~data as _=?, _) => (),
|
package/src/util/Lru.res
CHANGED
|
@@ -36,7 +36,8 @@ let put = (cache: t<'k, 'v>, key: 'k, value: 'v): unit =>
|
|
|
36
36
|
if cache.store->Map.size > cache.capacity {
|
|
37
37
|
// Evict the least-recently-used entry = oldest insertion = first key.
|
|
38
38
|
switch cache.store->Map.keys->Array.fromIterator->Array.get(0) {
|
|
39
|
-
| Some(oldest) =>
|
|
39
|
+
| Some(oldest) =>
|
|
40
|
+
let _ = cache.store->Map.delete(oldest)
|
|
40
41
|
| None => ()
|
|
41
42
|
}
|
|
42
43
|
}
|
package/src/util/Lru.resi
CHANGED
|
@@ -10,7 +10,6 @@ next same-entity command reads only the delta instead of folding full history.
|
|
|
10
10
|
`capacity`, `put` evicts the least-recently-used key. A `capacity <= 0` disables
|
|
11
11
|
the cache entirely (`get` always misses, `put` is a no-op) so a slice can opt out.
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
13
|
type t<'k, 'v>
|
|
15
14
|
|
|
16
15
|
/** Creates an empty cache holding at most `capacity` entries (`<= 0` disables it). */
|
|
@@ -26,7 +25,7 @@ let put: (t<'k, 'v>, 'k, 'v) => unit
|
|
|
26
25
|
let invalidate: (t<'k, 'v>, 'k) => unit
|
|
27
26
|
|
|
28
27
|
/** Drops every entry. */
|
|
29
|
-
let clear:
|
|
28
|
+
let clear: t<'k, 'v> => unit
|
|
30
29
|
|
|
31
30
|
/** Current number of live entries. */
|
|
32
|
-
let size:
|
|
31
|
+
let size: t<'k, 'v> => int
|
package/src/util/ScheduleOps.res
CHANGED
|
@@ -71,23 +71,20 @@ let create = (
|
|
|
71
71
|
let name = schedule.name->resourceNaming.validateName
|
|
72
72
|
let schedule = {...schedule, name}
|
|
73
73
|
let createSchedule = scheduler.createSchedule
|
|
74
|
-
let exit =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`create: created ${schedule->JSON.stringifyAny->Option.getOr("")}`,
|
|
83
|
-
)
|
|
74
|
+
let exit = await Effect.tryPromise(
|
|
75
|
+
~catch=err => Util.Error.messageFromUnknown(err, "schedule create"),
|
|
76
|
+
() => createSchedule(channelResources, schedule),
|
|
77
|
+
)
|
|
78
|
+
->Effect.tap(_ =>
|
|
79
|
+
EffectLogger.logInfo(
|
|
80
|
+
~comp=__MODULE__,
|
|
81
|
+
`create: created ${schedule->JSON.stringifyAny->Option.getOr("")}`,
|
|
84
82
|
)
|
|
85
|
-
|
|
83
|
+
)
|
|
84
|
+
->Effect.runPromiseExit
|
|
86
85
|
if !(exit->Exit.isSuccess) {
|
|
87
|
-
let errMsg =
|
|
88
|
-
~onFailure=cause => cause->Cause.pretty,
|
|
89
|
-
~onSuccess=_ => "unknown",
|
|
90
|
-
)
|
|
86
|
+
let errMsg =
|
|
87
|
+
exit->Exit.match(~onFailure=cause => cause->Cause.pretty, ~onSuccess=_ => "unknown")
|
|
91
88
|
EffectLogger.logError(
|
|
92
89
|
~comp=__MODULE__,
|
|
93
90
|
`create: couldn't create ${schedule
|
|
@@ -106,19 +103,19 @@ let delete = (
|
|
|
106
103
|
async name => {
|
|
107
104
|
let name = name->resourceNaming.validateName
|
|
108
105
|
let deleteSchedule = scheduler.deleteSchedule
|
|
109
|
-
let exit =
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
->Effect.runPromiseExit
|
|
106
|
+
let exit = await Effect.tryPromise(
|
|
107
|
+
~catch=err => Util.Error.messageFromUnknown(err, "schedule delete"),
|
|
108
|
+
() => deleteSchedule(channelResources, name),
|
|
109
|
+
)
|
|
110
|
+
->Effect.tap(_ => EffectLogger.logInfo(~comp=__MODULE__, `delete: deleted ${name}`))
|
|
111
|
+
->Effect.runPromiseExit
|
|
116
112
|
if !(exit->Exit.isSuccess) {
|
|
117
|
-
let errMsg =
|
|
118
|
-
~onFailure=cause => cause->Cause.pretty,
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
let errMsg =
|
|
114
|
+
exit->Exit.match(~onFailure=cause => cause->Cause.pretty, ~onSuccess=_ => "unknown")
|
|
115
|
+
EffectLogger.logError(
|
|
116
|
+
~comp=__MODULE__,
|
|
117
|
+
`delete: couldn't delete ${name}: ${errMsg}`,
|
|
118
|
+
)->Effect.runSync
|
|
122
119
|
throw(ScheduleNotDeleted(name))
|
|
123
120
|
}
|
|
124
121
|
}
|
|
@@ -73,24 +73,21 @@ let collisionMessage = (c: collision): string => {
|
|
|
73
73
|
| None => ""
|
|
74
74
|
}
|
|
75
75
|
let sites = site(c.first) ++ site(c.second)
|
|
76
|
-
let where =
|
|
77
|
-
|
|
78
|
-
`declaring component and field as a comment.\n`
|
|
79
|
-
|
|
76
|
+
let where =
|
|
77
|
+
sites == ""
|
|
78
|
+
? ` Both keys appear in the platform's generated capability file, which records each ` ++ `declaring component and field as a comment.\n`
|
|
79
|
+
: sites
|
|
80
80
|
if c.nested {
|
|
81
81
|
`Object store "${c.first.qualified}" is rooted at "${c.first.prefix}/", which encloses ` ++
|
|
82
82
|
`"${c.second.qualified}" at "${c.second.prefix}/".\n` ++
|
|
83
83
|
where ++
|
|
84
|
-
` One store's objects would sit inside the other's — for serving, for upload grants and ` ++
|
|
85
|
-
`for a store wipe alike. Rename one of them.`
|
|
84
|
+
` One store's objects would sit inside the other's — for serving, for upload grants and ` ++ `for a store wipe alike. Rename one of them.`
|
|
86
85
|
} else {
|
|
87
86
|
`Object stores "${c.first.qualified}" and "${c.second.qualified}" both root their objects ` ++
|
|
88
87
|
`at "${c.first.prefix}/".\n` ++
|
|
89
88
|
where ++
|
|
90
89
|
` A platform serves one cache behavior per prefix and scopes upload grants by prefix, so ` ++
|
|
91
90
|
`two stores cannot share one.\n` ++
|
|
92
|
-
` Rename one store, or — if they were meant to be one shared store — qualify the ` ++
|
|
93
|
-
`\`@storageRef\` annotation with the owning plugin.`
|
|
91
|
+
` Rename one store, or — if they were meant to be one shared store — qualify the ` ++ `\`@storageRef\` annotation with the owning plugin.`
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
|
-
|
|
@@ -52,7 +52,10 @@ let onEndHandler = async (flush, resolve) => {
|
|
|
52
52
|
let _ = switch await flush() {
|
|
53
53
|
| _res => resolve()
|
|
54
54
|
| exception JsExn(e) =>
|
|
55
|
-
EffectLogger.logError(
|
|
55
|
+
EffectLogger.logError(
|
|
56
|
+
~comp=__MODULE__,
|
|
57
|
+
`${__LOC__}: ${e->JsExn.message->Option.getOr("unknown")}`,
|
|
58
|
+
)->Effect.runSync
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -70,7 +70,7 @@ async function onEndHandler(flush, resolve) {
|
|
|
70
70
|
} catch (raw_e) {
|
|
71
71
|
let e = Primitive_exceptions.internalToException(raw_e);
|
|
72
72
|
if (e.RE_EXN_ID === "JsExn") {
|
|
73
|
-
Effect.runSync(EffectLogger$ReventlessCore.logError("Util_Promise-ReventlessCore", undefined, "File \"Util_Promise.res\", line
|
|
73
|
+
Effect.runSync(EffectLogger$ReventlessCore.logError("Util_Promise-ReventlessCore", undefined, "File \"Util_Promise.res\", line 57, characters 9-16" + `: ` + Stdlib_Option.getOr(Stdlib_JsExn.message(e._1), "unknown")));
|
|
74
74
|
} else {
|
|
75
75
|
throw e;
|
|
76
76
|
}
|