@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
@@ -34,109 +34,126 @@ let uninstallChannels = () => {
34
34
 
35
35
  describe("Aggregate decide-rejection propagation:", () => {
36
36
  describe("single rejected command", () => {
37
- testPromise("Create on existing aggregate reports Rejected with errorCode", async () => {
38
- // Seed: aggregate already created → second Create rejects with AlreadyExists.
39
- let _ =
40
- await Stream.fromIterable([
37
+ testPromise(
38
+ "Create on existing aggregate reports Rejected with errorCode",
39
+ async () => {
40
+ // Seed: aggregate already created → second Create rejects with AlreadyExists.
41
+ let _ = await Stream.fromIterable([
41
42
  makeTopicItem("ref-seed", AggSpec.Create({name: "Widget"})),
42
- ])->TestHandler.handleCommands->Effect.runPromise
43
+ ])
44
+ ->TestHandler.handleCommands
45
+ ->Effect.runPromise
43
46
 
44
- installChannels()
45
- let results =
46
- await Stream.fromIterable([
47
+ installChannels()
48
+ let results = await Stream.fromIterable([
47
49
  makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
48
- ])->TestHandler.handleCommands->Effect.runPromise
49
- uninstallChannels()
50
+ ])
51
+ ->TestHandler.handleCommands
52
+ ->Effect.runPromise
53
+ uninstallChannels()
50
54
 
51
- // Producer sees Rejected on the channel; SQS sees Ok (delete — don't redeliver).
52
- expect(results)->toEqual([Ok("ref-1")])
53
- expect(capturedRejections.contents->Array.length)->toBe(1)
54
- let (ref, info) = capturedRejections.contents->Array.getUnsafe(0)
55
- expect(ref)->toEqual("ref-1")
56
- expect(info.errorCode)->toEqual("AlreadyExists")
57
- // No event was appended.
58
- expect(mock.getAll()->Array.length)->toBe(1)
59
- })
55
+ // Producer sees Rejected on the channel; SQS sees Ok (delete — don't redeliver).
56
+ expect(results)->toEqual([Ok("ref-1")])
57
+ expect(capturedRejections.contents->Array.length)->toBe(1)
58
+ let (ref, info) = capturedRejections.contents->Array.getUnsafe(0)
59
+ expect(ref)->toEqual("ref-1")
60
+ expect(info.errorCode)->toEqual("AlreadyExists")
61
+ // No event was appended.
62
+ expect(mock.getAll()->Array.length)->toBe(1)
63
+ },
64
+ )
60
65
  })
61
66
 
62
67
  describe("mixed batch", () => {
63
- testPromise("rejected command does not cancel surviving commands", async () => {
64
- // Seed.
65
- let _ =
66
- await Stream.fromIterable([
68
+ testPromise(
69
+ "rejected command does not cancel surviving commands",
70
+ async () => {
71
+ // Seed.
72
+ let _ = await Stream.fromIterable([
67
73
  makeTopicItem(~aggId="agg-1", "ref-seed", AggSpec.Create({name: "Widget"})),
68
- ])->TestHandler.handleCommands->Effect.runPromise
74
+ ])
75
+ ->TestHandler.handleCommands
76
+ ->Effect.runPromise
69
77
 
70
- installChannels()
71
- // Batch on the same aggregate: Rename (ok) → Create (rejects) → Rename (ok)
72
- let results =
73
- await Stream.fromIterable([
78
+ installChannels()
79
+ // Batch on the same aggregate: Rename (ok) → Create (rejects) → Rename (ok)
80
+ let results = await Stream.fromIterable([
74
81
  makeTopicItem(~aggId="agg-1", "ref-1", AggSpec.Rename({newName: "First"})),
75
82
  makeTopicItem(~aggId="agg-1", "ref-2", AggSpec.Create({name: "Boom"})),
76
83
  makeTopicItem(~aggId="agg-1", "ref-3", AggSpec.Rename({newName: "Last"})),
77
- ])->TestHandler.handleCommands->Effect.runPromise
78
- uninstallChannels()
84
+ ])
85
+ ->TestHandler.handleCommands
86
+ ->Effect.runPromise
87
+ uninstallChannels()
79
88
 
80
- // All three references map to Ok (rejected ones still Ok — SQS deletes).
81
- expect(results->Array.length)->toBe(3)
82
- results->Array.forEach(r =>
83
- switch r {
84
- | Ok(_) => ()
85
- | Error(_) => expect("expected all Ok")->toEqual("got Error")
86
- }
87
- )
88
- // Two Renamed events appended (the rejected Create produced none).
89
- // Seed = 1, plus 2 Renamed = 3 stored.
90
- expect(mock.getAll()->Array.length)->toBe(3)
91
- // ref-2 reported as Rejected with AlreadyExists.
92
- let rejected = capturedRejections.contents
93
- expect(rejected->Array.length)->toBe(1)
94
- let (rRef, rInfo) = rejected->Array.getUnsafe(0)
95
- expect(rRef)->toEqual("ref-2")
96
- expect(rInfo.errorCode)->toEqual("AlreadyExists")
97
- // ref-1 and ref-3 reported as Accepted (eventCount > 0 against the appended batch).
98
- let accepted = capturedAccepts.contents
99
- expect(accepted->Array.length)->toBe(2)
100
- })
89
+ // All three references map to Ok (rejected ones still Ok — SQS deletes).
90
+ expect(results->Array.length)->toBe(3)
91
+ results->Array.forEach(
92
+ r =>
93
+ switch r {
94
+ | Ok(_) => ()
95
+ | Error(_) => expect("expected all Ok")->toEqual("got Error")
96
+ },
97
+ )
98
+ // Two Renamed events appended (the rejected Create produced none).
99
+ // Seed = 1, plus 2 Renamed = 3 stored.
100
+ expect(mock.getAll()->Array.length)->toBe(3)
101
+ // ref-2 reported as Rejected with AlreadyExists.
102
+ let rejected = capturedRejections.contents
103
+ expect(rejected->Array.length)->toBe(1)
104
+ let (rRef, rInfo) = rejected->Array.getUnsafe(0)
105
+ expect(rRef)->toEqual("ref-2")
106
+ expect(rInfo.errorCode)->toEqual("AlreadyExists")
107
+ // ref-1 and ref-3 reported as Accepted (eventCount > 0 against the appended batch).
108
+ let accepted = capturedAccepts.contents
109
+ expect(accepted->Array.length)->toBe(2)
110
+ },
111
+ )
101
112
  })
102
113
 
103
114
  describe("all-reject batch", () => {
104
- testPromise("3 rejecting commands → no append, all reported Rejected, no Accepted", async () => {
105
- // No seed → empty history. Rename on a NotCreated aggregate rejects with NotFound.
106
- installChannels()
107
- let results =
108
- await Stream.fromIterable([
115
+ testPromise(
116
+ "3 rejecting commands → no append, all reported Rejected, no Accepted",
117
+ async () => {
118
+ // No seed → empty history. Rename on a NotCreated aggregate rejects with NotFound.
119
+ installChannels()
120
+ let results = await Stream.fromIterable([
109
121
  makeTopicItem(~aggId="agg-x", "ref-1", AggSpec.Rename({newName: "A"})),
110
122
  makeTopicItem(~aggId="agg-x", "ref-2", AggSpec.Rename({newName: "B"})),
111
123
  makeTopicItem(~aggId="agg-x", "ref-3", AggSpec.Rename({newName: "C"})),
112
- ])->TestHandler.handleCommands->Effect.runPromise
113
- uninstallChannels()
124
+ ])
125
+ ->TestHandler.handleCommands
126
+ ->Effect.runPromise
127
+ uninstallChannels()
114
128
 
115
- expect(results)->toEqual([Ok("ref-1"), Ok("ref-2"), Ok("ref-3")])
116
- // No events appended.
117
- expect(mock.getAll()->Array.length)->toBe(0)
118
- // All three reported as Rejected.
119
- expect(capturedRejections.contents->Array.length)->toBe(3)
120
- capturedRejections.contents->Array.forEach(((_ref, info)) =>
121
- expect(info.errorCode)->toEqual("NotFound")
122
- )
123
- // No Accepted callbacks fired (when nothing is appended and nothing is OK).
124
- expect(capturedAccepts.contents->Array.length)->toBe(0)
125
- })
129
+ expect(results)->toEqual([Ok("ref-1"), Ok("ref-2"), Ok("ref-3")])
130
+ // No events appended.
131
+ expect(mock.getAll()->Array.length)->toBe(0)
132
+ // All three reported as Rejected.
133
+ expect(capturedRejections.contents->Array.length)->toBe(3)
134
+ capturedRejections.contents->Array.forEach(
135
+ ((_ref, info)) => expect(info.errorCode)->toEqual("NotFound"),
136
+ )
137
+ // No Accepted callbacks fired (when nothing is appended and nothing is OK).
138
+ expect(capturedAccepts.contents->Array.length)->toBe(0)
139
+ },
140
+ )
126
141
  })
127
142
 
128
143
  describe("payload-less variant errors", () => {
129
- testPromise("errorDetail is empty string for unit-payload variants", async () => {
130
- // AggSpec.error variants are all payload-less (NotFound | AlreadyExists).
131
- installChannels()
132
- let _ =
133
- await Stream.fromIterable([
134
- makeTopicItem("ref-1", AggSpec.Rename({newName: "X"})),
135
- ])->TestHandler.handleCommands->Effect.runPromise
136
- uninstallChannels()
144
+ testPromise(
145
+ "errorDetail is empty string for unit-payload variants",
146
+ async () => {
147
+ // AggSpec.error variants are all payload-less (NotFound | AlreadyExists).
148
+ installChannels()
149
+ let _ = await Stream.fromIterable([makeTopicItem("ref-1", AggSpec.Rename({newName: "X"}))])
150
+ ->TestHandler.handleCommands
151
+ ->Effect.runPromise
152
+ uninstallChannels()
137
153
 
138
- let (_ref, info) = capturedRejections.contents->Array.getUnsafe(0)
139
- expect(info.errorDetail)->toEqual("")
140
- })
154
+ let (_ref, info) = capturedRejections.contents->Array.getUnsafe(0)
155
+ expect(info.errorDetail)->toEqual("")
156
+ },
157
+ )
141
158
  })
142
159
  })
@@ -12,7 +12,6 @@
12
12
 
13
13
  open JestGlobals
14
14
 
15
-
16
15
  module AggSpec = {
17
16
  module Id = Reventless.Id.StringPure
18
17
  let name = "SnapshotTestAggregate"
@@ -24,7 +23,7 @@ module AggSpec = {
24
23
  type event = Added({item: string})
25
24
 
26
25
  @schema
27
- type error = | Never
26
+ type error = Never
28
27
 
29
28
  let moduleUrl: string = %raw(`import.meta.url`)
30
29
  }
@@ -161,7 +160,11 @@ let mock = makeMockEL()
161
160
 
162
161
  module OuterEventLog = EventLog
163
162
 
164
- module MakeOps = (B: {let name: string}) => {
163
+ module MakeOps = (
164
+ B: {
165
+ let name: string
166
+ },
167
+ ) => {
165
168
  module Spec = AggSpec
166
169
  module EventLog = {
167
170
  module Spec = {
@@ -178,11 +181,11 @@ module MakeOps = (B: {let name: string}) => {
178
181
  ) => promise<result<unit, EventLog.appendError>>,
179
182
  replay: string => promise<array<AggSpec.event>>,
180
183
  replayStream: (string, ~fromSeq: int=?) => Stream.t<AggSpec.event, string, unit>,
181
- appendStream: (int, string, Stream.t<AggSpec.event, string, unit>) => Effect.t<
182
- unit,
184
+ appendStream: (
185
+ int,
183
186
  string,
184
- unit,
185
- >,
187
+ Stream.t<AggSpec.event, string, unit>,
188
+ ) => Effect.t<unit, string, unit>,
186
189
  latestSnapshot: string => promise<result<option<EventLog.snapshot>, string>>,
187
190
  writeSnapshot: (string, EventLog.snapshot) => promise<result<unit, string>>,
188
191
  }
@@ -199,7 +202,9 @@ module MakeOps = (B: {let name: string}) => {
199
202
  }
200
203
  }
201
204
 
202
- module TestOps = MakeOps({let name = "SnapshotMockEventLog"})
205
+ module TestOps = MakeOps({
206
+ let name = "SnapshotMockEventLog"
207
+ })
203
208
  module TestHandler = Aggregate_Callback.Make(AggSpec, TestBehavior, TestOps)
204
209
 
205
210
  // A second behavior with snapshots DISABLED, sharing the same mock, to prove
@@ -225,7 +230,9 @@ module PlainBehavior = {
225
230
  }
226
231
  }
227
232
 
228
- module PlainOps = MakeOps({let name = "PlainMockEventLog"})
233
+ module PlainOps = MakeOps({
234
+ let name = "PlainMockEventLog"
235
+ })
229
236
  module PlainHandler = Aggregate_Callback.Make(AggSpec, PlainBehavior, PlainOps)
230
237
 
231
238
  let makeItem = (~id="agg-1", reference, command): CommandTopic.topicItem<
@@ -253,7 +260,10 @@ describe("Aggregate_Callback — snapshots:", () => {
253
260
  testPromise("writes a snapshot each time an interval boundary is crossed", async () => {
254
261
  // 25 single-event commands → boundaries at 10 and 20 (not 25).
255
262
  for i in 1 to 25 {
256
- let _ = await run(~handler=TestHandler.handleCommands, AggSpec.Add({item: `i${i->Int.toString}`}))
263
+ let _ = await run(
264
+ ~handler=TestHandler.handleCommands,
265
+ AggSpec.Add({item: `i${i->Int.toString}`}),
266
+ )
257
267
  }
258
268
  let _ = await tick()
259
269
  expect(mock.snapshotWriteCount.contents)->toBe(2)
@@ -266,7 +276,10 @@ describe("Aggregate_Callback — snapshots:", () => {
266
276
 
267
277
  testPromise("cold replay seeds from the snapshot and reads only the delta", async () => {
268
278
  for i in 1 to 12 {
269
- let _ = await run(~handler=TestHandler.handleCommands, AggSpec.Add({item: `i${i->Int.toString}`}))
279
+ let _ = await run(
280
+ ~handler=TestHandler.handleCommands,
281
+ AggSpec.Add({item: `i${i->Int.toString}`}),
282
+ )
270
283
  }
271
284
  let _ = await tick()
272
285
  // A snapshot exists at seq 10. Evict the in-process cache to force a cold read.
@@ -282,7 +295,10 @@ describe("Aggregate_Callback — snapshots:", () => {
282
295
 
283
296
  testPromise("state seeded from snapshot equals a full-replay fold", async () => {
284
297
  for i in 1 to 15 {
285
- let _ = await run(~handler=TestHandler.handleCommands, AggSpec.Add({item: `x${i->Int.toString}`}))
298
+ let _ = await run(
299
+ ~handler=TestHandler.handleCommands,
300
+ AggSpec.Add({item: `x${i->Int.toString}`}),
301
+ )
286
302
  }
287
303
  let _ = await tick()
288
304
  // Snapshot-seeded cold read (snapshot at seq 10, delta 10..15).
@@ -292,7 +308,10 @@ describe("Aggregate_Callback — snapshots:", () => {
292
308
  // Force a boundary to capture the seeded state as a fresh snapshot: add up to
293
309
  // seq 20 and compare its item count to the true event count.
294
310
  for i in 16 to 20 {
295
- let _ = await run(~handler=TestHandler.handleCommands, AggSpec.Add({item: `x${i->Int.toString}`}))
311
+ let _ = await run(
312
+ ~handler=TestHandler.handleCommands,
313
+ AggSpec.Add({item: `x${i->Int.toString}`}),
314
+ )
296
315
  }
297
316
  let _ = await tick()
298
317
  switch mock.getSnapshot("agg-1") {
@@ -312,7 +331,10 @@ describe("Aggregate_Callback — snapshots:", () => {
312
331
 
313
332
  testPromise("schema-drift snapshot is ignored → full replay from 0", async () => {
314
333
  for i in 1 to 12 {
315
- let _ = await run(~handler=TestHandler.handleCommands, AggSpec.Add({item: `i${i->Int.toString}`}))
334
+ let _ = await run(
335
+ ~handler=TestHandler.handleCommands,
336
+ AggSpec.Add({item: `i${i->Int.toString}`}),
337
+ )
316
338
  }
317
339
  let _ = await tick()
318
340
  // Corrupt the stored snapshot's hash to simulate a state-shape change.
@@ -329,7 +351,10 @@ describe("Aggregate_Callback — snapshots:", () => {
329
351
 
330
352
  testPromise("snapshot write failure does not fail the command", async () => {
331
353
  for i in 1 to 9 {
332
- let _ = await run(~handler=TestHandler.handleCommands, AggSpec.Add({item: `i${i->Int.toString}`}))
354
+ let _ = await run(
355
+ ~handler=TestHandler.handleCommands,
356
+ AggSpec.Add({item: `i${i->Int.toString}`}),
357
+ )
333
358
  }
334
359
  // The 10th append crosses the boundary; make its snapshot write fail.
335
360
  mock.failNextWrite := true
@@ -344,7 +369,10 @@ describe("Aggregate_Callback — snapshots:", () => {
344
369
 
345
370
  testPromise("disabled aggregate does zero snapshot reads and writes", async () => {
346
371
  for i in 1 to 12 {
347
- let _ = await run(~handler=PlainHandler.handleCommands, AggSpec.Add({item: `i${i->Int.toString}`}))
372
+ let _ = await run(
373
+ ~handler=PlainHandler.handleCommands,
374
+ AggSpec.Add({item: `i${i->Int.toString}`}),
375
+ )
348
376
  }
349
377
  let _ = await tick()
350
378
  PlainHandler.resetCache()
@@ -40,8 +40,9 @@ describe("Api_Ids.encode / decode", () => {
40
40
 
41
41
  describe("Api_Ids.alternateKey — the fallback a door tries on a miss", () => {
42
42
  testSync("a global id offers the storage key inside it", () =>
43
- expect(Api_Ids.alternateKey(Api_Ids.encode(~typeName="Catalog_Product", ~localId="p-1")))
44
- ->toEqual(Some("p-1"))
43
+ expect(
44
+ Api_Ids.alternateKey(Api_Ids.encode(~typeName="Catalog_Product", ~localId="p-1")),
45
+ )->toEqual(Some("p-1"))
45
46
  )
46
47
 
47
48
  testSync("a plain key offers nothing, so the lookup is never retried", () =>
@@ -83,8 +84,13 @@ describe("stamping an id onto a row leaves the stored row alone", () => {
83
84
  JSON.Encode.object(obj)
84
85
  }
85
86
  let idOf = j =>
86
- j->JSON.Decode.object->Option.flatMap(d => d->Dict.get("id"))->Option.flatMap(JSON.Decode.string)
87
- expect(idOf(stamped))->toEqual(Some(Api_Ids.encode(~typeName="Ordering_Customer", ~localId="cust-42")))
87
+ j
88
+ ->JSON.Decode.object
89
+ ->Option.flatMap(d => d->Dict.get("id"))
90
+ ->Option.flatMap(JSON.Decode.string)
91
+ expect(idOf(stamped))->toEqual(
92
+ Some(Api_Ids.encode(~typeName="Ordering_Customer", ~localId="cust-42")),
93
+ )
88
94
  // The stored row still carries its storage key.
89
95
  expect(idOf(row))->toEqual(Some("cust-42"))
90
96
  })
@@ -21,54 +21,66 @@ describe("a field marker on a branded semantic:", () => {
21
21
  }
22
22
 
23
23
  describe("@owner on an Email field:", () => {
24
- testSync("marks the field as the owner", () =>
25
- expect(fieldOf("email")->Option.mapOr(false, Reventless.Owner.isFieldOwner))->toBe(true)
24
+ testSync(
25
+ "marks the field as the owner",
26
+ () =>
27
+ expect(fieldOf("email")->Option.mapOr(false, Reventless.Owner.isFieldOwner))->toBe(true),
26
28
  )
27
29
 
28
- testSync("keeps the email semantic", () =>
29
- expect(
30
- fieldOf("email")
31
- ->Option.flatMap(Reventless.Semantic.getFrom)
32
- ->Option.map(s => s.id),
33
- )->toEqual(Some("email"))
30
+ testSync(
31
+ "keeps the email semantic",
32
+ () =>
33
+ expect(
34
+ fieldOf("email")
35
+ ->Option.flatMap(Reventless.Semantic.getFrom)
36
+ ->Option.map(s => s.id),
37
+ )->toEqual(Some("email")),
34
38
  )
35
39
 
36
40
  // The regression a substituting fix would land, and it lands in silence:
37
41
  // the row still scopes to its owner, and the field accepts anything.
38
- testSync("still rejects what is not an address", () => {
39
- let parses = raw =>
40
- switch fieldOf("email") {
41
- | Some(schema) =>
42
- switch raw->JSON.Encode.string->S.parseOrThrow(~to=schema) {
43
- | _ => true
44
- | exception _ => false
42
+ testSync(
43
+ "still rejects what is not an address",
44
+ () => {
45
+ let parses = raw =>
46
+ switch fieldOf("email") {
47
+ | Some(schema) =>
48
+ switch raw->JSON.Encode.string->S.parseOrThrow(~to=schema) {
49
+ | _ => true
50
+ | exception _ => false
51
+ }
52
+ | None => false
45
53
  }
46
- | None => false
47
- }
48
- expect((parses("buyer@example.com"), parses("buyer")))->toEqual((true, false))
49
- })
54
+ expect((parses("buyer@example.com"), parses("buyer")))->toEqual((true, false))
55
+ },
56
+ )
50
57
  })
51
58
 
52
59
  describe("@displayName on a DateTime field:", () => {
53
- testSync("names the row by it", () =>
54
- expect(
55
- S.Metadata.get(stateSchema, ~id=Reventless.DisplayName.displayNameId)->Option.map(d =>
56
- d.fields
57
- ),
58
- )->toEqual(Some(["openedAt"]))
60
+ testSync(
61
+ "names the row by it",
62
+ () =>
63
+ expect(
64
+ S.Metadata.get(stateSchema, ~id=Reventless.DisplayName.displayNameId)->Option.map(
65
+ d => d.fields,
66
+ ),
67
+ )->toEqual(Some(["openedAt"])),
59
68
  )
60
69
 
61
- testSync("and the instant grammar survives", () => {
62
- let parses = raw =>
63
- switch fieldOf("openedAt") {
64
- | Some(schema) =>
65
- switch raw->JSON.Encode.string->S.parseOrThrow(~to=schema) {
66
- | _ => true
67
- | exception _ => false
70
+ testSync(
71
+ "and the instant grammar survives",
72
+ () => {
73
+ let parses = raw =>
74
+ switch fieldOf("openedAt") {
75
+ | Some(schema) =>
76
+ switch raw->JSON.Encode.string->S.parseOrThrow(~to=schema) {
77
+ | _ => true
78
+ | exception _ => false
79
+ }
80
+ | None => false
68
81
  }
69
- | None => false
70
- }
71
- expect((parses("2026-03-02T09:00:00Z"), parses("tomorrow")))->toEqual((true, false))
72
- })
82
+ expect((parses("2026-03-02T09:00:00Z"), parses("tomorrow")))->toEqual((true, false))
83
+ },
84
+ )
73
85
  })
74
86
  })
@@ -101,8 +101,8 @@ describe("the Geolocation semantic emits its three member types", () => {
101
101
  })
102
102
 
103
103
  testSync("the field is typed as the union", () => {
104
- expect(typeDefFor("type SemanticGeoCustomer")->String.includes("geolocation: Geolocation"))->toBe(
105
- true,
106
- )
104
+ expect(
105
+ typeDefFor("type SemanticGeoCustomer")->String.includes("geolocation: Geolocation"),
106
+ )->toBe(true)
107
107
  })
108
108
  })