@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,412 @@
1
+ module type T = {
2
+ module Spec: Reventless.StateChangeSlice.Spec
3
+ module Behavior: Reventless.StateChangeSlice.Behavior with module Spec := Spec
4
+ let handleCommands: (
5
+ ~tagKeysByEventType: Dict.t<array<string>>=?,
6
+ ~crossPartitionTagKeys: array<string>=?,
7
+ DcbEventLog.operations,
8
+ Stream.t<
9
+ CommandTopic.topicItem<Message.command'<Reventless.Id.String.t, Spec.command>>,
10
+ string,
11
+ unit,
12
+ >,
13
+ ) => Effect.t<array<result<string, string>>, string, unit>
14
+ /** Flushes this slice's in-process decision-model projection cache. The cache
15
+ is keyed on durable storage positions, so it must be cleared whenever the
16
+ backing store is reset out-of-band (test isolation; operational flush). */
17
+ let resetCache: unit => unit
18
+ }
19
+
20
+ module Make = (
21
+ Spec: Reventless.StateChangeSlice.Spec,
22
+ Behavior: Reventless.StateChangeSlice.Behavior with module Spec := Spec,
23
+ ): (T with module Spec = Spec and module Behavior := Behavior) => {
24
+ module Spec = Spec
25
+ module Behavior = Behavior
26
+
27
+ let comp = `StateChangeSlice(${Spec.name})`
28
+
29
+ let decoder = Reventless.DcbDecode.makeDecoder(Spec.consumedEventSchema)
30
+ let queryEventTypes = decoder.eventTypes
31
+
32
+ let encodeEvent = (
33
+ ~parentMeta: Message.meta,
34
+ ~tagKeysByEventType: Dict.t<array<string>>,
35
+ event: Spec.event,
36
+ ): ReventlessInfra.DcbEventLog.rawEvent => {
37
+ let json = event->JSON.stringifyAny->Option.getOrThrow->JSON.parseOrThrow
38
+ let (eventType, data) = json->Message.splitMessage
39
+ // Use `extractTagsExpanded` (not `extractTags`) so per-element tags on
40
+ // `array<string>` fields are emitted — e.g. OrderPlaced's
41
+ // `productIds: array<string>` produces one tag per productId rather than
42
+ // dropping the field entirely. The stored event then carries each productId
43
+ // as a GSI tag attribute, so composite/GSI readers and the per-productId
44
+ // partition (for events partitioned by productId) resolve correctly.
45
+ //
46
+ // Note: a productId here is a *secondary* tag on OrderPlaced (the partition
47
+ // tag is orderId). The DynamoDB adapter fences a tag only when it is the
48
+ // event's partition tag, so emitting productId tags does NOT bump
49
+ // `fence#productId:<x>` — that fence is owned by productId-partitioned events
50
+ // (e.g. CatalogProductSynced). This keeps read-scope and fence-scope aligned;
51
+ // see `docs/analysis/dcb-consistency-check-issues.md`.
52
+ // Keep only the keys this event type is *indexed* by (`tagKeysByEventType`,
53
+ // which Dcb_Builder threads from the inferred scope — or the full annotated tag
54
+ // set on an ambiguous boundary, where this filter is a no-op). A foreign
55
+ // reference key that is payload here (e.g. `categoryId` on `ProductAdded`) is
56
+ // dropped, so the event is never written to that key's GSI and a cross-partition
57
+ // read of it can't sweep up this event. When no entry exists for the type, keep
58
+ // all tags (back-compat for callers that don't thread the map).
59
+ let baseTags = Reventless.DcbTag.extractTagsExpanded(Spec.eventSchema, event)
60
+ let indexedTags = switch tagKeysByEventType->Dict.get(eventType) {
61
+ | Some(keys) => baseTags->Array.filter(t => keys->Array.includes(t.key))
62
+ | None => baseTags
63
+ }
64
+ let tags =
65
+ indexedTags->Array.concat([{Reventless.DcbTag.key: "originatorSlice", value: Spec.name}])
66
+ // Inherit service from the triggering command — the DcbEventLog publish path
67
+ // overrides service to `<name>DcbEventLog` for routing so EventCollector
68
+ // subscriptions still match.
69
+ let meta = Message.deriveMeta(~parent=parentMeta)
70
+ {eventType, data: JSON.Object(data), tags, meta}
71
+ }
72
+
73
+ // Computed once at functor init — used to extract entityId for publishJsonsAndWait outcomes.
74
+ let derivedPartitionTag = Reventless.DcbTag.derivePartitionTag([
75
+ (Spec.name, Behavior.moduleUrl, Spec.eventSchema->S.castToUnknown),
76
+ ])
77
+
78
+ // Extracts the entity id of a read event from its own tags, for logging
79
+ // which events the decision model was built from. Prefers this slice's
80
+ // partition key (derived from the produced event), but consumed events from
81
+ // other sources are tagged by their own key (e.g. CatalogProductSynced →
82
+ // productId, not this slice's orderId), so fall back to the read event's own
83
+ // tag value(s) instead of logging no id.
84
+ let readEventId = (tags: array<Reventless.DcbTag.tag>): option<string> => {
85
+ let ownTagValues = () => {
86
+ // Skip the `originatorSlice` metadata tag that `encodeEvent` appends to
87
+ // every stored event — it's the producing slice's name, not an entity id.
88
+ let vals =
89
+ tags
90
+ ->Array.filter((t: Reventless.DcbTag.tag) => t.key != "originatorSlice")
91
+ ->Array.reduce([], (acc, t: Reventless.DcbTag.tag) =>
92
+ acc->Array.includes(t.value) ? acc : acc->Array.concat([t.value])
93
+ )
94
+ vals->Array.length == 0 ? None : Some(vals->Array.join(","))
95
+ }
96
+ switch derivedPartitionTag {
97
+ | Simple(pt) =>
98
+ switch tags->Array.findMap((t: Reventless.DcbTag.tag) =>
99
+ t.key == pt.key ? Some(t.value) : None
100
+ ) {
101
+ | Some(v) => Some(v)
102
+ | None => ownTagValues()
103
+ }
104
+ | Composite(spec) => Some(Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec))
105
+ }
106
+ }
107
+
108
+ let maxRetries = 3
109
+
110
+ // In-process decision-model projection cache (per warm Lambda instance, per
111
+ // slice). Keyed on the serialised DCB query, it holds the
112
+ // `(decisionState, readHead)` the previous command for that query derived.
113
+ //
114
+ // On a hit, `handleSingleCommand` seeds the fold from the cached state and
115
+ // reads only events *after* `readHead` (the delta) instead of folding full
116
+ // history — O(delta) instead of O(history) per warm same-entity command.
117
+ //
118
+ // What is cached is deliberately the state the slice *decided on* and the head
119
+ // it *read up to* — NOT the events this command produced, and NOT the
120
+ // position `append` returned. The produced events are read back by the next
121
+ // command's delta read (their position is always > readHead on both the
122
+ // DynamoDB and in-memory backends), so the cache never needs to fold produced
123
+ // events (sidestepping the consumedEvent/event type split) nor trust the
124
+ // append position (which is the batch *base* on DynamoDB but the batch *max*
125
+ // in-memory). Correctness still rests entirely on the conditional append's
126
+ // fence: a stale cached state only changes the *decision*, and a stale
127
+ // decision conflicts at append time → retry → re-read refreshes the state.
128
+ //
129
+ // Capacity is fixed at 100 entries; a per-slice knob is a future refinement
130
+ // (see the plan's Step 4).
131
+ let projectionCacheCapacity = 100
132
+ let projectionCache: Lru.t<
133
+ string,
134
+ (Behavior.state, option<Reventless.DcbTag.sequencePosition>),
135
+ > = Lru.make(~capacity=projectionCacheCapacity)
136
+
137
+ let resetCache = () => projectionCache->Lru.clear
138
+
139
+ // Processes one command against the DCB event log with optimistic concurrency:
140
+ // 1. Reads relevant events (filtered by command tags) to build the decision
141
+ // model — seeded from the projection cache when warm, so only events after
142
+ // the cached head are read (delta), else the full history (cold)
143
+ // 2. Decodes raw events using consumedEventSchema
144
+ // 3. Calls Behavior.decide to produce new events
145
+ // 4. Encodes produced events to raw and appends with a condition
146
+ // 5. On conflict, retries from step 1 (up to maxRetries)
147
+ let handleSingleCommand = (
148
+ ~tagKeysByEventType,
149
+ ~crossPartitionTagKeys,
150
+ dcbEventLog: DcbEventLog.operations,
151
+ command': Message.command'<Reventless.Id.String.t, Spec.command>,
152
+ ) => {
153
+ let cmdJson =
154
+ command'->Message.commandJsonOfCommand'(
155
+ ~idToString=Reventless.Id.String.toString,
156
+ ~commandSchema=Spec.commandSchema,
157
+ )
158
+ // Render `Name({fields})` without the standalone command id: for DCB slice
159
+ // commands the id is the entity/partition id, which is already shown among
160
+ // the fields, so a leading `(id)` would just duplicate it.
161
+ EffectLogger.logInfo(
162
+ ~comp,
163
+ ~detail=cmdJson.commandJson,
164
+ `handling command: ${cmdJson->LogFormat.cmdDetailNoId}`,
165
+ )->Effect.runSync
166
+
167
+ let query = Reventless.DcbTag.buildQueryFromCommand(
168
+ ~eventTypes=queryEventTypes,
169
+ ~schema=Spec.commandSchema,
170
+ ~value=command'.command,
171
+ ~tagKeysByEventType,
172
+ ~crossPartitionTagKeys,
173
+ )
174
+
175
+ // Log the DCB query parameters — the OR clauses (event types + tags) the
176
+ // read below filters on. Constant across retries, so logged once per command.
177
+ let queryDetail =
178
+ query
179
+ ->Array.map((qi: Reventless.DcbTag.queryItem) => {
180
+ let types = switch qi.eventTypes {
181
+ | Some(ts) => ts->Array.map(LogFormat.bold)->Array.join("|")
182
+ | None => "*"
183
+ }
184
+ let tags = switch qi.tags {
185
+ | Some(ts) =>
186
+ ts->Array.map((t: Reventless.DcbTag.tag) => `${t.key}=${t.value}`)->Array.join(",")
187
+ | None => ""
188
+ }
189
+ tags == "" ? types : `${types}{${tags}}`
190
+ })
191
+ ->Array.join(" OR ")
192
+ EffectLogger.logInfo(~comp, `query: ${queryDetail}`)->Effect.runSync
193
+
194
+ // Extract the entity ID from the command for use in Accepted outcomes.
195
+ let entityId = switch derivedPartitionTag {
196
+ | Simple(pt) => Reventless.DcbTag.getPartitionTagValue(query, pt)
197
+ | Composite(spec) =>
198
+ let tags = Reventless.DcbTag.extractTags(Spec.commandSchema, command'.command)
199
+ Some(Reventless.DcbTag.getCompositePartitionKeyValue(tags, spec))
200
+ }
201
+
202
+ let cacheKey = query->JSON.stringifyAny->Option.getOr("")
203
+
204
+ // Working seed across retries: the `(state, head)` the read folds from.
205
+ // Starts from the projection cache (warm) or empty (cold); the conflict
206
+ // branch re-seeds it with the just-read `(state, head)` so each retry reads
207
+ // only the delta the conflicting writer added rather than full history.
208
+ let seed = ref(Lru.get(projectionCache, cacheKey))
209
+
210
+ let rec attempt = (~retries) => {
211
+ let (baseState, afterPos) = switch seed.contents {
212
+ | Some((state, head)) => (state, head)
213
+ | None => (Behavior.initialState, None)
214
+ }
215
+ let cacheHit = seed.contents->Option.isSome
216
+
217
+ // Consistency: governed by the slice's build-time `readConsistency` mode
218
+ // (default `EscalateOnRetry`). Correctness is identical in every mode — the
219
+ // conditional append's fence is always evaluated strongly, so a stale read
220
+ // can only cost a rejected append (then a retry), never a wrong write. The
221
+ // mode is a per-slice RCU/latency lever against replica-lag conflicts.
222
+ // EscalateOnRetry — eventual on the first attempt (cheaper RCU), then
223
+ // strong on every retry so a replica-lag conflict self-heals.
224
+ // AlwaysStrong — strong every attempt (known-hot slices).
225
+ // AlwaysEventual — eventual every attempt (cost-sensitive, low-contention).
226
+ let strongConsistency = switch Spec.readConsistency {
227
+ | Reventless.ReadConsistency.EscalateOnRetry => retries < maxRetries
228
+ | AlwaysStrong => true
229
+ | AlwaysEventual => false
230
+ }
231
+
232
+ dcbEventLog.readStream(~query, ~after=?afterPos, ~strongConsistency)
233
+ ->Stream.map(raw => {
234
+ let decoded = decoder.decode(
235
+ ~eventType=raw.eventType,
236
+ ~data=raw.data->JSON.Decode.object->Option.getOr(Dict.make()),
237
+ )
238
+ decoded->Option.map(event => (event, raw.position, raw.eventType, readEventId(raw.tags)))
239
+ })
240
+ ->Stream.flatMap(opt =>
241
+ switch opt {
242
+ | Some(v) => Stream.fromIterable([v])
243
+ | None => Stream.empty
244
+ }
245
+ )
246
+ // The head accumulator starts at `afterPos` (the seeded head), not `None`,
247
+ // so an empty delta read keeps the cached head — the append must condition
248
+ // on the head that actually exists, not assert "no events exist yet".
249
+ ->Stream.runFold((baseState, afterPos, []), (
250
+ (dm, _pos, reads),
251
+ (event, position, eventType, eventId),
252
+ ) => (
253
+ Behavior.evolve(dm, event),
254
+ Some(position),
255
+ reads->Array.concat([
256
+ switch eventId {
257
+ | Some(id) => `${eventType->LogFormat.bold}(${id})`
258
+ | None => eventType->LogFormat.bold
259
+ },
260
+ ]),
261
+ ))
262
+ ->Effect.tap(((_, _, reads)) =>
263
+ EffectLogger.logInfo(
264
+ ~comp,
265
+ `read${cacheHit ? " (cached, delta)" : ""}: ${reads->Array.length->Int.toString} event(s)${reads->Array.length == 0
266
+ ? ""
267
+ : ` [${reads->Array.join(", ")}]`}`,
268
+ )
269
+ )
270
+ ->Effect.flatMap(((state, headPosition, _)) =>
271
+ EffectLogger.logDebug(
272
+ ~comp,
273
+ `deciding on state: ${state->JSON.stringifyAny->Option.getOr("<unserializable>")}`,
274
+ )->Effect.flatMap(_ =>
275
+ switch Behavior.decide(state, command'.command) {
276
+ | Ok(newEvents) if newEvents->Array.length == 0 =>
277
+ // No append, but the read snapshot is valid — cache it for the next command.
278
+ Lru.put(projectionCache, cacheKey, (state, headPosition))
279
+ CommandTopic_Helpers.reportAccepted(
280
+ cmdJson.meta.msgId,
281
+ switch entityId {
282
+ | Some(eid) => {entityId: eid, eventCount: 0}
283
+ | None => {eventCount: 0}
284
+ },
285
+ )
286
+ EffectLogger.logInfo(~comp, "no events produced")->Effect.map(_ => Ok("ok"))
287
+ | Ok(newEvents) =>
288
+ let rawEvents =
289
+ newEvents->Array.map(e =>
290
+ encodeEvent(~parentMeta=command'.meta, ~tagKeysByEventType, e)
291
+ )
292
+ let eventCount = rawEvents->Array.length->Int.toString
293
+ let eventDetails =
294
+ rawEvents
295
+ ->Array.map(
296
+ e => {
297
+ let fields = switch e.data {
298
+ | Object(dict) =>
299
+ let f =
300
+ dict
301
+ ->Dict.toArray
302
+ ->Array.map(((k, v)) => `${k}:${v->JSON.stringify}`)
303
+ ->Array.join(",")
304
+ f == "" ? "" : `({${f}})`
305
+ | _ => ""
306
+ }
307
+ `${LogFormat.bold(e.eventType)}${fields}`
308
+ },
309
+ )
310
+ ->Array.join(", ")
311
+ let eventJsons = rawEvents->Array.map(e => e.data)->JSON.Encode.array
312
+ let condition: Reventless.DcbTag.appendCondition = {
313
+ query,
314
+ after: ?headPosition,
315
+ }
316
+ EffectLogger.logInfo(
317
+ ~comp,
318
+ ~detail=eventJsons,
319
+ `produced ${eventCount} event(s): [${eventDetails}]`,
320
+ )
321
+ ->Effect.flatMap(_ => Effect.promise(() => dcbEventLog.append(rawEvents, ~condition)))
322
+ ->Effect.flatMap(
323
+ appendResult =>
324
+ switch appendResult {
325
+ | Ok(_position) =>
326
+ // Cache the decided-on state at the read head (NOT including the
327
+ // events we just appended, and NOT the returned position): the
328
+ // next command's delta read picks our events up from `headPosition`.
329
+ Lru.put(projectionCache, cacheKey, (state, headPosition))
330
+ CommandTopic_Helpers.reportAccepted(
331
+ cmdJson.meta.msgId,
332
+ switch entityId {
333
+ | Some(eid) => {entityId: eid, eventCount: rawEvents->Array.length}
334
+ | None => {eventCount: rawEvents->Array.length}
335
+ },
336
+ )
337
+ EffectLogger.logInfo(~comp, `append: ${eventCount} event(s)`)->Effect.map(
338
+ _ => Ok("ok"),
339
+ )
340
+ | Error(err) =>
341
+ if retries > 0 {
342
+ // Re-seed from the just-read snapshot so the retry reads only
343
+ // the delta the conflicting writer added, not full history.
344
+ seed := Some((state, headPosition))
345
+ // Per-slice CloudWatch counter: rising AppendRetry signals a
346
+ // slice feeling contention (the metric to watch the eventual
347
+ // default with — see dcb-high-contention-handling.md).
348
+ Metrics.emitCount(~metric="AppendRetry", ~slice=Spec.name)
349
+ EffectLogger.logWarn(
350
+ ~comp,
351
+ `append failed (retrying ${(maxRetries - retries + 1)
352
+ ->Int.toString}/${maxRetries->Int.toString}): ${err}`,
353
+ )->Effect.flatMap(_ => attempt(~retries=retries - 1))
354
+ } else {
355
+ // Retries exhausted — drop any cached snapshot so the next
356
+ // command for this entity takes the cold full-read path.
357
+ Lru.invalidate(projectionCache, cacheKey)
358
+ let errorCode = err->String.startsWith("Conflict") ? "Conflict" : "AppendFailed"
359
+ // A surfaced Conflict means the 3-retry loop could not absorb
360
+ // the contention — the operator signal for "this slice is hot"
361
+ // (consider sharding / async — Issue 10, §4 of the analysis).
362
+ if errorCode == "Conflict" {
363
+ Metrics.emitCount(~metric="AppendConflict", ~slice=Spec.name)
364
+ }
365
+ CommandTopic_Helpers.reportRejected(
366
+ cmdJson.meta.msgId,
367
+ {errorCode, errorDetail: err},
368
+ )
369
+ EffectLogger.logError(
370
+ ~comp,
371
+ `append failed, retries exhausted: ${err}`,
372
+ )->Effect.map(_ => Error(err))
373
+ }
374
+ },
375
+ )
376
+ | Error(error) =>
377
+ // Business-rule rejection — no append, but the read snapshot is valid; cache it.
378
+ Lru.put(projectionCache, cacheKey, (state, headPosition))
379
+ let errorJson = error->S.reverseConvertToJsonOrThrow(Spec.errorSchema)
380
+ let errorCode = errorJson->Message.variantNameOfJson
381
+ let (_, payloadDict) = errorJson->Message.splitMessage
382
+ let errorDetail =
383
+ payloadDict->Dict.toArray->Array.length == 0
384
+ ? ""
385
+ : payloadDict->JSON.Encode.object->JSON.stringify
386
+ CommandTopic_Helpers.reportRejected(cmdJson.meta.msgId, {errorCode, errorDetail})
387
+ EffectLogger.logError(
388
+ ~comp,
389
+ `decide rejected: ${errorCode} ${errorDetail}`,
390
+ )->Effect.map(_ => Ok("rejected"))
391
+ }
392
+ )
393
+ )
394
+ }
395
+
396
+ attempt(~retries=maxRetries)
397
+ }
398
+
399
+ // CommandTopic handler — processes each command sequentially through handleSingleCommand,
400
+ // returning Ok(reference) or Error(reference) per command.
401
+ let handleCommands = (~tagKeysByEventType=Dict.make(), ~crossPartitionTagKeys=[], dcbEventLog, stream) =>
402
+ stream
403
+ ->Stream.mapEffect(({ReventlessInfra.CommandTopic.reference: reference, command}) =>
404
+ handleSingleCommand(~tagKeysByEventType, ~crossPartitionTagKeys, dcbEventLog, command)->Effect.map(result =>
405
+ switch result {
406
+ | Ok(_) => Ok(reference)
407
+ | Error(_) => Error(reference)
408
+ }
409
+ )
410
+ )
411
+ ->Stream.runCollect
412
+ }