@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,1730 @@
1
+ let log = Logger.fromEnv()
2
+
3
+ // Wrapper to safely store Pulumi Output values as option fields.
4
+ // Pulumi Outputs are JS Proxies; wrapping them directly in Some() triggers
5
+ // the BS_PRIVATE_NESTED_SOME_NONE sentinel bug. Storing as {val: x} avoids
6
+ // this because the plain record has no BS_PRIVATE_NESTED_SOME_NONE property.
7
+ type hookedValue<'a> = {val: 'a}
8
+
9
+ // Local-only intermediate type used by Plugin_Builder during construction.
10
+ // All fields use Pulumi.Output.t-wrapped component output types because they
11
+ // originate from freshly-built local components (not deserialized stack exports).
12
+ // Cross-stack consumers use ReventlessInterop.Plugin.resolvedOutputs instead.
13
+ type builderOutputs = {
14
+ id: string,
15
+ version: string,
16
+ heartbeatInterval: int,
17
+ eventCollector: EventCollector.outputs,
18
+ extensionPoints: dict<ExtensionPoint.outputs>,
19
+ extensions: dict<Extension.outputs>,
20
+ aggregates: dict<Aggregate.outputs>,
21
+ stateChangeSlices: dict<StateChangeSlice.outputs>,
22
+ stateViewSlices: dict<StateViewSlice.outputs>,
23
+ automationSlices: dict<AutomationSlice.outputs>,
24
+ outboundTranslationSlices: dict<OutboundTranslationSlice.outputs>,
25
+ inboundTranslationSlices: dict<InboundTranslationSlice.outputs>,
26
+ readModels: dict<ReadModel.outputs>,
27
+ tasks: dict<Task.outputs>,
28
+ resolvers: array<ReventlessInfra.Adapter.resource>,
29
+ heartbeat: Heartbeat.outputs,
30
+ dcbEventLog: option<DcbEventLog.outputs>,
31
+ uiFragments: option<Reventless.Plugin.uiFragmentManifest>,
32
+ }
33
+
34
+ let getRemoteStorageResources = (pluginName, queryDbName) =>
35
+ switch Util_StackRefs.get(pluginName)->Option.map(stackRef => {
36
+ // Read the "readModels" top-level export directly (no longer nested under "plugin").
37
+ let readModelsOutput: Pulumi.Output.t<option<JSON.t>> =
38
+ stackRef->Pulumi.StackReference.getOutput("readModels")
39
+
40
+ readModelsOutput->Pulumi.Output.apply(readModelsOpt =>
41
+ switch readModelsOpt {
42
+ | Some(rawReadModels) =>
43
+ switch rawReadModels->JSON.Decode.object {
44
+ | Some(dict) =>
45
+ switch dict->Dict.get(queryDbName) {
46
+ | Some(rawReadModel) =>
47
+ try {
48
+ let readModel =
49
+ rawReadModel->S.parseOrThrow(ReventlessInterop.ReadModel.resolvedOutputsSchema)
50
+ readModel.queryDb.resources->Adapter.fromInteropResources
51
+ } catch {
52
+ | exn =>
53
+ let msg =
54
+ exn
55
+ ->JsExn.fromException
56
+ ->Option.flatMap(JsExn.message)
57
+ ->Option.getOr("parse error")
58
+ log.error(
59
+ ~comp="Plugin_Helpers",
60
+ `getRemoteStorageResources: failed to parse readModel ${queryDbName} from ${pluginName}: ${msg}`,
61
+ )
62
+ []
63
+ }
64
+ | None => []
65
+ }
66
+ | None => []
67
+ }
68
+ | None => []
69
+ }
70
+ )
71
+ }) {
72
+ | Some(resources) => resources
73
+ | None =>
74
+ let known = Util_StackRefs.stackRefs->Dict.keysToArray->Array.join(",")
75
+ log.error(
76
+ ~comp="Plugin_Helpers",
77
+ `getRemoteStorageResources: plugin ${pluginName} not found (check platform.stack config) known=[${known}]`,
78
+ )
79
+ []->Pulumi.Output.make
80
+ }
81
+
82
+ let getStorageResources = (allQueryDbs, pluginName, queryDbName) =>
83
+ switch pluginName {
84
+ | None => Util_QueryDb.getLocalStorageResources(allQueryDbs, queryDbName)->Pulumi.Output.make
85
+ | Some(pluginName) => getRemoteStorageResources(pluginName, queryDbName)
86
+ }
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // Plugin EventCollector context registry.
90
+ //
91
+ // Adapter runtime entry points (e.g. AdminEventCollectorEntryPoint.mjs) read
92
+ // HANDLER_CONFIG to reconstruct Plugin_Callback at cold start. The JSON payload
93
+ // is assembled at deploy time inside `forPluginEventCollector` (AWS), but the
94
+ // plugin-specific data (pluginDefinition, the auto-included Connect extension
95
+ // entry, the admin EP cmd-topic URL the extension publishes to) is only known
96
+ // inside `Plugin_Helpers.connect` / `Platform_Admin.connect` where the relevant
97
+ // Outputs have resolved.
98
+ //
99
+ // The registry bridges that gap: core's connect helpers register the per-plugin
100
+ // context here keyed by EventCollector component name; the AWS adapter reads it
101
+ // when building the Lambda's HANDLER_CONFIG. Adapters that don't need it (in-
102
+ // memory) simply ignore the ref.
103
+ //
104
+ // moduleUrl strings are hardcoded framework-internal paths (Admin Plugin EP +
105
+ // PluginConnectExtension only — both ship from reventless-core/-infra). When
106
+ // user-declared extensions land, propagate Blueprint.moduleUrl through the
107
+ // registry too — likely by extending `Plugin_Helpers.createExtensions` to
108
+ // capture each blueprint's moduleUrl into its returned tuple.
109
+ // ---------------------------------------------------------------------------
110
+
111
+ type extensionPointEntry = {
112
+ specModule: string,
113
+ mappingsModule: string,
114
+ eventTopicArn: Pulumi.Output.t<string>,
115
+ aggregateNames: array<string>,
116
+ }
117
+
118
+ type connectExtensionEntry = {
119
+ specModule: string,
120
+ mappingsModule: string,
121
+ extensionPointName: string,
122
+ }
123
+
124
+ // User-declared extension entry — one per merged extension group (multiple
125
+ // `*_Extension.res` files targeting the same EP combine into one component).
126
+ type extensionEntry = {
127
+ name: string,
128
+ specModule: string,
129
+ mappingsModule: string,
130
+ // npm specifier of the Delegate spec (aggregate / slice). The bundled Plugin
131
+ // EventCollector entry point dynamic-imports this at cold start to
132
+ // reconstruct `Mapping.Delegate` before handing the full mapping to
133
+ // ExtensionMapping.Make.
134
+ delegateModule: string,
135
+ extensionPointName: string,
136
+ // Subset of top-level publishToAggregates this extension publishes to —
137
+ // derived from Extension.outputs.aggregateNames.
138
+ aggregateNames: array<string>,
139
+ // RMs this extension's mapping may enqueue events into directly. Derived
140
+ // from readModelNamesForSourceName by reverse lookup on the extension's
141
+ // EP name (the source carried on incoming events).
142
+ readModelNames: array<string>,
143
+ }
144
+
145
+ type eventCollectorContext = {
146
+ // Pre-serialised JSON of the pluginDefinition (sury-encoded then JSON.stringify).
147
+ // Output because it's assembled from resolved component outputs at deploy time.
148
+ pluginDefinitionJson: Pulumi.Output.t<string>,
149
+ // Outgoing EPs whose events this Lambda's mapping handles. Admin Lambda: 1
150
+ // entry (its own Plugin EP). Plugin Lambda: 0 (plugins don't process their own
151
+ // EP outgoing events here).
152
+ extensionPoints: array<extensionPointEntry>,
153
+ // The auto-included PluginConnectExtension entry. Some for plugins; None for
154
+ // the admin Lambda (the admin IS the Plugin EP, doesn't consume it).
155
+ connectExtension: option<connectExtensionEntry>,
156
+ // User-declared extensions on this plugin. Empty for the admin Lambda.
157
+ extensions: array<extensionEntry>,
158
+ // SQS URL of the admin's Plugin EP command topic — where extensions publish
159
+ // ConnectPlugin commands via `publishToPluginExtensionPoint`. Empty string
160
+ // for admin (no extensions consume it).
161
+ pluginExtensionPointCmdTopicUrl: Pulumi.Output.t<string>,
162
+ // aggregateName → cmd-topic SQS URL. Includes every aggregate / DCB slice
163
+ // any user extension publishes to plus the admin's Plugin aggregate when
164
+ // ConnectExtension is wired.
165
+ publishToAggregates: dict<Pulumi.Output.t<string>>,
166
+ // rmName → RM EventCollector SQS URL. Populated only for RMs that user
167
+ // extensions feed directly via Extension_Operations.publishToReadModels.
168
+ readModelQueueUrls: dict<Pulumi.Output.t<string>>,
169
+ // Inversion of RM.sourceNames — sourceServiceName → [rmName]. Same dict
170
+ // surface used by Builder_Helpers; serialised verbatim into HANDLER_CONFIG.
171
+ readModelNamesForSourceName: dict<array<string>>,
172
+ }
173
+
174
+ let eventCollectorContextRef: ref<dict<eventCollectorContext>> = ref(Dict.make())
175
+
176
+ let registerEventCollectorContext = (~componentName: string, ~context: eventCollectorContext) =>
177
+ eventCollectorContextRef.contents->Dict.set(componentName, context)
178
+
179
+ // Framework-internal module URLs for the auto-Connect path — package specifiers
180
+ // the bundled EventCollector resolves (NOT file URLs). The two mapping specifiers
181
+ // are sourced from each module's `@@reventless.spec`-injected `moduleUrl`
182
+ // (derived from the file path, so they survive folder moves) rather than
183
+ // hardcoded. The spec specifier lives in reventless-infra (whose own `moduleUrl`
184
+ // is an `import.meta.url` file URL, the wrong form here), so it stays an explicit
185
+ // package specifier.
186
+ // User-declared extensions will eventually need to propagate their own URLs
187
+ // via createExtensions; this scope only covers the built-in Plugin EP + Connect.
188
+ let adminPluginExtensionPointSpecModule =
189
+ "@reventlessdev/reventless-infra/src/types/PluginExtensionPointSpec.res.mjs"
190
+ let adminPluginExtensionPointMappingsModule = PluginExtensionPoint_Plugin.moduleUrl
191
+ // Runtime-safe mapping module (not the `_Builder` variant, which the Lambda layer
192
+ // strips because it pulls Pulumi via `include Extension_Builder.Make(...)`).
193
+ let pluginConnectExtensionMappingsModule = PluginConnectExtension_Mapping.moduleUrl
194
+
195
+ type jsonEventsHandler = Plugin_Callback.jsonEventsHandler
196
+ type jsonEventsHandlers = {
197
+ outgoing?: jsonEventsHandler,
198
+ incoming?: jsonEventsHandler,
199
+ }
200
+ let getIncomingJsonEventsHandler = jsonEventsHandlers => jsonEventsHandlers.incoming
201
+ let getOutgoingJsonEventsHandler = jsonEventsHandlers => jsonEventsHandlers.outgoing
202
+
203
+ let serviceNameToJsonEventsHandlers: (
204
+ array<'o>,
205
+ 'o => array<string>,
206
+ array<jsonEventsHandlers>,
207
+ jsonEventsHandlers => option<jsonEventsHandler>,
208
+ ) => dict<array<jsonEventsHandler>> = (outputs, getServiceNames, handlers, getEventHandler) => {
209
+ let dict = Dict.make()
210
+ Array.zip(outputs, handlers)->Array.forEach(((outputs, jsonEventsHandlers)) => {
211
+ jsonEventsHandlers
212
+ ->getEventHandler
213
+ ->Option.forEach(jsonEventsHandler =>
214
+ outputs
215
+ ->getServiceNames
216
+ ->Array.forEach(
217
+ serviceName =>
218
+ switch dict->Dict.get(serviceName) {
219
+ | Some(jsonEventsHandlers) =>
220
+ Dict.set(dict, serviceName, jsonEventsHandlers->Array.concat([jsonEventsHandler]))
221
+ | None => Dict.set(dict, serviceName, [jsonEventsHandler])
222
+ },
223
+ )
224
+ )
225
+ })
226
+ dict
227
+ }
228
+
229
+ include Builder_Helpers
230
+
231
+ module ApiNoApi = ApiNoApiHelpers
232
+
233
+ let isNoApi = ApiNoApi.isNoApi
234
+ let getExcludedVariants = ApiNoApi.getExcludedVariants
235
+ let filterNoApiVariants = ApiNoApi.filterNoApiVariants
236
+
237
+ // Side-output of `createExtensions`: per merged-group registry data the
238
+ // adapter entry point reconstructs Extension_Operations from. Lives next to
239
+ // the existing `extensionsOutputs` / `extensionsHandlers` arrays — same
240
+ // indexing.
241
+ type extensionRegistryInfo = {
242
+ specModule: string,
243
+ mappingsModule: string,
244
+ delegateModule: string,
245
+ }
246
+
247
+ let createExtensions = (
248
+ extensions: array<module(ReventlessInfra.Extension.Blueprint)>,
249
+ ~pluginName,
250
+ ~publishToPluginExtensionPoint,
251
+ ~publishToAggregates,
252
+ ~publishToReadModels,
253
+ ~queryEngine,
254
+ ~opts,
255
+ ) => {
256
+ // Group blueprints by extension point name for auto-merge.
257
+ let groups: dict<array<module(ReventlessInfra.Extension.Blueprint)>> = Dict.make()
258
+ extensions->Array.forEach(bp => {
259
+ let module(BP: ReventlessInfra.Extension.Blueprint) = bp
260
+ let epName = BP.Spec.name
261
+ switch groups->Dict.get(epName) {
262
+ | Some(existing) => existing->Array.push(bp)
263
+ | None => groups->Dict.set(epName, [bp])
264
+ }
265
+ })
266
+
267
+ // For each EP group: merge mappings, build Extension component.
268
+ let triples = groups
269
+ ->Dict.toArray
270
+ ->Array.map(((_epName, blueprints)) => {
271
+ // Use the first blueprint's Spec as the canonical type.
272
+ let module(First: ReventlessInfra.Extension.Blueprint) = blueprints->Array.getUnsafe(0)
273
+
274
+ // Merge all mappings arrays. Blueprints for the same EP have the same Spec
275
+ // at runtime — use Obj.magic to unify the existential Mapping types.
276
+ let allMappings: array<module(First.Mapping)> =
277
+ blueprints->Array.flatMap(bp => {
278
+ let module(BP: ReventlessInfra.Extension.Blueprint) = bp
279
+ (BP.mappings: array<module(BP.Mapping)>)->Obj.magic
280
+ })
281
+
282
+ // Build the Extension component with pluginName as the extension name.
283
+ module Spec = First.Spec
284
+ module Mappings: Extension.Mappings with module Spec := Spec = {
285
+ module type Mapping = ReventlessInfra.ExtensionMapping.T
286
+ with module ExtensionPoint := Spec
287
+ let name = pluginName
288
+ let moduleUrl = First.moduleUrl
289
+ let mappings: array<module(Mapping)> = allMappings->Obj.magic
290
+ }
291
+ module ExtensionMaker = Extension_Builder.Make(Spec, Mappings)
292
+
293
+ let extension = ExtensionMaker.make(
294
+ ~publishToPluginExtensionPoint,
295
+ ~publishToAggregates,
296
+ ~readModelNamesForSourceName,
297
+ ~publishToReadModels,
298
+ ~queryEngine,
299
+ ~opts=Some(opts),
300
+ )
301
+ let ops: Pulumi.Output.t<Extension.operations> =
302
+ ExtensionMaker.operations(extension)->Obj.magic
303
+ let registryInfo: extensionRegistryInfo = {
304
+ // EP spec module URL (e.g. OrderingSpec/.../Orders_ExtensionPoint.res.mjs)
305
+ specModule: Spec.moduleUrl,
306
+ // User extension file URL — the .res.mjs declaring `module Mapping`.
307
+ // The bundled Plugin EventCollector entry point dynamic-imports this to
308
+ // pick up mapIncomingEvent / mapOutgoingEvent. Multi-blueprint merges
309
+ // still surface one path here so the runtime has one known module to
310
+ // import; the entry point regroups by extensionPointName.
311
+ mappingsModule: First.moduleUrl,
312
+ // Delegate spec URL (aggregate / slice the extension delegates to).
313
+ // The entry point dynamic-imports this to reconstruct
314
+ // `Mapping.Delegate` before handing the full mapping to ExtensionMapping.Make.
315
+ delegateModule: First.delegateModuleUrl,
316
+ }
317
+ (
318
+ ExtensionMaker.outputs(extension),
319
+ ops->Pulumi.Output.apply(({outgoingJsonEventsHandler, incomingJsonEventsHandler}) => {
320
+ incoming: incomingJsonEventsHandler,
321
+ outgoing: outgoingJsonEventsHandler,
322
+ }),
323
+ registryInfo,
324
+ )
325
+ })
326
+ let outputs = triples->Array.map(((o, _, _)) => o)
327
+ let handlers = triples->Array.map(((_, h, _)) => h)
328
+ let registryInfos = triples->Array.map(((_, _, r)) => r)
329
+ (outputs, handlers, registryInfos)
330
+ }
331
+
332
+ let extractExtensionPointDefinitions = (extensionPointsOutputs: array<ExtensionPoint.outputs>) =>
333
+ extensionPointsOutputs
334
+ ->Array.map(extensionPointOutputs =>
335
+ (
336
+ extensionPointOutputs.commandTopic->Pulumi.Output.flatMap(({resources}) =>
337
+ switch resources->Array.get(0) {
338
+ | Some(r) => r.id
339
+ | None => Pulumi.Output.make("")
340
+ }
341
+ ),
342
+ extensionPointOutputs.eventTopic->Pulumi.Output.flatMap(({resources}) =>
343
+ switch resources->Array.get(0) {
344
+ | Some(r) => r.id
345
+ | None => Pulumi.Output.make("")
346
+ }
347
+ ),
348
+ )
349
+ ->Pulumi.Output.all2
350
+ ->Pulumi.Output.apply(((commandTopicChannelId, eventTopicPublisherId)) => {
351
+ Reventless.Plugin.name: extensionPointOutputs.name,
352
+ commandTopic: commandTopicChannelId,
353
+ eventTopic: eventTopicPublisherId,
354
+ })
355
+ )
356
+ ->Pulumi.Output.all
357
+
358
+ // `dcbSources` lists cross-plugin DCB EventLog names this extension consumes.
359
+ // Empty for now: the current Extension model is mono-source (single EP Spec).
360
+ // Future work will populate this by walking extension blueprint mappings for
361
+ // `Source { name = "<peer>DcbEventLog" }` declarations.
362
+ let extractExtensionDefinitions = (extensionsOutputs: array<Extension.outputs>) =>
363
+ extensionsOutputs->Array.map(extensionOutputs => {
364
+ Reventless.Plugin.name: extensionOutputs.name,
365
+ extensionPointName: extensionOutputs.extensionPointName,
366
+ dcbSources: [],
367
+ })
368
+
369
+ let createConnectPluginExtension = (
370
+ ~pluginDefinition,
371
+ ~publishToPluginExtensionPoint,
372
+ ~publishToAggregates,
373
+ ~readModelNamesForSourceName,
374
+ ~publishToReadModels,
375
+ ~queryEngine,
376
+ ~opts,
377
+ ) =>
378
+ pluginDefinition
379
+ ->Pulumi.Output.apply(pluginDefinition => {
380
+ module ConnectPluginExtension = PluginConnectExtension_Builder.Make({
381
+ let pluginDefinition = pluginDefinition
382
+ })
383
+ let connectPluginExtension = ConnectPluginExtension.make(
384
+ ~publishToPluginExtensionPoint,
385
+ ~publishToAggregates,
386
+ ~readModelNamesForSourceName,
387
+ ~publishToReadModels,
388
+ ~queryEngine,
389
+ ~opts=Some(opts),
390
+ )
391
+ let connectPluginExtensionOutputs = connectPluginExtension->Component.outputs
392
+ let connectPluginExtensionIncomingEventHandler =
393
+ connectPluginExtension
394
+ ->Component.operations
395
+ ->Pulumi.Output.apply(({incomingJsonEventsHandler}) => incomingJsonEventsHandler)
396
+
397
+ (connectPluginExtensionOutputs, connectPluginExtensionIncomingEventHandler)
398
+ })
399
+ ->Pulumi.Output.unzip
400
+
401
+ let tasksOutputs = ref([])
402
+
403
+ let createTasks = (
404
+ tasks,
405
+ ~aggregatesOutputs,
406
+ ~scheduler,
407
+ ~schedulerRoleUrn,
408
+ ~publishToAggregates,
409
+ ~queryEngine,
410
+ ~resourceNaming,
411
+ ~opts,
412
+ ) => {
413
+ tasksOutputs :=
414
+ tasks->Array.map((module(SpecificTask: ReventlessInfra.Task.T)) =>
415
+ SpecificTask.outputs(SpecificTask.make(
416
+ ~queryBucketName=(~taskName, ~bucketName="Bucket") =>
417
+ ResourceQueryRuntime.bucketNameOfTaskExn(tasksOutputs.contents, ~taskName, ~bucketName),
418
+ ~scheduler,
419
+ ~schedulerRoleUrn,
420
+ ~publishToAggregates,
421
+ ~queryEngine,
422
+ ~resourceNaming,
423
+ ~allAggregates=aggregatesOutputs,
424
+ ~opts=Some(opts),
425
+ ))
426
+ )
427
+ tasksOutputs.contents
428
+ }
429
+
430
+ module MakeEventCollectorHelper = (
431
+ RuntimeEnvironment: Runtime.Environment,
432
+ EventCollectorChannel: EventCollector_Adapter.Channel
433
+ with type runtimeParts = RuntimeEnvironment.parts,
434
+ PluginRuntimeBuilder: PluginRuntime_Builder.T
435
+ with module EventCollectorChannel = EventCollectorChannel,
436
+ ) => {
437
+ module PluginEventCollector = EventCollector_Builder.Make(
438
+ RuntimeEnvironment,
439
+ EventCollectorChannel,
440
+ )
441
+ let make = (~name, ~eventTopics, ~opts) => {
442
+ let eventCollector = PluginEventCollector.make(~name, ~eventTopics, ~opts)
443
+ let eventCollectorOutputs = eventCollector->Component.outputs
444
+ // pluginDefinition.eventCollector must identify the EC's inbound queue
445
+ // ARN — admin's `manageSubscriptions` uses it as the subscription target
446
+ // (SNS topic → SQS endpoint). The AWS SQS EventCollectorChannel appends
447
+ // the queue resource AFTER the upstream event-topic resources in its
448
+ // `channel.resources` list, so the queue is always the last element.
449
+ // Earlier this picked `resources[0]`, which silently selected the first
450
+ // subscribed event topic (e.g. a DCB EventLog DynamoDB stream ARN) and
451
+ // produced "Invalid parameter: SQS endpoint ARN" errors at subscribe
452
+ // time. In-memory adapters don't use this field (no SNS), so the choice
453
+ // there is moot.
454
+ let resources = eventCollectorOutputs.resources
455
+ let eventCollectorUrn = switch resources->Array.get(resources->Array.length - 1) {
456
+ | Some(r) => r.urn
457
+ | None => Pulumi.Output.make("")
458
+ }
459
+
460
+ (eventCollector, eventCollectorOutputs, eventCollectorUrn)
461
+ }
462
+
463
+ // Unified connect — handles both with-admin and without-admin cases.
464
+ // When ~pluginExtensionPointUnwrapped is provided, admin extension point
465
+ // resources and ConnectPluginExtension handlers are wired. Otherwise falls
466
+ // back to a simplified path (no admin extension point resources, empty
467
+ // incoming connect extension handlers).
468
+ let connect = (
469
+ ~eventCollector: EventCollector.component,
470
+ ~eventTopics: EventTopic.allOutputs,
471
+ ~extensionPointsOutputs: array<ExtensionPoint.outputs>,
472
+ ~extensionsOutputs: array<Extension.outputs>,
473
+ ~pluginExtensionPointUnwrapped: option<ReventlessInterop.ExtensionPoint.resolvedOutputs>=?,
474
+ ~pluginDefinition,
475
+ ~connectPluginExtensionIncomingEventHandler: option<Pulumi.Output.t<Pulumi.Output.t<Plugin_Callback.jsonEventsHandler>>>=?,
476
+ ~extensionsHandlers,
477
+ ~extensionPointsHandlers,
478
+ ~connectPluginExtensionOutputs: option<Pulumi.Output.t<Extension.outputs>>=?,
479
+ // Per-extension registry metadata (parallel to extensionsOutputs / extensionsHandlers).
480
+ // Empty when there are no user extensions or when the caller doesn't need
481
+ // bundled-handler reconstruction (e.g. Platform_Admin path).
482
+ ~extensionRegistryInfos: array<extensionRegistryInfo>=[],
483
+ // Per-extension-point registry metadata (parallel to extensionPointsOutputs /
484
+ // extensionPointsHandlers). Carries spec + mapping module URLs the
485
+ // EventCollector entry point dynamic-imports to publish outgoing events.
486
+ // Empty when there are no user extension points (e.g. Platform_Admin path).
487
+ ~extensionPointRegistryInfos: array<Builder_Helpers.extensionPointRegistryInfo>=[],
488
+ // aggregateName → cmd-topic SQS URL. Includes every aggregate / DCB slice
489
+ // that a user extension may publish to. The full plugin dict is fine —
490
+ // the runtime filters to ext.aggregateNames when invoking each extension.
491
+ ~aggregateQueueUrls: dict<Pulumi.Output.t<string>>=Dict.make(),
492
+ // rmName → RM EventCollector SQS URL. Populated only for RMs that
493
+ // user extensions may enqueue events into directly. Plugin RMs fed
494
+ // through the normal EventTopic → EventColl subscription path don't
495
+ // need entries here.
496
+ ~readModelQueueUrls: dict<Pulumi.Output.t<string>>=Dict.make(),
497
+ // The global readModelNamesForSourceName inversion (sourceName → [rmName]).
498
+ // Plain dict — no Pulumi outputs because it's pure name metadata.
499
+ ~readModelNamesForSourceName: dict<array<string>>=Dict.make(),
500
+ ) => {
501
+ let resources =
502
+ extensionPointsOutputs
503
+ ->Array.map(extensionPoint => extensionPoint.eventTopic)
504
+ ->Pulumi.Output.all
505
+ ->Pulumi.Output.apply(eventTopics => {
506
+ let base =
507
+ eventTopics
508
+ ->Array.map(eventTopic => eventTopic.resources)
509
+ ->Array.flat
510
+ switch pluginExtensionPointUnwrapped {
511
+ | Some(unwrapped) =>
512
+ base->Array.concat(unwrapped.commandTopic.resources->Adapter.fromInteropResources)
513
+ | None => base
514
+ }
515
+ })
516
+
517
+ // Resolve ConnectPluginExtension data (or provide defaults for no-Core path)
518
+ let connectExtData =
519
+ switch (connectPluginExtensionIncomingEventHandler, connectPluginExtensionOutputs) {
520
+ | (Some(handler), Some(outputs)) =>
521
+ (handler->Pulumi.Output.unwrap, outputs)
522
+ ->Pulumi.Output.all2
523
+ ->Pulumi.Output.apply(((h, o)) => Some((h, o)))
524
+ | _ => Pulumi.Output.make(None)
525
+ }
526
+
527
+ (
528
+ pluginDefinition,
529
+ connectExtData,
530
+ extensionsHandlers->Pulumi.Output.all,
531
+ extensionPointsHandlers->Pulumi.Output.all,
532
+ resources,
533
+ )
534
+ ->Pulumi.Output.all5
535
+ ->Pulumi.Output.apply(((
536
+ pluginDefinition,
537
+ connectExtData,
538
+ extensionsHandlers,
539
+ extensionPointsHandlers,
540
+ resources,
541
+ )) => {
542
+ let incomingConnectExtensionEventHandlers = switch connectExtData {
543
+ | Some((handler, outputs)) =>
544
+ serviceNameToJsonEventsHandlers(
545
+ [outputs],
546
+ outputs => [outputs.extensionPointName],
547
+ [{incoming: handler}],
548
+ getIncomingJsonEventsHandler,
549
+ )
550
+ | None => Dict.make()
551
+ }
552
+ module Callback = Plugin_Callback.Make({
553
+ let pluginDefinition = pluginDefinition
554
+ let outgoingExtensionPointEventHandlers = serviceNameToJsonEventsHandlers(
555
+ extensionPointsOutputs,
556
+ outputs => outputs.aggregateNames,
557
+ extensionPointsHandlers->Array.map(extensionPointsHandler => {
558
+ outgoing: extensionPointsHandler,
559
+ }),
560
+ getOutgoingJsonEventsHandler,
561
+ )
562
+ let incomingConnectExtensionEventHandlers = incomingConnectExtensionEventHandlers
563
+ let outgoingExtensionEventHandlers = serviceNameToJsonEventsHandlers(
564
+ extensionsOutputs,
565
+ outputs => outputs.aggregateNames,
566
+ extensionsHandlers,
567
+ getOutgoingJsonEventsHandler,
568
+ )
569
+ let incomingExtensionEventHandlers = serviceNameToJsonEventsHandlers(
570
+ extensionsOutputs,
571
+ outputs => [outputs.extensionPointName],
572
+ extensionsHandlers,
573
+ getIncomingJsonEventsHandler,
574
+ )
575
+ })
576
+ let handler = PluginEventCollector.makeHandler(
577
+ ~eventCollector,
578
+ ~jsonEventsHandler=Callback.handleJsonEvents,
579
+ )
580
+
581
+ // Register the runtime context the adapter entry point reconstructs from
582
+ // HANDLER_CONFIG. AWS reads this in forPluginEventCollector; in-memory
583
+ // adapters ignore it and stay on the Output-bound Callback above.
584
+ let ecResource = eventCollector->Component.toPulumiResource
585
+ let ecName =
586
+ ecResource.name->ComponentType.nameOpt(EventCollector.componentType)
587
+ let pluginDefinitionJson =
588
+ pluginDefinition
589
+ ->S.reverseConvertToJsonOrThrow(Reventless.Plugin.pluginDefinitionSchema)
590
+ ->JSON.stringify
591
+ ->Pulumi.Output.make
592
+ let pluginExtensionPointCmdTopicUrl = switch pluginExtensionPointUnwrapped {
593
+ | Some(unwrapped) =>
594
+ switch unwrapped.commandTopic.resources->Array.get(0) {
595
+ | Some(r) => Pulumi.Output.make(r.id)
596
+ | None => Pulumi.Output.make("")
597
+ }
598
+ | None => Pulumi.Output.make("")
599
+ }
600
+ let connectExtension = switch connectExtData {
601
+ | Some(_) =>
602
+ Some({
603
+ specModule: adminPluginExtensionPointSpecModule,
604
+ mappingsModule: pluginConnectExtensionMappingsModule,
605
+ extensionPointName: ReventlessInfra.PluginExtensionPointSpec.name,
606
+ })
607
+ | None => None
608
+ }
609
+ // Build the user-extension registry entries. Each entry pairs
610
+ // Extension.outputs (name/EP name/aggregate names) with the matching
611
+ // moduleUrls captured by createExtensions. Skipped if the parallel
612
+ // arrays don't match length — defensive against future refactors.
613
+ let extensions: array<extensionEntry> = if (
614
+ extensionsOutputs->Array.length == extensionRegistryInfos->Array.length
615
+ ) {
616
+ extensionsOutputs->Array.mapWithIndex((output, i) => {
617
+ let info = extensionRegistryInfos->Array.getUnsafe(i)
618
+ let rmNames =
619
+ readModelNamesForSourceName
620
+ ->Dict.get(output.extensionPointName)
621
+ ->Option.getOr([])
622
+ {
623
+ name: output.name,
624
+ specModule: info.specModule,
625
+ mappingsModule: info.mappingsModule,
626
+ delegateModule: info.delegateModule,
627
+ extensionPointName: output.extensionPointName,
628
+ aggregateNames: output.aggregateNames,
629
+ readModelNames: rmNames,
630
+ }
631
+ })
632
+ } else {
633
+ []
634
+ }
635
+ // Connect always publishes to the admin's Plugin aggregate. When
636
+ // user extensions are wired, merge their aggregate URLs in as well —
637
+ // the runtime filters per extension.
638
+ let mergedAggregateUrls = Dict.make()
639
+ aggregateQueueUrls
640
+ ->Dict.toArray
641
+ ->Array.forEach(((k, v)) => mergedAggregateUrls->Dict.set(k, v))
642
+ switch connectExtData {
643
+ | Some(_) =>
644
+ // Plugin aggregate cmd-topic URL = the admin's Plugin EP cmd topic
645
+ // (Connect routes ConnectPlugin through the EP). Look it up if not
646
+ // already supplied by the caller.
647
+ switch mergedAggregateUrls->Dict.get(ReventlessCore.PluginSpec.name) {
648
+ | Some(_) => ()
649
+ | None => mergedAggregateUrls->Dict.set(ReventlessCore.PluginSpec.name, pluginExtensionPointCmdTopicUrl)
650
+ }
651
+ | None => ()
652
+ }
653
+ // Build the extension-point registry entries (mirrors the user-extension
654
+ // pattern above). Pairs Pulumi outputs (name / eventTopic / aggregateNames)
655
+ // with the moduleUrls captured by createExtensionPoints. Skipped if the
656
+ // parallel arrays don't match length — defensive against future refactors.
657
+ let extensionPointEntries: array<extensionPointEntry> = if (
658
+ extensionPointsOutputs->Array.length == extensionPointRegistryInfos->Array.length
659
+ ) {
660
+ extensionPointsOutputs->Array.mapWithIndex((output, i) => {
661
+ let info = extensionPointRegistryInfos->Array.getUnsafe(i)
662
+ let eventTopicArn =
663
+ output.eventTopic->Pulumi.Output.flatMap(({resources}) =>
664
+ switch resources->Array.get(0) {
665
+ | Some(r) => r.id
666
+ | None => Pulumi.Output.make("")
667
+ }
668
+ )
669
+ {
670
+ specModule: info.specModule,
671
+ mappingsModule: info.mappingsModule,
672
+ eventTopicArn,
673
+ aggregateNames: output.aggregateNames,
674
+ }
675
+ })
676
+ } else {
677
+ []
678
+ }
679
+ registerEventCollectorContext(
680
+ ~componentName=ecName,
681
+ ~context={
682
+ pluginDefinitionJson,
683
+ extensionPoints: extensionPointEntries,
684
+ connectExtension,
685
+ extensions,
686
+ pluginExtensionPointCmdTopicUrl,
687
+ publishToAggregates: mergedAggregateUrls,
688
+ readModelQueueUrls,
689
+ readModelNamesForSourceName,
690
+ },
691
+ )
692
+
693
+ eventCollector->PluginRuntimeBuilder.forPluginEventCollector(
694
+ ~handler,
695
+ ~eventTopics,
696
+ ~resources,
697
+ )
698
+
699
+ let _ = switch (eventCollector->Component.outputs).resources->Array.get(0) {
700
+ | Some(r) => r.urn->Pulumi.Output.apply(urn => pluginDefinition.eventCollector = urn)
701
+ | None => Pulumi.Output.make()
702
+ }
703
+ })
704
+ }
705
+ }
706
+
707
+
708
+ // ---------------------------------------------------------------------------
709
+ // Shared schema type and plugin-built hook — re-exported from Plugin_Callbacks
710
+ // (runtime-safe, no Pulumi imports) for backward compatibility.
711
+ // ---------------------------------------------------------------------------
712
+ include Plugin_BuiltHook
713
+
714
+ // ---------------------------------------------------------------------------
715
+ // Plugin-deployed hook — fires inside Output.apply after all component
716
+ // resources have resolved, providing fully resolved resource data.
717
+ // ---------------------------------------------------------------------------
718
+ type pluginDeployedSubComponent = {
719
+ role: string,
720
+ resources: array<ReventlessInterop.Resource.t>,
721
+ }
722
+
723
+ type pluginDeployedComponent = {
724
+ name: string,
725
+ kind: string,
726
+ schema: pluginDeployedSchema,
727
+ resources: array<ReventlessInterop.Resource.t>,
728
+ subComponents: array<pluginDeployedSubComponent>,
729
+ }
730
+
731
+ type extensionWiring = {
732
+ extensionName: string,
733
+ extensionPointName: string,
734
+ providerPlugin: string,
735
+ providerVersion: string,
736
+ subscriberPlugin: string,
737
+ subscriberVersion: string,
738
+ }
739
+
740
+ type pluginDeployedInfo = {
741
+ name: string,
742
+ version: string,
743
+ environment: string,
744
+ stackName: string,
745
+ deployedAt: string,
746
+ actor: string,
747
+ deploymentId: string,
748
+ kind?: pluginKind,
749
+ displayName?: string,
750
+ vendor?: string,
751
+ architectureType?: architectureType,
752
+ components: array<pluginDeployedComponent>,
753
+ extensionWirings: array<extensionWiring>,
754
+ }
755
+
756
+ let onPluginDeployedHook: ref<option<pluginDeployedInfo => promise<unit>>> = ref(None)
757
+
758
+ let registerOnPluginDeployed = (hook: pluginDeployedInfo => promise<unit>) => {
759
+ onPluginDeployedHook.contents = Some(hook)
760
+ }
761
+
762
+ let clearOnPluginDeployed = () => {
763
+ onPluginDeployedHook.contents = None
764
+ }
765
+
766
+ // ---------------------------------------------------------------------------
767
+ // Platform-deployed hook — fires after deployPlatform / makePlatform
768
+ // completes, providing platform-level metadata with resolved values.
769
+ // ---------------------------------------------------------------------------
770
+ type platformDeployedInfo = {
771
+ name: string,
772
+ environment: string,
773
+ region: string,
774
+ // Domain API — handles application mutations from plugin stacks.
775
+ domainApiEndpoint: string,
776
+ domainApiRoleArn: string,
777
+ // Platform API — handles Platform_Sync* and admin mutations.
778
+ // Equals domainApiEndpoint/domainApiRoleArn in unified (non-split) mode.
779
+ platformApiEndpoint: string,
780
+ platformApiRoleArn: string,
781
+ adminResources: array<ReventlessInterop.Resource.t>,
782
+ }
783
+
784
+ let onPlatformDeployedHook: ref<option<platformDeployedInfo => unit>> = ref(None)
785
+
786
+ let lastPlatformDeployedInfo: ref<option<platformDeployedInfo>> = ref(None)
787
+
788
+ let registerOnPlatformDeployed = (hook: platformDeployedInfo => unit) => {
789
+ onPlatformDeployedHook.contents = Some(hook)
790
+ }
791
+
792
+ let firePlatformDeployedHook = (info: platformDeployedInfo) => {
793
+ lastPlatformDeployedInfo.contents = Some(info)
794
+ switch onPlatformDeployedHook.contents {
795
+ | Some(hook) => hook(info)
796
+ | None => ()
797
+ }
798
+ }
799
+
800
+ let replayPlatformDeployedHook = () => {
801
+ switch (onPlatformDeployedHook.contents, lastPlatformDeployedInfo.contents) {
802
+ | (Some(hook), Some(info)) => hook(info)
803
+ | _ => ()
804
+ }
805
+ }
806
+
807
+ let clearOnPlatformDeployed = () => {
808
+ onPlatformDeployedHook.contents = None
809
+ lastPlatformDeployedInfo.contents = None
810
+ }
811
+
812
+ // Resolver error hook has moved to Plugin_ResolverError to keep it on the
813
+ // runtime-safe import chain (CommandGenerator_Callback runs in Lambda; this
814
+ // module pulls in Pulumi for deploy-time helpers).
815
+
816
+ // ---------------------------------------------------------------------------
817
+ // Shared parameter types for hooks that carry structured data.
818
+ // ---------------------------------------------------------------------------
819
+ type mutationKind = Aggregate | Dcb
820
+
821
+ type inboundAppSyncResolverParams = {
822
+ runtime: Runtime.environment<unknown>,
823
+ fieldNames: array<string>,
824
+ externalInputSchemas: array<S.t<unknown>>,
825
+ opts: Pulumi.ComponentResource.options,
826
+ }
827
+
828
+ type dcbAppSyncResolverParams = {
829
+ runtime: Runtime.environment<unknown>,
830
+ fieldNames: array<string>,
831
+ tags: array<string>,
832
+ opts: Pulumi.ComponentResource.options,
833
+ }
834
+
835
+ // ---------------------------------------------------------------------------
836
+ // Query field names registry — populated by Plugin_Builder during construct()
837
+ // to map QueryDb component names → plugin-prefixed GraphQL query field names.
838
+ // Read by QueryDbResolvers_GraphQL.make() to align resolver SDL with fragment SDL.
839
+ // ---------------------------------------------------------------------------
840
+ let queryFieldNamesRegistry: dict<Api_Naming.queryNames> = Dict.make()
841
+
842
+ // ---------------------------------------------------------------------------
843
+ // State schema registry — populated alongside queryFieldNamesRegistry so that
844
+ // the in-memory QueryDb resolver can derive the same `serverCapability`
845
+ // (filter / orderBy fields) the FragmentGenerator computed at SDL emission
846
+ // time. Keyed by Spec.name like queryFieldNamesRegistry.
847
+ // ---------------------------------------------------------------------------
848
+ let stateSchemaRegistry: dict<S.t<unknown>> = Dict.make()
849
+
850
+ // ---------------------------------------------------------------------------
851
+ // Aggregate mutation field names registry — populated by Plugin_Builder during
852
+ // construct() to map aggregate Spec.name → plugin-prefixed mutation field names.
853
+ // Read by CommandGenerator_Builder.connect() to provide plugin-prefixed mutation field names.
854
+ // ---------------------------------------------------------------------------
855
+ let aggregateMutationFieldsRegistry: dict<array<string>> = Dict.make()
856
+
857
+ // ---------------------------------------------------------------------------
858
+ // MCP schema registration params type — shared by platformHooks and callers.
859
+ // ---------------------------------------------------------------------------
860
+ type mcpRegistrationParams = {
861
+ pluginName: string,
862
+ mutationEntries: array<ReventlessInfra.Api.mutationSchemaEntry>,
863
+ queryEntries: array<ReventlessInfra.Api.querySchemaEntry>,
864
+ eventLogEntries: array<ReventlessInfra.Api.eventLogSchemaEntry>,
865
+ /** Subscription SDL field strings from the plugin fragment (Sources A, B, C).
866
+ Used by the in-memory platform to register yoga WebSocket subscription resolvers. */
867
+ subscriptionFields: array<string>,
868
+ }
869
+
870
+ // Subscription infrastructure hook params — fired after allQueryDbs and allEventTopics
871
+ // are assembled inside builderOutputs. Lets the AWS platform wire StateTopic and
872
+ // EventLogSubscription Lambdas without touching reventless-core.
873
+ type subscriptionInfraParams = {
874
+ allQueryDbs: ReventlessInfra.QueryDb.allOutputs,
875
+ allEventTopics: dict<ReventlessInfra.EventTopic.outputs>,
876
+ eventLogEntries: array<ReventlessInfra.Api.eventLogSchemaEntry>,
877
+ opts: Pulumi.ComponentResource.options,
878
+ }
879
+
880
+ // ---------------------------------------------------------------------------
881
+ // platformHooks — platform callbacks and coordination state passed to builder
882
+ // functors as a record.
883
+ //
884
+ // Optional fields (field?): callbacks set at record creation; absent = None.
885
+ // Required ref field: adminExtensionPoints — a mutable cell set by makePlatform
886
+ // after Admin.construct() returns, read by Plugin_Builder to wire the local
887
+ // admin connection path (in-memory). Initialized to an empty dict output;
888
+ // AWS platforms leave it empty and fall back to Interstack instead.
889
+ //
890
+ // `noHooks` is the "no callbacks" default, with adminExtensionPoints starting
891
+ // as an empty dict output.
892
+ // ---------------------------------------------------------------------------
893
+ type platformHooks = {
894
+ // ── In-memory GraphQL mutation registration ────────────────────────────
895
+ // Phase 1: register SDL + resolver stub synchronously.
896
+ // `commandAuthorization` is the `command => permission` function from the
897
+ // aggregate / slice Spec; the resolver evaluates it per-request against
898
+ // `ctx.identity` to enforce per-constructor authorization rules.
899
+ mutationResolverHook?: (
900
+ ~kind: mutationKind,
901
+ ~fields: array<string>,
902
+ ~commandSchema: S.t<unknown>,
903
+ ~commandAuthorization: unknown => Reventless.Authorization.permission,
904
+ ) => unit,
905
+ // Phase 2: bind generateCommand inside Output.apply.
906
+ mutationBindHook?: (~field: string, ~generateCommand: CommandGenerator.commandGenerator) => unit,
907
+ // InboundTranslationSlice — phase 1: register SDL + stub.
908
+ inboundMutationResolverHook?: (~fieldName: string, ~externalInputSchema: S.t<unknown>) => unit,
909
+ // InboundTranslationSlice — phase 2: bind receive.
910
+ inboundMutationBindReceiveHook?: (~fieldName: string, ~receive: JSON.t => promise<result<array<string>, string>>) => unit,
911
+ // GraphQL type definitions.
912
+ schemaTypeRegistrationHook?: array<string> => unit,
913
+ // Subscription infrastructure (AWS): wire StateTopic + EventLogSubscription Lambdas.
914
+ // Fired inside builderOutputs after allQueryDbs and allEventTopics are assembled.
915
+ subscriptionInfraHook?: subscriptionInfraParams => unit,
916
+ // MCP tools and resources.
917
+ mcpSchemaRegistrationHook?: mcpRegistrationParams => unit,
918
+ // ── AppSync resolver creation (AWS) ───────────────────────────────────
919
+ preResolversSchemaHook?: (~name: string, ~version: string, Reventless.Plugin.apiSchemaFragment) => Pulumi.Output.t<unit>,
920
+ // Admin equivalent of preResolversSchemaHook. Set by AWS platforms to push
921
+ // the admin SDL to the Platform (split mode) or Domain (unified mode) API.
922
+ // Platform_Admin.construct invokes this with a barrier that resolves once the
923
+ // admin AppSync DataSources are ready, and gates admin createResolvers on the
924
+ // returned Output so resolver CreateResolver calls don't race the API-level
925
+ // schema-creation lock. Mirrors Plugin_Builder's schemaPushed gating at
926
+ // Plugin_Builder.res:452-466. The hook owns SDL construction (no fragment
927
+ // arg — the admin SDL is platform-defined, not per-plugin).
928
+ preAdminResolversSchemaHook?: (~adminBarrier: Pulumi.Output.t<unit>) => Pulumi.Output.t<unit>,
929
+ inboundAppSyncResolverHook?: inboundAppSyncResolverParams => unit,
930
+ dcbAppSyncResolverHook?: dcbAppSyncResolverParams => unit,
931
+ // ── Deployment lifecycle (AWS) ─────────────────────────────────────────
932
+ onDcbEventLogCreated?: unknown => unit,
933
+ onDcbCommandTopicCreated?: unknown => unit,
934
+ onDcbSlicesCreated?: unknown => unit,
935
+ onHeartbeatEpChannelAvailable?: (unknown, ~pluginId: string) => unit,
936
+ // ── Admin → Plugin coordination ────────────────────────────────────────
937
+ // Set by makePlatform after Admin.construct(); read by Plugin_Builder to
938
+ // wire the local admin connection path (in-memory). Starts as an empty
939
+ // dict; AWS platforms leave it empty and use Interstack instead.
940
+ adminExtensionPoints: ref<Pulumi.Output.t<dict<ExtensionPoint.outputs>>>,
941
+ // ── Platform context (populated by makePlatform/deployPlugin) ──────────
942
+ // Read by Plugin_Builder.make so app plugins don't need to pass these.
943
+ // api/apiRole stored as hookedValue<unknown> to avoid Pulumi Output Proxy
944
+ // corrupting ReScript option boxing (BS_PRIVATE_NESTED_SOME_NONE sentinel).
945
+ // Cast back via Obj.magic in Plugin_Builder where concrete types are known.
946
+ scheduler: ref<option<Pulumi.Output.t<Scheduler.operations>>>,
947
+ // URN identifying the principal/role the scheduler invokes targets as.
948
+ // Populated by deployment-aware platforms; empty Output on platforms that
949
+ // don't expose this (e.g. in-memory). Threaded through Plugin_Builder into
950
+ // each Task's runtime config so bundled handlers can talk to the
951
+ // underlying scheduler service.
952
+ schedulerRoleUrn: ref<Pulumi.Output.t<string>>,
953
+ api: ref<option<hookedValue<unknown>>>,
954
+ apiRole: ref<option<hookedValue<unknown>>>,
955
+ // Current deploy target, set by deployPlugin before plugin.make() is called.
956
+ // "Domain" (default) → resolvers/schema go to the DomainApi.
957
+ // "Platform" → resolvers/schema go to the PlatformApi.
958
+ // Plugin_Builder captures this synchronously when constructing pluginDefinition
959
+ // to avoid the async-reset race (deployPlugin resets to "Domain" after make()).
960
+ deployTarget: ref<string>,
961
+ }
962
+
963
+ // Default hooks — no callbacks, empty platform context.
964
+ let noHooks: platformHooks = {
965
+ adminExtensionPoints: ref(Pulumi.Output.make(Dict.make())),
966
+ scheduler: ref(None),
967
+ schedulerRoleUrn: ref(Pulumi.Output.make("")),
968
+ api: ref(None),
969
+ apiRole: ref(None),
970
+ deployTarget: ref("Domain"),
971
+ }
972
+
973
+ // Functor parameter wrapper for platformHooks.
974
+ module type HooksConfig = {
975
+ let hooks: platformHooks
976
+ }
977
+
978
+ // Pre-built HooksConfig with no hooks — use for builders that need no callbacks
979
+ // (e.g. AWS aggregate builders that route via AggregateRuntimeBuilder instead).
980
+ module NoopHooksConfig: HooksConfig = {
981
+ let hooks = noHooks
982
+ }
983
+
984
+ // Derive admin-prefixed mutation field names from each aggregate's command schema,
985
+ // drop @noApi variants, register them into aggregateMutationFieldsRegistry (consumed
986
+ // by CommandGenerator_Builder.connect to wire AppSync resolvers in the auto-flow)
987
+ // and fire `mutationResolverHook` so adapter-side SDL stubs get registered
988
+ // synchronously. The matching `mutationSchemaEntry` records — needed to keep the
989
+ // SDL aligned — live in `PluginBaseFragment.pluginAggregateMutationEntries` so the
990
+ // AWS path (which pushes `AdminApi.baseFragment` directly, not Admin.construct's
991
+ // adminFragment) picks them up too. This helper is side-effect only.
992
+ let registerAdminAggregateMutations = (
993
+ type a,
994
+ aggregates: array<module(ReventlessInfra.Aggregate.T with type api = a)>,
995
+ ~hooks: platformHooks,
996
+ ): unit =>
997
+ aggregates->Array.forEach((module(M: ReventlessInfra.Aggregate.T with type api = a)) => {
998
+ let commandSchema = M.Spec.commandSchema->S.castToUnknown
999
+ if ApiNoApiHelpers.isNoApi(commandSchema) {
1000
+ ()
1001
+ } else {
1002
+ let constructorNames = Reventless.DcbTag.extractAllVariantNames(M.Spec.commandSchema)
1003
+ let filteredConstructorNames =
1004
+ ApiNoApiHelpers.filterNoApiVariants(constructorNames, commandSchema)
1005
+ let fieldNames =
1006
+ filteredConstructorNames->Array.map(cname =>
1007
+ Api_Naming.adminField(~name=M.Spec.name ++ "_" ++ cname)
1008
+ )
1009
+ aggregateMutationFieldsRegistry->Dict.set(M.Spec.name, fieldNames)
1010
+ if fieldNames->Array.length > 0 {
1011
+ hooks.mutationResolverHook->Option.forEach(registerResolver =>
1012
+ registerResolver(
1013
+ ~kind=Aggregate,
1014
+ ~fields=fieldNames,
1015
+ ~commandSchema,
1016
+ ~commandAuthorization=M.Spec.commandAuthorization->Obj.magic,
1017
+ )
1018
+ )
1019
+ }
1020
+ }
1021
+ })
1022
+
1023
+ // ---------------------------------------------------------------------------
1024
+ // Interop metadata — computed from builderOutputs at deploy time and stored so
1025
+ // that the plugin's entry-point module can export it as `_interopMeta`.
1026
+ // ---------------------------------------------------------------------------
1027
+
1028
+ // Module-level ref; follows the same mutable-state pattern as `tasksOutputs`
1029
+ // above. Set by Plugin_Builder during construct(); read by user entry-point
1030
+ // code via `getInteropMeta()`.
1031
+ // IMPORTANT: Do NOT use option<Pulumi.Output.t<_>> here. Pulumi.Output.t is a
1032
+ // JavaScript Proxy. ReScript's Caml_option.some() checks for BS_PRIVATE_NESTED_SOME_NONE
1033
+ // on the value — the Proxy intercepts that property access and returns a truthy value,
1034
+ // causing some() to produce the sentinel object {BS_PRIVATE_NESTED_SOME_NONE: 0}
1035
+ // instead of wrapping the actual Output. Use a raw JS null ref to avoid option wrapping.
1036
+ let interopMetaOutput: ref<Pulumi.Output.t<JSON.t>> = ref(%raw(`null`))
1037
+
1038
+ // Derive a field-name union across all tasks (field names present in at least
1039
+ // one task's serialized resolvedOutputs). Optional fields only appear in the
1040
+ // union when they are Some in the source Task.outputs record.
1041
+ let taskFieldUnion = (tasks: dict<Task.outputs>): array<string> => {
1042
+ module SSet = Belt.Set.String
1043
+ tasks
1044
+ ->Dict.valuesToArray
1045
+ ->Array.reduce(SSet.empty, (acc, taskOutput) => {
1046
+ // Convert Task.outputs → Task.resolvedOutputs using placeholders for nested
1047
+ // Pulumi.Output.t values — we only need presence, not actual string content.
1048
+ // ReScript optional fields must be set to the inner type (not option<_>) in
1049
+ // record literals, so we use a switch to conditionally include them.
1050
+ let resolved: ReventlessInterop.Task.resolvedOutputs =
1051
+ switch (taskOutput.bucketNames, taskOutput.sideEffectSources) {
1052
+ | (None, None) => {name: taskOutput.name}
1053
+ | (Some(_), None) => {name: taskOutput.name, bucketNames: Dict.make()}
1054
+ | (None, Some(src)) => {name: taskOutput.name, sideEffectSources: src}
1055
+ | (Some(_), Some(src)) => {
1056
+ name: taskOutput.name,
1057
+ bucketNames: Dict.make(),
1058
+ sideEffectSources: src,
1059
+ }
1060
+ }
1061
+ ReventlessInterop.ExportMeta.fieldNamesOf(resolved, ReventlessInterop.Task.resolvedOutputsSchema)
1062
+ ->Array.reduce(acc, SSet.add)
1063
+ })
1064
+ ->SSet.toArray
1065
+ }
1066
+
1067
+ // Build an ExportMeta.t from builderOutputs. Called inside a Pulumi.Output.apply
1068
+ // so all top-level Output.t wrappers in builderOutputs are already resolved.
1069
+ // Nested Output.t values (e.g. inside Task.bucketNames dict values) are still
1070
+ // pending — we use placeholder detection (Some vs None) rather than unwrapping.
1071
+ let toInteropMeta = (outputs: builderOutputs): ReventlessInterop.ExportMeta.t => {
1072
+ // EventMapper field manifest uses minimum required fields (counter presence
1073
+ // cannot be checked without resolving inner Output.t — improved in later phase).
1074
+ let eventMapperMinimal: ReventlessInterop.EventMapper.resolvedOutputs = {
1075
+ name: "",
1076
+ eventCollector: {name: "", resources: []},
1077
+ }
1078
+
1079
+ {
1080
+ version: ReventlessInterop.ExportMeta.version,
1081
+ fields: Dict.fromArray([
1082
+ ("tasks", taskFieldUnion(outputs.tasks)),
1083
+ (
1084
+ "eventMappers",
1085
+ ReventlessInterop.ExportMeta.fieldNamesOf(
1086
+ eventMapperMinimal,
1087
+ ReventlessInterop.EventMapper.resolvedOutputsSchema,
1088
+ ),
1089
+ ),
1090
+ ]),
1091
+ }
1092
+ }
1093
+
1094
+ // Returns the computed interop meta Output. Call this from the plugin's entry-
1095
+ // point module and export the result as `let _interopMeta = getInteropMeta()`.
1096
+ let getInteropMeta = (): Pulumi.Output.t<JSON.t> => {
1097
+ let v = interopMetaOutput.contents
1098
+ // Use raw null check to avoid option wrapping of the Proxy value.
1099
+ if %raw(`v === null`) {
1100
+ JsError.throwWithMessage("getInteropMeta() called before Plugin_Builder.construct()")
1101
+ } else {
1102
+ v
1103
+ }
1104
+ }
1105
+
1106
+ // ---------------------------------------------------------------------------
1107
+ // Stack metadata export — environment, region, timestamp, actor, git SHA.
1108
+ // Called from both exportPluginOutputs and exportPlatformOutputs.
1109
+ // ---------------------------------------------------------------------------
1110
+ @val external processEnv: dict<string> = "process.env"
1111
+
1112
+ let exportDeploymentMetadata = () => {
1113
+ let metadata =
1114
+ [
1115
+ ("environment", Pulumi.Pulumi.getStackName()),
1116
+ ("region", Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region")->Option.getOr("unknown")),
1117
+ ("timestamp", Date.make()->Date.toISOString),
1118
+ ("gitSha", processEnv->Dict.get("GITHUB_SHA")->Option.getOr("unknown")),
1119
+ ("actor", processEnv->Dict.get("GITHUB_ACTOR")->Option.getOr("unknown")),
1120
+ ]
1121
+ ->Dict.fromArray
1122
+ Pulumi.Pulumi.export(
1123
+ "deploymentMetadata",
1124
+ metadata->Dict.mapValues(JSON.Encode.string)->JSON.Encode.object->Pulumi.Output.make,
1125
+ )
1126
+ }
1127
+
1128
+ // ---------------------------------------------------------------------------
1129
+ // Serialize individual component output dicts as top-level Pulumi stack exports.
1130
+ // Each component type gets its own export key (e.g. "aggregates", "readModels").
1131
+ // ---------------------------------------------------------------------------
1132
+
1133
+ // Serialize a plain dict of component outputs to JSON. Unlike serializeDictExport,
1134
+ // this does NOT wrap the dict in Pulumi.Output.make (which deeply resolves nested
1135
+ // Outputs and breaks toResolvedOutputs).
1136
+ let serializePlainDictExport = (
1137
+ dict: dict<'outputs>,
1138
+ toResolved: 'outputs => Pulumi.Output.t<'resolved>,
1139
+ schema: S.t<'resolved>,
1140
+ ): Pulumi.Output.t<JSON.t> =>
1141
+ dict
1142
+ ->Dict.toArray
1143
+ ->Array.map(((name, outputs)) =>
1144
+ outputs
1145
+ ->toResolved
1146
+ ->Pulumi.Output.apply(resolved => (
1147
+ name,
1148
+ resolved->S.reverseConvertToJsonOrThrow(schema),
1149
+ ))
1150
+ )
1151
+ ->Pulumi.Output.all
1152
+ ->Pulumi.Output.apply(pairs => pairs->Dict.fromArray->JSON.Encode.object)
1153
+
1154
+ let serializeDictExport = (
1155
+ dictOutput: Pulumi.Output.t<dict<'outputs>>,
1156
+ toResolved: 'outputs => Pulumi.Output.t<'resolved>,
1157
+ schema: S.t<'resolved>,
1158
+ ): Pulumi.Output.t<JSON.t> =>
1159
+ dictOutput->Pulumi.Output.flatMap(dict =>
1160
+ dict
1161
+ ->Dict.toArray
1162
+ ->Array.map(((name, outputs)) =>
1163
+ outputs
1164
+ ->toResolved
1165
+ ->Pulumi.Output.apply(resolved => (
1166
+ name,
1167
+ resolved->S.reverseConvertToJsonOrThrow(schema),
1168
+ ))
1169
+ )
1170
+ ->Pulumi.Output.all
1171
+ ->Pulumi.Output.apply(pairs => pairs->Dict.fromArray->JSON.Encode.object)
1172
+ )
1173
+
1174
+ // Serialize tasks dict to JSON array for the "tasks" stack export.
1175
+ let serializeTasksOutputs = (pluginOutputs: Plugin.outputs): Pulumi.Output.t<JSON.t> =>
1176
+ pluginOutputs.tasks->Pulumi.Output.flatMap(tasks =>
1177
+ tasks
1178
+ ->Dict.valuesToArray
1179
+ ->Array.map(task =>
1180
+ task
1181
+ ->Task.toResolvedOutputs
1182
+ ->Pulumi.Output.apply(resolved =>
1183
+ resolved->S.reverseConvertToJsonOrThrow(ReventlessInterop.Task.resolvedOutputsSchema)
1184
+ )
1185
+ )
1186
+ ->Pulumi.Output.all
1187
+ ->Pulumi.Output.apply(arr => arr->JSON.Encode.array)
1188
+ )
1189
+
1190
+ // Serialize event mappers from aggregates to JSON array for the "eventMappers" stack export.
1191
+ let serializeEventMappersOutputs = (pluginOutputs: Plugin.outputs): Pulumi.Output.t<JSON.t> =>
1192
+ pluginOutputs.aggregates->Pulumi.Output.flatMap(aggregates =>
1193
+ aggregates
1194
+ ->Dict.valuesToArray
1195
+ ->Array.filterMap((agg: Aggregate.outputs) =>
1196
+ agg.eventMapper->Option.map(eventMapperOutput =>
1197
+ eventMapperOutput->Pulumi.Output.flatMap(em =>
1198
+ em
1199
+ ->EventMapper.toResolvedOutputs
1200
+ ->Pulumi.Output.apply(resolved =>
1201
+ resolved->S.reverseConvertToJsonOrThrow(
1202
+ ReventlessInterop.EventMapper.resolvedOutputsSchema,
1203
+ )
1204
+ )
1205
+ )
1206
+ )
1207
+ )
1208
+ ->Pulumi.Output.all
1209
+ ->Pulumi.Output.apply(arr => arr->JSON.Encode.array)
1210
+ )
1211
+
1212
+ // Export platform admin component outputs as individual top-level Pulumi stack exports.
1213
+ // Follows the same serialization pattern as exportPluginOutputs.
1214
+ // Only exports non-empty component dicts to avoid cluttering stack output with empty values.
1215
+ let exportPlatformOutputs = (
1216
+ ~extensionPointsOutputs: Pulumi.Output.t<array<ExtensionPoint.outputs>>,
1217
+ ~aggregatesOutputs: dict<Aggregate.outputs>,
1218
+ ~readModelsOutputs: dict<ReadModel.outputs>,
1219
+ ~dcbEventLogOutputs: option<DcbEventLog.outputs>,
1220
+ ~stateChangeSlicesOutputs: dict<StateChangeSlice.outputs>,
1221
+ ~stateViewSlicesOutputs: dict<StateViewSlice.outputs>,
1222
+ ~automationSlicesOutputs: dict<AutomationSlice.outputs>,
1223
+ ~outboundTranslationSlicesOutputs: dict<OutboundTranslationSlice.outputs>,
1224
+ ~inboundTranslationSlicesOutputs: dict<InboundTranslationSlice.outputs>,
1225
+ ) => {
1226
+ // Stack metadata
1227
+ exportDeploymentMetadata()
1228
+
1229
+ // Extension points — always exported (the admin's primary component output)
1230
+ Pulumi.Pulumi.export(
1231
+ "extensionPoints",
1232
+ extensionPointsOutputs->Pulumi.Output.flatMap(eps =>
1233
+ eps
1234
+ ->Array.map(ep =>
1235
+ ep
1236
+ ->ExtensionPoint.toResolvedOutputs
1237
+ ->Pulumi.Output.apply(resolved => (
1238
+ ep.name,
1239
+ resolved->S.reverseConvertToJsonOrThrow(
1240
+ ReventlessInterop.ExtensionPoint.resolvedOutputsSchema,
1241
+ ),
1242
+ ))
1243
+ )
1244
+ ->Pulumi.Output.all
1245
+ ->Pulumi.Output.apply(pairs => pairs->Dict.fromArray->JSON.Encode.object)
1246
+ ),
1247
+ )
1248
+
1249
+ // Aggregates — only export if non-empty
1250
+ if aggregatesOutputs->Dict.keysToArray->Array.length > 0 {
1251
+ Pulumi.Pulumi.export(
1252
+ "aggregates",
1253
+ serializePlainDictExport(
1254
+ aggregatesOutputs,
1255
+ Aggregate.toResolvedOutputs,
1256
+ ReventlessInterop.Aggregate.resolvedOutputsSchema,
1257
+ ),
1258
+ )
1259
+ }
1260
+
1261
+ // ReadModels — only export if non-empty
1262
+ if readModelsOutputs->Dict.keysToArray->Array.length > 0 {
1263
+ Pulumi.Pulumi.export(
1264
+ "readModels",
1265
+ serializePlainDictExport(
1266
+ readModelsOutputs,
1267
+ ReadModel.toResolvedOutputs,
1268
+ ReventlessInterop.ReadModel.resolvedOutputsSchema,
1269
+ ),
1270
+ )
1271
+ }
1272
+
1273
+ // DCB event log — only export if present
1274
+ switch dcbEventLogOutputs {
1275
+ | Some(dcbOutputs) =>
1276
+ Pulumi.Pulumi.export(
1277
+ "dcbEventLog",
1278
+ dcbOutputs
1279
+ ->DcbEventLog.toResolvedOutputs
1280
+ ->Pulumi.Output.apply(resolved =>
1281
+ resolved->S.reverseConvertToJsonOrThrow(
1282
+ ReventlessInterop.DcbEventLog.resolvedOutputsSchema,
1283
+ )
1284
+ ),
1285
+ )
1286
+ | None => ()
1287
+ }
1288
+
1289
+ // DCB slices — only export non-empty dicts
1290
+ if stateChangeSlicesOutputs->Dict.keysToArray->Array.length > 0 {
1291
+ Pulumi.Pulumi.export(
1292
+ "stateChangeSlices",
1293
+ serializePlainDictExport(
1294
+ stateChangeSlicesOutputs,
1295
+ StateChangeSlice.toResolvedOutputs,
1296
+ ReventlessInterop.StateChangeSlice.resolvedOutputsSchema,
1297
+ ),
1298
+ )
1299
+ }
1300
+
1301
+ if stateViewSlicesOutputs->Dict.keysToArray->Array.length > 0 {
1302
+ Pulumi.Pulumi.export(
1303
+ "stateViewSlices",
1304
+ serializePlainDictExport(
1305
+ stateViewSlicesOutputs,
1306
+ StateViewSlice.toResolvedOutputs,
1307
+ ReventlessInterop.StateViewSlice.resolvedOutputsSchema,
1308
+ ),
1309
+ )
1310
+ }
1311
+
1312
+ if automationSlicesOutputs->Dict.keysToArray->Array.length > 0 {
1313
+ Pulumi.Pulumi.export(
1314
+ "automationSlices",
1315
+ serializePlainDictExport(
1316
+ automationSlicesOutputs,
1317
+ AutomationSlice.toResolvedOutputs,
1318
+ ReventlessInterop.AutomationSlice.resolvedOutputsSchema,
1319
+ ),
1320
+ )
1321
+ }
1322
+
1323
+ if outboundTranslationSlicesOutputs->Dict.keysToArray->Array.length > 0 {
1324
+ Pulumi.Pulumi.export(
1325
+ "outboundTranslationSlices",
1326
+ serializePlainDictExport(
1327
+ outboundTranslationSlicesOutputs,
1328
+ OutboundTranslationSlice.toResolvedOutputs,
1329
+ ReventlessInterop.OutboundTranslationSlice.resolvedOutputsSchema,
1330
+ ),
1331
+ )
1332
+ }
1333
+
1334
+ if inboundTranslationSlicesOutputs->Dict.keysToArray->Array.length > 0 {
1335
+ Pulumi.Pulumi.export(
1336
+ "inboundTranslationSlices",
1337
+ serializePlainDictExport(
1338
+ inboundTranslationSlicesOutputs,
1339
+ InboundTranslationSlice.toResolvedOutputs,
1340
+ ReventlessInterop.InboundTranslationSlice.resolvedOutputsSchema,
1341
+ ),
1342
+ )
1343
+ }
1344
+ }
1345
+
1346
+ // Export all plugin outputs as individual top-level Pulumi stack exports.
1347
+ // Each component type is its own export key for flat, readable `pulumi stack output`.
1348
+ let exportPluginOutputs = (pluginOutputs: Plugin.outputs) => {
1349
+ // Stack metadata
1350
+ exportDeploymentMetadata()
1351
+
1352
+ // Scalar fields
1353
+ Pulumi.Pulumi.export("id", pluginOutputs.id->Pulumi.Output.apply(v => v->JSON.Encode.string))
1354
+ Pulumi.Pulumi.export(
1355
+ "version",
1356
+ pluginOutputs.version->Pulumi.Output.apply(v => v->JSON.Encode.string),
1357
+ )
1358
+
1359
+ // Component dicts
1360
+ Pulumi.Pulumi.export(
1361
+ "aggregates",
1362
+ serializeDictExport(
1363
+ pluginOutputs.aggregates,
1364
+ Aggregate.toResolvedOutputs,
1365
+ ReventlessInterop.Aggregate.resolvedOutputsSchema,
1366
+ ),
1367
+ )
1368
+ Pulumi.Pulumi.export(
1369
+ "readModels",
1370
+ serializeDictExport(
1371
+ pluginOutputs.readModels,
1372
+ ReadModel.toResolvedOutputs,
1373
+ ReventlessInterop.ReadModel.resolvedOutputsSchema,
1374
+ ),
1375
+ )
1376
+ Pulumi.Pulumi.export(
1377
+ "extensionPoints",
1378
+ serializeDictExport(
1379
+ pluginOutputs.extensionPoints,
1380
+ ExtensionPoint.toResolvedOutputs,
1381
+ ReventlessInterop.ExtensionPoint.resolvedOutputsSchema,
1382
+ ),
1383
+ )
1384
+ Pulumi.Pulumi.export(
1385
+ "stateChangeSlices",
1386
+ serializeDictExport(
1387
+ pluginOutputs.stateChangeSlices,
1388
+ StateChangeSlice.toResolvedOutputs,
1389
+ ReventlessInterop.StateChangeSlice.resolvedOutputsSchema,
1390
+ ),
1391
+ )
1392
+ Pulumi.Pulumi.export(
1393
+ "stateViewSlices",
1394
+ serializeDictExport(
1395
+ pluginOutputs.stateViewSlices,
1396
+ StateViewSlice.toResolvedOutputs,
1397
+ ReventlessInterop.StateViewSlice.resolvedOutputsSchema,
1398
+ ),
1399
+ )
1400
+ Pulumi.Pulumi.export(
1401
+ "automationSlices",
1402
+ serializeDictExport(
1403
+ pluginOutputs.automationSlices,
1404
+ AutomationSlice.toResolvedOutputs,
1405
+ ReventlessInterop.AutomationSlice.resolvedOutputsSchema,
1406
+ ),
1407
+ )
1408
+ Pulumi.Pulumi.export(
1409
+ "outboundTranslationSlices",
1410
+ serializeDictExport(
1411
+ pluginOutputs.outboundTranslationSlices,
1412
+ OutboundTranslationSlice.toResolvedOutputs,
1413
+ ReventlessInterop.OutboundTranslationSlice.resolvedOutputsSchema,
1414
+ ),
1415
+ )
1416
+ Pulumi.Pulumi.export(
1417
+ "inboundTranslationSlices",
1418
+ serializeDictExport(
1419
+ pluginOutputs.inboundTranslationSlices,
1420
+ InboundTranslationSlice.toResolvedOutputs,
1421
+ ReventlessInterop.InboundTranslationSlice.resolvedOutputsSchema,
1422
+ ),
1423
+ )
1424
+
1425
+ // DCB event log — single optional value
1426
+ Pulumi.Pulumi.export(
1427
+ "dcbEventLog",
1428
+ pluginOutputs.dcbEventLog->Pulumi.Output.flatMap(opt =>
1429
+ switch opt {
1430
+ | Some(dcbOutputs) =>
1431
+ dcbOutputs
1432
+ ->DcbEventLog.toResolvedOutputs
1433
+ ->Pulumi.Output.apply(resolved =>
1434
+ resolved->S.reverseConvertToJsonOrThrow(
1435
+ ReventlessInterop.DcbEventLog.resolvedOutputsSchema,
1436
+ )
1437
+ )
1438
+ | None => Pulumi.Output.make(Obj.magic(JSON.Encode.null))
1439
+ }
1440
+ ),
1441
+ )
1442
+
1443
+ // Array exports
1444
+ Pulumi.Pulumi.export("tasks", serializeTasksOutputs(pluginOutputs))
1445
+ Pulumi.Pulumi.export("eventMappers", serializeEventMappersOutputs(pluginOutputs))
1446
+
1447
+ // Fire onPluginDeployed hook with fully resolved resource data.
1448
+ switch onPluginDeployedHook.contents {
1449
+ | Some(hook) =>
1450
+ // Read deployment provenance from env vars synchronously (before Output.apply).
1451
+ let actor =
1452
+ processEnv
1453
+ ->Dict.get("GITHUB_ACTOR")
1454
+ ->Option.orElse(processEnv->Dict.get("CI_COMMIT_AUTHOR"))
1455
+ ->Option.orElse(processEnv->Dict.get("USER"))
1456
+ ->Option.getOr("local")
1457
+ let deploymentId =
1458
+ processEnv
1459
+ ->Dict.get("GITHUB_SHA")
1460
+ ->Option.orElse(processEnv->Dict.get("CI_COMMIT_SHA"))
1461
+ ->Option.getOr(Date.make()->Date.toISOString)
1462
+ let schemaFor = name =>
1463
+ componentSchemaRegistry->Dict.get(name)->Option.getOr({})
1464
+ let resolveAggregates = pluginOutputs.aggregates->Pulumi.Output.flatMap(aggs =>
1465
+ aggs
1466
+ ->Dict.toArray
1467
+ ->Array.map(((name, outputs)) =>
1468
+ outputs
1469
+ ->Aggregate.toResolvedOutputs
1470
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.Aggregate.resolvedOutputs) => {
1471
+ let component: pluginDeployedComponent = {
1472
+ name,
1473
+ kind: "Aggregate",
1474
+ schema: schemaFor(name),
1475
+ resources: [],
1476
+ subComponents: [
1477
+ {role: "commandGenerator", resources: resolved.commandGenerator.resources},
1478
+ {role: "commandTopic", resources: resolved.commandTopic.resources},
1479
+ {role: "eventLog", resources: resolved.eventLog.resources},
1480
+ {role: "eventTopic", resources: resolved.eventLog.eventTopic.resources},
1481
+ ],
1482
+ }
1483
+ component
1484
+ })
1485
+ )
1486
+ ->Pulumi.Output.all
1487
+ )
1488
+
1489
+ let resolveReadModels = pluginOutputs.readModels->Pulumi.Output.flatMap(rms =>
1490
+ rms
1491
+ ->Dict.toArray
1492
+ ->Array.map(((name, outputs)) =>
1493
+ outputs
1494
+ ->ReadModel.toResolvedOutputs
1495
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.ReadModel.resolvedOutputs) => {
1496
+ let component: pluginDeployedComponent = {
1497
+ name,
1498
+ kind: "ReadModel",
1499
+ schema: schemaFor(name),
1500
+ resources: [],
1501
+ subComponents: [{role: "queryDb", resources: resolved.queryDb.resources}],
1502
+ }
1503
+ component
1504
+ })
1505
+ )
1506
+ ->Pulumi.Output.all
1507
+ )
1508
+
1509
+ let resolveExtensionPoints = pluginOutputs.extensionPoints->Pulumi.Output.flatMap(eps =>
1510
+ eps
1511
+ ->Dict.toArray
1512
+ ->Array.map(((name, outputs)) =>
1513
+ outputs
1514
+ ->ExtensionPoint.toResolvedOutputs
1515
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.ExtensionPoint.resolvedOutputs) => {
1516
+ let component: pluginDeployedComponent = {
1517
+ name,
1518
+ kind: "ExtensionPoint",
1519
+ schema: schemaFor(name),
1520
+ resources: [],
1521
+ subComponents: [
1522
+ {role: "commandTopic", resources: resolved.commandTopic.resources},
1523
+ {role: "eventTopic", resources: resolved.eventTopic.resources},
1524
+ ],
1525
+ }
1526
+ component
1527
+ })
1528
+ )
1529
+ ->Pulumi.Output.all
1530
+ )
1531
+
1532
+ let resolveStateChangeSlices = pluginOutputs.stateChangeSlices->Pulumi.Output.flatMap(slices =>
1533
+ slices
1534
+ ->Dict.toArray
1535
+ ->Array.map(((name, outputs)) =>
1536
+ outputs
1537
+ ->StateChangeSlice.toResolvedOutputs
1538
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.StateChangeSlice.resolvedOutputs) => {
1539
+ let component: pluginDeployedComponent = {
1540
+ name,
1541
+ kind: "StateChangeSlice",
1542
+ schema: schemaFor(name),
1543
+ resources: resolved.resources,
1544
+ subComponents: [],
1545
+ }
1546
+ component
1547
+ })
1548
+ )
1549
+ ->Pulumi.Output.all
1550
+ )
1551
+
1552
+ let resolveStateViewSlices = pluginOutputs.stateViewSlices->Pulumi.Output.flatMap(slices =>
1553
+ slices
1554
+ ->Dict.toArray
1555
+ ->Array.map(((name, outputs)) =>
1556
+ outputs
1557
+ ->StateViewSlice.toResolvedOutputs
1558
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.StateViewSlice.resolvedOutputs) => {
1559
+ let component: pluginDeployedComponent = {
1560
+ name,
1561
+ kind: "StateViewSlice",
1562
+ schema: schemaFor(name),
1563
+ resources: resolved.resources,
1564
+ subComponents: [{role: "queryDb", resources: resolved.queryDb.resources}],
1565
+ }
1566
+ component
1567
+ })
1568
+ )
1569
+ ->Pulumi.Output.all
1570
+ )
1571
+
1572
+ let resolveAutomationSlices = pluginOutputs.automationSlices->Pulumi.Output.flatMap(slices =>
1573
+ slices
1574
+ ->Dict.toArray
1575
+ ->Array.map(((name, outputs)) =>
1576
+ outputs
1577
+ ->AutomationSlice.toResolvedOutputs
1578
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.AutomationSlice.resolvedOutputs) => {
1579
+ let component: pluginDeployedComponent = {
1580
+ name,
1581
+ kind: "AutomationSlice",
1582
+ schema: schemaFor(name),
1583
+ resources: resolved.resources,
1584
+ subComponents: [{role: "queryDb", resources: resolved.queryDb.resources}],
1585
+ }
1586
+ component
1587
+ })
1588
+ )
1589
+ ->Pulumi.Output.all
1590
+ )
1591
+
1592
+ let resolveOutboundTranslationSlices =
1593
+ pluginOutputs.outboundTranslationSlices->Pulumi.Output.flatMap(slices =>
1594
+ slices
1595
+ ->Dict.toArray
1596
+ ->Array.map(((name, outputs)) =>
1597
+ outputs
1598
+ ->OutboundTranslationSlice.toResolvedOutputs
1599
+ ->Pulumi.Output.apply(
1600
+ (resolved: ReventlessInterop.OutboundTranslationSlice.resolvedOutputs) => {
1601
+ let component: pluginDeployedComponent = {
1602
+ name,
1603
+ kind: "OutboundTranslationSlice",
1604
+ schema: schemaFor(name),
1605
+ resources: resolved.resources,
1606
+ subComponents: [{role: "queryDb", resources: resolved.queryDb.resources}],
1607
+ }
1608
+ component
1609
+ },
1610
+ )
1611
+ )
1612
+ ->Pulumi.Output.all
1613
+ )
1614
+
1615
+ let resolveInboundTranslationSlices =
1616
+ pluginOutputs.inboundTranslationSlices->Pulumi.Output.flatMap(slices =>
1617
+ slices
1618
+ ->Dict.toArray
1619
+ ->Array.map(((name, outputs)) =>
1620
+ outputs
1621
+ ->InboundTranslationSlice.toResolvedOutputs
1622
+ ->Pulumi.Output.apply(
1623
+ (resolved: ReventlessInterop.InboundTranslationSlice.resolvedOutputs) => {
1624
+ let component: pluginDeployedComponent = {
1625
+ name,
1626
+ kind: "InboundTranslationSlice",
1627
+ schema: schemaFor(name),
1628
+ resources: resolved.resources,
1629
+ subComponents: [{role: "queryDb", resources: resolved.queryDb.resources}],
1630
+ }
1631
+ component
1632
+ },
1633
+ )
1634
+ )
1635
+ ->Pulumi.Output.all
1636
+ )
1637
+
1638
+ let resolveDcbEventLog = pluginOutputs.dcbEventLog->Pulumi.Output.flatMap(opt =>
1639
+ switch opt {
1640
+ | Some(outputs) =>
1641
+ outputs
1642
+ ->DcbEventLog.toResolvedOutputs
1643
+ ->Pulumi.Output.apply((resolved: ReventlessInterop.DcbEventLog.resolvedOutputs) => {
1644
+ let component: pluginDeployedComponent = {
1645
+ name: "DcbEventLog",
1646
+ kind: "DcbEventLog",
1647
+ schema: schemaFor("DcbEventLog"),
1648
+ resources: resolved.resources,
1649
+ subComponents: [{role: "eventTopic", resources: resolved.eventTopic.resources}],
1650
+ }
1651
+ [component]
1652
+ })
1653
+ | None => Pulumi.Output.make([])
1654
+ }
1655
+ )
1656
+
1657
+ // Resolve extension wiring metadata.
1658
+ let resolveExtensionWirings = pluginOutputs.extensions->Pulumi.Output.flatMap(exts =>
1659
+ pluginOutputs.id->Pulumi.Output.apply(id => {
1660
+ let pluginName = id->String.split("@")->Array.getUnsafe(0)
1661
+ let pluginVersion = id->String.split("@")->Array.getUnsafe(1)
1662
+ exts
1663
+ ->Dict.valuesToArray
1664
+ ->Array.map((ext: ReventlessInfra.Extension.outputs) => {
1665
+ // Derive provider plugin name from the extension point name
1666
+ // (e.g. "Catalog.Products" → "Catalog").
1667
+ let providerPlugin =
1668
+ ext.extensionPointName->String.split(".")->Array.getUnsafe(0)
1669
+ let wiring: extensionWiring = {
1670
+ extensionName: ext.name,
1671
+ extensionPointName: ext.extensionPointName,
1672
+ providerPlugin,
1673
+ providerVersion: "",
1674
+ subscriberPlugin: pluginName,
1675
+ subscriberVersion: pluginVersion,
1676
+ }
1677
+ wiring
1678
+ })
1679
+ })
1680
+ )
1681
+
1682
+ // Collect all resolved components, fire the hook, and export the resulting
1683
+ // Output<unit> at top level so Pulumi blocks on the hook's Promise.
1684
+ let hookOutput =
1685
+ (
1686
+ pluginOutputs.id,
1687
+ pluginOutputs.version,
1688
+ resolveAggregates,
1689
+ resolveReadModels,
1690
+ resolveExtensionPoints,
1691
+ resolveStateChangeSlices,
1692
+ )
1693
+ ->Pulumi.Output.all6
1694
+ ->Pulumi.Output.flatMap(((id, version, aggs, rms, eps, scs)) =>
1695
+ (
1696
+ resolveStateViewSlices,
1697
+ resolveAutomationSlices,
1698
+ resolveOutboundTranslationSlices,
1699
+ resolveInboundTranslationSlices,
1700
+ resolveDcbEventLog,
1701
+ resolveExtensionWirings,
1702
+ )
1703
+ ->Pulumi.Output.all6
1704
+ ->Pulumi.Output.apply(((svs, autos, ots, its, dcb, wirings)) => {
1705
+ let name = id->String.split("@")->Array.getUnsafe(0)
1706
+ let meta = pluginMetadataRegistry.contents
1707
+ let info: pluginDeployedInfo = {
1708
+ name,
1709
+ version,
1710
+ environment: Pulumi.Pulumi.getStackName(),
1711
+ stackName: Pulumi.Pulumi.getStackName(),
1712
+ deployedAt: Date.make()->Date.toISOString,
1713
+ actor,
1714
+ deploymentId,
1715
+ kind: ?meta->Option.flatMap(m => m.kind),
1716
+ displayName: ?meta->Option.flatMap(m => m.displayName),
1717
+ vendor: ?meta->Option.flatMap(m => m.vendor),
1718
+ architectureType: ?meta->Option.flatMap(m => m.architectureType),
1719
+ components: Array.flat([aggs, rms, eps, scs, svs, autos, ots, its, dcb]),
1720
+ extensionWirings: wirings,
1721
+ }
1722
+ hook(info)
1723
+ })
1724
+ )
1725
+ ->Pulumi.Output.flatMap(p => p->Pulumi.Output.fromPromise)
1726
+
1727
+ Pulumi.Pulumi.export("_pluginDeployedSync", hookOutput)
1728
+ | None => ()
1729
+ }
1730
+ }