@reventlessdev/reventless-aws 3.0.0-alpha.344 → 3.0.0-alpha.345

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 (232) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +11 -11
  3. package/scripts/ProvisionIdentity.res +8 -3
  4. package/src/Platform.res +327 -328
  5. package/src/Platform.res.mjs +4 -2
  6. package/src/Platform_Casts.res +13 -4
  7. package/src/adapter/Api/AppSyncEventsSigner_Ops.res +8 -4
  8. package/src/adapter/Api/AppSync_EventsApi.res +12 -14
  9. package/src/adapter/Api/AppSync_Resolver_Native.res +3 -4
  10. package/src/adapter/Api/AppSync_Resolver_Retrying.res +78 -70
  11. package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +11 -8
  12. package/src/adapter/Api/Platform_AdminScan_Ops.res +15 -14
  13. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +10 -2
  14. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +40 -50
  15. package/src/adapter/Api/Platform_UIFragments_Lambda.res +39 -32
  16. package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +5 -2
  17. package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +0 -1
  18. package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -2
  19. package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -4
  20. package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +5 -2
  21. package/src/adapter/Auth/Auth_Cognito.res +3 -9
  22. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +1 -4
  23. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +3 -1
  24. package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +1 -4
  25. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +7 -4
  26. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +6 -1
  27. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +7 -4
  28. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +24 -18
  29. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +9 -4
  30. package/src/adapter/CommandTopic/CommandTopicRegistry.res +1 -4
  31. package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +15 -15
  32. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +9 -5
  33. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +179 -213
  34. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +5 -5
  35. package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +6 -2
  36. package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +14 -7
  37. package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +14 -7
  38. package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +6 -3
  39. package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +6 -1
  40. package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +13 -17
  41. package/src/adapter/EventLog/EventLogStorage_Postgres.res +7 -4
  42. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +12 -7
  43. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +4 -2
  44. package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +3 -2
  45. package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +20 -12
  46. package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +21 -9
  47. package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -3
  48. package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +6 -3
  49. package/src/adapter/Mcp/MCP_Lambda.res +31 -46
  50. package/src/adapter/Messaging/Messaging_Ses_Backend.res +11 -7
  51. package/src/adapter/Messaging/Messaging_Ses_Backend.res.mjs +2 -4
  52. package/src/adapter/Monitoring/Monitoring_CloudWatch.res +16 -16
  53. package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +5 -10
  54. package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +4 -2
  55. package/src/adapter/Postgres/PgConnection.res +6 -5
  56. package/src/adapter/Postgres/PgMigration_Builder.res +4 -8
  57. package/src/adapter/Postgres/PgRuntime.res +4 -7
  58. package/src/adapter/QueryDb/PgQueryResolver_Builder.res +9 -11
  59. package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +22 -21
  60. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +114 -111
  61. package/src/adapter/QueryDb/QueryDbResolvers_Lambda.res +1 -7
  62. package/src/adapter/QueryDb/QueryDbStorage.res +4 -2
  63. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +23 -24
  64. package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +8 -2
  65. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +71 -73
  66. package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +5 -2
  67. package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +1 -4
  68. package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +8 -2
  69. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +73 -81
  70. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +72 -78
  71. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +44 -67
  72. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +44 -67
  73. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +53 -82
  74. package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +47 -77
  75. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +18 -11
  76. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -97
  77. package/src/adapter/Runtime/CounterEntryPoint_Ops.res +2 -7
  78. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -10
  79. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +24 -15
  80. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +17 -37
  81. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +31 -57
  82. package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +18 -24
  83. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -5
  84. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +4 -3
  85. package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
  86. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +4 -2
  87. package/src/adapter/Runtime/PgMigrationEntryPoint.res +0 -1
  88. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +3 -2
  89. package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -2
  90. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +4 -5
  91. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +22 -10
  92. package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +8 -2
  93. package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +14 -31
  94. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +16 -17
  95. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +10 -9
  96. package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +46 -52
  97. package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +36 -41
  98. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +31 -37
  99. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +6 -7
  100. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +4 -6
  101. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +2 -6
  102. package/src/adapter/StateTopic/StateTopic_AppSync.res +21 -16
  103. package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +36 -32
  104. package/src/adapter/Task/TaskBucket_S3.res +6 -1
  105. package/src/adapter/Upload/Upload_Claim_S3.res +17 -20
  106. package/src/adapter/Upload/Upload_Claim_S3_Ops.res +5 -2
  107. package/src/adapter/Upload/Upload_Presign_S3.res +51 -49
  108. package/src/capability/Capability_Geocoding_AwsLocation.res +4 -1
  109. package/src/capability/Capability_Messaging.res +4 -5
  110. package/src/capability/Capability_Messaging_Ses.res +3 -1
  111. package/src/capability/Capability_ObjectStore_S3.res +1 -7
  112. package/src/components/Api/AppSync_Adapter.res +28 -41
  113. package/src/components/Api/AppSync_SdlDecorate.res +38 -30
  114. package/src/components/AutomationSlice_Builder.res +6 -4
  115. package/src/components/ExtensionPoint_Builder.res +9 -10
  116. package/src/components/InboundTranslationSlice_Builder.res +7 -8
  117. package/src/components/OutboundTranslationSlice_Builder.res +14 -8
  118. package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
  119. package/src/components/SideEffectHandler_Single.res +4 -4
  120. package/src/components/StateViewSlice_Builder.res +6 -4
  121. package/src/components/StateViewSlice_Builder_Stream.res +6 -4
  122. package/src/components/Task_Builder_PerBucket.res +10 -11
  123. package/src/plugin/cloner/ClonerRunner_Fargate.res +3 -10
  124. package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +1 -4
  125. package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +5 -5
  126. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +19 -21
  127. package/src/plugin/runtime/PluginRuntime_Builder.res +167 -188
  128. package/src/plugin/runtime/Util_PluginMessage_Runtime.res +6 -5
  129. package/src/plugin/stack/Plugin_Stack.res +104 -103
  130. package/src/util/Util_AlarmSpec.res +2 -1
  131. package/src/util/Util_AppSync.res +8 -2
  132. package/src/util/Util_AppSync_Caller.res +15 -14
  133. package/src/util/Util_Bundle.res +46 -42
  134. package/src/util/Util_CognitoGroupUser_Runtime.res +32 -34
  135. package/src/util/Util_Cognito_Runtime.res +11 -7
  136. package/src/util/Util_DeadLetterQueue.res +12 -2
  137. package/src/util/Util_DynamoDb.res +5 -3
  138. package/src/util/Util_DynamoDbStream.res +7 -3
  139. package/src/util/Util_DynamoDbStream_Runtime.res +1 -2
  140. package/src/util/Util_DynamoDb_Runtime.res +23 -41
  141. package/src/util/Util_HostUiDomain.res +6 -1
  142. package/src/util/Util_Kinesis_Runtime.res +10 -11
  143. package/src/util/Util_Lambda.res +12 -5
  144. package/src/util/Util_LambdaEnvBudget.res +5 -5
  145. package/src/util/Util_LambdaLogging.res +1 -2
  146. package/src/util/Util_LogGroup_Adopting.res +1 -4
  147. package/src/util/Util_ResourceNaming.res +1 -2
  148. package/src/util/Util_SNS.res +8 -3
  149. package/src/util/Util_SNS_FIFO.res +1 -1
  150. package/src/util/Util_SNS_Runtime.res +11 -10
  151. package/src/util/Util_SQS.res +4 -2
  152. package/src/util/Util_SQS_FIFO.res +5 -2
  153. package/src/util/Util_SQS_Runtime.res +37 -36
  154. package/src/util/Util_ShellConfig.res +3 -2
  155. package/src/util/Util_StaticBundle.res +1 -3
  156. package/src/util/Util_StoreLayout.res +4 -1
  157. package/tests/AWS_TagsTest.res +16 -5
  158. package/tests/AppSyncEventsSigner_OpsTest.res +11 -2
  159. package/tests/AppSync_AdapterTest.res +203 -224
  160. package/tests/AppSync_Resolver_RetryingTest.res +64 -44
  161. package/tests/AppSync_RetirementNarrowingTest.res +59 -46
  162. package/tests/AppSync_SdlDecorateTest.res +22 -20
  163. package/tests/AppSync_SourceApiAssociation_RetryingTest.res +40 -22
  164. package/tests/Auth_ActiveRolePoolAttachmentTest.res +114 -107
  165. package/tests/Auth_ActiveRoleStoreTest.res +12 -9
  166. package/tests/Auth_ActiveRoleStore_SchemaTest.res +2 -1
  167. package/tests/Auth_ActiveRoleTrigger_OpsTest.res +20 -16
  168. package/tests/Auth_CognitoTest.res +31 -46
  169. package/tests/AutomationSliceEntryPoint_OpsTest.res +69 -67
  170. package/tests/BakeConvergenceTest.res +22 -25
  171. package/tests/Capability_MessagingTest.res +28 -12
  172. package/tests/CommandTopicQueuePolicyTest.res +1 -2
  173. package/tests/CounterEntryPoint_OpsTest.res +3 -7
  174. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +306 -210
  175. package/tests/EventCollectorConnectLambdaPreviewTest.res +14 -7
  176. package/tests/EventCollectorEntryPoint_OpsTest.res +12 -4
  177. package/tests/EventCollectorPluginDefinitionAssetTest.res +18 -11
  178. package/tests/EventCollectorReadyGateTest.res +5 -4
  179. package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -2
  180. package/tests/EventMapperEntryPoint_OpsTest.res +1 -3
  181. package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -4
  182. package/tests/HandlerFactoryDispatchTest.res +97 -70
  183. package/tests/MCP_LambdaTest.res +16 -27
  184. package/tests/PgChangeFeedRelay_IntegrationTest.res +123 -93
  185. package/tests/PgChangeFeedRelay_RuntimeTest.res +13 -10
  186. package/tests/PgMigrationEntryPoint_IntegrationTest.res +0 -1
  187. package/tests/PgPipeline_IntegrationTest.res +80 -66
  188. package/tests/PgQueryDbUnion_IntegrationTest.res +1 -2
  189. package/tests/PgQueryResolverEntryPoint_OpsTest.res +2 -6
  190. package/tests/PgQueryResolver_LambdaTest.res +41 -24
  191. package/tests/Platform_AdminScan_OpsTest.res +4 -1
  192. package/tests/Platform_ComponentDefinitions_Lambda_OpsTest.res +137 -129
  193. package/tests/ProjectionEntryPoint_DisplayNameTest.res +7 -3
  194. package/tests/ProjectionEntryPoint_UnionStampTest.res +3 -2
  195. package/tests/ProvisionIdentityTest.res +2 -6
  196. package/tests/QueryDbOwnerIndexTableTest.res +6 -4
  197. package/tests/QueryDbResolvers_AppSyncTest.res +23 -16
  198. package/tests/QueryInterceptor_LambdaTest.res +11 -13
  199. package/tests/ReadModelEntryPoint_OpsTest.res +43 -41
  200. package/tests/RuntimeExtensionEntryPoint_OpsTest.res +4 -3
  201. package/tests/SideEffectEntryPoint_OpsTest.res +23 -18
  202. package/tests/StateChangeDescriptorParityTest.res +28 -26
  203. package/tests/StateTopicKeySchemaTest.res +18 -15
  204. package/tests/StateViewSliceEntryPoint_OpsTest.res +55 -44
  205. package/tests/TaskBucketEntryPoint_OpsTest.res +13 -13
  206. package/tests/Upload_ClaimTest.res +3 -3
  207. package/tests/Util_AwsErrorTest.res +4 -7
  208. package/tests/Util_BundleDependencyClosureTest.res +15 -3
  209. package/tests/Util_BundleEsmLoaderTest.res +3 -3
  210. package/tests/Util_BundleResolveTest.res +4 -6
  211. package/tests/Util_BundleRuntimeExtensionTest.res +17 -18
  212. package/tests/Util_DcbMetricsTest.res +6 -6
  213. package/tests/Util_DynamoDbStreamTest.res +4 -5
  214. package/tests/Util_DynamoDbTest.res +3 -2
  215. package/tests/Util_LambdaEnvBudgetTest.res +22 -18
  216. package/tests/Util_LambdaLoggingTest.res +9 -8
  217. package/tests/Util_LogGroup_AdoptingTest.res +10 -5
  218. package/tests/Util_LogRetentionTest.res +6 -2
  219. package/tests/Util_OwnerScopeEnvTest.res +10 -8
  220. package/tests/Util_SQS_RuntimeTest.res +5 -7
  221. package/tests/Util_ShellConfigTest.res +7 -17
  222. package/tests/Util_StaticBundleTest.res +3 -8
  223. package/tests/Util_StoreLayoutTest.res +17 -12
  224. package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -4
  225. package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +15 -15
  226. package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +296 -232
  227. package/tests/integration/DcbIntegrationHarness.res +8 -8
  228. package/tests/integration/EpCompositeSlice.res +16 -8
  229. package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +8 -10
  230. package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +10 -10
  231. package/tests/integration/SvsTestSlice_Projection.res +1 -3
  232. package/tests/util/Util_AlarmSpecTest.res +62 -49
@@ -93,9 +93,9 @@ let addToRegistry = (
93
93
  | None => registry->Dict.set(sourceUrn, [handler])
94
94
  }
95
95
 
96
- let groupBySource = (
97
- records: array<PulumiAws.Lambda.CallbackFunction.record>,
98
- ): dict<array<PulumiAws.Lambda.CallbackFunction.record>> => {
96
+ let groupBySource = (records: array<PulumiAws.Lambda.CallbackFunction.record>): dict<
97
+ array<PulumiAws.Lambda.CallbackFunction.record>,
98
+ > => {
99
99
  let grouped = Dict.make()
100
100
  records->Array.forEach(record =>
101
101
  switch grouped->Dict.get(record.eventSourceARN) {
@@ -110,47 +110,42 @@ let groupBySource = (
110
110
  // handler registered for each source (independent storage, so concurrent is
111
111
  // safe). Each handler carries its own comp so the shared Lambda's log lines
112
112
  // stay separable per component.
113
- let makeRoutedHandler = (
114
- ~comp: string,
115
- registryPromise: promise<dict<array<registeredHandler>>>,
116
- ) =>
113
+ let makeRoutedHandler = (~comp: string, registryPromise: promise<dict<array<registeredHandler>>>) =>
117
114
  async (event: PulumiAws.Lambda.CallbackFunction.event, context: PulumiAws.Lambda.context) => {
118
115
  setRequestId(context.awsRequestId)
119
116
  let registry = await registryPromise
120
- let _ =
121
- await groupBySource(event.records)
122
- ->Dict.toArray
123
- ->Array.map(async ((arn, subRecords)) =>
124
- switch registry->Dict.get(arn)->Option.filter(hs => hs->Array.length > 0) {
125
- | Some(streamHandlers) =>
126
- logDebug(
127
- `found ${streamHandlers->Array.length->Int.toString} handler(s) for ${arn}`,
128
- {comp: comp},
117
+ let _ = await groupBySource(event.records)
118
+ ->Dict.toArray
119
+ ->Array.map(async ((arn, subRecords)) =>
120
+ switch registry->Dict.get(arn)->Option.filter(hs => hs->Array.length > 0) {
121
+ | Some(streamHandlers) =>
122
+ logDebug(
123
+ `found ${streamHandlers->Array.length->Int.toString} handler(s) for ${arn}`,
124
+ {comp: comp},
125
+ )
126
+ let correlationId = extractMetaField(subRecords, "correlationId")
127
+ let causationId = extractMetaField(subRecords, "causationId")
128
+ let timestamp = extractSentTimestamp(subRecords)
129
+ let retryCount = extractRetryCount(subRecords)
130
+ let subEvent: PulumiAws.Lambda.CallbackFunction.event = {records: subRecords}
131
+ let _ = await streamHandlers
132
+ ->Array.map(registered =>
133
+ runEffect(
134
+ registered.handler(subEvent, context),
135
+ {
136
+ ?correlationId,
137
+ ?causationId,
138
+ comp: ?registered.comp,
139
+ plugin: ?registered.plugin,
140
+ ?timestamp,
141
+ retryCount,
142
+ },
129
143
  )
130
- let correlationId = extractMetaField(subRecords, "correlationId")
131
- let causationId = extractMetaField(subRecords, "causationId")
132
- let timestamp = extractSentTimestamp(subRecords)
133
- let retryCount = extractRetryCount(subRecords)
134
- let subEvent: PulumiAws.Lambda.CallbackFunction.event = {records: subRecords}
135
- let _ =
136
- await streamHandlers
137
- ->Array.map(registered =>
138
- runEffect(
139
- registered.handler(subEvent, context),
140
- {
141
- correlationId: ?correlationId,
142
- causationId: ?causationId,
143
- comp: ?registered.comp,
144
- plugin: ?registered.plugin,
145
- timestamp: ?timestamp,
146
- retryCount,
147
- },
148
- )
149
- )
150
- ->Promise.all
151
- | None => logWarn("no handler found: " ++ arn, {comp: comp})
152
- }
153
- )
154
- ->Promise.all
144
+ )
145
+ ->Promise.all
146
+ | None => logWarn("no handler found: " ++ arn, {comp: comp})
147
+ }
148
+ )
149
+ ->Promise.all
155
150
  ""
156
151
  }
@@ -140,40 +140,36 @@ let dispatchTaskActions = async (
140
140
  ~publishCommands: dict<ReventlessCore.CommandTopic.publishJsons>,
141
141
  ~schedulerOps: unit => option<schedulerOps>,
142
142
  ): unit => {
143
- let _ =
144
- await actions
145
- ->Array.map(async action =>
146
- switch action {
147
- | Reventless.Task.PublishCommands(aggregateName, cmdJsons) =>
148
- switch publishCommands->Dict.get(aggregateName) {
149
- | Some(publish) => await publish(cmdJsons)
150
- | None =>
151
- logWarn(
152
- `no publish function for aggregate "${aggregateName}"`,
153
- {comp: "TaskBucketRuntime"},
154
- )
155
- }
156
- | CreateSchedule(schedule) =>
157
- switch schedulerOps() {
158
- | Some(ops) => await ops.createSchedule(schedule)
159
- | None =>
160
- logWarn(
161
- "CreateSchedule skipped — no scheduler configured for this Task (add sideEffects to setup)",
162
- {comp: "TaskBucketRuntime"},
163
- )
164
- }
165
- | DeleteSchedule(name) =>
166
- switch schedulerOps() {
167
- | Some(ops) => await ops.deleteSchedule(name)
168
- | None =>
169
- logWarn(
170
- "DeleteSchedule skipped — no scheduler configured for this Task (add sideEffects to setup)",
171
- {comp: "TaskBucketRuntime"},
172
- )
173
- }
143
+ let _ = await actions
144
+ ->Array.map(async action =>
145
+ switch action {
146
+ | Reventless.Task.PublishCommands(aggregateName, cmdJsons) =>
147
+ switch publishCommands->Dict.get(aggregateName) {
148
+ | Some(publish) => await publish(cmdJsons)
149
+ | None =>
150
+ logWarn(`no publish function for aggregate "${aggregateName}"`, {comp: "TaskBucketRuntime"})
174
151
  }
175
- )
176
- ->Promise.all
152
+ | CreateSchedule(schedule) =>
153
+ switch schedulerOps() {
154
+ | Some(ops) => await ops.createSchedule(schedule)
155
+ | None =>
156
+ logWarn(
157
+ "CreateSchedule skipped — no scheduler configured for this Task (add sideEffects to setup)",
158
+ {comp: "TaskBucketRuntime"},
159
+ )
160
+ }
161
+ | DeleteSchedule(name) =>
162
+ switch schedulerOps() {
163
+ | Some(ops) => await ops.deleteSchedule(name)
164
+ | None =>
165
+ logWarn(
166
+ "DeleteSchedule skipped — no scheduler configured for this Task (add sideEffects to setup)",
167
+ {comp: "TaskBucketRuntime"},
168
+ )
169
+ }
170
+ }
171
+ )
172
+ ->Promise.all
177
173
  }
178
174
 
179
175
  // ── Exported Lambda handler ─────────────────────────────────────────────────
@@ -187,10 +183,8 @@ let makeHandler = (~callback: ReventlessCore.Task.bucketCallback, ~config: handl
187
183
  let publishCommands = buildPublishCommands(config.publishToAggregates)
188
184
  async (event: PulumiAws.S3.Bucket.event, context: PulumiAws.Lambda.context) => {
189
185
  let actions = await handleEvents(event, context)
190
- await dispatchTaskActions(
191
- ~actions,
192
- ~publishCommands,
193
- ~schedulerOps=() => makeSchedulerOps(config.scheduler),
186
+ await dispatchTaskActions(~actions, ~publishCommands, ~schedulerOps=() =>
187
+ makeSchedulerOps(config.scheduler)
194
188
  )
195
189
  ""
196
190
  }
@@ -35,13 +35,14 @@ let forBucketCallback = (
35
35
  })
36
36
 
37
37
  // Build HANDLER_CONFIG JSON
38
- let callbackModule =
39
- callbackModulePath->JSON.stringifyAny->Option.getOr(`""`)
38
+ let callbackModule = callbackModulePath->JSON.stringifyAny->Option.getOr(`""`)
40
39
  let publishToAggregatesJson =
41
40
  publishToAggregatesEnvVars
42
41
  ->Dict.toArray
43
42
  ->Array.map(((aggName, envVar)) =>
44
- `${aggName->JSON.stringifyAny->Option.getOr(`""`)}: ${envVar->JSON.stringifyAny->Option.getOr(`""`)}`
43
+ `${aggName->JSON.stringifyAny->Option.getOr(`""`)}: ${envVar
44
+ ->JSON.stringifyAny
45
+ ->Option.getOr(`""`)}`
45
46
  )
46
47
  ->Array.join(",")
47
48
 
@@ -50,14 +51,12 @@ let forBucketCallback = (
50
51
  // runtime. None for tasks without a side-effect handler.
51
52
  let handlerConfigJson = switch schedulerConfig {
52
53
  | None =>
53
- `{"callbackModule":${callbackModule},"publishToAggregates":{${publishToAggregatesJson}}}`
54
- ->Pulumi.Output.make
54
+ `{"callbackModule":${callbackModule},"publishToAggregates":{${publishToAggregatesJson}}}`->Pulumi.Output.make
55
55
  | Some({schedulerRoleUrn, targetUrn, targetName}) =>
56
56
  envVars->Dict.set("SCHEDULER_ROLE_ARN", schedulerRoleUrn->Pulumi.Output.asInput)
57
57
  envVars->Dict.set("SCHEDULER_TARGET_ARN", targetUrn->Pulumi.Output.asInput)
58
58
  envVars->Dict.set("SCHEDULER_TARGET_NAME", targetName->Pulumi.Output.asInput)
59
- `{"callbackModule":${callbackModule},"publishToAggregates":{${publishToAggregatesJson}},"scheduler":{"roleArnEnv":"SCHEDULER_ROLE_ARN","targetArnEnv":"SCHEDULER_TARGET_ARN","targetNameEnv":"SCHEDULER_TARGET_NAME"}}`
60
- ->Pulumi.Output.make
59
+ `{"callbackModule":${callbackModule},"publishToAggregates":{${publishToAggregatesJson}},"scheduler":{"roleArnEnv":"SCHEDULER_ROLE_ARN","targetArnEnv":"SCHEDULER_TARGET_ARN","targetNameEnv":"SCHEDULER_TARGET_NAME"}}`->Pulumi.Output.make
61
60
  }
62
61
  envVars->Dict.set("HANDLER_CONFIG", handlerConfigJson->Pulumi.Output.asInput)
63
62
 
@@ -56,11 +56,9 @@ let make: ReventlessCore.Scheduler_Adapter.scheduledPublisherMaker = (~name, ~op
56
56
  ~service="CloudWatchEvents"->Pulumi.Output.make,
57
57
  ~resourceType="aws:cloudwatch:EventRule"->Pulumi.Output.make,
58
58
  ),
59
- operations: role.arn->Pulumi.Output.apply(roleArn => (
60
- {
61
- createSchedule: ScheduledPublisher_CloudWatchEvents_Runtime.createSchedule(~roleArn),
62
- deleteSchedule: ScheduledPublisher_CloudWatchEvents_Runtime.deleteSchedule,
63
- }: ReventlessInfra.Scheduler.operations
64
- )),
59
+ operations: role.arn->Pulumi.Output.apply((roleArn): ReventlessInfra.Scheduler.operations => {
60
+ createSchedule: ScheduledPublisher_CloudWatchEvents_Runtime.createSchedule(~roleArn),
61
+ deleteSchedule: ScheduledPublisher_CloudWatchEvents_Runtime.deleteSchedule,
62
+ }),
65
63
  }
66
64
  }
@@ -28,9 +28,7 @@ let createSchedule = (~roleArn: string): ReventlessCore.Scheduler.createSchedule
28
28
  | [] =>
29
29
  let err = "createSchedule not possible: no Queue configured !"
30
30
  ReventlessCore.EffectLogger.logError(~comp=__MODULE__, err)
31
- ->Effect.flatMap(_ =>
32
- Effect.sync(() => JsError.throwWithMessage(err))
33
- )
31
+ ->Effect.flatMap(_ => Effect.sync(() => JsError.throwWithMessage(err)))
34
32
  ->Effect.runPromise
35
33
  | resources =>
36
34
  let resource = resources->Array.getUnsafe(0) // FIXME
@@ -69,9 +67,7 @@ let deleteSchedule: ReventlessCore.Scheduler.deleteSchedule = (queueResources, n
69
67
  | [] =>
70
68
  let err = "deleteSchedule not possible: no Queue configured !"
71
69
  ReventlessCore.EffectLogger.logError(~comp=__MODULE__, err)
72
- ->Effect.flatMap(_ =>
73
- Effect.sync(() => JsError.throwWithMessage(err))
74
- )
70
+ ->Effect.flatMap(_ => Effect.sync(() => JsError.throwWithMessage(err)))
75
71
  ->Effect.runPromise
76
72
  | resources =>
77
73
  let resource = resources->Array.getUnsafe(0) // FIXME
@@ -126,7 +126,6 @@ let registry: dict<array<streamEntry>> = Dict.make()
126
126
  // Uses native Node.js crypto + fetch with SigV4 — no extra SDK packages needed.
127
127
  // Credentials come from the Lambda execution role via the process.env AWS_* variables.
128
128
 
129
-
130
129
  // ── Registration ──────────────────────────────────────────────────────────────
131
130
 
132
131
  /** Register any stream-enabled DynamoDB table with the relay. Read-model and
@@ -206,10 +205,7 @@ let make = (
206
205
 
207
206
  // ── Finalize: build the shared Lambda + IAM + ESMs ────────────────────────────
208
207
 
209
- let finish = (
210
- ~eventsApi: AppSync_EventsApi.t,
211
- ~opts: Pulumi.CustomResourceOptions.t,
212
- ) => {
208
+ let finish = (~eventsApi: AppSync_EventsApi.t, ~opts: Pulumi.CustomResourceOptions.t) => {
213
209
  let key = eventsApi.name
214
210
  switch registry->Dict.get(key) {
215
211
  | None => ()
@@ -231,8 +227,7 @@ let finish = (
231
227
  )
232
228
 
233
229
  // IAM policy: read from every stream + publish to the events API.
234
- let streamArnsOutput =
235
- entries->Array.map(e => e.streamArn)->Pulumi.Output.all
230
+ let streamArnsOutput = entries->Array.map(e => e.streamArn)->Pulumi.Output.all
236
231
  let _ =
237
232
  (streamArnsOutput, eventsApi.api.apiArn)
238
233
  ->Pulumi.Output.all2
@@ -306,13 +301,15 @@ let finish = (
306
301
  let dict = Dict.make()
307
302
  tableNames->Array.forEachWithIndex((tableName, i) => {
308
303
  let entry = entries->Array.getUnsafe(i)
309
- entry.retiredField->Option.forEach(f => {
310
- let obj = Dict.fromArray([("field", f->JSON.Encode.string)])
311
- entry.retiredValues->Option.forEach(vs =>
312
- obj->Dict.set("values", vs->Array.map(JSON.Encode.string)->JSON.Encode.array)
313
- )
314
- dict->Dict.set(tableName, obj->JSON.Encode.object)
315
- })
304
+ entry.retiredField->Option.forEach(
305
+ f => {
306
+ let obj = Dict.fromArray([("field", f->JSON.Encode.string)])
307
+ entry.retiredValues->Option.forEach(
308
+ vs => obj->Dict.set("values", vs->Array.map(JSON.Encode.string)->JSON.Encode.array),
309
+ )
310
+ dict->Dict.set(tableName, obj->JSON.Encode.object)
311
+ },
312
+ )
316
313
  })
317
314
  dict->JSON.Encode.object->JSON.stringify
318
315
  })
@@ -324,7 +321,10 @@ let finish = (
324
321
  // buildCodeArchive ships the ESM resolve-hook so `@rescript/runtime` and the
325
322
  // handler's bare @aws-sdk/util-dynamodb resolve from layer / managed runtime.
326
323
  let packageDirs = Dict.fromArray([
327
- ("@reventlessdev/reventless-aws", Util_Bundle.resolvePackageRoot("@reventlessdev/reventless-aws")),
324
+ (
325
+ "@reventlessdev/reventless-aws",
326
+ Util_Bundle.resolvePackageRoot("@reventlessdev/reventless-aws"),
327
+ ),
328
328
  ])
329
329
  let {code, sourceCodeHash} = Util_Bundle.buildCodeArchive(
330
330
  ~entryPointModule="@reventlessdev/reventless-aws/src/adapter/StateTopic/StateTopic_AppSync_Ops.res.mjs",
@@ -365,7 +365,12 @@ let finish = (
365
365
  memorySize: 256->Pulumi.Input.make,
366
366
  timeout: 30->Pulumi.Input.make,
367
367
  layers,
368
- tags: AWS.Tags.make(~name=name ++ "StateTopic", ~kind=ReventlessCore.QueryDb.componentType, ~role=StateTopic, ~component=name),
368
+ tags: AWS.Tags.make(
369
+ ~name=name ++ "StateTopic",
370
+ ~kind=ReventlessCore.QueryDb.componentType,
371
+ ~role=StateTopic,
372
+ ~component=name,
373
+ ),
369
374
  environment: (
370
375
  {
371
376
  Lambda.Function.variables: Dict.fromArray([
@@ -17,19 +17,21 @@
17
17
  // a core import can't drag deploy-time code into the Lambda's import graph — so
18
18
  // `StateChangeDescriptorParityTest` drives all three and asserts they agree.
19
19
 
20
-
21
20
  let endpoint = NodeProcess.env->Dict.get("APPSYNC_ENDPOINT")->Option.getOr("")
22
21
 
23
22
  // STATE_TOPIC_MAP: `{ <tableName>: <topicName> }`, injected at deploy time.
24
- let topicMap: dict<string> =
25
- switch NodeProcess.env->Dict.get("STATE_TOPIC_MAP")->Option.getOr("{}")->JSON.parseOrThrow->JSON.Decode.object {
26
- | Some(obj) =>
27
- obj
28
- ->Dict.toArray
29
- ->Array.filterMap(((k, v)) => v->JSON.Decode.string->Option.map(s => (k, s)))
30
- ->Dict.fromArray
31
- | None => Dict.make()
32
- }
23
+ let topicMap: dict<string> = switch NodeProcess.env
24
+ ->Dict.get("STATE_TOPIC_MAP")
25
+ ->Option.getOr("{}")
26
+ ->JSON.parseOrThrow
27
+ ->JSON.Decode.object {
28
+ | Some(obj) =>
29
+ obj
30
+ ->Dict.toArray
31
+ ->Array.filterMap(((k, v)) => v->JSON.Decode.string->Option.map(s => (k, s)))
32
+ ->Dict.fromArray
33
+ | None => Dict.make()
34
+ }
33
35
 
34
36
  // ── DynamoDB stream event (only the fields this handler reads) ───────────────
35
37
 
@@ -64,34 +66,35 @@ type event = {@as("Records") records: array<record>}
64
66
  // writer the other, and the two drift the first time a state name contains the
65
67
  // separator — an argument that only gets stronger now that a lifecycle can name
66
68
  // several states.
67
- let retiredMap: dict<Reventless.OwnerScope.retiredScope> =
68
- switch NodeProcess.env
69
- ->Dict.get("STATE_RETIRED_MAP")
70
- ->Option.getOr("{}")
71
- ->JSON.parseOrThrow
72
- ->JSON.Decode.object {
73
- | Some(d) =>
74
- let out = Dict.make()
75
- d->Dict.forEachWithKey((v, k) =>
76
- v
77
- ->JSON.Decode.object
78
- ->Option.flatMap(o =>
79
- o
80
- ->Dict.get("field")
81
- ->Option.flatMap(JSON.Decode.string)
82
- ->Option.map(field => {
69
+ let retiredMap: dict<Reventless.OwnerScope.retiredScope> = switch NodeProcess.env
70
+ ->Dict.get("STATE_RETIRED_MAP")
71
+ ->Option.getOr("{}")
72
+ ->JSON.parseOrThrow
73
+ ->JSON.Decode.object {
74
+ | Some(d) =>
75
+ let out = Dict.make()
76
+ d->Dict.forEachWithKey((v, k) =>
77
+ v
78
+ ->JSON.Decode.object
79
+ ->Option.flatMap(o =>
80
+ o
81
+ ->Dict.get("field")
82
+ ->Option.flatMap(JSON.Decode.string)
83
+ ->Option.map(
84
+ field => {
83
85
  Reventless.OwnerScope.field,
84
86
  values: o
85
87
  ->Dict.get("values")
86
88
  ->Option.flatMap(JSON.Decode.array)
87
89
  ->Option.map(vs => vs->Array.filterMap(JSON.Decode.string)),
88
- })
90
+ },
89
91
  )
90
- ->Option.forEach(scope => out->Dict.set(k, scope))
91
92
  )
92
- out
93
- | None => Dict.make()
94
- }
93
+ ->Option.forEach(scope => out->Dict.set(k, scope))
94
+ )
95
+ out
96
+ | None => Dict.make()
97
+ }
95
98
 
96
99
  let tableNameFromEventSourceArn = (arn: string): option<string> => {
97
100
  let parts = arn->String.split("/")
@@ -166,7 +169,8 @@ let pickSortKeyValue = (image: dict<JSON.t>): option<string> =>
166
169
  /** Cap on the serialised state payload, in characters. Must match
167
170
  `LocalStateChangeDescriptor.maxStateChars` and `StateTopicPublish.mjs`'s
168
171
  MAX_STATE_CHARS — see the local module for the reasoning. */
169
- let maxStateChars = 60 * 1024
172
+ let maxStateChars =
173
+ 60 * 1024
170
174
 
171
175
  /** Build the change descriptor. Split out of `processRecord` so the wire format
172
176
  can be asserted against the other two implementations without a network call.
@@ -3,7 +3,12 @@ type callbackEvent = PulumiAws.S3.Bucket.event
3
3
  type context = PulumiAws.Lambda.context
4
4
  type bucketParts = PulumiAws.S3.Bucket.t
5
5
 
6
- let subscribeLambda2S3Bucket = (lambda: Pulumi.Output.t<PulumiAws.Lambda.Function.t>, name, bucket, opts) => {
6
+ let subscribeLambda2S3Bucket = (
7
+ lambda: Pulumi.Output.t<PulumiAws.Lambda.Function.t>,
8
+ name,
9
+ bucket,
10
+ opts,
11
+ ) => {
7
12
  // Coerce Function.t → CallbackFunction.t for S3 bucket notification bindings
8
13
  // (structurally compatible: both have arn, id, name)
9
14
  let handler: Pulumi.Output.t<PulumiAws.Lambda.CallbackFunction.t> = lambda->Obj.magic
@@ -127,8 +127,7 @@ let finish = (
127
127
  log.warn(
128
128
  ~comp="Upload_Claim",
129
129
  `event log(s) ${logs->Array.join(", ")} declare storage-ref fields but publish through an ` ++
130
- `SNS event topic, which the claimer does not subscribe to — objects those events reference ` ++
131
- `keep the pending tag. Do not enable a store's expiry rule while this is true.`,
130
+ `SNS event topic, which the claimer does not subscribe to — objects those events reference ` ++ `keep the pending tag. Do not enable a store's expiry rule while this is true.`,
132
131
  )
133
132
  unreachable->Dict.set(plugin, [])
134
133
  | _ => ()
@@ -161,8 +160,7 @@ let finish = (
161
160
  ->Pulumi.Output.all2
162
161
  ->Pulumi.Output.apply(((streamArns, stores)) => {
163
162
  open PolicyDocument
164
- let objectArns =
165
- stores->Array.map(s => `arn:aws:s3:::${s.bucketName}/${s.servedPrefix}/*`)
163
+ let objectArns = stores->Array.map(s => `arn:aws:s3:::${s.bucketName}/${s.servedPrefix}/*`)
166
164
  let _rolePolicy = IAM.RolePolicy.make(
167
165
  ~name=name ++ "Policy",
168
166
  ~args={
@@ -226,20 +224,19 @@ let finish = (
226
224
 
227
225
  // `UPLOAD_STORES` — the same qualified-name → {bucket, prefix} shape the
228
226
  // presign service reads, so mint and claim resolve a store identically.
229
- let uploadStoresJson =
230
- stores->Pulumi.Output.apply(stores =>
231
- stores
232
- ->Array.map(s => (
233
- s.qualified,
234
- Dict.fromArray([
235
- ("bucket", JSON.Encode.string(s.bucketName)),
236
- ("prefix", JSON.Encode.string(s.servedPrefix)),
237
- ])->JSON.Encode.object,
238
- ))
239
- ->Dict.fromArray
240
- ->JSON.Encode.object
241
- ->JSON.stringify
242
- )
227
+ let uploadStoresJson = stores->Pulumi.Output.apply(stores =>
228
+ stores
229
+ ->Array.map(s => (
230
+ s.qualified,
231
+ Dict.fromArray([
232
+ ("bucket", JSON.Encode.string(s.bucketName)),
233
+ ("prefix", JSON.Encode.string(s.servedPrefix)),
234
+ ])->JSON.Encode.object,
235
+ ))
236
+ ->Dict.fromArray
237
+ ->JSON.Encode.object
238
+ ->JSON.stringify
239
+ )
243
240
 
244
241
  // Compiled EntryPoint rather than a serialized closure, for the reason the
245
242
  // presign service is one: the handler reaches the AWS SDK v3 S3 client, and
@@ -359,8 +356,8 @@ let finish = (
359
356
  ->Pulumi.Output.asInput,
360
357
  treatMissingData: "notBreaching"->Pulumi.Input.make,
361
358
  alarmDescription: (`${name} is behind on committed events. While it is behind, objects an ` ++
362
- `event already references still carry the pending tag — and a store with an expiry rule ` ++
363
- `enabled will delete them.`)->Pulumi.Input.make,
359
+ `event already references still carry the pending tag — and a store with an expiry rule ` ++ `enabled will delete them.`)
360
+ ->Pulumi.Input.make,
364
361
  tags: AWS.Tags.make(
365
362
  ~name=name ++ "Lag",
366
363
  ~kind=ReventlessCore.ComponentType.Plugin,
@@ -236,7 +236,9 @@ type event = {@as("Records") records: array<record>}
236
236
  in it. */
237
237
  let targetsOfRecord = (record: record): array<target> =>
238
238
  switch (
239
- record.eventSourceARN->tableNameFromEventSourceArn->Option.flatMap(t => refFieldsByTable->Dict.get(t)),
239
+ record.eventSourceARN
240
+ ->tableNameFromEventSourceArn
241
+ ->Option.flatMap(t => refFieldsByTable->Dict.get(t)),
240
242
  record.dynamodb->Option.flatMap(d => d.newImage),
241
243
  ) {
242
244
  | (Some(byEventType), Some(image)) =>
@@ -269,7 +271,8 @@ let targetsOfRecord = (record: record): array<target> =>
269
271
  let handler = async (event: event): unit => {
270
272
  // An append-only log only ever inserts events; MODIFY rows are fence and
271
273
  // snapshot updates, which `targetsOfRecord` would drop anyway.
272
- let targets = event.records->Array.filter(r => r.eventName == "INSERT")->Array.flatMap(targetsOfRecord)
274
+ let targets =
275
+ event.records->Array.filter(r => r.eventName == "INSERT")->Array.flatMap(targetsOfRecord)
273
276
  // Sequential: a batch carries a handful of refs at most, and a failure must
274
277
  // reach the ESM as a throw so the record is retried rather than silently
275
278
  // leaving an object tagged.
@@ -111,58 +111,60 @@ let make = (
111
111
  // presigned request runs with the *signer's* permissions, so tag-on-put fails
112
112
  // with AccessDenied without it — and an untagged object is one the sweep can
113
113
  // never reach.
114
- let _policy =
115
- resolvedStores->Pulumi.Output.apply(list => {
116
- let arns = list->Array.map(((_, bucket, prefix)) => `arn:aws:s3:::${bucket}/${prefix}/*`)
117
- let _ = IAM.RolePolicy.make(
118
- ~name=name ++ "LambdaPolicy",
119
- ~args={
120
- policy: PolicyDocument.make(
121
- ~id=name ++ "LambdaPolicy",
122
- ~statements=[
123
- {
124
- sid: "AllowLambdaLogging",
125
- effect: Allow,
126
- actions: Actions(["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]),
127
- resources: Resource("arn:aws:logs:*:*:*"),
128
- },
129
- {
130
- sid: "AllowUploadObjectAccess",
131
- effect: Allow,
132
- actions: Actions([
133
- "s3:PutObject",
134
- "s3:PutObjectTagging",
135
- "s3:DeleteObject",
136
- "s3:GetObject",
137
- ]),
138
- resources: Resources(arns),
139
- },
140
- ],
141
- )
142
- ->PolicyDocument.toJsonString
143
- ->Pulumi.Input.make,
144
- role: lambdaRole.id->Pulumi.Output.asInput,
145
- },
146
- ~opts,
147
- )
148
- })
114
+ let _policy = resolvedStores->Pulumi.Output.apply(list => {
115
+ let arns = list->Array.map(((_, bucket, prefix)) => `arn:aws:s3:::${bucket}/${prefix}/*`)
116
+ let _ = IAM.RolePolicy.make(
117
+ ~name=name ++ "LambdaPolicy",
118
+ ~args={
119
+ policy: PolicyDocument.make(
120
+ ~id=name ++ "LambdaPolicy",
121
+ ~statements=[
122
+ {
123
+ sid: "AllowLambdaLogging",
124
+ effect: Allow,
125
+ actions: Actions([
126
+ "logs:CreateLogGroup",
127
+ "logs:CreateLogStream",
128
+ "logs:PutLogEvents",
129
+ ]),
130
+ resources: Resource("arn:aws:logs:*:*:*"),
131
+ },
132
+ {
133
+ sid: "AllowUploadObjectAccess",
134
+ effect: Allow,
135
+ actions: Actions([
136
+ "s3:PutObject",
137
+ "s3:PutObjectTagging",
138
+ "s3:DeleteObject",
139
+ "s3:GetObject",
140
+ ]),
141
+ resources: Resources(arns),
142
+ },
143
+ ],
144
+ )
145
+ ->PolicyDocument.toJsonString
146
+ ->Pulumi.Input.make,
147
+ role: lambdaRole.id->Pulumi.Output.asInput,
148
+ },
149
+ ~opts,
150
+ )
151
+ })
149
152
 
150
153
  // `UPLOAD_STORES` — the qualified-name → {bucket, prefix} map the handler resolves
151
154
  // the caller's `store` argument against.
152
- let uploadStoresJson =
153
- resolvedStores->Pulumi.Output.apply(list =>
154
- list
155
- ->Array.map(((qualified, bucket, prefix)) => (
156
- qualified,
157
- Dict.fromArray([
158
- ("bucket", JSON.Encode.string(bucket)),
159
- ("prefix", JSON.Encode.string(prefix)),
160
- ])->JSON.Encode.object,
161
- ))
162
- ->Dict.fromArray
163
- ->JSON.Encode.object
164
- ->JSON.stringify
165
- )
155
+ let uploadStoresJson = resolvedStores->Pulumi.Output.apply(list =>
156
+ list
157
+ ->Array.map(((qualified, bucket, prefix)) => (
158
+ qualified,
159
+ Dict.fromArray([
160
+ ("bucket", JSON.Encode.string(bucket)),
161
+ ("prefix", JSON.Encode.string(prefix)),
162
+ ])->JSON.Encode.object,
163
+ ))
164
+ ->Dict.fromArray
165
+ ->JSON.Encode.object
166
+ ->JSON.stringify
167
+ )
166
168
 
167
169
  // Bundle reventless-aws (the compiled `_Ops` handler lives inside it) and
168
170
  // re-export its `handler`; buildCodeArchive also ships the ESM resolve-hook.