@reventlessdev/reventless-local 3.0.0-alpha.249 → 3.0.0-alpha.250

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.
Files changed (170) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +13 -13
  3. package/src/BakedManifest.res +5 -6
  4. package/src/EmitCapabilities.res +3 -1
  5. package/src/LocalPlatformRegistry.res +3 -1
  6. package/src/LocalPlatformStart.res +7 -6
  7. package/src/LocalSeedTarget.res +3 -1
  8. package/src/Platform.res +291 -215
  9. package/src/ShellConfig.res +10 -17
  10. package/src/UiHints.res +8 -14
  11. package/src/UiSlots.res +10 -17
  12. package/src/adapter/Api/LocalEvents_Server.res +5 -3
  13. package/src/adapter/Api/LocalGraphQL_Adapter.res +4 -4
  14. package/src/adapter/Auth/LocalAuth.res +11 -15
  15. package/src/adapter/Auth/UserStore.res +5 -7
  16. package/src/adapter/Backend.res +1 -2
  17. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +42 -26
  18. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +13 -3
  19. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +15 -17
  20. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +18 -22
  21. package/src/adapter/Counter/LocalCounterHandler.res +1 -1
  22. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +33 -22
  23. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +57 -57
  24. package/src/adapter/DomainGraphQL_Server.res +35 -34
  25. package/src/adapter/DomainMCP_Server.res +45 -41
  26. package/src/adapter/EventCollector/LocalEventCollectorChannel.res +47 -36
  27. package/src/adapter/EventHistory/EventHistoryResolvers_GraphQL.res +15 -12
  28. package/src/adapter/EventLog/EventLogStorage_InMemory.res +9 -4
  29. package/src/adapter/EventLog/EventLogStorage_Sqlite.res +36 -24
  30. package/src/adapter/EventTopic/LocalEventTopicPublisher.res +9 -3
  31. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +9 -14
  32. package/src/adapter/LocalBus.res +12 -12
  33. package/src/adapter/LocalCapabilities.res.mjs +1 -1
  34. package/src/adapter/LocalGeocodeResolvers.res +1 -4
  35. package/src/adapter/LocalSideEffectHandler.res +1 -1
  36. package/src/adapter/LocalStateChangeDescriptor.res +2 -1
  37. package/src/adapter/MCP_ServerInstance.res +51 -39
  38. package/src/adapter/ObjectStore/LocalObjectStore.res +5 -2
  39. package/src/adapter/ObjectStore/ObjectStoreStorage_FileSystem.res +1 -2
  40. package/src/adapter/PlatformGraphQL_Server.res +9 -5
  41. package/src/adapter/ProjectionCheckpoint.res +8 -1
  42. package/src/adapter/ProjectionPending.res +1 -3
  43. package/src/adapter/QueryDb/LocalQueryDbStorage.res +2 -1
  44. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +367 -269
  45. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +5 -3
  46. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +63 -40
  47. package/src/adapter/QueryDb/SortKey_Filter.res +14 -6
  48. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +12 -10
  49. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +8 -2
  50. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +1 -4
  51. package/src/adapter/Scheduler/LocalScheduledPublisher.res +12 -12
  52. package/src/adapter/SqliteDriver.res +16 -4
  53. package/src/adapter/Task/TaskBucket_Sqlite.res +5 -6
  54. package/src/components/Aggregate_Builder.res +6 -1
  55. package/src/components/Counter_Builder.res +1 -5
  56. package/src/components/DcbEventLog_Builder.res +5 -3
  57. package/src/components/ExtensionPoint_Builder.res +13 -15
  58. package/src/components/InboundTranslationSlice_Builder.res +3 -2
  59. package/src/components/OutboundTranslationSlice_Builder.res +3 -2
  60. package/src/components/ReadModel_Builder.res +18 -20
  61. package/src/components/StateViewSlice_Builder.res +3 -2
  62. package/src/components/Task_Builder.res +12 -13
  63. package/src/reset/LocalSeedReset.res +2 -5
  64. package/src/test/Mocks/MockDcbEventLogStorage.res +5 -1
  65. package/src/test/Mocks/MockEventLogStorage.res +8 -3
  66. package/src/test/Mocks/MockQueryDbStorage.res +3 -2
  67. package/src/test/TestRunner.res +1 -1
  68. package/tests/BakedManifestFilesTest.res +7 -10
  69. package/tests/LocalEventTapTest.res +26 -21
  70. package/tests/LocalPlatformStartTest.res +33 -28
  71. package/tests/PluginEventDecodeTest.res +3 -3
  72. package/tests/ShellConfigTest.res +30 -21
  73. package/tests/SplitApiFixtures.res +34 -10
  74. package/tests/SplitApiTest.res +92 -62
  75. package/tests/adapter/BackendParityTest.res +180 -130
  76. package/tests/adapter/CollectNEventsTest.res +6 -4
  77. package/tests/adapter/CommandAuthorizationTest.res +47 -41
  78. package/tests/adapter/CommandTopicChannelTest.res +163 -139
  79. package/tests/adapter/CounterHandlerTest.res +95 -77
  80. package/tests/adapter/DcbEventLogStorageSqliteTest.res +171 -168
  81. package/tests/adapter/DcbEventLogStorageTest.res +264 -207
  82. package/tests/adapter/DomainGraphQL_ServerTest.res +53 -43
  83. package/tests/adapter/EventCollectorChannelTest.res +153 -124
  84. package/tests/adapter/EventHistoryResolverTest.res +46 -18
  85. package/tests/adapter/EventLogSnapshotParityTest.res +57 -45
  86. package/tests/adapter/EventLogStorageSqliteTest.res +9 -10
  87. package/tests/adapter/EventTapTest.res +37 -20
  88. package/tests/adapter/EventTopicPublisherTest.res +74 -50
  89. package/tests/adapter/GraphQLSubscriptionBridgeTest.res +4 -3
  90. package/tests/adapter/GraphQL_SchemaInspectorTest.res +666 -568
  91. package/tests/adapter/GraphQL_SubscriptionResolversTest.res +105 -96
  92. package/tests/adapter/HeartbeatRunnerTest.res +99 -81
  93. package/tests/adapter/InboundTranslationMutationTest.res +4 -1
  94. package/tests/adapter/LocalAuthHttpTest.res +79 -85
  95. package/tests/adapter/LocalAuthLoginTest.res +42 -50
  96. package/tests/adapter/LocalAuthTest.res +8 -16
  97. package/tests/adapter/LocalAuthUserStoreTest.res +2 -7
  98. package/tests/adapter/LocalBusBoundedTest.res +187 -117
  99. package/tests/adapter/LocalBusPubSubTest.res +118 -76
  100. package/tests/adapter/LocalDispatchContextTest.res +1 -2
  101. package/tests/adapter/LocalEvents_ServerTest.res +242 -187
  102. package/tests/adapter/PgProjectionCatchupTest.res +44 -10
  103. package/tests/adapter/ProjectionCheckpointTest.res +261 -206
  104. package/tests/adapter/QueryDbGsiTtlTest.res +123 -83
  105. package/tests/adapter/QueryDbListPushdownParityTest.res +107 -67
  106. package/tests/adapter/QueryDbListResolverTest.res +225 -208
  107. package/tests/adapter/QueryDbResolvedFieldsTest.res +17 -14
  108. package/tests/adapter/QueryDbStorageSqliteTest.res +33 -49
  109. package/tests/adapter/QueryDbStorageTest.res +163 -117
  110. package/tests/adapter/QueryDbUnionRoundTripTest.res +8 -10
  111. package/tests/adapter/QueryEngineTest.res +179 -126
  112. package/tests/adapter/ScheduledPublisherTest.res +171 -135
  113. package/tests/adapter/ServedBucketHttpTest.res +65 -59
  114. package/tests/adapter/SortKey_FilterTest.res +19 -3
  115. package/tests/adapter/SqliteDriverTest.res +13 -10
  116. package/tests/adapter/TaskBucketTest.res +94 -80
  117. package/tests/components/aggregate/AggregateTest.res +31 -18
  118. package/tests/components/automationslice/AutomationSliceCallbackTest.res +259 -222
  119. package/tests/components/automationslice/AutomationSliceFixtures.res +4 -2
  120. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +38 -38
  121. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +12 -14
  122. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +8 -32
  123. package/tests/components/commandgenerator/CommandGeneratorFixtures.res +7 -5
  124. package/tests/components/commandgenerator/CommandGeneratorTest.res +40 -31
  125. package/tests/components/commandtopic/CommandTopicFixtures.res +3 -4
  126. package/tests/components/commandtopic/CommandTopicStreamFixtures.res +7 -5
  127. package/tests/components/commandtopic/CommandTopicTest.res +24 -15
  128. package/tests/components/counter/CounterFixtures.res +6 -8
  129. package/tests/components/dcb/DcbCrossPartitionFixtures.res +8 -2
  130. package/tests/components/dcb/DcbCrossPartitionReadTest.res +20 -13
  131. package/tests/components/dcb/DcbEventLogAppendStreamTest.res +12 -8
  132. package/tests/components/dcb/DcbEventLogStreamTest.res +88 -61
  133. package/tests/components/dcb/DcbFixtures.res +4 -1
  134. package/tests/components/dcb/DcbTest.res +9 -6
  135. package/tests/components/eventcollector/EventCollectorFixtures.res +0 -1
  136. package/tests/components/eventcollector/EventCollectorTest.res +6 -3
  137. package/tests/components/eventlog/EventLogAppendStreamTest.res +88 -68
  138. package/tests/components/eventlog/EventLogConflictTest.res +8 -4
  139. package/tests/components/eventlog/EventLogFixtures.res +3 -3
  140. package/tests/components/eventlog/EventLogProvisioningSeamTest.res +26 -13
  141. package/tests/components/eventlog/EventLogStreamTest.res +119 -56
  142. package/tests/components/eventlog/EventLogTest.res +20 -4
  143. package/tests/components/eventtopic/EventTopicFixtures.res +3 -3
  144. package/tests/components/eventtopic/EventTopicStreamFixtures.res +1 -2
  145. package/tests/components/eventtopic/EventTopicStreamTest.res +7 -1
  146. package/tests/components/extensionpoint/ExtensionPointFixtures.res +14 -9
  147. package/tests/components/extensionpoint/ExtensionPointTest.res +3 -2
  148. package/tests/components/heartbeat/HeartbeatFixtures.res +5 -6
  149. package/tests/components/heartbeat/HeartbeatTest.res +56 -47
  150. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +271 -249
  151. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +3 -2
  152. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +361 -276
  153. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +8 -10
  154. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +37 -43
  155. package/tests/components/querydb/QueryDbFixtures.res +1 -5
  156. package/tests/components/querydb/QueryDbTest.res +2 -4
  157. package/tests/components/readmodel/DcbReadModelE2EFixtures.res +15 -18
  158. package/tests/components/readmodel/MixedSourceReadModelFixtures.res +5 -7
  159. package/tests/components/readmodel/ReadModelFixtures.res +8 -8
  160. package/tests/components/scheduler/SchedulerTest.res +76 -58
  161. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +4 -4
  162. package/tests/components/stateviewslice/StateViewSliceDisplayNameFixtures.res +5 -7
  163. package/tests/components/stateviewslice/StateViewSliceFixtures.res +8 -6
  164. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +17 -11
  165. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +12 -2
  166. package/tests/components/task/TaskFixtures.res +5 -5
  167. package/tests/components/task/TaskTest.res +95 -80
  168. package/tests/plugin/PluginsProjection_GWT.res +3 -1
  169. package/tests/plugin/UiFragments_GWT.res +6 -1
  170. package/tests/reset/LocalSeedResetTest.res +1 -0
package/src/Platform.res CHANGED
@@ -45,7 +45,9 @@ let decodePluginEventEnvelope = (eventJson: JSON.t): option<ReventlessCore.Plugi
45
45
  switch eventJson
46
46
  ->JSON.Decode.object
47
47
  ->Option.flatMap(d => d->Dict.get("event"))
48
- ->Option.map(payload => payload->Reventless.Util_Sury.fromJson(ReventlessCore.PluginSpec.eventSchema)) {
48
+ ->Option.map(payload =>
49
+ payload->Reventless.Util_Sury.fromJson(ReventlessCore.PluginSpec.eventSchema)
50
+ ) {
49
51
  | result => result
50
52
  | exception _ => None
51
53
  }
@@ -54,9 +56,9 @@ let decodePluginEventEnvelope = (eventJson: JSON.t): option<ReventlessCore.Plugi
54
56
  // bus envelope — same {id, meta, event} shape as the aggregate topic above
55
57
  // (DcbEventLog_Operations publishes via Message.composeEventJson'). Top-level,
56
58
  // not inside the functor, so the decode is unit-testable.
57
- let decodeUiFragmentRegistryEventEnvelope = (
58
- eventJson: JSON.t,
59
- ): option<ReventlessCore.UiFragmentRegistry.event> =>
59
+ let decodeUiFragmentRegistryEventEnvelope = (eventJson: JSON.t): option<
60
+ ReventlessCore.UiFragmentRegistry.event,
61
+ > =>
60
62
  switch eventJson
61
63
  ->JSON.Decode.object
62
64
  ->Option.flatMap(d => d->Dict.get("event"))
@@ -128,6 +130,7 @@ module MakeWithConfig = (
128
130
  }
129
131
  let db = SqliteDriver.openDb(~path)
130
132
  BackendState.setSqlite(~db, ~path)
133
+
131
134
  // The object store persists beside the database under this backend (see
132
135
  // LocalObjectStore), so a reset that wipes the events wipes the bytes they
133
136
  // reference too — otherwise the session starts with orphaned uploads and
@@ -304,7 +307,13 @@ module MakeWithConfig = (
304
307
  EventHistoryResolvers.register(~server=resolveTargetGraphQL(), params),
305
308
  // MCP tools and resources — registered during plugin construction.
306
309
  // See the large lambda below; it references Bus for QueryDb lookups.
307
- mcpSchemaRegistrationHook: ({pluginName, mutationEntries, queryEntries, eventLogEntries, subscriptionFields}) => {
310
+ mcpSchemaRegistrationHook: ({
311
+ pluginName,
312
+ mutationEntries,
313
+ queryEntries,
314
+ eventLogEntries,
315
+ subscriptionFields,
316
+ }) => {
308
317
  let mcp = resolveTargetMCP()
309
318
  mcp.registerToolsFromEntries(~pluginName, ~mutationEntries, ~commandHandler=async (
310
319
  toolName,
@@ -421,7 +430,9 @@ module MakeWithConfig = (
421
430
  let filtered = switch after {
422
431
  | Some(afterPos) =>
423
432
  let idx =
424
- events->Array.findIndex(e => getPosition(e)->Option.mapOr(false, p => positionGt(p, afterPos)))
433
+ events->Array.findIndex(e =>
434
+ getPosition(e)->Option.mapOr(false, p => positionGt(p, afterPos))
435
+ )
425
436
  if idx >= 0 {
426
437
  events->Array.slice(~start=idx, ~end=events->Array.length)
427
438
  } else {
@@ -526,7 +537,7 @@ module MakeWithConfig = (
526
537
  )
527
538
 
528
539
  // Register subscription SDL fields and resolvers with the GraphQL server
529
- let makeEntry = topic => ({fieldName: topic, topic}: subscriptionEntry)
540
+ let makeEntry = (topic): subscriptionEntry => {fieldName: topic, topic}
530
541
  let sourceAEntries = eventLogEntries->Array.map(e => makeEntry(sourceATopic(e.displayName)))
531
542
  registerAll(~server, ~sdlFields=subscriptionFields, ~sourceAEntries, ~sourceBEntries=[])
532
543
  }
@@ -618,8 +629,7 @@ module MakeWithConfig = (
618
629
  module Mappings: ReventlessInfra.ExtensionPoint.Mappings with module Spec := Spec = {
619
630
  module type Mapping = ReventlessInfra.ExtensionPointMapping.T
620
631
  with module ExtensionPoint := Spec
621
- let name =
622
- Mapping1.Delegate.name ++ "+" ++ Mapping2.Delegate.name
632
+ let name = Mapping1.Delegate.name ++ "+" ++ Mapping2.Delegate.name
623
633
  // First mapping's URL — matches the user-extension merge convention.
624
634
  let moduleUrl = Mapping1.moduleUrl
625
635
  let mappings: array<module(Mapping)> = [module(CM1), module(CM2)]
@@ -643,11 +653,7 @@ module MakeWithConfig = (
643
653
  module type Mapping = ReventlessInfra.ExtensionPointMapping.T
644
654
  with module ExtensionPoint := Spec
645
655
  let name =
646
- Mapping1.Delegate.name ++
647
- "+" ++
648
- Mapping2.Delegate.name ++
649
- "+" ++
650
- Mapping3.Delegate.name
656
+ Mapping1.Delegate.name ++ "+" ++ Mapping2.Delegate.name ++ "+" ++ Mapping3.Delegate.name
651
657
  // First mapping's URL — matches the user-extension merge convention.
652
658
  let moduleUrl = Mapping1.moduleUrl
653
659
  let mappings: array<module(Mapping)> = [module(CM1), module(CM2), module(CM3)]
@@ -668,14 +674,12 @@ module MakeWithConfig = (
668
674
  ): ReventlessInfra.Extension.Blueprint => {
669
675
  module Spec = Mapping.ExtensionPoint
670
676
  module CompiledMapping = ReventlessInfra.ExtensionMapping.Make(Mapping)
671
- module type Mapping = ReventlessInfra.ExtensionMapping.T
672
- with module ExtensionPoint := Spec
677
+ module type Mapping = ReventlessInfra.ExtensionMapping.T with module ExtensionPoint := Spec
673
678
  let name = Mapping.Delegate.name
674
679
  let moduleUrl = Mapping.moduleUrl
675
680
  let delegateModuleUrl = Mapping.delegateModuleUrl
676
681
  let mappings: array<module(Mapping)> = [module(CompiledMapping)]
677
682
  }
678
-
679
683
  }
680
684
 
681
685
  module Task = {
@@ -690,8 +694,9 @@ module MakeWithConfig = (
690
694
  module Make = (
691
695
  Spec: Reventless.StateChangeSlice.Spec,
692
696
  Behavior: Reventless.StateChangeSlice.Behavior with module Spec := Spec,
693
- ): (ReventlessInfra.StateChangeSlice.T with module Spec = Spec) =>
694
- StateChangeSlice_Builder.Make(Spec, Behavior)
697
+ ): (
698
+ ReventlessInfra.StateChangeSlice.T with module Spec = Spec
699
+ ) => StateChangeSlice_Builder.Make(Spec, Behavior)
695
700
  /** Async variant — in-memory uses the same channel (no FIFO distinction). */
696
701
  module MakeAsync = (
697
702
  Spec: Reventless.StateChangeSlice.Spec,
@@ -706,8 +711,10 @@ module MakeWithConfig = (
706
711
  module Make = (
707
712
  Spec: Reventless.StateViewSlice.Spec,
708
713
  Projection: Reventless.StateViewSlice.Projection with module Spec := Spec,
709
- ): (ReventlessInfra.StateViewSlice.T with module Spec = Spec) =>
710
- StateViewSliceMaker.Make(Spec, Projection)
714
+ ): (ReventlessInfra.StateViewSlice.T with module Spec = Spec) => StateViewSliceMaker.Make(
715
+ Spec,
716
+ Projection,
717
+ )
711
718
  }
712
719
 
713
720
  // Admin UI-fragment registry (docs/plans/done/event-sourced-fragment-registries.md): the
@@ -727,32 +734,38 @@ module MakeWithConfig = (
727
734
  module Make = (
728
735
  Spec: Reventless.StateViewSlice.Spec,
729
736
  Projection: Reventless.StateViewSlice.Projection with module Spec := Spec,
730
- ): (ReventlessInfra.StateViewSlice.T with module Spec = Spec) =>
731
- StateViewSliceMaker.Make(Spec, Projection)
737
+ ): (ReventlessInfra.StateViewSlice.T with module Spec = Spec) => StateViewSliceMaker.Make(
738
+ Spec,
739
+ Projection,
740
+ )
732
741
  }
733
742
 
734
743
  module AutomationSlice = {
735
744
  module Make = (
736
745
  Spec: Reventless.AutomationSlice.Spec,
737
746
  Automation: Reventless.AutomationSlice.Automation with module Spec := Spec,
738
- ): (ReventlessInfra.AutomationSlice.T with module Spec = Spec) =>
739
- AutomationSliceMaker.Make(Spec, Automation)
747
+ ): (ReventlessInfra.AutomationSlice.T with module Spec = Spec) => AutomationSliceMaker.Make(
748
+ Spec,
749
+ Automation,
750
+ )
740
751
  }
741
752
 
742
753
  module OutboundTranslationSlice = {
743
754
  module Make = (
744
755
  Spec: Reventless.OutboundTranslationSlice.Spec,
745
756
  Translation: Reventless.OutboundTranslationSlice.Translation with module Spec := Spec,
746
- ): (ReventlessInfra.OutboundTranslationSlice.T with module Spec = Spec) =>
747
- OutboundTranslationSliceMaker.Make(Spec, Translation)
757
+ ): (
758
+ ReventlessInfra.OutboundTranslationSlice.T with module Spec = Spec
759
+ ) => OutboundTranslationSliceMaker.Make(Spec, Translation)
748
760
  }
749
761
 
750
762
  module InboundTranslationSlice = {
751
763
  module Make = (
752
764
  Spec: Reventless.InboundTranslationSlice.Spec,
753
765
  Translation: Reventless.InboundTranslationSlice.Translation with module Spec := Spec,
754
- ): (ReventlessInfra.InboundTranslationSlice.T with module Spec = Spec) =>
755
- InboundTranslationSliceMaker.Make(Spec, Translation)
766
+ ): (
767
+ ReventlessInfra.InboundTranslationSlice.T with module Spec = Spec
768
+ ) => InboundTranslationSliceMaker.Make(Spec, Translation)
756
769
  }
757
770
 
758
771
  module PluginMaker = Plugin_Builder.Make(
@@ -782,7 +795,8 @@ module MakeWithConfig = (
782
795
  // CommandGenerator auto-flow (same path user-plugin aggregates use). Internal-protocol
783
796
  // variants (Heartbeat, Connect, Disconnect, ReportIncompatibility) carry `@noApi` and
784
797
  // are filtered out before SDL/resolver generation.
785
- module LocalPluginAggregate: ReventlessInfra.Aggregate.T with type api = unit = AggregateMaker.Make(
798
+ module LocalPluginAggregate: ReventlessInfra.Aggregate.T
799
+ with type api = unit = AggregateMaker.Make(
786
800
  ReventlessCore.PluginSpec,
787
801
  ReventlessCore.PluginBehavior,
788
802
  ReventlessInfra.NoEventMappings.Make(ReventlessCore.PluginSpec),
@@ -812,10 +826,7 @@ module MakeWithConfig = (
812
826
  EventCollectorChannel,
813
827
  QE,
814
828
  LocalClonerRunner,
815
- ReventlessCore.PluginRuntime_Builder_Micro.Make(
816
- LocalRuntimeEnvironment,
817
- EventCollectorChannel,
818
- ),
829
+ ReventlessCore.PluginRuntime_Builder_Micro.Make(LocalRuntimeEnvironment, EventCollectorChannel),
819
830
  LocalDcbEventLogStorage.Make(Bus),
820
831
  LocalEventTopicPublisher.Make(Bus),
821
832
  LocalCommandTopicChannel.Make(Bus),
@@ -930,15 +941,16 @@ module MakeWithConfig = (
930
941
  // Inside the apply, not after the forEach: the structure only exists
931
942
  // once the Output resolves, so anything reading
932
943
  // `pluginStructuresStore` synchronously below reads an empty dict.
933
- declaredStoresOf(def)->Array.forEach(qualified =>
934
- // Registering the store is what lets an uploaded object be attributed
935
- // to the plugin that declared it, the way an S3 key's prefix does —
936
- // under the served `uploads/` prefix locally, for the reason
937
- // LocalObjectStore.localPrefixFor gives.
938
- LocalObjectStore.registerStore(
939
- ~qualified,
940
- ~prefix=LocalObjectStore.localPrefixFor(~qualified),
941
- )
944
+ declaredStoresOf(def)->Array.forEach(
945
+ qualified =>
946
+ // Registering the store is what lets an uploaded object be attributed
947
+ // to the plugin that declared it, the way an S3 key's prefix does —
948
+ // under the served `uploads/` prefix locally, for the reason
949
+ // LocalObjectStore.localPrefixFor gives.
950
+ LocalObjectStore.registerStore(
951
+ ~qualified,
952
+ ~prefix=LocalObjectStore.localPrefixFor(~qualified),
953
+ ),
942
954
  )
943
955
  // Two plugins declaring one store name is refused by the deployed
944
956
  // platform before it provisions anything. Local provisions no stores, so
@@ -950,12 +962,18 @@ module MakeWithConfig = (
950
962
  // Checked against every store registered so far rather than this
951
963
  // plugin's own, since a collision is by definition between two plugins.
952
964
  ReventlessCore.StorePrefixCollision.collisionsFor(
953
- ~stores=LocalObjectStore.declaredStoreList()->Array.map(((qualified, prefix)) => {
954
- ReventlessCore.StorePrefixCollision.qualified,
955
- prefix,
956
- }),
957
- )->Array.forEach(c =>
958
- log.warn(~comp="Platform:plugins", ReventlessCore.StorePrefixCollision.collisionMessage(c))
965
+ ~stores=LocalObjectStore.declaredStoreList()->Array.map(
966
+ ((qualified, prefix)) => {
967
+ ReventlessCore.StorePrefixCollision.qualified,
968
+ prefix,
969
+ },
970
+ ),
971
+ )->Array.forEach(
972
+ c =>
973
+ log.warn(
974
+ ~comp="Platform:plugins",
975
+ ReventlessCore.StorePrefixCollision.collisionMessage(c),
976
+ ),
959
977
  )
960
978
  | None => ()
961
979
  }
@@ -966,15 +984,17 @@ module MakeWithConfig = (
966
984
  // Bus keys for the admin Plugin aggregate (name-keyed). ComponentType.toName maps
967
985
  // CommandTopic → "CmdTopic" and EventTopic → "EventTopic".
968
986
  let pluginCmdTopicKey = ReventlessCore.PluginSpec.name ++ "Aggr" ++ "CmdTopic" // "PluginAggrCmdTopic"
969
- let pluginEventTopicKey =
970
- ReventlessCore.PluginSpec.name ++ "Aggr" ++ "EventTopic" // "PluginAggrEventTopic"
987
+ let pluginEventTopicKey = ReventlessCore.PluginSpec.name ++ "Aggr" ++ "EventTopic" // "PluginAggrEventTopic"
971
988
 
972
989
  // Dispatch a Plugin aggregate command in-process via the Bus command topic. The
973
990
  // body is the {id, meta, command} shape LocalCommandTopicChannel produces; the
974
991
  // aggregate id is the plugin NAME. dispatchCommand parks the command until the
975
992
  // aggregate's handler is registered (LocalBus pending-queue), so call-before-wire
976
993
  // is safe.
977
- let dispatchPluginCommand = (~pluginName: string, ~command: ReventlessCore.PluginSpec.command) => {
994
+ let dispatchPluginCommand = (
995
+ ~pluginName: string,
996
+ ~command: ReventlessCore.PluginSpec.command,
997
+ ) => {
978
998
  let cmdJson: Reventless.Message.commandJson = {
979
999
  id: pluginName,
980
1000
  meta: ReventlessCore.Message.generateMeta(~service=ReventlessCore.PluginSpec.name),
@@ -1104,7 +1124,11 @@ module MakeWithConfig = (
1104
1124
  ~manifest=manifestJson(newManifest),
1105
1125
  )
1106
1126
  | Some(UiFragmentDeregistered({pluginId})) =>
1107
- publishUIFragment(~name=pluginId, ~changeKind="Deregistered", ~manifest=JSON.Encode.null)
1127
+ publishUIFragment(
1128
+ ~name=pluginId,
1129
+ ~changeKind="Deregistered",
1130
+ ~manifest=JSON.Encode.null,
1131
+ )
1108
1132
  | None => ()
1109
1133
  }
1110
1134
  }
@@ -1175,18 +1199,20 @@ module MakeWithConfig = (
1175
1199
  },
1176
1200
  ),
1177
1201
  extensionProtocols: [],
1178
- apiSchemaFragment: apiSchemaFragment->Option.map(f =>
1179
- f->ReventlessCore.Plugin_Helpers.offloadPayload(
1180
- ~schema=Reventless.Plugin.apiSchemaFragmentSchema,
1181
- ~store="pluginApiFragments",
1182
- )
1202
+ apiSchemaFragment: apiSchemaFragment->Option.map(
1203
+ f =>
1204
+ f->ReventlessCore.Plugin_Helpers.offloadPayload(
1205
+ ~schema=Reventless.Plugin.apiSchemaFragmentSchema,
1206
+ ~store="pluginApiFragments",
1207
+ ),
1183
1208
  ),
1184
1209
  apiTarget: None,
1185
- structure: pluginStructure->Option.map(s =>
1186
- s->ReventlessCore.Plugin_Helpers.offloadPayload(
1187
- ~schema=Reventless.Plugin.pluginStructureSchema,
1188
- ~store="pluginStructures",
1189
- )
1210
+ structure: pluginStructure->Option.map(
1211
+ s =>
1212
+ s->ReventlessCore.Plugin_Helpers.offloadPayload(
1213
+ ~schema=Reventless.Plugin.pluginStructureSchema,
1214
+ ~store="pluginStructures",
1215
+ ),
1190
1216
  ),
1191
1217
  dcbEventLog: None,
1192
1218
  kind: Domain,
@@ -1227,8 +1253,7 @@ module MakeWithConfig = (
1227
1253
  exts
1228
1254
  ->Dict.valuesToArray
1229
1255
  ->Array.map((ext: ReventlessInfra.Extension.outputs) => {
1230
- let providerPlugin =
1231
- ext.extensionPointName->String.split(".")->Array.getUnsafe(0)
1256
+ let providerPlugin = ext.extensionPointName->String.split(".")->Array.getUnsafe(0)
1232
1257
  let wiring: ReventlessCore.Plugin_Helpers.extensionWiring = {
1233
1258
  extensionName: ext.name,
1234
1259
  extensionPointName: ext.extensionPointName,
@@ -1329,9 +1354,10 @@ module MakeWithConfig = (
1329
1354
  // After the register, and it fills the tap port in once the socket is bound:
1330
1355
  // the port is ephemeral by default, so it is not known until `listen` calls
1331
1356
  // back. The entry therefore never names a port that is not listening.
1332
- LocalEventTap.start(~onBound=tapPort =>
1333
- LocalPlatformRegistry.publishTapPort(~port=domainPort, ~tapPort)
1334
- , ())
1357
+ LocalEventTap.start(
1358
+ ~onBound=tapPort => LocalPlatformRegistry.publishTapPort(~port=domainPort, ~tapPort),
1359
+ (),
1360
+ )
1335
1361
  // Fire onPlatformDeployed after all servers are started so late-deployed
1336
1362
  // plugins (e.g. PlatformInspector) have their handler refs populated.
1337
1363
  ReventlessCore.Plugin_Helpers.firePlatformDeployedHook({
@@ -1377,7 +1403,10 @@ module MakeWithConfig = (
1377
1403
  let connectionResponse = (items: array<JSON.t>): JSON.t => {
1378
1404
  let edges =
1379
1405
  items->Array.mapWithIndex((item, i) =>
1380
- Dict.fromArray([("node", item), ("cursor", Int.toString(i)->JSON.Encode.string)])->JSON.Encode.object
1406
+ Dict.fromArray([
1407
+ ("node", item),
1408
+ ("cursor", Int.toString(i)->JSON.Encode.string),
1409
+ ])->JSON.Encode.object
1381
1410
  )
1382
1411
  let hasItems = edges->Array.length > 0
1383
1412
  Dict.fromArray([
@@ -1412,28 +1441,30 @@ module MakeWithConfig = (
1412
1441
  // `<single>Items(id, …)` — all rows under one partition (composite key).
1413
1442
  switch entry.subIdField {
1414
1443
  | Some(_) =>
1415
- queryResolvers->Dict.set(
1416
- entry.singleFieldName ++ "Items",
1417
- async (_root, args, _ctx): JSON.t =>
1418
- if !live {
1419
- connectionResponse([])
1420
- } else {
1421
- let id =
1422
- args
1423
- ->JSON.Decode.object
1424
- ->Option.flatMap(d => d->Dict.get("id"))
1425
- ->Option.flatMap(JSON.Decode.string)
1426
- ->Option.getOr("")
1427
- let items = switch Bus.getQueryDb(queryDbName) {
1428
- | Some(ops) =>
1429
- await ops.loadStream(id)
1430
- ->Stream.runCollect
1431
- ->Effect.catchAll(_ => Effect.succeed([]))
1432
- ->Effect.runPromise
1433
- | None => []
1434
- }
1435
- connectionResponse(items)
1436
- },
1444
+ queryResolvers->Dict.set(entry.singleFieldName ++ "Items", async (
1445
+ _root,
1446
+ args,
1447
+ _ctx,
1448
+ ): JSON.t =>
1449
+ if !live {
1450
+ connectionResponse([])
1451
+ } else {
1452
+ let id =
1453
+ args
1454
+ ->JSON.Decode.object
1455
+ ->Option.flatMap(d => d->Dict.get("id"))
1456
+ ->Option.flatMap(JSON.Decode.string)
1457
+ ->Option.getOr("")
1458
+ let items = switch Bus.getQueryDb(queryDbName) {
1459
+ | Some(ops) =>
1460
+ await ops.loadStream(id)
1461
+ ->Stream.runCollect
1462
+ ->Effect.catchAll(_ => Effect.succeed([]))
1463
+ ->Effect.runPromise
1464
+ | None => []
1465
+ }
1466
+ connectionResponse(items)
1467
+ }
1437
1468
  )
1438
1469
  | None => ()
1439
1470
  }
@@ -1450,8 +1481,9 @@ module MakeWithConfig = (
1450
1481
  ~singleFieldName=entry.singleFieldName,
1451
1482
  ~index=ic.index,
1452
1483
  )
1453
- queryResolvers->Dict.set(fieldName, async (_root, _args, _ctx): JSON.t =>
1454
- connectionResponse([])
1484
+ queryResolvers->Dict.set(
1485
+ fieldName,
1486
+ async (_root, _args, _ctx): JSON.t => connectionResponse([]),
1455
1487
  )
1456
1488
  })
1457
1489
  | None => ()
@@ -1547,16 +1579,20 @@ module MakeWithConfig = (
1547
1579
  // BEFORE this session appends anything. Catch-up replays only (checkpoint,
1548
1580
  // bound] — this session's own events (Connect dispatches, user commands)
1549
1581
  // are live-delivered and must not be redelivered.
1550
- let projectionCatchup = BackendState.getSqliteDb()->Option.map(db => (
1551
- db,
1552
- ProjectionCheckpoint.maxPosition(db, ProjectionPending.Aggregate),
1553
- ProjectionCheckpoint.maxPosition(db, ProjectionPending.Dcb),
1554
- ))
1582
+ let projectionCatchup =
1583
+ BackendState.getSqliteDb()->Option.map(db => (
1584
+ db,
1585
+ ProjectionCheckpoint.maxPosition(db, ProjectionPending.Aggregate),
1586
+ ProjectionCheckpoint.maxPosition(db, ProjectionPending.Dcb),
1587
+ ))
1555
1588
  // Postgres: read models are in-memory (rebuilt on every start), so capture the
1556
1589
  // pre-session head NOW — before plugins build or this session appends — and
1557
1590
  // full-replay (0, head] after the plugins register their projection handlers.
1558
1591
  let pgProjectionCatchup =
1559
- BackendState.getPostgresPool()->Option.map(pool => (pool, PgProjectionCatchup.captureBounds(pool)))
1592
+ BackendState.getPostgresPool()->Option.map(pool => (
1593
+ pool,
1594
+ PgProjectionCatchup.captureBounds(pool),
1595
+ ))
1560
1596
 
1561
1597
  // Create scheduler and populate platform context refs.
1562
1598
  let scheduler = makeScheduler()
@@ -1610,9 +1646,8 @@ module MakeWithConfig = (
1610
1646
  // receiveRegistry entries are pre-populated (queuing forwarder) so calls
1611
1647
  // are parked and drained once bindReceive fires (async, via Output.apply).
1612
1648
  ReventlessCore.Plugin_Helpers.onPluginBuiltHook.contents = existingBuiltHook
1613
- let allPluginOutputs = plugins->Array.map(p =>
1614
- (ReventlessCore.Component.outputs(p): ReventlessInfra.Plugin.outputs)
1615
- )
1649
+ let allPluginOutputs =
1650
+ plugins->Array.map((p): ReventlessInfra.Plugin.outputs => ReventlessCore.Component.outputs(p))
1616
1651
  firePluginDeployedHooks(~builtInfos=builtInfos.contents, ~pluginOutputs=allPluginOutputs)
1617
1652
 
1618
1653
  // Wire cross-plugin Extension → EP EventTopic subscriptions.
@@ -1625,11 +1660,15 @@ module MakeWithConfig = (
1625
1660
  (outputs.eventCollector, outputs.extensions)
1626
1661
  ->Pulumi.Output.all2
1627
1662
  ->Pulumi.Output.apply(((eventCollector, extensions)) => {
1628
- extensions->Dict.toArray->Array.forEach(((_, ext: ReventlessInfra.Extension.outputs)) => {
1629
- let epTopicKey =
1630
- ext.extensionPointName->String.replace(".", "") ++ "ExtPointEventTopic"
1631
- Bus.subscribeEventCollectorToTopic(eventCollector.name, epTopicKey)
1632
- })
1663
+ extensions
1664
+ ->Dict.toArray
1665
+ ->Array.forEach(
1666
+ ((_, ext: ReventlessInfra.Extension.outputs)) => {
1667
+ let epTopicKey =
1668
+ ext.extensionPointName->String.replace(".", "") ++ "ExtPointEventTopic"
1669
+ Bus.subscribeEventCollectorToTopic(eventCollector.name, epTopicKey)
1670
+ },
1671
+ )
1633
1672
  })
1634
1673
  })
1635
1674
  ReventlessCore.Plugin_Helpers.firePlatformDeployedHook({
@@ -1773,7 +1812,9 @@ module MakeWithConfig = (
1773
1812
  switch Bus.getQueryDbScan(pluginQueryDbName) {
1774
1813
  | Some(scanAll) =>
1775
1814
  scanAll()->Array.forEach(json =>
1776
- switch json->Reventless.Util_Sury.fromJson(ReventlessCore.PluginsReadModelSpec.stateSchema) {
1815
+ switch json->Reventless.Util_Sury.fromJson(
1816
+ ReventlessCore.PluginsReadModelSpec.stateSchema,
1817
+ ) {
1777
1818
  | state => statusByName->Dict.set(state.name, state.status)
1778
1819
  | exception _ => ()
1779
1820
  }
@@ -1799,7 +1840,9 @@ module MakeWithConfig = (
1799
1840
  let adminQueryEntry = ReventlessCore.PluginBaseFragment.queryEntries->Array.getUnsafe(0)
1800
1841
  let singleQueryField = adminQueryEntry.singleFieldName
1801
1842
  let listQueryField = adminQueryEntry.listFieldName
1802
- let adminMutationEntries = ReventlessCore.Platform_AdminApi.mutationEntries(~cloner=Config.cloner)
1843
+ let adminMutationEntries = ReventlessCore.Platform_AdminApi.mutationEntries(
1844
+ ~cloner=Config.cloner,
1845
+ )
1803
1846
  let adminMutationFieldNames = adminMutationEntries->Array.flatMap(entry => entry.fieldNames)
1804
1847
 
1805
1848
  // Register the admin Plugin aggregate's types/queries/mutations to the platform target.
@@ -1855,7 +1898,9 @@ module MakeWithConfig = (
1855
1898
  switch Bus.getQueryDbScan(pluginQueryDbName) {
1856
1899
  | Some(scanAll) =>
1857
1900
  scanAll()->Array.forEach(json =>
1858
- switch json->Reventless.Util_Sury.fromJson(ReventlessCore.PluginsReadModelSpec.stateSchema) {
1901
+ switch json->Reventless.Util_Sury.fromJson(
1902
+ ReventlessCore.PluginsReadModelSpec.stateSchema,
1903
+ ) {
1859
1904
  | state =>
1860
1905
  let id = state.name ++ "@" ++ state.version
1861
1906
  dict->Dict.set(id, state.status)
@@ -1897,67 +1942,60 @@ module MakeWithConfig = (
1897
1942
  latestByName->Dict.valuesToArray->Array.map(((_, pair)) => pair)
1898
1943
  }
1899
1944
 
1900
- queryResolvers->Dict.set(
1901
- "Platform_ComponentDefinitions",
1902
- async (_root, _args, _ctx): JSON.t =>
1903
- connectedLatestStructures()
1904
- ->Array.map(((pluginId, def)) =>
1905
- ReventlessCore.Platform_ComponentDefinitionsApi.encodePluginStructureEntry(~pluginId, def)
1906
- )
1907
- ->JSON.Encode.array,
1945
+ queryResolvers->Dict.set("Platform_ComponentDefinitions", async (_root, _args, _ctx): JSON.t =>
1946
+ connectedLatestStructures()
1947
+ ->Array.map(((pluginId, def)) =>
1948
+ ReventlessCore.Platform_ComponentDefinitionsApi.encodePluginStructureEntry(~pluginId, def)
1949
+ )
1950
+ ->JSON.Encode.array
1908
1951
  )
1909
1952
 
1910
1953
  // Platform_PluginStructures resolver — the same plugins, encoded unfiltered for
1911
1954
  // developer tooling (Internal components kept, extension points carried).
1912
- queryResolvers->Dict.set(
1913
- "Platform_PluginStructures",
1914
- async (_root, _args, _ctx): JSON.t =>
1915
- connectedLatestStructures()
1916
- ->Array.map(((pluginId, def)) =>
1917
- ReventlessCore.Platform_PluginStructuresApi.encodePluginStructureEntry(~pluginId, def)
1918
- )
1919
- ->JSON.Encode.array,
1955
+ queryResolvers->Dict.set("Platform_PluginStructures", async (_root, _args, _ctx): JSON.t =>
1956
+ connectedLatestStructures()
1957
+ ->Array.map(((pluginId, def)) =>
1958
+ ReventlessCore.Platform_PluginStructuresApi.encodePluginStructureEntry(~pluginId, def)
1959
+ )
1960
+ ->JSON.Encode.array
1920
1961
  )
1921
1962
 
1922
1963
  // Platform_UIFragments resolver — reads the UiFragments StateViewSlice
1923
1964
  // QueryDb (populated by the UiFragmentRegistry slice's projection) and
1924
1965
  // encodes via the shared Platform_UIFragmentsApi encoder so AWS and
1925
1966
  // in-memory return the same JSON shape.
1926
- queryResolvers->Dict.set(
1927
- "Platform_UIFragments",
1928
- async (_root, _args, _ctx): JSON.t => {
1929
- let items = switch Bus.getQueryDbScan(uiFragmentQueryDbName) {
1930
- | Some(scanAll) => scanAll()
1931
- | None => []
1932
- }
1933
- // Collapse to one entry per plugin name (highest version). The registry is
1934
- // keyed by bare plugin name now (a no-op collapse), but rows persisted by
1935
- // the pre-slice registry were keyed name@version — keep the dedup so a
1936
- // mixed store never surfaces duplicates (mirrors Platform_UIFragments_Lambda.res).
1937
- let latestByName = Dict.make()
1938
- items->Array.forEach(item =>
1939
- switch item->S.parseOrThrow(~to=ReventlessCore.UiFragments.stateSchema) {
1940
- | state =>
1941
- let name = ReventlessCore.Plugin.name(state.pluginId)
1942
- let version = ReventlessCore.Plugin.version(state.pluginId)
1943
- switch latestByName->Dict.get(name) {
1944
- | Some((prevVersion, _)) =>
1945
- if ReventlessCore.Plugin.compareVersions(version, prevVersion) > 0 {
1946
- latestByName->Dict.set(name, (version, state))
1947
- }
1948
- | None => latestByName->Dict.set(name, (version, state))
1967
+ queryResolvers->Dict.set("Platform_UIFragments", async (_root, _args, _ctx): JSON.t => {
1968
+ let items = switch Bus.getQueryDbScan(uiFragmentQueryDbName) {
1969
+ | Some(scanAll) => scanAll()
1970
+ | None => []
1971
+ }
1972
+ // Collapse to one entry per plugin name (highest version). The registry is
1973
+ // keyed by bare plugin name now (a no-op collapse), but rows persisted by
1974
+ // the pre-slice registry were keyed name@version keep the dedup so a
1975
+ // mixed store never surfaces duplicates (mirrors Platform_UIFragments_Lambda.res).
1976
+ let latestByName = Dict.make()
1977
+ items->Array.forEach(item =>
1978
+ switch item->S.parseOrThrow(~to=ReventlessCore.UiFragments.stateSchema) {
1979
+ | state =>
1980
+ let name = ReventlessCore.Plugin.name(state.pluginId)
1981
+ let version = ReventlessCore.Plugin.version(state.pluginId)
1982
+ switch latestByName->Dict.get(name) {
1983
+ | Some((prevVersion, _)) =>
1984
+ if ReventlessCore.Plugin.compareVersions(version, prevVersion) > 0 {
1985
+ latestByName->Dict.set(name, (version, state))
1949
1986
  }
1950
- | exception _ => ()
1987
+ | None => latestByName->Dict.set(name, (version, state))
1951
1988
  }
1952
- )
1953
- latestByName
1954
- ->Dict.valuesToArray
1955
- ->Array.map(((_, state)) =>
1956
- ReventlessCore.Platform_UIFragmentsApi.encodeUIFragmentEntry(state)
1957
- )
1958
- ->JSON.Encode.array
1959
- },
1960
- )
1989
+ | exception _ => ()
1990
+ }
1991
+ )
1992
+ latestByName
1993
+ ->Dict.valuesToArray
1994
+ ->Array.map(((_, state)) =>
1995
+ ReventlessCore.Platform_UIFragmentsApi.encodeUIFragmentEntry(state)
1996
+ )
1997
+ ->JSON.Encode.array
1998
+ })
1961
1999
  // Composite-key / index admin query fields. Live loads from the seeded QueryDb stores.
1962
2000
  registerAdminItemsAndIndexResolvers(~queryResolvers, ~live=true)
1963
2001
 
@@ -1982,7 +2020,9 @@ module MakeWithConfig = (
1982
2020
  switch Bus.getQueryDbScan(pluginQueryDbName) {
1983
2021
  | Some(scanAll) =>
1984
2022
  scanAll()->Array.findMap(json =>
1985
- switch json->Reventless.Util_Sury.fromJson(ReventlessCore.PluginsReadModelSpec.stateSchema) {
2023
+ switch json->Reventless.Util_Sury.fromJson(
2024
+ ReventlessCore.PluginsReadModelSpec.stateSchema,
2025
+ ) {
1986
2026
  | state if state.name == pluginName => Some(state.version)
1987
2027
  | _ => None
1988
2028
  | exception _ => None
@@ -2013,9 +2053,16 @@ module MakeWithConfig = (
2013
2053
  }
2014
2054
  switch version {
2015
2055
  | Some(version) =>
2016
- log.info(~comp=ReventlessCore.Platform_Admin_Structure.pluginId, `${field}(${pluginName}@${version}): dispatching to aggregate`)
2056
+ log.info(
2057
+ ~comp=ReventlessCore.Platform_Admin_Structure.pluginId,
2058
+ `${field}(${pluginName}@${version}): dispatching to aggregate`,
2059
+ )
2017
2060
  let _ = dispatchPluginCommand(~pluginName, ~command=makeCommand(version))
2018
- | None => log.warn(~comp=ReventlessCore.Platform_Admin_Structure.pluginId, `${field}(${pluginName}): plugin not found`)
2061
+ | None =>
2062
+ log.warn(
2063
+ ~comp=ReventlessCore.Platform_Admin_Structure.pluginId,
2064
+ `${field}(${pluginName}): plugin not found`,
2065
+ )
2019
2066
  }
2020
2067
  commandAccepted(~msgId, ~entityId=pluginName)
2021
2068
  }
@@ -2024,13 +2071,19 @@ module MakeWithConfig = (
2024
2071
  let retireField = ReventlessCore.Api_Naming.adminField(~name="Plugin_Retire")
2025
2072
  let mutationResolvers = Dict.make()
2026
2073
  mutationResolvers->Dict.set(activateField, async (_root, args, _ctx): JSON.t =>
2027
- dispatchLifecycle(~field=activateField, args, v => ReventlessCore.PluginSpec.Activate({version: v}))
2074
+ dispatchLifecycle(~field=activateField, args, v => ReventlessCore.PluginSpec.Activate({
2075
+ version: v,
2076
+ }))
2028
2077
  )
2029
2078
  mutationResolvers->Dict.set(deactivateField, async (_root, args, _ctx): JSON.t =>
2030
- dispatchLifecycle(~field=deactivateField, args, v => ReventlessCore.PluginSpec.Deactivate({version: v}))
2079
+ dispatchLifecycle(~field=deactivateField, args, v => ReventlessCore.PluginSpec.Deactivate({
2080
+ version: v,
2081
+ }))
2031
2082
  )
2032
2083
  mutationResolvers->Dict.set(retireField, async (_root, args, _ctx): JSON.t =>
2033
- dispatchLifecycle(~field=retireField, args, v => ReventlessCore.PluginSpec.Retire({version: v}))
2084
+ dispatchLifecycle(~field=retireField, args, v => ReventlessCore.PluginSpec.Retire({
2085
+ version: v,
2086
+ }))
2034
2087
  )
2035
2088
  // Remaining admin mutations (e.g., Clone) are no-ops in-memory.
2036
2089
  adminMutationFieldNames->Array.forEach(field =>
@@ -2050,7 +2103,7 @@ module MakeWithConfig = (
2050
2103
  ("pluginId", JSON.Encode.string(ReventlessCore.Plugin.name(pluginId))),
2051
2104
  ("changeKind", JSON.Encode.string(changeKind)),
2052
2105
  ("manifest", manifest),
2053
- ])
2106
+ ]),
2054
2107
  )
2055
2108
  let addUIFragmentMutation = (fieldName, changeKind) =>
2056
2109
  mutationResolvers->Dict.set(fieldName, async (_root, args, _ctx): JSON.t => {
@@ -2169,6 +2222,7 @@ module MakeWithConfig = (
2169
2222
  // Geocoding client door (D9 half 2) on the domain server — same mirror. A dev
2170
2223
  // stub (no real geocoder locally), so the map picker's search box works offline.
2171
2224
  LocalGeocodeResolvers.register(DomainGraphQL_Server.asInterface)
2225
+
2172
2226
  // In split mode, inject Relay base types (Node interface, PageInfo) into the platform
2173
2227
  // server so SDL fragments compile. The node(id) query is Domain-only — the Platform
2174
2228
  // API is consumed by admin tools and agents, not Relay clients.
@@ -2187,7 +2241,6 @@ module MakeWithConfig = (
2187
2241
  DomainGraphQL_Server.start()
2188
2242
  DomainMCP_Server.start()
2189
2243
  }
2190
-
2191
2244
  }
2192
2245
 
2193
2246
  let deployPlatform = (
@@ -2241,9 +2294,8 @@ module MakeWithConfig = (
2241
2294
  // Platform_UIFragments — empty in the platform-only path (no plugins
2242
2295
  // connected → no UI fragments registered). The SDL declares it as a
2243
2296
  // non-null array so we must register a resolver returning [].
2244
- queryResolvers->Dict.set(
2245
- "Platform_UIFragments",
2246
- async (_root, _args, _ctx): JSON.t => JSON.Encode.array([]),
2297
+ queryResolvers->Dict.set("Platform_UIFragments", async (_root, _args, _ctx): JSON.t =>
2298
+ JSON.Encode.array([])
2247
2299
  )
2248
2300
  // Composite-key / index admin query fields — empty stubs in the platform-only
2249
2301
  // path (no plugins connected → no QueryDb seeded).
@@ -2251,7 +2303,9 @@ module MakeWithConfig = (
2251
2303
  adminGraphQL.registerQueries(~sdlFields=baseParts.queries, ~resolvers=queryResolvers)
2252
2304
 
2253
2305
  let mutationResolvers = Dict.make()
2254
- let adminMutationEntries = ReventlessCore.Platform_AdminApi.mutationEntries(~cloner=Config.cloner)
2306
+ let adminMutationEntries = ReventlessCore.Platform_AdminApi.mutationEntries(
2307
+ ~cloner=Config.cloner,
2308
+ )
2255
2309
  let adminMutationFieldNames = adminMutationEntries->Array.flatMap(entry => entry.fieldNames)
2256
2310
  adminMutationFieldNames->Array.forEach(field =>
2257
2311
  mutationResolvers->Dict.set(field, async (_root, _args, _ctx): JSON.t =>
@@ -2288,17 +2342,17 @@ module MakeWithConfig = (
2288
2342
  "Deregistered",
2289
2343
  )
2290
2344
  CommandGeneratorResolvers_GraphQL.ensureCommandResultTypes(adminGraphQL)
2291
- adminGraphQL.registerMutations(~sdlFields=adminMutationSdl(baseParts.mutations), ~resolvers=mutationResolvers)
2345
+ adminGraphQL.registerMutations(
2346
+ ~sdlFields=adminMutationSdl(baseParts.mutations),
2347
+ ~resolvers=mutationResolvers,
2348
+ )
2292
2349
  adminGraphQL.registerSubscriptions(
2293
2350
  ~sdlFields=[
2294
2351
  " onUIFragmentChange: UIFragmentChangeEvent",
2295
2352
  " onPluginStatusChange: PluginStatusChangeEvent",
2296
2353
  ],
2297
2354
  ~resolvers=Dict.fromArray([
2298
- (
2299
- "onUIFragmentChange",
2300
- LocalGraphQL_SubscriptionResolvers.makeFieldResolver(dpSubTopic),
2301
- ),
2355
+ ("onUIFragmentChange", LocalGraphQL_SubscriptionResolvers.makeFieldResolver(dpSubTopic)),
2302
2356
  (
2303
2357
  "onPluginStatusChange",
2304
2358
  LocalGraphQL_SubscriptionResolvers.makeFieldResolver("onPluginStatusChange"),
@@ -2317,11 +2371,22 @@ module MakeWithConfig = (
2317
2371
  // server's `asInterface.start` accepts but ignores `~contextFactory`
2318
2372
  // because it always wires its own internal auth context.
2319
2373
  adminGraphQL.start(
2320
- ~port=if Config.splitApi { 4001 } else { 4000 },
2374
+ ~port=if Config.splitApi {
2375
+ 4001
2376
+ } else {
2377
+ 4000
2378
+ },
2321
2379
  ~contextFactory=Auth_GraphqlContext.buildAuthContext,
2322
2380
  (),
2323
2381
  )
2324
- adminMCP.start(~port=if Config.splitApi { 3002 } else { 3001 }, ())
2382
+ adminMCP.start(
2383
+ ~port=if Config.splitApi {
2384
+ 3002
2385
+ } else {
2386
+ 3001
2387
+ },
2388
+ (),
2389
+ )
2325
2390
  if Config.splitApi {
2326
2391
  DomainGraphQL_Server.start()
2327
2392
  DomainMCP_Server.start()
@@ -2346,11 +2411,18 @@ module MakeWithConfig = (
2346
2411
  }
2347
2412
 
2348
2413
  let deployPlugin = (~plugin: module(PluginMaker), ~apiTarget=Domain) => {
2349
- log.info(~comp="Platform", `deployPlugin target=${switch apiTarget { | Domain => "Domain" | Platform => "Platform" }}`)
2414
+ log.info(
2415
+ ~comp="Platform",
2416
+ `deployPlugin target=${switch apiTarget {
2417
+ | Domain => "Domain"
2418
+ | Platform => "Platform"
2419
+ }}`,
2420
+ )
2350
2421
 
2351
2422
  // Set the active deploy target so resolveTargetGraphQL/MCP() and QueryDb serverRef/relayRef
2352
2423
  // route registrations to the correct server. Mirrors AWS resolveTargetApi() pattern.
2353
2424
  currentDeployTarget.contents = apiTarget
2425
+
2354
2426
  // Update QueryDb server/relay refs on the shared StateViewSliceMaker.QueryDbResolvers instance.
2355
2427
  // Do NOT create a new QueryDbResolvers_GraphQL.Make(Bus) here — that would be a different
2356
2428
  // module instance from the one StateViewSlice_Builder captured, leaving its refs unchanged.
@@ -2417,46 +2489,46 @@ module MakeWithConfig = (
2417
2489
 
2418
2490
  let queryResolvers = Dict.make()
2419
2491
  let adminQueryEntry = ReventlessCore.PluginBaseFragment.queryEntries->Array.getUnsafe(0)
2420
- queryResolvers->Dict.set(adminQueryEntry.singleFieldName, async (_root, _args, _ctx): JSON.t =>
2421
- JSON.Encode.null
2422
- )
2492
+ queryResolvers->Dict.set(adminQueryEntry.singleFieldName, async (
2493
+ _root,
2494
+ _args,
2495
+ _ctx,
2496
+ ): JSON.t => JSON.Encode.null)
2423
2497
  queryResolvers->Dict.set(adminQueryEntry.listFieldName, async (_root, _args, _ctx): JSON.t =>
2424
2498
  connectionResponse([])
2425
2499
  )
2426
2500
  // Platform_UIFragments — single-plugin path. Populated by the
2427
2501
  // UiFragments StateViewSlice when the plugin registers a manifest through
2428
2502
  // the admin EP (connectPlugin below), otherwise scans an empty store.
2429
- queryResolvers->Dict.set(
2430
- "Platform_UIFragments",
2431
- async (_root, _args, _ctx): JSON.t => {
2432
- let items = switch Bus.getQueryDbScan(ReventlessCore.UiFragments.name) {
2433
- | Some(scanAll) => scanAll()
2434
- | None => []
2503
+ queryResolvers->Dict.set("Platform_UIFragments", async (_root, _args, _ctx): JSON.t => {
2504
+ let items = switch Bus.getQueryDbScan(ReventlessCore.UiFragments.name) {
2505
+ | Some(scanAll) => scanAll()
2506
+ | None => []
2507
+ }
2508
+ items
2509
+ ->Array.filterMap(item =>
2510
+ switch item->S.parseOrThrow(~to=ReventlessCore.UiFragments.stateSchema) {
2511
+ | state => Some(ReventlessCore.Platform_UIFragmentsApi.encodeUIFragmentEntry(state))
2512
+ | exception _ => None
2435
2513
  }
2436
- items
2437
- ->Array.filterMap(item =>
2438
- switch item->S.parseOrThrow(~to=ReventlessCore.UiFragments.stateSchema) {
2439
- | state =>
2440
- Some(ReventlessCore.Platform_UIFragmentsApi.encodeUIFragmentEntry(state))
2441
- | exception _ => None
2442
- }
2443
- )
2444
- ->JSON.Encode.array
2445
- },
2446
- )
2514
+ )
2515
+ ->JSON.Encode.array
2516
+ })
2447
2517
  // Platform_ComponentDefinitions resolver — SDL is already stitched into baseParts via
2448
2518
  // Platform_AdminApi.baseFragment so we register only the resolver here. Uses the shared
2449
2519
  // encoder so the dynamic-plugin admin server emits the same canonical shape as
2450
2520
  // the main platform server (and as AWS).
2451
- queryResolvers->Dict.set(
2452
- "Platform_ComponentDefinitions",
2453
- async (_root, _args, _ctx): JSON.t =>
2454
- pluginStructuresStore.contents
2455
- ->Dict.toArray
2456
- ->Array.map(((pluginId, def)) =>
2457
- ReventlessCore.Platform_ComponentDefinitionsApi.encodePluginStructureEntry(~pluginId, def)
2458
- )
2459
- ->JSON.Encode.array,
2521
+ queryResolvers->Dict.set("Platform_ComponentDefinitions", async (
2522
+ _root,
2523
+ _args,
2524
+ _ctx,
2525
+ ): JSON.t =>
2526
+ pluginStructuresStore.contents
2527
+ ->Dict.toArray
2528
+ ->Array.map(((pluginId, def)) =>
2529
+ ReventlessCore.Platform_ComponentDefinitionsApi.encodePluginStructureEntry(~pluginId, def)
2530
+ )
2531
+ ->JSON.Encode.array
2460
2532
  )
2461
2533
  // Composite-key / index admin query fields.
2462
2534
  // Live loads from the seeded QueryDb stores (empty when not yet seeded).
@@ -2464,7 +2536,9 @@ module MakeWithConfig = (
2464
2536
  adminGraphQL.registerQueries(~sdlFields=baseParts.queries, ~resolvers=queryResolvers)
2465
2537
 
2466
2538
  let mutationResolvers = Dict.make()
2467
- let adminMutationEntries = ReventlessCore.Platform_AdminApi.mutationEntries(~cloner=Config.cloner)
2539
+ let adminMutationEntries = ReventlessCore.Platform_AdminApi.mutationEntries(
2540
+ ~cloner=Config.cloner,
2541
+ )
2468
2542
  let adminMutationFieldNames = adminMutationEntries->Array.flatMap(entry => entry.fieldNames)
2469
2543
  adminMutationFieldNames->Array.forEach(field =>
2470
2544
  mutationResolvers->Dict.set(field, async (_root, _args, _ctx): JSON.t =>
@@ -2501,14 +2575,14 @@ module MakeWithConfig = (
2501
2575
  "Deregistered",
2502
2576
  )
2503
2577
  CommandGeneratorResolvers_GraphQL.ensureCommandResultTypes(adminGraphQL)
2504
- adminGraphQL.registerMutations(~sdlFields=adminMutationSdl(baseParts.mutations), ~resolvers=mutationResolvers)
2578
+ adminGraphQL.registerMutations(
2579
+ ~sdlFields=adminMutationSdl(baseParts.mutations),
2580
+ ~resolvers=mutationResolvers,
2581
+ )
2505
2582
  adminGraphQL.registerSubscriptions(
2506
2583
  ~sdlFields=[" onUIFragmentChange: UIFragmentChangeEvent"],
2507
2584
  ~resolvers=Dict.fromArray([
2508
- (
2509
- "onUIFragmentChange",
2510
- LocalGraphQL_SubscriptionResolvers.makeFieldResolver(dpSubTopic2),
2511
- ),
2585
+ ("onUIFragmentChange", LocalGraphQL_SubscriptionResolvers.makeFieldResolver(dpSubTopic2)),
2512
2586
  ]),
2513
2587
  )
2514
2588
  adminRegisteredServers.contents->Array.push(adminGraphQL)
@@ -2527,7 +2601,9 @@ module MakeWithConfig = (
2527
2601
  seedPluginStructuresStore(~pluginComponents=[pluginComponent])
2528
2602
 
2529
2603
  // Fire onPluginDeployed hooks so subscribers learn about this plugin.
2530
- let deployedPluginOutputs = [(ReventlessCore.Component.outputs(pluginComponent): ReventlessInfra.Plugin.outputs)]
2604
+ let deployedPluginOutputs = [
2605
+ (ReventlessCore.Component.outputs(pluginComponent): ReventlessInfra.Plugin.outputs),
2606
+ ]
2531
2607
  firePluginDeployedHooks(~builtInfos=builtInfos.contents, ~pluginOutputs=deployedPluginOutputs)
2532
2608
 
2533
2609
  // Late-deployed plugins may register an onPlatformDeployed hook that missed