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

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 (174) hide show
  1. package/CHANGELOG.md +30 -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 +12 -16
  15. package/src/adapter/Auth/LocalAuth.res.mjs +2 -1
  16. package/src/adapter/Auth/UserStore.res +13 -40
  17. package/src/adapter/Auth/UserStore.res.mjs +11 -67
  18. package/src/adapter/Backend.res +1 -2
  19. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +42 -26
  20. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +13 -3
  21. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +15 -17
  22. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +18 -22
  23. package/src/adapter/Counter/LocalCounterHandler.res +1 -1
  24. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +33 -22
  25. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +57 -57
  26. package/src/adapter/DomainGraphQL_Server.res +35 -34
  27. package/src/adapter/DomainMCP_Server.res +45 -41
  28. package/src/adapter/EventCollector/LocalEventCollectorChannel.res +47 -36
  29. package/src/adapter/EventHistory/EventHistoryResolvers_GraphQL.res +15 -12
  30. package/src/adapter/EventLog/EventLogStorage_InMemory.res +9 -4
  31. package/src/adapter/EventLog/EventLogStorage_Sqlite.res +36 -24
  32. package/src/adapter/EventTopic/LocalEventTopicPublisher.res +9 -3
  33. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +9 -14
  34. package/src/adapter/LocalBus.res +12 -12
  35. package/src/adapter/LocalCapabilities.res +6 -0
  36. package/src/adapter/LocalCapabilities.res.mjs +5 -2
  37. package/src/adapter/LocalGeocodeResolvers.res +1 -4
  38. package/src/adapter/LocalSideEffectHandler.res +1 -1
  39. package/src/adapter/LocalStateChangeDescriptor.res +2 -1
  40. package/src/adapter/MCP_ServerInstance.res +51 -39
  41. package/src/adapter/ObjectStore/LocalObjectStore.res +5 -2
  42. package/src/adapter/ObjectStore/ObjectStoreStorage_FileSystem.res +1 -2
  43. package/src/adapter/PlatformGraphQL_Server.res +10 -6
  44. package/src/adapter/PlatformGraphQL_Server.res.mjs +2 -1
  45. package/src/adapter/ProjectionCheckpoint.res +8 -1
  46. package/src/adapter/ProjectionPending.res +1 -3
  47. package/src/adapter/QueryDb/LocalQueryDbStorage.res +2 -1
  48. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +367 -269
  49. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +5 -3
  50. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +63 -40
  51. package/src/adapter/QueryDb/SortKey_Filter.res +14 -6
  52. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +12 -10
  53. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +8 -2
  54. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +1 -4
  55. package/src/adapter/Scheduler/LocalScheduledPublisher.res +12 -12
  56. package/src/adapter/SqliteDriver.res +16 -4
  57. package/src/adapter/Task/TaskBucket_Sqlite.res +5 -6
  58. package/src/components/Aggregate_Builder.res +6 -1
  59. package/src/components/Counter_Builder.res +1 -5
  60. package/src/components/DcbEventLog_Builder.res +5 -3
  61. package/src/components/ExtensionPoint_Builder.res +13 -15
  62. package/src/components/InboundTranslationSlice_Builder.res +3 -2
  63. package/src/components/OutboundTranslationSlice_Builder.res +3 -2
  64. package/src/components/ReadModel_Builder.res +18 -20
  65. package/src/components/StateViewSlice_Builder.res +3 -2
  66. package/src/components/Task_Builder.res +12 -13
  67. package/src/reset/LocalSeedReset.res +2 -5
  68. package/src/test/Mocks/MockDcbEventLogStorage.res +5 -1
  69. package/src/test/Mocks/MockEventLogStorage.res +8 -3
  70. package/src/test/Mocks/MockQueryDbStorage.res +3 -2
  71. package/src/test/TestRunner.res +1 -1
  72. package/tests/BakedManifestFilesTest.res +7 -10
  73. package/tests/LocalEventTapTest.res +26 -21
  74. package/tests/LocalPlatformStartTest.res +33 -28
  75. package/tests/PluginEventDecodeTest.res +3 -3
  76. package/tests/ShellConfigTest.res +30 -21
  77. package/tests/SplitApiFixtures.res +34 -10
  78. package/tests/SplitApiTest.res +92 -62
  79. package/tests/adapter/BackendParityTest.res +180 -130
  80. package/tests/adapter/CollectNEventsTest.res +6 -4
  81. package/tests/adapter/CommandAuthorizationTest.res +47 -41
  82. package/tests/adapter/CommandTopicChannelTest.res +163 -139
  83. package/tests/adapter/CounterHandlerTest.res +95 -77
  84. package/tests/adapter/DcbEventLogStorageSqliteTest.res +171 -168
  85. package/tests/adapter/DcbEventLogStorageTest.res +264 -207
  86. package/tests/adapter/DomainGraphQL_ServerTest.res +53 -43
  87. package/tests/adapter/EventCollectorChannelTest.res +153 -124
  88. package/tests/adapter/EventHistoryResolverTest.res +46 -18
  89. package/tests/adapter/EventLogSnapshotParityTest.res +57 -45
  90. package/tests/adapter/EventLogStorageSqliteTest.res +9 -10
  91. package/tests/adapter/EventTapTest.res +37 -20
  92. package/tests/adapter/EventTopicPublisherTest.res +74 -50
  93. package/tests/adapter/GraphQLSubscriptionBridgeTest.res +4 -3
  94. package/tests/adapter/GraphQL_SchemaInspectorTest.res +666 -568
  95. package/tests/adapter/GraphQL_SubscriptionResolversTest.res +105 -96
  96. package/tests/adapter/HeartbeatRunnerTest.res +99 -81
  97. package/tests/adapter/InboundTranslationMutationTest.res +4 -1
  98. package/tests/adapter/LocalAuthHttpTest.res +79 -85
  99. package/tests/adapter/LocalAuthLoginTest.res +42 -50
  100. package/tests/adapter/LocalAuthTest.res +8 -16
  101. package/tests/adapter/LocalAuthUserStoreTest.res +2 -7
  102. package/tests/adapter/LocalBusBoundedTest.res +187 -117
  103. package/tests/adapter/LocalBusPubSubTest.res +118 -76
  104. package/tests/adapter/LocalDispatchContextTest.res +1 -2
  105. package/tests/adapter/LocalEvents_ServerTest.res +242 -187
  106. package/tests/adapter/PgProjectionCatchupTest.res +44 -10
  107. package/tests/adapter/ProjectionCheckpointTest.res +261 -206
  108. package/tests/adapter/QueryDbGsiTtlTest.res +123 -83
  109. package/tests/adapter/QueryDbListPushdownParityTest.res +107 -67
  110. package/tests/adapter/QueryDbListResolverTest.res +225 -208
  111. package/tests/adapter/QueryDbResolvedFieldsTest.res +17 -14
  112. package/tests/adapter/QueryDbStorageSqliteTest.res +33 -49
  113. package/tests/adapter/QueryDbStorageTest.res +163 -117
  114. package/tests/adapter/QueryDbUnionRoundTripTest.res +8 -10
  115. package/tests/adapter/QueryEngineTest.res +179 -126
  116. package/tests/adapter/ScheduledPublisherTest.res +171 -135
  117. package/tests/adapter/ServedBucketHttpTest.res +65 -59
  118. package/tests/adapter/SortKey_FilterTest.res +19 -3
  119. package/tests/adapter/SqliteDriverTest.res +13 -10
  120. package/tests/adapter/TaskBucketTest.res +94 -80
  121. package/tests/components/aggregate/AggregateTest.res +31 -18
  122. package/tests/components/automationslice/AutomationSliceCallbackTest.res +259 -222
  123. package/tests/components/automationslice/AutomationSliceFixtures.res +4 -2
  124. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +38 -38
  125. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +12 -14
  126. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +8 -32
  127. package/tests/components/commandgenerator/CommandGeneratorFixtures.res +7 -5
  128. package/tests/components/commandgenerator/CommandGeneratorTest.res +40 -31
  129. package/tests/components/commandtopic/CommandTopicFixtures.res +3 -4
  130. package/tests/components/commandtopic/CommandTopicStreamFixtures.res +7 -5
  131. package/tests/components/commandtopic/CommandTopicTest.res +24 -15
  132. package/tests/components/counter/CounterFixtures.res +6 -8
  133. package/tests/components/dcb/DcbCrossPartitionFixtures.res +8 -2
  134. package/tests/components/dcb/DcbCrossPartitionReadTest.res +20 -13
  135. package/tests/components/dcb/DcbEventLogAppendStreamTest.res +12 -8
  136. package/tests/components/dcb/DcbEventLogStreamTest.res +88 -61
  137. package/tests/components/dcb/DcbFixtures.res +4 -1
  138. package/tests/components/dcb/DcbTest.res +9 -6
  139. package/tests/components/eventcollector/EventCollectorFixtures.res +0 -1
  140. package/tests/components/eventcollector/EventCollectorTest.res +6 -3
  141. package/tests/components/eventlog/EventLogAppendStreamTest.res +88 -68
  142. package/tests/components/eventlog/EventLogConflictTest.res +8 -4
  143. package/tests/components/eventlog/EventLogFixtures.res +3 -3
  144. package/tests/components/eventlog/EventLogProvisioningSeamTest.res +26 -13
  145. package/tests/components/eventlog/EventLogStreamTest.res +119 -56
  146. package/tests/components/eventlog/EventLogTest.res +20 -4
  147. package/tests/components/eventtopic/EventTopicFixtures.res +3 -3
  148. package/tests/components/eventtopic/EventTopicStreamFixtures.res +1 -2
  149. package/tests/components/eventtopic/EventTopicStreamTest.res +7 -1
  150. package/tests/components/extensionpoint/ExtensionPointFixtures.res +14 -9
  151. package/tests/components/extensionpoint/ExtensionPointTest.res +3 -2
  152. package/tests/components/heartbeat/HeartbeatFixtures.res +5 -6
  153. package/tests/components/heartbeat/HeartbeatTest.res +56 -47
  154. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +271 -249
  155. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +3 -2
  156. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +361 -276
  157. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +8 -10
  158. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +37 -43
  159. package/tests/components/querydb/QueryDbFixtures.res +1 -5
  160. package/tests/components/querydb/QueryDbTest.res +2 -4
  161. package/tests/components/readmodel/DcbReadModelE2EFixtures.res +15 -18
  162. package/tests/components/readmodel/MixedSourceReadModelFixtures.res +5 -7
  163. package/tests/components/readmodel/ReadModelFixtures.res +8 -8
  164. package/tests/components/scheduler/SchedulerTest.res +76 -58
  165. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +4 -4
  166. package/tests/components/stateviewslice/StateViewSliceDisplayNameFixtures.res +5 -7
  167. package/tests/components/stateviewslice/StateViewSliceFixtures.res +8 -6
  168. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +17 -11
  169. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +12 -2
  170. package/tests/components/task/TaskFixtures.res +5 -5
  171. package/tests/components/task/TaskTest.res +95 -80
  172. package/tests/plugin/PluginsProjection_GWT.res +3 -1
  173. package/tests/plugin/UiFragments_GWT.res +6 -1
  174. package/tests/reset/LocalSeedResetTest.res +1 -0
@@ -21,8 +21,7 @@ module SendTrackingEmailSpec = {
21
21
  let moduleUrl: string = %raw(`import.meta.url`)
22
22
 
23
23
  @schema
24
- type consumedEvent =
25
- | OrderShipped({orderId: string, email: string})
24
+ type consumedEvent = OrderShipped({orderId: string, email: string})
26
25
 
27
26
  @schema
28
27
  type outboundItem = {orderId: string, email: string}
@@ -56,8 +55,7 @@ module ProcessPaymentSpec = {
56
55
  let moduleUrl: string = %raw(`import.meta.url`)
57
56
 
58
57
  @schema
59
- type consumedEvent =
60
- | PaymentReceived({orderId: string, amount: float})
58
+ type consumedEvent = PaymentReceived({orderId: string, amount: float})
61
59
 
62
60
  @schema
63
61
  type outboundItem = {orderId: string, amount: float}
@@ -71,9 +69,9 @@ module ProcessPaymentSpec = {
71
69
  }
72
70
 
73
71
  // Simulate calling external payment gateway, then return a command
74
- let translateFn: ref<(string, outboundItem) => promise<result<option<(string, inboundCommand)>, string>>> = ref(
75
- async (id, _item) => Ok(Some((id, ConfirmPayment({orderId: id}))))
76
- )
72
+ let translateFn: ref<
73
+ (string, outboundItem) => promise<result<option<(string, inboundCommand)>, string>>,
74
+ > = ref(async (id, _item) => Ok(Some((id, ConfirmPayment({orderId: id})))))
77
75
 
78
76
  // The mock stays two-arg: a test that wants to vary behaviour varies it on
79
77
  // the item, and threading capabilities into every fixture would make each
@@ -82,9 +80,9 @@ module ProcessPaymentSpec = {
82
80
 
83
81
  // Overridable like `translateFn`, so a test can assert both answers a slice may
84
82
  // give when its budget runs out: say nothing, or tell the domain.
85
- let onExhaustedFn: ref<(string, outboundItem, option<string>) => option<(string, inboundCommand)>> = ref(
86
- (_id, _item, _lastError) => None
87
- )
83
+ let onExhaustedFn: ref<
84
+ (string, outboundItem, option<string>) => option<(string, inboundCommand)>,
85
+ > = ref((_id, _item, _lastError) => None)
88
86
  let onExhausted = (id, item, ~lastError) => onExhaustedFn.contents(id, item, lastError)
89
87
 
90
88
  let maxRetries = 2
@@ -25,19 +25,13 @@ module PlaceSpec = {
25
25
  let moduleUrl: string = %raw(`import.meta.url`)
26
26
 
27
27
  @schema
28
- type event = Placed({
29
- orderId: @s.matches(Reventless.DcbTag.string) string,
30
- customerId: string,
31
- })
28
+ type event = Placed({orderId: @s.matches(Reventless.DcbTag.string) string, customerId: string})
32
29
 
33
30
  @schema
34
31
  type consumedEvent = Placed
35
32
 
36
33
  @schema
37
- type command = Place({
38
- orderId: @s.matches(Reventless.DcbTag.string) string,
39
- customerId: string,
40
- })
34
+ type command = Place({orderId: @s.matches(Reventless.DcbTag.string) string, customerId: string})
41
35
 
42
36
  @schema
43
37
  type error = AlreadyPlaced
@@ -137,42 +131,40 @@ let dcbEventLog = DcbLogMaker.make(
137
131
  // ─────────────────────────────────────────────────────────────
138
132
 
139
133
  let publishJsons: ReventlessInfra.CommandTopic.publishJsons = async cmdJsons => {
140
- let _ =
141
- await cmdJsons
142
- ->Array.map(async cmdJson => {
143
- let typeName = switch cmdJson.commandJson {
144
- | JSON.Object(dict) =>
145
- dict
146
- ->Dict.get("TAG")
147
- ->Option.flatMap(j =>
148
- switch j {
149
- | JSON.String(s) => Some(s)
150
- | _ => None
151
- }
152
- )
153
- ->Option.getOr("")
154
- | _ => ""
155
- }
156
- let fullBody = JSON.Encode.object(
157
- Dict.fromArray([
158
- ("id", JSON.Encode.string(cmdJson.id)),
159
- ("meta", cmdJson.meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema)),
160
- ("command", cmdJson.commandJson),
161
- ]),
134
+ let _ = await cmdJsons
135
+ ->Array.map(async cmdJson => {
136
+ let typeName = switch cmdJson.commandJson {
137
+ | JSON.Object(dict) =>
138
+ dict
139
+ ->Dict.get("TAG")
140
+ ->Option.flatMap(j =>
141
+ switch j {
142
+ | JSON.String(s) => Some(s)
143
+ | _ => None
144
+ }
162
145
  )
163
- let handlers = ReventlessCore.CommandTopic.getHandlers(typeName)
164
- let _ =
165
- await handlers
166
- ->Array.map(async entry => {
167
- let item: ReventlessInfra.CommandTopic.topicItem<JSON.t> = {
168
- reference: cmdJson.id,
169
- command: fullBody,
170
- }
171
- let _ = await entry.handler(Stream.fromIterable([item]))->Effect.runPromise
172
- })
173
- ->Promise.all
146
+ ->Option.getOr("")
147
+ | _ => ""
148
+ }
149
+ let fullBody = JSON.Encode.object(
150
+ Dict.fromArray([
151
+ ("id", JSON.Encode.string(cmdJson.id)),
152
+ ("meta", cmdJson.meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema)),
153
+ ("command", cmdJson.commandJson),
154
+ ]),
155
+ )
156
+ let handlers = ReventlessCore.CommandTopic.getHandlers(typeName)
157
+ let _ = await handlers
158
+ ->Array.map(async entry => {
159
+ let item: ReventlessInfra.CommandTopic.topicItem<JSON.t> = {
160
+ reference: cmdJson.id,
161
+ command: fullBody,
162
+ }
163
+ let _ = await entry.handler(Stream.fromIterable([item]))->Effect.runPromise
174
164
  })
175
165
  ->Promise.all
166
+ })
167
+ ->Promise.all
176
168
  }
177
169
 
178
170
  let publishJsonsOutput = publishJsons->Pulumi.Output.make
@@ -199,8 +191,10 @@ let sendConfirmSlice = SendConfirm.make(~dcbEventLog, ~publishJsons=publishJsons
199
191
  let placeCmdJson = (orderId: string): Reventless.Message.commandJson => {
200
192
  id: orderId,
201
193
  meta: testMeta,
202
- commandJson: PlaceSpec.Place({orderId, customerId: "cust-" ++ orderId})
203
- ->Reventless.Util_Sury.toJson(PlaceSpec.commandSchema),
194
+ commandJson: PlaceSpec.Place({
195
+ orderId,
196
+ customerId: "cust-" ++ orderId,
197
+ })->Reventless.Util_Sury.toJson(PlaceSpec.commandSchema),
204
198
  }
205
199
 
206
200
  let readEventTypes = async (orderId: string) => {
@@ -30,10 +30,6 @@ let _ = TestRunner.setup()
30
30
 
31
31
  module QDbStorage = LocalQueryDbStorage.Make(Bus)
32
32
  module QDbResolvers = ReventlessCore.QueryDb_Adapter.NoResolvers(QDbStorage)
33
- module QueryDbMaker = ReventlessCore.QueryDb_Builder.Make(
34
- ItemQueryDbSpec,
35
- QDbStorage,
36
- QDbResolvers,
37
- )
33
+ module QueryDbMaker = ReventlessCore.QueryDb_Builder.Make(ItemQueryDbSpec, QDbStorage, QDbResolvers)
38
34
 
39
35
  let queryDb = QueryDbMaker.make(~api=(), ~apiRole=())
@@ -59,8 +59,7 @@ describe("QueryDb (in-memory)", () => {
59
59
  testPromise("loadStream emits saved states", async () => {
60
60
  let ops = await queryDb->ReventlessCore.Component.operations->TestRunner.resolve
61
61
  let _ = await ops.save("stream-item", {name: "Streamed", count: 42}, Init, None)
62
- let arr =
63
- await ops.loadStream("stream-item")->Stream.runCollect->Effect.runPromise
62
+ let arr = await ops.loadStream("stream-item")->Stream.runCollect->Effect.runPromise
64
63
  expect(arr->Array.length)->toBe(1)
65
64
  let s = arr->Array.getUnsafe(0)
66
65
  expect((s.name, s.count))->toEqual(("Streamed", 42))
@@ -68,8 +67,7 @@ describe("QueryDb (in-memory)", () => {
68
67
 
69
68
  testPromise("loadStream returns empty for unknown id", async () => {
70
69
  let ops = await queryDb->ReventlessCore.Component.operations->TestRunner.resolve
71
- let arr =
72
- await ops.loadStream("no-such-id")->Stream.runCollect->Effect.runPromise
70
+ let arr = await ops.loadStream("no-such-id")->Stream.runCollect->Effect.runPromise
73
71
  expect(arr->Array.length)->toBe(0)
74
72
  })
75
73
 
@@ -21,20 +21,13 @@ module AddProductSpec = {
21
21
  let moduleUrl: string = %raw(`import.meta.url`)
22
22
 
23
23
  @schema
24
- type event =
25
- ProductAdded({
26
- productId: @s.matches(Reventless.DcbTag.string) string,
27
- name: string,
28
- })
24
+ type event = ProductAdded({productId: @s.matches(Reventless.DcbTag.string) string, name: string})
29
25
 
30
26
  @schema
31
27
  type consumedEvent = ProductAdded
32
28
 
33
29
  @schema
34
- type command = AddProduct({
35
- productId: @s.matches(Reventless.DcbTag.string) string,
36
- name: string,
37
- })
30
+ type command = AddProduct({productId: @s.matches(Reventless.DcbTag.string) string, name: string})
38
31
 
39
32
  @schema
40
33
  type error = ProductAlreadyExists
@@ -180,7 +173,9 @@ let _addProductSlice = AddProductMaker.make(~dcbEventLog, ~publishJsons=publishJ
180
173
  // under the key `<name> ++ "DcbEventLog"`.
181
174
  // ─────────────────────────────────────────────────────────────
182
175
 
183
- let dcbTopicOutputs: ReventlessInfra.EventTopic.outputs = (dcbEventLog->ReventlessInfra.Component.outputs).eventTopic
176
+ let dcbTopicOutputs: ReventlessInfra.EventTopic.outputs = (
177
+ dcbEventLog->ReventlessInfra.Component.outputs
178
+ ).eventTopic
184
179
 
185
180
  let allEventTopics: ReventlessInfra.EventTopic.allOutputs = Dict.fromArray([
186
181
  ("ProductCatalogDcbEventLog", dcbTopicOutputs),
@@ -198,18 +193,20 @@ let dispatch = async (commandJson, id) =>
198
193
  await publishJsons([{Reventless.Message.id, meta: testMeta, commandJson}])
199
194
 
200
195
  let addProductCmd = (productId, name) =>
201
- AddProductSpec.AddProduct({productId, name})
202
- ->Reventless.Util_Sury.toJson(AddProductSpec.commandSchema)
196
+ AddProductSpec.AddProduct({productId, name})->Reventless.Util_Sury.toJson(
197
+ AddProductSpec.commandSchema,
198
+ )
203
199
 
204
200
  let loadState = async productId => {
205
201
  switch Bus.getQueryDb("TestProductsReadModel") {
206
202
  | None => []
207
203
  | Some(ops) =>
208
- let states =
209
- await ops.loadStream(productId)
210
- ->Stream.runCollect
211
- ->Effect.catchAll(_ => Effect.succeed([]))
212
- ->Effect.runPromise
213
- states->Array.map(json => json->Reventless.Util_Sury.fromJson(ProductsReadModelSpec.stateSchema))
204
+ let states = await ops.loadStream(productId)
205
+ ->Stream.runCollect
206
+ ->Effect.catchAll(_ => Effect.succeed([]))
207
+ ->Effect.runPromise
208
+ states->Array.map(json =>
209
+ json->Reventless.Util_Sury.fromJson(ProductsReadModelSpec.stateSchema)
210
+ )
214
211
  }
215
212
  }
@@ -80,8 +80,7 @@ module DcbMapping = Mapping.Make(
80
80
  {
81
81
  let project = (msg: Message.event'<string, DcbSource.event>) =>
82
82
  switch msg.event {
83
- | DcbItemAdded({name}) =>
84
- Create(msg.id, ({name, source: "dcb"}: MixedReadModelSpec.state))
83
+ | DcbItemAdded({name}) => Create(msg.id, ({name, source: "dcb"}: MixedReadModelSpec.state))
85
84
  | DcbItemNameChanged({name}) => Update(msg.id, state => {...state, name})
86
85
  }
87
86
  },
@@ -171,11 +170,10 @@ let loadState = async id => {
171
170
  switch Bus.getQueryDb("TestMixedReadModel") {
172
171
  | None => []
173
172
  | Some(ops) =>
174
- let states =
175
- await ops.loadStream(id)
176
- ->Stream.runCollect
177
- ->Effect.catchAll(_ => Effect.succeed([]))
178
- ->Effect.runPromise
173
+ let states = await ops.loadStream(id)
174
+ ->Stream.runCollect
175
+ ->Effect.catchAll(_ => Effect.succeed([]))
176
+ ->Effect.runPromise
179
177
  states->Array.map(json => json->Reventless.Util_Sury.fromJson(MixedReadModelSpec.stateSchema))
180
178
  }
181
179
  }
@@ -32,7 +32,7 @@ module ItemEventSource = {
32
32
  let name = "TestItemEventTopic" // must match allEventTopics key AND meta.service in published events
33
33
 
34
34
  @schema
35
- type event = | ItemCreated({name: string})
35
+ type event = ItemCreated({name: string})
36
36
  }
37
37
 
38
38
  // ─────────────────────────────────────────────────────────────
@@ -114,8 +114,9 @@ let publishItemCreated = async (id, name) => {
114
114
  ("meta", testMeta->Reventless.Util_Sury.toJson(Message.metaSchema)),
115
115
  (
116
116
  "event",
117
- ItemEventSource.ItemCreated({name: name})
118
- ->Reventless.Util_Sury.toJson(ItemEventSource.eventSchema),
117
+ ItemEventSource.ItemCreated({name: name})->Reventless.Util_Sury.toJson(
118
+ ItemEventSource.eventSchema,
119
+ ),
119
120
  ),
120
121
  ]),
121
122
  )
@@ -128,11 +129,10 @@ let loadState = async id => {
128
129
  switch Bus.getQueryDb("TestItemReadModel") {
129
130
  | None => []
130
131
  | Some(ops) =>
131
- let states =
132
- await ops.loadStream(id)
133
- ->Stream.runCollect
134
- ->Effect.catchAll(_ => Effect.succeed([]))
135
- ->Effect.runPromise
132
+ let states = await ops.loadStream(id)
133
+ ->Stream.runCollect
134
+ ->Effect.catchAll(_ => Effect.succeed([]))
135
+ ->Effect.runPromise
136
136
  states->Array.map(json => json->Reventless.Util_Sury.fromJson(ItemReadModelSpec.stateSchema))
137
137
  }
138
138
  }
@@ -10,67 +10,85 @@ describe("Scheduler_Builder.Make:", () => {
10
10
  let _ = afterEach(() => SP.reset())
11
11
 
12
12
  describe("createSchedule:", () => {
13
- testPromise("recurring schedule fires event on each interval advance", async () => {
14
- let ops = schedulerOps.contents->Option.getUnsafe
15
- let count = ref(0)
16
- Bus.subscribeToEvents("sched-recurring", async (_, _, _) => {
17
- count := count.contents + 1
18
- })
19
- // createSchedule async body has no await — setInterval registered synchronously
20
- let _ = ops.createSchedule(
21
- [makeTopicResource("sched-recurring")],
22
- {name: "test-recurring", rate: Reventless.Schedule.Minutes(1), payload: "{}"},
23
- )
24
- // Two microtask ticks: publishEvent uses Effect.all(concurrency=unbounded) which forks
25
- // child fibers via startFork — one tick runs the child fiber (Queue.offer),
26
- // a second tick runs the drain fiber callback.
27
- jest->advanceTimersByTime(60 * 1000)
28
- let _ = await Promise.resolve(())
29
- let _ = await Promise.resolve(())
30
- expect(count.contents)->toBe(1)
31
- jest->advanceTimersByTime(60 * 1000)
32
- let _ = await Promise.resolve(())
33
- let _ = await Promise.resolve(())
34
- expect(count.contents)->toBe(2)
35
- })
13
+ testPromise(
14
+ "recurring schedule fires event on each interval advance",
15
+ async () => {
16
+ let ops = schedulerOps.contents->Option.getUnsafe
17
+ let count = ref(0)
18
+ Bus.subscribeToEvents(
19
+ "sched-recurring",
20
+ async (_, _, _) => {
21
+ count := count.contents + 1
22
+ },
23
+ )
24
+ // createSchedule async body has no await setInterval registered synchronously
25
+ let _ = ops.createSchedule(
26
+ [makeTopicResource("sched-recurring")],
27
+ {name: "test-recurring", rate: Reventless.Schedule.Minutes(1), payload: "{}"},
28
+ )
29
+ // Two microtask ticks: publishEvent uses Effect.all(concurrency=unbounded) which forks
30
+ // child fibers via startFork — one tick runs the child fiber (Queue.offer),
31
+ // a second tick runs the drain fiber callback.
32
+ jest->advanceTimersByTime(60 * 1000)
33
+ let _ = await Promise.resolve()
34
+ let _ = await Promise.resolve()
35
+ expect(count.contents)->toBe(1)
36
+ jest->advanceTimersByTime(60 * 1000)
37
+ let _ = await Promise.resolve()
38
+ let _ = await Promise.resolve()
39
+ expect(count.contents)->toBe(2)
40
+ },
41
+ )
36
42
 
37
- testPromise("single-shot schedule fires once then stops", async () => {
38
- let ops = schedulerOps.contents->Option.getUnsafe
39
- let count = ref(0)
40
- Bus.subscribeToEvents("sched-single", async (_, _, _) => {
41
- count := count.contents + 1
42
- })
43
- let _ = ops.createSchedule(
44
- [makeTopicResource("sched-single")],
45
- {
46
- name: "test-single",
47
- rate: Reventless.Schedule.Single(2024, 1, 1, 0, 0),
48
- payload: "{}",
49
- },
50
- )
51
- jest->advanceTimersByTime(0)
52
- let _ = await Promise.resolve(())
53
- let _ = await Promise.resolve(())
54
- expect(count.contents)->toBe(1)
55
- jest->advanceTimersByTime(60 * 1000)
56
- expect(count.contents)->toBe(1) // No further firing
57
- })
43
+ testPromise(
44
+ "single-shot schedule fires once then stops",
45
+ async () => {
46
+ let ops = schedulerOps.contents->Option.getUnsafe
47
+ let count = ref(0)
48
+ Bus.subscribeToEvents(
49
+ "sched-single",
50
+ async (_, _, _) => {
51
+ count := count.contents + 1
52
+ },
53
+ )
54
+ let _ = ops.createSchedule(
55
+ [makeTopicResource("sched-single")],
56
+ {
57
+ name: "test-single",
58
+ rate: Reventless.Schedule.Single(2024, 1, 1, 0, 0),
59
+ payload: "{}",
60
+ },
61
+ )
62
+ jest->advanceTimersByTime(0)
63
+ let _ = await Promise.resolve()
64
+ let _ = await Promise.resolve()
65
+ expect(count.contents)->toBe(1)
66
+ jest->advanceTimersByTime(60 * 1000)
67
+ expect(count.contents)->toBe(1) // No further firing
68
+ },
69
+ )
58
70
  })
59
71
 
60
72
  describe("deleteSchedule:", () => {
61
- testPromise("deleted schedule does not fire after deletion", async () => {
62
- let ops = schedulerOps.contents->Option.getUnsafe
63
- let count = ref(0)
64
- Bus.subscribeToEvents("sched-delete", async (_, _, _) => {
65
- count := count.contents + 1
66
- })
67
- let _ = ops.createSchedule(
68
- [makeTopicResource("sched-delete")],
69
- {name: "test-delete", rate: Reventless.Schedule.Minutes(2), payload: "{}"},
70
- )
71
- let _ = ops.deleteSchedule([], "test-delete")
72
- jest->advanceTimersByTime(2 * 60 * 1000)
73
- expect(count.contents)->toBe(0)
74
- })
73
+ testPromise(
74
+ "deleted schedule does not fire after deletion",
75
+ async () => {
76
+ let ops = schedulerOps.contents->Option.getUnsafe
77
+ let count = ref(0)
78
+ Bus.subscribeToEvents(
79
+ "sched-delete",
80
+ async (_, _, _) => {
81
+ count := count.contents + 1
82
+ },
83
+ )
84
+ let _ = ops.createSchedule(
85
+ [makeTopicResource("sched-delete")],
86
+ {name: "test-delete", rate: Reventless.Schedule.Minutes(2), payload: "{}"},
87
+ )
88
+ let _ = ops.deleteSchedule([], "test-delete")
89
+ jest->advanceTimersByTime(2 * 60 * 1000)
90
+ expect(count.contents)->toBe(0)
91
+ },
92
+ )
75
93
  })
76
94
  })
@@ -3,7 +3,6 @@
3
3
 
4
4
  open TestFixtures
5
5
 
6
-
7
6
  // ─────────────────────────────────────────────────────────────
8
7
  // Isolated bus + Pulumi mock mode
9
8
  // ─────────────────────────────────────────────────────────────
@@ -20,7 +19,7 @@ module TestSEHSource = {
20
19
  let name = "TestSEHSource"
21
20
 
22
21
  @schema
23
- type event = | OrderPlaced({orderId: string})
22
+ type event = OrderPlaced({orderId: string})
24
23
  }
25
24
 
26
25
  // ─────────────────────────────────────────────────────────────
@@ -119,8 +118,9 @@ let publishOrderPlaced = async (id, orderId) => {
119
118
  ("meta", testMeta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema)),
120
119
  (
121
120
  "event",
122
- TestSEHSource.OrderPlaced({orderId: orderId})
123
- ->Reventless.Util_Sury.toJson(TestSEHSource.eventSchema),
121
+ TestSEHSource.OrderPlaced({orderId: orderId})->Reventless.Util_Sury.toJson(
122
+ TestSEHSource.eventSchema,
123
+ ),
124
124
  ),
125
125
  ]),
126
126
  )
@@ -48,8 +48,7 @@ module OrdersViewProjection = {
48
48
 
49
49
  let project = ({event}: Reventless.StateViewSlice.consumed<consumedEvent>) =>
50
50
  switch event {
51
- | OrderPlaced({id, placedAt}) =>
52
- [Set(id, {id, placedAt, shippedAt: "", displayName: None})]
51
+ | OrderPlaced({id, placedAt}) => [Set(id, {id, placedAt, shippedAt: "", displayName: None})]
53
52
  | OrderShipped({id, shippedAt}) => [Update(id, s => {...s, shippedAt})]
54
53
  }
55
54
  }
@@ -88,11 +87,10 @@ let loadState = async id => {
88
87
  switch Bus.getQueryDb("DnOrdersView") {
89
88
  | None => []
90
89
  | Some(ops) =>
91
- let states =
92
- await ops.loadStream(id)
93
- ->Stream.runCollect
94
- ->Effect.catchAll(_ => Effect.succeed([]))
95
- ->Effect.runPromise
90
+ let states = await ops.loadStream(id)
91
+ ->Stream.runCollect
92
+ ->Effect.catchAll(_ => Effect.succeed([]))
93
+ ->Effect.runPromise
96
94
  states->Array.map(json => json->Reventless.Util_Sury.fromJson(OrdersViewSpec.stateSchema))
97
95
  }
98
96
  }
@@ -67,7 +67,10 @@ let _ = TestRunner.setup()
67
67
  // ─────────────────────────────────────────────────────────────
68
68
 
69
69
  module ItemEventLogMaker = DcbEventLog_Builder.Make(Bus)
70
- let eventLog = ItemEventLogMaker.make(~name="ItemEventLog", ~partitionTag=Reventless.DcbTag.Simple({key: "id"}))
70
+ let eventLog = ItemEventLogMaker.make(
71
+ ~name="ItemEventLog",
72
+ ~partitionTag=Reventless.DcbTag.Simple({key: "id"}),
73
+ )
71
74
 
72
75
  // ─────────────────────────────────────────────────────────────
73
76
  // Build StateViewSlice
@@ -107,11 +110,10 @@ let loadState = async id => {
107
110
  switch Bus.getQueryDb("ItemsView") {
108
111
  | None => []
109
112
  | Some(ops) =>
110
- let states =
111
- await ops.loadStream(id)
112
- ->Stream.runCollect
113
- ->Effect.catchAll(_ => Effect.succeed([]))
114
- ->Effect.runPromise
113
+ let states = await ops.loadStream(id)
114
+ ->Stream.runCollect
115
+ ->Effect.catchAll(_ => Effect.succeed([]))
116
+ ->Effect.runPromise
115
117
  states->Array.map(json => json->Reventless.Util_Sury.fromJson(ItemsViewSpec.stateSchema))
116
118
  }
117
119
  }
@@ -11,8 +11,17 @@ open Reventless.Projection
11
11
  module ScoreEventLog = {
12
12
  @schema
13
13
  type event =
14
- | ScoreRecorded({id: @s.matches(Reventless.DcbTag.string) string, category: string, date: string, score: int})
15
- | ScoreRemoved({id: @s.matches(Reventless.DcbTag.string) string, category: string, date: string})
14
+ | ScoreRecorded({
15
+ id: @s.matches(Reventless.DcbTag.string) string,
16
+ category: string,
17
+ date: string,
18
+ score: int,
19
+ })
20
+ | ScoreRemoved({
21
+ id: @s.matches(Reventless.DcbTag.string) string,
22
+ category: string,
23
+ date: string,
24
+ })
16
25
  }
17
26
 
18
27
  // ─────────────────────────────────────────────────────────────
@@ -46,10 +55,8 @@ module ScoresViewProjection = {
46
55
 
47
56
  let project = ({event}: Reventless.StateViewSlice.consumed<consumedEvent>) =>
48
57
  switch event {
49
- | ScoreRecorded({id, category, date, score}) =>
50
- [Set(id, {id, category, date, score})]
51
- | ScoreRemoved({id, category: _, date: _}) =>
52
- [Delete(id)]
58
+ | ScoreRecorded({id, category, date, score}) => [Set(id, {id, category, date, score})]
59
+ | ScoreRemoved({id, category: _, date: _}) => [Delete(id)]
53
60
  }
54
61
  }
55
62
 
@@ -107,11 +114,10 @@ let loadScores = async id => {
107
114
  switch Bus.getQueryDb("ScoresView") {
108
115
  | None => []
109
116
  | Some(ops) =>
110
- let states =
111
- await ops.loadStream(id)
112
- ->Stream.runCollect
113
- ->Effect.catchAll(_ => Effect.succeed([]))
114
- ->Effect.runPromise
117
+ let states = await ops.loadStream(id)
118
+ ->Stream.runCollect
119
+ ->Effect.catchAll(_ => Effect.succeed([]))
120
+ ->Effect.runPromise
115
121
  states->Array.map(json => json->Reventless.Util_Sury.fromJson(ScoresViewSpec.stateSchema))
116
122
  }
117
123
  }
@@ -29,7 +29,12 @@ describe("StateViewSlice sub-ID E2E", () => {
29
29
  ScoreEventLog.ScoreRecorded({id: "player-2", category: "math", date: "2026-01", score: 80}),
30
30
  )
31
31
  let _ = await appendEvent(
32
- ScoreEventLog.ScoreRecorded({id: "player-2", category: "science", date: "2026-01", score: 95}),
32
+ ScoreEventLog.ScoreRecorded({
33
+ id: "player-2",
34
+ category: "science",
35
+ date: "2026-01",
36
+ score: 95,
37
+ }),
33
38
  )
34
39
  let _ = await appendEvent(
35
40
  ScoreEventLog.ScoreRecorded({id: "player-2", category: "math", date: "2026-02", score: 85}),
@@ -40,7 +45,12 @@ describe("StateViewSlice sub-ID E2E", () => {
40
45
 
41
46
  testPromise("loadStream returns sub-key items in alphabetical order", async () => {
42
47
  let _ = await appendEvent(
43
- ScoreEventLog.ScoreRecorded({id: "player-3", category: "science", date: "2026-03", score: 70}),
48
+ ScoreEventLog.ScoreRecorded({
49
+ id: "player-3",
50
+ category: "science",
51
+ date: "2026-03",
52
+ score: 70,
53
+ }),
44
54
  )
45
55
  let _ = await appendEvent(
46
56
  ScoreEventLog.ScoreRecorded({id: "player-3", category: "math", date: "2026-01", score: 88}),
@@ -1,7 +1,6 @@
1
1
  // Fixtures for Task integration tests.
2
2
  // Tests Task_Builder.Make wiring with in-memory adapters.
3
3
 
4
-
5
4
  // Activate Pulumi mock mode (must be called before any Component.make)
6
5
  let _ = TestRunner.setup()
7
6
 
@@ -52,8 +51,7 @@ module OneBucketSpec = {
52
51
  bucketName: "Reports",
53
52
  bucketMode: Reventless.Task.Read,
54
53
  callback: async (~eventName, ~key) => {
55
- capturedEvents :=
56
- capturedEvents.contents->Array.concat([(eventName, key)])
54
+ capturedEvents := capturedEvents.contents->Array.concat([(eventName, key)])
57
55
  []
58
56
  },
59
57
  },
@@ -67,8 +65,10 @@ module OneBucketSpec = {
67
65
 
68
66
  let mockPublishToAggregates: dict<ReventlessInfra.CommandTopic.publishJsons> = Dict.make()
69
67
 
70
- let mockQueryBucketName: ReventlessInfra.Task.queryBucketName = (~taskName as _, ~bucketName as _=?) =>
71
- "in-memory-bucket"
68
+ let mockQueryBucketName: ReventlessInfra.Task.queryBucketName = (
69
+ ~taskName as _,
70
+ ~bucketName as _=?,
71
+ ) => "in-memory-bucket"
72
72
 
73
73
  // ─────────────────────────────────────────────────────────────
74
74
  // Pre-built task makers