@reventlessdev/reventless-aws 3.0.0-alpha.167

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 (394) hide show
  1. package/CHANGELOG.md +1564 -0
  2. package/README.md +62 -0
  3. package/__mocks__/emptyModule.js +1 -0
  4. package/all-licenses.csv +565 -0
  5. package/docker-compose.dynamodb-local.yml +12 -0
  6. package/jest.setup.cjs +5 -0
  7. package/licenses-analysis.ods +0 -0
  8. package/package.json +73 -0
  9. package/rescript.json +39 -0
  10. package/reventless-licenses-analysis.xls +0 -0
  11. package/scripts/run-integration-tests.sh +43 -0
  12. package/src/Platform.res +1940 -0
  13. package/src/Platform.res.mjs +2281 -0
  14. package/src/Platform_Casts.res +106 -0
  15. package/src/Platform_Casts.res.mjs +13 -0
  16. package/src/Platform_Stack.res +153 -0
  17. package/src/Platform_Stack.res.mjs +121 -0
  18. package/src/Types.res +39 -0
  19. package/src/Types.res.mjs +21 -0
  20. package/src/adapter/AWS.res +96 -0
  21. package/src/adapter/AWS.res.mjs +186 -0
  22. package/src/adapter/AWS_Tags.res +16 -0
  23. package/src/adapter/AWS_Tags.res.mjs +48 -0
  24. package/src/adapter/Adapter_Helpers.res +19 -0
  25. package/src/adapter/Adapter_Helpers.res.mjs +37 -0
  26. package/src/adapter/Api/AppSync_EventsApi.res +172 -0
  27. package/src/adapter/Api/AppSync_EventsApi.res.mjs +96 -0
  28. package/src/adapter/Api/AppSync_Resolver_Native.res +93 -0
  29. package/src/adapter/Api/AppSync_Resolver_Native.res.mjs +67 -0
  30. package/src/adapter/Api/AppSync_Resolver_Retrying.res +653 -0
  31. package/src/adapter/Api/AppSync_Resolver_Retrying.res.mjs +462 -0
  32. package/src/adapter/Api/CommandSubscriptionResolvers_AppSync.res +29 -0
  33. package/src/adapter/Api/CommandSubscriptionResolvers_AppSync.res.mjs +15 -0
  34. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +238 -0
  35. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +179 -0
  36. package/src/adapter/Api/Platform_UIFragments_Lambda.res +229 -0
  37. package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +245 -0
  38. package/src/adapter/Auth/Auth_Cognito.res +209 -0
  39. package/src/adapter/Auth/Auth_Cognito.res.mjs +135 -0
  40. package/src/adapter/CommandGenerator/CommandGeneratorResolvers.res +2 -0
  41. package/src/adapter/CommandGenerator/CommandGeneratorResolvers.res.mjs +12 -0
  42. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +251 -0
  43. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res.mjs +126 -0
  44. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +20 -0
  45. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res.mjs +23 -0
  46. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_Runtime.res +1 -0
  47. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_Runtime.res.mjs +11 -0
  48. package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +95 -0
  49. package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res.mjs +50 -0
  50. package/src/adapter/CommandTopic/CommandTopicChannel.res +6 -0
  51. package/src/adapter/CommandTopic/CommandTopicChannel.res.mjs +21 -0
  52. package/src/adapter/CommandTopic/CommandTopicChannel_Helpers.res +196 -0
  53. package/src/adapter/CommandTopic/CommandTopicChannel_Helpers.res.mjs +145 -0
  54. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +91 -0
  55. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res.mjs +74 -0
  56. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +69 -0
  57. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res.mjs +62 -0
  58. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +60 -0
  59. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res.mjs +56 -0
  60. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +73 -0
  61. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs +65 -0
  62. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +88 -0
  63. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res.mjs +76 -0
  64. package/src/adapter/CommandTopic/CommandTopicRemoteChannel.res +1 -0
  65. package/src/adapter/CommandTopic/CommandTopicRemoteChannel.res.mjs +9 -0
  66. package/src/adapter/CommandTopic/CommandTopicRemoteChannel_SQS.res +7 -0
  67. package/src/adapter/CommandTopic/CommandTopicRemoteChannel_SQS.res.mjs +17 -0
  68. package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +103 -0
  69. package/src/adapter/Counter/CounterHandler_DynamoDbStream.res.mjs +68 -0
  70. package/src/adapter/Counter/CounterHandler_DynamoDbStream_Runtime.res +107 -0
  71. package/src/adapter/Counter/CounterHandler_DynamoDbStream_Runtime.res.mjs +145 -0
  72. package/src/adapter/DcbEventLog/DcbEventLogStorage.res +1 -0
  73. package/src/adapter/DcbEventLog/DcbEventLogStorage.res.mjs +9 -0
  74. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +84 -0
  75. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res.mjs +52 -0
  76. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +1436 -0
  77. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +1143 -0
  78. package/src/adapter/EventCollector/EventCollectorChannel.res +6 -0
  79. package/src/adapter/EventCollector/EventCollectorChannel.res.mjs +21 -0
  80. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +63 -0
  81. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res.mjs +56 -0
  82. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream_Runtime.res +20 -0
  83. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream_Runtime.res.mjs +32 -0
  84. package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +266 -0
  85. package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res.mjs +166 -0
  86. package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +81 -0
  87. package/src/adapter/EventCollector/EventCollectorChannel_SQS.res.mjs +54 -0
  88. package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +59 -0
  89. package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res.mjs +45 -0
  90. package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +91 -0
  91. package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res.mjs +89 -0
  92. package/src/adapter/EventLog/EventLogStorage.res +3 -0
  93. package/src/adapter/EventLog/EventLogStorage.res.mjs +15 -0
  94. package/src/adapter/EventLog/EventLogStorage_DynamoDb.res +25 -0
  95. package/src/adapter/EventLog/EventLogStorage_DynamoDb.res.mjs +34 -0
  96. package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +26 -0
  97. package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res.mjs +35 -0
  98. package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +121 -0
  99. package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res.mjs +137 -0
  100. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +265 -0
  101. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +185 -0
  102. package/src/adapter/EventTopic/EventTopicPublisher.res +6 -0
  103. package/src/adapter/EventTopic/EventTopicPublisher.res.mjs +21 -0
  104. package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +25 -0
  105. package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res.mjs +28 -0
  106. package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +40 -0
  107. package/src/adapter/EventTopic/EventTopicPublisher_SNS.res.mjs +39 -0
  108. package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +39 -0
  109. package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res.mjs +38 -0
  110. package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -0
  111. package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res.mjs +18 -0
  112. package/src/adapter/Mcp/MCP_Lambda.res +502 -0
  113. package/src/adapter/Mcp/MCP_Lambda.res.mjs +289 -0
  114. package/src/adapter/QueryDb/NodeResolver_AppSync.res +71 -0
  115. package/src/adapter/QueryDb/NodeResolver_AppSync.res.mjs +44 -0
  116. package/src/adapter/QueryDb/QueryDbResolvers.res +2 -0
  117. package/src/adapter/QueryDb/QueryDbResolvers.res.mjs +12 -0
  118. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +434 -0
  119. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res.mjs +243 -0
  120. package/src/adapter/QueryDb/QueryDbResolvers_AppSync_NoOp.res +21 -0
  121. package/src/adapter/QueryDb/QueryDbResolvers_AppSync_NoOp.res.mjs +14 -0
  122. package/src/adapter/QueryDb/QueryDbResolvers_NoOp.res +21 -0
  123. package/src/adapter/QueryDb/QueryDbResolvers_NoOp.res.mjs +14 -0
  124. package/src/adapter/QueryDb/QueryDbStorage.res +5 -0
  125. package/src/adapter/QueryDb/QueryDbStorage.res.mjs +18 -0
  126. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +115 -0
  127. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res.mjs +100 -0
  128. package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +52 -0
  129. package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res.mjs +38 -0
  130. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +271 -0
  131. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res.mjs +306 -0
  132. package/src/adapter/QueryDb/QueryInterceptor_Lambda.res +20 -0
  133. package/src/adapter/QueryDb/QueryInterceptor_Lambda.res.mjs +22 -0
  134. package/src/adapter/QueryEngine/QueryEngine.res +3 -0
  135. package/src/adapter/QueryEngine/QueryEngine.res.mjs +12 -0
  136. package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +184 -0
  137. package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res.mjs +221 -0
  138. package/src/adapter/Runtime/AdminEventCollectorEntryPoint.mjs +879 -0
  139. package/src/adapter/Runtime/AggregateEntryPoint.mjs +313 -0
  140. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +327 -0
  141. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res.mjs +239 -0
  142. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +331 -0
  143. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res.mjs +240 -0
  144. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +247 -0
  145. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res.mjs +185 -0
  146. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +244 -0
  147. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res.mjs +185 -0
  148. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +347 -0
  149. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res.mjs +244 -0
  150. package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +285 -0
  151. package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res.mjs +212 -0
  152. package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +124 -0
  153. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +187 -0
  154. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +147 -0
  155. package/src/adapter/Runtime/CounterEntryPoint.mjs +91 -0
  156. package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +265 -0
  157. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +122 -0
  158. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res.mjs +89 -0
  159. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +193 -0
  160. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res.mjs +137 -0
  161. package/src/adapter/Runtime/EventMapperEntryPoint.mjs +97 -0
  162. package/src/adapter/Runtime/ExtensionPointEntryPoint.mjs +101 -0
  163. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +83 -0
  164. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res.mjs +59 -0
  165. package/src/adapter/Runtime/HandlerFactoryHelpers.mjs +142 -0
  166. package/src/adapter/Runtime/HeartbeatEntryPoint.mjs +38 -0
  167. package/src/adapter/Runtime/PluginExtensionPointEntryPoint.mjs +137 -0
  168. package/src/adapter/Runtime/ReadModelEntryPoint.mjs +143 -0
  169. package/src/adapter/Runtime/RuntimeEnvironment.res +1 -0
  170. package/src/adapter/Runtime/RuntimeEnvironment.res.mjs +9 -0
  171. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +254 -0
  172. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +169 -0
  173. package/src/adapter/Runtime/SideEffectEntryPoint.mjs +81 -0
  174. package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +178 -0
  175. package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res.mjs +129 -0
  176. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +166 -0
  177. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res.mjs +87 -0
  178. package/src/adapter/Runtime/StateViewSliceEntryPoint.mjs +136 -0
  179. package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +344 -0
  180. package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res.mjs +242 -0
  181. package/src/adapter/Runtime/TaskBucketEntryPoint.mjs +150 -0
  182. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +123 -0
  183. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res.mjs +74 -0
  184. package/src/adapter/ScheduledPublisher/ScheduledPublisher.res +2 -0
  185. package/src/adapter/ScheduledPublisher/ScheduledPublisher.res.mjs +12 -0
  186. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +54 -0
  187. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res.mjs +41 -0
  188. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +97 -0
  189. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res.mjs +85 -0
  190. package/src/adapter/StateTopic/StateTopic_AppSync.res +418 -0
  191. package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +295 -0
  192. package/src/adapter/Task/TaskBucket.res +1 -0
  193. package/src/adapter/Task/TaskBucket.res.mjs +9 -0
  194. package/src/adapter/Task/TaskBucket_S3.res +157 -0
  195. package/src/adapter/Task/TaskBucket_S3.res.mjs +108 -0
  196. package/src/adapter/Task/TaskBucket_S3_Runtime.res +11 -0
  197. package/src/adapter/Task/TaskBucket_S3_Runtime.res.mjs +15 -0
  198. package/src/components/Aggregate_Builder.res +1 -0
  199. package/src/components/Aggregate_Builder.res.mjs +25 -0
  200. package/src/components/Aggregate_Builder_Micro.res +63 -0
  201. package/src/components/Aggregate_Builder_Micro.res.mjs +80 -0
  202. package/src/components/Aggregate_Builder_NoResolver.res +61 -0
  203. package/src/components/Aggregate_Builder_NoResolver.res.mjs +80 -0
  204. package/src/components/Aggregate_Builder_PerAggregate.res +57 -0
  205. package/src/components/Aggregate_Builder_PerAggregate.res.mjs +80 -0
  206. package/src/components/Aggregate_Builder_Single.res +59 -0
  207. package/src/components/Aggregate_Builder_Single.res.mjs +80 -0
  208. package/src/components/Aggregate_Builder_Single_Async.res +59 -0
  209. package/src/components/Aggregate_Builder_Single_Async.res.mjs +80 -0
  210. package/src/components/Api/AppSync_Adapter.res +500 -0
  211. package/src/components/Api/AppSync_Adapter.res.mjs +396 -0
  212. package/src/components/AutomationSlice_Builder.res +52 -0
  213. package/src/components/AutomationSlice_Builder.res.mjs +72 -0
  214. package/src/components/AutomationSlice_Builder_Bundled.res.mjs +70 -0
  215. package/src/components/Counter_Builder.res +10 -0
  216. package/src/components/Counter_Builder.res.mjs +16 -0
  217. package/src/components/DataCleaner.res +170 -0
  218. package/src/components/DataCleaner.res.mjs +2 -0
  219. package/src/components/DcbEventLog_Builder.res +8 -0
  220. package/src/components/DcbEventLog_Builder.res.mjs +14 -0
  221. package/src/components/ExtensionPoint_Builder.res +16 -0
  222. package/src/components/ExtensionPoint_Builder.res.mjs +37 -0
  223. package/src/components/ForeignReadModel_Builder.res +19 -0
  224. package/src/components/ForeignReadModel_Builder.res.mjs +48 -0
  225. package/src/components/InboundTranslationSlice_Builder.res +25 -0
  226. package/src/components/InboundTranslationSlice_Builder.res.mjs +31 -0
  227. package/src/components/OutboundTranslationSlice_Builder.res +60 -0
  228. package/src/components/OutboundTranslationSlice_Builder.res.mjs +76 -0
  229. package/src/components/OutboundTranslationSlice_Builder_Bundled.res.mjs +75 -0
  230. package/src/components/Plugin.res +29 -0
  231. package/src/components/Plugin.res.mjs +63 -0
  232. package/src/components/ReadModel_Builder.res +1 -0
  233. package/src/components/ReadModel_Builder.res.mjs +19 -0
  234. package/src/components/ReadModel_Builder_NoResolver.res +55 -0
  235. package/src/components/ReadModel_Builder_NoResolver.res.mjs +64 -0
  236. package/src/components/ReadModel_Builder_NoResolver_Stream.res +60 -0
  237. package/src/components/ReadModel_Builder_NoResolver_Stream.res.mjs +64 -0
  238. package/src/components/ReadModel_Builder_PerReadModel.res +53 -0
  239. package/src/components/ReadModel_Builder_PerReadModel.res.mjs +66 -0
  240. package/src/components/ReadModel_Builder_Single.res +52 -0
  241. package/src/components/ReadModel_Builder_Single.res.mjs +66 -0
  242. package/src/components/ReadModel_Builder_Single_Stream.res +60 -0
  243. package/src/components/ReadModel_Builder_Single_Stream.res.mjs +66 -0
  244. package/src/components/Scheduler.res +1 -0
  245. package/src/components/Scheduler.res.mjs +13 -0
  246. package/src/components/SideEffectHandler.res +1 -0
  247. package/src/components/SideEffectHandler.res.mjs +19 -0
  248. package/src/components/SideEffectHandler_PerSideEffectHandler.res +13 -0
  249. package/src/components/SideEffectHandler_PerSideEffectHandler.res.mjs +52 -0
  250. package/src/components/SideEffectHandler_Single.res +54 -0
  251. package/src/components/SideEffectHandler_Single.res.mjs +60 -0
  252. package/src/components/StateChangeSlice_Builder.res +17 -0
  253. package/src/components/StateChangeSlice_Builder.res.mjs +23 -0
  254. package/src/components/StateViewSlice_Builder.res +46 -0
  255. package/src/components/StateViewSlice_Builder.res.mjs +68 -0
  256. package/src/components/StateViewSlice_Builder_Bundled.res.mjs +69 -0
  257. package/src/components/StateViewSlice_Builder_Stream.res +50 -0
  258. package/src/components/StateViewSlice_Builder_Stream.res.mjs +68 -0
  259. package/src/components/Task_Builder.res +1 -0
  260. package/src/components/Task_Builder.res.mjs +28 -0
  261. package/src/components/Task_Builder_PerBucket.res +22 -0
  262. package/src/components/Task_Builder_PerBucket.res.mjs +63 -0
  263. package/src/components/Vpc.res +214 -0
  264. package/src/components/Vpc.res.mjs +117 -0
  265. package/src/components/Vpc.resi +22 -0
  266. package/src/errors/AppSync_Error.res +36 -0
  267. package/src/errors/AppSync_Error.res.mjs +38 -0
  268. package/src/errors/Cognito_Error.res +36 -0
  269. package/src/errors/Cognito_Error.res.mjs +38 -0
  270. package/src/errors/DynamoDb_Error.res +75 -0
  271. package/src/errors/DynamoDb_Error.res.mjs +86 -0
  272. package/src/errors/Kinesis_Error.res +36 -0
  273. package/src/errors/Kinesis_Error.res.mjs +38 -0
  274. package/src/errors/SNS_Error.res +34 -0
  275. package/src/errors/SNS_Error.res.mjs +38 -0
  276. package/src/errors/SQS_Error.res +40 -0
  277. package/src/errors/SQS_Error.res.mjs +41 -0
  278. package/src/plugin/cloner/ClonerRunner.res +1 -0
  279. package/src/plugin/cloner/ClonerRunner.res.mjs +9 -0
  280. package/src/plugin/cloner/ClonerRunner_Fargate.res +362 -0
  281. package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +246 -0
  282. package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +42 -0
  283. package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res.mjs +45 -0
  284. package/src/plugin/heartbeat/HeartbeatRunner.res +1 -0
  285. package/src/plugin/heartbeat/HeartbeatRunner.res.mjs +9 -0
  286. package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +96 -0
  287. package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res.mjs +69 -0
  288. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +115 -0
  289. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res.mjs +88 -0
  290. package/src/plugin/runtime/PluginRuntimeOperations.res +5 -0
  291. package/src/plugin/runtime/PluginRuntimeOperations.res.mjs +14 -0
  292. package/src/plugin/runtime/PluginRuntime_Builder.res +769 -0
  293. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +464 -0
  294. package/src/plugin/runtime/Util_PluginMessage_Runtime.res +13 -0
  295. package/src/plugin/runtime/Util_PluginMessage_Runtime.res.mjs +19 -0
  296. package/src/plugin/stack/Plugin_ExtensionPoint_Builder.res +28 -0
  297. package/src/plugin/stack/Plugin_ExtensionPoint_Builder.res.mjs +67 -0
  298. package/src/plugin/stack/Plugin_Stack.res +439 -0
  299. package/src/plugin/stack/Plugin_Stack.res.mjs +263 -0
  300. package/src/util/Util.res +29 -0
  301. package/src/util/Util.res.mjs +93 -0
  302. package/src/util/Util_AppSync.res +36 -0
  303. package/src/util/Util_AppSync.res.mjs +35 -0
  304. package/src/util/Util_AppSync_Caller.res +213 -0
  305. package/src/util/Util_AppSync_Caller.res.mjs +170 -0
  306. package/src/util/Util_Bundle.res +255 -0
  307. package/src/util/Util_Bundle.res.mjs +179 -0
  308. package/src/util/Util_Cloudwatch.res +14 -0
  309. package/src/util/Util_Cloudwatch.res.mjs +19 -0
  310. package/src/util/Util_CognitoGroupUser.res +39 -0
  311. package/src/util/Util_CognitoGroupUser.res.mjs +32 -0
  312. package/src/util/Util_CognitoGroupUser_Runtime.res +65 -0
  313. package/src/util/Util_CognitoGroupUser_Runtime.res.mjs +50 -0
  314. package/src/util/Util_Cognito_Runtime.res +52 -0
  315. package/src/util/Util_Cognito_Runtime.res.mjs +35 -0
  316. package/src/util/Util_DeadLetterQueue.res +154 -0
  317. package/src/util/Util_DeadLetterQueue.res.mjs +158 -0
  318. package/src/util/Util_DynamoDb.res +210 -0
  319. package/src/util/Util_DynamoDb.res.mjs +218 -0
  320. package/src/util/Util_DynamoDbStream.res +138 -0
  321. package/src/util/Util_DynamoDbStream.res.mjs +134 -0
  322. package/src/util/Util_DynamoDbStream_Runtime.res +94 -0
  323. package/src/util/Util_DynamoDbStream_Runtime.res.mjs +131 -0
  324. package/src/util/Util_DynamoDb_Runtime.res +216 -0
  325. package/src/util/Util_DynamoDb_Runtime.res.mjs +257 -0
  326. package/src/util/Util_DynamoDb_TableManager.res +23 -0
  327. package/src/util/Util_DynamoDb_TableManager.res.mjs +35 -0
  328. package/src/util/Util_DynamoDb_TableManager.resi +3 -0
  329. package/src/util/Util_Env.res +5 -0
  330. package/src/util/Util_Env.res.mjs +2 -0
  331. package/src/util/Util_EventSourceMapping.res +49 -0
  332. package/src/util/Util_EventSourceMapping.res.mjs +32 -0
  333. package/src/util/Util_HostUiDomain.res +28 -0
  334. package/src/util/Util_HostUiDomain.res.mjs +26 -0
  335. package/src/util/Util_IAM_Role.res +14 -0
  336. package/src/util/Util_IAM_Role.res.mjs +28 -0
  337. package/src/util/Util_Kinesis_Runtime.res +20 -0
  338. package/src/util/Util_Kinesis_Runtime.res.mjs +24 -0
  339. package/src/util/Util_Lambda.res +39 -0
  340. package/src/util/Util_Lambda.res.mjs +45 -0
  341. package/src/util/Util_LocalConfig.res +119 -0
  342. package/src/util/Util_LocalConfig.res.mjs +112 -0
  343. package/src/util/Util_ResourceNaming.res +15 -0
  344. package/src/util/Util_ResourceNaming.res.mjs +26 -0
  345. package/src/util/Util_S3.res +17 -0
  346. package/src/util/Util_S3.res.mjs +30 -0
  347. package/src/util/Util_S3_Runtime.res +11 -0
  348. package/src/util/Util_S3_Runtime.res.mjs +15 -0
  349. package/src/util/Util_SNS.res +33 -0
  350. package/src/util/Util_SNS.res.mjs +50 -0
  351. package/src/util/Util_SNS_FIFO.res +21 -0
  352. package/src/util/Util_SNS_FIFO.res.mjs +27 -0
  353. package/src/util/Util_SNS_Runtime.res +33 -0
  354. package/src/util/Util_SNS_Runtime.res.mjs +27 -0
  355. package/src/util/Util_SQS.res +70 -0
  356. package/src/util/Util_SQS.res.mjs +83 -0
  357. package/src/util/Util_SQS_FIFO.res +16 -0
  358. package/src/util/Util_SQS_FIFO.res.mjs +28 -0
  359. package/src/util/Util_SQS_Runtime.res +169 -0
  360. package/src/util/Util_SQS_Runtime.res.mjs +150 -0
  361. package/src/util/Util_SesPolicy_Runtime.res +54 -0
  362. package/src/util/Util_SesPolicy_Runtime.res.mjs +55 -0
  363. package/src/util/Util_StaticBundle.res +124 -0
  364. package/src/util/Util_StaticBundle.res.mjs +132 -0
  365. package/src/util/Util_Vpc.res +22 -0
  366. package/src/util/Util_Vpc.res.mjs +27 -0
  367. package/tests/AppSync_AdapterTest.res +396 -0
  368. package/tests/AppSync_AdapterTest.res.mjs +326 -0
  369. package/tests/AppSync_Resolver_RetryingTest.res +59 -0
  370. package/tests/AppSync_Resolver_RetryingTest.res.mjs +66 -0
  371. package/tests/Auth_CognitoTest.res +203 -0
  372. package/tests/Auth_CognitoTest.res.mjs +248 -0
  373. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +602 -0
  374. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res.mjs +742 -0
  375. package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +57 -0
  376. package/tests/EventLogStorage_DynamoDb_RuntimeTest.res.mjs +68 -0
  377. package/tests/MCP_LambdaTest.res +101 -0
  378. package/tests/MCP_LambdaTest.res.mjs +56 -0
  379. package/tests/Util_HostUiDomainTest.res +90 -0
  380. package/tests/Util_HostUiDomainTest.res.mjs +50 -0
  381. package/tests/Util_SQS_RuntimeTest.res +46 -0
  382. package/tests/Util_SQS_RuntimeTest.res.mjs +45 -0
  383. package/tests/Util_StaticBundleTest.res +136 -0
  384. package/tests/Util_StaticBundleTest.res.mjs +149 -0
  385. package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +101 -0
  386. package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res.mjs +91 -0
  387. package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +315 -0
  388. package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res.mjs +435 -0
  389. package/tests/integration/DcbIntegrationHarness.res +102 -0
  390. package/tests/integration/DcbIntegrationHarness.res.mjs +163 -0
  391. package/tests/integration/EpTestSlice.res +28 -0
  392. package/tests/integration/EpTestSlice.res.mjs +43 -0
  393. package/tests/integration/EpTestSliceBehavior.res +18 -0
  394. package/tests/integration/EpTestSliceBehavior.res.mjs +35 -0
@@ -0,0 +1,149 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Fs from "fs";
4
+ import * as Os from "os";
5
+ import * as Path from "path";
6
+ import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
7
+ import * as Util_StaticBundle$ReventlessAws from "../src/util/Util_StaticBundle.res.mjs";
8
+
9
+ function makeFixture() {
10
+ let base = Fs.mkdtempSync(Path.join(Os.tmpdir(), "static-bundle-"));
11
+ Fs.writeFileSync(Path.join(base, "index.html"), "<html></html>");
12
+ Fs.writeFileSync(Path.join(base, "app.js"), "console.log('x')");
13
+ Fs.writeFileSync(Path.join(base, "app.css"), "body{color:red}");
14
+ Fs.writeFileSync(Path.join(base, ".DS_Store"), "ignored");
15
+ let assets = Path.join(base, "assets");
16
+ Fs.mkdirSync(assets, {
17
+ recursive: true
18
+ });
19
+ Fs.writeFileSync(Path.join(assets, "logo.svg"), "<svg/>");
20
+ Fs.writeFileSync(Path.join(assets, "favicon.ico"), "ico");
21
+ return base;
22
+ }
23
+
24
+ globalThis.describe("Util_StaticBundle.contentTypeFor", () => {
25
+ globalThis.test("html", () => {
26
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("index.html")).toBe("text/html; charset=utf-8");
27
+ });
28
+ globalThis.test("css", () => {
29
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("foo/bar.css")).toBe("text/css; charset=utf-8");
30
+ });
31
+ globalThis.test("js", () => {
32
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("app.js")).toBe("application/javascript; charset=utf-8");
33
+ });
34
+ globalThis.test("mjs", () => {
35
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("module.mjs")).toBe("application/javascript; charset=utf-8");
36
+ });
37
+ globalThis.test("json", () => {
38
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("data.json")).toBe("application/json; charset=utf-8");
39
+ });
40
+ globalThis.test("svg", () => {
41
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("logo.svg")).toBe("image/svg+xml");
42
+ });
43
+ globalThis.test("woff2", () => {
44
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("font.woff2")).toBe("font/woff2");
45
+ });
46
+ globalThis.test("wasm", () => {
47
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("blob.wasm")).toBe("application/wasm");
48
+ });
49
+ globalThis.test("uppercase extension is normalised", () => {
50
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("LOGO.PNG")).toBe("image/png");
51
+ });
52
+ globalThis.test("unknown extension defaults to octet-stream", () => {
53
+ globalThis.expect(Util_StaticBundle$ReventlessAws.contentTypeFor("blob.xyz")).toBe("application/octet-stream");
54
+ });
55
+ });
56
+
57
+ globalThis.describe("Util_StaticBundle.sanitizeName", () => {
58
+ globalThis.test("replaces slashes with dashes", () => {
59
+ globalThis.expect(Util_StaticBundle$ReventlessAws.sanitizeName("foo/bar/baz")).toBe("foo-bar-baz");
60
+ });
61
+ globalThis.test("replaces dots with dashes", () => {
62
+ globalThis.expect(Util_StaticBundle$ReventlessAws.sanitizeName("index.html")).toBe("index-html");
63
+ });
64
+ globalThis.test("replaces both", () => {
65
+ globalThis.expect(Util_StaticBundle$ReventlessAws.sanitizeName("assets/logo.svg")).toBe("assets-logo-svg");
66
+ });
67
+ });
68
+
69
+ globalThis.describe("Util_StaticBundle.walk", () => {
70
+ globalThis.test("returns one entry per file, skips dotfiles, uses forward slashes", () => {
71
+ let dir = makeFixture();
72
+ let entries = Util_StaticBundle$ReventlessAws.walk(dir);
73
+ let keys = entries.map(e => e.relativePath).toSorted(Primitive_string.compare);
74
+ globalThis.expect(keys).toEqual([
75
+ "app.css",
76
+ "app.js",
77
+ "assets/favicon.ico",
78
+ "assets/logo.svg",
79
+ "index.html"
80
+ ]);
81
+ Fs.rmSync(dir, {
82
+ recursive: true,
83
+ force: true
84
+ });
85
+ });
86
+ globalThis.test("computes a non-empty content hash for each entry", () => {
87
+ let dir = makeFixture();
88
+ let entries = Util_StaticBundle$ReventlessAws.walk(dir);
89
+ entries.forEach(e => {
90
+ globalThis.expect(e.contentHash.length > 0).toBe(true);
91
+ });
92
+ Fs.rmSync(dir, {
93
+ recursive: true,
94
+ force: true
95
+ });
96
+ });
97
+ globalThis.test("identical contents produce identical hashes", () => {
98
+ let dir = makeFixture();
99
+ let entries = Util_StaticBundle$ReventlessAws.walk(dir);
100
+ let indexEntry = entries.find(e => e.relativePath === "index.html");
101
+ let indexHash = indexEntry.contentHash;
102
+ let dir2 = Fs.mkdtempSync(Path.join(Os.tmpdir(), "static-bundle-"));
103
+ Fs.writeFileSync(Path.join(dir2, "index.html"), "<html></html>");
104
+ let entries2 = Util_StaticBundle$ReventlessAws.walk(dir2);
105
+ let indexHash2 = entries2[0].contentHash;
106
+ globalThis.expect(indexHash).toBe(indexHash2);
107
+ Fs.rmSync(dir, {
108
+ recursive: true,
109
+ force: true
110
+ });
111
+ Fs.rmSync(dir2, {
112
+ recursive: true,
113
+ force: true
114
+ });
115
+ });
116
+ globalThis.test("different contents produce different hashes", () => {
117
+ let dirA = Fs.mkdtempSync(Path.join(Os.tmpdir(), "static-bundle-"));
118
+ Fs.writeFileSync(Path.join(dirA, "f.txt"), "AAA");
119
+ let dirB = Fs.mkdtempSync(Path.join(Os.tmpdir(), "static-bundle-"));
120
+ Fs.writeFileSync(Path.join(dirB, "f.txt"), "BBB");
121
+ let hashA = Util_StaticBundle$ReventlessAws.walk(dirA)[0].contentHash;
122
+ let hashB = Util_StaticBundle$ReventlessAws.walk(dirB)[0].contentHash;
123
+ globalThis.expect(hashA === hashB).toBe(false);
124
+ Fs.rmSync(dirA, {
125
+ recursive: true,
126
+ force: true
127
+ });
128
+ Fs.rmSync(dirB, {
129
+ recursive: true,
130
+ force: true
131
+ });
132
+ });
133
+ globalThis.test("throws when assetsDir does not exist", () => {
134
+ let missing = Path.join(Os.tmpdir(), "static-bundle-does-not-exist-xyz123");
135
+ let threw;
136
+ try {
137
+ Util_StaticBundle$ReventlessAws.walk(missing);
138
+ threw = false;
139
+ } catch (exn) {
140
+ threw = true;
141
+ }
142
+ globalThis.expect(threw).toBe(true);
143
+ });
144
+ });
145
+
146
+ export {
147
+ makeFixture,
148
+ }
149
+ /* Not a pure module */
@@ -0,0 +1,101 @@
1
+ // Integration regression guard for the DCB CommandTopic Lambda entry point.
2
+ //
3
+ // Drives the real `DcbCommandTopicEntryPoint.mjs` against a DynamoDB Local
4
+ // table, with a test loader supplying a tiny `EpTestSlice` spec/behavior pair
5
+ // in place of the production Lambda's `/var/task/node_modules` dynamic import.
6
+ // Covers the regression class behind the 2026-06-21 incident: the entry point
7
+ // was passing the wrong number of positional args to ReScript-compiled
8
+ // `StateChangeSlice_Callback.handleCommands`, so `stream` landed as undefined
9
+ // and the Lambda crashed inside Effect's `Stream.mapEffect` with
10
+ // `'channel' in undefined`. Any future arity drift between the JS caller and
11
+ // the ReScript signature (e.g. a new optional labelled arg added before the
12
+ // positional ones) re-breaks the same path; this test fails it as
13
+ // CommandAccepted → Lambda:Unhandled.
14
+ //
15
+ // Boots via the same `pnpm run test:integration` Docker-gated suite as the
16
+ // storage-runtime integration tests; harnessed by `DcbIntegrationHarness`.
17
+
18
+ open JestGlobals
19
+
20
+ module H = DcbIntegrationHarness
21
+
22
+ // `cmdGenHandler(event)` returns an Effect that must be runPromise'd through
23
+ // the request context the production handler supplies. This raw helper drives
24
+ // the full real pipeline: build handlers via the entry point's exported
25
+ // factory, dispatch one AppSync event, run the Effect, return the AppSync-
26
+ // shape outcome JSON.
27
+ let runOneAppSyncEvent: (string, JSON.t) => promise<JSON.t> = %raw(`
28
+ async (tableName, event) => {
29
+ const { buildHandlersForConfig } = await import(
30
+ "@reventlessdev/reventless-aws/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs"
31
+ );
32
+ const Effect = await import("effect/Effect");
33
+ const { tag: requestContextTag } = await import(
34
+ "@reventlessdev/reventless-core/src/RequestContext.res.mjs"
35
+ );
36
+ const { commandOutcomeToJson } = await import(
37
+ "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic_Helpers.res.mjs"
38
+ );
39
+
40
+ const loadModule = async (specifier) => {
41
+ if (specifier === "ep-test://spec") return await import("./EpTestSlice.res.mjs");
42
+ if (specifier === "ep-test://behavior") return await import("./EpTestSliceBehavior.res.mjs");
43
+ throw new Error("unknown test specifier: " + specifier);
44
+ };
45
+
46
+ const config = {
47
+ pluginName: "EpTestPlugin",
48
+ dcbEventLogTableName: tableName,
49
+ stateChangeSliceModules: [{ spec: "ep-test://spec", behavior: "ep-test://behavior" }],
50
+ queueUrl: "https://sqs.eu-west-1.amazonaws.com/000000000000/ep-test-queue",
51
+ };
52
+
53
+ const [, cmdGenHandler] = await buildHandlersForConfig(config, { loadModule });
54
+
55
+ const effect = cmdGenHandler(event)
56
+ .pipe(Effect.provideService(requestContextTag, { correlationId: "ep-test" }));
57
+ const outcome = await Effect.runPromise(effect);
58
+ return commandOutcomeToJson(outcome);
59
+ }
60
+ `)
61
+
62
+ let buildAppSyncEvent = (widgetId): JSON.t => {
63
+ // CommandGenerator payload: `{command, arguments, meta, identity?}` — the
64
+ // exact shape AppSync's direct-invoke resolver sends (matches the resolver
65
+ // template in `DcbCmdHandlerResolver_GraphQL.res`).
66
+ let command = Dict.fromArray([("AddWidget", Dict.make()->JSON.Encode.object)])
67
+ let arguments = Dict.fromArray([("widgetId", widgetId->JSON.Encode.string)])
68
+ let meta = Dict.fromArray([
69
+ ("user", "ep-test"->JSON.Encode.string),
70
+ ("ip", JSON.Encode.null),
71
+ ])
72
+ Dict.fromArray([
73
+ ("command", command->JSON.Encode.object),
74
+ ("arguments", arguments->JSON.Encode.object),
75
+ ("meta", meta->JSON.Encode.object),
76
+ ])->JSON.Encode.object
77
+ }
78
+
79
+ describe("DcbCommandTopicEntryPoint integration", () => {
80
+ testAsync(
81
+ "AppSync direct-invoke routes through the runtime handler to CommandAccepted",
82
+ async () => {
83
+ // Own table-name prefix avoids `ResourceInUseException` when the test
84
+ // shares a DDB Local instance with sibling suites that also use the
85
+ // harness's `DcbItTest_N` counter.
86
+ let table = await H.createDcbTable("EpTest_" ++ Date.now()->Float.toString)
87
+ let event = buildAppSyncEvent("widget-1")
88
+ let outcomeJson = await runOneAppSyncEvent(table.name, event)
89
+
90
+ // `commandOutcomeToJson` produces an AppSync-shape envelope:
91
+ // { __typename: "CommandAccepted" | "CommandRejected" | "CommandPending", ... }
92
+ // The arity bug surfaces as `Lambda:Unhandled` at the AppSync layer —
93
+ // here it would manifest as a thrown error from `runPromise` before
94
+ // `commandOutcomeToJson` ever runs, so reaching this assertion at all
95
+ // already proves the regression hasn't returned. We still assert on
96
+ // `CommandAccepted` so a future drift to silent-rejection also fails.
97
+ let s = outcomeJson->JSON.stringifyAny->Option.getOr("<unserializable>")
98
+ expect(s->String.includes("CommandAccepted"))->toBe(true)
99
+ },
100
+ )
101
+ })
@@ -0,0 +1,91 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
+ import * as DcbIntegrationHarness$ReventlessAws from "./DcbIntegrationHarness.res.mjs";
5
+
6
+ let runOneAppSyncEvent = (async (tableName, event) => {
7
+ const { buildHandlersForConfig } = await import(
8
+ "@reventlessdev/reventless-aws/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs"
9
+ );
10
+ const Effect = await import("effect/Effect");
11
+ const { tag: requestContextTag } = await import(
12
+ "@reventlessdev/reventless-core/src/RequestContext.res.mjs"
13
+ );
14
+ const { commandOutcomeToJson } = await import(
15
+ "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic_Helpers.res.mjs"
16
+ );
17
+
18
+ const loadModule = async (specifier) => {
19
+ if (specifier === "ep-test://spec") return await import("./EpTestSlice.res.mjs");
20
+ if (specifier === "ep-test://behavior") return await import("./EpTestSliceBehavior.res.mjs");
21
+ throw new Error("unknown test specifier: " + specifier);
22
+ };
23
+
24
+ const config = {
25
+ pluginName: "EpTestPlugin",
26
+ dcbEventLogTableName: tableName,
27
+ stateChangeSliceModules: [{ spec: "ep-test://spec", behavior: "ep-test://behavior" }],
28
+ queueUrl: "https://sqs.eu-west-1.amazonaws.com/000000000000/ep-test-queue",
29
+ };
30
+
31
+ const [, cmdGenHandler] = await buildHandlersForConfig(config, { loadModule });
32
+
33
+ const effect = cmdGenHandler(event)
34
+ .pipe(Effect.provideService(requestContextTag, { correlationId: "ep-test" }));
35
+ const outcome = await Effect.runPromise(effect);
36
+ return commandOutcomeToJson(outcome);
37
+ });
38
+
39
+ function buildAppSyncEvent(widgetId) {
40
+ let command = Object.fromEntries([[
41
+ "AddWidget",
42
+ {}
43
+ ]]);
44
+ let $$arguments = Object.fromEntries([[
45
+ "widgetId",
46
+ widgetId
47
+ ]]);
48
+ let meta = Object.fromEntries([
49
+ [
50
+ "user",
51
+ "ep-test"
52
+ ],
53
+ [
54
+ "ip",
55
+ null
56
+ ]
57
+ ]);
58
+ return Object.fromEntries([
59
+ [
60
+ "command",
61
+ command
62
+ ],
63
+ [
64
+ "arguments",
65
+ $$arguments
66
+ ],
67
+ [
68
+ "meta",
69
+ meta
70
+ ]
71
+ ]);
72
+ }
73
+
74
+ globalThis.describe("DcbCommandTopicEntryPoint integration", () => {
75
+ globalThis.test("AppSync direct-invoke routes through the runtime handler to CommandAccepted", async () => {
76
+ let table = await DcbIntegrationHarness$ReventlessAws.createDcbTable("EpTest_" + Date.now().toString());
77
+ let event = buildAppSyncEvent("widget-1");
78
+ let outcomeJson = await runOneAppSyncEvent(table.name, event);
79
+ let s = Stdlib_Option.getOr(JSON.stringify(outcomeJson), "<unserializable>");
80
+ globalThis.expect(s.includes("CommandAccepted")).toBe(true);
81
+ });
82
+ });
83
+
84
+ let H;
85
+
86
+ export {
87
+ H,
88
+ runOneAppSyncEvent,
89
+ buildAppSyncEvent,
90
+ }
91
+ /* runOneAppSyncEvent Not a pure module */
@@ -0,0 +1,315 @@
1
+ // ⚠️ PENDING REWRITE (dcb-fence-event-type-granularity): this suite still encodes
2
+ // the OLD scalar-`lastPosition` fence + `create#…` create-guard model. The adapter
3
+ // now uses PER-TYPE `pos#<eventType>` fence attributes with the create guard folded
4
+ // in, so `H.setFence(~lastPosition=…)` seeding, the `create#…`-row assertions, and
5
+ // the tag-only (no `eventTypes`) queries below must be reworked and re-run against
6
+ // DynamoDB Local before they pass. Tracked as Test plan #2 in
7
+ // docs/plans/dcb-fence-event-type-granularity.md. Not run by the default unit suite
8
+ // (CI `pnpm test`), so it does not gate the build.
9
+ //
10
+ // DCB DynamoDB integration suite — exercises the real fence path against a
11
+ // DynamoDB Local engine (NOT run by the default unit suite; see
12
+ // `jest.integration.config.js` + `scripts/run-integration-tests.sh`).
13
+ //
14
+ // The unit suite (`DcbEventLogStorage_DynamoDb_RuntimeTest.res`) asserts the
15
+ // *shape* of the built `TransactWriteItems`. This suite asserts DynamoDB's
16
+ // *behaviour* — that the `ConditionExpression`s interpret as we expect — which
17
+ // is the only thing that proves the fence-scope model (Issue 1 fix) and the
18
+ // optimistic-concurrency guarantees end-to-end. See
19
+ // `docs/analysis/dcb-consistency-check-issues.md` and
20
+ // `docs/plans/dcb-consistency-hardening.md` (Phase 1).
21
+
22
+ open JestGlobals
23
+
24
+ module H = DcbIntegrationHarness
25
+ module Runtime = DcbEventLogStorage_DynamoDb_Runtime
26
+
27
+ let tag = (key, value): Reventless.DcbTag.tag => {key, value}
28
+ let meta = () => ReventlessCore.Message.generateMeta(~service="dcb-it")
29
+
30
+ let event = (eventType, tags): ReventlessCore.DcbEventLog_Adapter.rawStoredEvent => {
31
+ eventType,
32
+ data: JSON.Object(Dict.make()),
33
+ tags,
34
+ meta: meta(),
35
+ }
36
+
37
+ let simple = (key): Reventless.DcbTag.derivedPartitionTag => Simple({key: key})
38
+
39
+ let isOk = r =>
40
+ switch r {
41
+ | Ok(_) => true
42
+ | Error(_) => false
43
+ }
44
+
45
+ let isConflict = r =>
46
+ switch r {
47
+ | Error(msg) => msg->String.includes("Conflict")
48
+ | Ok(_) => false
49
+ }
50
+
51
+ // Read a slice's decision-model head position for a query — the `after` an
52
+ // append rides with.
53
+ let readAfter = async (table, query: Reventless.DcbTag.query) => {
54
+ let result = await Runtime.read(table)(~query)
55
+ result.headPosition
56
+ }
57
+
58
+ // Seed a single event with no consistency check (import/replay path). Bumps the
59
+ // event's partition fence so later conditional readers observe it.
60
+ let seed = (table, ev, ~partitionTag) => Runtime.appendUnconditional(table, [ev], ~partitionTag)
61
+
62
+ describe("DCB DynamoDb integration — fence-scope = read-scope (Issue 1 regression)", () => {
63
+ let productTag = tag("productId", "P5")
64
+
65
+ // Place an order: read (orderId ∪ productId), then append OrderPlaced.
66
+ let placeOrder = async (table, ~orderId, ~customerId) => {
67
+ let query: Reventless.DcbTag.query = [
68
+ {tags: [tag("orderId", orderId)]},
69
+ {tags: [productTag]},
70
+ ]
71
+ let after = await readAfter(table, query)
72
+ await Runtime.appendConditional(
73
+ table,
74
+ [event("OrderPlaced", [tag("orderId", orderId), tag("customerId", customerId), productTag])],
75
+ {query, after: ?after},
76
+ ~partitionTag=simple("orderId"),
77
+ )
78
+ }
79
+
80
+ testAsync("a second order of the same product (different order + customer) succeeds", async () => {
81
+ let table = await H.freshTable()
82
+ let _ = await seed(table, event("CatalogProductSynced", [productTag]), ~partitionTag=simple("productId"))
83
+
84
+ let r1 = await placeOrder(table, ~orderId="O1", ~customerId="C1")
85
+ let r2 = await placeOrder(table, ~orderId="O2", ~customerId="C2")
86
+
87
+ expect(isOk(r1))->toBe(true)
88
+ expect(isOk(r2))->toBe(true)
89
+ })
90
+
91
+ testAsync("two concurrent orders of the same product both succeed (no productId contention)", async () => {
92
+ let table = await H.freshTable()
93
+ let _ = await seed(table, event("CatalogProductSynced", [productTag]), ~partitionTag=simple("productId"))
94
+
95
+ let results = await Promise.all([
96
+ placeOrder(table, ~orderId="OA", ~customerId="CA"),
97
+ placeOrder(table, ~orderId="OB", ~customerId="CB"),
98
+ ])
99
+
100
+ expect(results->Array.every(isOk))->toBe(true)
101
+ })
102
+
103
+ testAsync("a concurrent product re-sync after the order's read still conflicts (OCC preserved)", async () => {
104
+ let table = await H.freshTable()
105
+ let _ = await seed(table, event("CatalogProductSynced", [productTag]), ~partitionTag=simple("productId"))
106
+
107
+ // Order reads its decision model (after = the sync's position)…
108
+ let query: Reventless.DcbTag.query = [{tags: [tag("orderId", "O1")]}, {tags: [productTag]}]
109
+ let after = (await readAfter(table, query))->Option.getOr("")
110
+ expect(after == "")->toBe(false)
111
+
112
+ // …a concurrent re-sync advances fence#productId:P5 past `after`. We set the
113
+ // fence directly (rather than racing a second appendUnconditional) so the
114
+ // advance is deterministically > after — same-millisecond writers can
115
+ // otherwise tie on UUID order (analysis Issue 7). Appending "z" stays
116
+ // lexically greater than any real position.
117
+ let _ = await H.setFence(table, productTag, ~lastPosition=after ++ "z")
118
+
119
+ // …so the now-stale order append must conflict on the productId fence.
120
+ let r = await Runtime.appendConditional(
121
+ table,
122
+ [event("OrderPlaced", [tag("orderId", "O1"), tag("customerId", "C1"), productTag])],
123
+ {query, after: ?Some(after)},
124
+ ~partitionTag=simple("orderId"),
125
+ )
126
+ expect(isConflict(r))->toBe(true)
127
+ })
128
+
129
+ testAsync("placing an order does not poison the customer slice (secondary customerId not fenced)", async () => {
130
+ let table = await H.freshTable()
131
+ let customerTag = tag("customerId", "C1")
132
+
133
+ // Customer exists (partitioned by customerId) → fence#customerId:C1 seeded.
134
+ let _ = await seed(table, event("CustomerRegistered", [customerTag]), ~partitionTag=simple("customerId"))
135
+
136
+ // Order for C1 carries customerId as a SECONDARY tag (partitioned by orderId).
137
+ let orderQuery: Reventless.DcbTag.query = [{tags: [tag("orderId", "O1")]}]
138
+ let orderAfter = await readAfter(table, orderQuery)
139
+ let _ = await Runtime.appendConditional(
140
+ table,
141
+ [event("OrderPlaced", [tag("orderId", "O1"), customerTag, productTag])],
142
+ {query: orderQuery, after: ?orderAfter},
143
+ ~partitionTag=simple("orderId"),
144
+ )
145
+
146
+ // The customer slice reads its own partition (sees only CustomerRegistered)
147
+ // and changes the email. Pre-fix the order would have bumped
148
+ // fence#customerId:C1, falsely conflicting this append.
149
+ let customerQuery: Reventless.DcbTag.query = [{tags: [customerTag]}]
150
+ let customerAfter = await readAfter(table, customerQuery)
151
+ let r = await Runtime.appendConditional(
152
+ table,
153
+ [event("EmailChanged", [customerTag])],
154
+ {query: customerQuery, after: ?customerAfter},
155
+ ~partitionTag=simple("customerId"),
156
+ )
157
+ expect(isOk(r))->toBe(true)
158
+ })
159
+ })
160
+
161
+ describe("DCB DynamoDb integration — optimistic concurrency primitives", () => {
162
+ testAsync("fresh first-writer (after=None) succeeds and seeds the fence", async () => {
163
+ let table = await H.freshTable()
164
+ let query: Reventless.DcbTag.query = [{tags: [tag("counterId", "K0")]}]
165
+ let r = await Runtime.appendConditional(
166
+ table,
167
+ [event("CounterStarted", [tag("counterId", "K0")])],
168
+ {query, after: ?None},
169
+ ~partitionTag=simple("counterId"),
170
+ )
171
+ expect(isOk(r))->toBe(true)
172
+
173
+ // The seeded event is now readable.
174
+ let after = await readAfter(table, query)
175
+ expect(after->Option.isSome)->toBe(true)
176
+ })
177
+
178
+ testAsync("two concurrent commits at the same after never both win (no duplicate)", async () => {
179
+ let table = await H.freshTable()
180
+ let counterTag = tag("counterId", "K1")
181
+ let _ = await seed(table, event("CounterStarted", [counterTag]), ~partitionTag=simple("counterId"))
182
+
183
+ let query: Reventless.DcbTag.query = [{tags: [counterTag]}]
184
+ let after = await readAfter(table, query)
185
+
186
+ let increment = () =>
187
+ Runtime.appendConditional(
188
+ table,
189
+ [event("CounterIncremented", [counterTag])],
190
+ {query, after: ?after},
191
+ ~partitionTag=simple("counterId"),
192
+ )
193
+
194
+ let results = await Promise.all([increment(), increment()])
195
+ let oks = results->Array.filter(isOk)->Array.length
196
+ let conflicts = results->Array.filter(isConflict)->Array.length
197
+ // Safety invariant at the raw-append layer: at most one writer commits, and
198
+ // every non-winner surfaces a Conflict. (DynamoDB may cancel BOTH with a
199
+ // mutual TransactionConflict — there is no retry here; the slice callback's
200
+ // 3-retry loop is what turns this into a guaranteed single winner in prod.)
201
+ expect(oks <= 1)->toBe(true)
202
+ expect(oks + conflicts)->toBe(2)
203
+ expect(conflicts >= 1)->toBe(true)
204
+ })
205
+
206
+ testAsync("two concurrent first-writers to the same entity — exactly one creates it (Issue 2)", async () => {
207
+ let table = await H.freshTable()
208
+ // Both writers read an empty decision model (after=None) and try to create
209
+ // the same order. The per-(eventType, partition) create guard must let only
210
+ // one through.
211
+ let create = () =>
212
+ Runtime.appendConditional(
213
+ table,
214
+ [event("OrderCreated", [tag("orderId", "O1")])],
215
+ {query: [{tags: [tag("orderId", "O1")]}], after: ?None},
216
+ ~partitionTag=simple("orderId"),
217
+ )
218
+
219
+ let results = await Promise.all([create(), create()])
220
+ let oks = results->Array.filter(isOk)->Array.length
221
+ // Safety: the two first-writers must NOT both create the entity. At most one
222
+ // commits; every non-winner surfaces a Conflict. (DynamoDB may cancel both
223
+ // with a mutual TransactionConflict — the slice callback's retry loop then
224
+ // makes exactly one win. Pre-fix this asserted-2: both committed = duplicate.)
225
+ expect(oks <= 1)->toBe(true)
226
+ expect(oks + results->Array.filter(isConflict)->Array.length)->toBe(2)
227
+
228
+ // No duplicate landed — persisted OrderCreated count matches the winners.
229
+ let readResult = await Runtime.read(table)(~query=[{tags: [tag("orderId", "O1")]}])
230
+ expect(readResult.events->Array.length)->toBe(oks)
231
+ })
232
+
233
+ testAsync("the create guard does not false-conflict a subset-event-type writer (Issue 4)", async () => {
234
+ let table = await H.freshTable()
235
+ // A productId partition already holds a ProductAdded (its own create guard +
236
+ // fence). A different slice reads only NameChanged on that partition, sees
237
+ // nothing (after=None), and appends the first NameChanged. Its guard is
238
+ // create#NameChanged#productId:P — distinct from ProductAdded's — so it must
239
+ // NOT conflict with the pre-existing partition state.
240
+ let productTag = tag("productId", "P")
241
+ let r1 = await Runtime.appendConditional(
242
+ table,
243
+ [event("ProductAdded", [productTag])],
244
+ {query: [{tags: [productTag]}], after: ?None},
245
+ ~partitionTag=simple("productId"),
246
+ )
247
+ expect(isOk(r1))->toBe(true)
248
+
249
+ let r2 = await Runtime.appendConditional(
250
+ table,
251
+ [event("NameChanged", [productTag])],
252
+ {query: [{tags: [productTag]}], after: ?None},
253
+ ~partitionTag=simple("productId"),
254
+ )
255
+ expect(isOk(r2))->toBe(true)
256
+ })
257
+
258
+ testAsync("a chain of compatible commits all succeed", async () => {
259
+ let table = await H.freshTable()
260
+ let counterTag = tag("counterId", "K2")
261
+ let _ = await seed(table, event("CounterStarted", [counterTag]), ~partitionTag=simple("counterId"))
262
+ let query: Reventless.DcbTag.query = [{tags: [counterTag]}]
263
+
264
+ let step = async () => {
265
+ let after = await readAfter(table, query)
266
+ await Runtime.appendConditional(
267
+ table,
268
+ [event("CounterIncremented", [counterTag])],
269
+ {query, after: ?after},
270
+ ~partitionTag=simple("counterId"),
271
+ )
272
+ }
273
+
274
+ let r1 = await step()
275
+ let r2 = await step()
276
+ let r3 = await step()
277
+ expect([r1, r2, r3]->Array.every(isOk))->toBe(true)
278
+ })
279
+
280
+ testAsync("a failed fence condition aborts the whole transaction (multi-tag atomicity)", async () => {
281
+ let table = await H.freshTable()
282
+ // Composite slice: one multi-tag clause → both tags get check+bump.
283
+ let tags = [tag("productId", "p1"), tag("orderId", "o1")]
284
+ let query: Reventless.DcbTag.query = [{tags: tags}]
285
+
286
+ // Seed one event so the next append rides after=Some.
287
+ let seedRes = await Runtime.appendConditional(
288
+ table,
289
+ [event("ProductDemandRecorded", tags)],
290
+ {query, after: ?None},
291
+ ~partitionTag=simple("productId"),
292
+ )
293
+ expect(isOk(seedRes))->toBe(true)
294
+
295
+ let after = (await readAfter(table, query))->Option.getOr("")
296
+ expect(after == "")->toBe(false)
297
+
298
+ // A concurrent writer advances ONLY the productId fence past `after`.
299
+ // Appending "z" keeps the position lexically greater than any real position.
300
+ let _ = await H.setFence(table, tag("productId", "p1"), ~lastPosition=after ++ "z")
301
+
302
+ let r = await Runtime.appendConditional(
303
+ table,
304
+ [event("ProductDemandRecorded", tags)],
305
+ {query, after: ?Some(after)},
306
+ ~partitionTag=simple("productId"),
307
+ )
308
+ expect(isConflict(r))->toBe(true)
309
+
310
+ // Atomic rollback: the second event was NOT written — the composite read
311
+ // still returns exactly the one seeded event.
312
+ let readResult = await Runtime.read(table)(~query)
313
+ expect(readResult.events->Array.length)->toBe(1)
314
+ })
315
+ })