@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/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.346 (2026-09-11)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **aws:** the schema refuses a rule it cannot enforce, instead of inverting it ([47da2ff](https://github.com/ReventlessDev/reventless-core/commit/47da2ffeff34498a5589d6df347de400f7360f63))
|
|
11
|
+
* feat(spec)!: a secret is a capability, so a test can know it in advance ([71507c6](https://github.com/ReventlessDev/reventless-core/commit/71507c6459b49178746f00c5040cb479d7fdade8))
|
|
12
|
+
* feat(spec)!: making a principal is a capability, so the provider is replaceable ([3e59b9b](https://github.com/ReventlessDev/reventless-core/commit/3e59b9b665cc7e4b6b6f156b63b1b6bd0c6181ca))
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **aws:** the first administrator is one command, not the console ([5f1a846](https://github.com/ReventlessDev/reventless-core/commit/5f1a84603b21a9feb691a08a148751c6c6e8eca8))
|
|
16
|
+
* **aws:** the rest of the cast is a file, not a comment ([aa23581](https://github.com/ReventlessDev/reventless-core/commit/aa23581f09948a47fb451ec2ecf2fc2bdd8e6ee6))
|
|
17
|
+
* **aws:** the sign-in attribute is chosen at first deploy, not hard-coded ([21ff246](https://github.com/ReventlessDev/reventless-core/commit/21ff24693fb8ddf8d50abeb5197d4b0d1ad54f83))
|
|
18
|
+
* **aws:** who may create an account is a setting, not a hard-coded field ([a89e13f](https://github.com/ReventlessDev/reventless-core/commit/a89e13f0b3929898ae604a101d0b338755008bfb))
|
|
19
|
+
* **spec:** preparing a manifest is not an AWS errand ([bd7f8e2](https://github.com/ReventlessDev/reventless-core/commit/bd7f8e2f6132c0cacac2ab839165f21fe91eaf6c))
|
|
20
|
+
|
|
21
|
+
### BREAKING CHANGES
|
|
22
|
+
|
|
23
|
+
* Capabilities.t gains a secrets member. A platform that builds
|
|
24
|
+
the record literally no longer compiles until it supplies one;
|
|
25
|
+
Capabilities.none.secrets is the refusing value. Code that spreads
|
|
26
|
+
Capabilities.none is unaffected.
|
|
27
|
+
* Capabilities.t gains an identityProvider member. A platform
|
|
28
|
+
that builds the record literally no longer compiles until it supplies one;
|
|
29
|
+
Capabilities.none.identityProvider is the refusing value to pass while no
|
|
30
|
+
backend exists. Code that spreads Capabilities.none is unaffected.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# 3.0.0-alpha.345 (2026-09-09)
|
|
35
|
+
|
|
36
|
+
**Note:** Version bump only for package @reventlessdev/reventless-aws
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
6
42
|
# 3.0.0-alpha.344 (2026-09-09)
|
|
7
43
|
|
|
8
44
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.346",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
7
|
-
"provision-identity": "./run-provision-identity.mjs"
|
|
7
|
+
"provision-identity": "./run-provision-identity.mjs",
|
|
8
|
+
"provision-admin": "./run-provision-admin.mjs",
|
|
9
|
+
"provision-accounts": "./run-provision-accounts.mjs"
|
|
8
10
|
},
|
|
9
11
|
"dependencies": {
|
|
10
12
|
"@aws-sdk/client-appsync": "3.970.0",
|
|
@@ -15,18 +17,19 @@
|
|
|
15
17
|
"@aws-sdk/s3-request-presigner": "3.970.0",
|
|
16
18
|
"sury": "11.0.0-rc.2",
|
|
17
19
|
"uuid": "^13.0.0",
|
|
18
|
-
"
|
|
20
|
+
"yaml": "^2.8.3",
|
|
21
|
+
"@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.18",
|
|
19
22
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
20
|
-
"@reventlessdev/rescript-
|
|
21
|
-
"@reventlessdev/rescript-aws
|
|
22
|
-
"@reventlessdev/rescript-
|
|
23
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.11",
|
|
24
|
+
"@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.13",
|
|
25
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.33",
|
|
26
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.20",
|
|
23
27
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
24
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
25
|
-
"@reventlessdev/reventless-interop": "3.0.0-alpha.
|
|
26
|
-
"@reventlessdev/reventless-postgres": "3.0.0-alpha.
|
|
27
|
-
"@reventlessdev/reventless-
|
|
28
|
-
"@reventlessdev/reventless-
|
|
29
|
-
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19"
|
|
28
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.262",
|
|
29
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.36",
|
|
30
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.126",
|
|
31
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.135",
|
|
32
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.163"
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
35
|
"rescript": "12.3.0",
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/***
|
|
2
|
+
Turn a declared cast of accounts into working sign-ins.
|
|
3
|
+
|
|
4
|
+
`provision-admin` makes the *first* administrator, which is the account that
|
|
5
|
+
cannot be made from a signed-in session because there is no signed-in session yet.
|
|
6
|
+
This one makes a declared list of accounts instead.
|
|
7
|
+
|
|
8
|
+
🚨 **Neither needs the other to have run.** Both authenticate as the AWS caller,
|
|
9
|
+
not as a Cognito principal, so there is no bootstrap ordering between them: a
|
|
10
|
+
manifest declaring an entry in the administrator group stands a deployment up on
|
|
11
|
+
its own. The difference is where the credential ends up — `provision-admin` prints
|
|
12
|
+
one and keeps no copy, while this writes into the manifest, which is what
|
|
13
|
+
`pnpm run seed` reads. For a demo whose cast already names an administrator, this
|
|
14
|
+
one alone is enough.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
pnpm exec provision-accounts
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
It reads `.reventless/users.yaml`, and knows nothing about any particular
|
|
21
|
+
application's cast: the manifest belongs to whoever is deploying. A demo's four
|
|
22
|
+
roles and a company's twelve staff are the same run. Which pool it writes to is
|
|
23
|
+
[ProvisionProvider]'s question, and usually needs no argument either.
|
|
24
|
+
|
|
25
|
+
🚨 **Two halves, and only the second is AWS's.** [Reventless.AccountsManifest.prepare]
|
|
26
|
+
validates the manifest and mints a password into every empty field, on any
|
|
27
|
+
platform and with no credentials — locally that is the whole of provisioning,
|
|
28
|
+
because there the manifest *is* the user store. This script then applies the
|
|
29
|
+
prepared manifest to a Cognito pool. That first half is its own bin,
|
|
30
|
+
`prepare-accounts`, so a platform that never deploys to AWS can reach it without
|
|
31
|
+
depending on this package.
|
|
32
|
+
|
|
33
|
+
Re-running is safe and is the normal case — an operator adding one account to
|
|
34
|
+
four. A password already in the file is never replaced; see
|
|
35
|
+
[Reventless.AccountsManifest.applyFills] for why that rule is the whole of the
|
|
36
|
+
write-back's safety.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
open AwsSdk
|
|
40
|
+
|
|
41
|
+
module Cognito = CognitoIdentityServiceProvider
|
|
42
|
+
module Manifest = Reventless.AccountsManifest
|
|
43
|
+
|
|
44
|
+
// ── Arguments ────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
type args = {
|
|
47
|
+
providerId: option<string>,
|
|
48
|
+
stack: option<string>,
|
|
49
|
+
file: option<string>,
|
|
50
|
+
help: bool,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Parsed rather than positional, and unknown flags are an error — the reason
|
|
54
|
+
[ProvisionAdmin.parseArgs] gives, which lands harder here: a typo'd
|
|
55
|
+
`--provider-id` would fall through to the environment and create the whole cast
|
|
56
|
+
in a *different pool* than the operator named. */
|
|
57
|
+
let parseArgs = (argv: array<string>): result<args, string> => {
|
|
58
|
+
let acc = ref(Ok({providerId: None, stack: None, file: None, help: false}))
|
|
59
|
+
let i = ref(0)
|
|
60
|
+
let count = argv->Array.length
|
|
61
|
+
while i.contents < count {
|
|
62
|
+
let flag = argv->Array.getUnsafe(i.contents)
|
|
63
|
+
let value = argv->Array.get(i.contents + 1)
|
|
64
|
+
switch (acc.contents, flag, value) {
|
|
65
|
+
| (Error(_), _, _) => i := count
|
|
66
|
+
| (Ok(a), "--provider-id", Some(v)) =>
|
|
67
|
+
acc := Ok({...a, providerId: Some(v)})
|
|
68
|
+
i := i.contents + 2
|
|
69
|
+
| (Ok(a), "--stack", Some(v)) =>
|
|
70
|
+
acc := Ok({...a, stack: Some(v)})
|
|
71
|
+
i := i.contents + 2
|
|
72
|
+
| (Ok(a), "--file", Some(v)) =>
|
|
73
|
+
acc := Ok({...a, file: Some(v)})
|
|
74
|
+
i := i.contents + 2
|
|
75
|
+
| (Ok(a), "--help", _) | (Ok(a), "-h", _) =>
|
|
76
|
+
acc := Ok({...a, help: true})
|
|
77
|
+
i := i.contents + 1
|
|
78
|
+
| (Ok(_), "--provider-id", None) | (Ok(_), "--file", None) | (Ok(_), "--stack", None) =>
|
|
79
|
+
acc := Error(`${flag} needs a value`)
|
|
80
|
+
| (Ok(_), unknown, _) => acc := Error(`unknown argument "${unknown}"`)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
acc.contents
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let usage = `
|
|
87
|
+
Turn a declared cast of accounts into working sign-ins.
|
|
88
|
+
|
|
89
|
+
--provider-id <id> The identity provider to create the accounts in. Usually
|
|
90
|
+
omitted: it falls back to ${ProvisionProvider.envKey},
|
|
91
|
+
then to the identityProviderId exported by the selected
|
|
92
|
+
Pulumi stack — which every deployment exports, whether it
|
|
93
|
+
created the pool or was handed one.
|
|
94
|
+
--stack <name> Read that output from this stack instead of the selected
|
|
95
|
+
one. The run always names the stack it used.
|
|
96
|
+
--file <path> The manifest. Defaults to .reventless/users.yaml relative
|
|
97
|
+
to the working directory, which is where both platforms
|
|
98
|
+
keep it.
|
|
99
|
+
|
|
100
|
+
For every entry: ensures the groups it names, ensures the account, sets a
|
|
101
|
+
permanent password, and applies the memberships. Generated passwords and the ids
|
|
102
|
+
the pool mints are written back into the manifest, so the seed client can read
|
|
103
|
+
them without anyone retyping a UUID.
|
|
104
|
+
|
|
105
|
+
A password already in the manifest is never replaced. Region and credentials come
|
|
106
|
+
from the environment, as for any AWS SDK call.
|
|
107
|
+
`
|
|
108
|
+
|
|
109
|
+
// ── Preflight ────────────────────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
let looksLikeEmail = (username: string): bool =>
|
|
112
|
+
username->String.includes("@") && username->String.includes(".")
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
Refuse a pool this cast could never sign in to.
|
|
116
|
+
|
|
117
|
+
The mirror of [ProvisionAdmin.checkPoolAcceptsEmail], and it has to run the other
|
|
118
|
+
way round: that script is handed an address and asks whether the pool takes one,
|
|
119
|
+
while a manifest usually names plain usernames — `shopper`, `merch` — and the
|
|
120
|
+
question is whether the pool will accept *those*. A pool created with
|
|
121
|
+
`UsernameAttributes: [email]` will not, and the accounts it makes instead are
|
|
122
|
+
correctly created and unable to authenticate.
|
|
123
|
+
|
|
124
|
+
Checked for every entry before anything is created, so a manifest that cannot work
|
|
125
|
+
costs nothing rather than half a cast.
|
|
126
|
+
*/
|
|
127
|
+
let checkPoolAcceptsUsernames = async (~providerId: string, ~usernames: array<string>): result<
|
|
128
|
+
unit,
|
|
129
|
+
string,
|
|
130
|
+
> =>
|
|
131
|
+
switch await ProvisionCognito.usernameAttributes(~providerId) {
|
|
132
|
+
| Error(_) as e => e
|
|
133
|
+
| Ok(attributes) =>
|
|
134
|
+
let signsInOnEmail = attributes->Array.includes("email")
|
|
135
|
+
let unusable = signsInOnEmail ? usernames->Array.filter(u => !looksLikeEmail(u)) : []
|
|
136
|
+
if unusable->Array.length == 0 {
|
|
137
|
+
Console.log(
|
|
138
|
+
`pool signs in on ${attributes->Array.length == 0
|
|
139
|
+
? "username"
|
|
140
|
+
: attributes->Array.join(", ")}`,
|
|
141
|
+
)
|
|
142
|
+
Ok()
|
|
143
|
+
} else {
|
|
144
|
+
Error(
|
|
145
|
+
`pool "${providerId}" signs in on ${attributes->Array.join(
|
|
146
|
+
", ",
|
|
147
|
+
)}, so ${unusable->Array.join(
|
|
148
|
+
", ",
|
|
149
|
+
)} could never authenticate. The sign-in attribute is fixed at pool creation and no update can change it — either name these accounts by address in the manifest, or provision them in a pool that signs in on a username.`,
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── Applying ─────────────────────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
let describe = (outcome: ProvisionCognito.outcome) =>
|
|
157
|
+
switch outcome {
|
|
158
|
+
| Created => "created"
|
|
159
|
+
| AlreadyPresent => "already present"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Every group the manifest names, made once rather than once per member.
|
|
163
|
+
|
|
164
|
+
The description says where the group came from because a pool outlives the
|
|
165
|
+
deployment that seeded it, and an operator meeting an undocumented group in the
|
|
166
|
+
console has no other way to find out. */
|
|
167
|
+
let ensureGroups = async (~providerId: string, ~entries: array<Manifest.entry>): unit => {
|
|
168
|
+
let named = []
|
|
169
|
+
entries->Array.forEach(entry =>
|
|
170
|
+
entry.groups->Array.forEach(group =>
|
|
171
|
+
if !(named->Array.includes(group)) {
|
|
172
|
+
named->Array.push(group)
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
for index in 0 to named->Array.length - 1 {
|
|
177
|
+
let group = named->Array.getUnsafe(index)
|
|
178
|
+
let outcome = await ProvisionCognito.ensureGroup(
|
|
179
|
+
~providerId,
|
|
180
|
+
~group,
|
|
181
|
+
~description="Declared in a Reventless accounts manifest",
|
|
182
|
+
)
|
|
183
|
+
Console.log(`group ${group} (${outcome->describe})`)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
One account: the entry, applied.
|
|
189
|
+
|
|
190
|
+
The password is set unconditionally rather than only for an account this run
|
|
191
|
+
created — the same reason `provision-admin` does it, arriving at a manifest: the
|
|
192
|
+
file is the record of what the credential *is*, so an account whose password
|
|
193
|
+
drifted from the file is exactly the case a re-run is expected to fix.
|
|
194
|
+
|
|
195
|
+
Returns the id the pool minted, which is the value the manifest cannot know until
|
|
196
|
+
the account exists and which nobody should be pasting by hand.
|
|
197
|
+
*/
|
|
198
|
+
let applyEntry = async (~providerId: string, ~entry: Manifest.entry): option<string> => {
|
|
199
|
+
let attributes: array<Cognito.AdminCreateUserCommand.attributeType> = looksLikeEmail(
|
|
200
|
+
entry.username,
|
|
201
|
+
)
|
|
202
|
+
? [{name: "email", value: entry.username}, {name: "email_verified", value: "true"}]
|
|
203
|
+
: []
|
|
204
|
+
let outcome = await ProvisionCognito.ensureUser(
|
|
205
|
+
~providerId,
|
|
206
|
+
~username=entry.username,
|
|
207
|
+
~attributes,
|
|
208
|
+
)
|
|
209
|
+
Console.log(`user ${entry.username} (${outcome->describe})`)
|
|
210
|
+
await ProvisionCognito.setPassword(
|
|
211
|
+
~providerId,
|
|
212
|
+
~username=entry.username,
|
|
213
|
+
~password=entry.password,
|
|
214
|
+
)
|
|
215
|
+
for index in 0 to entry.groups->Array.length - 1 {
|
|
216
|
+
let group = entry.groups->Array.getUnsafe(index)
|
|
217
|
+
await ProvisionCognito.addToGroup(~providerId, ~username=entry.username, ~group)
|
|
218
|
+
Console.log(`member ${entry.username} in ${group}`)
|
|
219
|
+
}
|
|
220
|
+
await ProvisionCognito.subOf(~providerId, ~username=entry.username)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
🚨 **The passwords are in the manifest, not in this output, and that is the whole
|
|
227
|
+
point of the write-back.**
|
|
228
|
+
|
|
229
|
+
`provision-admin` prints its one credential because there is nowhere else for it
|
|
230
|
+
to live. A cast of four has somewhere: the file the seed client already reads to
|
|
231
|
+
sign in. Printing them here would put every account's password in scrollback and
|
|
232
|
+
in any build log, and buy nothing — whoever needs them can read the file they
|
|
233
|
+
already have.
|
|
234
|
+
*/
|
|
235
|
+
let manifestNote = (~file: string) =>
|
|
236
|
+
`
|
|
237
|
+
🚨 Generated passwords were written into ${file}. They are not printed here
|
|
238
|
+
because that file is where they are read from — by you and by \`pnpm run seed\`.
|
|
239
|
+
It is gitignored on every platform; keep it that way. These are bootstrap
|
|
240
|
+
credentials for a deployment, not secrets to reuse anywhere real.`
|
|
241
|
+
|
|
242
|
+
let run = async (): result<unit, string> =>
|
|
243
|
+
// argv[0] is node, argv[1] this script.
|
|
244
|
+
switch parseArgs(NodeProcess.argv->Array.slice(~start=2, ~end=NodeProcess.argv->Array.length)) {
|
|
245
|
+
| Error(_) as e => e
|
|
246
|
+
| Ok(args) if args.help =>
|
|
247
|
+
Console.log(usage)
|
|
248
|
+
Ok()
|
|
249
|
+
| Ok(args) =>
|
|
250
|
+
switch Manifest.locate(~given=?args.file, ()) {
|
|
251
|
+
| Error(_) as e => e
|
|
252
|
+
| Ok(located) =>
|
|
253
|
+
let file = located->Manifest.pathOf
|
|
254
|
+
switch located {
|
|
255
|
+
| SeededFrom(_, template) => Console.log(`manifest ${file} (new, copied from ${template})`)
|
|
256
|
+
| Declared(_) => ()
|
|
257
|
+
}
|
|
258
|
+
switch Manifest.prepare(~path=file) {
|
|
259
|
+
| Error(message) => Error(`${file}: ${message}`)
|
|
260
|
+
| Ok([]) => Error(`${file} declares no accounts`)
|
|
261
|
+
| Ok(prepared) =>
|
|
262
|
+
let generated = prepared->Array.filter(p => p.passwordGenerated)->Array.length
|
|
263
|
+
Console.log(
|
|
264
|
+
`manifest ${file} (${prepared
|
|
265
|
+
->Array.length
|
|
266
|
+
->Int.toString} accounts, ${generated->Int.toString} password(s) generated)`,
|
|
267
|
+
)
|
|
268
|
+
let entries = prepared->Array.map(p => p.entry)
|
|
269
|
+
switch ProvisionProvider.resolve(~given=args.providerId, ~stack=args.stack) {
|
|
270
|
+
| Error(message) =>
|
|
271
|
+
Error(
|
|
272
|
+
`${message}. To fill in the manifest without creating anything, run prepare-accounts`,
|
|
273
|
+
)
|
|
274
|
+
| Ok((providerId, source)) =>
|
|
275
|
+
Console.log(`provider ${providerId} (from ${source->ProvisionProvider.describe})`)
|
|
276
|
+
switch await checkPoolAcceptsUsernames(
|
|
277
|
+
~providerId,
|
|
278
|
+
~usernames=entries->Array.map(e => e.username),
|
|
279
|
+
) {
|
|
280
|
+
| Error(_) as e => e
|
|
281
|
+
| Ok() =>
|
|
282
|
+
await ensureGroups(~providerId, ~entries)
|
|
283
|
+
let fills = []
|
|
284
|
+
for index in 0 to entries->Array.length - 1 {
|
|
285
|
+
let entry = entries->Array.getUnsafe(index)
|
|
286
|
+
let userId = await applyEntry(~providerId, ~entry)
|
|
287
|
+
fills->Array.push({Manifest.index, password: None, userId})
|
|
288
|
+
}
|
|
289
|
+
switch Manifest.fillFile(~path=file, ~fills) {
|
|
290
|
+
| Error(message) => Error(`${file}: ${message}`)
|
|
291
|
+
| Ok(report) =>
|
|
292
|
+
let corrected = report->Array.filter(r => r.userIdWritten)->Array.length
|
|
293
|
+
Console.log(
|
|
294
|
+
`manifest ${file} (${corrected->Int.toString} id(s) written back)${manifestNote(
|
|
295
|
+
~file,
|
|
296
|
+
)}`,
|
|
297
|
+
)
|
|
298
|
+
Ok()
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
🚨 **Catches thrown exceptions, not only `Error` results** — the reason
|
|
308
|
+
[ProvisionAdmin.main] gives. Without it an SDK failure escapes an async function
|
|
309
|
+
nothing awaits and Node reports `UnhandledPromiseRejection ... "#<Object>"`,
|
|
310
|
+
naming neither the call that failed nor why.
|
|
311
|
+
*/
|
|
312
|
+
let main = async () =>
|
|
313
|
+
switch await run() {
|
|
314
|
+
| Ok() => ()
|
|
315
|
+
| Error(message) =>
|
|
316
|
+
Console.error(`provision-accounts: ${message}`)
|
|
317
|
+
NodeProcess.exit(1)
|
|
318
|
+
| exception exn =>
|
|
319
|
+
Console.error(`provision-accounts: ${Util_AwsError.describe(exn)}`)
|
|
320
|
+
NodeProcess.exit(1)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 🚨 **No top-level call.** `../run-provision-accounts.mjs` invokes [main]; this
|
|
324
|
+
// module only defines it. A module that ran itself on import could not be
|
|
325
|
+
// imported by a test.
|