@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,80 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Util_Bundle$ReventlessAws from "../util/Util_Bundle.res.mjs";
|
|
4
|
+
import * as Plugin_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/component/Plugin_Helpers.res.mjs";
|
|
5
|
+
import * as Aggregate_Builder$ReventlessCore from "@reventlessdev/reventless-core/src/components/Aggregate/Aggregate_Builder.res.mjs";
|
|
6
|
+
import * as RuntimeEnvironment_Lambda$ReventlessAws from "../adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs";
|
|
7
|
+
import * as CommandTopicChannel_SQS_Async$ReventlessAws from "../adapter/CommandTopic/CommandTopicChannel_SQS_Async.res.mjs";
|
|
8
|
+
import * as EventLogStorage_DynamoDbStream$ReventlessAws from "../adapter/EventLog/EventLogStorage_DynamoDbStream.res.mjs";
|
|
9
|
+
import * as CommandGeneratorResolvers_AppSync$ReventlessAws from "../adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res.mjs";
|
|
10
|
+
import * as EventTopicPublisher_DynamoDbStream$ReventlessAws from "../adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res.mjs";
|
|
11
|
+
import * as EventCollectorChannel_DynamoDbStream$ReventlessAws from "../adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res.mjs";
|
|
12
|
+
import * as AggregateRuntime_Builder_Single_Async$ReventlessAws from "../adapter/Runtime/AggregateRuntime_Builder_Single_Async.res.mjs";
|
|
13
|
+
|
|
14
|
+
function Make(Spec) {
|
|
15
|
+
return Behavior => (EventMappings => {
|
|
16
|
+
let Inner = Aggregate_Builder$ReventlessCore.Make(Spec)(Behavior)({
|
|
17
|
+
mappings: EventMappings.mappings,
|
|
18
|
+
counter: EventMappings.counter
|
|
19
|
+
})({
|
|
20
|
+
make: RuntimeEnvironment_Lambda$ReventlessAws.make,
|
|
21
|
+
groupBySource: RuntimeEnvironment_Lambda$ReventlessAws.groupBySource,
|
|
22
|
+
extractCorrelationId: RuntimeEnvironment_Lambda$ReventlessAws.extractCorrelationId,
|
|
23
|
+
asEventHandler: prim => prim,
|
|
24
|
+
asEffectHandler: prim => prim
|
|
25
|
+
})(CommandGeneratorResolvers_AppSync$ReventlessAws)({
|
|
26
|
+
make: CommandTopicChannel_SQS_Async$ReventlessAws.make
|
|
27
|
+
})(EventLogStorage_DynamoDbStream$ReventlessAws)(EventTopicPublisher_DynamoDbStream$ReventlessAws)({
|
|
28
|
+
make: EventCollectorChannel_DynamoDbStream$ReventlessAws.make,
|
|
29
|
+
connect: EventCollectorChannel_DynamoDbStream$ReventlessAws.connect
|
|
30
|
+
})({
|
|
31
|
+
CommandTopicChannel: {
|
|
32
|
+
make: CommandTopicChannel_SQS_Async$ReventlessAws.make
|
|
33
|
+
},
|
|
34
|
+
EventCollectorChannel: {
|
|
35
|
+
make: EventCollectorChannel_DynamoDbStream$ReventlessAws.make,
|
|
36
|
+
connect: EventCollectorChannel_DynamoDbStream$ReventlessAws.connect
|
|
37
|
+
},
|
|
38
|
+
forCommandGenerator: AggregateRuntime_Builder_Single_Async$ReventlessAws.forCommandGenerator,
|
|
39
|
+
forCommandTopic: AggregateRuntime_Builder_Single_Async$ReventlessAws.forCommandTopic,
|
|
40
|
+
forEventCollector: AggregateRuntime_Builder_Single_Async$ReventlessAws.forEventCollector,
|
|
41
|
+
finish: AggregateRuntime_Builder_Single_Async$ReventlessAws.finish
|
|
42
|
+
})(Plugin_Helpers$ReventlessCore.NoopHooksConfig);
|
|
43
|
+
let make = (api, opts) => {
|
|
44
|
+
let aggregate = Inner.make(api, opts);
|
|
45
|
+
let eventLogOutputs = Inner.outputs(aggregate).eventLog;
|
|
46
|
+
let tableResource = eventLogOutputs.resources[0];
|
|
47
|
+
let eventLogTableName = tableResource.name;
|
|
48
|
+
AggregateRuntime_Builder_Single_Async$ReventlessAws.registerAggregate(Spec.name, Util_Bundle$ReventlessAws.getModuleSpecifier(Spec.moduleUrl), Util_Bundle$ReventlessAws.getModuleSpecifier(Behavior.moduleUrl), eventLogTableName);
|
|
49
|
+
return aggregate;
|
|
50
|
+
};
|
|
51
|
+
let finish = () => AggregateRuntime_Builder_Single_Async$ReventlessAws.finish();
|
|
52
|
+
return {
|
|
53
|
+
Spec: Spec,
|
|
54
|
+
make: make,
|
|
55
|
+
outputs: Inner.outputs,
|
|
56
|
+
operations: Inner.operations,
|
|
57
|
+
finish: finish
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let CommandGeneratorResolvers;
|
|
63
|
+
|
|
64
|
+
let CommandTopicChannel;
|
|
65
|
+
|
|
66
|
+
let EventCollectorChannel;
|
|
67
|
+
|
|
68
|
+
let RuntimeEnvironment;
|
|
69
|
+
|
|
70
|
+
let AggregateRuntimeBuilder;
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
CommandGeneratorResolvers,
|
|
74
|
+
CommandTopicChannel,
|
|
75
|
+
EventCollectorChannel,
|
|
76
|
+
RuntimeEnvironment,
|
|
77
|
+
AggregateRuntimeBuilder,
|
|
78
|
+
Make,
|
|
79
|
+
}
|
|
80
|
+
/* Util_Bundle-ReventlessAws Not a pure module */
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
// AppSync_Adapter — implements ReventlessInfra.Api_Adapter.Provider for AWS AppSync.
|
|
2
|
+
//
|
|
3
|
+
// Creates a new AppSync GraphQL API and IAM execution role.
|
|
4
|
+
// updateSchema uses the AWS AppSync SDK to push a stitched SDL whenever plugins connect.
|
|
5
|
+
|
|
6
|
+
open PulumiAws
|
|
7
|
+
|
|
8
|
+
let log = ReventlessCore.Logger.fromEnv()
|
|
9
|
+
|
|
10
|
+
// ── SHA-256 helper ─────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
type hashObject
|
|
13
|
+
@module("node:crypto") external createHash: string => hashObject = "createHash"
|
|
14
|
+
@send external hashUpdate: (hashObject, string) => hashObject = "update"
|
|
15
|
+
@send external hashDigest: (hashObject, string) => string = "digest"
|
|
16
|
+
|
|
17
|
+
let sha256Hex = (input: string): string =>
|
|
18
|
+
createHash("sha256")->hashUpdate(input)->hashDigest("hex")
|
|
19
|
+
|
|
20
|
+
// ── Inline AppSync SDK binding ─────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
type appSyncClient
|
|
23
|
+
|
|
24
|
+
// AWS SDK v3 command pattern: client.send(new StartSchemaCreationCommand({...}))
|
|
25
|
+
type startSchemaCreationInput = {
|
|
26
|
+
apiId: string,
|
|
27
|
+
definition: string,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type startSchemaCreationCommand
|
|
31
|
+
|
|
32
|
+
@module("@aws-sdk/client-appsync") @new
|
|
33
|
+
external makeAppSyncClient: unit => appSyncClient = "AppSyncClient"
|
|
34
|
+
|
|
35
|
+
@module("@aws-sdk/client-appsync") @new
|
|
36
|
+
external makeStartSchemaCreationCommand: startSchemaCreationInput => startSchemaCreationCommand =
|
|
37
|
+
"StartSchemaCreationCommand"
|
|
38
|
+
|
|
39
|
+
@send
|
|
40
|
+
external send: (appSyncClient, startSchemaCreationCommand) => promise<unknown> = "send"
|
|
41
|
+
|
|
42
|
+
let startSchemaCreation = (client: appSyncClient, input: startSchemaCreationInput) =>
|
|
43
|
+
client->send(input->makeStartSchemaCreationCommand)
|
|
44
|
+
|
|
45
|
+
// Retrying wrapper: AppSync holds an API-level lock during schema creation and
|
|
46
|
+
// rejects concurrent StartSchemaCreation calls with HTTP 409
|
|
47
|
+
// ConcurrentModificationException ("Schema is currently being altered, please
|
|
48
|
+
// wait until that is complete."). When multiple processes deploy plugin stacks
|
|
49
|
+
// in parallel against the same AppSync API, they race on this lock. Retry with
|
|
50
|
+
// jittered exponential backoff so a losing call can wait for the in-progress
|
|
51
|
+
// schema to finish and try again. Permanent errors (e.g. invalid SDL) are not
|
|
52
|
+
// retried — see AppSync_Error.classify.
|
|
53
|
+
let startSchemaCreationRetrying = (
|
|
54
|
+
client: appSyncClient,
|
|
55
|
+
input: startSchemaCreationInput,
|
|
56
|
+
): promise<unit> => {
|
|
57
|
+
Effect.tryPromise(
|
|
58
|
+
~catch=AppSync_Error.classify,
|
|
59
|
+
() => startSchemaCreation(client, input)->Promise.then(_ => Promise.resolve()),
|
|
60
|
+
)
|
|
61
|
+
->Effect.retry(AppSync_Error.retrySchedule)
|
|
62
|
+
->Effect.runPromise
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// GetSchemaCreationStatus — poll until schema is ACTIVE
|
|
66
|
+
type getSchemaCreationStatusInput = {apiId: string}
|
|
67
|
+
type getSchemaCreationStatusCommand
|
|
68
|
+
type getSchemaCreationStatusResult = {status: string, details: option<string>}
|
|
69
|
+
|
|
70
|
+
@module("@aws-sdk/client-appsync") @new
|
|
71
|
+
external makeGetSchemaCreationStatusCommand: getSchemaCreationStatusInput => getSchemaCreationStatusCommand =
|
|
72
|
+
"GetSchemaCreationStatusCommand"
|
|
73
|
+
|
|
74
|
+
@send
|
|
75
|
+
external sendGetStatus: (appSyncClient, getSchemaCreationStatusCommand) => promise<getSchemaCreationStatusResult> =
|
|
76
|
+
"send"
|
|
77
|
+
|
|
78
|
+
let rec waitForSchemaActive = async (client, apiId, ~maxAttempts=30, ~attempt=0) => {
|
|
79
|
+
let result = await client->sendGetStatus(
|
|
80
|
+
{apiId: apiId}->makeGetSchemaCreationStatusCommand,
|
|
81
|
+
)
|
|
82
|
+
switch result.status {
|
|
83
|
+
| "ACTIVE" | "SUCCESS" => ()
|
|
84
|
+
| "FAILED" =>
|
|
85
|
+
let details = result.details->Option.getOr("(no details)")
|
|
86
|
+
JsError.throwWithMessage(`Schema creation failed for API ${apiId}: ${details}`)
|
|
87
|
+
| status if attempt >= maxAttempts =>
|
|
88
|
+
JsError.throwWithMessage(
|
|
89
|
+
`Schema creation timed out after ${maxAttempts->Int.toString} attempts (status: ${status})`,
|
|
90
|
+
)
|
|
91
|
+
| _ =>
|
|
92
|
+
await Promise.make((resolve, _) => setTimeout(resolve, 500)->ignore)
|
|
93
|
+
await waitForSchemaActive(client, apiId, ~maxAttempts, ~attempt=attempt + 1)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// GetIntrospectionSchema — fetch the live schema as an SDL string. Used by the
|
|
98
|
+
// deploy-time drift check in preResolversSchemaHook to detect a live schema that
|
|
99
|
+
// was clobbered out-of-band by a runtime re-stitch (the stored deploy hash does
|
|
100
|
+
// not reflect such clobbers). Returns "" when the API has no schema or when
|
|
101
|
+
// introspection fails — the caller decides how to treat an empty result.
|
|
102
|
+
type getIntrospectionSchemaInput = {apiId: string, format: string}
|
|
103
|
+
type getIntrospectionSchemaCommand
|
|
104
|
+
type schemaBlob
|
|
105
|
+
type getIntrospectionSchemaResult = {schema: option<schemaBlob>}
|
|
106
|
+
|
|
107
|
+
@module("@aws-sdk/client-appsync") @new
|
|
108
|
+
external makeGetIntrospectionSchemaCommand: getIntrospectionSchemaInput => getIntrospectionSchemaCommand =
|
|
109
|
+
"GetIntrospectionSchemaCommand"
|
|
110
|
+
|
|
111
|
+
@send
|
|
112
|
+
external sendGetIntrospection: (
|
|
113
|
+
appSyncClient,
|
|
114
|
+
getIntrospectionSchemaCommand,
|
|
115
|
+
) => promise<getIntrospectionSchemaResult> = "send"
|
|
116
|
+
|
|
117
|
+
// resp.schema is a Uint8Array of the SDL text; decode it to UTF-8.
|
|
118
|
+
type nodeBuffer
|
|
119
|
+
@val @scope("Buffer") external bufferFrom: schemaBlob => nodeBuffer = "from"
|
|
120
|
+
@send external bufferToString: (nodeBuffer, string) => string = "toString"
|
|
121
|
+
|
|
122
|
+
let getIntrospectionSdl = async (client: appSyncClient, apiId: string): string => {
|
|
123
|
+
try {
|
|
124
|
+
let resp = await client->sendGetIntrospection(
|
|
125
|
+
{apiId, format: "SDL"}->makeGetIntrospectionSchemaCommand,
|
|
126
|
+
)
|
|
127
|
+
switch resp.schema {
|
|
128
|
+
| Some(blob) => bufferFrom(blob)->bufferToString("utf-8")
|
|
129
|
+
| None => ""
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
| exn =>
|
|
133
|
+
let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
|
|
134
|
+
log.warn(~comp="AppSync_Adapter", `getIntrospectionSdl failed for ${apiId}: ${msg}`)
|
|
135
|
+
""
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let deploySchemaWithRetry = (
|
|
140
|
+
client: appSyncClient,
|
|
141
|
+
apiId: string,
|
|
142
|
+
definition: string,
|
|
143
|
+
): Effect.t<unit, AppSync_Error.t, unit> =>
|
|
144
|
+
Effect.tryPromise(
|
|
145
|
+
~catch=AppSync_Error.classify,
|
|
146
|
+
() => startSchemaCreation(client, {apiId, definition})->Promise.then(_ => Promise.resolve()),
|
|
147
|
+
)->Effect.retry(AppSync_Error.retrySchedule)
|
|
148
|
+
|
|
149
|
+
// ── Schema-push serialization lock ──────────────────────────────────────────
|
|
150
|
+
//
|
|
151
|
+
// Plugin/service stacks share one AppSync API, and StartSchemaCreation REPLACES
|
|
152
|
+
// the whole schema. When two stacks scan the deploy-schema table, stitch, and
|
|
153
|
+
// push concurrently, a push built from a stale scan (missing a peer's not-yet-
|
|
154
|
+
// written fragment) clobbers the peer's fields — orphaning their resolvers
|
|
155
|
+
// (NotFoundException: No field named X). The shrink guard only catches
|
|
156
|
+
// catastrophic (>threshold) drops, not a single dropped field.
|
|
157
|
+
//
|
|
158
|
+
// This lease serialises scan→stitch→push across stacks via a conditional-write
|
|
159
|
+
// lock row in the shared PluginSchemaPersistence table. A push that holds the
|
|
160
|
+
// lease always scans a table already containing every prior push's fragment, so
|
|
161
|
+
// the last push is complete and nothing is clobbered. The lease carries a TTL so
|
|
162
|
+
// a crashed holder cannot deadlock the table; if the lock cannot be acquired
|
|
163
|
+
// within maxWaitMs we proceed best-effort rather than fail the deploy.
|
|
164
|
+
|
|
165
|
+
@val external schemaLockSetTimeout: (unit => unit, int) => unit = "setTimeout"
|
|
166
|
+
let schemaLockSleep = (ms: int): promise<unit> =>
|
|
167
|
+
Promise.make((resolve, _) => schemaLockSetTimeout(() => resolve(), ms))
|
|
168
|
+
let _schemaLockCounter = ref(0)
|
|
169
|
+
|
|
170
|
+
let withSchemaPushLock = async (
|
|
171
|
+
~tableName: string,
|
|
172
|
+
~apiId: string,
|
|
173
|
+
~leaseMs: int=120000,
|
|
174
|
+
~maxWaitMs: int=180000,
|
|
175
|
+
fn: unit => promise<'a>,
|
|
176
|
+
): 'a => {
|
|
177
|
+
open AwsSdk.DynamoDb.DocumentClient
|
|
178
|
+
let lockId = `schema-push-lock:${apiId}`
|
|
179
|
+
_schemaLockCounter := _schemaLockCounter.contents + 1
|
|
180
|
+
let holder = `${apiId}#${Date.now()->Float.toString}#${_schemaLockCounter.contents->Int.toString}`
|
|
181
|
+
|
|
182
|
+
let acquire = async () => {
|
|
183
|
+
let deadline = Date.now() +. maxWaitMs->Int.toFloat
|
|
184
|
+
let acquired = ref(false)
|
|
185
|
+
while !acquired.contents {
|
|
186
|
+
let now = Date.now()
|
|
187
|
+
let ok =
|
|
188
|
+
await PutCommand.make({
|
|
189
|
+
PutCommand.tableName,
|
|
190
|
+
item: Dict.fromArray([
|
|
191
|
+
("id", lockId->JSON.Encode.string),
|
|
192
|
+
("holder", holder->JSON.Encode.string),
|
|
193
|
+
("expiresAt", (now +. leaseMs->Int.toFloat)->JSON.Encode.float),
|
|
194
|
+
])->JSON.Encode.object,
|
|
195
|
+
conditionExpression: "attribute_not_exists(id) OR expiresAt < :now",
|
|
196
|
+
expressionAttributeValues: Dict.fromArray([(":now", now->JSON.Encode.float)]),
|
|
197
|
+
})
|
|
198
|
+
->PutCommand.send
|
|
199
|
+
->Promise.thenResolve(_ => true)
|
|
200
|
+
->Promise.catch(_ => Promise.resolve(false))
|
|
201
|
+
if ok {
|
|
202
|
+
acquired := true
|
|
203
|
+
} else if Date.now() > deadline {
|
|
204
|
+
log.warn(
|
|
205
|
+
~comp="AppSync_Adapter",
|
|
206
|
+
`schema-push lock for ${apiId} not acquired within ${maxWaitMs->Int.toString}ms — proceeding best-effort`,
|
|
207
|
+
)
|
|
208
|
+
acquired := true
|
|
209
|
+
} else {
|
|
210
|
+
await schemaLockSleep(1000)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let release = async () => {
|
|
216
|
+
let _ =
|
|
217
|
+
await DeleteCommand.make({
|
|
218
|
+
DeleteCommand.tableName,
|
|
219
|
+
key: Dict.fromArray([("id", lockId->JSON.Encode.string)]),
|
|
220
|
+
conditionExpression: "holder = :holder",
|
|
221
|
+
expressionAttributeValues: Dict.fromArray([(":holder", holder->JSON.Encode.string)]),
|
|
222
|
+
})
|
|
223
|
+
->DeleteCommand.send
|
|
224
|
+
->Promise.thenResolve(_ => ())
|
|
225
|
+
->Promise.catch(_ => Promise.resolve()) // expired lease stolen by a peer — leave theirs intact
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
await acquire()
|
|
229
|
+
try {
|
|
230
|
+
let r = await fn()
|
|
231
|
+
let _ = await release()
|
|
232
|
+
r
|
|
233
|
+
} catch {
|
|
234
|
+
| exn =>
|
|
235
|
+
let _ = await release()
|
|
236
|
+
throw(exn)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Lazy singleton AppSync client (runtime only)
|
|
241
|
+
let _client: ref<option<appSyncClient>> = ref(None)
|
|
242
|
+
let getClient = () =>
|
|
243
|
+
switch _client.contents {
|
|
244
|
+
| Some(c) => c
|
|
245
|
+
| None =>
|
|
246
|
+
let c = makeAppSyncClient()
|
|
247
|
+
_client.contents = Some(c)
|
|
248
|
+
c
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ── @aws_auth directive injection ─────────────────────────────────────────
|
|
252
|
+
// Injects @aws_auth(cognito_groups: [...]) directives into SDL field strings
|
|
253
|
+
// based on authorization metadata from schema entries.
|
|
254
|
+
//
|
|
255
|
+
// Two sources are merged:
|
|
256
|
+
// 1. The legacy `authorization?: {tableName, group}` field — single group
|
|
257
|
+
// per entry, kept for the indexed-access auth path.
|
|
258
|
+
// 2. The Stage E2 spec-level `Authorization.permission` fields
|
|
259
|
+
// (`fieldPermissions` on mutations, `permission` on queries) — derived
|
|
260
|
+
// from `@@reventless.authorize` / `@authorize` PPX annotations.
|
|
261
|
+
//
|
|
262
|
+
// When both are present on the same field, the spec-level permission wins
|
|
263
|
+
// (it is more specific). `AllowGroups([g1, g2, ...])` emits
|
|
264
|
+
// `@aws_auth(cognito_groups: ["g1", "g2", ...])`. `AllowAuthenticated` /
|
|
265
|
+
// `AllowAnonymous` emit no directive (with Cognito as primary auth, any
|
|
266
|
+
// reaching request is already authenticated). `AllowGroups([])` and
|
|
267
|
+
// `DenyAll` emit a sentinel `__deny_all__` group that no Cognito user can
|
|
268
|
+
// belong to — effectively blocking the field at the API layer.
|
|
269
|
+
|
|
270
|
+
let _permissionToCognitoGroups = (
|
|
271
|
+
permission: Reventless.Authorization.permission,
|
|
272
|
+
): option<array<string>> =>
|
|
273
|
+
switch permission {
|
|
274
|
+
| AllowGroups([]) => Some(["__deny_all__"])
|
|
275
|
+
| AllowGroups(groups) => Some(groups)
|
|
276
|
+
| DenyAll => Some(["__deny_all__"])
|
|
277
|
+
| AllowAuthenticated | AllowAnonymous => None
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let _formatGroupsDirective = (groups: array<string>): string => {
|
|
281
|
+
let quoted = groups->Array.map(g => `"${g}"`)->Array.join(", ")
|
|
282
|
+
`@aws_auth(cognito_groups: [${quoted}])`
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let injectAwsAuth = (
|
|
286
|
+
fragment: Reventless.Plugin.apiSchemaFragment,
|
|
287
|
+
~mutationEntries: array<ReventlessInfra.Api.mutationSchemaEntry>,
|
|
288
|
+
~queryEntries: array<ReventlessInfra.Api.querySchemaEntry>,
|
|
289
|
+
): Reventless.Plugin.apiSchemaFragment => {
|
|
290
|
+
let parts = ReventlessCore.GraphQL_Stitcher.decode(fragment)
|
|
291
|
+
|
|
292
|
+
// Build authorization lookup from mutation entries: fieldName -> groups.
|
|
293
|
+
// Spec-level `fieldPermissions` takes precedence over the legacy
|
|
294
|
+
// `authorization.group` per-entry single-group form.
|
|
295
|
+
let mutationAuthMap: Dict.t<array<string>> = Dict.make()
|
|
296
|
+
mutationEntries->Array.forEach(entry => {
|
|
297
|
+
switch entry.authorization {
|
|
298
|
+
| Some({group}) =>
|
|
299
|
+
entry.fieldNames->Array.forEach(fieldName =>
|
|
300
|
+
mutationAuthMap->Dict.set(fieldName, [group])
|
|
301
|
+
)
|
|
302
|
+
| None => ()
|
|
303
|
+
}
|
|
304
|
+
switch entry.fieldPermissions {
|
|
305
|
+
| Some(fp) =>
|
|
306
|
+
fp
|
|
307
|
+
->Dict.toArray
|
|
308
|
+
->Array.forEach(((fieldName, permission)) => {
|
|
309
|
+
switch _permissionToCognitoGroups(permission) {
|
|
310
|
+
| Some(groups) => mutationAuthMap->Dict.set(fieldName, groups)
|
|
311
|
+
| None => mutationAuthMap->Dict.delete(fieldName)
|
|
312
|
+
}
|
|
313
|
+
})
|
|
314
|
+
| None => ()
|
|
315
|
+
}
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
// Build authorization lookup from query entries: fieldName -> groups.
|
|
319
|
+
// Spec-level `permission` takes precedence over the legacy authorization.
|
|
320
|
+
let queryAuthMap: Dict.t<array<string>> = Dict.make()
|
|
321
|
+
queryEntries->Array.forEach(entry => {
|
|
322
|
+
switch entry.authorization {
|
|
323
|
+
| Some({group}) =>
|
|
324
|
+
queryAuthMap->Dict.set(entry.singleFieldName, [group])
|
|
325
|
+
queryAuthMap->Dict.set(entry.listFieldName, [group])
|
|
326
|
+
| None => ()
|
|
327
|
+
}
|
|
328
|
+
switch entry.permission {
|
|
329
|
+
| Some(permission) =>
|
|
330
|
+
switch _permissionToCognitoGroups(permission) {
|
|
331
|
+
| Some(groups) =>
|
|
332
|
+
queryAuthMap->Dict.set(entry.singleFieldName, groups)
|
|
333
|
+
queryAuthMap->Dict.set(entry.listFieldName, groups)
|
|
334
|
+
| None =>
|
|
335
|
+
queryAuthMap->Dict.delete(entry.singleFieldName)
|
|
336
|
+
queryAuthMap->Dict.delete(entry.listFieldName)
|
|
337
|
+
}
|
|
338
|
+
| None => ()
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
let augmentedMutations = parts.mutations->Array.map(field => {
|
|
343
|
+
let fieldName = ReventlessCore.GraphQL_Stitcher.extractLeadingName(field)
|
|
344
|
+
switch mutationAuthMap->Dict.get(fieldName) {
|
|
345
|
+
| Some(groups) => `${field}\n ${_formatGroupsDirective(groups)}`
|
|
346
|
+
| None => field
|
|
347
|
+
}
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
let augmentedQueries = parts.queries->Array.map(field => {
|
|
351
|
+
let fieldName = ReventlessCore.GraphQL_Stitcher.extractLeadingName(field)
|
|
352
|
+
switch queryAuthMap->Dict.get(fieldName) {
|
|
353
|
+
| Some(groups) => `${field} ${_formatGroupsDirective(groups)}`
|
|
354
|
+
| None => field
|
|
355
|
+
}
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
let encoded =
|
|
359
|
+
JSON.Encode.object(
|
|
360
|
+
Dict.fromArray([
|
|
361
|
+
("types", JSON.Encode.array(parts.types->Array.map(JSON.Encode.string))),
|
|
362
|
+
("mutations", JSON.Encode.array(augmentedMutations->Array.map(JSON.Encode.string))),
|
|
363
|
+
("queries", JSON.Encode.array(augmentedQueries->Array.map(JSON.Encode.string))),
|
|
364
|
+
(
|
|
365
|
+
"subscriptions",
|
|
366
|
+
JSON.Encode.array(parts.subscriptions->Array.map(JSON.Encode.string)),
|
|
367
|
+
),
|
|
368
|
+
]),
|
|
369
|
+
)->JSON.stringify
|
|
370
|
+
|
|
371
|
+
{Reventless.Plugin.encoded, protocol: "graphql"}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Injects @aws_auth with the given group on ALL mutation, query, and subscription
|
|
375
|
+
// fields in a fragment. Used for the base fragment where all fields share the
|
|
376
|
+
// same authorization group.
|
|
377
|
+
let injectAwsAuthAll = (
|
|
378
|
+
fragment: Reventless.Plugin.apiSchemaFragment,
|
|
379
|
+
~group: string,
|
|
380
|
+
): Reventless.Plugin.apiSchemaFragment => {
|
|
381
|
+
let parts = ReventlessCore.GraphQL_Stitcher.decode(fragment)
|
|
382
|
+
|
|
383
|
+
let augmentedMutations = parts.mutations->Array.map(field =>
|
|
384
|
+
`${field}\n @aws_auth(cognito_groups: ["${group}"])`
|
|
385
|
+
)
|
|
386
|
+
let augmentedQueries = parts.queries->Array.map(field =>
|
|
387
|
+
`${field} @aws_auth(cognito_groups: ["${group}"])`
|
|
388
|
+
)
|
|
389
|
+
let augmentedSubscriptions = parts.subscriptions->Array.map(field =>
|
|
390
|
+
`${field}\n @aws_auth(cognito_groups: ["${group}"])`
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
let encoded =
|
|
394
|
+
JSON.Encode.object(
|
|
395
|
+
Dict.fromArray([
|
|
396
|
+
("types", JSON.Encode.array(parts.types->Array.map(JSON.Encode.string))),
|
|
397
|
+
("mutations", JSON.Encode.array(augmentedMutations->Array.map(JSON.Encode.string))),
|
|
398
|
+
("queries", JSON.Encode.array(augmentedQueries->Array.map(JSON.Encode.string))),
|
|
399
|
+
(
|
|
400
|
+
"subscriptions",
|
|
401
|
+
JSON.Encode.array(augmentedSubscriptions->Array.map(JSON.Encode.string)),
|
|
402
|
+
),
|
|
403
|
+
]),
|
|
404
|
+
)->JSON.stringify
|
|
405
|
+
|
|
406
|
+
{Reventless.Plugin.encoded, protocol: "graphql"}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ── Provider implementation ────────────────────────────────────────────────
|
|
410
|
+
|
|
411
|
+
type api = AppSync.GraphQLApi.t
|
|
412
|
+
type role = IAM.Role.t
|
|
413
|
+
|
|
414
|
+
let makeApiResource = (
|
|
415
|
+
~name: string,
|
|
416
|
+
~opts: Pulumi.ComponentResource.options,
|
|
417
|
+
): (Pulumi.Output.t<api>, Pulumi.Output.t<role>) => {
|
|
418
|
+
let customOpts: Pulumi.CustomResourceOptions.t = {
|
|
419
|
+
parent: ?opts.parent,
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Create IAM role for AppSync
|
|
423
|
+
let iamRole = IAM.Role.make(
|
|
424
|
+
~name=`${name}-appsync-role`,
|
|
425
|
+
~args={
|
|
426
|
+
assumeRolePolicy: `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"appsync.amazonaws.com"},"Action":"sts:AssumeRole"}]}`
|
|
427
|
+
->Pulumi.Input.make,
|
|
428
|
+
},
|
|
429
|
+
~opts=Some(customOpts),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
// Resolve the Cognito UserPool — cached inside Platform_Stack, so calling
|
|
433
|
+
// from each API call site (DomainApi, PlatformApi) is safe. Returned as a
|
|
434
|
+
// single Output that yields the {userPoolId, awsRegion, defaultAction}
|
|
435
|
+
// record AppSync expects.
|
|
436
|
+
let authConfigOut = Auth_Cognito.make(~name=`${name}-auth`)
|
|
437
|
+
let userPoolConfigOut =
|
|
438
|
+
authConfigOut->Pulumi.Output.apply((c: Auth_Cognito.authConfig) =>
|
|
439
|
+
(
|
|
440
|
+
{
|
|
441
|
+
userPoolId: c.userPoolId,
|
|
442
|
+
awsRegion: c.region,
|
|
443
|
+
defaultAction: AppSync.GraphQLApi.ALLOW,
|
|
444
|
+
}: AppSync.GraphQLApi.userPoolConfig
|
|
445
|
+
)
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
// Cognito as primary auth, AWS_IAM as additional provider for
|
|
449
|
+
// server-to-server lambdas (heartbeat, Plugin_Connected emission) signed via
|
|
450
|
+
// the existing IAM role.
|
|
451
|
+
let apiArgs: AppSync.GraphQLApi.args = {
|
|
452
|
+
authenticationType: AppSync.GraphQLApi
|
|
453
|
+
.AMAZON_COGNITO_USER_POOLS->Pulumi.Input.make,
|
|
454
|
+
userPoolConfig: userPoolConfigOut->Pulumi.Output.asInput,
|
|
455
|
+
additionalAuthenticationProviders: [
|
|
456
|
+
(
|
|
457
|
+
{
|
|
458
|
+
authenticationType: AppSync.GraphQLApi.AWS_IAM->Pulumi.Input.make,
|
|
459
|
+
}: AppSync.GraphQLApi.additionalAuthenticationProvider
|
|
460
|
+
)->Pulumi.Input.make,
|
|
461
|
+
]->Pulumi.Input.make,
|
|
462
|
+
}
|
|
463
|
+
let graphQLApi = AppSync.GraphQLApi.make(~name, ~args=apiArgs, ~opts=Some(customOpts))
|
|
464
|
+
|
|
465
|
+
(graphQLApi->Pulumi.Output.make, iamRole->Pulumi.Output.make)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
let generateFragment = (
|
|
469
|
+
~mutationEntries: array<ReventlessInfra.Api.mutationSchemaEntry>,
|
|
470
|
+
~queryEntries: array<ReventlessInfra.Api.querySchemaEntry>,
|
|
471
|
+
): Reventless.Plugin.apiSchemaFragment => {
|
|
472
|
+
let fragment = ReventlessCore.GraphQL_FragmentGenerator.generate(~mutationEntries, ~queryEntries)
|
|
473
|
+
injectAwsAuth(fragment, ~mutationEntries, ~queryEntries)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
let updateSchema = (
|
|
477
|
+
~api: Pulumi.Output.t<api>,
|
|
478
|
+
~baseFragment: Reventless.Plugin.apiSchemaFragment,
|
|
479
|
+
~pluginFragments: array<Reventless.Plugin.apiSchemaFragment>,
|
|
480
|
+
): promise<unit> => {
|
|
481
|
+
// Inject @aws_auth(cognito_groups: ["Admin"]) into all base fragment fields.
|
|
482
|
+
// The base fragment contains core Plugin aggregate queries/mutations — all Admin-only.
|
|
483
|
+
// Plugin fragments already have @aws_auth injected via generateFragment.
|
|
484
|
+
let augmentedBaseFragment = injectAwsAuthAll(baseFragment, ~group="Admin")
|
|
485
|
+
let sdl = ReventlessCore.GraphQL_Stitcher.stitch(~baseFragment=augmentedBaseFragment, ~pluginFragments)
|
|
486
|
+
// Resolve the API ID from the Output chain. In mock mode (tests) and in Lambda runtime
|
|
487
|
+
// (where the Output is backed by already-known values), this completes synchronously.
|
|
488
|
+
// The resulting promise wraps the AppSync SDK call.
|
|
489
|
+
let resultPromise: ref<promise<unit>> = ref(Promise.resolve())
|
|
490
|
+
let _ =
|
|
491
|
+
api
|
|
492
|
+
->Pulumi.Output.apply(graphQLApi =>
|
|
493
|
+
graphQLApi.id->Pulumi.Output.apply(apiId => {
|
|
494
|
+
let effect = deploySchemaWithRetry(getClient(), apiId, sdl)
|
|
495
|
+
let p = effect->Effect.runPromise
|
|
496
|
+
resultPromise.contents = p
|
|
497
|
+
})
|
|
498
|
+
)
|
|
499
|
+
resultPromise.contents
|
|
500
|
+
}
|