@reventlessdev/reventless-core 3.0.0-alpha.259 → 3.0.0-alpha.261

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +11 -11
  3. package/src/Behavior.res +1 -4
  4. package/src/Message.res +17 -14
  5. package/src/Projection.res +51 -25
  6. package/src/RequestContext.res +8 -9
  7. package/src/ResourceAttribution.res +28 -14
  8. package/src/adapter/Adapter.res +48 -4
  9. package/src/adapter/EventLogProvisioning/EventLogProvisioning.res +5 -5
  10. package/src/adapter/Messaging/Messaging_Log_Backend.res +10 -7
  11. package/src/adapter/Messaging/Messaging_Log_Backend.res.mjs +2 -4
  12. package/src/adapter/Monitoring/Monitoring.res +16 -17
  13. package/src/adapter/QueryInterception/QueryInterception.res +0 -1
  14. package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +12 -5
  15. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +11 -7
  16. package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +1 -7
  17. package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +1 -7
  18. package/src/adapter/RuntimeExtension/RuntimeExtension.res +0 -1
  19. package/src/admin/Platform_Admin.res +17 -6
  20. package/src/admin/Platform_AdminApi.res +14 -9
  21. package/src/admin/Platform_Admin_Callback.res +1 -1
  22. package/src/admin/Platform_BakedManifest.res +34 -34
  23. package/src/admin/Platform_ComponentDefinitionsApi.res +9 -21
  24. package/src/admin/Platform_PluginStructuresApi.res +15 -12
  25. package/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res +1 -1
  26. package/src/components/Aggregate/Aggregate.res +13 -12
  27. package/src/components/Aggregate/Aggregate_Builder.res +22 -21
  28. package/src/components/Aggregate/Aggregate_Callback.res +91 -86
  29. package/src/components/Api/ApiNoApiHelpers.res +1 -3
  30. package/src/components/Api/Api_Ids.res +0 -1
  31. package/src/components/Api/Api_Naming.res +41 -18
  32. package/src/components/Api/GraphQL_FragmentGenerator.res +42 -52
  33. package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +11 -4
  34. package/src/components/Api/GraphQL_SchemaInspector.res +5 -3
  35. package/src/components/Api/GraphQL_Stitcher.res +9 -10
  36. package/src/components/Api/MCP_SchemaGenerator.res +8 -12
  37. package/src/components/Api/OwnerScopeDiagnostics.res +1 -2
  38. package/src/components/Api/QueryDbListQuery.res +13 -6
  39. package/src/components/Api/SchemaType.res +40 -20
  40. package/src/components/Api/SchemaType.res.mjs +16 -0
  41. package/src/components/Api/SuryToJsonSchema.res +18 -10
  42. package/src/components/Api/SuryToJsonSchema.res.mjs +135 -121
  43. package/src/components/AutomationSlice/AutomationSlice.res +4 -4
  44. package/src/components/AutomationSlice/AutomationSlice_Builder.res +15 -14
  45. package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -3
  46. package/src/components/Builder_Helpers.res +12 -23
  47. package/src/components/CommandGenerator/CommandGenerator.res +6 -1
  48. package/src/components/CommandGenerator/CommandGenerator_Builder.res +29 -21
  49. package/src/components/CommandGenerator/CommandGenerator_Callback.res +17 -21
  50. package/src/components/CommandTopic/CommandTopic.res +3 -3
  51. package/src/components/CommandTopic/CommandTopic_Builder.res +10 -10
  52. package/src/components/CommandTopic/CommandTopic_Callback.res +1 -4
  53. package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -2
  54. package/src/components/Counter/Counter_Builder.res +1 -6
  55. package/src/components/Counter/Counter_Callback.res +3 -3
  56. package/src/components/Dcb/Dcb_Builder.res +970 -956
  57. package/src/components/DcbEventLog/DcbEventLog.res +4 -4
  58. package/src/components/DcbEventLog/DcbEventLog_Builder.res +0 -1
  59. package/src/components/DcbEventLog/DcbEventLog_Operations.res +17 -18
  60. package/src/components/EventCollector/EventCollector_Builder.res +2 -1
  61. package/src/components/EventLog/EventLog.res +5 -1
  62. package/src/components/EventLog/EventLog_Operations.res +12 -8
  63. package/src/components/EventMapper/EventMapper.res +8 -10
  64. package/src/components/EventMapper/EventMapper_Builder.res +4 -1
  65. package/src/components/EventMapper/EventMapper_Callback.res +46 -31
  66. package/src/components/EventTopic/EventTopic.res +3 -3
  67. package/src/components/EventTopic/EventTopic_Builder.res +1 -1
  68. package/src/components/Extension/Extension.res +4 -1
  69. package/src/components/Extension/Extension_Operations.res +11 -3
  70. package/src/components/ExtensionPoint/ExtensionPoint.res +3 -3
  71. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +9 -10
  72. package/src/components/ExtensionPoint/ExtensionPoint_Callback.res +2 -6
  73. package/src/components/ExtensionPoint/ExtensionPoint_Operations.res +13 -5
  74. package/src/components/Heartbeat/Heartbeat_Callback.res +3 -3
  75. package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +4 -4
  76. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +7 -10
  77. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res +4 -4
  78. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +15 -14
  79. package/src/components/QueryDb/QueryDb_Adapter.res +1 -3
  80. package/src/components/QueryDb/QueryDb_Operations.res +10 -10
  81. package/src/components/ReadModel/ReadModel.res +3 -3
  82. package/src/components/ReadModel/ReadModel_Builder.res +1 -2
  83. package/src/components/ReadModel/ReadModel_Callback.res +2 -1
  84. package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +5 -2
  85. package/src/components/StateChangeSlice/StateChangeSlice.res +3 -3
  86. package/src/components/StateChangeSlice/StateChangeSlice_Builder.res +23 -4
  87. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +22 -6
  88. package/src/components/StateTopic.res +1 -3
  89. package/src/components/StateViewSlice/StateViewSlice.res +4 -4
  90. package/src/components/StateViewSlice/StateViewSlice_Builder.res +79 -68
  91. package/src/components/StateViewSlice/StateViewSlice_Callback.res +3 -1
  92. package/src/components/Task/Task.res +3 -3
  93. package/src/components/Task/Task_Adapter.res +4 -1
  94. package/src/components/Task/Task_Builder.res +24 -21
  95. package/src/plugin/api/PluginBaseFragment.res +9 -3
  96. package/src/plugin/component/Capability_Inference.res +8 -10
  97. package/src/plugin/component/Plugin.res +6 -6
  98. package/src/plugin/component/Plugin_Builder.res +54 -50
  99. package/src/plugin/component/Plugin_Callback.res +10 -6
  100. package/src/plugin/component/Plugin_Helpers.res +264 -230
  101. package/src/plugin/component/Plugin_Structure.res +370 -324
  102. package/src/plugin/component/Plugin_SubscriptionSchema.res +8 -6
  103. package/src/plugin/component/SchemaWalker.res +11 -12
  104. package/src/plugin/connect/PluginConnectExtension_Mapping.res +45 -50
  105. package/src/plugin/lifecycle/PluginBehavior.res +3 -4
  106. package/src/plugin/lifecycle/PluginSpec.res +1 -2
  107. package/src/plugin/lifecycle/PluginsProjection.res +16 -5
  108. package/src/plugin/lifecycle/PluginsReadModelSpec.res +0 -2
  109. package/src/util/CommandPublisher.res +9 -2
  110. package/src/util/CsvStream.res +3 -3
  111. package/src/util/Interstack.res +7 -15
  112. package/src/util/Interstack.resi +3 -3
  113. package/src/util/LogFormat.res +5 -9
  114. package/src/util/Logger.res +1 -2
  115. package/src/util/Lru.res +2 -1
  116. package/src/util/Lru.resi +2 -3
  117. package/src/util/ScheduleOps.res +24 -27
  118. package/src/util/StorePrefixCollision.res +6 -9
  119. package/src/util/Util_Promise.res +4 -1
  120. package/src/util/Util_Promise.res.mjs +1 -1
  121. package/tests/IdentityTest.res +166 -113
  122. package/tests/ResourceAttributionTest.res +28 -25
  123. package/tests/StorePrefixCollisionTest.res +2 -1
  124. package/tests/TaskBucketNamingTest.res +3 -2
  125. package/tests/adapter/EventLogProvisioningTest.res +51 -48
  126. package/tests/adapter/MonitoringTest.res +81 -38
  127. package/tests/adapter/QueryInterceptionTest.res +2 -2
  128. package/tests/adapter/RefusalVocabularyTest.res +31 -23
  129. package/tests/adapter/RuntimeExtensionHookReachTest.res +9 -8
  130. package/tests/adapter/RuntimeExtensionTest.res +5 -3
  131. package/tests/admin/AdminApiSchemaDriftTest.res +22 -16
  132. package/tests/admin/Platform_Admin_StructureTest.res +10 -11
  133. package/tests/admin/Platform_BakedManifestTest.res +31 -35
  134. package/tests/admin/Platform_ComponentDefinitionsApiTest.res +18 -15
  135. package/tests/admin/Platform_PluginStructuresApiTest.res +5 -3
  136. package/tests/admin/Platform_UIFragmentsApiTest.res +6 -3
  137. package/tests/aggregate/AggregateCacheTest.res +10 -12
  138. package/tests/aggregate/AggregateCallbackTest.res +75 -46
  139. package/tests/aggregate/AggregateCausationTest.res +19 -20
  140. package/tests/aggregate/AggregateConflictTest.res +41 -19
  141. package/tests/aggregate/AggregateFixtures.res +15 -5
  142. package/tests/aggregate/AggregateRejectionTest.res +97 -80
  143. package/tests/aggregate/AggregateSnapshotTest.res +44 -16
  144. package/tests/api/Api_IdsTest.res +10 -4
  145. package/tests/api/BrandedMarkerCompositionTest.res +48 -36
  146. package/tests/api/GeolocationSemanticTest.res +3 -3
  147. package/tests/api/GraphQL_FragmentGeneratorTest.res +66 -54
  148. package/tests/api/OwnerScopeDiagnosticsTest.res +31 -27
  149. package/tests/api/StorageRefFieldsTest.res +30 -18
  150. package/tests/api/SuryToJsonSchemaTest.res +1338 -981
  151. package/tests/api/SuryToJsonSchemaTest.res.mjs +31 -0
  152. package/tests/api/TaggedUnionSchemaTest.res +17 -24
  153. package/tests/commandgenerator/CommandGeneratorCallbackTest.res +235 -179
  154. package/tests/commandgenerator/CommandGeneratorFixtures.res +8 -13
  155. package/tests/commandgenerator/OwnerStampingTest.res +91 -76
  156. package/tests/commandtopic/CommandOutcomeHookTest.res +198 -155
  157. package/tests/commandtopic/CommandTopicCallbackFixtures.res +5 -4
  158. package/tests/commandtopic/CommandTopicCallbackTest.res +61 -43
  159. package/tests/commandtopic/CommandTopicHelpersRejectionTest.res +70 -55
  160. package/tests/counter/CounterCallbackTest.res +40 -34
  161. package/tests/counter/CounterFixtures.res +4 -4
  162. package/tests/dcb/DcbDecodeTest.res +115 -84
  163. package/tests/dcb/DcbEventLogOperationsTest.res +194 -143
  164. package/tests/dcb/DcbEventLogSchemaTest.res +13 -13
  165. package/tests/dcb/DcbFixtures.res +4 -5
  166. package/tests/dcb/DcbScopeInferenceTest.res +173 -114
  167. package/tests/dcb/DcbStateChangeSliceTest.res +391 -262
  168. package/tests/dcb/DcbTagTest.res +22 -11
  169. package/tests/dcb/DcbValidationTest.res +288 -218
  170. package/tests/eventlog/EventLogFixtures.res +4 -4
  171. package/tests/eventlog/EventLogOperationsTest.res +102 -67
  172. package/tests/eventlog/EventLogRetryTest.res +104 -65
  173. package/tests/eventmapper/EventMapperCallbackTest.res +118 -83
  174. package/tests/eventmapper/EventMapperFixtures.res +15 -23
  175. package/tests/eventmapper/EventMapperTest.res +54 -38
  176. package/tests/eventtopic/EventTopicFixtures.res +3 -4
  177. package/tests/eventtopic/EventTopicOperationsTest.res +41 -29
  178. package/tests/extensionpoint/ExtensionPointCallbackTest.res +58 -45
  179. package/tests/extensionpoint/ExtensionPointFixtures.res +16 -20
  180. package/tests/extensionpoint/ExtensionPointOperationsTest.res +70 -49
  181. package/tests/extensionpoint/PluginDisconnectScheduleTest.res +2 -1
  182. package/tests/logger/LogFormatTest.res +104 -82
  183. package/tests/logger/LoggerLazyTest.res +21 -12
  184. package/tests/message/MessageTest.res +96 -93
  185. package/tests/message/MetaEnvelopeTest.res +26 -30
  186. package/tests/plugin/HeartbeatDisconnectGraceTest.res +31 -25
  187. package/tests/plugin/ManifestVisibilityTest.res +20 -12
  188. package/tests/plugin/PluginDefinitionScalars.res +1 -2
  189. package/tests/plugin/PluginLifecycleCorpusTest.res +15 -12
  190. package/tests/plugin/PluginSpecExperiment.res +0 -1
  191. package/tests/plugin/PluginStructureTest.res +1533 -1030
  192. package/tests/plugin/PluginStructureTest.res.mjs +6 -0
  193. package/tests/plugin/Plugin_EventQuerySchemaTest.res +21 -10
  194. package/tests/plugin/SchemaWalkerTest.res +116 -70
  195. package/tests/plugin/StateChange/PsReserveStock.res +4 -4
  196. package/tests/plugin/StateView/PsAnnotatedView.res +6 -4
  197. package/tests/plugin/StateView/PsAnnotatedView.res.mjs +7 -3
  198. package/tests/plugin/StateView/PsCustomersView.res +4 -4
  199. package/tests/plugin/StateView/PsShipmentsView.res +3 -2
  200. package/tests/projection/LifecycleTrailTest.res +1 -4
  201. package/tests/projection/ProjectionOptimizeTest.res +13 -9
  202. package/tests/querydb/QueryDbFixtures.res +0 -1
  203. package/tests/querydb/QueryDbOperationsTest.res +99 -64
  204. package/tests/querydb/TaggedUnionStampTest.res +10 -8
  205. package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res +50 -35
  206. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +4 -10
  207. package/tests/util/CommandPublisherTest.res +0 -1
  208. package/tests/util/CsvStreamTest.res +3 -3
  209. package/tests/util/LruTest.res +84 -56
@@ -25,7 +25,9 @@ module OpsAlt = DcbEventLog_Operations.Make(TestOpsAlt)
25
25
  let _ = beforeEach(() => mock.reset())
26
26
 
27
27
  // Helper to encode a TestEventLogSpec event to a rawEvent for testing
28
- let encodeEvent = (event: DcbFixtures.TestEventLogSpec.event): ReventlessInfra.DcbEventLog.rawEvent => {
28
+ let encodeEvent = (
29
+ event: DcbFixtures.TestEventLogSpec.event,
30
+ ): ReventlessInfra.DcbEventLog.rawEvent => {
29
31
  let json = event->Reventless.Util_Sury.toJson(DcbFixtures.TestEventLogSpec.eventSchema)
30
32
  let (eventType, data) = json->Message.splitMessage
31
33
  let tags = Reventless.DcbTag.extractTags(DcbFixtures.TestEventLogSpec.eventSchema, event)
@@ -34,7 +36,9 @@ let encodeEvent = (event: DcbFixtures.TestEventLogSpec.event): ReventlessInfra.D
34
36
  }
35
37
 
36
38
  // Helper to decode a rawSequencedEvent back to a TestEventLogSpec event
37
- let decodeEvent = (raw: ReventlessInfra.DcbEventLog.rawSequencedEvent): DcbFixtures.TestEventLogSpec.event => {
39
+ let decodeEvent = (
40
+ raw: ReventlessInfra.DcbEventLog.rawSequencedEvent,
41
+ ): DcbFixtures.TestEventLogSpec.event => {
38
42
  let json = Message.combineMessage(
39
43
  raw.eventType,
40
44
  raw.data->JSON.Decode.object->Option.getOr(Dict.make()),
@@ -44,152 +48,199 @@ let decodeEvent = (raw: ReventlessInfra.DcbEventLog.rawSequencedEvent): DcbFixtu
44
48
 
45
49
  describe("DcbEventLog_Operations:", () => {
46
50
  describe("round-trip (append then read)", () => {
47
- testPromise("ItemCreated preserves through round-trip", async () => {
48
- let event = DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})
49
- let rawEvent = encodeEvent(event)
50
- let _ = await Ops.append([rawEvent])
51
- let result = await Ops.read(~query=[{}])
52
-
53
- expect((
54
- result.events->Array.length,
55
- result.events->Array.get(0)->Option.map(se => decodeEvent(se)),
56
- ))->toEqual((1, Some(event)))
57
- })
58
-
59
- testPromise("CountUpdated with int tag preserves through round-trip", async () => {
60
- let event = DcbFixtures.TestEventLogSpec.CountUpdated({category: "electronics", amount: 42})
61
- let rawEvent = encodeEvent(event)
62
- let _ = await Ops.append([rawEvent])
63
- let result = await Ops.read(~query=[{}])
64
-
65
- expect(result.events->Array.get(0)->Option.map(se => decodeEvent(se)))->toEqual(Some(event))
66
- })
67
-
68
- testPromise("multiple events in single append all read back", async () => {
69
- let events = [
70
- DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "First"}),
71
- DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Second"}),
72
- ]
73
- let rawEvents = events->Array.map(encodeEvent)
74
- let _ = await Ops.append(rawEvents)
75
- let result = await Ops.read(~query=[{}])
76
-
77
- expect((
78
- result.events->Array.length,
79
- result.events->Array.map(se => decodeEvent(se)),
80
- ))->toEqual((2, events))
81
- })
51
+ testPromise(
52
+ "ItemCreated preserves through round-trip",
53
+ async () => {
54
+ let event = DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})
55
+ let rawEvent = encodeEvent(event)
56
+ let _ = await Ops.append([rawEvent])
57
+ let result = await Ops.read(~query=[{}])
58
+
59
+ expect((
60
+ result.events->Array.length,
61
+ result.events->Array.get(0)->Option.map(se => decodeEvent(se)),
62
+ ))->toEqual((1, Some(event)))
63
+ },
64
+ )
65
+
66
+ testPromise(
67
+ "CountUpdated with int tag preserves through round-trip",
68
+ async () => {
69
+ let event = DcbFixtures.TestEventLogSpec.CountUpdated({category: "electronics", amount: 42})
70
+ let rawEvent = encodeEvent(event)
71
+ let _ = await Ops.append([rawEvent])
72
+ let result = await Ops.read(~query=[{}])
73
+
74
+ expect(result.events->Array.get(0)->Option.map(se => decodeEvent(se)))->toEqual(Some(event))
75
+ },
76
+ )
77
+
78
+ testPromise(
79
+ "multiple events in single append all read back",
80
+ async () => {
81
+ let events = [
82
+ DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "First"}),
83
+ DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Second"}),
84
+ ]
85
+ let rawEvents = events->Array.map(encodeEvent)
86
+ let _ = await Ops.append(rawEvents)
87
+ let result = await Ops.read(~query=[{}])
88
+
89
+ expect((
90
+ result.events->Array.length,
91
+ result.events->Array.map(se => decodeEvent(se)),
92
+ ))->toEqual((2, events))
93
+ },
94
+ )
82
95
  })
83
96
 
84
97
  describe("append", () => {
85
- testPromise("stores events and publishes to event topic", async () => {
86
- let event = DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})
87
- let result = await Ops.append([encodeEvent(event)])
88
-
89
- expect((
90
- Result.isOk(result),
91
- mock.getEvents()->Array.length,
92
- mock.publishedEvents.contents->Array.length,
93
- ))->toEqual((true, 1, 1))
94
- })
95
-
96
- testPromise("published events have correct service name", async () => {
97
- let _ = await Ops.append([
98
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
99
- ])
100
-
101
- expect(
102
- mock.publishedEvents.contents->Array.get(0)->Option.map(pe => pe.service),
103
- )->toEqual(Some("TestDcbEventLog"))
104
- })
105
-
106
- testPromise("service comes from Ops.serviceName, not Ops.name", async () => {
107
- let _ = await OpsAlt.append([
108
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
109
- ])
110
-
111
- expect(
112
- mock.publishedEvents.contents->Array.get(0)->Option.map(pe => pe.service),
113
- )->toEqual(Some("CatalogDcbEventLog"))
114
- })
115
-
116
- testPromise("error from storage does not publish to event topic", async () => {
117
- mock.failNextAppends := 1
118
- let result = await Ops.append([
119
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
120
- ])
121
-
122
- expect((Result.isError(result), mock.publishedEvents.contents->Array.length))->toEqual((
123
- true,
124
- 0,
125
- ))
126
- })
127
-
128
- testPromise("with condition (no conflict) succeeds", async () => {
129
- let _ = await Ops.append([
130
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
131
- ])
132
- let condition: Reventless.DcbTag.appendCondition = {
133
- query: [{eventTypes: ["ItemCreated"], tags: [{Reventless.DcbTag.key: "itemId", value: "item-1"}]}],
134
- after: "1",
135
- }
136
- let result = await Ops.append(
137
- [encodeEvent(DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Updated"}))],
138
- ~condition,
139
- )
140
-
141
- expect(Result.isOk(result))->toBe(true)
142
- })
143
-
144
- testPromise("multiple events all stored and published", async () => {
145
- let events = [
146
- DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "First"}),
147
- DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-2", name: "Second"}),
148
- ]
149
- let _ = await Ops.append(events->Array.map(encodeEvent))
150
-
151
- expect((
152
- mock.getEvents()->Array.length,
153
- mock.publishedEvents.contents->Array.length,
154
- ))->toEqual((2, 2))
155
- })
98
+ testPromise(
99
+ "stores events and publishes to event topic",
100
+ async () => {
101
+ let event = DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})
102
+ let result = await Ops.append([encodeEvent(event)])
103
+
104
+ expect((
105
+ Result.isOk(result),
106
+ mock.getEvents()->Array.length,
107
+ mock.publishedEvents.contents->Array.length,
108
+ ))->toEqual((true, 1, 1))
109
+ },
110
+ )
111
+
112
+ testPromise(
113
+ "published events have correct service name",
114
+ async () => {
115
+ let _ = await Ops.append([
116
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
117
+ ])
118
+
119
+ expect(mock.publishedEvents.contents->Array.get(0)->Option.map(pe => pe.service))->toEqual(
120
+ Some("TestDcbEventLog"),
121
+ )
122
+ },
123
+ )
124
+
125
+ testPromise(
126
+ "service comes from Ops.serviceName, not Ops.name",
127
+ async () => {
128
+ let _ = await OpsAlt.append([
129
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
130
+ ])
131
+
132
+ expect(mock.publishedEvents.contents->Array.get(0)->Option.map(pe => pe.service))->toEqual(
133
+ Some("CatalogDcbEventLog"),
134
+ )
135
+ },
136
+ )
137
+
138
+ testPromise(
139
+ "error from storage does not publish to event topic",
140
+ async () => {
141
+ mock.failNextAppends := 1
142
+ let result = await Ops.append([
143
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
144
+ ])
145
+
146
+ expect((Result.isError(result), mock.publishedEvents.contents->Array.length))->toEqual((
147
+ true,
148
+ 0,
149
+ ))
150
+ },
151
+ )
152
+
153
+ testPromise(
154
+ "with condition (no conflict) succeeds",
155
+ async () => {
156
+ let _ = await Ops.append([
157
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
158
+ ])
159
+ let condition: Reventless.DcbTag.appendCondition = {
160
+ query: [
161
+ {
162
+ eventTypes: ["ItemCreated"],
163
+ tags: [{Reventless.DcbTag.key: "itemId", value: "item-1"}],
164
+ },
165
+ ],
166
+ after: "1",
167
+ }
168
+ let result = await Ops.append(
169
+ [
170
+ encodeEvent(
171
+ DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Updated"}),
172
+ ),
173
+ ],
174
+ ~condition,
175
+ )
176
+
177
+ expect(Result.isOk(result))->toBe(true)
178
+ },
179
+ )
180
+
181
+ testPromise(
182
+ "multiple events all stored and published",
183
+ async () => {
184
+ let events = [
185
+ DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "First"}),
186
+ DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-2", name: "Second"}),
187
+ ]
188
+ let _ = await Ops.append(events->Array.map(encodeEvent))
189
+
190
+ expect((
191
+ mock.getEvents()->Array.length,
192
+ mock.publishedEvents.contents->Array.length,
193
+ ))->toEqual((2, 2))
194
+ },
195
+ )
156
196
  })
157
197
 
158
198
  describe("read", () => {
159
- testPromise("returns headPosition from storage", async () => {
160
- let _ = await Ops.append([
161
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
162
- ])
163
- let result = await Ops.read(~query=[{}])
164
-
165
- expect(result.headPosition)->toEqual(Some("1"))
166
- })
167
-
168
- testPromise("with ~after parameter filters out earlier events", async () => {
169
- let _ = await Ops.append([
170
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "First"})),
171
- ])
172
- let _ = await Ops.append([
173
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Second"})),
174
- ])
175
- let result = await Ops.read(~query=[{}], ~after="1")
176
-
177
- expect((
178
- result.events->Array.length,
179
- result.events->Array.get(0)->Option.map(se => decodeEvent(se)),
180
- ))->toEqual((
181
- 1,
182
- Some(DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Second"})),
183
- ))
184
- })
185
-
186
- testPromise("no matching events returns empty array", async () => {
187
- let _ = await Ops.append([
188
- encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
189
- ])
190
- let result = await Ops.read(~query=[{eventTypes: ["NonExistent"]}])
191
-
192
- expect(result.events->Array.length)->toEqual(0)
193
- })
199
+ testPromise(
200
+ "returns headPosition from storage",
201
+ async () => {
202
+ let _ = await Ops.append([
203
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
204
+ ])
205
+ let result = await Ops.read(~query=[{}])
206
+
207
+ expect(result.headPosition)->toEqual(Some("1"))
208
+ },
209
+ )
210
+
211
+ testPromise(
212
+ "with ~after parameter filters out earlier events",
213
+ async () => {
214
+ let _ = await Ops.append([
215
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "First"})),
216
+ ])
217
+ let _ = await Ops.append([
218
+ encodeEvent(
219
+ DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Second"}),
220
+ ),
221
+ ])
222
+ let result = await Ops.read(~query=[{}], ~after="1")
223
+
224
+ expect((
225
+ result.events->Array.length,
226
+ result.events->Array.get(0)->Option.map(se => decodeEvent(se)),
227
+ ))->toEqual((
228
+ 1,
229
+ Some(DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-1", newName: "Second"})),
230
+ ))
231
+ },
232
+ )
233
+
234
+ testPromise(
235
+ "no matching events returns empty array",
236
+ async () => {
237
+ let _ = await Ops.append([
238
+ encodeEvent(DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"})),
239
+ ])
240
+ let result = await Ops.read(~query=[{eventTypes: ["NonExistent"]}])
241
+
242
+ expect(result.events->Array.length)->toEqual(0)
243
+ },
244
+ )
194
245
  })
195
246
  })
@@ -26,17 +26,18 @@ let variant = (~tag: string, fields: array<(string, S.t<unknown>)>): S.t<unknown
26
26
 
27
27
  let ref_ = (~store: string) => Reventless.StorageRef.forStore(~store)->S.castToUnknown
28
28
 
29
- let addCategory = S.union([
30
- variant(~tag="CategoryAdded", [("imageUrl", ref_(~store="categoryImages"))]),
31
- ])->S.castToUnknown
29
+ let addCategory =
30
+ S.union([
31
+ variant(~tag="CategoryAdded", [("imageUrl", ref_(~store="categoryImages"))]),
32
+ ])->S.castToUnknown
32
33
 
33
- let addProduct = S.union([
34
- variant(~tag="ProductAdded", [("imageUrl", ref_(~store="productImages"))]),
35
- ])->S.castToUnknown
34
+ let addProduct =
35
+ S.union([
36
+ variant(~tag="ProductAdded", [("imageUrl", ref_(~store="productImages"))]),
37
+ ])->S.castToUnknown
36
38
 
37
- let renameCategory = S.union([
38
- variant(~tag="CategoryRenamed", [("name", S.string->S.castToUnknown)]),
39
- ])->S.castToUnknown
39
+ let renameCategory =
40
+ S.union([variant(~tag="CategoryRenamed", [("name", S.string->S.castToUnknown)])])->S.castToUnknown
40
41
 
41
42
  describe("Dcb_Builder.mergedEventSchema", () => {
42
43
  testSync("carries every slice's event types, not the first slice's", () => {
@@ -53,10 +54,9 @@ describe("Dcb_Builder.mergedEventSchema", () => {
53
54
  testSync("surfaces the ref fields of every slice that declares one", () => {
54
55
  let merged = [addCategory, addProduct, renameCategory]->Dcb_Builder.mergedEventSchema
55
56
  expect(
56
- StorageRefFields.fromEventSchema(~plugin="Catalog", merged)->Array.map(e => (
57
- e.eventType,
58
- e.fields->Array.map(f => f.store),
59
- )),
57
+ StorageRefFields.fromEventSchema(~plugin="Catalog", merged)->Array.map(
58
+ e => (e.eventType, e.fields->Array.map(f => f.store)),
59
+ ),
60
60
  )->toEqual([
61
61
  ("CategoryAdded", ["Catalog.categoryImages"]),
62
62
  ("ProductAdded", ["Catalog.productImages"]),
@@ -1,4 +1,3 @@
1
-
2
1
  // --- Test Event Log Spec (events with DCB tags) ---
3
2
 
4
3
  module TestEventLogSpec = {
@@ -339,9 +338,8 @@ type multiProductCommand =
339
338
  // Scalar field override — non-Id name remapped via @dcbTag("explicitKey") at the PPX
340
339
  // level; the runtime side is exercised here directly with stringForKey.
341
340
  @schema
342
- type customKeyEvent = ProductLabelled({
343
- sku: @s.matches(Reventless.DcbTag.stringForKey(~key="productSku")) string,
344
- })
341
+ type customKeyEvent =
342
+ ProductLabelled({sku: @s.matches(Reventless.DcbTag.stringForKey(~key="productSku")) string})
345
343
 
346
344
  // --- Composite partition tag test schemas ---
347
345
 
@@ -357,7 +355,8 @@ type compositeEvent =
357
355
  @schema
358
356
  type compositeEventCustomSep =
359
357
  | ConfigUpdated({
360
- tenantId: @s.matches(Reventless.DcbTag.compositePartitionMember(~position=0, ~sep=":")) string,
358
+ tenantId: @s.matches(Reventless.DcbTag.compositePartitionMember(~position=0, ~sep=":"))
359
+ string,
361
360
  region: @s.matches(Reventless.DcbTag.compositePartitionMember(~position=1, ~sep="/")) string,
362
361
  service: @s.matches(Reventless.DcbTag.compositePartitionMember(~position=2)) string,
363
362
  value: string,