@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,653 @@
|
|
|
1
|
+
/** AppSync resolver backed by a Pulumi dynamic provider that retries
|
|
2
|
+
CreateResolver / UpdateResolver on the schema-propagation race:
|
|
3
|
+
|
|
4
|
+
NotFoundException: No field named X found on type Query
|
|
5
|
+
|
|
6
|
+
The `aws-native` Cloud Control handler does NOT internally wait for this
|
|
7
|
+
propagation; neither does the classic provider. A custom dynamic provider
|
|
8
|
+
that calls the AppSync SDK directly and retries with exponential backoff
|
|
9
|
+
is the only reliable solution.
|
|
10
|
+
|
|
11
|
+
Exposes the same `makeUnitJsResolver` / `makePipelineJsResolver` API as
|
|
12
|
+
`AppSync_Resolver_Native` so `QueryDbResolvers_AppSync` only needs a
|
|
13
|
+
one-line module swap.
|
|
14
|
+
|
|
15
|
+
State migration: adds an alias pointing at the old
|
|
16
|
+
`aws-native:appsync/resolver:Resolver` type so existing resources are
|
|
17
|
+
adopted in-place on first deploy (no delete+recreate).
|
|
18
|
+
|
|
19
|
+
See docs/plans/appsync-resolver-aws-native-retry.md. */
|
|
20
|
+
|
|
21
|
+
// ── AWS SDK bindings ─────────────────────────────────────────────────────────
|
|
22
|
+
//
|
|
23
|
+
// Pulumi dynamic providers serialise the provider object (and its captured
|
|
24
|
+
// closure of imports) into stack state. A static `@module("@aws-sdk/client-appsync")`
|
|
25
|
+
// binding pulls the SDK's transitive deps into that closure, and Pulumi's
|
|
26
|
+
// serialiser fails to resolve them at runtime (CJS/ESM dual-export confusion
|
|
27
|
+
// produces invalid module paths like
|
|
28
|
+
// `@aws-sdk/client-appsync/node_modules/@aws-sdk/region-config-resolver/dist-cjs/index.js`).
|
|
29
|
+
//
|
|
30
|
+
// Workaround: lazy-import the SDK at handler-invocation time via `dynImport`,
|
|
31
|
+
// so the SDK module is NOT part of the captured closure. Each provider method
|
|
32
|
+
// resolves the SDK on first use and caches an initialised client.
|
|
33
|
+
|
|
34
|
+
let log = ReventlessCore.Logger.fromEnv()
|
|
35
|
+
|
|
36
|
+
type appSyncClient
|
|
37
|
+
|
|
38
|
+
type sdkRuntime = {name: string, runtimeVersion: string}
|
|
39
|
+
|
|
40
|
+
let appsyncJsRuntime: sdkRuntime = {name: "APPSYNC_JS", runtimeVersion: "1.0.0"}
|
|
41
|
+
|
|
42
|
+
type sdkPipelineConfig = {functions: array<string>}
|
|
43
|
+
|
|
44
|
+
type sdkResolverInput = {
|
|
45
|
+
apiId: string,
|
|
46
|
+
typeName: string,
|
|
47
|
+
fieldName: string,
|
|
48
|
+
dataSourceName?: string,
|
|
49
|
+
kind?: string,
|
|
50
|
+
code?: string,
|
|
51
|
+
runtime?: sdkRuntime,
|
|
52
|
+
pipelineConfig?: sdkPipelineConfig,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type sdkResolverOutput = {resolverArn?: string}
|
|
56
|
+
type sdkResolverResult = {resolver?: sdkResolverOutput}
|
|
57
|
+
|
|
58
|
+
type createResolverCmd
|
|
59
|
+
type updateResolverCmd
|
|
60
|
+
type deleteResolverCmd
|
|
61
|
+
type getResolverCmd
|
|
62
|
+
|
|
63
|
+
type sdkDeleteInput = {apiId: string, typeName: string, fieldName: string}
|
|
64
|
+
|
|
65
|
+
// Shape of the dynamically-imported `@aws-sdk/client-appsync` module.
|
|
66
|
+
// Constructors are typed as `('arg) => 'class` so we can call them with `new`
|
|
67
|
+
// via a small JS interop helper.
|
|
68
|
+
type sdkModule = {
|
|
69
|
+
@as("AppSyncClient") clientCtor: unit => appSyncClient,
|
|
70
|
+
@as("CreateResolverCommand") createCtor: sdkResolverInput => createResolverCmd,
|
|
71
|
+
@as("UpdateResolverCommand") updateCtor: sdkResolverInput => updateResolverCmd,
|
|
72
|
+
@as("DeleteResolverCommand") deleteCtor: sdkDeleteInput => deleteResolverCmd,
|
|
73
|
+
@as("GetResolverCommand") getCtor: sdkDeleteInput => getResolverCmd,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Calls a constructor function with `new`. The SDK exports plain classes,
|
|
77
|
+
// so calling them as functions throws — we need `new`.
|
|
78
|
+
let newOf1: ('ctor, 'arg) => 'r = %raw(`(C, x) => new C(x)`)
|
|
79
|
+
let newOf0: 'ctor => 'r = %raw(`(C) => new C()`)
|
|
80
|
+
|
|
81
|
+
@send
|
|
82
|
+
external sendCreate: (appSyncClient, createResolverCmd) => promise<sdkResolverResult> = "send"
|
|
83
|
+
@send
|
|
84
|
+
external sendUpdate: (appSyncClient, updateResolverCmd) => promise<sdkResolverResult> = "send"
|
|
85
|
+
@send external sendDelete: (appSyncClient, deleteResolverCmd) => promise<unit> = "send"
|
|
86
|
+
@send external sendGet: (appSyncClient, getResolverCmd) => promise<sdkResolverResult> = "send"
|
|
87
|
+
|
|
88
|
+
// Dynamic ESM import — emitted by ReScript as a literal `import("...")`
|
|
89
|
+
// expression so the bundler does not statically capture the module.
|
|
90
|
+
@val external dynImport: string => promise<sdkModule> = "import"
|
|
91
|
+
|
|
92
|
+
// Lazy singletons — one SDK module + one client per deploy process.
|
|
93
|
+
let _sdk: ref<option<sdkModule>> = ref(None)
|
|
94
|
+
let _client: ref<option<appSyncClient>> = ref(None)
|
|
95
|
+
|
|
96
|
+
let getSdk = async (): sdkModule =>
|
|
97
|
+
switch _sdk.contents {
|
|
98
|
+
| Some(m) => m
|
|
99
|
+
| None =>
|
|
100
|
+
let m = await dynImport("@aws-sdk/client-appsync")
|
|
101
|
+
_sdk.contents = Some(m)
|
|
102
|
+
m
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let getClient = async (): appSyncClient =>
|
|
106
|
+
switch _client.contents {
|
|
107
|
+
| Some(c) => c
|
|
108
|
+
| None =>
|
|
109
|
+
let sdk = await getSdk()
|
|
110
|
+
let c = newOf0(sdk.clientCtor)
|
|
111
|
+
_client.contents = Some(c)
|
|
112
|
+
c
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ── Error classification ──────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
@get @return(nullable) external exnName: JsExn.t => option<string> = "name"
|
|
118
|
+
|
|
119
|
+
/** Returns `true` iff the error is the AppSync schema-propagation race:
|
|
120
|
+
`NotFoundException` with a message containing `"No field named"`.
|
|
121
|
+
|
|
122
|
+
Critical: must NOT match the delete-path `"No resolver found"` 404 —
|
|
123
|
+
those have the same exception name but a different message. */
|
|
124
|
+
let isFieldNotFoundError = (jsErr: JsExn.t): bool =>
|
|
125
|
+
switch (jsErr->exnName, JsExn.message(jsErr)) {
|
|
126
|
+
| (Some("NotFoundException"), Some(msg)) => msg->String.includes("No field named")
|
|
127
|
+
| _ => false
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Returns `true` iff a delete should be treated as a no-op because the
|
|
131
|
+
target resource no longer exists in AWS. Covers three cases:
|
|
132
|
+
|
|
133
|
+
- `"API not found."` — the AppSync API itself was already deleted (e.g.
|
|
134
|
+
manually in the console or by a prior teardown); the resolver cannot
|
|
135
|
+
exist without its parent API.
|
|
136
|
+
- `"No resolver found"` — the API exists but the resolver was already
|
|
137
|
+
removed (diverged Pulumi state).
|
|
138
|
+
- `"Type not found"` — the parent GraphQL type was dropped from the schema
|
|
139
|
+
(e.g. a plugin's schema fragment was lost during a runtime re-stitch),
|
|
140
|
+
taking every field-attached resolver with it; resolver absent is the
|
|
141
|
+
desired end-state, so `refresh` should report drift and a subsequent
|
|
142
|
+
`up` will recreate against the restored schema.
|
|
143
|
+
|
|
144
|
+
In all cases the desired end-state (resolver absent) is already reached,
|
|
145
|
+
so the Pulumi delete should succeed. */
|
|
146
|
+
let isAlreadyDeletedError = (jsErr: JsExn.t): bool =>
|
|
147
|
+
switch (jsErr->exnName, JsExn.message(jsErr)) {
|
|
148
|
+
| (Some("NotFoundException"), Some(msg)) =>
|
|
149
|
+
msg->String.includes("API not found") ||
|
|
150
|
+
msg->String.includes("No resolver found") ||
|
|
151
|
+
msg->String.includes("Type not found")
|
|
152
|
+
| _ => false
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Returns `true` iff AppSync rejected the create because a resolver for that
|
|
156
|
+
field already exists (Pulumi state / AppSync divergence). */
|
|
157
|
+
let isAlreadyExistsError = (jsErr: JsExn.t): bool =>
|
|
158
|
+
switch (jsErr->exnName, JsExn.message(jsErr)) {
|
|
159
|
+
| (Some("BadRequestException"), Some(msg)) => msg->String.includes("Only one resolver is allowed")
|
|
160
|
+
| _ => false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Returns `true` iff AppSync rejected the mutation because the API-level
|
|
164
|
+
schema-creation lock is held by an in-flight `StartSchemaCreation`:
|
|
165
|
+
`ConcurrentModificationException` with message
|
|
166
|
+
`"Schema is currently being altered"`.
|
|
167
|
+
|
|
168
|
+
AppSync holds a single per-API lock during schema creation and rejects any
|
|
169
|
+
concurrent `CreateResolver` / `UpdateResolver` (and `CreateDataSource`,
|
|
170
|
+
`CreateFunction`) until the schema reaches ACTIVE. Plugin_Builder gates
|
|
171
|
+
resolver creation on the plugin schema push, but admin-side resolvers in
|
|
172
|
+
`Platform_Admin.construct` are created synchronously and race the platform
|
|
173
|
+
schema push initiated from `Platform.res`. */
|
|
174
|
+
let isSchemaAlteringError = (jsErr: JsExn.t): bool =>
|
|
175
|
+
switch (jsErr->exnName, JsExn.message(jsErr)) {
|
|
176
|
+
| (Some("ConcurrentModificationException"), Some(msg)) =>
|
|
177
|
+
msg->String.includes("Schema is currently being altered")
|
|
178
|
+
| _ => false
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ── Retry helper ─────────────────────────────────────────────────────────────
|
|
182
|
+
//
|
|
183
|
+
// Pulumi serialises the dynamic provider object (and its entire closure of
|
|
184
|
+
// captured references) into stack state. Anything reachable from the provider
|
|
185
|
+
// methods must be JS-serialisable. `Effect` (from the `effect` package)
|
|
186
|
+
// captures runtime-level state that fails Pulumi's `serializeFunction`, so
|
|
187
|
+
// the retry loop here is hand-rolled rather than `Effect.retry` + `Schedule`.
|
|
188
|
+
// See https://www.pulumi.com/docs/concepts/resources/dynamic-providers/ —
|
|
189
|
+
// "the entire closure of values captured by the provider is serialised".
|
|
190
|
+
|
|
191
|
+
@val external setTimeout: (unit => unit, int) => int = "setTimeout"
|
|
192
|
+
|
|
193
|
+
/** Throws a JavaScript exception directly (bypasses the ReScript exn wrapper). */
|
|
194
|
+
let jsThrow: JsExn.t => 'a = %raw(`e => { throw e }`)
|
|
195
|
+
|
|
196
|
+
/** Hand-rolled retry on two transient AppSync races with capped exponential
|
|
197
|
+
backoff:
|
|
198
|
+
|
|
199
|
+
- `NotFoundException / No field named` — schema-propagation race after a
|
|
200
|
+
successful `StartSchemaCreation`. Backstop for the per-plugin dedup
|
|
201
|
+
flow (see `docs/plans/appsync-schema-push-dedup.md`).
|
|
202
|
+
- `ConcurrentModificationException / Schema is currently being altered` —
|
|
203
|
+
API-level lock contention with an in-flight `StartSchemaCreation` on
|
|
204
|
+
the same API (admin resolvers racing the platform schema push from
|
|
205
|
+
`Platform.res`).
|
|
206
|
+
|
|
207
|
+
Backoff: delay starts at 2 s, doubles each attempt, caps at 30 s. Up to
|
|
208
|
+
8 attempts → ~150 s total budget — generous enough to outlast a typical
|
|
209
|
+
admin schema push (`waitForSchemaActive` polls 30 × 500 ms = 15 s and
|
|
210
|
+
real propagation usually finishes well inside that). The cap doubles as
|
|
211
|
+
a coarse fairness bound: if a schema push is genuinely taking > 2 min,
|
|
212
|
+
failing loud is better than retrying forever.
|
|
213
|
+
|
|
214
|
+
This is a **backstop**. The architectural fix for the
|
|
215
|
+
`ConcurrentModificationException` case is to gate
|
|
216
|
+
`Platform_Admin.construct`'s `createResolvers` on the admin schema push,
|
|
217
|
+
mirroring what Plugin_Builder does with `schemaPushed`. */
|
|
218
|
+
let rec runWithRaceRetry = async (
|
|
219
|
+
~attempt: int=0,
|
|
220
|
+
~maxAttempts: int=8,
|
|
221
|
+
~delayMs: int=2000,
|
|
222
|
+
~maxDelayMs: int=30000,
|
|
223
|
+
makeCall: unit => promise<'a>,
|
|
224
|
+
): 'a => {
|
|
225
|
+
try {
|
|
226
|
+
await makeCall()
|
|
227
|
+
} catch {
|
|
228
|
+
| exn =>
|
|
229
|
+
let jsExn = exn->JsExn.fromException
|
|
230
|
+
let name = jsExn->Option.flatMap(exnName)->Option.getOr("(no name)")
|
|
231
|
+
let msg = jsExn->Option.flatMap(JsExn.message)->Option.getOr("(no message)")
|
|
232
|
+
let isRetryable =
|
|
233
|
+
attempt < maxAttempts &&
|
|
234
|
+
jsExn->Option.mapOr(false, e => isFieldNotFoundError(e) || isSchemaAlteringError(e))
|
|
235
|
+
if isRetryable {
|
|
236
|
+
log.info(
|
|
237
|
+
~comp="AppSync_Resolver_Retrying",
|
|
238
|
+
`attempt ${(attempt + 1)->Int.toString}/${maxAttempts->Int.toString} failed, retrying in ${delayMs->Int.toString}ms: ${name}: ${msg}`,
|
|
239
|
+
)
|
|
240
|
+
let _ = await Promise.make((resolve, _) => setTimeout(resolve, delayMs)->ignore)
|
|
241
|
+
let nextDelay = delayMs * 2
|
|
242
|
+
let cappedDelay = nextDelay > maxDelayMs ? maxDelayMs : nextDelay
|
|
243
|
+
await runWithRaceRetry(
|
|
244
|
+
~attempt=attempt + 1,
|
|
245
|
+
~maxAttempts,
|
|
246
|
+
~delayMs=cappedDelay,
|
|
247
|
+
~maxDelayMs,
|
|
248
|
+
makeCall,
|
|
249
|
+
)
|
|
250
|
+
} else {
|
|
251
|
+
// Only log when we exhausted retries on a retryable error — not on the
|
|
252
|
+
// first non-retryable failure, which the caller may handle itself.
|
|
253
|
+
if attempt > 0 {
|
|
254
|
+
log.warn(
|
|
255
|
+
~comp="AppSync_Resolver_Retrying",
|
|
256
|
+
`giving up after ${(attempt + 1)->Int.toString} attempts: ${name}: ${msg}`,
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
// Re-throw the original JavaScript error so Pulumi can display its message.
|
|
260
|
+
// throw(exn) would rethrow the ReScript exception wrapper (RE_EXN_ID), which
|
|
261
|
+
// has no `.message` property and causes Pulumi to display "error: undefined".
|
|
262
|
+
switch jsExn {
|
|
263
|
+
| Some(e) => jsThrow(e)
|
|
264
|
+
| None => throw(exn)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ── Provider inputs (plain JS values delivered by Pulumi after resolution) ────
|
|
271
|
+
|
|
272
|
+
type providerInputs = {
|
|
273
|
+
apiId: string,
|
|
274
|
+
typeName: string,
|
|
275
|
+
fieldName: string,
|
|
276
|
+
dataSourceName?: string,
|
|
277
|
+
kind: string,
|
|
278
|
+
code: string,
|
|
279
|
+
functions?: array<string>,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ── SDK input builder ─────────────────────────────────────────────────────────
|
|
283
|
+
|
|
284
|
+
let buildSdkInput = (inputs: providerInputs): sdkResolverInput => {
|
|
285
|
+
// Build the base required fields; then spread optional ones to keep
|
|
286
|
+
// the SDK payload free of explicit `undefined` keys.
|
|
287
|
+
let base: sdkResolverInput = {
|
|
288
|
+
apiId: inputs.apiId,
|
|
289
|
+
typeName: inputs.typeName,
|
|
290
|
+
fieldName: inputs.fieldName,
|
|
291
|
+
kind: inputs.kind,
|
|
292
|
+
code: inputs.code,
|
|
293
|
+
runtime: appsyncJsRuntime,
|
|
294
|
+
}
|
|
295
|
+
let withDs = switch inputs.dataSourceName {
|
|
296
|
+
| Some(ds) => {...base, dataSourceName: ds}
|
|
297
|
+
| None => base
|
|
298
|
+
}
|
|
299
|
+
switch inputs.functions {
|
|
300
|
+
| Some(fns) => {...withDs, pipelineConfig: {functions: fns}}
|
|
301
|
+
| None => withDs
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let extractArn = (resp: sdkResolverResult): string =>
|
|
306
|
+
resp.resolver->Option.flatMap(r => r.resolverArn)->Option.getOr("unknown-arn")
|
|
307
|
+
|
|
308
|
+
// ── Dynamic provider method types ─────────────────────────────────────────────
|
|
309
|
+
|
|
310
|
+
// Pulumi passes OUTPUTS (not inputs) to diff/delete/update handlers, so all fields
|
|
311
|
+
// that diff_ compares must be stored in createOuts/updateResult.outs, otherwise
|
|
312
|
+
// olds.fieldX is undefined at diff time and `undefined != newValue` is always true
|
|
313
|
+
// in JavaScript — causing every deploy to trigger a delete+recreate.
|
|
314
|
+
type createOuts = {
|
|
315
|
+
resolverArn: string,
|
|
316
|
+
apiId: string,
|
|
317
|
+
typeName: string,
|
|
318
|
+
fieldName: string,
|
|
319
|
+
kind: string,
|
|
320
|
+
code: string,
|
|
321
|
+
dataSourceName?: string,
|
|
322
|
+
functions?: array<string>,
|
|
323
|
+
}
|
|
324
|
+
type createResult = {id: string, outs: createOuts}
|
|
325
|
+
type updateResult = {outs: createOuts}
|
|
326
|
+
type diffResult = {changes: bool, replaces: array<string>, deleteBeforeReplace: bool}
|
|
327
|
+
// Optional fields so `read_` can return `{}` when the resolver no longer exists
|
|
328
|
+
// in AppSync — Pulumi treats an empty `ReadResult` as "resource gone", removes
|
|
329
|
+
// it from state on `pulumi refresh`, and re-creates it on the next `pulumi up`.
|
|
330
|
+
type readResult = {id?: string, props?: providerInputs}
|
|
331
|
+
|
|
332
|
+
// ── Provider methods ──────────────────────────────────────────────────────────
|
|
333
|
+
|
|
334
|
+
let makeOuts = (resolverArn: string, inputs: providerInputs): createOuts => {
|
|
335
|
+
let base: createOuts = {
|
|
336
|
+
resolverArn,
|
|
337
|
+
apiId: inputs.apiId,
|
|
338
|
+
typeName: inputs.typeName,
|
|
339
|
+
fieldName: inputs.fieldName,
|
|
340
|
+
kind: inputs.kind,
|
|
341
|
+
code: inputs.code,
|
|
342
|
+
}
|
|
343
|
+
let withDs = switch inputs.dataSourceName {
|
|
344
|
+
| Some(ds) => {...base, dataSourceName: ds}
|
|
345
|
+
| None => base
|
|
346
|
+
}
|
|
347
|
+
switch inputs.functions {
|
|
348
|
+
| Some(fns) => {...withDs, functions: fns}
|
|
349
|
+
| None => withDs
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let create = async (inputs: providerInputs): createResult => {
|
|
354
|
+
let sdk = await getSdk()
|
|
355
|
+
let client = await getClient()
|
|
356
|
+
let arn =
|
|
357
|
+
try {
|
|
358
|
+
await runWithRaceRetry(() =>
|
|
359
|
+
client
|
|
360
|
+
->sendCreate(newOf1(sdk.createCtor, inputs->buildSdkInput))
|
|
361
|
+
->Promise.thenResolve(extractArn)
|
|
362
|
+
)
|
|
363
|
+
} catch {
|
|
364
|
+
| exn =>
|
|
365
|
+
// If the resolver already exists (AppSync / Pulumi state divergence from a
|
|
366
|
+
// previous partial deploy), update it to match desired config and adopt its ARN.
|
|
367
|
+
// This makes create idempotent and lets stuck stacks recover without manual intervention.
|
|
368
|
+
let handled =
|
|
369
|
+
exn->JsExn.fromException->Option.mapOr(false, isAlreadyExistsError)
|
|
370
|
+
if handled {
|
|
371
|
+
let resp = await client->sendUpdate(newOf1(sdk.updateCtor, inputs->buildSdkInput))
|
|
372
|
+
extractArn(resp)
|
|
373
|
+
} else {
|
|
374
|
+
let jsExn = exn->JsExn.fromException
|
|
375
|
+
switch jsExn {
|
|
376
|
+
| Some(e) => jsThrow(e)
|
|
377
|
+
| None => throw(exn)
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
{id: arn, outs: makeOuts(arn, inputs)}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let update = async (id: string, _olds: providerInputs, news: providerInputs): updateResult => {
|
|
385
|
+
let sdk = await getSdk()
|
|
386
|
+
let client = await getClient()
|
|
387
|
+
let arn =
|
|
388
|
+
try {
|
|
389
|
+
let _ = await runWithRaceRetry(() =>
|
|
390
|
+
client->sendUpdate(newOf1(sdk.updateCtor, news->buildSdkInput))
|
|
391
|
+
)
|
|
392
|
+
// ARN is stable across updates — reuse the existing id
|
|
393
|
+
id
|
|
394
|
+
} catch {
|
|
395
|
+
| exn =>
|
|
396
|
+
// If the resolver was deleted from AppSync (e.g. by a schema replacement),
|
|
397
|
+
// fall back to CreateResolver so the resource is transparently recreated.
|
|
398
|
+
let handled =
|
|
399
|
+
exn->JsExn.fromException->Option.mapOr(false, isAlreadyDeletedError)
|
|
400
|
+
if handled {
|
|
401
|
+
let resp = await runWithRaceRetry(() =>
|
|
402
|
+
client
|
|
403
|
+
->sendCreate(newOf1(sdk.createCtor, news->buildSdkInput))
|
|
404
|
+
->Promise.thenResolve(extractArn)
|
|
405
|
+
)
|
|
406
|
+
resp
|
|
407
|
+
} else {
|
|
408
|
+
let jsExn = exn->JsExn.fromException
|
|
409
|
+
switch jsExn {
|
|
410
|
+
| Some(e) => jsThrow(e)
|
|
411
|
+
| None => throw(exn)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
{outs: makeOuts(arn, news)}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Parse apiId, typeName, fieldName from the resolver ARN.
|
|
419
|
+
ARN format: arn:aws:appsync:{region}:{account}:apis/{apiId}/types/{typeName}/resolvers/{fieldName}
|
|
420
|
+
Pulumi dynamic providers pass OUTPUTS (not inputs) to delete, so props.apiId etc. may be
|
|
421
|
+
undefined. The ARN passed as `id` is always available and contains all needed identifiers. */
|
|
422
|
+
let parseArn = (arn: string): option<sdkDeleteInput> => {
|
|
423
|
+
let parts = arn->String.split("/")
|
|
424
|
+
switch (parts->Array.get(1), parts->Array.get(3), parts->Array.get(5)) {
|
|
425
|
+
| (Some(apiId), Some(typeName), Some(fieldName)) => Some({apiId, typeName, fieldName})
|
|
426
|
+
| _ => None
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
let delete_ = async (id: string, props: providerInputs): unit => {
|
|
431
|
+
let sdk = await getSdk()
|
|
432
|
+
let client = await getClient()
|
|
433
|
+
// Prefer parsing from the ARN since Pulumi passes outputs (not inputs) to delete handlers.
|
|
434
|
+
// Fall back to props fields for backward compat with older state that stores inputs in outs.
|
|
435
|
+
let deleteInput: sdkDeleteInput = switch parseArn(id) {
|
|
436
|
+
| Some(parsed) => parsed
|
|
437
|
+
| None => {apiId: props.apiId, typeName: props.typeName, fieldName: props.fieldName}
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
await client->sendDelete(newOf1(sdk.deleteCtor, deleteInput))
|
|
441
|
+
} catch {
|
|
442
|
+
| exn if exn->JsExn.fromException->Option.mapOr(false, isAlreadyDeletedError) => ()
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Guard against undefined in olds for resources created with older code that did not
|
|
447
|
+
// store all fields in createOuts. In JavaScript `undefined !== value` evaluates to
|
|
448
|
+
// true, which would incorrectly flag every such field as requiring replacement.
|
|
449
|
+
let isDefined: string => bool = %raw(`x => x !== undefined && x !== null`)
|
|
450
|
+
|
|
451
|
+
/** Returns `true` for fields whose change requires delete+recreate.
|
|
452
|
+
AppSync does not allow renaming the API, type, field, or kind in-place. */
|
|
453
|
+
let diff_ = (_id: string, olds: providerInputs, news: providerInputs): diffResult => {
|
|
454
|
+
let replaces =
|
|
455
|
+
[
|
|
456
|
+
if isDefined(olds.apiId) && olds.apiId != news.apiId {Some("apiId")} else {None},
|
|
457
|
+
if isDefined(olds.typeName) && olds.typeName != news.typeName {Some("typeName")} else {None},
|
|
458
|
+
if isDefined(olds.fieldName) && olds.fieldName != news.fieldName {Some("fieldName")} else {None},
|
|
459
|
+
if isDefined(olds.kind) && olds.kind != news.kind {Some("kind")} else {None},
|
|
460
|
+
]->Array.filterMap(x => x)
|
|
461
|
+
// For in-place update detection (non-replace changes): compare as-is.
|
|
462
|
+
// If olds is from old state (missing fields), this may trigger an unnecessary
|
|
463
|
+
// update, but that is safe — the update simply re-applies the resolver.
|
|
464
|
+
let changes =
|
|
465
|
+
replaces->Array.length > 0 ||
|
|
466
|
+
olds.code != news.code ||
|
|
467
|
+
olds.dataSourceName != news.dataSourceName ||
|
|
468
|
+
olds.functions != news.functions
|
|
469
|
+
{changes, replaces, deleteBeforeReplace: true}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** Read live state for `pulumi refresh`.
|
|
473
|
+
|
|
474
|
+
Calls `GetResolver` against AppSync. If the resolver exists, returns the
|
|
475
|
+
stored inputs unchanged so Pulumi keeps the resource in state. If AppSync
|
|
476
|
+
reports the resolver as missing (`NotFoundException / No resolver found`
|
|
477
|
+
or `API not found.`), returns `{}` to signal drift — Pulumi removes the
|
|
478
|
+
resource from state on `pulumi refresh` and the next `pulumi up` recreates
|
|
479
|
+
it via `create`.
|
|
480
|
+
|
|
481
|
+
Healing flow: `pulumi refresh && pulumi up` after a schema replacement
|
|
482
|
+
that silently drops resolvers in AppSync. Without the live check the
|
|
483
|
+
`update` AlreadyDeleted→Create fallback only fires when an input field
|
|
484
|
+
changes; refresh alone could not detect the drift. */
|
|
485
|
+
let read_ = async (id: string, props: providerInputs): readResult => {
|
|
486
|
+
let sdk = await getSdk()
|
|
487
|
+
let client = await getClient()
|
|
488
|
+
// Prefer parsing the ARN since Pulumi passes outputs (not inputs) to read
|
|
489
|
+
// handlers; fall back to props fields for older state.
|
|
490
|
+
let getInput: sdkDeleteInput = switch parseArn(id) {
|
|
491
|
+
| Some(parsed) => parsed
|
|
492
|
+
| None => {apiId: props.apiId, typeName: props.typeName, fieldName: props.fieldName}
|
|
493
|
+
}
|
|
494
|
+
try {
|
|
495
|
+
let _ = await client->sendGet(newOf1(sdk.getCtor, getInput))
|
|
496
|
+
{id, props}
|
|
497
|
+
} catch {
|
|
498
|
+
| exn if exn->JsExn.fromException->Option.mapOr(false, isAlreadyDeletedError) =>
|
|
499
|
+
log.info(
|
|
500
|
+
~comp="AppSync_Resolver_Retrying",
|
|
501
|
+
`resolver ${getInput.typeName}.${getInput.fieldName} missing in AppSync; reporting drift`,
|
|
502
|
+
)
|
|
503
|
+
({}: readResult)
|
|
504
|
+
| exn =>
|
|
505
|
+
// Propagate non-404 errors (network/auth) so refresh fails loudly rather
|
|
506
|
+
// than silently dropping the resource from state.
|
|
507
|
+
let jsExn = exn->JsExn.fromException
|
|
508
|
+
switch jsExn {
|
|
509
|
+
| Some(e) => jsThrow(e)
|
|
510
|
+
| None => throw(exn)
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Provider as a plain JS object (no Pulumi Output captures — all state via inputs/olds/news)
|
|
516
|
+
let provider = {
|
|
517
|
+
"create": create,
|
|
518
|
+
"update": update,
|
|
519
|
+
"delete": delete_,
|
|
520
|
+
"diff": diff_,
|
|
521
|
+
"read": read_,
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// ── Pulumi dynamic resource binding ──────────────────────────────────────────
|
|
525
|
+
|
|
526
|
+
/** Output shape is identical to AwsNative.AppSync.Resolver.t so
|
|
527
|
+
`Util.AppSync.toResourceNative` works without modification. */
|
|
528
|
+
type t = PulumiAws.AwsNative.AppSync.Resolver.t
|
|
529
|
+
|
|
530
|
+
type constructorProps = {
|
|
531
|
+
apiId: Pulumi.Input.t<string>,
|
|
532
|
+
typeName: Pulumi.Input.t<string>,
|
|
533
|
+
fieldName: Pulumi.Input.t<string>,
|
|
534
|
+
dataSourceName?: Pulumi.Input.t<string>,
|
|
535
|
+
kind: Pulumi.Input.t<string>,
|
|
536
|
+
code: Pulumi.Input.t<string>,
|
|
537
|
+
functions?: Pulumi.Input.t<array<string>>,
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// pulumi.dynamic.Resource constructor: (provider, name, props, opts)
|
|
541
|
+
// Use the explicit /index.js path because @pulumi/pulumi/dynamic is a
|
|
542
|
+
// directory import not resolvable in ESM mode.
|
|
543
|
+
@module("@pulumi/pulumi/dynamic/index.js") @new
|
|
544
|
+
external _newResource: ('provider, string, 'props, Pulumi.CustomResourceOptions.t) => t =
|
|
545
|
+
"Resource"
|
|
546
|
+
|
|
547
|
+
let makeResolver = (
|
|
548
|
+
~name: string,
|
|
549
|
+
~props: constructorProps,
|
|
550
|
+
~opts: option<Pulumi.CustomResourceOptions.t>,
|
|
551
|
+
): t => {
|
|
552
|
+
// Always include an alias for the aws-native resource previously in state —
|
|
553
|
+
// prevents delete+recreate on first deploy (in-place adoption).
|
|
554
|
+
let migrationAlias = Pulumi.Alias.make(
|
|
555
|
+
~type_="aws-native:appsync/resolver:Resolver",
|
|
556
|
+
~name,
|
|
557
|
+
(),
|
|
558
|
+
)
|
|
559
|
+
let finalOpts: Pulumi.CustomResourceOptions.t = switch opts {
|
|
560
|
+
| Some(o) => {...o, aliases: [migrationAlias]}
|
|
561
|
+
| None => {aliases: [migrationAlias]}
|
|
562
|
+
}
|
|
563
|
+
_newResource(provider, name, props, finalOpts)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ── Public API (identical signatures to AppSync_Resolver_Native) ──────────────
|
|
567
|
+
|
|
568
|
+
module Functions = PulumiAws.AppSync.Resolver.Functions
|
|
569
|
+
|
|
570
|
+
let makeSubscriptionResolverCode = (~filter: option<string>): string =>
|
|
571
|
+
switch filter {
|
|
572
|
+
| None => `export function request(ctx) {
|
|
573
|
+
return { payload: null };
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export function response(ctx) {
|
|
577
|
+
return ctx.result;
|
|
578
|
+
}`
|
|
579
|
+
| Some(f) => `export function request(ctx) {
|
|
580
|
+
extensions.setSubscriptionFilter(${f});
|
|
581
|
+
return {};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export function response(ctx) {
|
|
585
|
+
return ctx.result;
|
|
586
|
+
}`
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
let makeSubscriptionResolver = (
|
|
590
|
+
~name,
|
|
591
|
+
~api: Pulumi.Output.t<PulumiAws.AppSync.GraphQLApi.t>,
|
|
592
|
+
~field,
|
|
593
|
+
~dataSourceName: option<Pulumi.Input.t<string>>=?,
|
|
594
|
+
~subscriptionFilter: option<string>=?,
|
|
595
|
+
~opts: option<Pulumi.CustomResourceOptions.t>=?,
|
|
596
|
+
) => {
|
|
597
|
+
let baseProps: constructorProps = {
|
|
598
|
+
apiId: api->Pulumi.Output.flatMap(a => a.id)->Pulumi.Output.asInput,
|
|
599
|
+
typeName: "Subscription"->Pulumi.Input.make,
|
|
600
|
+
fieldName: field->Pulumi.Input.make,
|
|
601
|
+
kind: "UNIT"->Pulumi.Input.make,
|
|
602
|
+
code: makeSubscriptionResolverCode(~filter=subscriptionFilter)->Pulumi.Input.make,
|
|
603
|
+
}
|
|
604
|
+
let props = switch dataSourceName {
|
|
605
|
+
| Some(ds) => {...baseProps, dataSourceName: ds}
|
|
606
|
+
| None => baseProps
|
|
607
|
+
}
|
|
608
|
+
makeResolver(~name, ~props, ~opts)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
let makeUnitJsResolver = (
|
|
612
|
+
~name,
|
|
613
|
+
~api: Pulumi.Output.t<PulumiAws.AppSync.GraphQLApi.t>,
|
|
614
|
+
~dataSourceName,
|
|
615
|
+
~type_,
|
|
616
|
+
~field,
|
|
617
|
+
~code,
|
|
618
|
+
~opts: option<Pulumi.CustomResourceOptions.t>=?,
|
|
619
|
+
) =>
|
|
620
|
+
makeResolver(
|
|
621
|
+
~name,
|
|
622
|
+
~props={
|
|
623
|
+
apiId: api->Pulumi.Output.flatMap(a => a.id)->Pulumi.Output.asInput,
|
|
624
|
+
typeName: type_,
|
|
625
|
+
fieldName: field,
|
|
626
|
+
dataSourceName: dataSourceName,
|
|
627
|
+
kind: "UNIT"->Pulumi.Input.make,
|
|
628
|
+
code,
|
|
629
|
+
},
|
|
630
|
+
~opts,
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
let makePipelineJsResolver = (
|
|
634
|
+
~name,
|
|
635
|
+
~api: Pulumi.Output.t<PulumiAws.AppSync.GraphQLApi.t>,
|
|
636
|
+
~type_,
|
|
637
|
+
~field,
|
|
638
|
+
~code,
|
|
639
|
+
~functions: array<PulumiAws.AppSync.Function.t>,
|
|
640
|
+
~opts: option<Pulumi.CustomResourceOptions.t>=?,
|
|
641
|
+
) =>
|
|
642
|
+
makeResolver(
|
|
643
|
+
~name,
|
|
644
|
+
~props={
|
|
645
|
+
apiId: api->Pulumi.Output.flatMap(a => a.id)->Pulumi.Output.asInput,
|
|
646
|
+
typeName: type_,
|
|
647
|
+
fieldName: field,
|
|
648
|
+
kind: "PIPELINE"->Pulumi.Input.make,
|
|
649
|
+
code,
|
|
650
|
+
functions: functions->Array.map(f => f.functionId)->Pulumi.Output.all->Pulumi.Output.asInput,
|
|
651
|
+
},
|
|
652
|
+
~opts,
|
|
653
|
+
)
|