@reventlessdev/reventless-core 3.0.0-alpha.134

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 (502) hide show
  1. package/CHANGELOG.md +1355 -0
  2. package/LICENSE +202 -0
  3. package/README.md +173 -0
  4. package/__mocks__/emptyModule.js +2 -0
  5. package/jest.setup.cjs +5 -0
  6. package/package.json +73 -0
  7. package/rescript.json +41 -0
  8. package/scripts/deploy.sh +6 -0
  9. package/scripts/post-deploy.sh +5 -0
  10. package/scripts/pre-deploy.sh +18 -0
  11. package/scripts/pulumi-up.sh +30 -0
  12. package/src/Behavior.res +18 -0
  13. package/src/Behavior.res.mjs +2 -0
  14. package/src/ComponentType.res +125 -0
  15. package/src/ComponentType.res.mjs +199 -0
  16. package/src/Env.res +5 -0
  17. package/src/Env.res.mjs +2 -0
  18. package/src/Mapper.res +36 -0
  19. package/src/Mapper.res.mjs +18 -0
  20. package/src/Mapper1toN.res +107 -0
  21. package/src/Mapper1toN.res.mjs +2 -0
  22. package/src/MapperNto1.res +78 -0
  23. package/src/MapperNto1.res.mjs +35 -0
  24. package/src/Message.res +353 -0
  25. package/src/Message.res.mjs +418 -0
  26. package/src/PluginRuntimeOperations.res +15 -0
  27. package/src/PluginRuntimeOperations.res.mjs +2 -0
  28. package/src/Projection.res +447 -0
  29. package/src/Projection.res.mjs +712 -0
  30. package/src/ProjectionMapper.res +44 -0
  31. package/src/ProjectionMapper.res.mjs +51 -0
  32. package/src/RequestContext.res +42 -0
  33. package/src/RequestContext.res.mjs +39 -0
  34. package/src/adapter/Adapter.res +178 -0
  35. package/src/adapter/Adapter.res.mjs +201 -0
  36. package/src/adapter/AdapterDeploytime.res +56 -0
  37. package/src/adapter/AdapterDeploytime.res.mjs +42 -0
  38. package/src/adapter/Auth/Auth_Adapter.res +42 -0
  39. package/src/adapter/Auth/Auth_Adapter.res.mjs +2 -0
  40. package/src/adapter/Runtime/AggregateRuntime_Builder.res +22 -0
  41. package/src/adapter/Runtime/AggregateRuntime_Builder.res.mjs +2 -0
  42. package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +259 -0
  43. package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res.mjs +190 -0
  44. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +92 -0
  45. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res.mjs +59 -0
  46. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +52 -0
  47. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res.mjs +49 -0
  48. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +64 -0
  49. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res.mjs +59 -0
  50. package/src/adapter/Runtime/EventCollectorRuntime_Builder.res +11 -0
  51. package/src/adapter/Runtime/EventCollectorRuntime_Builder.res.mjs +2 -0
  52. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +46 -0
  53. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res.mjs +40 -0
  54. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +204 -0
  55. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res.mjs +150 -0
  56. package/src/adapter/Runtime/ExtensionPointRuntime_Builder.res +18 -0
  57. package/src/adapter/Runtime/ExtensionPointRuntime_Builder.res.mjs +2 -0
  58. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +36 -0
  59. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res.mjs +28 -0
  60. package/src/adapter/Runtime/PluginRuntime_Builder.res +23 -0
  61. package/src/adapter/Runtime/PluginRuntime_Builder.res.mjs +2 -0
  62. package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +97 -0
  63. package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res.mjs +62 -0
  64. package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +89 -0
  65. package/src/adapter/Runtime/PluginRuntime_Builder_Single.res.mjs +62 -0
  66. package/src/adapter/Runtime/Runtime.res +106 -0
  67. package/src/adapter/Runtime/Runtime.res.mjs +22 -0
  68. package/src/adapter/Runtime/TaskRuntime_Builder.res +32 -0
  69. package/src/adapter/Runtime/TaskRuntime_Builder.res.mjs +2 -0
  70. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +42 -0
  71. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res.mjs +29 -0
  72. package/src/admin/AdminApi.res +88 -0
  73. package/src/admin/AdminApi.res.mjs +89 -0
  74. package/src/admin/Admin_Callback.res +27 -0
  75. package/src/admin/Admin_Callback.res.mjs +20 -0
  76. package/src/admin/Platform_Admin.res +402 -0
  77. package/src/admin/Platform_Admin.res.mjs +250 -0
  78. package/src/admin/Platform_Admin_Structure.res +125 -0
  79. package/src/admin/Platform_Admin_Structure.res.mjs +182 -0
  80. package/src/admin/Platform_ComponentDefinitionsApi.res +160 -0
  81. package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +299 -0
  82. package/src/admin/Platform_UIFragmentsApi.res +55 -0
  83. package/src/admin/Platform_UIFragmentsApi.res.mjs +124 -0
  84. package/src/admin/UIFragmentRegistryProjection.res +43 -0
  85. package/src/admin/UIFragmentRegistryProjection.res.mjs +81 -0
  86. package/src/admin/UIFragmentRegistryReadModelSpec.res +13 -0
  87. package/src/admin/UIFragmentRegistryReadModelSpec.res.mjs +40 -0
  88. package/src/components/Aggregate/Aggregate.res +96 -0
  89. package/src/components/Aggregate/Aggregate.res.mjs +82 -0
  90. package/src/components/Aggregate/Aggregate_Builder.res +175 -0
  91. package/src/components/Aggregate/Aggregate_Builder.res.mjs +119 -0
  92. package/src/components/Aggregate/Aggregate_Callback.res +273 -0
  93. package/src/components/Aggregate/Aggregate_Callback.res.mjs +208 -0
  94. package/src/components/Api/ApiAllowedStatesHelpers.res +19 -0
  95. package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +16 -0
  96. package/src/components/Api/ApiNoApiHelpers.res +13 -0
  97. package/src/components/Api/ApiNoApiHelpers.res.mjs +29 -0
  98. package/src/components/Api/Api_Builder.res +40 -0
  99. package/src/components/Api/Api_Builder.res.mjs +33 -0
  100. package/src/components/Api/Api_Naming.res +92 -0
  101. package/src/components/Api/Api_Naming.res.mjs +103 -0
  102. package/src/components/Api/Api_Operations.res +13 -0
  103. package/src/components/Api/Api_Operations.res.mjs +12 -0
  104. package/src/components/Api/GraphQL_FragmentGenerator.res +612 -0
  105. package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +503 -0
  106. package/src/components/Api/GraphQL_SchemaInspector.res +156 -0
  107. package/src/components/Api/GraphQL_SchemaInspector.res.mjs +123 -0
  108. package/src/components/Api/GraphQL_Stitcher.res +271 -0
  109. package/src/components/Api/GraphQL_Stitcher.res.mjs +229 -0
  110. package/src/components/Api/MCP_SchemaGenerator.res +185 -0
  111. package/src/components/Api/MCP_SchemaGenerator.res.mjs +146 -0
  112. package/src/components/Api/SchemaType.res +126 -0
  113. package/src/components/Api/SchemaType.res.mjs +143 -0
  114. package/src/components/Api/SuryToJsonSchema.res +142 -0
  115. package/src/components/Api/SuryToJsonSchema.res.mjs +210 -0
  116. package/src/components/AutomationSlice/AutomationSlice.res +39 -0
  117. package/src/components/AutomationSlice/AutomationSlice.res.mjs +24 -0
  118. package/src/components/AutomationSlice/AutomationSlice_Builder.res +207 -0
  119. package/src/components/AutomationSlice/AutomationSlice_Builder.res.mjs +123 -0
  120. package/src/components/AutomationSlice/AutomationSlice_Callback.res +212 -0
  121. package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +189 -0
  122. package/src/components/Builder_Helpers.res +196 -0
  123. package/src/components/Builder_Helpers.res.mjs +142 -0
  124. package/src/components/Cloner.res +84 -0
  125. package/src/components/Cloner.res.mjs +88 -0
  126. package/src/components/CommandGenerator/CommandGenerator.res +54 -0
  127. package/src/components/CommandGenerator/CommandGenerator.res.mjs +15 -0
  128. package/src/components/CommandGenerator/CommandGenerator_Adapter.res +22 -0
  129. package/src/components/CommandGenerator/CommandGenerator_Adapter.res.mjs +2 -0
  130. package/src/components/CommandGenerator/CommandGenerator_Builder.res +70 -0
  131. package/src/components/CommandGenerator/CommandGenerator_Builder.res.mjs +68 -0
  132. package/src/components/CommandGenerator/CommandGenerator_Callback.res +191 -0
  133. package/src/components/CommandGenerator/CommandGenerator_Callback.res.mjs +161 -0
  134. package/src/components/CommandTopic/CommandTopic.res +79 -0
  135. package/src/components/CommandTopic/CommandTopic.res.mjs +68 -0
  136. package/src/components/CommandTopic/CommandTopic_Adapter.res +53 -0
  137. package/src/components/CommandTopic/CommandTopic_Adapter.res.mjs +2 -0
  138. package/src/components/CommandTopic/CommandTopic_Builder.res +146 -0
  139. package/src/components/CommandTopic/CommandTopic_Builder.res.mjs +127 -0
  140. package/src/components/CommandTopic/CommandTopic_Callback.res +38 -0
  141. package/src/components/CommandTopic/CommandTopic_Callback.res.mjs +49 -0
  142. package/src/components/CommandTopic/CommandTopic_Helpers.res +176 -0
  143. package/src/components/CommandTopic/CommandTopic_Helpers.res.mjs +195 -0
  144. package/src/components/CommandTopic/CommandTopic_Operations.res +40 -0
  145. package/src/components/CommandTopic/CommandTopic_Operations.res.mjs +49 -0
  146. package/src/components/Component.res +1 -0
  147. package/src/components/Component.res.mjs +34 -0
  148. package/src/components/Component.resi +1 -0
  149. package/src/components/Counter/Counter.res +47 -0
  150. package/src/components/Counter/Counter.res.mjs +55 -0
  151. package/src/components/Counter/Counter_Adapter.res +18 -0
  152. package/src/components/Counter/Counter_Adapter.res.mjs +2 -0
  153. package/src/components/Counter/Counter_Builder.res +142 -0
  154. package/src/components/Counter/Counter_Builder.res.mjs +112 -0
  155. package/src/components/Counter/Counter_Callback.res +94 -0
  156. package/src/components/Counter/Counter_Callback.res.mjs +70 -0
  157. package/src/components/Counter/Counter_Operations.res +70 -0
  158. package/src/components/Counter/Counter_Operations.res.mjs +91 -0
  159. package/src/components/Dcb/Dcb_Builder.res +971 -0
  160. package/src/components/Dcb/Dcb_Builder.res.mjs +572 -0
  161. package/src/components/DcbEventLog/DcbEventLog.res +43 -0
  162. package/src/components/DcbEventLog/DcbEventLog.res.mjs +24 -0
  163. package/src/components/DcbEventLog/DcbEventLog_Adapter.res +57 -0
  164. package/src/components/DcbEventLog/DcbEventLog_Adapter.res.mjs +2 -0
  165. package/src/components/DcbEventLog/DcbEventLog_Builder.res +72 -0
  166. package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +67 -0
  167. package/src/components/DcbEventLog/DcbEventLog_Operations.res +160 -0
  168. package/src/components/DcbEventLog/DcbEventLog_Operations.res.mjs +121 -0
  169. package/src/components/EventCollector/EventCollector.res +34 -0
  170. package/src/components/EventCollector/EventCollector.res.mjs +9 -0
  171. package/src/components/EventCollector/EventCollector_Adapter.res +45 -0
  172. package/src/components/EventCollector/EventCollector_Adapter.res.mjs +2 -0
  173. package/src/components/EventCollector/EventCollector_Builder.res +91 -0
  174. package/src/components/EventCollector/EventCollector_Builder.res.mjs +64 -0
  175. package/src/components/EventLog/EventLog.res +27 -0
  176. package/src/components/EventLog/EventLog.res.mjs +13 -0
  177. package/src/components/EventLog/EventLog_Adapter.res +15 -0
  178. package/src/components/EventLog/EventLog_Adapter.res.mjs +2 -0
  179. package/src/components/EventLog/EventLog_Builder.res +65 -0
  180. package/src/components/EventLog/EventLog_Builder.res.mjs +57 -0
  181. package/src/components/EventLog/EventLog_Operations.res +209 -0
  182. package/src/components/EventLog/EventLog_Operations.res.mjs +202 -0
  183. package/src/components/EventLog/EventPublish_Callback.res +29 -0
  184. package/src/components/EventLog/EventPublish_Callback.res.mjs +32 -0
  185. package/src/components/EventMapper/EventMapper.res +72 -0
  186. package/src/components/EventMapper/EventMapper.res.mjs +54 -0
  187. package/src/components/EventMapper/EventMapper_Builder.res +128 -0
  188. package/src/components/EventMapper/EventMapper_Builder.res.mjs +81 -0
  189. package/src/components/EventMapper/EventMapper_Callback.res +323 -0
  190. package/src/components/EventMapper/EventMapper_Callback.res.mjs +231 -0
  191. package/src/components/EventTopic/EventTopic.res +69 -0
  192. package/src/components/EventTopic/EventTopic.res.mjs +50 -0
  193. package/src/components/EventTopic/EventTopic_Adapter.res +15 -0
  194. package/src/components/EventTopic/EventTopic_Adapter.res.mjs +2 -0
  195. package/src/components/EventTopic/EventTopic_Builder.res +53 -0
  196. package/src/components/EventTopic/EventTopic_Builder.res.mjs +46 -0
  197. package/src/components/EventTopic/EventTopic_Operations.res +37 -0
  198. package/src/components/EventTopic/EventTopic_Operations.res.mjs +39 -0
  199. package/src/components/Extension/Extension.res +32 -0
  200. package/src/components/Extension/Extension.res.mjs +9 -0
  201. package/src/components/Extension/Extension_Builder.res +82 -0
  202. package/src/components/Extension/Extension_Builder.res.mjs +57 -0
  203. package/src/components/Extension/Extension_Operations.res +203 -0
  204. package/src/components/Extension/Extension_Operations.res.mjs +154 -0
  205. package/src/components/ExtensionPoint/ExtensionPoint.res +49 -0
  206. package/src/components/ExtensionPoint/ExtensionPoint.res.mjs +25 -0
  207. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +163 -0
  208. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res.mjs +113 -0
  209. package/src/components/ExtensionPoint/ExtensionPoint_Callback.res +110 -0
  210. package/src/components/ExtensionPoint/ExtensionPoint_Callback.res.mjs +76 -0
  211. package/src/components/ExtensionPoint/ExtensionPoint_Operations.res +146 -0
  212. package/src/components/ExtensionPoint/ExtensionPoint_Operations.res.mjs +122 -0
  213. package/src/components/Heartbeat/Heartbeat.res +25 -0
  214. package/src/components/Heartbeat/Heartbeat.res.mjs +9 -0
  215. package/src/components/Heartbeat/Heartbeat_Adapter.res +14 -0
  216. package/src/components/Heartbeat/Heartbeat_Adapter.res.mjs +2 -0
  217. package/src/components/Heartbeat/Heartbeat_Builder.res +43 -0
  218. package/src/components/Heartbeat/Heartbeat_Builder.res.mjs +47 -0
  219. package/src/components/Heartbeat/Heartbeat_Callback.res +32 -0
  220. package/src/components/Heartbeat/Heartbeat_Callback.res.mjs +40 -0
  221. package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +34 -0
  222. package/src/components/InboundTranslationSlice/InboundTranslationSlice.res.mjs +24 -0
  223. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +98 -0
  224. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res.mjs +87 -0
  225. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +191 -0
  226. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +175 -0
  227. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res +35 -0
  228. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res.mjs +24 -0
  229. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +181 -0
  230. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res.mjs +137 -0
  231. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +173 -0
  232. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +173 -0
  233. package/src/components/QueryDb/QueryDb.res +74 -0
  234. package/src/components/QueryDb/QueryDb.res.mjs +37 -0
  235. package/src/components/QueryDb/QueryDb_Adapter.res +78 -0
  236. package/src/components/QueryDb/QueryDb_Adapter.res.mjs +17 -0
  237. package/src/components/QueryDb/QueryDb_Builder.res +76 -0
  238. package/src/components/QueryDb/QueryDb_Builder.res.mjs +53 -0
  239. package/src/components/QueryDb/QueryDb_Callback.res +18 -0
  240. package/src/components/QueryDb/QueryDb_Callback.res.mjs +21 -0
  241. package/src/components/QueryDb/QueryDb_Operations.res +116 -0
  242. package/src/components/QueryDb/QueryDb_Operations.res.mjs +165 -0
  243. package/src/components/ReadModel/ReadModel.res +42 -0
  244. package/src/components/ReadModel/ReadModel.res.mjs +27 -0
  245. package/src/components/ReadModel/ReadModel_Builder.res +155 -0
  246. package/src/components/ReadModel/ReadModel_Builder.res.mjs +101 -0
  247. package/src/components/ReadModel/ReadModel_Callback.res +48 -0
  248. package/src/components/ReadModel/ReadModel_Callback.res.mjs +48 -0
  249. package/src/components/Scheduler/Scheduler.res +13 -0
  250. package/src/components/Scheduler/Scheduler.res.mjs +9 -0
  251. package/src/components/Scheduler/Scheduler_Adapter.res +13 -0
  252. package/src/components/Scheduler/Scheduler_Adapter.res.mjs +2 -0
  253. package/src/components/Scheduler/Scheduler_Builder.res +19 -0
  254. package/src/components/Scheduler/Scheduler_Builder.res.mjs +29 -0
  255. package/src/components/SideEffectHandler/SideEffectHandler.res +30 -0
  256. package/src/components/SideEffectHandler/SideEffectHandler.res.mjs +12 -0
  257. package/src/components/SideEffectHandler/SideEffectHandler_Builder.res +117 -0
  258. package/src/components/SideEffectHandler/SideEffectHandler_Builder.res.mjs +64 -0
  259. package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +116 -0
  260. package/src/components/SideEffectHandler/SideEffectHandler_Callback.res.mjs +95 -0
  261. package/src/components/StateChangeSlice/StateChangeSlice.res +38 -0
  262. package/src/components/StateChangeSlice/StateChangeSlice.res.mjs +17 -0
  263. package/src/components/StateChangeSlice/StateChangeSlice_Builder.res +91 -0
  264. package/src/components/StateChangeSlice/StateChangeSlice_Builder.res.mjs +81 -0
  265. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +412 -0
  266. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +299 -0
  267. package/src/components/StateTopic.res +91 -0
  268. package/src/components/StateTopic.res.mjs +41 -0
  269. package/src/components/StateViewSlice/StateViewSlice.res +33 -0
  270. package/src/components/StateViewSlice/StateViewSlice.res.mjs +24 -0
  271. package/src/components/StateViewSlice/StateViewSlice_Builder.res +176 -0
  272. package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +134 -0
  273. package/src/components/StateViewSlice/StateViewSlice_Callback.res +64 -0
  274. package/src/components/StateViewSlice/StateViewSlice_Callback.res.mjs +56 -0
  275. package/src/components/Task/Task.res +81 -0
  276. package/src/components/Task/Task.res.mjs +51 -0
  277. package/src/components/Task/Task_Adapter.res +31 -0
  278. package/src/components/Task/Task_Adapter.res.mjs +2 -0
  279. package/src/components/Task/Task_Builder.res +223 -0
  280. package/src/components/Task/Task_Builder.res.mjs +115 -0
  281. package/src/plugin/api/PluginBaseFragment.res +104 -0
  282. package/src/plugin/api/PluginBaseFragment.res.mjs +64 -0
  283. package/src/plugin/component/Plugin.res +100 -0
  284. package/src/plugin/component/Plugin.res.mjs +61 -0
  285. package/src/plugin/component/Plugin_Builder.res +1017 -0
  286. package/src/plugin/component/Plugin_Builder.res.mjs +608 -0
  287. package/src/plugin/component/Plugin_BuiltHook.res +141 -0
  288. package/src/plugin/component/Plugin_BuiltHook.res.mjs +39 -0
  289. package/src/plugin/component/Plugin_Callback.res +98 -0
  290. package/src/plugin/component/Plugin_Callback.res.mjs +55 -0
  291. package/src/plugin/component/Plugin_Helpers.res +1730 -0
  292. package/src/plugin/component/Plugin_Helpers.res.mjs +1010 -0
  293. package/src/plugin/component/Plugin_ResolverError.res +27 -0
  294. package/src/plugin/component/Plugin_ResolverError.res.mjs +21 -0
  295. package/src/plugin/component/Plugin_Structure.res +570 -0
  296. package/src/plugin/component/Plugin_Structure.res.mjs +458 -0
  297. package/src/plugin/component/Plugin_SubscriptionSchema.res +103 -0
  298. package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +71 -0
  299. package/src/plugin/component/SchemaWalker.res +164 -0
  300. package/src/plugin/component/SchemaWalker.res.mjs +183 -0
  301. package/src/plugin/connect/PluginConnectExtension_Builder.res +14 -0
  302. package/src/plugin/connect/PluginConnectExtension_Builder.res.mjs +36 -0
  303. package/src/plugin/connect/PluginConnectExtension_Mapping.res +76 -0
  304. package/src/plugin/connect/PluginConnectExtension_Mapping.res.mjs +89 -0
  305. package/src/plugin/connect/PluginExtensionPoint_Builder.res +39 -0
  306. package/src/plugin/connect/PluginExtensionPoint_Builder.res.mjs +33 -0
  307. package/src/plugin/connect/PluginExtensionPoint_Plugin.res +231 -0
  308. package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +353 -0
  309. package/src/plugin/lifecycle/PluginBehavior.res +250 -0
  310. package/src/plugin/lifecycle/PluginBehavior.res.mjs +391 -0
  311. package/src/plugin/lifecycle/PluginSpec.res +84 -0
  312. package/src/plugin/lifecycle/PluginSpec.res.mjs +148 -0
  313. package/src/plugin/lifecycle/PluginsProjection.res +154 -0
  314. package/src/plugin/lifecycle/PluginsProjection.res.mjs +230 -0
  315. package/src/plugin/lifecycle/PluginsReadModelSpec.res +66 -0
  316. package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +58 -0
  317. package/src/util/AWS.res +7 -0
  318. package/src/util/AWS.res.mjs +20 -0
  319. package/src/util/CSV.res +27 -0
  320. package/src/util/CSV.res.mjs +56 -0
  321. package/src/util/CommandPublisher.res +133 -0
  322. package/src/util/CommandPublisher.res.mjs +161 -0
  323. package/src/util/CsvStream.res +39 -0
  324. package/src/util/CsvStream.res.mjs +42 -0
  325. package/src/util/EffectLogger.res +178 -0
  326. package/src/util/EffectLogger.res.mjs +171 -0
  327. package/src/util/FTP.res +69 -0
  328. package/src/util/FTP.res.mjs +101 -0
  329. package/src/util/FTPHandler.res +142 -0
  330. package/src/util/FTPHandler.res.mjs +136 -0
  331. package/src/util/Hash.res +1 -0
  332. package/src/util/Hash.res.mjs +10 -0
  333. package/src/util/Interstack.res +74 -0
  334. package/src/util/Interstack.res.mjs +126 -0
  335. package/src/util/Interstack.resi +25 -0
  336. package/src/util/LogFormat.res +222 -0
  337. package/src/util/LogFormat.res.mjs +257 -0
  338. package/src/util/Logger.res +196 -0
  339. package/src/util/Logger.res.mjs +238 -0
  340. package/src/util/Lru.res +51 -0
  341. package/src/util/Lru.res.mjs +59 -0
  342. package/src/util/Lru.resi +32 -0
  343. package/src/util/Metrics.res +32 -0
  344. package/src/util/Metrics.res.mjs +42 -0
  345. package/src/util/OutputFailsafeDeploytime.res +16 -0
  346. package/src/util/OutputFailsafeDeploytime.res.mjs +20 -0
  347. package/src/util/OutputFailsafeRuntime.res +6 -0
  348. package/src/util/OutputFailsafeRuntime.res.mjs +15 -0
  349. package/src/util/OutputLogger.res +9 -0
  350. package/src/util/OutputLogger.res.mjs +19 -0
  351. package/src/util/ResourceQuery.res +14 -0
  352. package/src/util/ResourceQuery.res.mjs +17 -0
  353. package/src/util/ResourceQueryRuntime.res +17 -0
  354. package/src/util/ResourceQueryRuntime.res.mjs +18 -0
  355. package/src/util/ScheduleOps.res +124 -0
  356. package/src/util/ScheduleOps.res.mjs +132 -0
  357. package/src/util/Util.res +12 -0
  358. package/src/util/Util.res.mjs +42 -0
  359. package/src/util/Util_Adapter.res +97 -0
  360. package/src/util/Util_Adapter.res.mjs +82 -0
  361. package/src/util/Util_AdapterRuntime.res +39 -0
  362. package/src/util/Util_AdapterRuntime.res.mjs +42 -0
  363. package/src/util/Util_Array.res +2 -0
  364. package/src/util/Util_Array.res.mjs +12 -0
  365. package/src/util/Util_Error.res +16 -0
  366. package/src/util/Util_Error.res.mjs +19 -0
  367. package/src/util/Util_Promise.res +67 -0
  368. package/src/util/Util_Promise.res.mjs +105 -0
  369. package/src/util/Util_Pulumi.res +35 -0
  370. package/src/util/Util_Pulumi.res.mjs +55 -0
  371. package/src/util/Util_Pulumi.resi +21 -0
  372. package/src/util/Util_QueryDb.res +14 -0
  373. package/src/util/Util_QueryDb.res.mjs +21 -0
  374. package/src/util/Util_QueryDbRuntime.res +11 -0
  375. package/src/util/Util_QueryDbRuntime.res.mjs +19 -0
  376. package/src/util/Util_ReadModel.res +2 -0
  377. package/src/util/Util_ReadModel.res.mjs +10 -0
  378. package/src/util/Util_StackRefs.res +24 -0
  379. package/src/util/Util_StackRefs.res.mjs +39 -0
  380. package/src/util/Validation.res +75 -0
  381. package/src/util/Validation.res.mjs +181 -0
  382. package/tests/.gitkeep +0 -0
  383. package/tests/IdentityTest.res +155 -0
  384. package/tests/IdentityTest.res.mjs +174 -0
  385. package/tests/admin/Platform_ComponentDefinitionsApiTest.res +237 -0
  386. package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +298 -0
  387. package/tests/admin/Platform_UIFragmentsApiTest.res +96 -0
  388. package/tests/admin/Platform_UIFragmentsApiTest.res.mjs +101 -0
  389. package/tests/aggregate/AggregateCallbackTest.res +81 -0
  390. package/tests/aggregate/AggregateCallbackTest.res.mjs +140 -0
  391. package/tests/aggregate/AggregateCausationTest.res +49 -0
  392. package/tests/aggregate/AggregateCausationTest.res.mjs +44 -0
  393. package/tests/aggregate/AggregateConflictTest.res +212 -0
  394. package/tests/aggregate/AggregateConflictTest.res.mjs +363 -0
  395. package/tests/aggregate/AggregateFixtures.res +177 -0
  396. package/tests/aggregate/AggregateFixtures.res.mjs +285 -0
  397. package/tests/aggregate/AggregateRejectionTest.res +139 -0
  398. package/tests/aggregate/AggregateRejectionTest.res.mjs +163 -0
  399. package/tests/api/ApiNoApiTest.res +62 -0
  400. package/tests/api/ApiNoApiTest.res.mjs +90 -0
  401. package/tests/api/GraphQL_StitcherTest.res +107 -0
  402. package/tests/api/GraphQL_StitcherTest.res.mjs +99 -0
  403. package/tests/api/SimpleTest.res +7 -0
  404. package/tests/api/SimpleTest.res.mjs +10 -0
  405. package/tests/api/SuryToJsonSchemaTest.res +405 -0
  406. package/tests/api/SuryToJsonSchemaTest.res.mjs +623 -0
  407. package/tests/commandgenerator/CommandGeneratorCallbackTest.res +128 -0
  408. package/tests/commandgenerator/CommandGeneratorCallbackTest.res.mjs +160 -0
  409. package/tests/commandgenerator/CommandGeneratorFixtures.res +139 -0
  410. package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +197 -0
  411. package/tests/commandtopic/CommandTopicCallbackFixtures.res +87 -0
  412. package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +152 -0
  413. package/tests/commandtopic/CommandTopicCallbackTest.res +66 -0
  414. package/tests/commandtopic/CommandTopicCallbackTest.res.mjs +106 -0
  415. package/tests/commandtopic/CommandTopicHelpersRejectionTest.res +83 -0
  416. package/tests/commandtopic/CommandTopicHelpersRejectionTest.res.mjs +109 -0
  417. package/tests/counter/CounterCallbackTest.res +83 -0
  418. package/tests/counter/CounterCallbackTest.res.mjs +140 -0
  419. package/tests/counter/CounterFixtures.res +57 -0
  420. package/tests/counter/CounterFixtures.res.mjs +67 -0
  421. package/tests/dcb/DcbDecodeTest.res +122 -0
  422. package/tests/dcb/DcbDecodeTest.res.mjs +194 -0
  423. package/tests/dcb/DcbEventLogOperationsTest.res +195 -0
  424. package/tests/dcb/DcbEventLogOperationsTest.res.mjs +268 -0
  425. package/tests/dcb/DcbFixtures.res +422 -0
  426. package/tests/dcb/DcbFixtures.res.mjs +534 -0
  427. package/tests/dcb/DcbScopeInferenceTest.res +242 -0
  428. package/tests/dcb/DcbScopeInferenceTest.res.mjs +480 -0
  429. package/tests/dcb/DcbStateChangeSliceTest.res +362 -0
  430. package/tests/dcb/DcbStateChangeSliceTest.res.mjs +546 -0
  431. package/tests/dcb/DcbTagTest.res +978 -0
  432. package/tests/dcb/DcbTagTest.res.mjs +867 -0
  433. package/tests/dcb/DcbValidationTest.res +349 -0
  434. package/tests/dcb/DcbValidationTest.res.mjs +476 -0
  435. package/tests/eventlog/EventLogFixtures.res +113 -0
  436. package/tests/eventlog/EventLogFixtures.res.mjs +166 -0
  437. package/tests/eventlog/EventLogOperationsTest.res +96 -0
  438. package/tests/eventlog/EventLogOperationsTest.res.mjs +192 -0
  439. package/tests/eventlog/EventLogRetryTest.res +121 -0
  440. package/tests/eventlog/EventLogRetryTest.res.mjs +171 -0
  441. package/tests/eventmapper/EventMapperCallbackTest.res +134 -0
  442. package/tests/eventmapper/EventMapperCallbackTest.res.mjs +141 -0
  443. package/tests/eventmapper/EventMapperFixtures.res +255 -0
  444. package/tests/eventmapper/EventMapperFixtures.res.mjs +440 -0
  445. package/tests/eventmapper/EventMapperTest.res +53 -0
  446. package/tests/eventmapper/EventMapperTest.res.mjs +83 -0
  447. package/tests/eventtopic/EventTopicFixtures.res +36 -0
  448. package/tests/eventtopic/EventTopicFixtures.res.mjs +65 -0
  449. package/tests/eventtopic/EventTopicOperationsTest.res +48 -0
  450. package/tests/eventtopic/EventTopicOperationsTest.res.mjs +71 -0
  451. package/tests/extensionpoint/ExtensionPointCallbackTest.res +84 -0
  452. package/tests/extensionpoint/ExtensionPointCallbackTest.res.mjs +94 -0
  453. package/tests/extensionpoint/ExtensionPointFixtures.res +173 -0
  454. package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +205 -0
  455. package/tests/extensionpoint/ExtensionPointOperationsTest.res +261 -0
  456. package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +304 -0
  457. package/tests/ftp/FTPTest.res +64 -0
  458. package/tests/ftp/FTPTest.res.mjs +88 -0
  459. package/tests/logger/LogFormatTest.res +348 -0
  460. package/tests/logger/LogFormatTest.res.mjs +309 -0
  461. package/tests/message/MessageTest.res +95 -0
  462. package/tests/message/MessageTest.res.mjs +93 -0
  463. package/tests/message/MetaEnvelopeTest.res +200 -0
  464. package/tests/message/MetaEnvelopeTest.res.mjs +188 -0
  465. package/tests/plugin/ManifestVisibilityTest.res +137 -0
  466. package/tests/plugin/ManifestVisibilityTest.res.mjs +205 -0
  467. package/tests/plugin/PluginSpecExperiment.res +13 -0
  468. package/tests/plugin/PluginSpecExperiment.res.mjs +31 -0
  469. package/tests/plugin/PluginStructureTest.res +298 -0
  470. package/tests/plugin/PluginStructureTest.res.mjs +388 -0
  471. package/tests/plugin/PluginVersionTest.res +34 -0
  472. package/tests/plugin/PluginVersionTest.res.mjs +30 -0
  473. package/tests/plugin/SchemaWalkerTest.res +115 -0
  474. package/tests/plugin/SchemaWalkerTest.res.mjs +160 -0
  475. package/tests/plugin/StateChangeSlice/PsPlaceOrder.res +24 -0
  476. package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +62 -0
  477. package/tests/plugin/StateChangeSlice/PsShipOrder.res +29 -0
  478. package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +69 -0
  479. package/tests/plugin/StateViewSlice/PsAnnotatedView.res +24 -0
  480. package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +94 -0
  481. package/tests/plugin/StateViewSlice/PsAvailableProductsView.res +18 -0
  482. package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +69 -0
  483. package/tests/plugin/StateViewSlice/PsCustomersView.res +22 -0
  484. package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +69 -0
  485. package/tests/plugin/StateViewSlice/PsOrdersView.res +20 -0
  486. package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +81 -0
  487. package/tests/poc/StructuralSubtypingPoc.res +211 -0
  488. package/tests/poc/StructuralSubtypingPoc.res.mjs +61 -0
  489. package/tests/querydb/QueryDbFixtures.res +65 -0
  490. package/tests/querydb/QueryDbFixtures.res.mjs +135 -0
  491. package/tests/querydb/QueryDbOperationsTest.res +94 -0
  492. package/tests/querydb/QueryDbOperationsTest.res.mjs +168 -0
  493. package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res +56 -0
  494. package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res.mjs +77 -0
  495. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +96 -0
  496. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +139 -0
  497. package/tests/util/CsvStreamTest.res +54 -0
  498. package/tests/util/CsvStreamTest.res.mjs +51 -0
  499. package/tests/util/LruTest.res +73 -0
  500. package/tests/util/LruTest.res.mjs +105 -0
  501. package/tests/util/MetricsTest.res +36 -0
  502. package/tests/util/MetricsTest.res.mjs +53 -0
@@ -0,0 +1,978 @@
1
+ open JestGlobals
2
+
3
+ describe("DcbTag:", () => {
4
+ describe("jsonValueToString", () => {
5
+ testSync(
6
+ "converts string value",
7
+ () => expect(Reventless.DcbTag.jsonValueToString(JSON.String("hello")))->toBe("hello"),
8
+ )
9
+
10
+ testSync(
11
+ "converts integer-like number",
12
+ () => expect(Reventless.DcbTag.jsonValueToString(JSON.Number(42.)))->toBe("42"),
13
+ )
14
+
15
+ testSync(
16
+ "converts float number",
17
+ () => expect(Reventless.DcbTag.jsonValueToString(JSON.Number(3.14)))->toBe("3.14"),
18
+ )
19
+
20
+ testSync(
21
+ "converts boolean true",
22
+ () => expect(Reventless.DcbTag.jsonValueToString(JSON.Boolean(true)))->toBe("true"),
23
+ )
24
+
25
+ testSync(
26
+ "converts boolean false",
27
+ () => expect(Reventless.DcbTag.jsonValueToString(JSON.Boolean(false)))->toBe("false"),
28
+ )
29
+
30
+ testSync(
31
+ "converts null",
32
+ () => expect(Reventless.DcbTag.jsonValueToString(JSON.Null))->toBe("null"),
33
+ )
34
+
35
+ testSync(
36
+ "converts array via JSON.stringify",
37
+ () =>
38
+ expect(
39
+ Reventless.DcbTag.jsonValueToString(JSON.Array([JSON.Number(1.), JSON.Number(2.)])),
40
+ )->toBe("[1,2]"),
41
+ )
42
+ })
43
+
44
+ describe("isTagged", () => {
45
+ testSync(
46
+ "returns true for Reventless.DcbTag.string schema",
47
+ () =>
48
+ expect(
49
+ Reventless.DcbTag.isTagged(Reventless.DcbTag.string->Reventless.DcbTag.toUnknownSchema),
50
+ )->toBe(true),
51
+ )
52
+
53
+ testSync(
54
+ "returns true for Reventless.DcbTag.int schema",
55
+ () =>
56
+ expect(
57
+ Reventless.DcbTag.isTagged(Reventless.DcbTag.int->Reventless.DcbTag.toUnknownSchema),
58
+ )->toBe(true),
59
+ )
60
+
61
+ testSync(
62
+ "returns false for plain S.string schema",
63
+ () =>
64
+ expect(Reventless.DcbTag.isTagged(S.string->Reventless.DcbTag.toUnknownSchema))->toBe(
65
+ false,
66
+ ),
67
+ )
68
+ })
69
+
70
+ describe("extractTags from variant (Union) schema", () => {
71
+ testSync(
72
+ "extracts itemId tag from ItemCreated",
73
+ () =>
74
+ expect(
75
+ Reventless.DcbTag.extractTags(
76
+ DcbFixtures.TestEventLogSpec.eventSchema,
77
+ DcbFixtures.TestEventLogSpec.ItemCreated({itemId: "item-1", name: "Test"}),
78
+ ),
79
+ )->toEqual([{Reventless.DcbTag.key: "itemId", value: "item-1"}]),
80
+ )
81
+
82
+ testSync(
83
+ "extracts itemId tag from ItemRenamed",
84
+ () =>
85
+ expect(
86
+ Reventless.DcbTag.extractTags(
87
+ DcbFixtures.TestEventLogSpec.eventSchema,
88
+ DcbFixtures.TestEventLogSpec.ItemRenamed({itemId: "item-2", newName: "Updated"}),
89
+ ),
90
+ )->toEqual([{Reventless.DcbTag.key: "itemId", value: "item-2"}]),
91
+ )
92
+
93
+ testSync(
94
+ "extracts multiple tags from CountUpdated",
95
+ () =>
96
+ expect(
97
+ Reventless.DcbTag.extractTags(
98
+ DcbFixtures.TestEventLogSpec.eventSchema,
99
+ DcbFixtures.TestEventLogSpec.CountUpdated({category: "electronics", amount: 42}),
100
+ ),
101
+ )->toEqual([
102
+ {Reventless.DcbTag.key: "category", value: "electronics"},
103
+ {key: "amount", value: "42"},
104
+ ]),
105
+ )
106
+
107
+ testSync(
108
+ "returns empty array for SimpleEvent (no payload)",
109
+ () =>
110
+ expect(
111
+ Reventless.DcbTag.extractTags(
112
+ DcbFixtures.TestEventLogSpec.eventSchema,
113
+ DcbFixtures.TestEventLogSpec.SimpleEvent,
114
+ ),
115
+ )->toEqual([]),
116
+ )
117
+
118
+ testSync(
119
+ "returns empty array for untagged PlainEvent",
120
+ () =>
121
+ expect(
122
+ Reventless.DcbTag.extractTags(
123
+ DcbFixtures.UntaggedEventSpec.eventSchema,
124
+ DcbFixtures.UntaggedEventSpec.PlainEvent({name: "test", value: 1}),
125
+ ),
126
+ )->toEqual([]),
127
+ )
128
+
129
+ testSync(
130
+ "returns empty array for untagged EmptyEvent",
131
+ () =>
132
+ expect(
133
+ Reventless.DcbTag.extractTags(
134
+ DcbFixtures.UntaggedEventSpec.eventSchema,
135
+ DcbFixtures.UntaggedEventSpec.EmptyEvent,
136
+ ),
137
+ )->toEqual([]),
138
+ )
139
+ })
140
+
141
+ describe("extractTags from Object schema", () => {
142
+ testSync(
143
+ "extracts tenantId tag from object record",
144
+ () =>
145
+ expect(
146
+ Reventless.DcbTag.extractTags(
147
+ DcbFixtures.objectEventSchema,
148
+ {DcbFixtures.tenantId: "tenant-1", data: "test"},
149
+ ),
150
+ )->toEqual([{Reventless.DcbTag.key: "tenantId", value: "tenant-1"}]),
151
+ )
152
+ })
153
+
154
+ describe("extractTags from command schema", () => {
155
+ testSync(
156
+ "extracts itemId tag from CreateItem command",
157
+ () =>
158
+ expect(
159
+ Reventless.DcbTag.extractTags(
160
+ DcbFixtures.TestCommandSpec.commandSchema,
161
+ DcbFixtures.TestCommandSpec.CreateItem({itemId: "item-1", name: "Test"}),
162
+ ),
163
+ )->toEqual([{Reventless.DcbTag.key: "itemId", value: "item-1"}]),
164
+ )
165
+
166
+ testSync(
167
+ "extracts itemId tag from RenameItem command",
168
+ () =>
169
+ expect(
170
+ Reventless.DcbTag.extractTags(
171
+ DcbFixtures.TestCommandSpec.commandSchema,
172
+ DcbFixtures.TestCommandSpec.RenameItem({itemId: "item-3", newName: "New"}),
173
+ ),
174
+ )->toEqual([{Reventless.DcbTag.key: "itemId", value: "item-3"}]),
175
+ )
176
+ })
177
+
178
+ describe("extractTaggedFields from schema", () => {
179
+ describe(
180
+ "Union (variant) schemas",
181
+ () => {
182
+ testSync(
183
+ "extracts all unique tagged field names from event schema",
184
+ () =>
185
+ expect(
186
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.TestEventLogSpec.eventSchema),
187
+ )->toEqual(["amount", "category", "itemId"]),
188
+ )
189
+
190
+ testSync(
191
+ "extracts tagged field names from command schema",
192
+ () =>
193
+ expect(
194
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.TestCommandSpec.commandSchema),
195
+ )->toEqual(["itemId"]),
196
+ )
197
+
198
+ testSync(
199
+ "returns empty array for untagged variant schema",
200
+ () =>
201
+ expect(
202
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.UntaggedEventSpec.eventSchema),
203
+ )->toEqual([]),
204
+ )
205
+
206
+ testSync(
207
+ "deduplicates field names across variants",
208
+ () => {
209
+ // TestEventLogSpec has:
210
+ // - ItemCreated: itemId
211
+ // - ItemRenamed: itemId
212
+ // - CountUpdated: category, amount
213
+ // Should return sorted unique: ["amount", "category", "itemId"]
214
+ let fields = Reventless.DcbTag.extractTaggedFields(
215
+ DcbFixtures.TestEventLogSpec.eventSchema,
216
+ )
217
+ expect(fields)->toEqual(["amount", "category", "itemId"])
218
+ },
219
+ )
220
+
221
+ testSync(
222
+ "returns sorted field names",
223
+ () => {
224
+ let fields = Reventless.DcbTag.extractTaggedFields(
225
+ DcbFixtures.TestEventLogSpec.eventSchema,
226
+ )
227
+ let sorted = fields->Array.toSorted((a, b) => String.compare(a, b))
228
+ // Verify alphabetical sorting - should already be sorted
229
+ expect(fields)->toEqual(sorted)
230
+ },
231
+ )
232
+ },
233
+ )
234
+
235
+ describe(
236
+ "Object (record) schemas",
237
+ () => {
238
+ testSync(
239
+ "extracts tagged field names from object schema",
240
+ () =>
241
+ expect(Reventless.DcbTag.extractTaggedFields(DcbFixtures.objectEventSchema))->toEqual([
242
+ "tenantId",
243
+ ]),
244
+ )
245
+
246
+ testSync(
247
+ "returns empty array for object with no tagged fields",
248
+ () =>
249
+ expect(
250
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.plainRecordSchema),
251
+ )->toEqual([]),
252
+ )
253
+
254
+ testSync(
255
+ "extracts multiple tagged fields from object schema",
256
+ () =>
257
+ expect(
258
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.multiTagRecordSchema),
259
+ )->toEqual(["tenantId", "userId"]),
260
+ )
261
+ },
262
+ )
263
+
264
+ describe(
265
+ "Edge cases",
266
+ () => {
267
+ testSync(
268
+ "handles variants with no payload (SimpleEvent)",
269
+ () => {
270
+ // TestEventLogSpec includes SimpleEvent which has no payload
271
+ // Should still extract fields from other variants
272
+ let fields = Reventless.DcbTag.extractTaggedFields(
273
+ DcbFixtures.TestEventLogSpec.eventSchema,
274
+ )
275
+ expect(fields->Array.length)->toBeGreaterThan(0)
276
+ },
277
+ )
278
+
279
+ testSync(
280
+ "handles schema with mix of tagged and untagged fields",
281
+ () =>
282
+ expect(Reventless.DcbTag.extractTaggedFields(DcbFixtures.mixedEventSchema))->toEqual([
283
+ "id",
284
+ ]),
285
+ )
286
+
287
+ testSync(
288
+ "handles empty schema gracefully",
289
+ () =>
290
+ expect(
291
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.emptyVariantSchema),
292
+ )->toEqual([]),
293
+ )
294
+
295
+ testSync(
296
+ "handles schema with int tags",
297
+ () =>
298
+ expect(Reventless.DcbTag.extractTaggedFields(DcbFixtures.intTagEventSchema))->toEqual([
299
+ "count",
300
+ ]),
301
+ )
302
+ },
303
+ )
304
+
305
+ describe(
306
+ "isTaggedArray",
307
+ () => {
308
+ testSync(
309
+ "returns true for array of tagged strings",
310
+ () => {
311
+ let schema = S.array(Reventless.DcbTag.string)->Reventless.DcbTag.toUnknownSchema
312
+ expect(Reventless.DcbTag.isTaggedArray(schema))->toBe(true)
313
+ },
314
+ )
315
+
316
+ testSync(
317
+ "returns false for array of plain strings",
318
+ () => {
319
+ let schema = S.array(S.string)->Reventless.DcbTag.toUnknownSchema
320
+ expect(Reventless.DcbTag.isTaggedArray(schema))->toBe(false)
321
+ },
322
+ )
323
+
324
+ testSync(
325
+ "returns false for tagged scalar",
326
+ () =>
327
+ expect(
328
+ Reventless.DcbTag.isTaggedArray(
329
+ Reventless.DcbTag.string->Reventless.DcbTag.toUnknownSchema,
330
+ ),
331
+ )->toBe(false),
332
+ )
333
+
334
+ testSync(
335
+ "returns false for plain string",
336
+ () =>
337
+ expect(
338
+ Reventless.DcbTag.isTaggedArray(S.string->Reventless.DcbTag.toUnknownSchema),
339
+ )->toBe(false),
340
+ )
341
+ },
342
+ )
343
+
344
+ describe(
345
+ "Complex schemas",
346
+ () => {
347
+ testSync(
348
+ "extracts from schema with many variants and fields",
349
+ () =>
350
+ expect(Reventless.DcbTag.extractTaggedFields(DcbFixtures.complexEventSchema))->toEqual([
351
+ "orderId",
352
+ "paymentId",
353
+ "trackingId",
354
+ "userId",
355
+ ]),
356
+ )
357
+
358
+ testSync(
359
+ "handles variants with multiple tagged fields in same variant",
360
+ () =>
361
+ expect(
362
+ Reventless.DcbTag.extractTaggedFields(DcbFixtures.multiFieldEventSchema),
363
+ )->toEqual(["sessionId", "tenantId", "userId"]),
364
+ )
365
+ },
366
+ )
367
+ })
368
+
369
+ describe("extractTagsExpanded (array expansion)", () => {
370
+ testSync(
371
+ "expands array tagged field into per-element tags",
372
+ () =>
373
+ expect(
374
+ Reventless.DcbTag.extractTagsExpanded(
375
+ DcbFixtures.crossEntityCommandSchema,
376
+ DcbFixtures.PlaceOrder({
377
+ orderId: "ord-1",
378
+ customerId: "cust-1",
379
+ productId: ["prod-1", "prod-2"],
380
+ }),
381
+ ),
382
+ )->toEqual([
383
+ {Reventless.DcbTag.key: "orderId", value: "ord-1"},
384
+ {key: "productId", value: "prod-1"},
385
+ {key: "productId", value: "prod-2"},
386
+ ]),
387
+ )
388
+
389
+ testSync(
390
+ "handles empty array tagged field",
391
+ () =>
392
+ expect(
393
+ Reventless.DcbTag.extractTagsExpanded(
394
+ DcbFixtures.crossEntityCommandSchema,
395
+ DcbFixtures.PlaceOrder({orderId: "ord-1", customerId: "cust-1", productId: []}),
396
+ ),
397
+ )->toEqual([{Reventless.DcbTag.key: "orderId", value: "ord-1"}]),
398
+ )
399
+
400
+ testSync(
401
+ "scalar tagged fields unchanged",
402
+ () =>
403
+ expect(
404
+ Reventless.DcbTag.extractTagsExpanded(
405
+ DcbFixtures.singleTagCommandSchema,
406
+ DcbFixtures.CreateItem({itemId: "item-1", name: "Test"}),
407
+ ),
408
+ )->toEqual([{Reventless.DcbTag.key: "itemId", value: "item-1"}]),
409
+ )
410
+ })
411
+
412
+ describe("extractCompositePartitionFields", () => {
413
+ testSync(
414
+ "extracts 3 fields from single-variant composite schema",
415
+ () => {
416
+ let fields = Reventless.DcbTag.extractCompositePartitionFields(
417
+ DcbFixtures.compositeEventSchema,
418
+ )
419
+ expect(fields->Array.length)->toBe(3)->ignore
420
+ expect(fields->Array.map(f => f.name))->toEqual(["environment", "platformName", "pluginName"])
421
+ },
422
+ )
423
+
424
+ testSync(
425
+ "fields are sorted by position",
426
+ () => {
427
+ let fields = Reventless.DcbTag.extractCompositePartitionFields(
428
+ DcbFixtures.compositeEventSchema,
429
+ )
430
+ let positions = fields->Array.map(f => f.position)
431
+ expect(positions)->toEqual([0, 1, 2])
432
+ },
433
+ )
434
+
435
+ testSync(
436
+ "extracts separator values",
437
+ () => {
438
+ let fields = Reventless.DcbTag.extractCompositePartitionFields(
439
+ DcbFixtures.compositeEventCustomSepSchema,
440
+ )
441
+ expect(fields->Array.map(f => f.sep))->toEqual([":", "/", "/"])
442
+ },
443
+ )
444
+
445
+ testSync(
446
+ "deduplicates fields across variants",
447
+ () => {
448
+ let fields = Reventless.DcbTag.extractCompositePartitionFields(
449
+ DcbFixtures.compositeMultiVariantSchema,
450
+ )
451
+ expect(fields->Array.length)->toBe(2)->ignore
452
+ expect(fields->Array.map(f => f.name))->toEqual(["env", "name"])
453
+ },
454
+ )
455
+
456
+ testSync(
457
+ "returns empty for schema without composite fields",
458
+ () => {
459
+ let fields = Reventless.DcbTag.extractCompositePartitionFields(
460
+ DcbFixtures.TestEventLogSpec.eventSchema,
461
+ )
462
+ expect(fields)->toEqual([])
463
+ },
464
+ )
465
+ })
466
+
467
+ describe("getCompositePartitionKeyValue", () => {
468
+ testSync(
469
+ "joins values with default separator",
470
+ () => {
471
+ let spec: Reventless.DcbTag.compositePartitionSpec = {
472
+ keys: ["environment", "platformName", "pluginName"],
473
+ seps: ["/", "/"],
474
+ }
475
+ let tags: array<Reventless.DcbTag.tag> = [
476
+ {key: "environment", value: "prod"},
477
+ {key: "platformName", value: "aws"},
478
+ {key: "pluginName", value: "catalog"},
479
+ ]
480
+ expect(Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec))->toBe(
481
+ "prod/aws/catalog",
482
+ )
483
+ },
484
+ )
485
+
486
+ testSync(
487
+ "joins values with mixed separators",
488
+ () => {
489
+ let spec: Reventless.DcbTag.compositePartitionSpec = {
490
+ keys: ["tenantId", "region", "service"],
491
+ seps: [":", "/"],
492
+ }
493
+ let tags: array<Reventless.DcbTag.tag> = [
494
+ {key: "tenantId", value: "acme"},
495
+ {key: "region", value: "eu-west-1"},
496
+ {key: "service", value: "auth"},
497
+ ]
498
+ expect(Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec))->toBe(
499
+ "acme:eu-west-1/auth",
500
+ )
501
+ },
502
+ )
503
+
504
+ testSync(
505
+ "uses empty string for missing tag values",
506
+ () => {
507
+ let spec: Reventless.DcbTag.compositePartitionSpec = {
508
+ keys: ["a", "b"],
509
+ seps: ["/"],
510
+ }
511
+ let tags: array<Reventless.DcbTag.tag> = [{key: "a", value: "x"}]
512
+ expect(Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec))->toBe("x/")
513
+ },
514
+ )
515
+
516
+ testSync(
517
+ "handles tags in different order than keys",
518
+ () => {
519
+ let spec: Reventless.DcbTag.compositePartitionSpec = {
520
+ keys: ["a", "b", "c"],
521
+ seps: ["/", "/"],
522
+ }
523
+ let tags: array<Reventless.DcbTag.tag> = [
524
+ {key: "c", value: "3"},
525
+ {key: "a", value: "1"},
526
+ {key: "b", value: "2"},
527
+ ]
528
+ expect(Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec))->toBe("1/2/3")
529
+ },
530
+ )
531
+ })
532
+
533
+ describe("derivePartitionTag", () => {
534
+ let u = S.castToUnknown
535
+
536
+ testSync(
537
+ "returns Composite for schema with >= 2 composite fields",
538
+ () => {
539
+ let result = Reventless.DcbTag.derivePartitionTag([
540
+ ("Sync", "test.res", DcbFixtures.compositeEventSchema->u),
541
+ ])
542
+ switch result {
543
+ | Composite(spec) =>
544
+ expect(spec.keys)->toEqual(["environment", "platformName", "pluginName"])->ignore
545
+ expect(spec.seps)->toEqual(["/", "/"])
546
+ | Simple(_) => fail("Expected Composite")
547
+ }
548
+ },
549
+ )
550
+
551
+ testSync(
552
+ "returns Composite with custom separators",
553
+ () => {
554
+ let result = Reventless.DcbTag.derivePartitionTag([
555
+ ("Config", "test.res", DcbFixtures.compositeEventCustomSepSchema->u),
556
+ ])
557
+ switch result {
558
+ | Composite(spec) =>
559
+ expect(spec.keys)->toEqual(["tenantId", "region", "service"])->ignore
560
+ expect(spec.seps)->toEqual([":", "/"])
561
+ | Simple(_) => fail("Expected Composite")
562
+ }
563
+ },
564
+ )
565
+
566
+ testSync(
567
+ "returns Simple for schema with only @partitionTag",
568
+ () => {
569
+ let result = Reventless.DcbTag.derivePartitionTag([
570
+ ("Order", "test.res", DcbFixtures.simplePartitionEventSchema->u),
571
+ ])
572
+ switch result {
573
+ | Simple(pt) => expect(pt.key)->toBe("orderId")
574
+ | Composite(_) => fail("Expected Simple")
575
+ }
576
+ },
577
+ )
578
+
579
+ testSync(
580
+ "returns Simple for schema with single tagged field",
581
+ () => {
582
+ let result = Reventless.DcbTag.derivePartitionTag([
583
+ ("Item", "test.res", DcbFixtures.singleTagCommandSchema->u),
584
+ ])
585
+ switch result {
586
+ | Simple(pt) => expect(pt.key)->toBe("itemId")
587
+ | Composite(_) => fail("Expected Simple")
588
+ }
589
+ },
590
+ )
591
+
592
+ testSync(
593
+ "throws on mixed composite and simple partition strategy",
594
+ () => {
595
+ let threw = ref(false)
596
+ try {
597
+ let _ = Reventless.DcbTag.derivePartitionTag([
598
+ ("Mixed", "test.res", DcbFixtures.mixedStrategyEventSchema->u),
599
+ ])
600
+ } catch {
601
+ | JsExn(err) =>
602
+ threw := true
603
+ expect(
604
+ JsExn.message(err)->Option.getOr("")->String.includes(
605
+ "mixes @compositePartitionTag and @partitionTag",
606
+ ),
607
+ )->toBe(true)->ignore
608
+ }
609
+ expect(threw.contents)->toBe(true)
610
+ },
611
+ )
612
+
613
+ testSync(
614
+ "throws on single composite field (< 2)",
615
+ () => {
616
+ let threw = ref(false)
617
+ try {
618
+ let _ = Reventless.DcbTag.derivePartitionTag([
619
+ ("Single", "test.res", DcbFixtures.singleCompositeEventSchema->u),
620
+ ])
621
+ } catch {
622
+ | JsExn(err) =>
623
+ threw := true
624
+ expect(
625
+ JsExn.message(err)->Option.getOr("")->String.includes("at least 2 annotated fields"),
626
+ )->toBe(true)->ignore
627
+ }
628
+ expect(threw.contents)->toBe(true)
629
+ },
630
+ )
631
+ })
632
+
633
+ describe("isCompositePartitionMember", () => {
634
+ testSync(
635
+ "returns true for compositePartitionMember schema",
636
+ () =>
637
+ expect(
638
+ Reventless.DcbTag.isCompositePartitionMember(
639
+ Reventless.DcbTag.compositePartitionMember(~position=0)->Reventless.DcbTag.toUnknownSchema,
640
+ ),
641
+ )->toBe(true),
642
+ )
643
+
644
+ testSync(
645
+ "returns false for plain DcbTag.string",
646
+ () =>
647
+ expect(
648
+ Reventless.DcbTag.isCompositePartitionMember(
649
+ Reventless.DcbTag.string->Reventless.DcbTag.toUnknownSchema,
650
+ ),
651
+ )->toBe(false),
652
+ )
653
+
654
+ testSync(
655
+ "returns false for plain S.string",
656
+ () =>
657
+ expect(
658
+ Reventless.DcbTag.isCompositePartitionMember(
659
+ S.string->Reventless.DcbTag.toUnknownSchema,
660
+ ),
661
+ )->toBe(false),
662
+ )
663
+ })
664
+
665
+ describe("buildQueryFromCommand", () => {
666
+ let eventTypes = ["EventA", "EventB"]
667
+
668
+ testSync(
669
+ "scalar-only command produces single AND clause",
670
+ () =>
671
+ expect(
672
+ Reventless.DcbTag.buildQueryFromCommand(
673
+ ~eventTypes,
674
+ ~schema=DcbFixtures.singleTagCommandSchema,
675
+ ~value=DcbFixtures.CreateItem({itemId: "item-1", name: "Test"}),
676
+ ),
677
+ )->toEqual([
678
+ {
679
+ Reventless.DcbTag.eventTypes,
680
+ tags: [{key: "itemId", value: "item-1"}],
681
+ },
682
+ ]),
683
+ )
684
+
685
+ testSync(
686
+ "tagged array command produces per-element OR clauses",
687
+ () =>
688
+ expect(
689
+ Reventless.DcbTag.buildQueryFromCommand(
690
+ ~eventTypes,
691
+ ~schema=DcbFixtures.crossEntityCommandSchema,
692
+ ~value=DcbFixtures.PlaceOrder({
693
+ orderId: "ord-1",
694
+ customerId: "cust-1",
695
+ productId: ["prod-1", "prod-2"],
696
+ }),
697
+ ),
698
+ )->toEqual([
699
+ {Reventless.DcbTag.eventTypes, tags: [{key: "orderId", value: "ord-1"}]},
700
+ {eventTypes, tags: [{key: "productId", value: "prod-1"}]},
701
+ {eventTypes, tags: [{key: "productId", value: "prod-2"}]},
702
+ ]),
703
+ )
704
+
705
+ testSync(
706
+ "tagged array with single element produces two OR clauses",
707
+ () =>
708
+ expect(
709
+ Reventless.DcbTag.buildQueryFromCommand(
710
+ ~eventTypes,
711
+ ~schema=DcbFixtures.crossEntityCommandSchema,
712
+ ~value=DcbFixtures.PlaceOrder({
713
+ orderId: "ord-1",
714
+ customerId: "cust-1",
715
+ productId: ["prod-1"],
716
+ }),
717
+ ),
718
+ )->toEqual([
719
+ {Reventless.DcbTag.eventTypes, tags: [{key: "orderId", value: "ord-1"}]},
720
+ {eventTypes, tags: [{key: "productId", value: "prod-1"}]},
721
+ ]),
722
+ )
723
+
724
+ testSync(
725
+ "tagged array with empty array produces single clause for scalar tag",
726
+ () =>
727
+ expect(
728
+ Reventless.DcbTag.buildQueryFromCommand(
729
+ ~eventTypes,
730
+ ~schema=DcbFixtures.crossEntityCommandSchema,
731
+ ~value=DcbFixtures.PlaceOrder({orderId: "ord-1", customerId: "cust-1", productId: []}),
732
+ ),
733
+ )->toEqual([{Reventless.DcbTag.eventTypes, tags: [{key: "orderId", value: "ord-1"}]}]),
734
+ )
735
+
736
+ // --- Vacuous-clause narrowing (Issue 14) ---
737
+
738
+ let orderTagKeys = Reventless.DcbTag.extractTagKeysByEventType(DcbFixtures.orderEventLogSchema)
739
+
740
+ testSync(
741
+ "extractTagKeysByEventType maps each event type to its produced tag keys",
742
+ () =>
743
+ expect(
744
+ orderTagKeys
745
+ ->Dict.toArray
746
+ ->Array.toSorted(((a, _), (b, _)) => String.compare(a, b)),
747
+ )->toEqual([
748
+ ("CatalogProductSynced", ["productId"]),
749
+ ("OrderPlaced", ["orderId", "customerId", "productId"]),
750
+ ]),
751
+ )
752
+
753
+ testSync(
754
+ "narrowing drops the vacuous (CatalogProductSynced, orderId) combination but keeps OrderPlaced under productId",
755
+ () =>
756
+ expect(
757
+ Reventless.DcbTag.buildQueryFromCommand(
758
+ ~eventTypes=["OrderPlaced", "CatalogProductSynced"],
759
+ ~schema=DcbFixtures.crossEntityCommandSchema,
760
+ ~value=DcbFixtures.PlaceOrder({
761
+ orderId: "ord-1",
762
+ customerId: "cust-1",
763
+ productId: ["prod-1"],
764
+ }),
765
+ ~tagKeysByEventType=orderTagKeys,
766
+ ),
767
+ )->toEqual([
768
+ {Reventless.DcbTag.eventTypes: ["OrderPlaced"], tags: [{key: "orderId", value: "ord-1"}]},
769
+ {
770
+ eventTypes: ["OrderPlaced", "CatalogProductSynced"],
771
+ tags: [{key: "productId", value: "prod-1"}],
772
+ },
773
+ ]),
774
+ )
775
+
776
+ testSync(
777
+ "narrowing the single AND clause keeps only types carrying every clause tag",
778
+ () =>
779
+ expect(
780
+ Reventless.DcbTag.buildQueryFromCommand(
781
+ ~eventTypes=["OrderPlaced", "CatalogProductSynced"],
782
+ ~schema=DcbFixtures.singleTagCommandSchema,
783
+ ~value=DcbFixtures.CreateItem({itemId: "item-1", name: "Test"}),
784
+ ~tagKeysByEventType=orderTagKeys,
785
+ ),
786
+ )->toEqual([
787
+ // Neither produced type carries `itemId`, so both are vacuous → empty.
788
+ {Reventless.DcbTag.eventTypes: [], tags: [{key: "itemId", value: "item-1"}]},
789
+ ]),
790
+ )
791
+
792
+ testSync(
793
+ "an empty map leaves all event types in place (no narrowing)",
794
+ () =>
795
+ expect(
796
+ Reventless.DcbTag.buildQueryFromCommand(
797
+ ~eventTypes=["OrderPlaced", "CatalogProductSynced"],
798
+ ~schema=DcbFixtures.crossEntityCommandSchema,
799
+ ~value=DcbFixtures.PlaceOrder({
800
+ orderId: "ord-1",
801
+ customerId: "cust-1",
802
+ productId: ["prod-1"],
803
+ }),
804
+ ~tagKeysByEventType=Dict.make(),
805
+ ),
806
+ )->toEqual([
807
+ {
808
+ Reventless.DcbTag.eventTypes: ["OrderPlaced", "CatalogProductSynced"],
809
+ tags: [{key: "orderId", value: "ord-1"}],
810
+ },
811
+ {
812
+ eventTypes: ["OrderPlaced", "CatalogProductSynced"],
813
+ tags: [{key: "productId", value: "prod-1"}],
814
+ },
815
+ ]),
816
+ )
817
+
818
+ // --- Cross-partition fan-out (Issue 13 / Phase 7) ---
819
+
820
+ testSync(
821
+ "extractCrossPartitionTagKeys returns only the @crossPartition keys",
822
+ () =>
823
+ expect(
824
+ Reventless.DcbTag.extractCrossPartitionTagKeys(DcbFixtures.subscriptionEventSchema),
825
+ )->toEqual(["studentId"]),
826
+ )
827
+
828
+ testSync(
829
+ "extractCrossPartitionTagKeys is empty when no field is @crossPartition",
830
+ () =>
831
+ expect(
832
+ Reventless.DcbTag.extractCrossPartitionTagKeys(DcbFixtures.simplePartitionEventSchema),
833
+ )->toEqual([]),
834
+ )
835
+
836
+ testSync(
837
+ "a cross-partition tag fans a 2-tag command into two single-tag clauses",
838
+ () =>
839
+ expect(
840
+ Reventless.DcbTag.buildQueryFromCommand(
841
+ ~eventTypes=["StudentSubscribed"],
842
+ ~schema=DcbFixtures.subscribeCommandSchema,
843
+ ~value=DcbFixtures.SubscribeStudent({courseId: "C1", studentId: "S1"}),
844
+ ~crossPartitionTagKeys=["studentId"],
845
+ ),
846
+ )->toEqual([
847
+ {Reventless.DcbTag.eventTypes: ["StudentSubscribed"], tags: [{key: "courseId", value: "C1"}]},
848
+ {eventTypes: ["StudentSubscribed"], tags: [{key: "studentId", value: "S1"}]},
849
+ ]),
850
+ )
851
+
852
+ testSync(
853
+ "without crossPartitionTagKeys the same 2-tag command stays one composite clause",
854
+ () =>
855
+ expect(
856
+ Reventless.DcbTag.buildQueryFromCommand(
857
+ ~eventTypes=["StudentSubscribed"],
858
+ ~schema=DcbFixtures.subscribeCommandSchema,
859
+ ~value=DcbFixtures.SubscribeStudent({courseId: "C1", studentId: "S1"}),
860
+ ),
861
+ )->toEqual([
862
+ {
863
+ Reventless.DcbTag.eventTypes: ["StudentSubscribed"],
864
+ tags: [{key: "courseId", value: "C1"}, {key: "studentId", value: "S1"}],
865
+ },
866
+ ]),
867
+ )
868
+
869
+ testSync(
870
+ "hasTaggedArrayFields detects tagged arrays",
871
+ () => {
872
+ expect(Reventless.DcbTag.hasTaggedArrayFields(DcbFixtures.crossEntityCommandSchema))->toBe(
873
+ true,
874
+ )
875
+ },
876
+ )
877
+
878
+ testSync(
879
+ "hasTaggedArrayFields returns false for scalar-only schemas",
880
+ () => {
881
+ expect(Reventless.DcbTag.hasTaggedArrayFields(DcbFixtures.singleTagCommandSchema))->toBe(
882
+ false,
883
+ )
884
+ },
885
+ )
886
+ })
887
+
888
+ describe("stringForKey (tag-key override)", () => {
889
+ testSync(
890
+ "isTagged is true for stringForKey schema",
891
+ () =>
892
+ expect(
893
+ Reventless.DcbTag.isTagged(
894
+ Reventless.DcbTag.stringForKey(~key="productId")->Reventless.DcbTag.toUnknownSchema,
895
+ ),
896
+ )->toBe(true),
897
+ )
898
+
899
+ testSync(
900
+ "extractTags returns the override key for a scalar field",
901
+ () =>
902
+ expect(
903
+ Reventless.DcbTag.extractTags(
904
+ DcbFixtures.customKeyEventSchema,
905
+ DcbFixtures.ProductLabelled({sku: "SKU-42"}),
906
+ ),
907
+ )->toEqual([{Reventless.DcbTag.key: "productSku", value: "SKU-42"}]),
908
+ )
909
+
910
+ testSync(
911
+ "extractTagsExpanded uses the override key on every array element",
912
+ () =>
913
+ expect(
914
+ Reventless.DcbTag.extractTagsExpanded(
915
+ DcbFixtures.multiProductCommandSchema,
916
+ DcbFixtures.PlaceOrderWithMany({
917
+ orderId: "ord-1",
918
+ productIds: ["prod-1", "prod-2"],
919
+ }),
920
+ ),
921
+ )->toEqual([
922
+ {Reventless.DcbTag.key: "orderId", value: "ord-1"},
923
+ {key: "productId", value: "prod-1"},
924
+ {key: "productId", value: "prod-2"},
925
+ ]),
926
+ )
927
+
928
+ testSync(
929
+ "buildQueryFromCommand emits the override key in OR clauses",
930
+ () =>
931
+ expect(
932
+ Reventless.DcbTag.buildQueryFromCommand(
933
+ ~eventTypes=["OrderPlaced", "CatalogProductSynced"],
934
+ ~schema=DcbFixtures.multiProductCommandSchema,
935
+ ~value=DcbFixtures.PlaceOrderWithMany({
936
+ orderId: "ord-1",
937
+ productIds: ["prod-1", "prod-2"],
938
+ }),
939
+ ),
940
+ )->toEqual([
941
+ {
942
+ Reventless.DcbTag.eventTypes: ["OrderPlaced", "CatalogProductSynced"],
943
+ tags: [{key: "orderId", value: "ord-1"}],
944
+ },
945
+ {
946
+ eventTypes: ["OrderPlaced", "CatalogProductSynced"],
947
+ tags: [{key: "productId", value: "prod-1"}],
948
+ },
949
+ {
950
+ eventTypes: ["OrderPlaced", "CatalogProductSynced"],
951
+ tags: [{key: "productId", value: "prod-2"}],
952
+ },
953
+ ]),
954
+ )
955
+
956
+ testSync(
957
+ "singular producer + plural consumer share the same tag key (round-trip)",
958
+ () => {
959
+ // Producer: singular field name `productId: string`.
960
+ let producerTags: array<Reventless.DcbTag.tag> = Reventless.DcbTag.extractTags(
961
+ DcbFixtures.singleProductEventSchema,
962
+ DcbFixtures.CatalogProductSynced({productId: "prod-1"}),
963
+ )
964
+ // Consumer: plural field name `productIds: array<string>` with key override.
965
+ let consumerTags: array<Reventless.DcbTag.tag> = Reventless.DcbTag.extractTagsExpanded(
966
+ DcbFixtures.multiProductCommandSchema,
967
+ DcbFixtures.PlaceOrderWithMany({orderId: "ord-1", productIds: ["prod-1"]}),
968
+ )
969
+ let producerHead: Reventless.DcbTag.tag = producerTags->Array.getUnsafe(0)
970
+ let consumerProductTag: Reventless.DcbTag.tag =
971
+ consumerTags
972
+ ->Array.find(t => t.Reventless.DcbTag.key != "orderId")
973
+ ->Option.getOrThrow
974
+ expect(consumerProductTag.key)->toBe(producerHead.key)
975
+ },
976
+ )
977
+ })
978
+ })