@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,208 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Nodefs from "node:fs";
4
+ import * as Nodeos from "node:os";
5
+ import * as Nodepath from "node:path";
6
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
+ import * as LocalAuth$ReventlessLocal from "../../src/adapter/Auth/LocalAuth.res.mjs";
8
+ import * as UserStore$ReventlessLocal from "../../src/adapter/Auth/UserStore.res.mjs";
9
+
10
+ function resetAll() {
11
+ LocalAuth$ReventlessLocal.resetUsers();
12
+ LocalAuth$ReventlessLocal.Login.resetStore();
13
+ UserStore$ReventlessLocal.resetResolution();
14
+ }
15
+
16
+ function _writeYamlFile(contents) {
17
+ let dir = Nodefs.mkdtempSync(Nodepath.join(Nodeos.tmpdir(), "reventless-userstore-"));
18
+ let path = Nodepath.join(dir, "users.yaml");
19
+ Nodefs.writeFileSync(path, contents, "utf8");
20
+ return path;
21
+ }
22
+
23
+ globalThis.test("parseString decodes a well-formed YAML document", async () => {
24
+ let entries = UserStore$ReventlessLocal.parseString(`
25
+ - username: alice
26
+ password: alice-pw
27
+ groups: [Editor]
28
+ - username: bob
29
+ password: bob-pw
30
+ groups: []
31
+ `);
32
+ if (entries.TAG !== "Ok") {
33
+ return Stdlib_JsError.throwWithMessage("parseString failed: " + entries._0);
34
+ }
35
+ let entries$1 = entries._0;
36
+ globalThis.expect(entries$1.length).toEqual(2);
37
+ let first = entries$1[0];
38
+ globalThis.expect(first.username).toEqual("alice");
39
+ globalThis.expect(first.password).toEqual("alice-pw");
40
+ globalThis.expect(first.groups).toEqual(["Editor"]);
41
+ });
42
+
43
+ globalThis.test("parseString rejects malformed YAML", async () => {
44
+ let match = UserStore$ReventlessLocal.parseString("not: valid: yaml: at all: ::");
45
+ if (match.TAG === "Ok") {
46
+ return Stdlib_JsError.throwWithMessage("expected Error for malformed YAML");
47
+ }
48
+ });
49
+
50
+ globalThis.test("parseString rejects entries missing required fields", async () => {
51
+ let match = UserStore$ReventlessLocal.parseString(`
52
+ - username: alice
53
+ groups: [Editor]
54
+ `);
55
+ if (match.TAG === "Ok") {
56
+ return Stdlib_JsError.throwWithMessage("expected Error for missing password");
57
+ }
58
+ });
59
+
60
+ globalThis.test("load(~users) registers credentials and returns InlineUsers", async () => {
61
+ resetAll();
62
+ let entries = [
63
+ {
64
+ username: "alice",
65
+ password: "alice-pw",
66
+ groups: ["Editor"]
67
+ },
68
+ {
69
+ username: "bob",
70
+ password: "bob-pw",
71
+ groups: [],
72
+ userId: "u-bob"
73
+ }
74
+ ];
75
+ let msg = UserStore$ReventlessLocal.load(entries, undefined, undefined);
76
+ if (msg.TAG === "Ok") {
77
+ let tmp = msg._0;
78
+ if (typeof tmp === "object" || tmp !== "InlineUsers") {
79
+ Stdlib_JsError.throwWithMessage("expected InlineUsers");
80
+ }
81
+ } else {
82
+ Stdlib_JsError.throwWithMessage("load failed: " + msg._0);
83
+ }
84
+ let result = await LocalAuth$ReventlessLocal.Login.issue("alice", "alice-pw");
85
+ if (result.TAG !== "Ok") {
86
+ Stdlib_JsError.throwWithMessage("issue rejected loaded credentials: " + result._0);
87
+ }
88
+ let identity = LocalAuth$ReventlessLocal.lookupUser("bob");
89
+ if (identity !== undefined) {
90
+ globalThis.expect(identity.userId).toEqual("u-bob");
91
+ return;
92
+ } else {
93
+ return Stdlib_JsError.throwWithMessage("bob not in user registry");
94
+ }
95
+ });
96
+
97
+ globalThis.test("load(~usersFile) reads a YAML file from disk", async () => {
98
+ resetAll();
99
+ let path = _writeYamlFile(`
100
+ - username: carol
101
+ password: carol-pw
102
+ groups: [Admin]
103
+ `);
104
+ let msg = UserStore$ReventlessLocal.load(undefined, path, undefined);
105
+ if (msg.TAG === "Ok") {
106
+ let p = msg._0;
107
+ if (typeof p !== "object" || p.TAG !== "UsersFile") {
108
+ Stdlib_JsError.throwWithMessage("expected UsersFile resolution");
109
+ } else {
110
+ globalThis.expect(p._0).toEqual(path);
111
+ }
112
+ } else {
113
+ Stdlib_JsError.throwWithMessage("load failed: " + msg._0);
114
+ }
115
+ let result = await LocalAuth$ReventlessLocal.Login.issue("carol", "carol-pw");
116
+ if (result.TAG !== "Ok") {
117
+ Stdlib_JsError.throwWithMessage("issue rejected file-loaded credentials: " + result._0);
118
+ }
119
+ Nodefs.rmSync(path, {
120
+ force: true
121
+ });
122
+ });
123
+
124
+ globalThis.test("load(~usersFile) returns Error when the file is missing", async () => {
125
+ resetAll();
126
+ let match = UserStore$ReventlessLocal.load(undefined, "/tmp/does-not-exist-reventless.yaml", undefined);
127
+ if (match.TAG === "Ok") {
128
+ return Stdlib_JsError.throwWithMessage("expected Error for missing file");
129
+ }
130
+ });
131
+
132
+ globalThis.test("load() with no args + no default file returns Empty", async () => {
133
+ resetAll();
134
+ let msg = UserStore$ReventlessLocal.load(undefined, undefined, undefined);
135
+ if (msg.TAG !== "Ok") {
136
+ return Stdlib_JsError.throwWithMessage("load failed: " + msg._0);
137
+ }
138
+ let tmp = msg._0;
139
+ if (typeof tmp !== "object") {
140
+ if (tmp === "InlineUsers") {
141
+ return Stdlib_JsError.throwWithMessage("expected Empty or DefaultFile");
142
+ } else {
143
+ return;
144
+ }
145
+ } else if (tmp.TAG === "UsersFile") {
146
+ return Stdlib_JsError.throwWithMessage("expected Empty or DefaultFile");
147
+ } else {
148
+ return;
149
+ }
150
+ });
151
+
152
+ globalThis.test("inline users win over a file path", async () => {
153
+ resetAll();
154
+ let path = _writeYamlFile(`
155
+ - username: file-user
156
+ password: file-pw
157
+ groups: []
158
+ `);
159
+ let inline = [{
160
+ username: "inline-user",
161
+ password: "inline-pw",
162
+ groups: []
163
+ }];
164
+ let msg = UserStore$ReventlessLocal.load(inline, path, undefined);
165
+ if (msg.TAG === "Ok") {
166
+ let tmp = msg._0;
167
+ if (typeof tmp === "object" || tmp !== "InlineUsers") {
168
+ Stdlib_JsError.throwWithMessage("expected InlineUsers (inline should win)");
169
+ }
170
+ } else {
171
+ Stdlib_JsError.throwWithMessage("load failed: " + msg._0);
172
+ }
173
+ let match = LocalAuth$ReventlessLocal.lookupUser("file-user");
174
+ if (match !== undefined) {
175
+ Stdlib_JsError.throwWithMessage("file-user leaked into registry despite inline override");
176
+ }
177
+ let match$1 = LocalAuth$ReventlessLocal.lookupUser("inline-user");
178
+ if (match$1 !== undefined) {
179
+
180
+ } else {
181
+ Stdlib_JsError.throwWithMessage("inline-user missing from registry");
182
+ }
183
+ Nodefs.rmSync(path, {
184
+ force: true
185
+ });
186
+ });
187
+
188
+ globalThis.test("autoLoadOnce is a no-op after an explicit load", async () => {
189
+ resetAll();
190
+ UserStore$ReventlessLocal.load([{
191
+ username: "x",
192
+ password: "x",
193
+ groups: []
194
+ }], undefined, undefined);
195
+ UserStore$ReventlessLocal.autoLoadOnce();
196
+ let match = LocalAuth$ReventlessLocal.lookupUser("x");
197
+ if (match !== undefined) {
198
+ return;
199
+ } else {
200
+ return Stdlib_JsError.throwWithMessage("autoLoadOnce wiped explicit registration");
201
+ }
202
+ });
203
+
204
+ export {
205
+ resetAll,
206
+ _writeYamlFile,
207
+ }
208
+ /* Not a pure module */
@@ -0,0 +1,157 @@
1
+ // Tests for the bounded PubSub mode of LocalBus (Phase G).
2
+ // Verifies that MakeBounded({let capacity = n}) delivers messages correctly, fans out to all
3
+ // subscribers, and exerts backpressure when subscriber queues are full.
4
+ //
5
+ // Timing note: bounded mode resolves publishEvent in ~3 microtask ticks
6
+ // (1 extra vs unbounded) because PubSub.publish runs inside Effect.runPromise
7
+ // rather than Effect.runSync.
8
+
9
+ open JestGlobals
10
+
11
+ let _ = TestRunner.setup()
12
+
13
+ let defaultMeta: Reventless.Message.meta = {
14
+ service: "test",
15
+ time: "",
16
+ ip: "",
17
+ user: "test",
18
+ msgId: "",
19
+ correlationId: "",
20
+ }
21
+
22
+ describe("LocalBus bounded PubSub (Phase G)", () => {
23
+ describe("basic delivery", () => {
24
+ testPromise("delivers a message to a subscriber in bounded mode", async () => {
25
+ module TestBus = LocalBus.MakeBounded({let capacity = 10})
26
+ let delivered = ref(false)
27
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
28
+ delivered := true
29
+ })
30
+ let _ = await TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
31
+ expect(delivered.contents)->toBe(true)
32
+ })
33
+
34
+ testPromise("bounded mode with no subscribers returns immediately", async () => {
35
+ module TestBus = LocalBus.MakeBounded({let capacity = 5})
36
+ // No subscribers — should not hang
37
+ await TestBus.publishEvent("empty-topic", "svc", defaultMeta, JSON.Null)
38
+ })
39
+
40
+ testPromise("passes service, meta, and json to the subscriber handler", async () => {
41
+ module TestBus = LocalBus.MakeBounded({let capacity = 10})
42
+ let capturedService = ref("")
43
+ let capturedJson = ref(JSON.Null)
44
+ TestBus.subscribeToEvents("T", async (svc, _meta, json) => {
45
+ capturedService := svc
46
+ capturedJson := json
47
+ })
48
+ let payload = JSON.parseOrThrow("{\"x\":42}")
49
+ let _ = await TestBus.publishEvent("T", "my-service", defaultMeta, payload)
50
+ expect(capturedService.contents)->toBe("my-service")
51
+ expect(capturedJson.contents)->toEqual(payload)
52
+ })
53
+ })
54
+
55
+ describe("fan-out", () => {
56
+ testPromise("delivers to all subscribers on the same topic", async () => {
57
+ module TestBus = LocalBus.MakeBounded({let capacity = 10})
58
+ let count = ref(0)
59
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
60
+ count := count.contents + 1
61
+ })
62
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
63
+ count := count.contents + 1
64
+ })
65
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
66
+ count := count.contents + 1
67
+ })
68
+ let _ = await TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
69
+ expect(count.contents)->toBe(3)
70
+ })
71
+
72
+ testPromise("topic isolation preserved in bounded mode", async () => {
73
+ module TestBus = LocalBus.MakeBounded({let capacity = 10})
74
+ let countA = ref(0)
75
+ let countB = ref(0)
76
+ TestBus.subscribeToEvents("topic-a", async (_, _, _) => {
77
+ countA := countA.contents + 1
78
+ })
79
+ TestBus.subscribeToEvents("topic-b", async (_, _, _) => {
80
+ countB := countB.contents + 1
81
+ })
82
+ let _ = await TestBus.publishEvent("topic-a", "svc", defaultMeta, JSON.Null)
83
+ expect(countA.contents)->toBe(1)
84
+ expect(countB.contents)->toBe(0)
85
+ })
86
+ })
87
+
88
+ describe("backpressure", () => {
89
+ testPromise("publisher suspends when subscriber queue is full (capacity=1)", async () => {
90
+ // capacity=1: subscriber queue can buffer 1 message while the subscriber is processing.
91
+ // Timeline:
92
+ // p1 publish: drain fiber D has a pending Queue.take → msg1 goes to D directly
93
+ // p2 publish: no pending take (D is processing msg1, blocked on gate) → msg2 buffered
94
+ // p3 publish: queue is full (msg2 there, capacity=1) → F3 SUSPENDS
95
+ // After opening gate: msg1 processed → done_1 → D takes msg2 → F3 wakes, delivers msg3
96
+ module TestBus = LocalBus.MakeBounded({let capacity = 1})
97
+ let processedCount = ref(0)
98
+ // Gate Deferred: subscriber blocks until explicitly opened
99
+ let gate: Deferred.t<unit, unit> = Deferred.make()->Effect.runSync
100
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
101
+ let _ = await Deferred.await_(gate)->Effect.runPromise
102
+ processedCount := processedCount.contents + 1
103
+ })
104
+ // Start 3 publishes without awaiting.
105
+ // p1: D's pending Queue.take resolves with msg1; D starts processing (blocks on gate)
106
+ // p2: msg2 buffered in queue (capacity=1, fits since D already took msg1)
107
+ // p3: queue full → F3 fiber suspends inside PubSub.publish
108
+ let p1 = TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
109
+ let p2 = TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
110
+ let p3 = TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
111
+ // Tick 1: drain fiber D runs, takes msg1, calls handler → handler blocks on gate
112
+ let _ = await Promise.resolve()
113
+ // Gate not open yet — no messages fully processed
114
+ expect(processedCount.contents)->toBe(0)
115
+ // Open gate: subscriber can now process all pending messages
116
+ let _ = Deferred.succeed(gate, ())->Effect.runSync
117
+ // Await each publish promise; by the time all resolve, all 3 handlers have run
118
+ let _ = await p1
119
+ let _ = await p2
120
+ let _ = await p3
121
+ expect(processedCount.contents)->toBe(3)
122
+ })
123
+ })
124
+
125
+ describe("timing", () => {
126
+ testPromise("bounded mode completes within 3 microtask ticks", async () => {
127
+ module TestBus = LocalBus.MakeBounded({let capacity = 10})
128
+ let delivered = ref(false)
129
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
130
+ delivered := true
131
+ })
132
+ let pubPromise = TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
133
+ // Not delivered synchronously
134
+ expect(delivered.contents)->toBe(false)
135
+ let _ = await Promise.resolve() // tick 1
136
+ let _ = await Promise.resolve() // tick 2
137
+ let _ = await Promise.resolve() // tick 3 (bounded adds 1 vs unbounded's 2)
138
+ let _ = await pubPromise
139
+ expect(delivered.contents)->toBe(true)
140
+ })
141
+ })
142
+
143
+ describe("reset", () => {
144
+ testPromise("reset shuts down bounded hubs cleanly", async () => {
145
+ module TestBus = LocalBus.MakeBounded({let capacity = 5})
146
+ let count = ref(0)
147
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
148
+ count := count.contents + 1
149
+ })
150
+ let _ = await TestBus.publishEvent("T", "svc", defaultMeta, JSON.Null)
151
+ expect(count.contents)->toBe(1)
152
+ // reset should not throw or hang
153
+ TestBus.reset()
154
+ expect(count.contents)->toBe(1) // count unchanged by reset itself
155
+ })
156
+ })
157
+ })
@@ -0,0 +1,168 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Effect from "effect/Effect";
4
+ import * as Deferred from "effect/Deferred";
5
+ import * as LocalBus$ReventlessLocal from "../../src/adapter/LocalBus.res.mjs";
6
+ import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
7
+
8
+ TestRunner$ReventlessLocal.setup();
9
+
10
+ let defaultMeta = {
11
+ service: "test",
12
+ time: "",
13
+ ip: "",
14
+ user: "test",
15
+ msgId: "",
16
+ correlationId: ""
17
+ };
18
+
19
+ globalThis.describe("LocalBus bounded PubSub (Phase G)", () => {
20
+ globalThis.describe("basic delivery", () => {
21
+ globalThis.test("delivers a message to a subscriber in bounded mode", async () => {
22
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
23
+ capacity: 10
24
+ });
25
+ let delivered = {
26
+ contents: false
27
+ };
28
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
29
+ delivered.contents = true;
30
+ });
31
+ await TestBus.publishEvent("T", "svc", defaultMeta, null);
32
+ globalThis.expect(delivered.contents).toBe(true);
33
+ });
34
+ globalThis.test("bounded mode with no subscribers returns immediately", async () => {
35
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
36
+ capacity: 5
37
+ });
38
+ return await TestBus.publishEvent("empty-topic", "svc", defaultMeta, null);
39
+ });
40
+ globalThis.test("passes service, meta, and json to the subscriber handler", async () => {
41
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
42
+ capacity: 10
43
+ });
44
+ let capturedService = {
45
+ contents: ""
46
+ };
47
+ let capturedJson = {
48
+ contents: null
49
+ };
50
+ TestBus.subscribeToEvents("T", async (svc, _meta, json) => {
51
+ capturedService.contents = svc;
52
+ capturedJson.contents = json;
53
+ });
54
+ let payload = JSON.parse("{\"x\":42}");
55
+ await TestBus.publishEvent("T", "my-service", defaultMeta, payload);
56
+ globalThis.expect(capturedService.contents).toBe("my-service");
57
+ globalThis.expect(capturedJson.contents).toEqual(payload);
58
+ });
59
+ });
60
+ globalThis.describe("fan-out", () => {
61
+ globalThis.test("delivers to all subscribers on the same topic", async () => {
62
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
63
+ capacity: 10
64
+ });
65
+ let count = {
66
+ contents: 0
67
+ };
68
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
69
+ count.contents = count.contents + 1 | 0;
70
+ });
71
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
72
+ count.contents = count.contents + 1 | 0;
73
+ });
74
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
75
+ count.contents = count.contents + 1 | 0;
76
+ });
77
+ await TestBus.publishEvent("T", "svc", defaultMeta, null);
78
+ globalThis.expect(count.contents).toBe(3);
79
+ });
80
+ globalThis.test("topic isolation preserved in bounded mode", async () => {
81
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
82
+ capacity: 10
83
+ });
84
+ let countA = {
85
+ contents: 0
86
+ };
87
+ let countB = {
88
+ contents: 0
89
+ };
90
+ TestBus.subscribeToEvents("topic-a", async (param, param$1, param$2) => {
91
+ countA.contents = countA.contents + 1 | 0;
92
+ });
93
+ TestBus.subscribeToEvents("topic-b", async (param, param$1, param$2) => {
94
+ countB.contents = countB.contents + 1 | 0;
95
+ });
96
+ await TestBus.publishEvent("topic-a", "svc", defaultMeta, null);
97
+ globalThis.expect(countA.contents).toBe(1);
98
+ globalThis.expect(countB.contents).toBe(0);
99
+ });
100
+ });
101
+ globalThis.describe("backpressure", () => {
102
+ globalThis.test("publisher suspends when subscriber queue is full (capacity=1)", async () => {
103
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
104
+ capacity: 1
105
+ });
106
+ let processedCount = {
107
+ contents: 0
108
+ };
109
+ let gate = Effect.runSync(Deferred.make());
110
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
111
+ await Effect.runPromise(Deferred.await(gate));
112
+ processedCount.contents = processedCount.contents + 1 | 0;
113
+ });
114
+ let p1 = TestBus.publishEvent("T", "svc", defaultMeta, null);
115
+ let p2 = TestBus.publishEvent("T", "svc", defaultMeta, null);
116
+ let p3 = TestBus.publishEvent("T", "svc", defaultMeta, null);
117
+ await Promise.resolve();
118
+ globalThis.expect(processedCount.contents).toBe(0);
119
+ Effect.runSync(Deferred.succeed(gate, undefined));
120
+ await p1;
121
+ await p2;
122
+ await p3;
123
+ globalThis.expect(processedCount.contents).toBe(3);
124
+ });
125
+ });
126
+ globalThis.describe("timing", () => {
127
+ globalThis.test("bounded mode completes within 3 microtask ticks", async () => {
128
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
129
+ capacity: 10
130
+ });
131
+ let delivered = {
132
+ contents: false
133
+ };
134
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
135
+ delivered.contents = true;
136
+ });
137
+ let pubPromise = TestBus.publishEvent("T", "svc", defaultMeta, null);
138
+ globalThis.expect(delivered.contents).toBe(false);
139
+ await Promise.resolve();
140
+ await Promise.resolve();
141
+ await Promise.resolve();
142
+ await pubPromise;
143
+ globalThis.expect(delivered.contents).toBe(true);
144
+ });
145
+ });
146
+ globalThis.describe("reset", () => {
147
+ globalThis.test("reset shuts down bounded hubs cleanly", async () => {
148
+ let TestBus = LocalBus$ReventlessLocal.MakeBounded({
149
+ capacity: 5
150
+ });
151
+ let count = {
152
+ contents: 0
153
+ };
154
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
155
+ count.contents = count.contents + 1 | 0;
156
+ });
157
+ await TestBus.publishEvent("T", "svc", defaultMeta, null);
158
+ globalThis.expect(count.contents).toBe(1);
159
+ TestBus.reset();
160
+ globalThis.expect(count.contents).toBe(1);
161
+ });
162
+ });
163
+ });
164
+
165
+ export {
166
+ defaultMeta,
167
+ }
168
+ /* Not a pure module */
@@ -0,0 +1,81 @@
1
+ // Tests for the PubSub-based LocalBus implementation (Phase F).
2
+ // Verifies the 2-tick timing guarantee and multi-subscriber fan-out.
3
+ //
4
+ // These tests lock in two invariants of the PubSub refactor:
5
+ // 1. publishEvent still resolves in exactly 2 microtask ticks (unbounded mode).
6
+ // 2. A single publishEvent call reaches all subscribers on the same topic.
7
+
8
+ open JestGlobals
9
+
10
+ let _ = TestRunner.setup()
11
+
12
+ let defaultMeta: Reventless.Message.meta = {
13
+ service: "test",
14
+ time: "",
15
+ ip: "",
16
+ user: "test",
17
+ msgId: "",
18
+ correlationId: "",
19
+ }
20
+
21
+ describe("LocalBus PubSub (Phase F)", () => {
22
+ describe("publishEvent timing", () => {
23
+ testPromise("resolves after exactly 2 microtask ticks", async () => {
24
+ module TestBus = LocalBus.Make()
25
+ let delivered = ref(false)
26
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
27
+ delivered := true
28
+ })
29
+ // Start publishEvent without awaiting — drive manually tick by tick.
30
+ let pubPromise = TestBus.publishEvent("T", "svc", defaultMeta, JSON.parseOrThrow("{}"))
31
+ // Tick 0: publish is synchronous; drain fiber hasn't run yet.
32
+ expect(delivered.contents)->toBe(false)
33
+ // Tick 1: Effect scheduler runs drain fiber; handler sets delivered.
34
+ let _ = await Promise.resolve()
35
+ // Tick 2: allDone Deferred resolves; pubPromise completes.
36
+ let _ = await Promise.resolve()
37
+ let _ = await pubPromise
38
+ expect(delivered.contents)->toBe(true)
39
+ })
40
+
41
+ testPromise("publishEvent with no subscribers returns immediately", async () => {
42
+ module TestBus = LocalBus.Make()
43
+ // No subscribers registered — should not hang.
44
+ await TestBus.publishEvent("empty-topic", "svc", defaultMeta, JSON.Null)
45
+ // If we reach here the test passes (no timeout/hang).
46
+ })
47
+ })
48
+
49
+ describe("fan-out", () => {
50
+ testPromise("delivers to all subscribers on the same topic", async () => {
51
+ module TestBus = LocalBus.Make()
52
+ let count = ref(0)
53
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
54
+ count := count.contents + 1
55
+ })
56
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
57
+ count := count.contents + 1
58
+ })
59
+ TestBus.subscribeToEvents("T", async (_, _, _) => {
60
+ count := count.contents + 1
61
+ })
62
+ let _ = await TestBus.publishEvent("T", "svc", defaultMeta, JSON.parseOrThrow("{}"))
63
+ expect(count.contents)->toBe(3)
64
+ })
65
+
66
+ testPromise("publishing to topic-a does not reach topic-b subscribers", async () => {
67
+ module TestBus = LocalBus.Make()
68
+ let countA = ref(0)
69
+ let countB = ref(0)
70
+ TestBus.subscribeToEvents("topic-a", async (_, _, _) => {
71
+ countA := countA.contents + 1
72
+ })
73
+ TestBus.subscribeToEvents("topic-b", async (_, _, _) => {
74
+ countB := countB.contents + 1
75
+ })
76
+ let _ = await TestBus.publishEvent("topic-a", "svc", defaultMeta, JSON.Null)
77
+ expect(countA.contents)->toBe(1)
78
+ expect(countB.contents)->toBe(0)
79
+ })
80
+ })
81
+ })
@@ -0,0 +1,81 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as LocalBus$ReventlessLocal from "../../src/adapter/LocalBus.res.mjs";
4
+ import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
5
+
6
+ TestRunner$ReventlessLocal.setup();
7
+
8
+ let defaultMeta = {
9
+ service: "test",
10
+ time: "",
11
+ ip: "",
12
+ user: "test",
13
+ msgId: "",
14
+ correlationId: ""
15
+ };
16
+
17
+ globalThis.describe("LocalBus PubSub (Phase F)", () => {
18
+ globalThis.describe("publishEvent timing", () => {
19
+ globalThis.test("resolves after exactly 2 microtask ticks", async () => {
20
+ let TestBus = LocalBus$ReventlessLocal.Make({});
21
+ let delivered = {
22
+ contents: false
23
+ };
24
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
25
+ delivered.contents = true;
26
+ });
27
+ let pubPromise = TestBus.publishEvent("T", "svc", defaultMeta, JSON.parse("{}"));
28
+ globalThis.expect(delivered.contents).toBe(false);
29
+ await Promise.resolve();
30
+ await Promise.resolve();
31
+ await pubPromise;
32
+ globalThis.expect(delivered.contents).toBe(true);
33
+ });
34
+ globalThis.test("publishEvent with no subscribers returns immediately", async () => {
35
+ let TestBus = LocalBus$ReventlessLocal.Make({});
36
+ return await TestBus.publishEvent("empty-topic", "svc", defaultMeta, null);
37
+ });
38
+ });
39
+ globalThis.describe("fan-out", () => {
40
+ globalThis.test("delivers to all subscribers on the same topic", async () => {
41
+ let TestBus = LocalBus$ReventlessLocal.Make({});
42
+ let count = {
43
+ contents: 0
44
+ };
45
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
46
+ count.contents = count.contents + 1 | 0;
47
+ });
48
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
49
+ count.contents = count.contents + 1 | 0;
50
+ });
51
+ TestBus.subscribeToEvents("T", async (param, param$1, param$2) => {
52
+ count.contents = count.contents + 1 | 0;
53
+ });
54
+ await TestBus.publishEvent("T", "svc", defaultMeta, JSON.parse("{}"));
55
+ globalThis.expect(count.contents).toBe(3);
56
+ });
57
+ globalThis.test("publishing to topic-a does not reach topic-b subscribers", async () => {
58
+ let TestBus = LocalBus$ReventlessLocal.Make({});
59
+ let countA = {
60
+ contents: 0
61
+ };
62
+ let countB = {
63
+ contents: 0
64
+ };
65
+ TestBus.subscribeToEvents("topic-a", async (param, param$1, param$2) => {
66
+ countA.contents = countA.contents + 1 | 0;
67
+ });
68
+ TestBus.subscribeToEvents("topic-b", async (param, param$1, param$2) => {
69
+ countB.contents = countB.contents + 1 | 0;
70
+ });
71
+ await TestBus.publishEvent("topic-a", "svc", defaultMeta, null);
72
+ globalThis.expect(countA.contents).toBe(1);
73
+ globalThis.expect(countB.contents).toBe(0);
74
+ });
75
+ });
76
+ });
77
+
78
+ export {
79
+ defaultMeta,
80
+ }
81
+ /* Not a pure module */