@reventlessdev/reventless-aws 3.0.0-alpha.344 → 3.0.0-alpha.346
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 +36 -0
- package/package.json +15 -12
- package/run-provision-accounts.mjs +3 -0
- package/run-provision-admin.mjs +3 -0
- package/scripts/ProvisionAccounts.res +325 -0
- package/scripts/ProvisionAccounts.res.mjs +337 -0
- package/scripts/ProvisionAdmin.res +275 -0
- package/scripts/ProvisionAdmin.res.mjs +289 -0
- package/scripts/ProvisionCognito.res +149 -0
- package/scripts/ProvisionCognito.res.mjs +98 -0
- package/scripts/ProvisionIdentity.res +84 -14
- package/scripts/ProvisionIdentity.res.mjs +72 -7
- package/scripts/ProvisionProvider.res +104 -0
- package/scripts/ProvisionProvider.res.mjs +123 -0
- package/src/Platform.res +358 -329
- package/src/Platform.res.mjs +24 -12
- package/src/Platform_Casts.res +13 -4
- package/src/Platform_Stack.res +119 -9
- package/src/Platform_Stack.res.mjs +42 -4
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res +8 -4
- package/src/adapter/Api/AppSync_EventsApi.res +12 -14
- package/src/adapter/Api/AppSync_Resolver_Native.res +3 -4
- package/src/adapter/Api/AppSync_Resolver_Retrying.res +78 -70
- package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +11 -8
- package/src/adapter/Api/Platform_AdminScan_Ops.res +15 -14
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +10 -2
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +40 -50
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +39 -32
- package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +5 -2
- package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +0 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -4
- package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +5 -2
- package/src/adapter/Auth/Auth_Cognito.res +3 -9
- package/src/adapter/Auth/Auth_LoginIdentifier.res +66 -0
- package/src/adapter/Auth/Auth_LoginIdentifier.res.mjs +70 -0
- package/src/adapter/Auth/Auth_SignUpMode.res +78 -0
- package/src/adapter/Auth/Auth_SignUpMode.res.mjs +56 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +1 -4
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +3 -1
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +1 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +7 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +6 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +7 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +24 -18
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +9 -4
- package/src/adapter/CommandTopic/CommandTopicRegistry.res +1 -4
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +15 -15
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +9 -5
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +179 -213
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +5 -5
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +6 -2
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +14 -7
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +14 -7
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +6 -3
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +6 -1
- package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +13 -17
- package/src/adapter/EventLog/EventLogStorage_Postgres.res +7 -4
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +12 -7
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +4 -2
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +3 -2
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +20 -12
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +21 -9
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -3
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +6 -3
- package/src/adapter/Mcp/MCP_Lambda.res +31 -46
- package/src/adapter/Messaging/Messaging_Ses_Backend.res +11 -7
- package/src/adapter/Messaging/Messaging_Ses_Backend.res.mjs +2 -4
- package/src/adapter/Monitoring/Monitoring_CloudWatch.res +16 -16
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +5 -10
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +4 -2
- package/src/adapter/Postgres/PgConnection.res +6 -5
- package/src/adapter/Postgres/PgMigration_Builder.res +4 -8
- package/src/adapter/Postgres/PgRuntime.res +4 -7
- package/src/adapter/QueryDb/PgQueryResolver_Builder.res +9 -11
- package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +22 -21
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +114 -111
- package/src/adapter/QueryDb/QueryDbResolvers_Lambda.res +1 -7
- package/src/adapter/QueryDb/QueryDbStorage.res +4 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +23 -24
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +8 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +71 -73
- package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +5 -2
- package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +1 -4
- package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +8 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +73 -81
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +72 -78
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +44 -67
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +44 -67
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +53 -82
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +47 -77
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +23 -11
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +5 -1
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -97
- package/src/adapter/Runtime/CounterEntryPoint_Ops.res +2 -7
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -10
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +24 -15
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +17 -37
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +31 -57
- package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +18 -24
- package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -5
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +4 -3
- package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +4 -2
- package/src/adapter/Runtime/PgMigrationEntryPoint.res +0 -1
- package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +3 -2
- package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -2
- package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +4 -5
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +22 -10
- package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +8 -2
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +14 -31
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +16 -17
- package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +10 -9
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +46 -52
- package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +36 -41
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +31 -37
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +6 -7
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +4 -6
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +2 -6
- package/src/adapter/StateTopic/StateTopic_AppSync.res +21 -16
- package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +36 -32
- package/src/adapter/Task/TaskBucket_S3.res +6 -1
- package/src/adapter/Upload/Upload_Claim_S3.res +17 -20
- package/src/adapter/Upload/Upload_Claim_S3_Ops.res +5 -2
- package/src/adapter/Upload/Upload_Presign_S3.res +51 -49
- package/src/capability/Capability_Geocoding_AwsLocation.res +4 -1
- package/src/capability/Capability_Messaging.res +4 -5
- package/src/capability/Capability_Messaging_Ses.res +3 -1
- package/src/capability/Capability_ObjectStore_S3.res +1 -7
- package/src/components/Api/AppSync_Adapter.res +80 -109
- package/src/components/Api/AppSync_Adapter.res.mjs +26 -60
- package/src/components/Api/AppSync_SdlDecorate.res +118 -31
- package/src/components/Api/AppSync_SdlDecorate.res.mjs +45 -0
- package/src/components/AutomationSlice_Builder.res +6 -4
- package/src/components/ExtensionPoint_Builder.res +9 -10
- package/src/components/InboundTranslationSlice_Builder.res +7 -8
- package/src/components/OutboundTranslationSlice_Builder.res +14 -8
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
- package/src/components/SideEffectHandler_Single.res +4 -4
- package/src/components/StateViewSlice_Builder.res +6 -4
- package/src/components/StateViewSlice_Builder_Stream.res +6 -4
- package/src/components/Task_Builder_PerBucket.res +10 -11
- package/src/plugin/cloner/ClonerRunner_Fargate.res +3 -10
- package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +1 -4
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +5 -5
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +19 -21
- package/src/plugin/runtime/PluginRuntime_Builder.res +167 -188
- package/src/plugin/runtime/Util_PluginMessage_Runtime.res +6 -5
- package/src/plugin/stack/Plugin_Stack.res +104 -103
- package/src/util/Util_AlarmSpec.res +2 -1
- package/src/util/Util_AppSync.res +8 -2
- package/src/util/Util_AppSync_Caller.res +15 -14
- package/src/util/Util_Bundle.res +46 -42
- package/src/util/Util_CognitoGroupUser_Runtime.res +32 -34
- package/src/util/Util_Cognito_Runtime.res +11 -7
- package/src/util/Util_DeadLetterQueue.res +12 -2
- package/src/util/Util_DynamoDb.res +5 -3
- package/src/util/Util_DynamoDbStream.res +7 -3
- package/src/util/Util_DynamoDbStream_Runtime.res +1 -2
- package/src/util/Util_DynamoDb_Runtime.res +23 -41
- package/src/util/Util_HostUiDomain.res +6 -1
- package/src/util/Util_Kinesis_Runtime.res +10 -11
- package/src/util/Util_Lambda.res +12 -5
- package/src/util/Util_LambdaEnvBudget.res +5 -5
- package/src/util/Util_LambdaLogging.res +1 -2
- package/src/util/Util_LogGroup_Adopting.res +1 -4
- package/src/util/Util_ResourceNaming.res +1 -2
- package/src/util/Util_SNS.res +8 -3
- package/src/util/Util_SNS_FIFO.res +1 -1
- package/src/util/Util_SNS_Runtime.res +11 -10
- package/src/util/Util_SQS.res +4 -2
- package/src/util/Util_SQS_FIFO.res +5 -2
- package/src/util/Util_SQS_Runtime.res +37 -36
- package/src/util/Util_ShellConfig.res +3 -2
- package/src/util/Util_StaticBundle.res +1 -3
- package/src/util/Util_StoreLayout.res +4 -1
- package/tests/AWS_TagsTest.res +16 -5
- package/tests/AppSyncEventsSigner_OpsTest.res +11 -2
- package/tests/AppSync_AdapterTest.res +286 -224
- package/tests/AppSync_AdapterTest.res.mjs +69 -0
- package/tests/AppSync_Resolver_RetryingTest.res +64 -44
- package/tests/AppSync_RetirementNarrowingTest.res +59 -46
- package/tests/AppSync_SdlDecorateTest.res +22 -20
- package/tests/AppSync_SourceApiAssociation_RetryingTest.res +40 -22
- package/tests/Auth_ActiveRolePoolAttachmentTest.res +114 -107
- package/tests/Auth_ActiveRoleStoreTest.res +12 -9
- package/tests/Auth_ActiveRoleStore_SchemaTest.res +2 -1
- package/tests/Auth_ActiveRoleTrigger_OpsTest.res +20 -16
- package/tests/Auth_CognitoTest.res +31 -46
- package/tests/Auth_LoginIdentifierTest.res +51 -0
- package/tests/Auth_LoginIdentifierTest.res.mjs +51 -0
- package/tests/Auth_SignUpModeTest.res +56 -0
- package/tests/Auth_SignUpModeTest.res.mjs +53 -0
- package/tests/AutomationSliceEntryPoint_OpsTest.res +69 -67
- package/tests/BakeConvergenceTest.res +22 -25
- package/tests/Capability_MessagingTest.res +28 -12
- package/tests/CommandTopicQueuePolicyTest.res +1 -2
- package/tests/CounterEntryPoint_OpsTest.res +3 -7
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +306 -210
- package/tests/EventCollectorConnectLambdaPreviewTest.res +14 -7
- package/tests/EventCollectorEntryPoint_OpsTest.res +12 -4
- package/tests/EventCollectorPluginDefinitionAssetTest.res +18 -11
- package/tests/EventCollectorReadyGateTest.res +5 -4
- package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -2
- package/tests/EventMapperEntryPoint_OpsTest.res +1 -3
- package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -4
- package/tests/HandlerFactoryDispatchTest.res +97 -70
- package/tests/MCP_LambdaTest.res +16 -27
- package/tests/PgChangeFeedRelay_IntegrationTest.res +123 -93
- package/tests/PgChangeFeedRelay_RuntimeTest.res +13 -10
- package/tests/PgMigrationEntryPoint_IntegrationTest.res +0 -1
- package/tests/PgPipeline_IntegrationTest.res +80 -66
- package/tests/PgQueryDbUnion_IntegrationTest.res +1 -2
- package/tests/PgQueryResolverEntryPoint_OpsTest.res +2 -6
- package/tests/PgQueryResolver_LambdaTest.res +41 -24
- package/tests/Platform_AdminScan_OpsTest.res +4 -1
- package/tests/Platform_ComponentDefinitions_Lambda_OpsTest.res +137 -129
- package/tests/ProjectionEntryPoint_DisplayNameTest.res +7 -3
- package/tests/ProjectionEntryPoint_UnionStampTest.res +3 -2
- package/tests/ProvisionAccountsTest.res +142 -0
- package/tests/ProvisionAccountsTest.res.mjs +153 -0
- package/tests/ProvisionAdminTest.res +55 -0
- package/tests/ProvisionAdminTest.res.mjs +66 -0
- package/tests/ProvisionIdentityTest.res +91 -9
- package/tests/ProvisionIdentityTest.res.mjs +66 -1
- package/tests/QueryDbOwnerIndexTableTest.res +6 -4
- package/tests/QueryDbResolvers_AppSyncTest.res +23 -16
- package/tests/QueryInterceptor_LambdaTest.res +11 -13
- package/tests/ReadModelEntryPoint_OpsTest.res +43 -41
- package/tests/RuntimeExtensionEntryPoint_OpsTest.res +4 -3
- package/tests/SideEffectEntryPoint_OpsTest.res +23 -18
- package/tests/StateChangeDescriptorParityTest.res +28 -26
- package/tests/StateTopicKeySchemaTest.res +18 -15
- package/tests/StateViewSliceEntryPoint_OpsTest.res +55 -44
- package/tests/TaskBucketEntryPoint_OpsTest.res +13 -13
- package/tests/Upload_ClaimTest.res +3 -3
- package/tests/Util_AwsErrorTest.res +4 -7
- package/tests/Util_BundleDependencyClosureTest.res +15 -3
- package/tests/Util_BundleEsmLoaderTest.res +3 -3
- package/tests/Util_BundleResolveTest.res +4 -6
- package/tests/Util_BundleRuntimeExtensionTest.res +17 -18
- package/tests/Util_DcbMetricsTest.res +6 -6
- package/tests/Util_DynamoDbStreamTest.res +4 -5
- package/tests/Util_DynamoDbTest.res +3 -2
- package/tests/Util_LambdaEnvBudgetTest.res +22 -18
- package/tests/Util_LambdaLoggingTest.res +9 -8
- package/tests/Util_LogGroup_AdoptingTest.res +10 -5
- package/tests/Util_LogRetentionTest.res +6 -2
- package/tests/Util_OwnerScopeEnvTest.res +35 -8
- package/tests/Util_OwnerScopeEnvTest.res.mjs +13 -0
- package/tests/Util_SQS_RuntimeTest.res +5 -7
- package/tests/Util_ShellConfigTest.res +7 -17
- package/tests/Util_StaticBundleTest.res +3 -8
- package/tests/Util_StoreLayoutTest.res +17 -12
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -4
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +15 -15
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +296 -232
- package/tests/integration/DcbIntegrationHarness.res +8 -8
- package/tests/integration/EpCompositeSlice.res +16 -8
- package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +8 -10
- package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +10 -10
- package/tests/integration/SvsTestSlice_Projection.res +1 -3
- package/tests/util/Util_AlarmSpecTest.res +62 -49
package/src/Platform.res
CHANGED
|
@@ -121,6 +121,31 @@ module MakeWithConfig = (
|
|
|
121
121
|
): (
|
|
122
122
|
ReventlessInfra.Platform.T with type api = Types.AppSync.api and type role = Types.AppSync.role
|
|
123
123
|
) => {
|
|
124
|
+
// The administrator group reads across every owner, unless the deployment says
|
|
125
|
+
// otherwise.
|
|
126
|
+
//
|
|
127
|
+
// Authorization and owner scoping decide admin-ness independently and nothing
|
|
128
|
+
// checks that they agree: without this, a deployment gets an administrator who
|
|
129
|
+
// passes every authorization check and then reads *empty* owner-scoped views.
|
|
130
|
+
// `Util_OwnerScopeEnv.applyElevatedGroupsDefault` already carries whatever
|
|
131
|
+
// `OwnerScope.elevatedGroups()` holds into every Lambda's environment — the pipe
|
|
132
|
+
// was laid and nothing ever put a value in.
|
|
133
|
+
//
|
|
134
|
+
// 🚨 **Here, at the entry point, rather than beside the pool that declares the
|
|
135
|
+
// group.** The value has to be set before the runtime builder composes any
|
|
136
|
+
// Lambda's environment, and this functor's body runs when the functor is
|
|
137
|
+
// applied — necessarily before any plugin is built through it. Written into
|
|
138
|
+
// `Platform_Stack.resolveCognitoUserPool` it would instead depend on *which
|
|
139
|
+
// caller resolved the pool first*, which is precisely how a feature once
|
|
140
|
+
// vanished from a deploy with no error and no resource; see the note on
|
|
141
|
+
// `_resolveUncached`. Ordering that is structural beats ordering that happens
|
|
142
|
+
// to hold.
|
|
143
|
+
//
|
|
144
|
+
// A default, never a forcing: an explicit `setElevatedGroups` in a platform
|
|
145
|
+
// root — including one naming nobody — means what it says and wins. See
|
|
146
|
+
// [Reventless.OwnerScope.defaultElevatedGroups].
|
|
147
|
+
Reventless.OwnerScope.defaultElevatedGroups([Reventless.AdminGroup.name])
|
|
148
|
+
|
|
124
149
|
// Dispatch per-flavor commandHandlerConfig records to the four runtime
|
|
125
150
|
// builders. Every sub-record is optional; only branches the caller actually
|
|
126
151
|
// supplied propagate, and within each sub-record every field is optional too
|
|
@@ -201,8 +226,10 @@ module MakeWithConfig = (
|
|
|
201
226
|
// A platform that provisions none omits the export entirely, which reads
|
|
202
227
|
// as "no store to claim in" — the claimer then builds nothing, rather
|
|
203
228
|
// than building something that can reach nothing.
|
|
204
|
-
|
|
205
|
-
|
|
229
|
+
|
|
230
|
+
(
|
|
231
|
+
stackRef->Pulumi.StackReference.getOutput("objectStores"): Pulumi.Output.t<option<JSON.t>>
|
|
232
|
+
)->Pulumi.Output.apply(objectStores =>
|
|
206
233
|
objectStores
|
|
207
234
|
->Option.flatMap(JSON.Decode.object)
|
|
208
235
|
->Option.getOr(Dict.make())
|
|
@@ -210,15 +237,16 @@ module MakeWithConfig = (
|
|
|
210
237
|
->Array.filterMap(((qualified, v)) =>
|
|
211
238
|
v
|
|
212
239
|
->JSON.Decode.object
|
|
213
|
-
->Option.flatMap(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
Some(
|
|
220
|
-
|
|
221
|
-
|
|
240
|
+
->Option.flatMap(
|
|
241
|
+
o =>
|
|
242
|
+
switch (
|
|
243
|
+
o->Dict.get("bucketName")->Option.flatMap(JSON.Decode.string),
|
|
244
|
+
o->Dict.get("keyPrefix")->Option.flatMap(JSON.Decode.string),
|
|
245
|
+
) {
|
|
246
|
+
| (Some(bucketName), Some(servedPrefix)) =>
|
|
247
|
+
Some({Upload_Claim_S3.qualified, bucketName, servedPrefix})
|
|
248
|
+
| _ => None
|
|
249
|
+
},
|
|
222
250
|
)
|
|
223
251
|
)
|
|
224
252
|
)
|
|
@@ -273,8 +301,9 @@ module MakeWithConfig = (
|
|
|
273
301
|
// shared types win over every plugin source's standalone copy (divergence
|
|
274
302
|
// is shadowed, not MERGE_FAILED — Phase-0 finding 1).
|
|
275
303
|
let assembleCanonicalSourceSdl = (~baseFragment): string =>
|
|
276
|
-
AppSync_Adapter.stitchStandaloneWithAwsDirectives(
|
|
277
|
-
|
|
304
|
+
AppSync_Adapter.stitchStandaloneWithAwsDirectives(
|
|
305
|
+
~fragment=baseFragment,
|
|
306
|
+
)->AppSync_SdlDecorate.stampCanonicalTypes
|
|
278
307
|
|
|
279
308
|
// Admin base as a source-API document — auth-decorated (all fields Admin,
|
|
280
309
|
// Cognito-only; the deploy-time SigV4 system-caller fields died with the
|
|
@@ -283,13 +312,14 @@ module MakeWithConfig = (
|
|
|
283
312
|
assembleCanonicalSourceSdl(
|
|
284
313
|
~baseFragment=AppSync_Adapter.injectAwsAuthAll(
|
|
285
314
|
ReventlessCore.Platform_AdminApi.baseFragment(~cloner=Config.cloner),
|
|
286
|
-
~group=
|
|
315
|
+
~group=Reventless.AdminGroup.name,
|
|
287
316
|
),
|
|
288
317
|
)
|
|
289
318
|
|
|
290
319
|
// Split-mode Domain source document: relay base types + Platform_ping — the
|
|
291
320
|
// Domain merged API's canonical owner (plugin fields come from plugin sources).
|
|
292
|
-
let domainBaseSourceSdl = (): string =>
|
|
321
|
+
let domainBaseSourceSdl = (): string =>
|
|
322
|
+
assembleCanonicalSourceSdl(~baseFragment=domainBaseFragment)
|
|
293
323
|
|
|
294
324
|
let (domainApi, domainApiRole, platformApi, platformApiRole) = switch platformStackRef {
|
|
295
325
|
| None =>
|
|
@@ -337,37 +367,40 @@ module MakeWithConfig = (
|
|
|
337
367
|
defaultOutput,
|
|
338
368
|
)
|
|
339
369
|
->Pulumi.Output.all3
|
|
340
|
-
->Pulumi.Output.apply(
|
|
341
|
-
(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
->Option.orElse(getFromDefault("identityProviderRegion"))
|
|
360
|
-
->Option.orElse(directRegion)
|
|
361
|
-
->Option.orElse(getFromDefault("cognitoRegion"))
|
|
362
|
-
(
|
|
363
|
-
{
|
|
364
|
-
userPoolId,
|
|
365
|
-
?awsRegion,
|
|
366
|
-
defaultAction: PulumiAws.AppSync.GraphQLApi.ALLOW,
|
|
367
|
-
}: PulumiAws.AppSync.GraphQLApi.userPoolConfig
|
|
370
|
+
->Pulumi.Output.apply(((
|
|
371
|
+
(directProviderId, directProviderRegion),
|
|
372
|
+
(directPoolId, directRegion),
|
|
373
|
+
default,
|
|
374
|
+
)) => {
|
|
375
|
+
let getFromDefault = key =>
|
|
376
|
+
default
|
|
377
|
+
->Option.flatMap(d => d->JSON.Decode.object)
|
|
378
|
+
->Option.flatMap(d => d->Dict.get(key))
|
|
379
|
+
->Option.flatMap(v => v->JSON.Decode.string)
|
|
380
|
+
// New spelling first at both levels, then the deprecated one. In ESM
|
|
381
|
+
// mode exports arrive nested under "default", hence each pair.
|
|
382
|
+
let userPoolId =
|
|
383
|
+
directProviderId
|
|
384
|
+
->Option.orElse(getFromDefault("identityProviderId"))
|
|
385
|
+
->Option.orElse(directPoolId)
|
|
386
|
+
->Option.orElse(getFromDefault("cognitoUserPoolId"))
|
|
387
|
+
->Option.getOrThrow(
|
|
388
|
+
~message="Platform stack exports neither 'identityProviderId' nor 'cognitoUserPoolId' — redeploy the platform stack first",
|
|
368
389
|
)
|
|
369
|
-
|
|
370
|
-
|
|
390
|
+
let awsRegion =
|
|
391
|
+
directProviderRegion
|
|
392
|
+
->Option.orElse(getFromDefault("identityProviderRegion"))
|
|
393
|
+
->Option.orElse(directRegion)
|
|
394
|
+
->Option.orElse(getFromDefault("cognitoRegion"))
|
|
395
|
+
|
|
396
|
+
(
|
|
397
|
+
{
|
|
398
|
+
userPoolId,
|
|
399
|
+
?awsRegion,
|
|
400
|
+
defaultAction: PulumiAws.AppSync.GraphQLApi.ALLOW,
|
|
401
|
+
}: PulumiAws.AppSync.GraphQLApi.userPoolConfig
|
|
402
|
+
)
|
|
403
|
+
})
|
|
371
404
|
let (api, role) = AppSync_Adapter.makePluginSourceApiResource(
|
|
372
405
|
~name="PluginSourceApi",
|
|
373
406
|
~userPoolConfig,
|
|
@@ -384,72 +417,73 @@ module MakeWithConfig = (
|
|
|
384
417
|
// Populate apiConfig with both domain and platform API references.
|
|
385
418
|
// In platform/monolithic mode, platformApi starts as domainApi and is updated
|
|
386
419
|
// by deployPlatform/makePlatform once the platform API resource is created (split mode).
|
|
387
|
-
let () =
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
420
|
+
let () =
|
|
421
|
+
apiConfigRef :=
|
|
422
|
+
Some({
|
|
423
|
+
domainApi,
|
|
424
|
+
domainApiRole,
|
|
425
|
+
platformApi,
|
|
426
|
+
platformApiRole,
|
|
427
|
+
})
|
|
393
428
|
|
|
394
429
|
// AppSync Events API — companion to the GraphQL API for Sources A and B subscriptions.
|
|
395
430
|
// In platform/monolithic mode: created here as a real resource.
|
|
396
431
|
// In plugin mode: reconstructed as a phantom from platform stack exports (eventsApiArn, eventsApiDns).
|
|
397
|
-
let domainEventsApiOpt: option<AppSync_EventsApi.t> =
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
432
|
+
let domainEventsApiOpt: option<AppSync_EventsApi.t> = switch platformStackRef {
|
|
433
|
+
| None =>
|
|
434
|
+
// Browser host-shell subscribes over WebSocket with a Cognito IdToken,
|
|
435
|
+
// so the Events API must carry a Cognito auth provider. The pool is the
|
|
436
|
+
// same process-cached one the GraphQL API + config.json use.
|
|
437
|
+
let cognitoPool = Platform_Stack.resolveCognitoUserPool()
|
|
438
|
+
let awsRegion =
|
|
439
|
+
Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region")->Option.getOr("unknown")
|
|
440
|
+
Some(
|
|
441
|
+
AppSync_EventsApi.make(
|
|
442
|
+
~name="DomainEventsApi",
|
|
443
|
+
~cognitoUserPoolId=cognitoPool.poolId->Pulumi.Output.asInput,
|
|
444
|
+
~awsRegion,
|
|
445
|
+
~opts={},
|
|
446
|
+
),
|
|
447
|
+
)
|
|
448
|
+
| Some(stackRef) =>
|
|
449
|
+
let eventsApiArnOutput: Pulumi.Output.t<option<string>> =
|
|
450
|
+
stackRef->Pulumi.StackReference.getOutput("eventsApiArn")
|
|
451
|
+
let eventsApiDnsOutput: Pulumi.Output.t<option<string>> =
|
|
452
|
+
stackRef->Pulumi.StackReference.getOutput("eventsApiDns")
|
|
453
|
+
let defaultEventsOutput: Pulumi.Output.t<option<JSON.t>> =
|
|
454
|
+
stackRef->Pulumi.StackReference.getOutput("default")
|
|
455
|
+
let getFromDefault = (default, key) =>
|
|
456
|
+
default
|
|
457
|
+
->Option.flatMap(d => d->JSON.Decode.object)
|
|
458
|
+
->Option.flatMap(d => d->Dict.get(key))
|
|
459
|
+
->Option.flatMap(v => v->JSON.Decode.string)
|
|
460
|
+
let apiArn =
|
|
461
|
+
(eventsApiArnOutput, defaultEventsOutput)
|
|
462
|
+
->Pulumi.Output.all2
|
|
463
|
+
->Pulumi.Output.apply(((direct, default)) =>
|
|
464
|
+
direct->Option.orElse(getFromDefault(default, "eventsApiArn"))
|
|
413
465
|
)
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
let dns =
|
|
433
|
-
(eventsApiDnsOutput, defaultEventsOutput)
|
|
434
|
-
->Pulumi.Output.all2
|
|
435
|
-
->Pulumi.Output.apply(((direct, default)) =>
|
|
436
|
-
direct->Option.orElse(getFromDefault(default, "eventsApiDns"))
|
|
437
|
-
)
|
|
438
|
-
let api: PulumiAws.AwsNative.AppSync.Api.t = {
|
|
439
|
-
apiId: Pulumi.Output.make(""),
|
|
440
|
-
apiArn: apiArn->Pulumi.Output.apply(v => v->Option.getOr("")),
|
|
441
|
-
dns: dns->Pulumi.Output.apply(dnsHttp => ({
|
|
442
|
-
PulumiAws.AwsNative.AppSync.Api.http: ?dnsHttp,
|
|
443
|
-
}: PulumiAws.AwsNative.AppSync.Api.dns)),
|
|
444
|
-
name: Pulumi.Output.make(""),
|
|
445
|
-
}
|
|
446
|
-
let eventsApi: AppSync_EventsApi.t = {
|
|
447
|
-
name: "DomainEventsApi",
|
|
448
|
-
api,
|
|
449
|
-
defaultNamespace: None,
|
|
450
|
-
}
|
|
451
|
-
Some(eventsApi)
|
|
466
|
+
let dns =
|
|
467
|
+
(eventsApiDnsOutput, defaultEventsOutput)
|
|
468
|
+
->Pulumi.Output.all2
|
|
469
|
+
->Pulumi.Output.apply(((direct, default)) =>
|
|
470
|
+
direct->Option.orElse(getFromDefault(default, "eventsApiDns"))
|
|
471
|
+
)
|
|
472
|
+
let api: PulumiAws.AwsNative.AppSync.Api.t = {
|
|
473
|
+
apiId: Pulumi.Output.make(""),
|
|
474
|
+
apiArn: apiArn->Pulumi.Output.apply(v => v->Option.getOr("")),
|
|
475
|
+
dns: dns->Pulumi.Output.apply((dnsHttp): PulumiAws.AwsNative.AppSync.Api.dns => {
|
|
476
|
+
PulumiAws.AwsNative.AppSync.Api.http: ?dnsHttp,
|
|
477
|
+
}),
|
|
478
|
+
name: Pulumi.Output.make(""),
|
|
479
|
+
}
|
|
480
|
+
let eventsApi: AppSync_EventsApi.t = {
|
|
481
|
+
name: "DomainEventsApi",
|
|
482
|
+
api,
|
|
483
|
+
defaultNamespace: None,
|
|
452
484
|
}
|
|
485
|
+
Some(eventsApi)
|
|
486
|
+
}
|
|
453
487
|
|
|
454
488
|
// B3.3: publish the events-API endpoint + ARN to the projection-Lambda runtime
|
|
455
489
|
// builders, so a subscription-enabled Postgres read model / view slice gets the
|
|
@@ -509,8 +543,7 @@ module MakeWithConfig = (
|
|
|
509
543
|
EventMappings: ReventlessInfra.EventMapper.Mappings with module Target := Spec,
|
|
510
544
|
): (
|
|
511
545
|
ReventlessInfra.Aggregate.T with type api = Types.AppSync.api
|
|
512
|
-
) =>
|
|
513
|
-
Aggregate_Builder_Single.Make(Spec, Behavior, EventMappings)
|
|
546
|
+
) => Aggregate_Builder_Single.Make(Spec, Behavior, EventMappings)
|
|
514
547
|
/** Async variant — uses FIFO SQS channel, commands return `CommandPending`. */
|
|
515
548
|
module MakeAsync = (
|
|
516
549
|
Spec: Reventless.Aggregate.Spec,
|
|
@@ -518,8 +551,7 @@ module MakeWithConfig = (
|
|
|
518
551
|
EventMappings: ReventlessInfra.EventMapper.Mappings with module Target := Spec,
|
|
519
552
|
): (
|
|
520
553
|
ReventlessInfra.Aggregate.T with type api = Types.AppSync.api
|
|
521
|
-
) =>
|
|
522
|
-
Aggregate_Builder_Single_Async.Make(Spec, Behavior, EventMappings)
|
|
554
|
+
) => Aggregate_Builder_Single_Async.Make(Spec, Behavior, EventMappings)
|
|
523
555
|
}
|
|
524
556
|
|
|
525
557
|
module ReadModel = {
|
|
@@ -531,8 +563,7 @@ module MakeWithConfig = (
|
|
|
531
563
|
with module Spec = Spec
|
|
532
564
|
and type api = Types.AppSync.api
|
|
533
565
|
and type role = Types.AppSync.role
|
|
534
|
-
) =>
|
|
535
|
-
ReadModel_Builder_Single.Make(Spec, Mappings)
|
|
566
|
+
) => ReadModel_Builder_Single.Make(Spec, Mappings)
|
|
536
567
|
}
|
|
537
568
|
|
|
538
569
|
/** Stream-enabled read model — DynamoDB Stream + StateTopic Lambda for
|
|
@@ -546,8 +577,7 @@ module MakeWithConfig = (
|
|
|
546
577
|
with module Spec = Spec
|
|
547
578
|
and type api = Types.AppSync.api
|
|
548
579
|
and type role = Types.AppSync.role
|
|
549
|
-
) =>
|
|
550
|
-
ReadModel_Builder_Single_Stream.Make(Spec, Mappings)
|
|
580
|
+
) => ReadModel_Builder_Single_Stream.Make(Spec, Mappings)
|
|
551
581
|
}
|
|
552
582
|
|
|
553
583
|
module ExtensionPoint = {
|
|
@@ -584,8 +614,7 @@ module MakeWithConfig = (
|
|
|
584
614
|
module Mappings: ReventlessInfra.ExtensionPoint.Mappings with module Spec := Spec = {
|
|
585
615
|
module type Mapping = ReventlessInfra.ExtensionPointMapping.T
|
|
586
616
|
with module ExtensionPoint := Spec
|
|
587
|
-
let name =
|
|
588
|
-
Mapping1.Delegate.name ++ "+" ++ Mapping2.Delegate.name
|
|
617
|
+
let name = Mapping1.Delegate.name ++ "+" ++ Mapping2.Delegate.name
|
|
589
618
|
// First mapping's URL — matches the user-extension merge convention.
|
|
590
619
|
// See Make's moduleUrl comment for the %raw rationale.
|
|
591
620
|
let moduleUrl = Mapping1.moduleUrl
|
|
@@ -610,11 +639,7 @@ module MakeWithConfig = (
|
|
|
610
639
|
module type Mapping = ReventlessInfra.ExtensionPointMapping.T
|
|
611
640
|
with module ExtensionPoint := Spec
|
|
612
641
|
let name =
|
|
613
|
-
Mapping1.Delegate.name ++
|
|
614
|
-
"+" ++
|
|
615
|
-
Mapping2.Delegate.name ++
|
|
616
|
-
"+" ++
|
|
617
|
-
Mapping3.Delegate.name
|
|
642
|
+
Mapping1.Delegate.name ++ "+" ++ Mapping2.Delegate.name ++ "+" ++ Mapping3.Delegate.name
|
|
618
643
|
// First mapping's URL — matches the user-extension merge convention.
|
|
619
644
|
// See Make's moduleUrl comment for the %raw rationale.
|
|
620
645
|
let moduleUrl = Mapping1.moduleUrl
|
|
@@ -636,14 +661,12 @@ module MakeWithConfig = (
|
|
|
636
661
|
): ReventlessInfra.Extension.Blueprint => {
|
|
637
662
|
module Spec = Mapping.ExtensionPoint
|
|
638
663
|
module CompiledMapping = ReventlessInfra.ExtensionMapping.Make(Mapping)
|
|
639
|
-
module type Mapping = ReventlessInfra.ExtensionMapping.T
|
|
640
|
-
with module ExtensionPoint := Spec
|
|
664
|
+
module type Mapping = ReventlessInfra.ExtensionMapping.T with module ExtensionPoint := Spec
|
|
641
665
|
let name = Mapping.Delegate.name
|
|
642
666
|
let moduleUrl = Mapping.moduleUrl
|
|
643
667
|
let delegateModuleUrl = Mapping.delegateModuleUrl
|
|
644
668
|
let mappings: array<module(Mapping)> = [module(CompiledMapping)]
|
|
645
669
|
}
|
|
646
|
-
|
|
647
670
|
}
|
|
648
671
|
|
|
649
672
|
module Task = {
|
|
@@ -658,8 +681,9 @@ module MakeWithConfig = (
|
|
|
658
681
|
module Make = (
|
|
659
682
|
Spec: Reventless.StateChangeSlice.Spec,
|
|
660
683
|
Behavior: Reventless.StateChangeSlice.Behavior with module Spec := Spec,
|
|
661
|
-
): (
|
|
662
|
-
|
|
684
|
+
): (
|
|
685
|
+
ReventlessInfra.StateChangeSlice.T with module Spec = Spec
|
|
686
|
+
) => StateChangeSlice_Builder.Make(Spec, Behavior)
|
|
663
687
|
/** Async variant — uses FIFO SQS channel, commands return `CommandPending`. */
|
|
664
688
|
module MakeAsync = (
|
|
665
689
|
Spec: Reventless.StateChangeSlice.Spec,
|
|
@@ -742,7 +766,6 @@ module MakeWithConfig = (
|
|
|
742
766
|
| None => resolveHookedApi()
|
|
743
767
|
}
|
|
744
768
|
|
|
745
|
-
|
|
746
769
|
let hooks: ReventlessCore.Plugin_Helpers.platformHooks = {
|
|
747
770
|
// AWS uses Interstack for admin extension points — leave ref at empty dict.
|
|
748
771
|
adminExtensionPoints: ref(Pulumi.Output.make(Dict.make())),
|
|
@@ -776,7 +799,6 @@ module MakeWithConfig = (
|
|
|
776
799
|
~opts,
|
|
777
800
|
)
|
|
778
801
|
},
|
|
779
|
-
|
|
780
802
|
// Admin-side schema push, gated on admin DataSources via adminBarrier.
|
|
781
803
|
// Platform_Admin.construct invokes this and chains createResolvers behind
|
|
782
804
|
// the returned Output — so admin CreateResolver calls fire only after
|
|
@@ -793,7 +815,6 @@ module MakeWithConfig = (
|
|
|
793
815
|
// before the resource resolves, so admin resolvers chained on the API are
|
|
794
816
|
// already ordered after the schema is ACTIVE. No push.
|
|
795
817
|
preAdminResolversSchemaHook: (~adminBarrier) => adminBarrier,
|
|
796
|
-
|
|
797
818
|
// Push the plugin's standalone subgraph document to the plugin's OWN
|
|
798
819
|
// source API — a single writer by construction. The returned Output gates
|
|
799
820
|
// resolver creation and deployPlugin additionally sequences the
|
|
@@ -802,23 +823,24 @@ module MakeWithConfig = (
|
|
|
802
823
|
// re-merges automatically.
|
|
803
824
|
preResolversSchemaHook: (~name, ~version, pluginFragment) => {
|
|
804
825
|
let sdl = AppSync_Adapter.stitchStandaloneWithAwsDirectives(~fragment=pluginFragment)
|
|
805
|
-
let pushed =
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
826
|
+
let pushed = domainApi->Pulumi.Output.flatMap(api =>
|
|
827
|
+
api.id->Pulumi.Output.flatMap(apiId => {
|
|
828
|
+
log.info(
|
|
829
|
+
~comp="preResolversSchemaHook",
|
|
830
|
+
`Pushing subgraph schema for ${name}@${version} to source API ${apiId}`,
|
|
831
|
+
)
|
|
832
|
+
let client = AppSync_Adapter.getClient()
|
|
833
|
+
client
|
|
834
|
+
->AppSync_Adapter.startSchemaCreationRetrying({apiId, definition: sdl})
|
|
835
|
+
->Promise.then(
|
|
836
|
+
async _ => {
|
|
816
837
|
await AppSync_Adapter.waitForSchemaActive(client, apiId)
|
|
817
838
|
log.info(~comp="preResolversSchemaHook", "subgraph schema is ACTIVE")
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
)
|
|
839
|
+
},
|
|
840
|
+
)
|
|
841
|
+
->Pulumi.Output.fromPromise
|
|
842
|
+
})
|
|
843
|
+
)
|
|
822
844
|
mergedSchemaPushedRef := Some(pushed)
|
|
823
845
|
pushed
|
|
824
846
|
},
|
|
@@ -864,98 +886,102 @@ module MakeWithConfig = (
|
|
|
864
886
|
~epQueueUrl=resource.id->Pulumi.Output.make,
|
|
865
887
|
(),
|
|
866
888
|
)
|
|
867
|
-
| None =>
|
|
868
|
-
log.warn(~comp="Platform", "heartbeat EP channel has no resources")
|
|
889
|
+
| None => log.warn(~comp="Platform", "heartbeat EP channel has no resources")
|
|
869
890
|
}
|
|
870
891
|
},
|
|
871
|
-
|
|
872
892
|
// Phase 4 + 5: wire StateTopic and EventLogSubscription Lambdas per plugin.
|
|
873
893
|
// Only active when the Events API resource exists (platform/monolithic mode).
|
|
874
|
-
subscriptionInfraHook: ?
|
|
875
|
-
(
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
894
|
+
subscriptionInfraHook: ?(
|
|
895
|
+
domainEventsApiOpt->Option.map(eventsApi =>
|
|
896
|
+
(params: ReventlessCore.Plugin_Helpers.subscriptionInfraParams) => {
|
|
897
|
+
let {pluginName, allQueryDbs, allEventTopics, eventLogEntries, opts} = params
|
|
898
|
+
let customOpts =
|
|
899
|
+
opts->ReventlessCore.Util.Pulumi.ComponentResourceOptions.toCustomResourceOptions
|
|
900
|
+
// StateTopic Lambda per stream-enabled QueryDb — publishes row changes
|
|
901
|
+
// to AppSync Events channels. No GraphQL Subscription resolver is
|
|
902
|
+
// wired: Source B uses the Events WebSocket directly, not @aws_subscribe.
|
|
903
|
+
allQueryDbs->Dict.forEachWithKey((_queryDbOutputs, readModelName) => {
|
|
904
|
+
if QueryDbStorage_DynamoDbStream.streamRegistry->Set.has(readModelName) {
|
|
905
|
+
// Channel root MUST equal what the host-shell subscribes to. The
|
|
906
|
+
// AutoUI manifest sets queryableDef.queryField = listFieldName
|
|
907
|
+
// (plural, e.g. "Catalog_Products") and AutoLive subscribes on that.
|
|
908
|
+
// Publishing on the singular returnTypeName ("Catalog_Product")
|
|
909
|
+
// would land descriptors on a channel no client listens to.
|
|
910
|
+
let topicName =
|
|
911
|
+
ReventlessCore.Plugin_Helpers.queryFieldNamesRegistry
|
|
912
|
+
->Dict.get(readModelName)
|
|
913
|
+
->Option.map(qn => qn.listFieldName)
|
|
914
|
+
->Option.getOr(readModelName)
|
|
915
|
+
StateTopic_AppSync.make(
|
|
916
|
+
~readModelName,
|
|
917
|
+
~topicName,
|
|
918
|
+
~allQueryDbs,
|
|
919
|
+
~eventsApi,
|
|
920
|
+
~opts=customOpts,
|
|
921
|
+
)
|
|
922
|
+
}
|
|
923
|
+
})
|
|
903
924
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
925
|
+
// Phase 5: EventLogSubscription per SNS-backed event log entry.
|
|
926
|
+
// DynamoDB stream event topics (Category, DCB) are skipped — no SNS subscription needed.
|
|
927
|
+
eventLogEntries->Array.forEach(entry => {
|
|
928
|
+
// Aggregate EventTopics are keyed by Spec.name (= displayName).
|
|
929
|
+
// DCB EventTopic is keyed by busKey (= pluginName ++ "DcbEventLog").
|
|
930
|
+
let isSns =
|
|
931
|
+
EventTopicPublisher_SNS.snsRegistry->Set.has(entry.displayName) ||
|
|
932
|
+
EventTopicPublisher_SNS.snsRegistry->Set.has(entry.busKey)
|
|
933
|
+
let topicOutputs =
|
|
934
|
+
allEventTopics
|
|
935
|
+
->Dict.get(entry.displayName)
|
|
936
|
+
->Option.orElse(allEventTopics->Dict.get(entry.busKey))
|
|
937
|
+
isSns
|
|
938
|
+
? topicOutputs->Option.forEach(
|
|
939
|
+
outputs =>
|
|
940
|
+
EventLogSubscription_AppSync.make(
|
|
941
|
+
~name=entry.displayName,
|
|
942
|
+
~topicName=entry.displayName,
|
|
943
|
+
~eventTopicOutputs=outputs,
|
|
944
|
+
~eventsApi,
|
|
945
|
+
~opts=customOpts,
|
|
946
|
+
),
|
|
924
947
|
)
|
|
925
|
-
)
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
948
|
+
: ()
|
|
949
|
+
// Register this event log with the upload claimer if — and only if —
|
|
950
|
+
// its events declare a `@storageRef` field. An event log that declares
|
|
951
|
+
// none is not registered, so a platform whose plugins declare no store
|
|
952
|
+
// provisions no claimer at all. `isSns` is the same synchronous answer
|
|
953
|
+
// the subscription above turns on, so the two cannot disagree about
|
|
954
|
+
// which channel an event log publishes through.
|
|
955
|
+
topicOutputs->Option.forEach(
|
|
956
|
+
outputs =>
|
|
957
|
+
Upload_Claim_S3.make(
|
|
958
|
+
~plugin=pluginName,
|
|
959
|
+
~eventLogName=entry.displayName,
|
|
960
|
+
~eventSchema=entry.eventSchema,
|
|
961
|
+
~eventTopicOutputs=outputs,
|
|
962
|
+
~isStreamBacked=!isSns,
|
|
963
|
+
),
|
|
940
964
|
)
|
|
941
|
-
)
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
965
|
+
})
|
|
966
|
+
// Finalize the shared StateTopic Lambda + IAM + per-stream ESMs from the
|
|
967
|
+
// entries the loop above just registered. Must run INSIDE this hook because
|
|
968
|
+
// Plugin_Builder fires it from inside a Pulumi.Output.apply chain — calling
|
|
969
|
+
// `finish` from deployPlugin (after P.make returns) would see the registry
|
|
970
|
+
// empty because the hook hasn't run yet. Admin's hook fires synchronously,
|
|
971
|
+
// but the call site is unified here so admin and plugins share one path.
|
|
972
|
+
StateTopic_AppSync.finish(~eventsApi, ~opts={})
|
|
973
|
+
// Same timing constraint, same reason: the claimer's registry is filled
|
|
974
|
+
// by the loop just above and drained here.
|
|
975
|
+
Upload_Claim_S3.finish(~plugin=pluginName, ~stores=claimStores, ~opts=customOpts)
|
|
976
|
+
}
|
|
977
|
+
)
|
|
954
978
|
),
|
|
955
979
|
}
|
|
956
980
|
|
|
957
981
|
// Apply Plugin functor with the platform hooks, then constrain the result to Plugin.T.
|
|
958
|
-
module PluginBuilderImpl = Plugin.Make({
|
|
982
|
+
module PluginBuilderImpl = Plugin.Make({
|
|
983
|
+
let hooks = hooks
|
|
984
|
+
})
|
|
959
985
|
module Plugin: ReventlessInfra.Plugin.T
|
|
960
986
|
with type api = Types.AppSync.api
|
|
961
987
|
and type role = Types.AppSync.role
|
|
@@ -995,9 +1021,8 @@ module MakeWithConfig = (
|
|
|
995
1021
|
// via the auto-resolver flow. Internal-protocol variants (Heartbeat, Connect,
|
|
996
1022
|
// Disconnect, ReportIncompatibility) carry `@noApi` and are filtered out before
|
|
997
1023
|
// SDL/resolver generation.
|
|
998
|
-
module PluginAggregate:
|
|
999
|
-
|
|
1000
|
-
) = Aggregate_Builder_Single.Make(
|
|
1024
|
+
module PluginAggregate: ReventlessInfra.Aggregate.T
|
|
1025
|
+
with type api = Types.AppSync.api = Aggregate_Builder_Single.Make(
|
|
1001
1026
|
ReventlessCore.PluginSpec,
|
|
1002
1027
|
ReventlessCore.PluginBehavior,
|
|
1003
1028
|
ReventlessInfra.NoEventMappings.Make(ReventlessCore.PluginSpec),
|
|
@@ -1061,8 +1086,9 @@ module MakeWithConfig = (
|
|
|
1061
1086
|
// this is how RM/SVS projections are fed. One subscriber per (feed, log)
|
|
1062
1087
|
// keeps checkpoints isolated.
|
|
1063
1088
|
let feedTargets = (~connectionConfig, ~logName, ~feed, ~isClassic) =>
|
|
1064
|
-
PgProjectionFeed.getFeedQueues()->Array.filterMap(fq =>
|
|
1065
|
-
|
|
1089
|
+
PgProjectionFeed.getFeedQueues()->Array.filterMap(fq => {
|
|
1090
|
+
let included = isClassic ? fq.includeClassic : fq.includeDcb
|
|
1091
|
+
included
|
|
1066
1092
|
? Some({
|
|
1067
1093
|
PgChangeFeedRelay_Builder.connectionConfig,
|
|
1068
1094
|
logName,
|
|
@@ -1072,7 +1098,7 @@ module MakeWithConfig = (
|
|
|
1072
1098
|
targetQueueArn: fq.arn,
|
|
1073
1099
|
})
|
|
1074
1100
|
: None
|
|
1075
|
-
)
|
|
1101
|
+
})
|
|
1076
1102
|
let dcbLogs = switch DcbBackend.get() {
|
|
1077
1103
|
| Some({connectionConfig}) =>
|
|
1078
1104
|
DcbBackend.getRelayLogs()->Array.flatMap(entry => {
|
|
@@ -1249,12 +1275,10 @@ module MakeWithConfig = (
|
|
|
1249
1275
|
// deployPlatform (staged) and each plugin with deployPlugin — makePlatform
|
|
1250
1276
|
// predates the merge path and never gained merged wiring.
|
|
1251
1277
|
failwith(
|
|
1252
|
-
"makePlatform is not supported on AWS — deploy the platform with deployPlatform and " ++
|
|
1253
|
-
"each plugin with deployPlugin (merged-API composition).",
|
|
1278
|
+
"makePlatform is not supported on AWS — deploy the platform with deployPlatform and " ++ "each plugin with deployPlugin (merged-API composition).",
|
|
1254
1279
|
)
|
|
1255
1280
|
}
|
|
1256
1281
|
|
|
1257
|
-
|
|
1258
1282
|
// Merged-mode outputs of deployPlatform — the merged API(s), plus the
|
|
1259
1283
|
// deploy-time merge gates (Outputs that resolve on MERGE_SUCCESS and fail
|
|
1260
1284
|
// the deploy on MERGE_FAILED; folded into the ARN exports so they are
|
|
@@ -1358,12 +1382,13 @@ module MakeWithConfig = (
|
|
|
1358
1382
|
splitApiOutputsRef := Some({platformApi, platformApiRole})
|
|
1359
1383
|
switch apiConfigRef.contents {
|
|
1360
1384
|
| Some(c) =>
|
|
1361
|
-
apiConfigRef :=
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1385
|
+
apiConfigRef :=
|
|
1386
|
+
Some({
|
|
1387
|
+
domainApi: c.domainApi,
|
|
1388
|
+
domainApiRole: c.domainApiRole,
|
|
1389
|
+
platformApi,
|
|
1390
|
+
platformApiRole,
|
|
1391
|
+
})
|
|
1367
1392
|
| None => ()
|
|
1368
1393
|
}
|
|
1369
1394
|
}
|
|
@@ -1434,21 +1459,18 @@ module MakeWithConfig = (
|
|
|
1434
1459
|
// targets a non-existent ARN, breaking the
|
|
1435
1460
|
// admin → plugin EventCollector → ConnectPlugin round-trip and leaving
|
|
1436
1461
|
// the Plugin read model empty.
|
|
1437
|
-
let pluginEpEventTopicArn =
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
| None => Pulumi.Output.make("NOT_AVAILABLE")
|
|
1450
|
-
}
|
|
1451
|
-
)
|
|
1462
|
+
let pluginEpEventTopicArn = admin.extensionPointsOutputs->Pulumi.Output.flatMap(eps =>
|
|
1463
|
+
switch eps->Array.find(ep => ep.name == ReventlessInfra.PluginExtensionPointSpec.name) {
|
|
1464
|
+
| Some(ep) =>
|
|
1465
|
+
ep.eventTopic->Pulumi.Output.flatMap(et =>
|
|
1466
|
+
switch et.resources->Array.get(0) {
|
|
1467
|
+
| Some(r) => r.urn
|
|
1468
|
+
| None => Pulumi.Output.make("NOT_AVAILABLE")
|
|
1469
|
+
}
|
|
1470
|
+
)
|
|
1471
|
+
| None => Pulumi.Output.make("NOT_AVAILABLE")
|
|
1472
|
+
}
|
|
1473
|
+
)
|
|
1452
1474
|
|
|
1453
1475
|
PluginRuntime_Builder.registerConfig(
|
|
1454
1476
|
~eventTopicArn=pluginEpEventTopicArn,
|
|
@@ -1555,7 +1577,10 @@ module MakeWithConfig = (
|
|
|
1555
1577
|
api.uris->Pulumi.Output.apply(uris => uris.graphQL)
|
|
1556
1578
|
),
|
|
1557
1579
|
)
|
|
1558
|
-
Pulumi.Pulumi.export(
|
|
1580
|
+
Pulumi.Pulumi.export(
|
|
1581
|
+
"platformApiRoleArn",
|
|
1582
|
+
platformApiRole->Pulumi.Output.flatMap(role => role.arn),
|
|
1583
|
+
)
|
|
1559
1584
|
} else {
|
|
1560
1585
|
// Platform API exports (unified mode — same resource as Domain API).
|
|
1561
1586
|
Pulumi.Pulumi.export("platformApiId", domainApi->Pulumi.Output.flatMap(api => api.id))
|
|
@@ -1565,16 +1590,17 @@ module MakeWithConfig = (
|
|
|
1565
1590
|
api.uris->Pulumi.Output.apply(uris => uris.graphQL)
|
|
1566
1591
|
),
|
|
1567
1592
|
)
|
|
1568
|
-
Pulumi.Pulumi.export(
|
|
1593
|
+
Pulumi.Pulumi.export(
|
|
1594
|
+
"platformApiRoleArn",
|
|
1595
|
+
domainApiRole->Pulumi.Output.flatMap(role => role.arn),
|
|
1596
|
+
)
|
|
1569
1597
|
}
|
|
1570
1598
|
|
|
1571
1599
|
// Domain API exports.
|
|
1572
1600
|
Pulumi.Pulumi.export("domainApiId", domainApi->Pulumi.Output.flatMap(api => api.id))
|
|
1573
1601
|
Pulumi.Pulumi.export(
|
|
1574
1602
|
"domainApiEndpoint",
|
|
1575
|
-
domainApi->Pulumi.Output.flatMap(api =>
|
|
1576
|
-
api.uris->Pulumi.Output.apply(uris => uris.graphQL)
|
|
1577
|
-
),
|
|
1603
|
+
domainApi->Pulumi.Output.flatMap(api => api.uris->Pulumi.Output.apply(uris => uris.graphQL)),
|
|
1578
1604
|
)
|
|
1579
1605
|
Pulumi.Pulumi.export("domainApiRoleArn", domainApiRole->Pulumi.Output.flatMap(role => role.arn))
|
|
1580
1606
|
|
|
@@ -1587,10 +1613,7 @@ module MakeWithConfig = (
|
|
|
1587
1613
|
switch mergedOutputs {
|
|
1588
1614
|
| Some({domainMerged, platformMerged, domainMergeGate, platformMergeGate}) =>
|
|
1589
1615
|
let mergeGatedArn = (merged: AppSync_MergedApi.t, gate: Pulumi.Output.t<unit>) =>
|
|
1590
|
-
(
|
|
1591
|
-
merged.api->Pulumi.Output.flatMap((api: PulumiAws.AppSync.GraphQLApi.t) => api.arn),
|
|
1592
|
-
gate,
|
|
1593
|
-
)
|
|
1616
|
+
(merged.api->Pulumi.Output.flatMap((api: PulumiAws.AppSync.GraphQLApi.t) => api.arn), gate)
|
|
1594
1617
|
->Pulumi.Output.all2
|
|
1595
1618
|
->Pulumi.Output.apply(((arn, _)) => arn)
|
|
1596
1619
|
let mergedEndpoint = (merged: AppSync_MergedApi.t) =>
|
|
@@ -1663,13 +1686,15 @@ module MakeWithConfig = (
|
|
|
1663
1686
|
| Some({platformMerged}) => platformMerged.api
|
|
1664
1687
|
| None => platformApi
|
|
1665
1688
|
}
|
|
1666
|
-
let resolvedDomainApiEndpoint =
|
|
1667
|
-
|
|
1668
|
-
|
|
1689
|
+
let resolvedDomainApiEndpoint =
|
|
1690
|
+
clientDomainApi->Pulumi.Output.flatMap(api =>
|
|
1691
|
+
api.uris->Pulumi.Output.apply(uris => uris.graphQL)
|
|
1692
|
+
)
|
|
1669
1693
|
let resolvedDomainApiRoleArn = domainApiRole->Pulumi.Output.flatMap(role => role.arn)
|
|
1670
|
-
let resolvedPlatformApiEndpoint =
|
|
1671
|
-
|
|
1672
|
-
|
|
1694
|
+
let resolvedPlatformApiEndpoint =
|
|
1695
|
+
clientPlatformApi->Pulumi.Output.flatMap(api =>
|
|
1696
|
+
api.uris->Pulumi.Output.apply(uris => uris.graphQL)
|
|
1697
|
+
)
|
|
1673
1698
|
let resolvedPlatformApiRoleArn = platformApiRole->Pulumi.Output.flatMap(role => role.arn)
|
|
1674
1699
|
// Collect admin aggregate + read model resources.
|
|
1675
1700
|
let adminResourcesOutput =
|
|
@@ -1709,7 +1734,13 @@ module MakeWithConfig = (
|
|
|
1709
1734
|
adminResourcesOutput,
|
|
1710
1735
|
)
|
|
1711
1736
|
->Pulumi.Output.all5
|
|
1712
|
-
->Pulumi.Output.apply(((
|
|
1737
|
+
->Pulumi.Output.apply(((
|
|
1738
|
+
domainApiEndpoint,
|
|
1739
|
+
domainApiRoleArn,
|
|
1740
|
+
platformApiEndpoint,
|
|
1741
|
+
platformApiRoleArn,
|
|
1742
|
+
adminResources,
|
|
1743
|
+
)) => {
|
|
1713
1744
|
let region =
|
|
1714
1745
|
Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region")->Option.getOr("unknown")
|
|
1715
1746
|
ReventlessCore.Plugin_Helpers.firePlatformDeployedHook({
|
|
@@ -1753,7 +1784,9 @@ module MakeWithConfig = (
|
|
|
1753
1784
|
switch c {
|
|
1754
1785
|
| ObjectStore({plugin, store}) => Some((plugin, store))
|
|
1755
1786
|
| Geocoding
|
|
1756
|
-
| Messaging
|
|
1787
|
+
| Messaging
|
|
1788
|
+
| IdentityProvider =>
|
|
1789
|
+
None
|
|
1757
1790
|
}
|
|
1758
1791
|
)
|
|
1759
1792
|
->Array.reduce([], (acc, (plugin, store)) =>
|
|
@@ -1843,8 +1876,7 @@ module MakeWithConfig = (
|
|
|
1843
1876
|
log.info(
|
|
1844
1877
|
~comp="Platform:deployPlatform",
|
|
1845
1878
|
`object store ${plugin}.${store}: never-claimed uploads under ${prefix}/ expire after ` ++
|
|
1846
|
-
`${days->Int.toString} days. Claimed objects and objects minted before the claim ` ++
|
|
1847
|
-
`component existed carry no pending tag and are outside the rule.`,
|
|
1879
|
+
`${days->Int.toString} days. Claimed objects and objects minted before the claim ` ++ `component existed carry no pending tag and are outside the rule.`,
|
|
1848
1880
|
)
|
|
1849
1881
|
})
|
|
1850
1882
|
)
|
|
@@ -1897,8 +1929,9 @@ module MakeWithConfig = (
|
|
|
1897
1929
|
->Dict.get(bucketName)
|
|
1898
1930
|
->Option.map(b => {
|
|
1899
1931
|
ReventlessInfra.Platform.id: bucketName,
|
|
1900
|
-
prefixes: declaredStoreServices
|
|
1901
|
-
|
|
1932
|
+
prefixes: declaredStoreServices->Array.filterMap(
|
|
1933
|
+
((_, prefix, bn, _)) => bn == bucketName ? Some(prefix) : None,
|
|
1934
|
+
),
|
|
1902
1935
|
bucketId: b.bucketId,
|
|
1903
1936
|
bucketArn: b.bucketArn,
|
|
1904
1937
|
bucketRegionalDomainName: b.bucketRegionalDomainName,
|
|
@@ -1956,7 +1989,7 @@ module MakeWithConfig = (
|
|
|
1956
1989
|
let uploadServiceStores =
|
|
1957
1990
|
declaredStoreServices
|
|
1958
1991
|
->Array.map(((qualified, keyPrefix, _logical, physicalBucketName)) => {
|
|
1959
|
-
Upload_Presign_S3.qualified
|
|
1992
|
+
Upload_Presign_S3.qualified,
|
|
1960
1993
|
bucketName: physicalBucketName,
|
|
1961
1994
|
servedPrefix: keyPrefix,
|
|
1962
1995
|
})
|
|
@@ -1993,10 +2026,10 @@ module MakeWithConfig = (
|
|
|
1993
2026
|
"objectStores",
|
|
1994
2027
|
declaredStoreEndpoints
|
|
1995
2028
|
->Array.map(e =>
|
|
1996
|
-
Pulumi.Output.all2((
|
|
1997
|
-
bucketName,
|
|
1998
|
-
baseUrl,
|
|
1999
|
-
)) => (e, bucketName, baseUrl))
|
|
2029
|
+
Pulumi.Output.all2((
|
|
2030
|
+
e.bucketName,
|
|
2031
|
+
e.baseUrl->Pulumi.Output.allOpt,
|
|
2032
|
+
))->Pulumi.Output.apply(((bucketName, baseUrl)) => (e, bucketName, baseUrl))
|
|
2000
2033
|
)
|
|
2001
2034
|
->Pulumi.Output.all
|
|
2002
2035
|
->Pulumi.Output.apply(resolved =>
|
|
@@ -2053,12 +2086,7 @@ module MakeWithConfig = (
|
|
|
2053
2086
|
Util_LocalConfig.get("hostUiProdStacks")
|
|
2054
2087
|
->Option.map(Util_HostUiDomain.parseProdStacks)
|
|
2055
2088
|
->Option.getOr(Util_HostUiDomain.defaultProdStacks)
|
|
2056
|
-
let fqdn = Util_HostUiDomain.deriveFqdn(
|
|
2057
|
-
~baseName,
|
|
2058
|
-
~stack,
|
|
2059
|
-
~baseDomain=bd,
|
|
2060
|
-
~prodStacks,
|
|
2061
|
-
)
|
|
2089
|
+
let fqdn = Util_HostUiDomain.deriveFqdn(~baseName, ~stack, ~baseDomain=bd, ~prodStacks)
|
|
2062
2090
|
Some({Plugin_Stack.fqdn, hostedZoneId: hz})
|
|
2063
2091
|
| _ => None
|
|
2064
2092
|
}
|
|
@@ -2186,8 +2214,7 @@ module MakeWithConfig = (
|
|
|
2186
2214
|
`provisions no place index.\n` ++
|
|
2187
2215
|
` Add \`let placeIndex = ReventlessAws.Capability_Geocoding_AwsLocation.make(~name=…)\` ` ++
|
|
2188
2216
|
`and pass \`~geocoderPlaceIndex=placeIndex\` in \`~hostUiBundle\`.\n` ++
|
|
2189
|
-
` The declaration is generated from the plugins' capabilities.json — regenerate with ` ++
|
|
2190
|
-
`\`pnpm run generate:platform\` if it is stale.`,
|
|
2217
|
+
` The declaration is generated from the plugins' capabilities.json — regenerate with ` ++ `\`pnpm run generate:platform\` if it is stale.`,
|
|
2191
2218
|
)
|
|
2192
2219
|
}
|
|
2193
2220
|
|
|
@@ -2250,8 +2277,7 @@ module MakeWithConfig = (
|
|
|
2250
2277
|
`instead — every message is logged and none is sent, and the address is optional.\n` ++
|
|
2251
2278
|
` The root must also pass \`~messagingSender\` in \`~hostUiBundle\`, from ` ++
|
|
2252
2279
|
`\`ReventlessAws.Capability_Messaging.make(~name=…)\`.\n` ++
|
|
2253
|
-
` The declaration is generated from the plugins' capabilities.json — regenerate with ` ++
|
|
2254
|
-
`\`pnpm run generate:platform\` if it is stale.`,
|
|
2280
|
+
` The declaration is generated from the plugins' capabilities.json — regenerate with ` ++ `\`pnpm run generate:platform\` if it is stale.`,
|
|
2255
2281
|
)
|
|
2256
2282
|
}
|
|
2257
2283
|
|
|
@@ -2514,7 +2540,11 @@ module MakeWithConfig = (
|
|
|
2514
2540
|
// Expose deploy target via hooks so Plugin_Builder can stamp pluginDefinition.apiTarget.
|
|
2515
2541
|
// This must be set before P.make() and is captured synchronously by Plugin_Builder
|
|
2516
2542
|
// (same timing requirement as hooks.api/apiRole).
|
|
2517
|
-
hooks.deployTarget :=
|
|
2543
|
+
hooks.deployTarget :=
|
|
2544
|
+
switch apiTarget {
|
|
2545
|
+
| Domain => "Domain"
|
|
2546
|
+
| Platform => "Platform"
|
|
2547
|
+
}
|
|
2518
2548
|
// Each plugin stack creates its own scheduler (closures can't cross stacks).
|
|
2519
2549
|
let scheduler = makeScheduler()
|
|
2520
2550
|
hooks.scheduler := Some(scheduler)
|
|
@@ -2532,8 +2562,9 @@ module MakeWithConfig = (
|
|
|
2532
2562
|
// The bucket name comes from the platform stack (deploy the platform first).
|
|
2533
2563
|
let offloadBucketName: Pulumi.Output.t<string> = switch platformStackRef {
|
|
2534
2564
|
| Some(stackRef) =>
|
|
2535
|
-
(
|
|
2536
|
-
|
|
2565
|
+
(
|
|
2566
|
+
stackRef->Pulumi.StackReference.getOutput("offloadBucket"): Pulumi.Output.t<option<string>>
|
|
2567
|
+
)->Pulumi.Output.apply(o => o->Option.getOr("OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY"))
|
|
2537
2568
|
| None => Pulumi.Output.make("OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY")
|
|
2538
2569
|
}
|
|
2539
2570
|
// The key this deploy wrote for the plugin's structure, exported below. The
|
|
@@ -2600,8 +2631,9 @@ module MakeWithConfig = (
|
|
|
2600
2631
|
let geocoderPlaceIndex: Pulumi.Output.t<string> = switch platformStackRef {
|
|
2601
2632
|
| Some(stackRef) =>
|
|
2602
2633
|
(
|
|
2603
|
-
stackRef->Pulumi.StackReference.getOutput("geocoderPlaceIndex"):
|
|
2604
|
-
|
|
2634
|
+
stackRef->Pulumi.StackReference.getOutput("geocoderPlaceIndex"): Pulumi.Output.t<
|
|
2635
|
+
option<string>,
|
|
2636
|
+
>
|
|
2605
2637
|
)->Pulumi.Output.apply(o => o->Option.getOr(""))
|
|
2606
2638
|
| None => geocoderPlaceIndexRef.contents
|
|
2607
2639
|
}
|
|
@@ -2615,8 +2647,9 @@ module MakeWithConfig = (
|
|
|
2615
2647
|
let messagingEmailSender: Pulumi.Output.t<string> = switch platformStackRef {
|
|
2616
2648
|
| Some(stackRef) =>
|
|
2617
2649
|
(
|
|
2618
|
-
stackRef->Pulumi.StackReference.getOutput("messagingEmailSender"):
|
|
2619
|
-
|
|
2650
|
+
stackRef->Pulumi.StackReference.getOutput("messagingEmailSender"): Pulumi.Output.t<
|
|
2651
|
+
option<string>,
|
|
2652
|
+
>
|
|
2620
2653
|
)->Pulumi.Output.apply(o => o->Option.getOr(""))
|
|
2621
2654
|
| None => messagingEmailSenderRef.contents
|
|
2622
2655
|
}
|
|
@@ -2630,15 +2663,13 @@ module MakeWithConfig = (
|
|
|
2630
2663
|
let messagingEmailProvider: Pulumi.Output.t<string> = switch platformStackRef {
|
|
2631
2664
|
| Some(stackRef) =>
|
|
2632
2665
|
(
|
|
2633
|
-
stackRef->Pulumi.StackReference.getOutput("messagingEmailProvider"):
|
|
2634
|
-
|
|
2666
|
+
stackRef->Pulumi.StackReference.getOutput("messagingEmailProvider"): Pulumi.Output.t<
|
|
2667
|
+
option<string>,
|
|
2668
|
+
>
|
|
2635
2669
|
)->Pulumi.Output.apply(o => o->Option.getOr(""))
|
|
2636
2670
|
| None => messagingEmailProviderRef.contents
|
|
2637
2671
|
}
|
|
2638
|
-
PluginRuntime_Builder.registerCapabilityEnv(
|
|
2639
|
-
"MESSAGING_EMAIL_PROVIDER",
|
|
2640
|
-
messagingEmailProvider,
|
|
2641
|
-
)
|
|
2672
|
+
PluginRuntime_Builder.registerCapabilityEnv("MESSAGING_EMAIL_PROVIDER", messagingEmailProvider)
|
|
2642
2673
|
|
|
2643
2674
|
module P = unpack(plugin)
|
|
2644
2675
|
let pluginComponent = P.make()
|
|
@@ -2687,8 +2718,7 @@ module MakeWithConfig = (
|
|
|
2687
2718
|
let defaultOutput: Pulumi.Output.t<option<JSON.t>> =
|
|
2688
2719
|
stackRef->Pulumi.StackReference.getOutput("default")
|
|
2689
2720
|
let getMergedExport = (key: string): Pulumi.Output.t<string> => {
|
|
2690
|
-
let direct: Pulumi.Output.t<option<string>> =
|
|
2691
|
-
stackRef->Pulumi.StackReference.getOutput(key)
|
|
2721
|
+
let direct: Pulumi.Output.t<option<string>> = stackRef->Pulumi.StackReference.getOutput(key)
|
|
2692
2722
|
(direct, defaultOutput)
|
|
2693
2723
|
->Pulumi.Output.all2
|
|
2694
2724
|
->Pulumi.Output.apply(((direct, default)) =>
|
|
@@ -2778,12 +2808,9 @@ module MakeWithConfig = (
|
|
|
2778
2808
|
messagingEmailSender,
|
|
2779
2809
|
)
|
|
2780
2810
|
->Pulumi.Output.all4
|
|
2781
|
-
->Pulumi.Output.apply((
|
|
2782
|
-
_,
|
|
2783
|
-
|
|
2784
|
-
string,
|
|
2785
|
-
string,
|
|
2786
|
-
))) => {
|
|
2811
|
+
->Pulumi.Output.apply((
|
|
2812
|
+
(structure, objectStores, placeIndex, emailSender): (_, option<JSON.t>, string, string),
|
|
2813
|
+
) => {
|
|
2787
2814
|
// ── Declared capabilities ──────────────────────────────────────────
|
|
2788
2815
|
//
|
|
2789
2816
|
// A slice that names `Geocoding` in `capabilityNeeds` says its
|
|
@@ -2819,14 +2846,16 @@ module MakeWithConfig = (
|
|
|
2819
2846
|
->Array.map(u =>
|
|
2820
2847
|
switch u.need {
|
|
2821
2848
|
| Geocoding =>
|
|
2822
|
-
`\n Geocoding is \`Capability_Geocoding_AwsLocation.make\`, passed to the ` ++
|
|
2823
|
-
`platform as \`~geocoderPlaceIndex\`.`
|
|
2849
|
+
`\n Geocoding is \`Capability_Geocoding_AwsLocation.make\`, passed to the ` ++ `platform as \`~geocoderPlaceIndex\`.`
|
|
2824
2850
|
| Messaging =>
|
|
2825
2851
|
`\n Messaging is \`Capability_Messaging.make\`, passed to the platform ` ++
|
|
2826
2852
|
`as \`~messagingSender\`. The sender itself is configuration and has no ` ++
|
|
2827
2853
|
`default: set \`platform:messagingEmailSender\` in Pulumi.<stack>.yaml (or ` ++
|
|
2828
|
-
`REVENTLESS_MESSAGING_EMAIL_SENDER), then verify the address with SES — or ` ++
|
|
2829
|
-
|
|
2854
|
+
`REVENTLESS_MESSAGING_EMAIL_SENDER), then verify the address with SES — or ` ++ `\`platform:messagingEmailProvider: log\` to log every message and send none.`
|
|
2855
|
+
| IdentityProvider =>
|
|
2856
|
+
`\n IdentityProvider has no backend on any platform yet — the seam and the ` ++
|
|
2857
|
+
`refusal exist, the Cognito and local implementations do not. A plugin ` ++
|
|
2858
|
+
`declaring this need cannot be deployed until one lands; nothing about this ` ++ `deployment's configuration will change that.`
|
|
2830
2859
|
}
|
|
2831
2860
|
)
|
|
2832
2861
|
// One line per capability, not per declaring component: two slices
|
|
@@ -2837,8 +2866,7 @@ module MakeWithConfig = (
|
|
|
2837
2866
|
)
|
|
2838
2867
|
}
|
|
2839
2868
|
|
|
2840
|
-
let required =
|
|
2841
|
-
structure->Option.flatMap(s => s.requiredStores)->Option.getOr([])
|
|
2869
|
+
let required = structure->Option.flatMap(s => s.requiredStores)->Option.getOr([])
|
|
2842
2870
|
let provisioned =
|
|
2843
2871
|
objectStores
|
|
2844
2872
|
->Option.flatMap(JSON.Decode.object)
|
|
@@ -2849,17 +2877,19 @@ module MakeWithConfig = (
|
|
|
2849
2877
|
| NotAdopted(missing) =>
|
|
2850
2878
|
log.warn(
|
|
2851
2879
|
~comp="Platform:deployPlugin",
|
|
2852
|
-
`declares ${missing->Array.join(
|
|
2853
|
-
|
|
2854
|
-
|
|
2880
|
+
`declares ${missing->Array.join(
|
|
2881
|
+
", ",
|
|
2882
|
+
)} but the platform stack provisions no object stores — ` ++
|
|
2883
|
+
`add them to the platform's ~capabilities and redeploy the platform first, ` ++ `or uploads will fall back to the legacy service and write to the wrong bucket`,
|
|
2855
2884
|
)
|
|
2856
2885
|
| Missing({missing, provisioned}) =>
|
|
2857
2886
|
JsError.throwWithMessage(
|
|
2858
|
-
`Plugin requires object store(s) the platform does not provision: ${missing->Array.join(
|
|
2887
|
+
`Plugin requires object store(s) the platform does not provision: ${missing->Array.join(
|
|
2888
|
+
", ",
|
|
2889
|
+
)}.\n` ++
|
|
2859
2890
|
` The platform stack provisions: ${provisioned->Array.join(", ")}.\n` ++
|
|
2860
2891
|
` A store's key is {plugin}.{store}, where {plugin} is the name the plugin registers — ` ++
|
|
2861
|
-
`check the capability's spelling and case against it.\n` ++
|
|
2862
|
-
` Add the missing entr(ies) to the platform's ~capabilities and redeploy the platform stack first.`,
|
|
2892
|
+
`check the capability's spelling and case against it.\n` ++ ` Add the missing entr(ies) to the platform's ~capabilities and redeploy the platform stack first.`,
|
|
2863
2893
|
)
|
|
2864
2894
|
}
|
|
2865
2895
|
})
|
|
@@ -2870,10 +2900,7 @@ module MakeWithConfig = (
|
|
|
2870
2900
|
->Pulumi.Output.all3
|
|
2871
2901
|
->Pulumi.Output.apply(((id, _, _)) => id),
|
|
2872
2902
|
)
|
|
2873
|
-
Pulumi.Pulumi.export(
|
|
2874
|
-
"pluginSourceApiId",
|
|
2875
|
-
domainApi->Pulumi.Output.flatMap(api => api.id),
|
|
2876
|
-
)
|
|
2903
|
+
Pulumi.Pulumi.export("pluginSourceApiId", domainApi->Pulumi.Output.flatMap(api => api.id))
|
|
2877
2904
|
Pulumi.Pulumi.export(
|
|
2878
2905
|
"pluginSourceApiEndpoint",
|
|
2879
2906
|
domainApi->Pulumi.Output.flatMap(api =>
|
|
@@ -2926,8 +2953,10 @@ module MakeWithConfig = (
|
|
|
2926
2953
|
// re-detect coming to correct it. Waiting on the heartbeat alone gated on a
|
|
2927
2954
|
// Lambda that has no part in the answer.
|
|
2928
2955
|
let redetectReady =
|
|
2929
|
-
(
|
|
2930
|
-
|
|
2956
|
+
(
|
|
2957
|
+
pluginOutputs.heartbeat,
|
|
2958
|
+
PluginRuntime_Builder.eventCollectorReadyRef.contents,
|
|
2959
|
+
)->Pulumi.Output.all2
|
|
2931
2960
|
let _ = redetectReady->Pulumi.Output.apply(_ => {
|
|
2932
2961
|
let hbConfig = PluginRuntime_Builder.heartbeatConfigRef.contents
|
|
2933
2962
|
switch (Pulumi.Pulumi.isDryRun(), hbConfig.epQueueUrl) {
|