@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
@@ -41,11 +41,7 @@ let manifestUrlOf = (config: ReventlessInfra.Platform.bakedManifest): string =>
41
41
  // caller matching no declared group gets and what every existing deployment has.
42
42
  let journeyManifestsKey = "journeyManifestUrls"
43
43
 
44
- let computedKeys = [
45
- "manifestUrl",
46
- journeyManifestsKey,
47
- ReventlessCore.Platform_UiSlots.configKey,
48
- ]
44
+ let computedKeys = ["manifestUrl", journeyManifestsKey, ReventlessCore.Platform_UiSlots.configKey]
49
45
 
50
46
  /**
51
47
  The overlay this platform puts on top of the shipped `config.json`.
@@ -96,8 +92,9 @@ let overlay = (
96
92
  if collisions->Array.length > 0 {
97
93
  JsError.throwWithMessage(
98
94
  "host UI config.json: shellConfig sets key(s) the platform already computes — " ++
99
- collisions->Array.join(", ") ++
100
- ". Remove them from shellConfig; a passthrough cannot redirect a computed key.",
95
+ collisions->Array.join(
96
+ ", ",
97
+ ) ++ ". Remove them from shellConfig; a passthrough cannot redirect a computed key.",
101
98
  )
102
99
  }
103
100
  extra->Dict.forEachWithKey((v, k) => out->Dict.set(k, v))
@@ -134,12 +131,10 @@ let emit = (
134
131
  ) => {
135
132
  let overlay = overlay(~bakedManifest, ~uiSlotsFile?, ~shellConfig)
136
133
 
137
- switch (
138
- switch dir {
139
- | Some(_) as given => given
140
- | None => HostShellDist.dir()
141
- }
142
- ) {
134
+ switch switch dir {
135
+ | Some(_) as given => given
136
+ | None => HostShellDist.dir()
137
+ } {
143
138
  | None =>
144
139
  // Nothing declared and no shell installed is the ordinary case for a
145
140
  // platform nobody points a browser at; only a declaration makes the missing
@@ -148,8 +143,7 @@ let emit = (
148
143
  JsError.throwWithMessage(
149
144
  `host UI config.json: cannot resolve ${HostShellDist.package} from ${NodeProcess.cwd()} — ` ++
150
145
  `the local shell reads its config from that package's dist/, so declaring shell ` ++
151
- `config without the package installed would write nothing and leave the shell ` ++
152
- `configured as it shipped.`,
146
+ `config without the package installed would write nothing and leave the shell ` ++ `configured as it shipped.`,
153
147
  )
154
148
  }
155
149
  | Some(dir) =>
@@ -163,8 +157,7 @@ let emit = (
163
157
  if !NodeFs.existsSync(path) {
164
158
  JsError.throwWithMessage(
165
159
  `host UI config.json: ${HostShellDist.package} ships no ${fileName} at ${dir} — ` ++
166
- `there is no baseline to overlay, so the shell would boot with only the keys ` ++
167
- `declared here and none of the ones it expects.`,
160
+ `there is no baseline to overlay, so the shell would boot with only the keys ` ++ `declared here and none of the ones it expects.`,
168
161
  )
169
162
  }
170
163
  NodeFs.writeFileSync(baselinePath, NodeFs.readFileSync(path))
package/src/UiHints.res CHANGED
@@ -50,27 +50,23 @@ let emit = (
50
50
  | exception _ =>
51
51
  JsError.throwWithMessage(
52
52
  `host UI ${fileName}: cannot read the declared uiHintsFile at ${path} — ` ++
53
- `the shell fetches this file at boot, so a declaration pointing nowhere ` ++
54
- `applies no hints and says nothing about why.`,
53
+ `the shell fetches this file at boot, so a declaration pointing nowhere ` ++ `applies no hints and says nothing about why.`,
55
54
  )
56
55
  }
57
56
  switch source->JSON.parseOrThrow {
58
57
  | _ => ()
59
58
  | exception _ =>
60
59
  JsError.throwWithMessage(
61
- `host UI ${fileName}: the declared uiHintsFile at ${path} is not JSON — ` ++
62
- `the shell warns once and applies no hints, which reads as hints that do nothing.`,
60
+ `host UI ${fileName}: the declared uiHintsFile at ${path} is not JSON — ` ++ `the shell warns once and applies no hints, which reads as hints that do nothing.`,
63
61
  )
64
62
  }
65
63
  source
66
64
  })
67
65
 
68
- switch (
69
- switch dir {
70
- | Some(_) as given => given
71
- | None => HostShellDist.dir()
72
- }
73
- ) {
66
+ switch switch dir {
67
+ | Some(_) as given => given
68
+ | None => HostShellDist.dir()
69
+ } {
74
70
  | None =>
75
71
  // No shell installed is the ordinary case for a platform nobody points a
76
72
  // browser at; only a declaration makes the missing package an error.
@@ -78,8 +74,7 @@ let emit = (
78
74
  JsError.throwWithMessage(
79
75
  `host UI ${fileName}: cannot resolve ${HostShellDist.package} from ${NodeProcess.cwd()} — ` ++
80
76
  `the local shell reads its hints from that package's dist/, so declaring a ` ++
81
- `uiHintsFile without the package installed would write nothing and leave the ` ++
82
- `shell applying whatever the package shipped.`,
77
+ `uiHintsFile without the package installed would write nothing and leave the ` ++ `shell applying whatever the package shipped.`,
83
78
  )
84
79
  }
85
80
  | Some(dir) =>
@@ -148,8 +143,7 @@ let watch = (
148
143
  // away between the two — worth a line, not worth a throw.
149
144
  log.warn(
150
145
  ~comp="UiHints",
151
- `not watching ${base}: ${sourceDir} does not exist, so changes to the declared ` ++
152
- `uiHintsFile will need a restart`,
146
+ `not watching ${base}: ${sourceDir} does not exist, so changes to the declared ` ++ `uiHintsFile will need a restart`,
153
147
  )
154
148
  None
155
149
  } else {
package/src/UiSlots.res CHANGED
@@ -66,18 +66,15 @@ let emit = (
66
66
  | exception _ =>
67
67
  JsError.throwWithMessage(
68
68
  `host UI ${fileName}: cannot read the declared uiSlotsFile at ${path} — ` ++
69
- `the shell imports this file at boot, so a declaration pointing nowhere ` ++
70
- `registers no renderers and says nothing about why.`,
69
+ `the shell imports this file at boot, so a declaration pointing nowhere ` ++ `registers no renderers and says nothing about why.`,
71
70
  )
72
71
  }
73
72
  )
74
73
 
75
- switch (
76
- switch dir {
77
- | Some(_) as given => given
78
- | None => HostShellDist.dir()
79
- }
80
- ) {
74
+ switch switch dir {
75
+ | Some(_) as given => given
76
+ | None => HostShellDist.dir()
77
+ } {
81
78
  | None =>
82
79
  // No shell installed is the ordinary case for a platform nobody points a
83
80
  // browser at; only a declaration makes the missing package an error.
@@ -85,8 +82,7 @@ let emit = (
85
82
  JsError.throwWithMessage(
86
83
  `host UI ${fileName}: cannot resolve ${HostShellDist.package} from ${NodeProcess.cwd()} — ` ++
87
84
  `the local shell imports its slot renderers from that package's dist/, so ` ++
88
- `declaring a uiSlotsFile without the package installed would write nothing ` ++
89
- `and leave every mode drawing its own regions.`,
85
+ `declaring a uiSlotsFile without the package installed would write nothing ` ++ `and leave every mode drawing its own regions.`,
90
86
  )
91
87
  }
92
88
  | Some(dir) =>
@@ -132,11 +128,9 @@ let emit = (
132
128
  `onReload` runs only after a re-copy actually succeeded, so a subscriber cannot
133
129
  be told to re-import a file that did not change.
134
130
  */
135
- let watch = (
136
- ~uiSlotsFile: option<string>,
137
- ~dir: option<string>=?,
138
- ~onReload: unit => unit,
139
- ): option<NodeFs.watcher> =>
131
+ let watch = (~uiSlotsFile: option<string>, ~dir: option<string>=?, ~onReload: unit => unit): option<
132
+ NodeFs.watcher,
133
+ > =>
140
134
  uiSlotsFile->Option.flatMap(path => {
141
135
  // Named apart from the `~dir` above, which is where the file is SERVED. This
142
136
  // is where it is AUTHORED, and the two are never the same place — letting
@@ -150,8 +144,7 @@ let watch = (
150
144
  // away between the two — worth a line, not worth a throw.
151
145
  log.warn(
152
146
  ~comp="UiSlots",
153
- `not watching ${base}: ${sourceDir} does not exist, so changes to the declared ` ++
154
- `uiSlotsFile will need a restart`,
147
+ `not watching ${base}: ${sourceDir} does not exist, so changes to the declared ` ++ `uiSlotsFile will need a restart`,
155
148
  )
156
149
  None
157
150
  } else {
@@ -27,8 +27,7 @@ let log = ReventlessCore.Logger.fromEnv()
27
27
 
28
28
  // Mirrors AppSyncEventsSigner_Ops.pathSegment (aws) and the client's channel
29
29
  // normalizer: any char outside [A-Za-z0-9-] becomes `-`.
30
- let pathSegment = (s: string): string =>
31
- s->String.replaceRegExp(/[^A-Za-z0-9-]/g, "-")
30
+ let pathSegment = (s: string): string => s->String.replaceRegExp(/[^A-Za-z0-9-]/g, "-")
32
31
 
33
32
  let clientChannelPrefix = "/client/"
34
33
 
@@ -172,7 +171,10 @@ let broadcastStateChange = (~name: string, ~descriptor: JSON.t): unit => {
172
171
  // -- Inbound frames (subscribe side) -----------------------------------------
173
172
 
174
173
  let decodeStringField = (json: JSON.t, field: string): option<string> =>
175
- json->JSON.Decode.object->Option.flatMap(o => o->Dict.get(field))->Option.flatMap(JSON.Decode.string)
174
+ json
175
+ ->JSON.Decode.object
176
+ ->Option.flatMap(o => o->Dict.get(field))
177
+ ->Option.flatMap(JSON.Decode.string)
176
178
 
177
179
  /** Handle one client→server text frame on an established connection. */
178
180
  let handleFrame = (conn: connection, text: string): unit => {
@@ -7,10 +7,10 @@
7
7
  type api = unit
8
8
  type role = unit
9
9
 
10
- let makeApiResource = (
11
- ~name as _: string,
12
- ~opts as _: Pulumi.ComponentResource.options,
13
- ): (Pulumi.Output.t<api>, Pulumi.Output.t<role>) => (Pulumi.Output.make(()), Pulumi.Output.make(()))
10
+ let makeApiResource = (~name as _: string, ~opts as _: Pulumi.ComponentResource.options): (
11
+ Pulumi.Output.t<api>,
12
+ Pulumi.Output.t<role>,
13
+ ) => (Pulumi.Output.make(), Pulumi.Output.make())
14
14
 
15
15
  let generateFragment = (
16
16
  ~mutationEntries: array<ReventlessInfra.Api.mutationSchemaEntry>,
@@ -33,8 +33,7 @@ let adminUser: Identity.t = {
33
33
  // A `dict<Identity.t>` keyed by `username`. A4 hydrates this from
34
34
  // `.reventless/users.yaml`; tests inject via `registerUser`.
35
35
 
36
- let initialUsers = () =>
37
- Dict.fromArray([("user", defaultUser), ("admin", adminUser)])
36
+ let initialUsers = () => Dict.fromArray([("user", defaultUser), ("admin", adminUser)])
38
37
 
39
38
  let users: ref<dict<Identity.t>> = ref(initialUsers())
40
39
 
@@ -43,8 +42,7 @@ let registerUser = (~username: string, ~identity: Identity.t): unit =>
43
42
 
44
43
  let resetUsers = (): unit => users := initialUsers()
45
44
 
46
- let lookupUser = (username: string): option<Identity.t> =>
47
- users.contents->Dict.get(username)
45
+ let lookupUser = (username: string): option<Identity.t> => users.contents->Dict.get(username)
48
46
 
49
47
  // ── Header parsing ────────────────────────────────────────────────────────
50
48
 
@@ -240,11 +238,10 @@ module Login = {
240
238
  `activeRole` narrows the minted token to one of the caller's own roles; unset
241
239
  mints exactly what it has always minted.
242
240
  */
243
- let issue = async (
244
- ~username: string,
245
- ~password: string,
246
- ~activeRole: option<string>=?,
247
- ): result<string, string> =>
241
+ let issue = async (~username: string, ~password: string, ~activeRole: option<string>=?): result<
242
+ string,
243
+ string,
244
+ > =>
248
245
  switch store.contents->Dict.get(username) {
249
246
  | Some({password: stored, identity}) if stored === password =>
250
247
  switch switch activeRole {
@@ -340,7 +337,6 @@ module Login = {
340
337
  }
341
338
  }
342
339
  }
343
-
344
340
  }
345
341
 
346
342
  // ── Provider implementation ───────────────────────────────────────────────
@@ -354,9 +350,7 @@ let _bearerToken = (header: string): option<string> =>
354
350
  None
355
351
  }
356
352
 
357
- let authenticate = async (
358
- ctx: ReventlessCore.Auth_Adapter.requestContext,
359
- ): Identity.authResult => {
353
+ let authenticate = async (ctx: ReventlessCore.Auth_Adapter.requestContext): Identity.authResult => {
360
354
  // Decoding order: Bearer (when signature valid) → X-User/X-Groups → default.
361
355
  // A *present* Bearer that fails verification is rejected (AuthError) rather
362
356
  // than falling through to defaultUser — otherwise a client whose token was
@@ -402,5 +396,7 @@ let authenticate = async (
402
396
  }
403
397
  }
404
398
 
405
- let make = (~name as _: string, ~opts as _: option<Pulumi.ComponentResource.options>=?): Pulumi.Output.t<authConfig> =>
406
- Pulumi.Output.make()
399
+ let make = (
400
+ ~name as _: string,
401
+ ~opts as _: option<Pulumi.ComponentResource.options>=?,
402
+ ): Pulumi.Output.t<authConfig> => Pulumi.Output.make()
@@ -83,11 +83,10 @@ let resolved: ref<bool> = ref(false)
83
83
 
84
84
  let resetResolution = (): unit => resolved := false
85
85
 
86
- let load = (
87
- ~users: option<array<entry>>=?,
88
- ~usersFile: option<string>=?,
89
- (),
90
- ): result<resolution, string> => {
86
+ let load = (~users: option<array<entry>>=?, ~usersFile: option<string>=?, ()): result<
87
+ resolution,
88
+ string,
89
+ > => {
91
90
  resolved := true
92
91
  switch users {
93
92
  | Some(entries) =>
@@ -109,8 +108,7 @@ let load = (
109
108
  })
110
109
  } else {
111
110
  Console.log(
112
- "[LocalAuth] no users configured — POST /__inmemory/login will reject all. " ++
113
- "Provide ~users / ~usersFile or create .reventless/users.yaml relative to cwd.",
111
+ "[LocalAuth] no users configured — POST /__inmemory/login will reject all. " ++ "Provide ~users / ~usersFile or create .reventless/users.yaml relative to cwd.",
114
112
  )
115
113
  Ok(Empty)
116
114
  }
@@ -30,11 +30,10 @@ let postgres = async (~connection, ~resetOnStart=false) => {
30
30
  }
31
31
  let initialCount =
32
32
  (await ReventlessPostgres.EventLogStorage_Postgres.countAll(pool)) +
33
- (await ReventlessPostgres.DcbEventLogStorage_Postgres.countAll(pool))
33
+ (await ReventlessPostgres.DcbEventLogStorage_Postgres.countAll(pool))
34
34
  Postgres({pool, initialCount, connection})
35
35
  }
36
36
 
37
-
38
37
  // Deletes a file if it exists. No-op if the path is missing.
39
38
 
40
39
  let removeFileIfExists = (path: string) =>
@@ -35,15 +35,14 @@ let extractIdentity = (ctx: JSON.t): Reventless.Identity.t => {
35
35
  // Returns a `CommandRejected` outcome with a fresh msgId so the GraphQL union
36
36
  // resolves consistently — matches the existing CommandResult contract.
37
37
 
38
- let rejectForbidden = (~field: string): JSON.t =>
39
- JSON.Object(
40
- Dict.fromArray([
41
- ("__typename", JSON.String("CommandRejected")),
42
- ("msgId", JSON.String(ReventlessCore.Message.uuid())),
43
- ("errorCode", JSON.String("Forbidden")),
44
- ("errorDetail", JSON.String(`Mutation.${field}: identity is not authorized`)),
45
- ]),
46
- )
38
+ let rejectForbidden = (~field: string): JSON.t => JSON.Object(
39
+ Dict.fromArray([
40
+ ("__typename", JSON.String("CommandRejected")),
41
+ ("msgId", JSON.String(ReventlessCore.Message.uuid())),
42
+ ("errorCode", JSON.String("Forbidden")),
43
+ ("errorDetail", JSON.String(`Mutation.${field}: identity is not authorized`)),
44
+ ]),
45
+ )
47
46
 
48
47
  // -- Plugin status gate -------------------------------------------------------
49
48
  // Set by the platform after Admin.construct to wire a per-mutation lookup against
@@ -61,15 +60,18 @@ let pluginStatusGate: ref<option<string => option<(string, string)>>> = ref(None
61
60
  let setPluginStatusGate = fn => pluginStatusGate := Some(fn)
62
61
  let resetPluginStatusGate = () => pluginStatusGate := None
63
62
 
64
- let rejectPluginStatus = (~field: string, ~errorCode: string, ~detail: string): JSON.t =>
65
- JSON.Object(
66
- Dict.fromArray([
67
- ("__typename", JSON.String("CommandRejected")),
68
- ("msgId", JSON.String(ReventlessCore.Message.uuid())),
69
- ("errorCode", JSON.String(errorCode)),
70
- ("errorDetail", JSON.String(`Mutation.${field}: ${detail}`)),
71
- ]),
72
- )
63
+ let rejectPluginStatus = (
64
+ ~field: string,
65
+ ~errorCode: string,
66
+ ~detail: string,
67
+ ): JSON.t => JSON.Object(
68
+ Dict.fromArray([
69
+ ("__typename", JSON.String("CommandRejected")),
70
+ ("msgId", JSON.String(ReventlessCore.Message.uuid())),
71
+ ("errorCode", JSON.String(errorCode)),
72
+ ("errorDetail", JSON.String(`Mutation.${field}: ${detail}`)),
73
+ ]),
74
+ )
73
75
 
74
76
  let checkPluginStatus = (~field: string): option<JSON.t> =>
75
77
  switch pluginStatusGate.contents {
@@ -92,8 +94,7 @@ let checkPluginStatus = (~field: string): option<JSON.t> =>
92
94
  let syntheticCommand = (cname: string, ~hasPayload: bool): unknown =>
93
95
  hasPayload ? {"TAG": cname}->Obj.magic : cname->Obj.magic
94
96
 
95
- let capitalize = s =>
96
- s->String.charAt(0)->String.toUpperCase ++ s->String.slice(~start=1)
97
+ let capitalize = s => s->String.charAt(0)->String.toUpperCase ++ s->String.slice(~start=1)
97
98
 
98
99
  // -- CommandResult SDL types --------------------------------------------------
99
100
  // Source of truth lives in GraphQL_FragmentGenerator.commandResultSdlTypes so
@@ -194,7 +195,10 @@ let register = (
194
195
  // Aggregate commands target a specific instance — prepend id: ID!
195
196
  let sdlFields = fields->Array.map(field => {
196
197
  let variantIndex = variantIndexForField(commandSchema, ~field)
197
- let sdl = deriveSdlField(~fieldName=field, extractVariantSchema(commandSchema, ~index=variantIndex))
198
+ let sdl = deriveSdlField(
199
+ ~fieldName=field,
200
+ extractVariantSchema(commandSchema, ~index=variantIndex),
201
+ )
198
202
  if sdl->String.includes("(") {
199
203
  sdl->String.replace(`${field}(`, `${field}(id: ID!, `)
200
204
  } else {
@@ -214,7 +218,11 @@ let register = (
214
218
  | _ => false
215
219
  }
216
220
  let commandName = extractCommandName(field)
217
- let resolver: ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn = async (_root, args, ctx) => {
221
+ let resolver: ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn = async (
222
+ _root,
223
+ args,
224
+ ctx,
225
+ ) => {
218
226
  switch handlerRef.contents {
219
227
  | Some(generateCommand) =>
220
228
  switch checkPluginStatus(~field) {
@@ -265,19 +273,27 @@ let registerDcb = (
265
273
  // non-first constructor of a multi-command slice.
266
274
  let constructorNames = Reventless.DcbTag.extractAllVariantNames(commandSchema->Obj.magic)
267
275
  let variantIndex = variantIndexForField(commandSchema, ~field=fieldName)
268
- let variantSchema = extractVariantSchema(commandSchema, ~index=variantIndex >= 0 ? variantIndex : 0)
276
+ let variantSchema = extractVariantSchema(
277
+ commandSchema,
278
+ ~index=variantIndex >= 0 ? variantIndex : 0,
279
+ )
269
280
  let sdlFields = [deriveSdlField(~fieldName, variantSchema)]
270
281
 
271
282
  // Extract TAG (variant constructor name) for routing
272
283
  let tag =
273
- (variantIndex >= 0 ? constructorNames->Array.get(variantIndex) : constructorNames->Array.get(0))
274
- ->Option.getOr(fieldName)
284
+ (
285
+ variantIndex >= 0 ? constructorNames->Array.get(variantIndex) : constructorNames->Array.get(0)
286
+ )->Option.getOr(fieldName)
275
287
  let hasPayload = Reventless.DcbTag.isVariantPayloadBearing(commandSchema->Obj.magic, tag)
276
288
 
277
289
  let handlerRef = ref(None)
278
290
  handlerRefs->Dict.set(fieldName, handlerRef)
279
291
 
280
- let resolver: ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn = async (_root, args, ctx) => {
292
+ let resolver: ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn = async (
293
+ _root,
294
+ args,
295
+ ctx,
296
+ ) => {
281
297
  switch handlerRef.contents {
282
298
  | Some(generateCommand) =>
283
299
  switch checkPluginStatus(~field=fieldName) {
@@ -25,7 +25,11 @@ let pendingQueueRegistry: dict<ref<array<pendingCall>>> = Dict.make()
25
25
  // Phase 1: Register SDL + resolver stub synchronously (before server starts).
26
26
  // Also pre-registers a queuing forwarder in receiveRegistry so callers can
27
27
  // invoke receive immediately; calls are parked until bindReceive drains them.
28
- let register = (~fieldName: string, ~externalInputSchema: S.t<unknown>, ~server: ReventlessGraphqlServer.GraphQL_ServerInstance.t) => {
28
+ let register = (
29
+ ~fieldName: string,
30
+ ~externalInputSchema: S.t<unknown>,
31
+ ~server: ReventlessGraphqlServer.GraphQL_ServerInstance.t,
32
+ ) => {
29
33
  // The mutation field returns CommandResult, so its union members must exist in
30
34
  // this scope's document. Registered here rather than relying on a plugin's
31
35
  // command handlers having registered them first — a plugin whose only mutation
@@ -53,11 +57,17 @@ let register = (~fieldName: string, ~externalInputSchema: S.t<unknown>, ~server:
53
57
  })
54
58
  receiveRegistry->Dict.set(fieldName, queuingReceive)
55
59
 
56
- let resolver: ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn = async (_root, args, _ctx) => {
60
+ let resolver: ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn = async (
61
+ _root,
62
+ args,
63
+ _ctx,
64
+ ) => {
57
65
  let inputJson: JSON.t = args->Obj.magic
58
66
  let receive = receiveRegistry->Dict.getUnsafe(fieldName)
59
67
  let result = await receive(inputJson)
60
- result->InboundTranslationSlice_Callback.receiveResultToOutcome->CommandTopic.commandOutcomeToJson
68
+ result
69
+ ->InboundTranslationSlice_Callback.receiveResultToOutcome
70
+ ->CommandTopic.commandOutcomeToJson
61
71
  }
62
72
 
63
73
  let resolvers = Dict.make()
@@ -32,17 +32,14 @@ module Make = (Bus: LocalBus.T) => {
32
32
  > = (~name, ~owner as _, ~opts as _=?) => {
33
33
  // Captured when handleChannelEvent is called; used by publishJsonsAndWait to
34
34
  // run the handler inline and collect typed outcomes without going through the bus.
35
- let handleCmdsRef: ref<
36
- option<ReventlessCore.CommandTopic.jsonCommandsHandler>,
37
- > = ref(None)
35
+ let handleCmdsRef: ref<option<ReventlessCore.CommandTopic.jsonCommandsHandler>> = ref(None)
38
36
 
39
37
  let publishJsons: ReventlessInfra.CommandTopic.publishJsons = async jsons => {
40
- let _ =
41
- await jsons
42
- ->Array.map(async (cmdJson: Reventless.Message.commandJson) => {
43
- await Bus.dispatchCommand(name, ReventlessCore.CommandTopic.encodeCommandJson(cmdJson))
44
- })
45
- ->Promise.all
38
+ let _ = await jsons
39
+ ->Array.map(async (cmdJson: Reventless.Message.commandJson) => {
40
+ await Bus.dispatchCommand(name, ReventlessCore.CommandTopic.encodeCommandJson(cmdJson))
41
+ })
42
+ ->Promise.all
46
43
  }
47
44
 
48
45
  let publishJsonsStream: ReventlessInfra.CommandTopic.publishJsonsStream = stream =>
@@ -55,18 +52,20 @@ module Make = (Bus: LocalBus.T) => {
55
52
  | None =>
56
53
  // Handler not yet registered — fall back to fire-and-forget, return Pending
57
54
  let _ = await publishJsons(jsons)
58
- jsons->Array.map(cmdJson =>
59
- ReventlessCore.CommandTopic.Pending({msgId: cmdJson.meta.msgId})
60
- )
61
- | Some(handleCmds) =>
62
- await ReventlessCore.CommandTopic.runInlineAndCollect(jsons, handleCmds)
55
+ jsons->Array.map(cmdJson => ReventlessCore.CommandTopic.Pending({
56
+ msgId: cmdJson.meta.msgId,
57
+ }))
58
+ | Some(handleCmds) => await ReventlessCore.CommandTopic.runInlineAndCollect(jsons, handleCmds)
63
59
  }
64
60
  }
65
61
 
66
62
  let handleChannelEvent = (
67
63
  handleCmds: ReventlessCore.CommandTopic.jsonCommandsHandler,
68
- ): Pulumi.Output.t<ReventlessCore.Runtime.effectHandler<callbackEvent, 'context, unit, string>> => {
64
+ ): Pulumi.Output.t<
65
+ ReventlessCore.Runtime.effectHandler<callbackEvent, 'context, unit, string>,
66
+ > => {
69
67
  handleCmdsRef.contents = Some(handleCmds)
68
+
70
69
  (
71
70
  (fullBody: JSON.t, _ctx) => {
72
71
  // Pass the full body as `command` — that's what handleJsonCommands decodes
@@ -84,8 +83,7 @@ module Make = (Bus: LocalBus.T) => {
84
83
  runtimeParts,
85
84
  > = (~name as _, ~channel, ~runtime, ~resources as _, ~opts as _) => {
86
85
  Bus.registerCommandHandler(channel.parts.name, async (json, ctx) => {
87
- let handler =
88
- await runtime.parts.handlerDeferred->Deferred.await_->Effect.runPromise
86
+ let handler = await runtime.parts.handlerDeferred->Deferred.await_->Effect.runPromise
89
87
  await handler(json, ctx)
90
88
  })
91
89
  []
@@ -5,28 +5,24 @@ module Make = (Bus: LocalBus.T) => {
5
5
  let make: ReventlessCore.CommandTopic_Adapter.remoteChannelMaker = resources => {
6
6
  resources,
7
7
  remotePublish: async jsons => {
8
- let _ =
9
- await jsons
10
- ->Array.map(async (cmdJson: Reventless.Message.commandJson) => {
11
- // Encode the same way LocalCommandTopicChannel does
12
- let body = JSON.Encode.object(
13
- Dict.fromArray([
14
- ("id", JSON.Encode.string(cmdJson.id)),
15
- (
16
- "meta",
17
- cmdJson.meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema),
18
- ),
19
- ("command", cmdJson.commandJson),
20
- ]),
21
- )
22
- // Dispatch to the first resource's name (the channel name)
23
- let channelName = switch resources {
24
- | [] => ""
25
- | resources => (resources->Array.getUnsafe(0)).name
26
- }
27
- await Bus.dispatchCommand(channelName, body)
28
- })
29
- ->Promise.all
8
+ let _ = await jsons
9
+ ->Array.map(async (cmdJson: Reventless.Message.commandJson) => {
10
+ // Encode the same way LocalCommandTopicChannel does
11
+ let body = JSON.Encode.object(
12
+ Dict.fromArray([
13
+ ("id", JSON.Encode.string(cmdJson.id)),
14
+ ("meta", cmdJson.meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema)),
15
+ ("command", cmdJson.commandJson),
16
+ ]),
17
+ )
18
+ // Dispatch to the first resource's name (the channel name)
19
+ let channelName = switch resources {
20
+ | [] => ""
21
+ | resources => (resources->Array.getUnsafe(0)).name
22
+ }
23
+ await Bus.dispatchCommand(channelName, body)
24
+ })
25
+ ->Promise.all
30
26
  },
31
27
  }
32
28
  }
@@ -20,7 +20,7 @@ let make: Counter_Adapter.handlerMaker = (
20
20
  ~publishChannelId as _,
21
21
  ~opts as _,
22
22
  ) => {
23
- addToCounterTarget: async ({ReventlessInfra.Counter.counterId, target, targetRef}) => {
23
+ addToCounterTarget: async ({ReventlessInfra.Counter.counterId: counterId, target, targetRef}) => {
24
24
  let refKey = counterId ++ ":" ++ targetRef
25
25
  switch targetRefStore.contents->Dict.get(refKey) {
26
26
  | Some(_) => () // Already counted this (counterId, targetRef) pair — skip