@reventlessdev/reventless-local 3.0.0-alpha.113

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 (334) hide show
  1. package/CHANGELOG.md +1197 -0
  2. package/LICENSE +202 -0
  3. package/__mocks__/emptyModule.js +2 -0
  4. package/__mocks__/nodeSqlite.mjs +6 -0
  5. package/package.json +67 -0
  6. package/rescript.json +39 -0
  7. package/src/Platform.res +2162 -0
  8. package/src/Platform.res.mjs +3389 -0
  9. package/src/adapter/Api/LocalGraphQL_Adapter.res +29 -0
  10. package/src/adapter/Api/LocalGraphQL_Adapter.res.mjs +26 -0
  11. package/src/adapter/Api/LocalGraphQL_SubscriptionResolvers.res +146 -0
  12. package/src/adapter/Api/LocalGraphQL_SubscriptionResolvers.res.mjs +88 -0
  13. package/src/adapter/Auth/Auth_GraphqlContext.res +83 -0
  14. package/src/adapter/Auth/Auth_GraphqlContext.res.mjs +76 -0
  15. package/src/adapter/Auth/LocalAuth.res +239 -0
  16. package/src/adapter/Auth/LocalAuth.res.mjs +247 -0
  17. package/src/adapter/Auth/UserStore.res +134 -0
  18. package/src/adapter/Auth/UserStore.res.mjs +146 -0
  19. package/src/adapter/Backend.res +46 -0
  20. package/src/adapter/Backend.res.mjs +66 -0
  21. package/src/adapter/BackendState.res +34 -0
  22. package/src/adapter/BackendState.res.mjs +42 -0
  23. package/src/adapter/Cloner/LocalClonerRunner.res +13 -0
  24. package/src/adapter/Cloner/LocalClonerRunner.res.mjs +12 -0
  25. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +329 -0
  26. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res.mjs +301 -0
  27. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +76 -0
  28. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res.mjs +57 -0
  29. package/src/adapter/CommandGenerator/LocalCommandGeneratorResolvers.res +19 -0
  30. package/src/adapter/CommandGenerator/LocalCommandGeneratorResolvers.res.mjs +19 -0
  31. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +104 -0
  32. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res.mjs +82 -0
  33. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +32 -0
  34. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res.mjs +38 -0
  35. package/src/adapter/Counter/LocalCounterHandler.res +42 -0
  36. package/src/adapter/Counter/LocalCounterHandler.res.mjs +45 -0
  37. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +131 -0
  38. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res.mjs +140 -0
  39. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +334 -0
  40. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +299 -0
  41. package/src/adapter/DomainGraphQL_Server.res +565 -0
  42. package/src/adapter/DomainGraphQL_Server.res.mjs +576 -0
  43. package/src/adapter/DomainMCP_Server.res +369 -0
  44. package/src/adapter/DomainMCP_Server.res.mjs +358 -0
  45. package/src/adapter/EventCollector/LocalEventCollectorChannel.res +87 -0
  46. package/src/adapter/EventCollector/LocalEventCollectorChannel.res.mjs +45 -0
  47. package/src/adapter/EventLog/EventLogStorage_InMemory.res +105 -0
  48. package/src/adapter/EventLog/EventLogStorage_InMemory.res.mjs +117 -0
  49. package/src/adapter/EventLog/EventLogStorage_Sqlite.res +145 -0
  50. package/src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs +155 -0
  51. package/src/adapter/EventTopic/LocalEventTopicPublisher.res +36 -0
  52. package/src/adapter/EventTopic/LocalEventTopicPublisher.res.mjs +31 -0
  53. package/src/adapter/GraphQL_Server.res +6 -0
  54. package/src/adapter/GraphQL_Server.res.mjs +154 -0
  55. package/src/adapter/GraphQL_ServerInstance.res +310 -0
  56. package/src/adapter/GraphQL_ServerInstance.res.mjs +257 -0
  57. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +57 -0
  58. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res.mjs +34 -0
  59. package/src/adapter/LocalBus.res +498 -0
  60. package/src/adapter/LocalBus.res.mjs +1011 -0
  61. package/src/adapter/LocalPluginSpec.res +16 -0
  62. package/src/adapter/LocalPluginSpec.res.mjs +33 -0
  63. package/src/adapter/LocalSideEffectHandler.res +44 -0
  64. package/src/adapter/LocalSideEffectHandler.res.mjs +34 -0
  65. package/src/adapter/MCP_Server.res +4 -0
  66. package/src/adapter/MCP_Server.res.mjs +67 -0
  67. package/src/adapter/MCP_ServerInstance.res +362 -0
  68. package/src/adapter/MCP_ServerInstance.res.mjs +313 -0
  69. package/src/adapter/PlatformGraphQL_Server.res +75 -0
  70. package/src/adapter/PlatformGraphQL_Server.res.mjs +84 -0
  71. package/src/adapter/PlatformMCP_Server.res +23 -0
  72. package/src/adapter/PlatformMCP_Server.res.mjs +46 -0
  73. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +793 -0
  74. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs +569 -0
  75. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +242 -0
  76. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res.mjs +241 -0
  77. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +339 -0
  78. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res.mjs +318 -0
  79. package/src/adapter/QueryDb/SortKey_Filter.res +48 -0
  80. package/src/adapter/QueryDb/SortKey_Filter.res.mjs +46 -0
  81. package/src/adapter/QueryEngine/LocalQueryEngine.res +57 -0
  82. package/src/adapter/QueryEngine/LocalQueryEngine.res.mjs +56 -0
  83. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +91 -0
  84. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res.mjs +50 -0
  85. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +47 -0
  86. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res.mjs +37 -0
  87. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +11 -0
  88. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res.mjs +30 -0
  89. package/src/adapter/Runtime/LocalRuntimeEnvironment.res +54 -0
  90. package/src/adapter/Runtime/LocalRuntimeEnvironment.res.mjs +40 -0
  91. package/src/adapter/Scheduler/LocalScheduledPublisher.res +102 -0
  92. package/src/adapter/Scheduler/LocalScheduledPublisher.res.mjs +84 -0
  93. package/src/adapter/SqliteDriver.res +52 -0
  94. package/src/adapter/SqliteDriver.res.mjs +76 -0
  95. package/src/adapter/SqliteDriver.resi +31 -0
  96. package/src/adapter/Task/LocalTaskBucket.res +75 -0
  97. package/src/adapter/Task/LocalTaskBucket.res.mjs +48 -0
  98. package/src/adapter/Task/TaskBucket_Sqlite.res +47 -0
  99. package/src/adapter/Task/TaskBucket_Sqlite.res.mjs +40 -0
  100. package/src/components/Aggregate_Builder.res +55 -0
  101. package/src/components/Aggregate_Builder.res.mjs +140 -0
  102. package/src/components/AutomationSlice_Builder.res +41 -0
  103. package/src/components/AutomationSlice_Builder.res.mjs +57 -0
  104. package/src/components/Counter_Builder.res +14 -0
  105. package/src/components/Counter_Builder.res.mjs +32 -0
  106. package/src/components/DcbEventLog_Builder.res +18 -0
  107. package/src/components/DcbEventLog_Builder.res.mjs +24 -0
  108. package/src/components/ExtensionPoint_Builder.res +25 -0
  109. package/src/components/ExtensionPoint_Builder.res.mjs +44 -0
  110. package/src/components/InboundTranslationSlice_Builder.res +34 -0
  111. package/src/components/InboundTranslationSlice_Builder.res.mjs +45 -0
  112. package/src/components/OutboundTranslationSlice_Builder.res +43 -0
  113. package/src/components/OutboundTranslationSlice_Builder.res.mjs +59 -0
  114. package/src/components/Plugin_Builder.res +37 -0
  115. package/src/components/Plugin_Builder.res.mjs +67 -0
  116. package/src/components/ReadModel_Builder.res +47 -0
  117. package/src/components/ReadModel_Builder.res.mjs +54 -0
  118. package/src/components/StateChangeSlice_Builder.res +19 -0
  119. package/src/components/StateChangeSlice_Builder.res.mjs +21 -0
  120. package/src/components/StateViewSlice_Builder.res +42 -0
  121. package/src/components/StateViewSlice_Builder.res.mjs +58 -0
  122. package/src/components/Task_Builder.res +28 -0
  123. package/src/components/Task_Builder.res.mjs +41 -0
  124. package/src/reexport/CommandTopic.res +3 -0
  125. package/src/reexport/CommandTopic.res.mjs +55 -0
  126. package/src/test/Mocks/MockDcbEventLogStorage.res +136 -0
  127. package/src/test/Mocks/MockDcbEventLogStorage.res.mjs +146 -0
  128. package/src/test/Mocks/MockEventLogStorage.res +57 -0
  129. package/src/test/Mocks/MockEventLogStorage.res.mjs +65 -0
  130. package/src/test/Mocks/MockPublisher.res +29 -0
  131. package/src/test/Mocks/MockPublisher.res.mjs +28 -0
  132. package/src/test/Mocks/MockQueryDbStorage.res +104 -0
  133. package/src/test/Mocks/MockQueryDbStorage.res.mjs +136 -0
  134. package/src/test/TestRunner.res +96 -0
  135. package/src/test/TestRunner.res.mjs +71 -0
  136. package/tests/SplitApiFixtures.res +84 -0
  137. package/tests/SplitApiFixtures.res.mjs +88 -0
  138. package/tests/SplitApiTest.res +102 -0
  139. package/tests/SplitApiTest.res.mjs +82 -0
  140. package/tests/TestFixtures.res +54 -0
  141. package/tests/TestFixtures.res.mjs +65 -0
  142. package/tests/adapter/BackendParityTest.res +94 -0
  143. package/tests/adapter/BackendParityTest.res.mjs +96 -0
  144. package/tests/adapter/CollectNEventsTest.res +82 -0
  145. package/tests/adapter/CollectNEventsTest.res.mjs +83 -0
  146. package/tests/adapter/CommandAuthorizationTest.res +200 -0
  147. package/tests/adapter/CommandAuthorizationTest.res.mjs +190 -0
  148. package/tests/adapter/CommandTopicChannelTest.res +174 -0
  149. package/tests/adapter/CommandTopicChannelTest.res.mjs +170 -0
  150. package/tests/adapter/CounterHandlerTest.res +113 -0
  151. package/tests/adapter/CounterHandlerTest.res.mjs +96 -0
  152. package/tests/adapter/DcbEventLogStorageSqliteTest.res +157 -0
  153. package/tests/adapter/DcbEventLogStorageSqliteTest.res.mjs +165 -0
  154. package/tests/adapter/DcbEventLogStorageTest.res +187 -0
  155. package/tests/adapter/DcbEventLogStorageTest.res.mjs +195 -0
  156. package/tests/adapter/EventCollectorChannelTest.res +166 -0
  157. package/tests/adapter/EventCollectorChannelTest.res.mjs +178 -0
  158. package/tests/adapter/EventLogStorageSqliteTest.res +105 -0
  159. package/tests/adapter/EventLogStorageSqliteTest.res.mjs +116 -0
  160. package/tests/adapter/EventTapTest.res +102 -0
  161. package/tests/adapter/EventTapTest.res.mjs +94 -0
  162. package/tests/adapter/EventTopicPublisherTest.res +76 -0
  163. package/tests/adapter/EventTopicPublisherTest.res.mjs +86 -0
  164. package/tests/adapter/GraphQL_SchemaInspectorTest.res +763 -0
  165. package/tests/adapter/GraphQL_SchemaInspectorTest.res.mjs +578 -0
  166. package/tests/adapter/GraphQL_SubscriptionResolversTest.res +161 -0
  167. package/tests/adapter/GraphQL_SubscriptionResolversTest.res.mjs +134 -0
  168. package/tests/adapter/HeartbeatRunnerTest.res +136 -0
  169. package/tests/adapter/HeartbeatRunnerTest.res.mjs +96 -0
  170. package/tests/adapter/LocalAuthHttpTest.res +224 -0
  171. package/tests/adapter/LocalAuthHttpTest.res.mjs +237 -0
  172. package/tests/adapter/LocalAuthLoginTest.res +180 -0
  173. package/tests/adapter/LocalAuthLoginTest.res.mjs +207 -0
  174. package/tests/adapter/LocalAuthTest.res +106 -0
  175. package/tests/adapter/LocalAuthTest.res.mjs +145 -0
  176. package/tests/adapter/LocalAuthUserStoreTest.res +172 -0
  177. package/tests/adapter/LocalAuthUserStoreTest.res.mjs +208 -0
  178. package/tests/adapter/LocalBusBoundedTest.res +157 -0
  179. package/tests/adapter/LocalBusBoundedTest.res.mjs +168 -0
  180. package/tests/adapter/LocalBusPubSubTest.res +81 -0
  181. package/tests/adapter/LocalBusPubSubTest.res.mjs +81 -0
  182. package/tests/adapter/QueryDbGsiTtlTest.res +268 -0
  183. package/tests/adapter/QueryDbGsiTtlTest.res.mjs +209 -0
  184. package/tests/adapter/QueryDbListResolverTest.res +361 -0
  185. package/tests/adapter/QueryDbListResolverTest.res.mjs +426 -0
  186. package/tests/adapter/QueryDbStorageSqliteTest.res +159 -0
  187. package/tests/adapter/QueryDbStorageSqliteTest.res.mjs +126 -0
  188. package/tests/adapter/QueryDbStorageTest.res +171 -0
  189. package/tests/adapter/QueryDbStorageTest.res.mjs +170 -0
  190. package/tests/adapter/QueryEngineTest.res +152 -0
  191. package/tests/adapter/QueryEngineTest.res.mjs +148 -0
  192. package/tests/adapter/ScheduledPublisherTest.res +199 -0
  193. package/tests/adapter/ScheduledPublisherTest.res.mjs +203 -0
  194. package/tests/adapter/SortKey_FilterTest.res +103 -0
  195. package/tests/adapter/SortKey_FilterTest.res.mjs +135 -0
  196. package/tests/adapter/SqliteDriverTest.res +86 -0
  197. package/tests/adapter/SqliteDriverTest.res.mjs +101 -0
  198. package/tests/adapter/TaskBucketSqliteTest.res +44 -0
  199. package/tests/adapter/TaskBucketSqliteTest.res.mjs +40 -0
  200. package/tests/adapter/TaskBucketTest.res +106 -0
  201. package/tests/adapter/TaskBucketTest.res.mjs +118 -0
  202. package/tests/components/aggregate/AggregateFixtures.res +78 -0
  203. package/tests/components/aggregate/AggregateFixtures.res.mjs +109 -0
  204. package/tests/components/aggregate/AggregateTest.res +129 -0
  205. package/tests/components/aggregate/AggregateTest.res.mjs +129 -0
  206. package/tests/components/automationslice/AutomationSliceCallbackTest.res +212 -0
  207. package/tests/components/automationslice/AutomationSliceCallbackTest.res.mjs +233 -0
  208. package/tests/components/automationslice/AutomationSliceFixtures.res +189 -0
  209. package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +276 -0
  210. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +289 -0
  211. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +453 -0
  212. package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res +47 -0
  213. package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res.mjs +31 -0
  214. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +213 -0
  215. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +268 -0
  216. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +118 -0
  217. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res.mjs +99 -0
  218. package/tests/components/commandgenerator/CommandGeneratorFixtures.res +73 -0
  219. package/tests/components/commandgenerator/CommandGeneratorFixtures.res.mjs +109 -0
  220. package/tests/components/commandgenerator/CommandGeneratorTest.res +43 -0
  221. package/tests/components/commandgenerator/CommandGeneratorTest.res.mjs +46 -0
  222. package/tests/components/commandtopic/CommandTopicFixtures.res +37 -0
  223. package/tests/components/commandtopic/CommandTopicFixtures.res.mjs +68 -0
  224. package/tests/components/commandtopic/CommandTopicStreamFixtures.res +43 -0
  225. package/tests/components/commandtopic/CommandTopicStreamFixtures.res.mjs +91 -0
  226. package/tests/components/commandtopic/CommandTopicStreamTest.res +30 -0
  227. package/tests/components/commandtopic/CommandTopicStreamTest.res.mjs +35 -0
  228. package/tests/components/commandtopic/CommandTopicTest.res +55 -0
  229. package/tests/components/commandtopic/CommandTopicTest.res.mjs +62 -0
  230. package/tests/components/counter/CounterFixtures.res +42 -0
  231. package/tests/components/counter/CounterFixtures.res.mjs +34 -0
  232. package/tests/components/counter/CounterTest.res +46 -0
  233. package/tests/components/counter/CounterTest.res.mjs +61 -0
  234. package/tests/components/dcb/DcbCrossPartitionFixtures.res +170 -0
  235. package/tests/components/dcb/DcbCrossPartitionFixtures.res.mjs +276 -0
  236. package/tests/components/dcb/DcbCrossPartitionReadTest.res +68 -0
  237. package/tests/components/dcb/DcbCrossPartitionReadTest.res.mjs +78 -0
  238. package/tests/components/dcb/DcbEventLogAppendStreamTest.res +72 -0
  239. package/tests/components/dcb/DcbEventLogAppendStreamTest.res.mjs +82 -0
  240. package/tests/components/dcb/DcbEventLogStreamTest.res +103 -0
  241. package/tests/components/dcb/DcbEventLogStreamTest.res.mjs +91 -0
  242. package/tests/components/dcb/DcbFixtures.res +145 -0
  243. package/tests/components/dcb/DcbFixtures.res.mjs +221 -0
  244. package/tests/components/dcb/DcbTest.res +55 -0
  245. package/tests/components/dcb/DcbTest.res.mjs +55 -0
  246. package/tests/components/eventcollector/EventCollectorFixtures.res +42 -0
  247. package/tests/components/eventcollector/EventCollectorFixtures.res.mjs +49 -0
  248. package/tests/components/eventcollector/EventCollectorTest.res +37 -0
  249. package/tests/components/eventcollector/EventCollectorTest.res.mjs +36 -0
  250. package/tests/components/eventlog/EventLogAppendStreamTest.res +93 -0
  251. package/tests/components/eventlog/EventLogAppendStreamTest.res.mjs +113 -0
  252. package/tests/components/eventlog/EventLogConflictTest.res +86 -0
  253. package/tests/components/eventlog/EventLogConflictTest.res.mjs +81 -0
  254. package/tests/components/eventlog/EventLogFixtures.res +52 -0
  255. package/tests/components/eventlog/EventLogFixtures.res.mjs +80 -0
  256. package/tests/components/eventlog/EventLogStreamTest.res +98 -0
  257. package/tests/components/eventlog/EventLogStreamTest.res.mjs +142 -0
  258. package/tests/components/eventlog/EventLogTest.res +53 -0
  259. package/tests/components/eventlog/EventLogTest.res.mjs +74 -0
  260. package/tests/components/eventtopic/EventTopicFixtures.res +47 -0
  261. package/tests/components/eventtopic/EventTopicFixtures.res.mjs +77 -0
  262. package/tests/components/eventtopic/EventTopicStreamFixtures.res +27 -0
  263. package/tests/components/eventtopic/EventTopicStreamFixtures.res.mjs +62 -0
  264. package/tests/components/eventtopic/EventTopicStreamTest.res +35 -0
  265. package/tests/components/eventtopic/EventTopicStreamTest.res.mjs +44 -0
  266. package/tests/components/eventtopic/EventTopicTest.res +35 -0
  267. package/tests/components/eventtopic/EventTopicTest.res.mjs +43 -0
  268. package/tests/components/extensionpoint/ExtensionPointFixtures.res +145 -0
  269. package/tests/components/extensionpoint/ExtensionPointFixtures.res.mjs +188 -0
  270. package/tests/components/extensionpoint/ExtensionPointTest.res +62 -0
  271. package/tests/components/extensionpoint/ExtensionPointTest.res.mjs +55 -0
  272. package/tests/components/heartbeat/HeartbeatFixtures.res +48 -0
  273. package/tests/components/heartbeat/HeartbeatFixtures.res.mjs +46 -0
  274. package/tests/components/heartbeat/HeartbeatTest.res +67 -0
  275. package/tests/components/heartbeat/HeartbeatTest.res.mjs +65 -0
  276. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +241 -0
  277. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +239 -0
  278. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +36 -0
  279. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +73 -0
  280. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +191 -0
  281. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +297 -0
  282. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +78 -0
  283. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +137 -0
  284. package/tests/components/querydb/QueryDbFixtures.res +39 -0
  285. package/tests/components/querydb/QueryDbFixtures.res.mjs +73 -0
  286. package/tests/components/querydb/QueryDbSubIdFixtures.res +44 -0
  287. package/tests/components/querydb/QueryDbSubIdFixtures.res.mjs +80 -0
  288. package/tests/components/querydb/QueryDbSubIdTest.res +104 -0
  289. package/tests/components/querydb/QueryDbSubIdTest.res.mjs +104 -0
  290. package/tests/components/querydb/QueryDbTest.res +81 -0
  291. package/tests/components/querydb/QueryDbTest.res.mjs +126 -0
  292. package/tests/components/readmodel/DcbReadModelE2EFixtures.res +215 -0
  293. package/tests/components/readmodel/DcbReadModelE2EFixtures.res.mjs +308 -0
  294. package/tests/components/readmodel/DcbReadModelE2ETest.res +45 -0
  295. package/tests/components/readmodel/DcbReadModelE2ETest.res.mjs +37 -0
  296. package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res +88 -0
  297. package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res.mjs +152 -0
  298. package/tests/components/readmodel/MixedSourceReadModelFixtures.res +181 -0
  299. package/tests/components/readmodel/MixedSourceReadModelFixtures.res.mjs +277 -0
  300. package/tests/components/readmodel/MixedSourceReadModelTest.res +61 -0
  301. package/tests/components/readmodel/MixedSourceReadModelTest.res.mjs +68 -0
  302. package/tests/components/readmodel/ReadModelFixtures.res +138 -0
  303. package/tests/components/readmodel/ReadModelFixtures.res.mjs +169 -0
  304. package/tests/components/readmodel/ReadModelTest.res +46 -0
  305. package/tests/components/readmodel/ReadModelTest.res.mjs +36 -0
  306. package/tests/components/scheduler/SchedulerFixtures.res +59 -0
  307. package/tests/components/scheduler/SchedulerFixtures.res.mjs +63 -0
  308. package/tests/components/scheduler/SchedulerTest.res +76 -0
  309. package/tests/components/scheduler/SchedulerTest.res.mjs +86 -0
  310. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +133 -0
  311. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +149 -0
  312. package/tests/components/sideeffecthandler/SideEffectHandlerTest.res +39 -0
  313. package/tests/components/sideeffecthandler/SideEffectHandlerTest.res.mjs +28 -0
  314. package/tests/components/stateviewslice/StateViewSliceFixtures.res +117 -0
  315. package/tests/components/stateviewslice/StateViewSliceFixtures.res.mjs +188 -0
  316. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +117 -0
  317. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res.mjs +183 -0
  318. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +78 -0
  319. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res.mjs +107 -0
  320. package/tests/components/stateviewslice/StateViewSliceTest.res +59 -0
  321. package/tests/components/stateviewslice/StateViewSliceTest.res.mjs +72 -0
  322. package/tests/components/task/TaskFixtures.res +87 -0
  323. package/tests/components/task/TaskFixtures.res.mjs +82 -0
  324. package/tests/components/task/TaskTest.res +98 -0
  325. package/tests/components/task/TaskTest.res.mjs +46 -0
  326. package/tests/plugin/PluginBehavior_GWT.res +146 -0
  327. package/tests/plugin/PluginBehavior_GWT.res.mjs +281 -0
  328. package/tests/plugin/Plugin_Fixtures.res +61 -0
  329. package/tests/plugin/Plugin_Fixtures.res.mjs +105 -0
  330. package/tests/plugin/PluginsProjection_GWT.res +95 -0
  331. package/tests/plugin/PluginsProjection_GWT.res.mjs +120 -0
  332. package/tests/plugin/UIFragmentRegistryProjection_GWT.res +72 -0
  333. package/tests/plugin/UIFragmentRegistryProjection_GWT.res.mjs +117 -0
  334. package/tests/setup/sqliteGlobal.cjs +12 -0
@@ -0,0 +1,78 @@
1
+ // E2E test fixtures for the Aggregate E2E test.
2
+ // Contains specs, behavior, bus setup, and shared test data.
3
+
4
+ // ─────────────────────────────────────────────────────────────
5
+ // Simple Item aggregate spec
6
+ // ─────────────────────────────────────────────────────────────
7
+
8
+ module ItemSpec = {
9
+ module Id = Reventless.Id.String
10
+ let name = "TestItem"
11
+
12
+ @schema
13
+ type command = CreateItem({name: string})
14
+
15
+ @schema
16
+ type event = ItemCreated({name: string})
17
+
18
+ @schema
19
+ type error = AlreadyExists
20
+
21
+ let moduleUrl: string = %raw(`import.meta.url`)
22
+ }
23
+
24
+ // ─────────────────────────────────────────────────────────────
25
+ // Item behavior: CreateItem → ItemCreated
26
+ // ─────────────────────────────────────────────────────────────
27
+
28
+ module ItemBehavior: ReventlessCore.Behavior.T with module Spec := ItemSpec = {
29
+ type state = bool // true = item exists
30
+
31
+ let initialState = false
32
+
33
+ let moduleUrl: string = %raw(`import.meta.url`)
34
+
35
+ let evolve = (_state, _event: ItemSpec.event) => true
36
+
37
+ let decide = (state, command: ItemSpec.command) =>
38
+ if state {
39
+ Error(ItemSpec.AlreadyExists)
40
+ } else {
41
+ switch command {
42
+ | ItemSpec.CreateItem({name}) => Ok([ItemSpec.ItemCreated({name: name})])
43
+ }
44
+ }
45
+ }
46
+
47
+ // ─────────────────────────────────────────────────────────────
48
+ // Isolated bus for the E2E test (shared across all tests here)
49
+ // ─────────────────────────────────────────────────────────────
50
+
51
+ module Bus = LocalBus.Make()
52
+
53
+ // Capture events published to the aggregate's event topic.
54
+ // Topic name = Spec.name ++ "Aggr" ++ "EventTopic" = "TestItemAggrEventTopic"
55
+ let capturedEventCount: ref<int> = ref(0)
56
+
57
+ let _ = Bus.subscribeToEvents("TestItemAggrEventTopic", async (_, _, _) => {
58
+ capturedEventCount := capturedEventCount.contents + 1
59
+ })
60
+
61
+ // ─────────────────────────────────────────────────────────────
62
+ // Activate Pulumi mock mode (must be before any Component.make)
63
+ // ─────────────────────────────────────────────────────────────
64
+
65
+ let _ = TestRunner.setup()
66
+
67
+ // ─────────────────────────────────────────────────────────────
68
+ // Build the aggregate (creates Pulumi components + wires bus)
69
+ // ─────────────────────────────────────────────────────────────
70
+
71
+ module ItemAggregateMaker = Aggregate_Builder.Make(Bus)
72
+ module ItemAgg = ItemAggregateMaker.Make(
73
+ ItemSpec,
74
+ ItemBehavior,
75
+ ReventlessInfra.NoEventMappings.Make(ItemSpec),
76
+ )
77
+
78
+ let agg = ItemAgg.make(~api=())
@@ -0,0 +1,109 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
5
+ import * as LocalBus$ReventlessLocal from "../../../src/adapter/LocalBus.res.mjs";
6
+ import * as TestRunner$ReventlessLocal from "../../../src/test/TestRunner.res.mjs";
7
+ import * as NoEventMappings$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/NoEventMappings.res.mjs";
8
+ import * as Aggregate_Builder$ReventlessLocal from "../../../src/components/Aggregate_Builder.res.mjs";
9
+
10
+ let name = "TestItem";
11
+
12
+ let commandSchema = S.schema(s => ({
13
+ TAG: "CreateItem",
14
+ name: s.m(S.string)
15
+ }));
16
+
17
+ let eventSchema = S.schema(s => ({
18
+ TAG: "ItemCreated",
19
+ name: s.m(S.string)
20
+ }));
21
+
22
+ let errorSchema = S.literal("AlreadyExists");
23
+
24
+ let moduleUrl = import.meta.url;
25
+
26
+ function commandAuthorization(param) {
27
+ return "AllowAuthenticated";
28
+ }
29
+
30
+ let ItemSpec = {
31
+ Id: undefined,
32
+ name: name,
33
+ commandSchema: commandSchema,
34
+ eventSchema: eventSchema,
35
+ errorSchema: errorSchema,
36
+ moduleUrl: moduleUrl,
37
+ commandAuthorization: commandAuthorization
38
+ };
39
+
40
+ let moduleUrl$1 = import.meta.url;
41
+
42
+ function evolve(_state, _event) {
43
+ return true;
44
+ }
45
+
46
+ function decide(state, command) {
47
+ if (state) {
48
+ return {
49
+ TAG: "Error",
50
+ _0: "AlreadyExists"
51
+ };
52
+ } else {
53
+ return {
54
+ TAG: "Ok",
55
+ _0: [{
56
+ TAG: "ItemCreated",
57
+ name: command.name
58
+ }]
59
+ };
60
+ }
61
+ }
62
+
63
+ let ItemBehavior = {
64
+ initialState: false,
65
+ evolve: evolve,
66
+ decide: decide,
67
+ moduleUrl: moduleUrl$1
68
+ };
69
+
70
+ let Bus = LocalBus$ReventlessLocal.Make({});
71
+
72
+ let capturedEventCount = {
73
+ contents: 0
74
+ };
75
+
76
+ Bus.subscribeToEvents("TestItemAggrEventTopic", async (param, param$1, param$2) => {
77
+ capturedEventCount.contents = capturedEventCount.contents + 1 | 0;
78
+ });
79
+
80
+ TestRunner$ReventlessLocal.setup();
81
+
82
+ let ItemAggregateMaker = Aggregate_Builder$ReventlessLocal.Make(Bus);
83
+
84
+ let ItemAgg = ItemAggregateMaker.Make({
85
+ Id: Id$Reventless.$$String,
86
+ name: name,
87
+ eventSchema: eventSchema,
88
+ errorSchema: errorSchema,
89
+ commandSchema: commandSchema,
90
+ moduleUrl: moduleUrl,
91
+ commandAuthorization: commandAuthorization
92
+ })(ItemBehavior)(NoEventMappings$ReventlessInfra.Make({
93
+ name: name,
94
+ Id: Id$Reventless.$$String,
95
+ commandSchema: commandSchema
96
+ }));
97
+
98
+ let agg = ItemAgg.make(undefined, undefined);
99
+
100
+ export {
101
+ ItemSpec,
102
+ ItemBehavior,
103
+ Bus,
104
+ capturedEventCount,
105
+ ItemAggregateMaker,
106
+ ItemAgg,
107
+ agg,
108
+ }
109
+ /* commandSchema Not a pure module */
@@ -0,0 +1,129 @@
1
+ // E2E test for reventless-local package.
2
+ // Verifies the full aggregate command → event flow using the in-memory bus.
3
+
4
+ open TestFixtures
5
+ open JestGlobals
6
+ open AggregateFixtures
7
+
8
+ describe("LocalBus", () => {
9
+ testPromise("publishes events to all subscribers", async () => {
10
+ module TestBus = LocalBus.Make()
11
+ let count: ref<int> = ref(0)
12
+ TestBus.subscribeToEvents("t1", async (_, _, _) => {
13
+ count := count.contents + 1
14
+ })
15
+ TestBus.subscribeToEvents("t1", async (_, _, _) => {
16
+ count := count.contents + 1
17
+ })
18
+ await TestBus.publishEvent("t1", "memory:InMemory", testMeta, JSON.Null)
19
+ expect(count.contents)->toBe(2)
20
+ })
21
+
22
+ testPromise("dispatches commands to registered handler", async () => {
23
+ module TestBus = LocalBus.Make()
24
+ let received: ref<option<string>> = ref(None)
25
+ TestBus.registerCommandHandler("cmd1", async (json, _) => {
26
+ received := switch json {
27
+ | JSON.String(s) => Some(s)
28
+ | _ => None
29
+ }
30
+ })
31
+ await TestBus.dispatchCommand("cmd1", JSON.Encode.string("hello"))
32
+ expect(received.contents)->toEqual(Some("hello"))
33
+ })
34
+
35
+ testPromise("reset clears all handlers and subscribers", async () => {
36
+ module TestBus = LocalBus.Make()
37
+ let count: ref<int> = ref(0)
38
+ TestBus.subscribeToEvents("topic", async (_, _, _) => {
39
+ count := count.contents + 1
40
+ })
41
+ TestBus.reset()
42
+ // After reset, no subscribers — this just verifies no crash
43
+ expect(count.contents)->toBe(0)
44
+ })
45
+ })
46
+
47
+ describe("EventLogStorage_InMemory", () => {
48
+ testPromise("append stores events and replay returns them", async () => {
49
+ let opts: Pulumi.CustomResourceOptions.t = {}
50
+ let storage = EventLogStorage_InMemory.make(~name="test-log", ~opts)
51
+ let ops = await storage.operations->TestRunner.resolve
52
+ let _ = await ops.append(0, "agg-1", [JSON.Encode.string("e1"), JSON.Encode.string("e2")])
53
+ let events = await ops.replay("agg-1")
54
+ expect(events->Array.length)->toBe(2)
55
+ })
56
+
57
+ testPromise("replay returns empty array for unknown aggregate id", async () => {
58
+ let opts: Pulumi.CustomResourceOptions.t = {}
59
+ let storage = EventLogStorage_InMemory.make(~name="test-log-2", ~opts)
60
+ let ops = await storage.operations->TestRunner.resolve
61
+ let events = await ops.replay("unknown-id")
62
+ expect(events->Array.length)->toBe(0)
63
+ })
64
+
65
+ testPromise("multiple appends accumulate events", async () => {
66
+ let opts: Pulumi.CustomResourceOptions.t = {}
67
+ let storage = EventLogStorage_InMemory.make(~name="test-log-3", ~opts)
68
+ let ops = await storage.operations->TestRunner.resolve
69
+ let _ = await ops.append(0, "agg-2", [JSON.Encode.string("e1")])
70
+ let _ = await ops.append(1, "agg-2", [JSON.Encode.string("e2"), JSON.Encode.string("e3")])
71
+ let events = await ops.replay("agg-2")
72
+ expect(events->Array.length)->toBe(3)
73
+ })
74
+ })
75
+
76
+ describe("Aggregate E2E", () => {
77
+ // Resolve the Output chain before any test runs so bus wiring is complete.
78
+ let _ = beforeAllAsync(async () => {
79
+ let _ = await agg->ItemAgg.operations->TestRunner.resolve
80
+ })
81
+
82
+ let _ = beforeEach(() => {
83
+ capturedEventCount := 0
84
+ })
85
+
86
+ testPromise("CreateItem command produces ItemCreated event on event topic", async () => {
87
+ let ops = await agg->ItemAgg.operations->TestRunner.resolve
88
+ let commandJson =
89
+ ItemSpec.CreateItem({name: "Widget"})->ReventlessCore.Message.encode(ItemSpec.commandSchema)
90
+ await ops.publishJsons([
91
+ {
92
+ Reventless.Message.id: "item-1",
93
+ meta: testMeta,
94
+ commandJson: commandJson,
95
+ },
96
+ ])
97
+ expect(capturedEventCount.contents)->toBe(1)
98
+ })
99
+
100
+ testPromise("second CreateItem for same id produces no events (AlreadyExists)", async () => {
101
+ // item-1 was already created in the previous test (same aggregate instance)
102
+ let ops = await agg->ItemAgg.operations->TestRunner.resolve
103
+ let commandJson =
104
+ ItemSpec.CreateItem({name: "Widget2"})->ReventlessCore.Message.encode(ItemSpec.commandSchema)
105
+ await ops.publishJsons([
106
+ {
107
+ Reventless.Message.id: "item-1",
108
+ meta: testMeta,
109
+ commandJson: commandJson,
110
+ },
111
+ ])
112
+ // AlreadyExists error → no events generated → no bus publish
113
+ expect(capturedEventCount.contents)->toBe(0)
114
+ })
115
+
116
+ testPromise("CreateItem for new id produces event", async () => {
117
+ let ops = await agg->ItemAgg.operations->TestRunner.resolve
118
+ let commandJson =
119
+ ItemSpec.CreateItem({name: "NewItem"})->ReventlessCore.Message.encode(ItemSpec.commandSchema)
120
+ await ops.publishJsons([
121
+ {
122
+ Reventless.Message.id: "item-2",
123
+ meta: testMeta,
124
+ commandJson: commandJson,
125
+ },
126
+ ])
127
+ expect(capturedEventCount.contents)->toBe(1)
128
+ })
129
+ })
@@ -0,0 +1,129 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
4
+ import * as LocalBus$ReventlessLocal from "../../../src/adapter/LocalBus.res.mjs";
5
+ import * as TestRunner$ReventlessLocal from "../../../src/test/TestRunner.res.mjs";
6
+ import * as TestFixtures$ReventlessLocal from "../../TestFixtures.res.mjs";
7
+ import * as AggregateFixtures$ReventlessLocal from "./AggregateFixtures.res.mjs";
8
+ import * as EventLogStorage_InMemory$ReventlessLocal from "../../../src/adapter/EventLog/EventLogStorage_InMemory.res.mjs";
9
+
10
+ globalThis.describe("LocalBus", () => {
11
+ globalThis.test("publishes events to all subscribers", async () => {
12
+ let TestBus = LocalBus$ReventlessLocal.Make({});
13
+ let count = {
14
+ contents: 0
15
+ };
16
+ TestBus.subscribeToEvents("t1", async (param, param$1, param$2) => {
17
+ count.contents = count.contents + 1 | 0;
18
+ });
19
+ TestBus.subscribeToEvents("t1", async (param, param$1, param$2) => {
20
+ count.contents = count.contents + 1 | 0;
21
+ });
22
+ await TestBus.publishEvent("t1", "memory:InMemory", TestFixtures$ReventlessLocal.testMeta, null);
23
+ globalThis.expect(count.contents).toBe(2);
24
+ });
25
+ globalThis.test("dispatches commands to registered handler", async () => {
26
+ let TestBus = LocalBus$ReventlessLocal.Make({});
27
+ let received = {
28
+ contents: undefined
29
+ };
30
+ TestBus.registerCommandHandler("cmd1", async (json, param) => {
31
+ let tmp;
32
+ tmp = typeof json === "string" ? json : undefined;
33
+ received.contents = tmp;
34
+ });
35
+ await TestBus.dispatchCommand("cmd1", "hello");
36
+ globalThis.expect(received.contents).toEqual("hello");
37
+ });
38
+ globalThis.test("reset clears all handlers and subscribers", async () => {
39
+ let TestBus = LocalBus$ReventlessLocal.Make({});
40
+ let count = {
41
+ contents: 0
42
+ };
43
+ TestBus.subscribeToEvents("topic", async (param, param$1, param$2) => {
44
+ count.contents = count.contents + 1 | 0;
45
+ });
46
+ TestBus.reset();
47
+ globalThis.expect(count.contents).toBe(0);
48
+ });
49
+ });
50
+
51
+ globalThis.describe("EventLogStorage_InMemory", () => {
52
+ globalThis.test("append stores events and replay returns them", async () => {
53
+ let storage = EventLogStorage_InMemory$ReventlessLocal.make("test-log", {});
54
+ let ops = await TestRunner$ReventlessLocal.resolve(storage.operations);
55
+ await ops.append(0, "agg-1", [
56
+ "e1",
57
+ "e2"
58
+ ]);
59
+ let events = await ops.replay("agg-1");
60
+ globalThis.expect(events.length).toBe(2);
61
+ });
62
+ globalThis.test("replay returns empty array for unknown aggregate id", async () => {
63
+ let storage = EventLogStorage_InMemory$ReventlessLocal.make("test-log-2", {});
64
+ let ops = await TestRunner$ReventlessLocal.resolve(storage.operations);
65
+ let events = await ops.replay("unknown-id");
66
+ globalThis.expect(events.length).toBe(0);
67
+ });
68
+ globalThis.test("multiple appends accumulate events", async () => {
69
+ let storage = EventLogStorage_InMemory$ReventlessLocal.make("test-log-3", {});
70
+ let ops = await TestRunner$ReventlessLocal.resolve(storage.operations);
71
+ await ops.append(0, "agg-2", ["e1"]);
72
+ await ops.append(1, "agg-2", [
73
+ "e2",
74
+ "e3"
75
+ ]);
76
+ let events = await ops.replay("agg-2");
77
+ globalThis.expect(events.length).toBe(3);
78
+ });
79
+ });
80
+
81
+ globalThis.describe("Aggregate E2E", () => {
82
+ globalThis.beforeAll(async () => {
83
+ await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
84
+ });
85
+ globalThis.beforeEach(() => {
86
+ AggregateFixtures$ReventlessLocal.capturedEventCount.contents = 0;
87
+ });
88
+ globalThis.test("CreateItem command produces ItemCreated event on event topic", async () => {
89
+ let ops = await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
90
+ let commandJson = Message$ReventlessCore.encode({
91
+ TAG: "CreateItem",
92
+ name: "Widget"
93
+ }, AggregateFixtures$ReventlessLocal.ItemSpec.commandSchema);
94
+ await ops.publishJsons([{
95
+ id: "item-1",
96
+ meta: TestFixtures$ReventlessLocal.testMeta,
97
+ commandJson: commandJson
98
+ }]);
99
+ globalThis.expect(AggregateFixtures$ReventlessLocal.capturedEventCount.contents).toBe(1);
100
+ });
101
+ globalThis.test("second CreateItem for same id produces no events (AlreadyExists)", async () => {
102
+ let ops = await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
103
+ let commandJson = Message$ReventlessCore.encode({
104
+ TAG: "CreateItem",
105
+ name: "Widget2"
106
+ }, AggregateFixtures$ReventlessLocal.ItemSpec.commandSchema);
107
+ await ops.publishJsons([{
108
+ id: "item-1",
109
+ meta: TestFixtures$ReventlessLocal.testMeta,
110
+ commandJson: commandJson
111
+ }]);
112
+ globalThis.expect(AggregateFixtures$ReventlessLocal.capturedEventCount.contents).toBe(0);
113
+ });
114
+ globalThis.test("CreateItem for new id produces event", async () => {
115
+ let ops = await TestRunner$ReventlessLocal.resolve(AggregateFixtures$ReventlessLocal.ItemAgg.operations(AggregateFixtures$ReventlessLocal.agg));
116
+ let commandJson = Message$ReventlessCore.encode({
117
+ TAG: "CreateItem",
118
+ name: "NewItem"
119
+ }, AggregateFixtures$ReventlessLocal.ItemSpec.commandSchema);
120
+ await ops.publishJsons([{
121
+ id: "item-2",
122
+ meta: TestFixtures$ReventlessLocal.testMeta,
123
+ commandJson: commandJson
124
+ }]);
125
+ globalThis.expect(AggregateFixtures$ReventlessLocal.capturedEventCount.contents).toBe(1);
126
+ });
127
+ });
128
+
129
+ /* Not a pure module */
@@ -0,0 +1,212 @@
1
+ // Unit tests for AutomationSlice_Callback (Plan 04 mixed-source shape) —
2
+ // exercises per-source decode dispatch, context plumbing, and toTags
3
+ // validation.
4
+
5
+ open JestGlobals
6
+ open AutomationSliceFixtures
7
+
8
+ module Callback = ReventlessCore.AutomationSlice_Callback.Make(
9
+ ShipOrderSpec,
10
+ ShipOrderAutomation,
11
+ )
12
+
13
+ module SkipCallback = ReventlessCore.AutomationSlice_Callback.Make(
14
+ SkipProcessSpec,
15
+ SkipProcessAutomation,
16
+ )
17
+
18
+ open ReventlessCore.AutomationSlice_Callback
19
+
20
+ describe("AutomationSlice Callback (mixed-source)", () => {
21
+ let _ = beforeEach(() => {
22
+ Callback.todoItems
23
+ ->Dict.keysToArray
24
+ ->Array.forEach(k => Callback.todoItems->Dict.delete(k))
25
+ SkipCallback.todoItems
26
+ ->Dict.keysToArray
27
+ ->Array.forEach(k => SkipCallback.todoItems->Dict.delete(k))
28
+ })
29
+
30
+ describe("Phase 1 — collect", () => {
31
+ testPromise("OrderPlaced JSON creates a pending TODO item", async () => {
32
+ let json = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))
33
+ Callback.phase1([json], testContext)
34
+ let items = Callback.todoItems
35
+ expect(items->Dict.toArray->Array.length)->toBe(1)
36
+ let row = items->Dict.get("ord-1")->Option.getOrThrow
37
+ expect(row.status)->toBe(Pending)
38
+ expect(row.retryCount)->toBe(0)
39
+ })
40
+
41
+ testPromise("duplicate OrderPlaced is idempotent", async () => {
42
+ let j1 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))
43
+ let j2 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "456 Oak Ave"}))
44
+ Callback.phase1([j1], testContext)
45
+ Callback.phase1([j2], testContext)
46
+ expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(1)
47
+ })
48
+
49
+ testPromise("multiple OrderPlaced events create multiple TODO items", async () => {
50
+ let j1 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))
51
+ let j2 = encodeShipOrderEvent(OrderPlaced({orderId: "ord-2", address: "456 Oak Ave"}))
52
+ Callback.phase1([j1, j2], testContext)
53
+ expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(2)
54
+ })
55
+
56
+ testPromise("ShipmentCreated does not create a TODO item", async () => {
57
+ let json = encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))
58
+ Callback.phase1([json], testContext)
59
+ expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(0)
60
+ })
61
+ })
62
+
63
+ describe("Phase 1 — resolve", () => {
64
+ testPromise("ShipmentCreated marks pending TODO item as completed", async () => {
65
+ Callback.phase1(
66
+ [encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
67
+ testContext,
68
+ )
69
+ Callback.phase1(
70
+ [encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))],
71
+ testContext,
72
+ )
73
+ let row = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
74
+ expect(row.status)->toBe(Completed)
75
+ })
76
+
77
+ testPromise("ShipmentCreated for unknown id is a no-op", async () => {
78
+ Callback.phase1(
79
+ [encodeShipOrderEvent(ShipmentCreated({orderId: "unknown"}))],
80
+ testContext,
81
+ )
82
+ expect(Callback.todoItems->Dict.toArray->Array.length)->toBe(0)
83
+ })
84
+ })
85
+
86
+ describe("Phase 2 — process", () => {
87
+ testPromise("pending items produce commands via publishJsons", async () => {
88
+ Callback.phase1(
89
+ [encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
90
+ testContext,
91
+ )
92
+ let publishedCommands = ref([])
93
+ let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
94
+ publishedCommands := cmds
95
+ }
96
+ await Callback.phase2(mockPublish)
97
+
98
+ expect(publishedCommands.contents->Array.length)->toBe(1)
99
+ let cmd = publishedCommands.contents->Array.getUnsafe(0)
100
+ expect(cmd.id)->toBe("ord-1")
101
+
102
+ let row = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
103
+ expect(row.status)->toBe(Processing)
104
+ })
105
+
106
+ testPromise("completed items are not processed", async () => {
107
+ Callback.phase1(
108
+ [encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
109
+ testContext,
110
+ )
111
+ Callback.phase1(
112
+ [encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))],
113
+ testContext,
114
+ )
115
+ let publishedCommands = ref([])
116
+ let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
117
+ publishedCommands := cmds
118
+ }
119
+ await Callback.phase2(mockPublish)
120
+ expect(publishedCommands.contents->Array.length)->toBe(0)
121
+ })
122
+
123
+ testPromise("items where process returns None are skipped", async () => {
124
+ let json = encodeSkipProcessEvent(OrderPlaced({orderId: "ord-1"}))
125
+ SkipCallback.phase1([json], testContext)
126
+ let publishedCommands = ref([])
127
+ let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
128
+ publishedCommands := cmds
129
+ }
130
+ await SkipCallback.phase2(mockPublish)
131
+ expect(publishedCommands.contents->Array.length)->toBe(0)
132
+ let row = SkipCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
133
+ expect(row.status)->toBe(Pending)
134
+ })
135
+
136
+ testPromise("empty TODO list produces no commands", async () => {
137
+ let publishedCommands = ref([])
138
+ let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
139
+ publishedCommands := cmds
140
+ }
141
+ await Callback.phase2(mockPublish)
142
+ expect(publishedCommands.contents->Array.length)->toBe(0)
143
+ })
144
+
145
+ testPromise("publishJsons failure marks items as Failed", async () => {
146
+ Callback.phase1(
147
+ [encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
148
+ testContext,
149
+ )
150
+ let failingPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => {
151
+ JsError.throwWithMessage("publish failed")
152
+ }
153
+ await Callback.phase2(failingPublish)
154
+ let row = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
155
+ expect(row.status)->toBe(Failed)
156
+ expect(row.retryCount)->toBe(1)
157
+ })
158
+
159
+ testPromise("failed items with retryCount < maxRetries are retried", async () => {
160
+ Callback.phase1(
161
+ [encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
162
+ testContext,
163
+ )
164
+ let failingPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => {
165
+ JsError.throwWithMessage("publish failed")
166
+ }
167
+ await Callback.phase2(failingPublish)
168
+ let row1 = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
169
+ expect(row1.retryCount)->toBe(1)
170
+
171
+ let publishedCommands = ref([])
172
+ let successPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
173
+ publishedCommands := cmds
174
+ }
175
+ await Callback.phase2(successPublish)
176
+ expect(publishedCommands.contents->Array.length)->toBe(1)
177
+ let row2 = Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow
178
+ expect(row2.status)->toBe(Processing)
179
+ })
180
+ })
181
+
182
+ describe("full lifecycle", () => {
183
+ testPromise("collect → process → resolve completes the TODO item", async () => {
184
+ Callback.phase1(
185
+ [encodeShipOrderEvent(OrderPlaced({orderId: "ord-1", address: "123 Main St"}))],
186
+ testContext,
187
+ )
188
+ expect((Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow).status)->toBe(Pending)
189
+
190
+ let publishedCommands = ref([])
191
+ let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
192
+ publishedCommands := cmds
193
+ }
194
+ await Callback.phase2(mockPublish)
195
+ expect(publishedCommands.contents->Array.length)->toBe(1)
196
+ expect((Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow).status)->toBe(Processing)
197
+
198
+ Callback.phase1(
199
+ [encodeShipOrderEvent(ShipmentCreated({orderId: "ord-1"}))],
200
+ testContext,
201
+ )
202
+ expect((Callback.todoItems->Dict.get("ord-1")->Option.getOrThrow).status)->toBe(Completed)
203
+
204
+ let publishedCommands2 = ref([])
205
+ let mockPublish2: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
206
+ publishedCommands2 := cmds
207
+ }
208
+ await Callback.phase2(mockPublish2)
209
+ expect(publishedCommands2.contents->Array.length)->toBe(0)
210
+ })
211
+ })
212
+ })