@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.
- package/CHANGELOG.md +1564 -0
- package/README.md +62 -0
- package/__mocks__/emptyModule.js +1 -0
- package/all-licenses.csv +565 -0
- package/docker-compose.dynamodb-local.yml +12 -0
- package/jest.setup.cjs +5 -0
- package/licenses-analysis.ods +0 -0
- package/package.json +73 -0
- package/rescript.json +39 -0
- package/reventless-licenses-analysis.xls +0 -0
- package/scripts/run-integration-tests.sh +43 -0
- package/src/Platform.res +1940 -0
- package/src/Platform.res.mjs +2281 -0
- package/src/Platform_Casts.res +106 -0
- package/src/Platform_Casts.res.mjs +13 -0
- package/src/Platform_Stack.res +153 -0
- package/src/Platform_Stack.res.mjs +121 -0
- package/src/Types.res +39 -0
- package/src/Types.res.mjs +21 -0
- package/src/adapter/AWS.res +96 -0
- package/src/adapter/AWS.res.mjs +186 -0
- package/src/adapter/AWS_Tags.res +16 -0
- package/src/adapter/AWS_Tags.res.mjs +48 -0
- package/src/adapter/Adapter_Helpers.res +19 -0
- package/src/adapter/Adapter_Helpers.res.mjs +37 -0
- package/src/adapter/Api/AppSync_EventsApi.res +172 -0
- package/src/adapter/Api/AppSync_EventsApi.res.mjs +96 -0
- package/src/adapter/Api/AppSync_Resolver_Native.res +93 -0
- package/src/adapter/Api/AppSync_Resolver_Native.res.mjs +67 -0
- package/src/adapter/Api/AppSync_Resolver_Retrying.res +653 -0
- package/src/adapter/Api/AppSync_Resolver_Retrying.res.mjs +462 -0
- package/src/adapter/Api/CommandSubscriptionResolvers_AppSync.res +29 -0
- package/src/adapter/Api/CommandSubscriptionResolvers_AppSync.res.mjs +15 -0
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +238 -0
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +179 -0
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +229 -0
- package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +245 -0
- package/src/adapter/Auth/Auth_Cognito.res +209 -0
- package/src/adapter/Auth/Auth_Cognito.res.mjs +135 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers.res +2 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers.res.mjs +12 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +251 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res.mjs +126 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +20 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res.mjs +23 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_Runtime.res +1 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_Runtime.res.mjs +11 -0
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +95 -0
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res.mjs +50 -0
- package/src/adapter/CommandTopic/CommandTopicChannel.res +6 -0
- package/src/adapter/CommandTopic/CommandTopicChannel.res.mjs +21 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_Helpers.res +196 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_Helpers.res.mjs +145 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +91 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res.mjs +74 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +69 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res.mjs +62 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +60 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res.mjs +56 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +73 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs +65 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +88 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res.mjs +76 -0
- package/src/adapter/CommandTopic/CommandTopicRemoteChannel.res +1 -0
- package/src/adapter/CommandTopic/CommandTopicRemoteChannel.res.mjs +9 -0
- package/src/adapter/CommandTopic/CommandTopicRemoteChannel_SQS.res +7 -0
- package/src/adapter/CommandTopic/CommandTopicRemoteChannel_SQS.res.mjs +17 -0
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +103 -0
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res.mjs +68 -0
- package/src/adapter/Counter/CounterHandler_DynamoDbStream_Runtime.res +107 -0
- package/src/adapter/Counter/CounterHandler_DynamoDbStream_Runtime.res.mjs +145 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage.res +1 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage.res.mjs +9 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +84 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res.mjs +52 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +1436 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +1143 -0
- package/src/adapter/EventCollector/EventCollectorChannel.res +6 -0
- package/src/adapter/EventCollector/EventCollectorChannel.res.mjs +21 -0
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +63 -0
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res.mjs +56 -0
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream_Runtime.res +20 -0
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream_Runtime.res.mjs +32 -0
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +266 -0
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res.mjs +166 -0
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +81 -0
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res.mjs +54 -0
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +59 -0
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res.mjs +45 -0
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +91 -0
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res.mjs +89 -0
- package/src/adapter/EventLog/EventLogStorage.res +3 -0
- package/src/adapter/EventLog/EventLogStorage.res.mjs +15 -0
- package/src/adapter/EventLog/EventLogStorage_DynamoDb.res +25 -0
- package/src/adapter/EventLog/EventLogStorage_DynamoDb.res.mjs +34 -0
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +26 -0
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res.mjs +35 -0
- package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +121 -0
- package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res.mjs +137 -0
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +265 -0
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +185 -0
- package/src/adapter/EventTopic/EventTopicPublisher.res +6 -0
- package/src/adapter/EventTopic/EventTopicPublisher.res.mjs +21 -0
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +25 -0
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res.mjs +28 -0
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +40 -0
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res.mjs +39 -0
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +39 -0
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res.mjs +38 -0
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -0
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res.mjs +18 -0
- package/src/adapter/Mcp/MCP_Lambda.res +502 -0
- package/src/adapter/Mcp/MCP_Lambda.res.mjs +289 -0
- package/src/adapter/QueryDb/NodeResolver_AppSync.res +71 -0
- package/src/adapter/QueryDb/NodeResolver_AppSync.res.mjs +44 -0
- package/src/adapter/QueryDb/QueryDbResolvers.res +2 -0
- package/src/adapter/QueryDb/QueryDbResolvers.res.mjs +12 -0
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +434 -0
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res.mjs +243 -0
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync_NoOp.res +21 -0
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync_NoOp.res.mjs +14 -0
- package/src/adapter/QueryDb/QueryDbResolvers_NoOp.res +21 -0
- package/src/adapter/QueryDb/QueryDbResolvers_NoOp.res.mjs +14 -0
- package/src/adapter/QueryDb/QueryDbStorage.res +5 -0
- package/src/adapter/QueryDb/QueryDbStorage.res.mjs +18 -0
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +115 -0
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res.mjs +100 -0
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +52 -0
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res.mjs +38 -0
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +271 -0
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res.mjs +306 -0
- package/src/adapter/QueryDb/QueryInterceptor_Lambda.res +20 -0
- package/src/adapter/QueryDb/QueryInterceptor_Lambda.res.mjs +22 -0
- package/src/adapter/QueryEngine/QueryEngine.res +3 -0
- package/src/adapter/QueryEngine/QueryEngine.res.mjs +12 -0
- package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +184 -0
- package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res.mjs +221 -0
- package/src/adapter/Runtime/AdminEventCollectorEntryPoint.mjs +879 -0
- package/src/adapter/Runtime/AggregateEntryPoint.mjs +313 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +327 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res.mjs +239 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +331 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res.mjs +240 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +247 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res.mjs +185 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +244 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res.mjs +185 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +347 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res.mjs +244 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +285 -0
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res.mjs +212 -0
- package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +124 -0
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +187 -0
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +147 -0
- package/src/adapter/Runtime/CounterEntryPoint.mjs +91 -0
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +265 -0
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +122 -0
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res.mjs +89 -0
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +193 -0
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res.mjs +137 -0
- package/src/adapter/Runtime/EventMapperEntryPoint.mjs +97 -0
- package/src/adapter/Runtime/ExtensionPointEntryPoint.mjs +101 -0
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +83 -0
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res.mjs +59 -0
- package/src/adapter/Runtime/HandlerFactoryHelpers.mjs +142 -0
- package/src/adapter/Runtime/HeartbeatEntryPoint.mjs +38 -0
- package/src/adapter/Runtime/PluginExtensionPointEntryPoint.mjs +137 -0
- package/src/adapter/Runtime/ReadModelEntryPoint.mjs +143 -0
- package/src/adapter/Runtime/RuntimeEnvironment.res +1 -0
- package/src/adapter/Runtime/RuntimeEnvironment.res.mjs +9 -0
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +254 -0
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +169 -0
- package/src/adapter/Runtime/SideEffectEntryPoint.mjs +81 -0
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +178 -0
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res.mjs +129 -0
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +166 -0
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res.mjs +87 -0
- package/src/adapter/Runtime/StateViewSliceEntryPoint.mjs +136 -0
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +344 -0
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res.mjs +242 -0
- package/src/adapter/Runtime/TaskBucketEntryPoint.mjs +150 -0
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +123 -0
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res.mjs +74 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher.res +2 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher.res.mjs +12 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +54 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res.mjs +41 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +97 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res.mjs +85 -0
- package/src/adapter/StateTopic/StateTopic_AppSync.res +418 -0
- package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +295 -0
- package/src/adapter/Task/TaskBucket.res +1 -0
- package/src/adapter/Task/TaskBucket.res.mjs +9 -0
- package/src/adapter/Task/TaskBucket_S3.res +157 -0
- package/src/adapter/Task/TaskBucket_S3.res.mjs +108 -0
- package/src/adapter/Task/TaskBucket_S3_Runtime.res +11 -0
- package/src/adapter/Task/TaskBucket_S3_Runtime.res.mjs +15 -0
- package/src/components/Aggregate_Builder.res +1 -0
- package/src/components/Aggregate_Builder.res.mjs +25 -0
- package/src/components/Aggregate_Builder_Micro.res +63 -0
- package/src/components/Aggregate_Builder_Micro.res.mjs +80 -0
- package/src/components/Aggregate_Builder_NoResolver.res +61 -0
- package/src/components/Aggregate_Builder_NoResolver.res.mjs +80 -0
- package/src/components/Aggregate_Builder_PerAggregate.res +57 -0
- package/src/components/Aggregate_Builder_PerAggregate.res.mjs +80 -0
- package/src/components/Aggregate_Builder_Single.res +59 -0
- package/src/components/Aggregate_Builder_Single.res.mjs +80 -0
- package/src/components/Aggregate_Builder_Single_Async.res +59 -0
- package/src/components/Aggregate_Builder_Single_Async.res.mjs +80 -0
- package/src/components/Api/AppSync_Adapter.res +500 -0
- package/src/components/Api/AppSync_Adapter.res.mjs +396 -0
- package/src/components/AutomationSlice_Builder.res +52 -0
- package/src/components/AutomationSlice_Builder.res.mjs +72 -0
- package/src/components/AutomationSlice_Builder_Bundled.res.mjs +70 -0
- package/src/components/Counter_Builder.res +10 -0
- package/src/components/Counter_Builder.res.mjs +16 -0
- package/src/components/DataCleaner.res +170 -0
- package/src/components/DataCleaner.res.mjs +2 -0
- package/src/components/DcbEventLog_Builder.res +8 -0
- package/src/components/DcbEventLog_Builder.res.mjs +14 -0
- package/src/components/ExtensionPoint_Builder.res +16 -0
- package/src/components/ExtensionPoint_Builder.res.mjs +37 -0
- package/src/components/ForeignReadModel_Builder.res +19 -0
- package/src/components/ForeignReadModel_Builder.res.mjs +48 -0
- package/src/components/InboundTranslationSlice_Builder.res +25 -0
- package/src/components/InboundTranslationSlice_Builder.res.mjs +31 -0
- package/src/components/OutboundTranslationSlice_Builder.res +60 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +76 -0
- package/src/components/OutboundTranslationSlice_Builder_Bundled.res.mjs +75 -0
- package/src/components/Plugin.res +29 -0
- package/src/components/Plugin.res.mjs +63 -0
- package/src/components/ReadModel_Builder.res +1 -0
- package/src/components/ReadModel_Builder.res.mjs +19 -0
- package/src/components/ReadModel_Builder_NoResolver.res +55 -0
- package/src/components/ReadModel_Builder_NoResolver.res.mjs +64 -0
- package/src/components/ReadModel_Builder_NoResolver_Stream.res +60 -0
- package/src/components/ReadModel_Builder_NoResolver_Stream.res.mjs +64 -0
- package/src/components/ReadModel_Builder_PerReadModel.res +53 -0
- package/src/components/ReadModel_Builder_PerReadModel.res.mjs +66 -0
- package/src/components/ReadModel_Builder_Single.res +52 -0
- package/src/components/ReadModel_Builder_Single.res.mjs +66 -0
- package/src/components/ReadModel_Builder_Single_Stream.res +60 -0
- package/src/components/ReadModel_Builder_Single_Stream.res.mjs +66 -0
- package/src/components/Scheduler.res +1 -0
- package/src/components/Scheduler.res.mjs +13 -0
- package/src/components/SideEffectHandler.res +1 -0
- package/src/components/SideEffectHandler.res.mjs +19 -0
- package/src/components/SideEffectHandler_PerSideEffectHandler.res +13 -0
- package/src/components/SideEffectHandler_PerSideEffectHandler.res.mjs +52 -0
- package/src/components/SideEffectHandler_Single.res +54 -0
- package/src/components/SideEffectHandler_Single.res.mjs +60 -0
- package/src/components/StateChangeSlice_Builder.res +17 -0
- package/src/components/StateChangeSlice_Builder.res.mjs +23 -0
- package/src/components/StateViewSlice_Builder.res +46 -0
- package/src/components/StateViewSlice_Builder.res.mjs +68 -0
- package/src/components/StateViewSlice_Builder_Bundled.res.mjs +69 -0
- package/src/components/StateViewSlice_Builder_Stream.res +50 -0
- package/src/components/StateViewSlice_Builder_Stream.res.mjs +68 -0
- package/src/components/Task_Builder.res +1 -0
- package/src/components/Task_Builder.res.mjs +28 -0
- package/src/components/Task_Builder_PerBucket.res +22 -0
- package/src/components/Task_Builder_PerBucket.res.mjs +63 -0
- package/src/components/Vpc.res +214 -0
- package/src/components/Vpc.res.mjs +117 -0
- package/src/components/Vpc.resi +22 -0
- package/src/errors/AppSync_Error.res +36 -0
- package/src/errors/AppSync_Error.res.mjs +38 -0
- package/src/errors/Cognito_Error.res +36 -0
- package/src/errors/Cognito_Error.res.mjs +38 -0
- package/src/errors/DynamoDb_Error.res +75 -0
- package/src/errors/DynamoDb_Error.res.mjs +86 -0
- package/src/errors/Kinesis_Error.res +36 -0
- package/src/errors/Kinesis_Error.res.mjs +38 -0
- package/src/errors/SNS_Error.res +34 -0
- package/src/errors/SNS_Error.res.mjs +38 -0
- package/src/errors/SQS_Error.res +40 -0
- package/src/errors/SQS_Error.res.mjs +41 -0
- package/src/plugin/cloner/ClonerRunner.res +1 -0
- package/src/plugin/cloner/ClonerRunner.res.mjs +9 -0
- package/src/plugin/cloner/ClonerRunner_Fargate.res +362 -0
- package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +246 -0
- package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +42 -0
- package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res.mjs +45 -0
- package/src/plugin/heartbeat/HeartbeatRunner.res +1 -0
- package/src/plugin/heartbeat/HeartbeatRunner.res.mjs +9 -0
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +96 -0
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res.mjs +69 -0
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +115 -0
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res.mjs +88 -0
- package/src/plugin/runtime/PluginRuntimeOperations.res +5 -0
- package/src/plugin/runtime/PluginRuntimeOperations.res.mjs +14 -0
- package/src/plugin/runtime/PluginRuntime_Builder.res +769 -0
- package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +464 -0
- package/src/plugin/runtime/Util_PluginMessage_Runtime.res +13 -0
- package/src/plugin/runtime/Util_PluginMessage_Runtime.res.mjs +19 -0
- package/src/plugin/stack/Plugin_ExtensionPoint_Builder.res +28 -0
- package/src/plugin/stack/Plugin_ExtensionPoint_Builder.res.mjs +67 -0
- package/src/plugin/stack/Plugin_Stack.res +439 -0
- package/src/plugin/stack/Plugin_Stack.res.mjs +263 -0
- package/src/util/Util.res +29 -0
- package/src/util/Util.res.mjs +93 -0
- package/src/util/Util_AppSync.res +36 -0
- package/src/util/Util_AppSync.res.mjs +35 -0
- package/src/util/Util_AppSync_Caller.res +213 -0
- package/src/util/Util_AppSync_Caller.res.mjs +170 -0
- package/src/util/Util_Bundle.res +255 -0
- package/src/util/Util_Bundle.res.mjs +179 -0
- package/src/util/Util_Cloudwatch.res +14 -0
- package/src/util/Util_Cloudwatch.res.mjs +19 -0
- package/src/util/Util_CognitoGroupUser.res +39 -0
- package/src/util/Util_CognitoGroupUser.res.mjs +32 -0
- package/src/util/Util_CognitoGroupUser_Runtime.res +65 -0
- package/src/util/Util_CognitoGroupUser_Runtime.res.mjs +50 -0
- package/src/util/Util_Cognito_Runtime.res +52 -0
- package/src/util/Util_Cognito_Runtime.res.mjs +35 -0
- package/src/util/Util_DeadLetterQueue.res +154 -0
- package/src/util/Util_DeadLetterQueue.res.mjs +158 -0
- package/src/util/Util_DynamoDb.res +210 -0
- package/src/util/Util_DynamoDb.res.mjs +218 -0
- package/src/util/Util_DynamoDbStream.res +138 -0
- package/src/util/Util_DynamoDbStream.res.mjs +134 -0
- package/src/util/Util_DynamoDbStream_Runtime.res +94 -0
- package/src/util/Util_DynamoDbStream_Runtime.res.mjs +131 -0
- package/src/util/Util_DynamoDb_Runtime.res +216 -0
- package/src/util/Util_DynamoDb_Runtime.res.mjs +257 -0
- package/src/util/Util_DynamoDb_TableManager.res +23 -0
- package/src/util/Util_DynamoDb_TableManager.res.mjs +35 -0
- package/src/util/Util_DynamoDb_TableManager.resi +3 -0
- package/src/util/Util_Env.res +5 -0
- package/src/util/Util_Env.res.mjs +2 -0
- package/src/util/Util_EventSourceMapping.res +49 -0
- package/src/util/Util_EventSourceMapping.res.mjs +32 -0
- package/src/util/Util_HostUiDomain.res +28 -0
- package/src/util/Util_HostUiDomain.res.mjs +26 -0
- package/src/util/Util_IAM_Role.res +14 -0
- package/src/util/Util_IAM_Role.res.mjs +28 -0
- package/src/util/Util_Kinesis_Runtime.res +20 -0
- package/src/util/Util_Kinesis_Runtime.res.mjs +24 -0
- package/src/util/Util_Lambda.res +39 -0
- package/src/util/Util_Lambda.res.mjs +45 -0
- package/src/util/Util_LocalConfig.res +119 -0
- package/src/util/Util_LocalConfig.res.mjs +112 -0
- package/src/util/Util_ResourceNaming.res +15 -0
- package/src/util/Util_ResourceNaming.res.mjs +26 -0
- package/src/util/Util_S3.res +17 -0
- package/src/util/Util_S3.res.mjs +30 -0
- package/src/util/Util_S3_Runtime.res +11 -0
- package/src/util/Util_S3_Runtime.res.mjs +15 -0
- package/src/util/Util_SNS.res +33 -0
- package/src/util/Util_SNS.res.mjs +50 -0
- package/src/util/Util_SNS_FIFO.res +21 -0
- package/src/util/Util_SNS_FIFO.res.mjs +27 -0
- package/src/util/Util_SNS_Runtime.res +33 -0
- package/src/util/Util_SNS_Runtime.res.mjs +27 -0
- package/src/util/Util_SQS.res +70 -0
- package/src/util/Util_SQS.res.mjs +83 -0
- package/src/util/Util_SQS_FIFO.res +16 -0
- package/src/util/Util_SQS_FIFO.res.mjs +28 -0
- package/src/util/Util_SQS_Runtime.res +169 -0
- package/src/util/Util_SQS_Runtime.res.mjs +150 -0
- package/src/util/Util_SesPolicy_Runtime.res +54 -0
- package/src/util/Util_SesPolicy_Runtime.res.mjs +55 -0
- package/src/util/Util_StaticBundle.res +124 -0
- package/src/util/Util_StaticBundle.res.mjs +132 -0
- package/src/util/Util_Vpc.res +22 -0
- package/src/util/Util_Vpc.res.mjs +27 -0
- package/tests/AppSync_AdapterTest.res +396 -0
- package/tests/AppSync_AdapterTest.res.mjs +326 -0
- package/tests/AppSync_Resolver_RetryingTest.res +59 -0
- package/tests/AppSync_Resolver_RetryingTest.res.mjs +66 -0
- package/tests/Auth_CognitoTest.res +203 -0
- package/tests/Auth_CognitoTest.res.mjs +248 -0
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +602 -0
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res.mjs +742 -0
- package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +57 -0
- package/tests/EventLogStorage_DynamoDb_RuntimeTest.res.mjs +68 -0
- package/tests/MCP_LambdaTest.res +101 -0
- package/tests/MCP_LambdaTest.res.mjs +56 -0
- package/tests/Util_HostUiDomainTest.res +90 -0
- package/tests/Util_HostUiDomainTest.res.mjs +50 -0
- package/tests/Util_SQS_RuntimeTest.res +46 -0
- package/tests/Util_SQS_RuntimeTest.res.mjs +45 -0
- package/tests/Util_StaticBundleTest.res +136 -0
- package/tests/Util_StaticBundleTest.res.mjs +149 -0
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +101 -0
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res.mjs +91 -0
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +315 -0
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res.mjs +435 -0
- package/tests/integration/DcbIntegrationHarness.res +102 -0
- package/tests/integration/DcbIntegrationHarness.res.mjs +163 -0
- package/tests/integration/EpTestSlice.res +28 -0
- package/tests/integration/EpTestSlice.res.mjs +43 -0
- package/tests/integration/EpTestSliceBehavior.res +18 -0
- package/tests/integration/EpTestSliceBehavior.res.mjs +35 -0
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
let log = ReventlessCore.Logger.fromEnv()
|
|
2
|
+
|
|
3
|
+
type adminConfig = {
|
|
4
|
+
eventTopicArn: option<Pulumi.Output.t<string>>,
|
|
5
|
+
pluginReadModelTableName: option<Pulumi.Output.t<string>>,
|
|
6
|
+
// Dedicated PluginSchemaPersistence table holding deploy-time SDL fragments
|
|
7
|
+
// (rows keyed "deploy-schema:<name>"). The runtime schema stitch reads this
|
|
8
|
+
// durable source instead of the lifecycle-volatile Plugin RM Connected rows.
|
|
9
|
+
pluginSchemaPersistenceTableName: option<Pulumi.Output.t<string>>,
|
|
10
|
+
schedulerRoleArn: option<Pulumi.Output.t<string>>,
|
|
11
|
+
schedulerQueueArn: option<Pulumi.Output.t<string>>,
|
|
12
|
+
schedulerQueueName: option<Pulumi.Output.t<string>>,
|
|
13
|
+
appSyncApiId: option<Pulumi.Output.t<string>>,
|
|
14
|
+
clonerEnabled: bool,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let configRef: ref<adminConfig> = ref({
|
|
18
|
+
eventTopicArn: None,
|
|
19
|
+
pluginReadModelTableName: None,
|
|
20
|
+
pluginSchemaPersistenceTableName: None,
|
|
21
|
+
schedulerRoleArn: None,
|
|
22
|
+
schedulerQueueArn: None,
|
|
23
|
+
schedulerQueueName: None,
|
|
24
|
+
appSyncApiId: None,
|
|
25
|
+
clonerEnabled: false,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
type sliceModulePaths = {
|
|
29
|
+
specPath: string,
|
|
30
|
+
behaviorPath: string,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type dcbConfig = {
|
|
34
|
+
pluginName: string,
|
|
35
|
+
dcbTableName: option<Pulumi.Output.t<string>>,
|
|
36
|
+
stateChangeSliceModulePaths: array<sliceModulePaths>,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let dcbConfigRef: ref<dcbConfig> = ref({
|
|
40
|
+
pluginName: "",
|
|
41
|
+
dcbTableName: None,
|
|
42
|
+
stateChangeSliceModulePaths: [],
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
let registeredSliceModulePaths: array<sliceModulePaths> = []
|
|
46
|
+
|
|
47
|
+
let registerStateChangeSliceSpec = (~specPath: string, ~behaviorPath: string) => {
|
|
48
|
+
let _ = registeredSliceModulePaths->Array.push({specPath, behaviorPath})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let registerDcbConfig = (~pluginName, ~dcbTableName=?, ~stateChangeSliceModulePaths=[], ()) => {
|
|
52
|
+
dcbConfigRef := {pluginName, dcbTableName, stateChangeSliceModulePaths}
|
|
53
|
+
stateChangeSliceModulePaths->Array.length
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let registerDcbTableName = (dcbTableName: Pulumi.Output.t<string>) =>
|
|
57
|
+
dcbConfigRef := {...dcbConfigRef.contents, dcbTableName: Some(dcbTableName)}
|
|
58
|
+
|
|
59
|
+
type heartbeatConfig = {
|
|
60
|
+
pluginId: string,
|
|
61
|
+
heartbeatTimeout: int,
|
|
62
|
+
epQueueUrl: option<Pulumi.Output.t<string>>,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let heartbeatConfigRef: ref<heartbeatConfig> = ref({
|
|
66
|
+
pluginId: "",
|
|
67
|
+
heartbeatTimeout: 10,
|
|
68
|
+
epQueueUrl: None,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
let registerHeartbeatConfig = (~pluginId, ~heartbeatTimeout=10, ~epQueueUrl=?, ()) =>
|
|
72
|
+
heartbeatConfigRef := {pluginId, heartbeatTimeout, epQueueUrl}
|
|
73
|
+
|
|
74
|
+
// Per-flavor commandHandlerConfig override for the two DCB command-handler Lambdas
|
|
75
|
+
// (`<Plugin>DcbCmdHandler` sync / `<Plugin>DcbAsyncCmdHandler` async); populated by
|
|
76
|
+
// Platform.MakeWithConfig from `commandHandlerConfig.stateChanges.{sync,async}`.
|
|
77
|
+
let syncStateChangesConfigRef: ref<ReventlessCore.Runtime.commandHandlerConfig> = ref(
|
|
78
|
+
({}: ReventlessCore.Runtime.commandHandlerConfig),
|
|
79
|
+
)
|
|
80
|
+
let asyncStateChangesConfigRef: ref<ReventlessCore.Runtime.commandHandlerConfig> = ref(
|
|
81
|
+
({}: ReventlessCore.Runtime.commandHandlerConfig),
|
|
82
|
+
)
|
|
83
|
+
let setStateChangesConfig = (~sync=?, ~async=?, ()) => {
|
|
84
|
+
sync->Option.forEach(c => syncStateChangesConfigRef := c)
|
|
85
|
+
async->Option.forEach(c => asyncStateChangesConfigRef := c)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let registerConfig = (
|
|
89
|
+
~eventTopicArn=?,
|
|
90
|
+
~pluginReadModelTableName=?,
|
|
91
|
+
~pluginSchemaPersistenceTableName=?,
|
|
92
|
+
~schedulerRoleArn=?,
|
|
93
|
+
~schedulerQueueArn=?,
|
|
94
|
+
~schedulerQueueName=?,
|
|
95
|
+
~appSyncApiId=?,
|
|
96
|
+
~clonerEnabled=false,
|
|
97
|
+
(),
|
|
98
|
+
) =>
|
|
99
|
+
configRef := {
|
|
100
|
+
eventTopicArn,
|
|
101
|
+
pluginReadModelTableName,
|
|
102
|
+
pluginSchemaPersistenceTableName,
|
|
103
|
+
schedulerRoleArn,
|
|
104
|
+
schedulerQueueArn,
|
|
105
|
+
schedulerQueueName,
|
|
106
|
+
appSyncApiId,
|
|
107
|
+
clonerEnabled,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// PluginRuntime_Builder is a functor so that the caller can inject the EventCollectorChannel
|
|
111
|
+
// implementation. All other runtime builders hardcode EventCollectorChannel.DynamoDbStream, but
|
|
112
|
+
// the Plugin admin handler (AdminEventCollectorEntryPoint) is shared across DCB and aggregate
|
|
113
|
+
// plugins which may use different event log backends. The functor keeps the builder generic
|
|
114
|
+
// while the concrete instantiation picks the right channel at the platform level.
|
|
115
|
+
module Make = (
|
|
116
|
+
EventCollectorChannel: ReventlessCore.EventCollector_Adapter.Channel
|
|
117
|
+
with type runtimeParts = Util.Lambda.runtimeParts,
|
|
118
|
+
): (
|
|
119
|
+
ReventlessCore.PluginRuntime_Builder.T
|
|
120
|
+
with type context = PulumiAws.Lambda.context
|
|
121
|
+
and type runtimeParts = Util.Lambda.runtimeParts
|
|
122
|
+
and module EventCollectorChannel = EventCollectorChannel
|
|
123
|
+
) => {
|
|
124
|
+
type context = PulumiAws.Lambda.context
|
|
125
|
+
type runtimeParts = Util.Lambda.runtimeParts
|
|
126
|
+
module EventCollectorChannel = EventCollectorChannel
|
|
127
|
+
|
|
128
|
+
let registerPluginName = (pluginName: string) =>
|
|
129
|
+
dcbConfigRef := {...dcbConfigRef.contents, pluginName}
|
|
130
|
+
|
|
131
|
+
let outputOrPlaceholder = opt =>
|
|
132
|
+
switch opt {
|
|
133
|
+
| Some(v) => v->Pulumi.Output.asInput
|
|
134
|
+
| None => "NOT_AVAILABLE"->Pulumi.Output.make->Pulumi.Output.asInput
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Synthesises an admin-flavoured eventCollectorContext when no plugin context
|
|
138
|
+
// is registered for this EventCollector. The admin Lambda processes outgoing
|
|
139
|
+
// events of its own Plugin ExtensionPoint and does not consume the auto-
|
|
140
|
+
// included Connect extension (it IS the Plugin EP). The fake pluginDefinition
|
|
141
|
+
// keeps the JSON shape consistent so the entry point can parse uniformly.
|
|
142
|
+
let synthesizeAdminContext = (): ReventlessCore.Plugin_Helpers.eventCollectorContext => {
|
|
143
|
+
let config = configRef.contents
|
|
144
|
+
// Stable JSON literal — matches Reventless.Plugin.pluginDefinitionSchema
|
|
145
|
+
// (optional fields encoded as null via js_nullable).
|
|
146
|
+
let fakePluginDefinitionJson =
|
|
147
|
+
`{"id":"Admin@INTERNAL","name":"Admin","version":"INTERNAL","extensionPoints":[],"extensions":[],"eventCollector":"NOT-SET","extensionProtocols":[],"apiSchemaFragment":null,"apiTarget":null,"uiFragments":null,"structure":null}`->Pulumi.Output.make
|
|
148
|
+
let adminEpEventTopicArn = switch config.eventTopicArn {
|
|
149
|
+
| Some(arn) => arn
|
|
150
|
+
| None => Pulumi.Output.make("NOT_AVAILABLE")
|
|
151
|
+
}
|
|
152
|
+
{
|
|
153
|
+
pluginDefinitionJson: fakePluginDefinitionJson,
|
|
154
|
+
extensionPoints: [
|
|
155
|
+
{
|
|
156
|
+
specModule: ReventlessCore.Plugin_Helpers.adminPluginExtensionPointSpecModule,
|
|
157
|
+
mappingsModule: ReventlessCore.Plugin_Helpers.adminPluginExtensionPointMappingsModule,
|
|
158
|
+
eventTopicArn: adminEpEventTopicArn,
|
|
159
|
+
aggregateNames: [ReventlessCore.PluginSpec.name],
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
connectExtension: None,
|
|
163
|
+
extensions: [],
|
|
164
|
+
pluginExtensionPointCmdTopicUrl: Pulumi.Output.make(""),
|
|
165
|
+
publishToAggregates: Dict.make(),
|
|
166
|
+
readModelQueueUrls: Dict.make(),
|
|
167
|
+
readModelNamesForSourceName: Dict.make(),
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let forPluginEventCollector: ReventlessCore.Runtime.forEventCollector<
|
|
172
|
+
ReventlessCore.Runtime.effectHandler<
|
|
173
|
+
EventCollectorChannel.callbackEvent,
|
|
174
|
+
context,
|
|
175
|
+
unit,
|
|
176
|
+
string,
|
|
177
|
+
>,
|
|
178
|
+
ReventlessCore.EventCollector.component,
|
|
179
|
+
> = (
|
|
180
|
+
~handler as _,
|
|
181
|
+
~eventTopics,
|
|
182
|
+
~resources,
|
|
183
|
+
~memorySize=1024,
|
|
184
|
+
~timeout=30,
|
|
185
|
+
eventCollector,
|
|
186
|
+
) => {
|
|
187
|
+
let resource = eventCollector->ReventlessCore.Component.toPulumiResource
|
|
188
|
+
let name = resource.name->ReventlessCore.ComponentType.nameOpt(
|
|
189
|
+
ReventlessCore.EventCollector.componentType,
|
|
190
|
+
)
|
|
191
|
+
let opts = {Pulumi.ComponentResource.parent: resource}
|
|
192
|
+
let config = configRef.contents
|
|
193
|
+
|
|
194
|
+
// Extract the SQS queue from the EventCollector channel
|
|
195
|
+
let channel = eventCollector->ReventlessCore.EventCollector_Adapter.channel
|
|
196
|
+
let channelParts: Util.SQS.channelParts = Obj.magic(channel.parts)
|
|
197
|
+
let queue = channelParts.queue
|
|
198
|
+
|
|
199
|
+
// Pull the per-EventCollector context registered by Plugin_Helpers.connect
|
|
200
|
+
// (plugins) or synthesise an admin one if none registered.
|
|
201
|
+
let context: ReventlessCore.Plugin_Helpers.eventCollectorContext =
|
|
202
|
+
switch ReventlessCore.Plugin_Helpers.eventCollectorContextRef.contents->Dict.get(name) {
|
|
203
|
+
| Some(ctx) => ctx
|
|
204
|
+
| None => synthesizeAdminContext()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let envVars: dict<Pulumi.Input.t<string>> = Dict.make()
|
|
208
|
+
|
|
209
|
+
// Lambda env vars carry the actual cmd-topic URLs that publishToAggregates
|
|
210
|
+
// points at (HANDLER_CONFIG holds only the env-var names — same indirection
|
|
211
|
+
// PluginExtensionPointEntryPoint uses).
|
|
212
|
+
context.publishToAggregates
|
|
213
|
+
->Dict.toArray
|
|
214
|
+
->Array.forEach(((_aggName, queueUrlOutput)) => {
|
|
215
|
+
// Env var name follows the existing convention: PTA_<aggregate>_QUEUE_URL.
|
|
216
|
+
let envVarName = `PTA_${_aggName}_QUEUE_URL`
|
|
217
|
+
envVars->Dict.set(envVarName, queueUrlOutput->Pulumi.Output.asInput)
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
// Same indirection for ReadModel EventCollector SQS URLs — only populated
|
|
221
|
+
// when user extensions enqueue directly into RMs (Extension_Operations
|
|
222
|
+
// publishToReadModels path). Empty for the admin Lambda and for the
|
|
223
|
+
// current Orders_Extension fixture (its RM is fed via the slice EventLog →
|
|
224
|
+
// RM EventColl subscription chain instead).
|
|
225
|
+
context.readModelQueueUrls
|
|
226
|
+
->Dict.toArray
|
|
227
|
+
->Array.forEach(((_rmName, queueUrlOutput)) => {
|
|
228
|
+
let envVarName = `PRM_${_rmName}_QUEUE_URL`
|
|
229
|
+
envVars->Dict.set(envVarName, queueUrlOutput->Pulumi.Output.asInput)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
// Outgoing arrays first — resolve EP eventTopicArns, then bundle everything
|
|
233
|
+
// into one Output.apply that builds the JSON.
|
|
234
|
+
let epEventTopicArnsOutput =
|
|
235
|
+
context.extensionPoints
|
|
236
|
+
->Array.map(ep => ep.eventTopicArn)
|
|
237
|
+
->Pulumi.Output.all
|
|
238
|
+
|
|
239
|
+
// HANDLER_CONFIG no longer carries pluginDefinition — it grew past AWS
|
|
240
|
+
// Lambda's 5120-byte UpdateFunctionConfiguration limit once pluginStructure
|
|
241
|
+
// started landing inline. The full pluginDefinition is shipped as a
|
|
242
|
+
// separate `pluginDefinition.json` asset bundled alongside index.mjs (see
|
|
243
|
+
// the buildCodeArchive call below); the entry point reads it from disk at
|
|
244
|
+
// cold start. Slim HANDLER_CONFIG keeps just the orchestration fields.
|
|
245
|
+
let handlerConfigJson =
|
|
246
|
+
Pulumi.Output.all([
|
|
247
|
+
queue.id,
|
|
248
|
+
context.pluginExtensionPointCmdTopicUrl->Pulumi.Output.asInput->Obj.magic,
|
|
249
|
+
config.eventTopicArn->outputOrPlaceholder->Obj.magic,
|
|
250
|
+
config.pluginReadModelTableName->outputOrPlaceholder->Obj.magic,
|
|
251
|
+
config.schedulerRoleArn->outputOrPlaceholder->Obj.magic,
|
|
252
|
+
config.schedulerQueueArn->outputOrPlaceholder->Obj.magic,
|
|
253
|
+
config.schedulerQueueName->outputOrPlaceholder->Obj.magic,
|
|
254
|
+
config.appSyncApiId->outputOrPlaceholder->Obj.magic,
|
|
255
|
+
epEventTopicArnsOutput->Pulumi.Output.asInput->Obj.magic,
|
|
256
|
+
config.pluginSchemaPersistenceTableName->outputOrPlaceholder->Obj.magic,
|
|
257
|
+
])
|
|
258
|
+
->Pulumi.Output.apply(values => {
|
|
259
|
+
let queueUrl = values->Array.getUnsafe(0)
|
|
260
|
+
let pluginEpCmdTopicUrl = values->Array.getUnsafe(1)
|
|
261
|
+
let topLevelEventTopicArn = values->Array.getUnsafe(2)
|
|
262
|
+
let rmTable = values->Array.getUnsafe(3)
|
|
263
|
+
let schedRoleArn = values->Array.getUnsafe(4)
|
|
264
|
+
let schedQueueArn = values->Array.getUnsafe(5)
|
|
265
|
+
let schedQueueName = values->Array.getUnsafe(6)
|
|
266
|
+
let appSyncApiId = values->Array.getUnsafe(7)
|
|
267
|
+
let epEventTopicArns: array<string> = Obj.magic(values->Array.getUnsafe(8))
|
|
268
|
+
let schemaPersistenceTable = values->Array.getUnsafe(9)
|
|
269
|
+
|
|
270
|
+
let dict = Dict.make()
|
|
271
|
+
dict->Dict.set("queueUrl", JSON.Encode.string(queueUrl))
|
|
272
|
+
dict->Dict.set("pluginExtensionPointCmdTopicUrl", JSON.Encode.string(pluginEpCmdTopicUrl))
|
|
273
|
+
dict->Dict.set("eventTopicArn", JSON.Encode.string(topLevelEventTopicArn))
|
|
274
|
+
dict->Dict.set("pluginReadModelTableName", JSON.Encode.string(rmTable))
|
|
275
|
+
dict->Dict.set(
|
|
276
|
+
"pluginSchemaPersistenceTableName",
|
|
277
|
+
JSON.Encode.string(schemaPersistenceTable),
|
|
278
|
+
)
|
|
279
|
+
dict->Dict.set("appSyncApiId", JSON.Encode.string(appSyncApiId))
|
|
280
|
+
dict->Dict.set("clonerEnabled", JSON.Encode.bool(config.clonerEnabled))
|
|
281
|
+
dict->Dict.set("schedulerRoleArn", JSON.Encode.string(schedRoleArn))
|
|
282
|
+
dict->Dict.set("schedulerQueueArn", JSON.Encode.string(schedQueueArn))
|
|
283
|
+
dict->Dict.set("schedulerQueueName", JSON.Encode.string(schedQueueName))
|
|
284
|
+
|
|
285
|
+
// pluginDefinition lives in pluginDefinition.json (see asset bundle
|
|
286
|
+
// below). The entry point reads it via fs.readFileSync at cold start.
|
|
287
|
+
|
|
288
|
+
// Pair each EP with its already-resolved eventTopicArn (parallel arrays)
|
|
289
|
+
// BEFORE sorting, so the (ep, arn) pairing survives the reorder. Then
|
|
290
|
+
// sort by ep.specModule for stable JSON output across deploys — without
|
|
291
|
+
// this, push-order drift in upstream Dict iteration produces pointless
|
|
292
|
+
// Lambda env-var "updates" on every `pulumi up`.
|
|
293
|
+
let extensionPointsArr =
|
|
294
|
+
context.extensionPoints
|
|
295
|
+
->Array.mapWithIndex((ep, i) => (ep, epEventTopicArns->Array.getUnsafe(i)))
|
|
296
|
+
->Array.toSorted(((a, _), (b, _)) => String.compare(a.specModule, b.specModule))
|
|
297
|
+
->Array.map(((ep, eventTopicArn)) => {
|
|
298
|
+
let entryDict = Dict.make()
|
|
299
|
+
entryDict->Dict.set("specModule", JSON.Encode.string(ep.specModule))
|
|
300
|
+
entryDict->Dict.set("mappingsModule", JSON.Encode.string(ep.mappingsModule))
|
|
301
|
+
entryDict->Dict.set("eventTopicArn", JSON.Encode.string(eventTopicArn))
|
|
302
|
+
entryDict->Dict.set(
|
|
303
|
+
"aggregateNames",
|
|
304
|
+
ep.aggregateNames->Array.map(JSON.Encode.string)->JSON.Encode.array,
|
|
305
|
+
)
|
|
306
|
+
JSON.Encode.object(entryDict)
|
|
307
|
+
})
|
|
308
|
+
dict->Dict.set("extensionPoints", JSON.Encode.array(extensionPointsArr))
|
|
309
|
+
|
|
310
|
+
let connectExtensionValue = switch context.connectExtension {
|
|
311
|
+
| Some(ce) =>
|
|
312
|
+
let ceDict = Dict.make()
|
|
313
|
+
ceDict->Dict.set("specModule", JSON.Encode.string(ce.specModule))
|
|
314
|
+
ceDict->Dict.set("mappingsModule", JSON.Encode.string(ce.mappingsModule))
|
|
315
|
+
ceDict->Dict.set("extensionPointName", JSON.Encode.string(ce.extensionPointName))
|
|
316
|
+
JSON.Encode.object(ceDict)
|
|
317
|
+
| None => JSON.Encode.null
|
|
318
|
+
}
|
|
319
|
+
dict->Dict.set("connectExtension", connectExtensionValue)
|
|
320
|
+
|
|
321
|
+
// User-declared extensions — one entry per merged extension group.
|
|
322
|
+
// Each entry carries enough metadata for the bundled handler to
|
|
323
|
+
// dynamic-import the spec / mapping modules and filter the top-level
|
|
324
|
+
// publishToAggregates + readModelQueueUrls maps down to the subset
|
|
325
|
+
// this extension actually uses.
|
|
326
|
+
// Sort by extension name so the serialized JSON is stable across deploys.
|
|
327
|
+
let extensionsArr =
|
|
328
|
+
context.extensions
|
|
329
|
+
->Array.toSorted((a, b) => String.compare(a.name, b.name))
|
|
330
|
+
->Array.map(ext => {
|
|
331
|
+
let entryDict = Dict.make()
|
|
332
|
+
entryDict->Dict.set("name", JSON.Encode.string(ext.name))
|
|
333
|
+
entryDict->Dict.set("specModule", JSON.Encode.string(ext.specModule))
|
|
334
|
+
entryDict->Dict.set("mappingsModule", JSON.Encode.string(ext.mappingsModule))
|
|
335
|
+
entryDict->Dict.set("delegateModule", JSON.Encode.string(ext.delegateModule))
|
|
336
|
+
entryDict->Dict.set("extensionPointName", JSON.Encode.string(ext.extensionPointName))
|
|
337
|
+
entryDict->Dict.set(
|
|
338
|
+
"aggregateNames",
|
|
339
|
+
ext.aggregateNames->Array.map(JSON.Encode.string)->JSON.Encode.array,
|
|
340
|
+
)
|
|
341
|
+
entryDict->Dict.set(
|
|
342
|
+
"readModelNames",
|
|
343
|
+
ext.readModelNames->Array.map(JSON.Encode.string)->JSON.Encode.array,
|
|
344
|
+
)
|
|
345
|
+
JSON.Encode.object(entryDict)
|
|
346
|
+
})
|
|
347
|
+
dict->Dict.set("extensions", JSON.Encode.array(extensionsArr))
|
|
348
|
+
|
|
349
|
+
let publishToAggregatesDict = Dict.make()
|
|
350
|
+
context.publishToAggregates
|
|
351
|
+
->Dict.keysToArray
|
|
352
|
+
->Array.forEach(aggName =>
|
|
353
|
+
publishToAggregatesDict->Dict.set(
|
|
354
|
+
aggName,
|
|
355
|
+
JSON.Encode.string(`PTA_${aggName}_QUEUE_URL`),
|
|
356
|
+
)
|
|
357
|
+
)
|
|
358
|
+
dict->Dict.set("publishToAggregates", JSON.Encode.object(publishToAggregatesDict))
|
|
359
|
+
|
|
360
|
+
let readModelQueueUrlsDict = Dict.make()
|
|
361
|
+
context.readModelQueueUrls
|
|
362
|
+
->Dict.keysToArray
|
|
363
|
+
->Array.forEach(rmName =>
|
|
364
|
+
readModelQueueUrlsDict->Dict.set(
|
|
365
|
+
rmName,
|
|
366
|
+
JSON.Encode.string(`PRM_${rmName}_QUEUE_URL`),
|
|
367
|
+
)
|
|
368
|
+
)
|
|
369
|
+
dict->Dict.set("readModelQueueUrls", JSON.Encode.object(readModelQueueUrlsDict))
|
|
370
|
+
|
|
371
|
+
let rmNamesForSourceDict = Dict.make()
|
|
372
|
+
context.readModelNamesForSourceName
|
|
373
|
+
->Dict.toArray
|
|
374
|
+
->Array.forEach(((sourceName, rmNames)) =>
|
|
375
|
+
rmNamesForSourceDict->Dict.set(
|
|
376
|
+
sourceName,
|
|
377
|
+
rmNames->Array.map(JSON.Encode.string)->JSON.Encode.array,
|
|
378
|
+
)
|
|
379
|
+
)
|
|
380
|
+
dict->Dict.set("readModelNamesForSourceName", JSON.Encode.object(rmNamesForSourceDict))
|
|
381
|
+
|
|
382
|
+
JSON.Encode.object(dict)->JSON.stringify
|
|
383
|
+
})
|
|
384
|
+
envVars->Dict.set("HANDLER_CONFIG", handlerConfigJson->Pulumi.Output.asInput)
|
|
385
|
+
|
|
386
|
+
// User-extension packages: each merged extension entry contributes three
|
|
387
|
+
// module specifiers (EP spec, user mapping file, delegate spec). Extract
|
|
388
|
+
// their npm package names and resolve to package roots so buildCodeArchive
|
|
389
|
+
// can include them in the asset zip — the bundled entry point then
|
|
390
|
+
// dynamic-imports each module at cold start. Admin path has no
|
|
391
|
+
// extensions, so packageDirs stays empty and the asset matches the
|
|
392
|
+
// pre-extension-wiring shape.
|
|
393
|
+
let packageDirs: dict<string> = Dict.make()
|
|
394
|
+
let addPackageFor = spec => {
|
|
395
|
+
let pkgName = Util_Bundle.extractPackageName(spec)
|
|
396
|
+
packageDirs->Dict.set(pkgName, Util_Bundle.resolvePackageRoot(pkgName))
|
|
397
|
+
}
|
|
398
|
+
context.extensions->Array.forEach(ext => {
|
|
399
|
+
[ext.specModule, ext.mappingsModule, ext.delegateModule]->Array.forEach(addPackageFor)
|
|
400
|
+
})
|
|
401
|
+
// Outgoing EPs: the entry point dynamic-imports ep.specModule and
|
|
402
|
+
// ep.mappingsModule at cold start (AdminEventCollectorEntryPoint.mjs).
|
|
403
|
+
// Without this walk the EP spec package (e.g. <plugin>-spec) is missing
|
|
404
|
+
// from the asset zip even though HANDLER_CONFIG references it, and the
|
|
405
|
+
// Lambda crashes with MODULE_NOT_FOUND before any event is processed.
|
|
406
|
+
context.extensionPoints->Array.forEach(ep => {
|
|
407
|
+
[ep.specModule, ep.mappingsModule]->Array.forEach(addPackageFor)
|
|
408
|
+
})
|
|
409
|
+
// The auto-included PluginConnectExtension entry is also dynamic-imported
|
|
410
|
+
// at cold start. Its modules live in reventless-infra / reventless-core,
|
|
411
|
+
// which are explicitly bundled below — walking it here is defensive but
|
|
412
|
+
// costs nothing once those entries dedupe in packageDirs.
|
|
413
|
+
switch context.connectExtension {
|
|
414
|
+
| Some(ce) => [ce.specModule, ce.mappingsModule]->Array.forEach(addPackageFor)
|
|
415
|
+
| None => ()
|
|
416
|
+
}
|
|
417
|
+
// Bundle the framework packages alongside the entry point so the deployed
|
|
418
|
+
// Lambda picks up uncommitted local changes without waiting for the Lambda
|
|
419
|
+
// Layer rebuild (the layer fetches @reventlessdev/reventless-* from GitHub
|
|
420
|
+
// Packages, not the local pnpm workspace). Mirrors the DCB asset pattern in
|
|
421
|
+
// forDcbCommandTopic below. Slightly larger function bundle in exchange
|
|
422
|
+
// for matching dev/CI source.
|
|
423
|
+
packageDirs->Dict.set(
|
|
424
|
+
"@reventlessdev/reventless-aws",
|
|
425
|
+
Util_Bundle.resolvePackageRoot("@reventlessdev/reventless-aws"),
|
|
426
|
+
)
|
|
427
|
+
packageDirs->Dict.set(
|
|
428
|
+
"@reventlessdev/reventless-core",
|
|
429
|
+
Util_Bundle.resolvePackageRoot("@reventlessdev/reventless-core"),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
// pluginDefinition.json must resolve before the asset zip is built;
|
|
433
|
+
// wrap the bundle in an Output.apply over the Output<string>. The
|
|
434
|
+
// resulting Output<codeArchive> threads through to makeFromCodeAsset's
|
|
435
|
+
// Archive.t / string args via Obj.magic — Pulumi's TS API accepts
|
|
436
|
+
// Output<Archive.t> wherever it accepts Archive.t, and Pulumi.Input.make
|
|
437
|
+
// is identity at runtime, so the Output unwraps correctly inside the
|
|
438
|
+
// Lambda Function args.
|
|
439
|
+
let bundleOutput =
|
|
440
|
+
context.pluginDefinitionJson->Pulumi.Output.apply(pluginDefinitionJson => {
|
|
441
|
+
let extraStringAssets = Dict.make()
|
|
442
|
+
extraStringAssets->Dict.set("pluginDefinition.json", pluginDefinitionJson)
|
|
443
|
+
Util_Bundle.buildCodeArchive(
|
|
444
|
+
~entryPointModule="@reventlessdev/reventless-aws/src/adapter/Runtime/AdminEventCollectorEntryPoint.mjs",
|
|
445
|
+
~packageDirs,
|
|
446
|
+
~extraStringAssets,
|
|
447
|
+
)
|
|
448
|
+
})
|
|
449
|
+
let codeOutput = bundleOutput->Pulumi.Output.apply(b => b.code)
|
|
450
|
+
let sourceCodeHashOutput = bundleOutput->Pulumi.Output.apply(b => b.sourceCodeHash)
|
|
451
|
+
|
|
452
|
+
let runtime = RuntimeEnvironment_Lambda.makeFromCodeAsset(
|
|
453
|
+
~name,
|
|
454
|
+
~code=codeOutput->Obj.magic,
|
|
455
|
+
~sourceCodeHash=sourceCodeHashOutput->Obj.magic,
|
|
456
|
+
~envVars,
|
|
457
|
+
~memorySize,
|
|
458
|
+
~timeout,
|
|
459
|
+
~opts,
|
|
460
|
+
)
|
|
461
|
+
let _connectResources = EventCollectorChannel.connect(
|
|
462
|
+
~name,
|
|
463
|
+
~channelSpecs=[
|
|
464
|
+
{
|
|
465
|
+
channel: eventCollector->ReventlessCore.EventCollector_Adapter.channel,
|
|
466
|
+
eventTopics,
|
|
467
|
+
resources,
|
|
468
|
+
},
|
|
469
|
+
],
|
|
470
|
+
~runtime,
|
|
471
|
+
~opts,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
// Admin-only cross-plugin SNS subscription permissions. The admin EC
|
|
475
|
+
// Lambda's manageSubscriptions hook (Phase 3 Step 1) creates SNS
|
|
476
|
+
// subscriptions at runtime as plugins connect/disconnect; that needs
|
|
477
|
+
// sns:Subscribe / sns:Unsubscribe / sns:ListSubscriptionsByTopic on every
|
|
478
|
+
// plugin's EP event topic. Detected via the same context lookup used to
|
|
479
|
+
// synthesize the admin-flavoured handler config: no registered context
|
|
480
|
+
// for this EventCollector name => admin path. Per-plugin EC Lambdas have
|
|
481
|
+
// a registered context and stay on the narrow IAM perimeter from
|
|
482
|
+
// EventCollectorChannel_Helpers.connectLambda.
|
|
483
|
+
let isAdminEventCollector =
|
|
484
|
+
ReventlessCore.Plugin_Helpers.eventCollectorContextRef.contents
|
|
485
|
+
->Dict.get(name)
|
|
486
|
+
->Option.isNone
|
|
487
|
+
if isAdminEventCollector {
|
|
488
|
+
let _ = PulumiAws.IAM.RolePolicy.make(
|
|
489
|
+
~name=`${name}-snsManageSubs`,
|
|
490
|
+
~args={
|
|
491
|
+
policy: PulumiAws.PolicyDocument.make(
|
|
492
|
+
~id=`${name}SnsManageSubsPolicy`,
|
|
493
|
+
~statements=[
|
|
494
|
+
{
|
|
495
|
+
sid: "AllowAdminManageCrossPluginSnsSubscriptions",
|
|
496
|
+
effect: Allow,
|
|
497
|
+
actions: Actions([
|
|
498
|
+
"sns:Subscribe",
|
|
499
|
+
"sns:Unsubscribe",
|
|
500
|
+
"sns:ListSubscriptionsByTopic",
|
|
501
|
+
"sns:GetSubscriptionAttributes",
|
|
502
|
+
]),
|
|
503
|
+
resources: AllResources,
|
|
504
|
+
},
|
|
505
|
+
// mkUpdateApiSchema runs on each Connect/Disconnect alongside
|
|
506
|
+
// manageSubscriptions — pushes the stitched SDL to AppSync via
|
|
507
|
+
// StartSchemaCreation. AppSync requires both the API-level
|
|
508
|
+
// appsync:StartSchemaCreation and appsync:GetSchemaCreationStatus
|
|
509
|
+
// permissions on the deployed API. GetIntrospectionSchema backs the
|
|
510
|
+
// shrink-guard circuit breaker, which reads the live schema before
|
|
511
|
+
// pushing to detect (and refuse) a catastrophic field-count drop.
|
|
512
|
+
{
|
|
513
|
+
sid: "AllowAdminStartSchemaCreation",
|
|
514
|
+
effect: Allow,
|
|
515
|
+
actions: Actions([
|
|
516
|
+
"appsync:StartSchemaCreation",
|
|
517
|
+
"appsync:GetSchemaCreationStatus",
|
|
518
|
+
"appsync:GetIntrospectionSchema",
|
|
519
|
+
]),
|
|
520
|
+
resources: AllResources,
|
|
521
|
+
},
|
|
522
|
+
],
|
|
523
|
+
)
|
|
524
|
+
->PulumiAws.PolicyDocument.toJsonString
|
|
525
|
+
->Pulumi.Input.make,
|
|
526
|
+
role: runtime.parts.lambdaRole.id->Pulumi.Output.asInput,
|
|
527
|
+
},
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
// manageSubscriptions / reconcileSubscriptionsOnce / forwardCommand all
|
|
531
|
+
// Scan the Plugin RM table to find connected peers + route forwarded
|
|
532
|
+
// commands. The Plugin RM is owned by a separate ReadModel EC, so the
|
|
533
|
+
// admin EC's default IAM policy does not include any DynamoDB perms on
|
|
534
|
+
// it. Grant Scan only — the admin EC never writes here, projections
|
|
535
|
+
// happen on the dedicated RM Lambda.
|
|
536
|
+
switch config.pluginReadModelTableName {
|
|
537
|
+
| Some(rmTableOutput) =>
|
|
538
|
+
let policyJson =
|
|
539
|
+
rmTableOutput->Pulumi.Output.apply(tableName =>
|
|
540
|
+
PulumiAws.PolicyDocument.make(
|
|
541
|
+
~id=`${name}PluginRmScanPolicy`,
|
|
542
|
+
~statements=[
|
|
543
|
+
{
|
|
544
|
+
sid: "AllowAdminScanPluginRm",
|
|
545
|
+
effect: Allow,
|
|
546
|
+
actions: Actions(["dynamodb:Scan"]),
|
|
547
|
+
resources: Resource("arn:aws:dynamodb:*:*:table/" ++ tableName),
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
)->PulumiAws.PolicyDocument.toJsonString
|
|
551
|
+
)
|
|
552
|
+
let _ = PulumiAws.IAM.RolePolicy.make(
|
|
553
|
+
~name=`${name}-pluginRmScan`,
|
|
554
|
+
~args={
|
|
555
|
+
policy: policyJson->Pulumi.Output.asInput,
|
|
556
|
+
role: runtime.parts.lambdaRole.id->Pulumi.Output.asInput,
|
|
557
|
+
},
|
|
558
|
+
)
|
|
559
|
+
| None => ()
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// mkUpdateApiSchema reads each plugin's deploy-time SDL fragment from the
|
|
563
|
+
// dedicated PluginSchemaPersistence table (deploy-schema:<name> rows) to
|
|
564
|
+
// re-stitch the live schema. Grant Scan on that table too — it is owned by
|
|
565
|
+
// Platform.res, so the admin EC's default policy includes no perms on it.
|
|
566
|
+
switch config.pluginSchemaPersistenceTableName {
|
|
567
|
+
| Some(schemaTableOutput) =>
|
|
568
|
+
let policyJson =
|
|
569
|
+
schemaTableOutput->Pulumi.Output.apply(tableName =>
|
|
570
|
+
PulumiAws.PolicyDocument.make(
|
|
571
|
+
~id=`${name}PluginSchemaScanPolicy`,
|
|
572
|
+
~statements=[
|
|
573
|
+
{
|
|
574
|
+
sid: "AllowAdminScanPluginSchemaPersistence",
|
|
575
|
+
effect: Allow,
|
|
576
|
+
actions: Actions(["dynamodb:Scan"]),
|
|
577
|
+
resources: Resource("arn:aws:dynamodb:*:*:table/" ++ tableName),
|
|
578
|
+
},
|
|
579
|
+
],
|
|
580
|
+
)->PulumiAws.PolicyDocument.toJsonString
|
|
581
|
+
)
|
|
582
|
+
let _ = PulumiAws.IAM.RolePolicy.make(
|
|
583
|
+
~name=`${name}-pluginSchemaScan`,
|
|
584
|
+
~args={
|
|
585
|
+
policy: policyJson->Pulumi.Output.asInput,
|
|
586
|
+
role: runtime.parts.lambdaRole.id->Pulumi.Output.asInput,
|
|
587
|
+
},
|
|
588
|
+
)
|
|
589
|
+
| None => ()
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Plugin EC sqs:SendMessage grants on the aggregate / StateChangeSlice
|
|
594
|
+
// command-topic queues that user extensions publish to. The default
|
|
595
|
+
// AllowLambdaSendSQS only covers CorePluginExtPointCmdTopic (added because
|
|
596
|
+
// the auto-included Connect extension publishes there), so without this
|
|
597
|
+
// grant every cross-plugin extension's first command publish fails with
|
|
598
|
+
// IAM AccessDenied (e.g. Catalog's Orders_Extension → RecordProductDemand).
|
|
599
|
+
//
|
|
600
|
+
// We deliberately walk context.extensions[].aggregateNames rather than
|
|
601
|
+
// Dict.valuesToArray over context.publishToAggregates: the dict is
|
|
602
|
+
// declared as dict<Output<string>> but Plugin_Builder.res:322 also writes
|
|
603
|
+
// Output<publishJsons> (function values) under DCB slice names — the type
|
|
604
|
+
// is a polite lie, and the function-valued entries make a blanket .apply
|
|
605
|
+
// over the values blow up at preview with "queueUrlOutput.apply is not a
|
|
606
|
+
// function". Iterating extensions limits us to the names extensions
|
|
607
|
+
// actually target, which are always backed by real URL Outputs in the
|
|
608
|
+
// dict (mergedAggregateUrls / aggregateQueueUrls — Plugin_Builder.res:629).
|
|
609
|
+
let aggregateNameSet = Dict.make()
|
|
610
|
+
context.extensions->Array.forEach(ext =>
|
|
611
|
+
ext.aggregateNames->Array.forEach(aggName =>
|
|
612
|
+
aggregateNameSet->Dict.set(aggName, ())
|
|
613
|
+
)
|
|
614
|
+
)
|
|
615
|
+
let queueUrlOutputs =
|
|
616
|
+
aggregateNameSet
|
|
617
|
+
->Dict.keysToArray
|
|
618
|
+
->Array.filterMap(aggName => context.publishToAggregates->Dict.get(aggName))
|
|
619
|
+
let _ = if queueUrlOutputs->Array.length > 0 {
|
|
620
|
+
// The dict is declared as `dict<Pulumi.Output.t<string>>` but the
|
|
621
|
+
// DCB slice path (Dcb_Builder.dcbCommandTopicQueueUrl) can leak the
|
|
622
|
+
// `{BS_PRIVATE_NESTED_SOME_NONE: 0}` nested-option sentinel as a
|
|
623
|
+
// value when the SQS Queue's .id is still unresolved during early
|
|
624
|
+
// CustomResource construction. Pulumi.all happily wraps & resolves
|
|
625
|
+
// it as Output<sentinel>, so .apply hands us a non-string. Drop
|
|
626
|
+
// anything that isn't actually a string — an extension targeting
|
|
627
|
+
// the affected slice will need a separate grant out-of-band until
|
|
628
|
+
// the resource is fully provisioned and a subsequent preview/up
|
|
629
|
+
// produces a real ARN. We build the policy document inline so an
|
|
630
|
+
// empty filtered ARN array skips RolePolicy creation entirely
|
|
631
|
+
// (PutRolePolicy rejects empty Resource arrays with
|
|
632
|
+
// MalformedPolicyDocument).
|
|
633
|
+
let policyJsonOutput =
|
|
634
|
+
queueUrlOutputs
|
|
635
|
+
->Pulumi.Output.all
|
|
636
|
+
->Pulumi.Output.apply(urls => {
|
|
637
|
+
let queueArns =
|
|
638
|
+
urls
|
|
639
|
+
->Array.filter(url => typeof(url) === #string)
|
|
640
|
+
->Array.map(url =>
|
|
641
|
+
// queue URL → ARN: https://sqs.<region>.amazonaws.com/<acct>/<name>
|
|
642
|
+
// → arn:aws:sqs:<region>:<acct>:<name>
|
|
643
|
+
switch url->String.split("/") {
|
|
644
|
+
| [_, _, host, acct, name] =>
|
|
645
|
+
let region =
|
|
646
|
+
host->String.split(".")->Array.get(1)->Option.getOr("eu-west-1")
|
|
647
|
+
`arn:aws:sqs:${region}:${acct}:${name}`
|
|
648
|
+
| _ => url
|
|
649
|
+
}
|
|
650
|
+
)
|
|
651
|
+
if queueArns->Array.length == 0 {
|
|
652
|
+
None
|
|
653
|
+
} else {
|
|
654
|
+
Some(
|
|
655
|
+
PulumiAws.PolicyDocument.make(
|
|
656
|
+
~id=`${name}PublishToAggregatesPolicy`,
|
|
657
|
+
~statements=[
|
|
658
|
+
{
|
|
659
|
+
sid: "AllowEcPublishToAggregateCmdTopics",
|
|
660
|
+
effect: Allow,
|
|
661
|
+
actions: Action("sqs:SendMessage"),
|
|
662
|
+
resources: Resources(queueArns),
|
|
663
|
+
},
|
|
664
|
+
],
|
|
665
|
+
)->PulumiAws.PolicyDocument.toJsonString,
|
|
666
|
+
)
|
|
667
|
+
}
|
|
668
|
+
})
|
|
669
|
+
// Pulumi.all wraps a Some(string)/None and resolves to either the
|
|
670
|
+
// policy JSON or undefined — the latter makes PutRolePolicy a no-op
|
|
671
|
+
// by failing fast in the provider, so guard RolePolicy creation on
|
|
672
|
+
// the resolved value being Some.
|
|
673
|
+
let _ =
|
|
674
|
+
policyJsonOutput->Pulumi.Output.apply(policyOpt =>
|
|
675
|
+
switch policyOpt {
|
|
676
|
+
| Some(policyJson) =>
|
|
677
|
+
let _ = PulumiAws.IAM.RolePolicy.make(
|
|
678
|
+
~name=`${name}-publishToAggregates`,
|
|
679
|
+
~args={
|
|
680
|
+
policy: policyJson->Pulumi.Input.make,
|
|
681
|
+
role: runtime.parts.lambdaRole.id->Pulumi.Output.asInput,
|
|
682
|
+
},
|
|
683
|
+
)
|
|
684
|
+
| None => ()
|
|
685
|
+
}
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
let forPluginHeartbeat: ReventlessCore.Runtime.forComponent<
|
|
691
|
+
ReventlessCore.Runtime.eventHandler<unit, context, unit>,
|
|
692
|
+
runtimeParts,
|
|
693
|
+
ReventlessCore.Heartbeat.component,
|
|
694
|
+
> = (
|
|
695
|
+
~handler as _,
|
|
696
|
+
~connect,
|
|
697
|
+
~memorySize=1024,
|
|
698
|
+
~timeout=30,
|
|
699
|
+
heartbeat,
|
|
700
|
+
) => {
|
|
701
|
+
let hbConfig = heartbeatConfigRef.contents
|
|
702
|
+
switch hbConfig.epQueueUrl {
|
|
703
|
+
| None =>
|
|
704
|
+
log.warn(~comp="PluginRuntime_Builder", "forPluginHeartbeat skipped (no EP queue URL)")
|
|
705
|
+
| Some(epQueueUrl) =>
|
|
706
|
+
let resource = heartbeat->ReventlessCore.Component.toPulumiResource
|
|
707
|
+
let name = resource.name->ReventlessCore.ComponentType.nameOpt(
|
|
708
|
+
ReventlessCore.Heartbeat.componentType,
|
|
709
|
+
)
|
|
710
|
+
let opts = {Pulumi.ComponentResource.parent: resource}
|
|
711
|
+
|
|
712
|
+
let envVars: dict<Pulumi.Input.t<string>> = Dict.make()
|
|
713
|
+
envVars->Dict.set("EP_QUEUE_URL", epQueueUrl->Pulumi.Output.asInput)
|
|
714
|
+
envVars->Dict.set(
|
|
715
|
+
"PLUGIN_ID",
|
|
716
|
+
hbConfig.pluginId->Pulumi.Output.make->Pulumi.Output.asInput,
|
|
717
|
+
)
|
|
718
|
+
envVars->Dict.set(
|
|
719
|
+
"HEARTBEAT_TIMEOUT",
|
|
720
|
+
hbConfig.heartbeatTimeout->Int.toString->Pulumi.Output.make->Pulumi.Output.asInput,
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
// Static re-export from Layer entry point — no esbuild, no user packages
|
|
724
|
+
let {code, sourceCodeHash} = Util_Bundle.buildCodeArchive(
|
|
725
|
+
~entryPointModule="@reventlessdev/reventless-aws/src/adapter/Runtime/HeartbeatEntryPoint.mjs",
|
|
726
|
+
~packageDirs=Dict.make(),
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
let runtime = RuntimeEnvironment_Lambda.makeFromCodeAsset(
|
|
730
|
+
~name,
|
|
731
|
+
~code,
|
|
732
|
+
~sourceCodeHash,
|
|
733
|
+
~envVars,
|
|
734
|
+
~memorySize,
|
|
735
|
+
~timeout,
|
|
736
|
+
~opts,
|
|
737
|
+
)
|
|
738
|
+
connect(~runtime)
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Thin delegator: supplies the registered slice paths + per-flavor config to
|
|
743
|
+
// the build in StateChangeSliceRuntime_Builder_Single (kept as a named file so
|
|
744
|
+
// it sits alongside StateViewSliceRuntime_Builder_Single, rather than buried
|
|
745
|
+
// here). Merges slice module paths: auto-registered (from moduleUrl) + manually
|
|
746
|
+
// registered (from registerDcbConfig).
|
|
747
|
+
let forDcbCommandTopic: ReventlessCore.Runtime.forComponent<
|
|
748
|
+
ReventlessCore.Runtime.effectHandler<'callbackEvent, context, unit, string>,
|
|
749
|
+
runtimeParts,
|
|
750
|
+
ReventlessCore.CommandTopic.component<'op>,
|
|
751
|
+
> = (~handler as _, ~connect, ~memorySize as _=1024, ~timeout as _=30, dcbCommandTopic) => {
|
|
752
|
+
let dcbConfig = dcbConfigRef.contents
|
|
753
|
+
let slicePaths =
|
|
754
|
+
registeredSliceModulePaths
|
|
755
|
+
->Array.concat(dcbConfig.stateChangeSliceModulePaths)
|
|
756
|
+
->Array.map(({specPath, behaviorPath}) => (specPath, behaviorPath))
|
|
757
|
+
StateChangeSliceRuntime_Builder_Single.forDcbCommandTopic(
|
|
758
|
+
~slicePaths,
|
|
759
|
+
~dcbTableName=dcbConfig.dcbTableName,
|
|
760
|
+
~pluginName=dcbConfig.pluginName,
|
|
761
|
+
~syncConfig=syncStateChangesConfigRef.contents,
|
|
762
|
+
~asyncConfig=asyncStateChangesConfigRef.contents,
|
|
763
|
+
~connect,
|
|
764
|
+
dcbCommandTopic,
|
|
765
|
+
)
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
let finish = () => ()
|
|
769
|
+
}
|