@reventlessdev/reventless-aws 3.0.0-alpha.396 → 3.0.0-alpha.398
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 +40 -0
- package/package.json +8 -8
- package/scripts/BakeManifest.res +15 -15
- package/scripts/DeployApp.res +8 -9
- package/scripts/DeployApp.res.mjs +4 -13
- package/scripts/DeployManifest.res +4 -5
- package/scripts/DeployManifest.res.mjs +0 -1
- package/scripts/ProvisionAccounts.res +41 -33
- package/scripts/ProvisionAccounts.res.mjs +6 -9
- package/scripts/ProvisionAdmin.res +10 -10
- package/scripts/ProvisionIdentity.res +2 -2
- package/scripts/ResolveEnvironment.res +3 -3
- package/src/Platform.res +6 -4
- package/src/Platform.res.mjs +6 -4
- package/src/Platform_ProvidedGroups.res +4 -4
- package/src/Platform_Stack.res +2 -3
- package/src/Platform_Stack.res.mjs +1 -2
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res +2 -2
- package/src/adapter/Api/AppSync_EventsApi.res +2 -2
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +6 -6
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res +15 -8
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +7 -7
- package/src/adapter/Auth/Auth_IdentityStore.res +41 -2
- package/src/adapter/Auth/Auth_IdentityStore.res.mjs +42 -3
- package/src/adapter/DcbEventLog/DcbBackend.res +3 -3
- package/src/adapter/DcbEventLog/DcbBackend.res.mjs +1 -3
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +11 -9
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +4 -6
- package/src/adapter/EventLog/EventLogBackend.res +3 -3
- package/src/adapter/EventLog/EventLogBackend.res.mjs +1 -3
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Backend.res +1 -1
- package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +5 -5
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +2 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +2 -2
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +32 -32
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +4 -3
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +6 -6
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -5
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +3 -3
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +5 -5
- package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +24 -18
- package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res +16 -14
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +2 -2
- package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +4 -4
- package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res +4 -4
- package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +9 -9
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +11 -9
- package/src/components/Api/AppSync_Adapter.res +4 -4
- package/src/components/InboundTranslationSlice_Builder.res +19 -0
- package/src/components/InboundTranslationSlice_Builder.res.mjs +12 -2
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +4 -7
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res.mjs +1 -4
- package/src/plugin/runtime/PluginRuntime_Builder.res +17 -26
- package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +7 -22
- package/tests/AppSyncEventsSigner_OpsTest.res +1 -1
- package/tests/AppSync_AdapterTest.res +4 -4
- package/tests/AppSync_AdapterTest.res.mjs +4 -8
- package/tests/Auth_ActiveRoleStoreTest.res +1 -1
- package/tests/Auth_ActiveRoleTrigger_OpsTest.res +1 -1
- package/tests/AutomationSliceEntryPoint_OpsTest.res +0 -2
- package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +3 -6
- package/tests/BakeConvergenceTest.res +1 -8
- package/tests/BakeConvergenceTest.res.mjs +3 -23
- package/tests/BakeManifestTest.res +5 -10
- package/tests/BakeManifestTest.res.mjs +1 -6
- package/tests/CommandLineTest.res +3 -3
- package/tests/DeployAppTest.res +3 -4
- package/tests/DeployAppTest.res.mjs +6 -15
- package/tests/EpInboundTestSlice.res +1 -0
- package/tests/EpInboundTestSlice.res.mjs +3 -0
- package/tests/EventCollectorPluginDefinitionAssetTest.res +1 -2
- package/tests/EventCollectorPluginDefinitionAssetTest.res.mjs +11 -21
- package/tests/IdentityProvider_Cognito_BackendTest.res +0 -3
- package/tests/IdentityProvider_Cognito_BackendTest.res.mjs +0 -3
- package/tests/PgQueryResolver_LambdaTest.res +6 -10
- package/tests/PgQueryResolver_LambdaTest.res.mjs +4 -34
- package/tests/Platform_ProvidedGroupsTest.res +2 -2
- package/tests/Platform_ProvidedGroupsTest.res.mjs +1 -2
- package/tests/ProvisionAccountsTest.res +5 -10
- package/tests/ProvisionAccountsTest.res.mjs +0 -9
- package/tests/ProvisionAdminTest.res +4 -9
- package/tests/ProvisionAdminTest.res.mjs +0 -7
- package/tests/ProvisionIdentityTest.res +2 -4
- package/tests/ProvisionIdentityTest.res.mjs +0 -2
- package/tests/SideEffectEntryPoint_OpsTest.res +2 -2
- package/tests/Util_ShellConfigTest.res +3 -3
- package/tests/Util_ShellConfigTest.res.mjs +1 -2
package/src/Platform.res.mjs
CHANGED
|
@@ -334,8 +334,7 @@ function MakeWithConfig(Config) {
|
|
|
334
334
|
};
|
|
335
335
|
domainEventsApiOpt = {
|
|
336
336
|
name: "DomainEventsApi",
|
|
337
|
-
api: api$2
|
|
338
|
-
defaultNamespace: undefined
|
|
337
|
+
api: api$2
|
|
339
338
|
};
|
|
340
339
|
} else {
|
|
341
340
|
let cognitoPool = Platform_Stack$ReventlessAws.resolveCognitoUserPool();
|
|
@@ -1505,6 +1504,8 @@ function MakeWithConfig(Config) {
|
|
|
1505
1504
|
return `\n Messaging is \`Capability_Messaging.make\`, passed to the platform as \`~messagingSender\`. The sender itself is configuration and has no default: set \`platform:messagingEmailSender\` in Pulumi.<stack>.yaml (or REVENTLESS_MESSAGING_EMAIL_SENDER), then verify the address with SES — or \`platform:messagingEmailProvider: log\` to log every message and send none.`;
|
|
1506
1505
|
case "IdentityProvider" :
|
|
1507
1506
|
return `\n IdentityProvider is the platform's Cognito pool, exported as \`identityProviderId\`. This platform stack exports none — deploy it first.`;
|
|
1507
|
+
case "Stash" :
|
|
1508
|
+
return `\n Stash has no deployed backend yet; the local platform keeps one in memory. Host a plugin that needs it on the local platform.`;
|
|
1508
1509
|
}
|
|
1509
1510
|
}))).join(""));
|
|
1510
1511
|
}
|
|
@@ -1768,8 +1769,7 @@ function Make($star) {
|
|
|
1768
1769
|
};
|
|
1769
1770
|
domainEventsApiOpt = {
|
|
1770
1771
|
name: "DomainEventsApi",
|
|
1771
|
-
api: api$2
|
|
1772
|
-
defaultNamespace: undefined
|
|
1772
|
+
api: api$2
|
|
1773
1773
|
};
|
|
1774
1774
|
} else {
|
|
1775
1775
|
let cognitoPool = Platform_Stack$ReventlessAws.resolveCognitoUserPool();
|
|
@@ -2914,6 +2914,8 @@ function Make($star) {
|
|
|
2914
2914
|
return `\n Messaging is \`Capability_Messaging.make\`, passed to the platform as \`~messagingSender\`. The sender itself is configuration and has no default: set \`platform:messagingEmailSender\` in Pulumi.<stack>.yaml (or REVENTLESS_MESSAGING_EMAIL_SENDER), then verify the address with SES — or \`platform:messagingEmailProvider: log\` to log every message and send none.`;
|
|
2915
2915
|
case "IdentityProvider" :
|
|
2916
2916
|
return `\n IdentityProvider is the platform's Cognito pool, exported as \`identityProviderId\`. This platform stack exports none — deploy it first.`;
|
|
2917
|
+
case "Stash" :
|
|
2918
|
+
return `\n Stash has no deployed backend yet; the local platform keeps one in memory. Host a plugin that needs it on the local platform.`;
|
|
2917
2919
|
}
|
|
2918
2920
|
}))).join(""));
|
|
2919
2921
|
}
|
|
@@ -8,7 +8,7 @@ read outside any `Output.apply`.
|
|
|
8
8
|
|
|
9
9
|
module Cognito = AwsSdk.CognitoIdentityServiceProvider
|
|
10
10
|
|
|
11
|
-
type pool = {id: string, region
|
|
11
|
+
type pool = {id: string, region?: string}
|
|
12
12
|
|
|
13
13
|
type send = Cognito.ListGroupsCommand.input => promise<Cognito.ListGroupsCommand.output>
|
|
14
14
|
|
|
@@ -39,7 +39,7 @@ let poolFromExports = (~get: string => option<JSON.t>): option<pool> => {
|
|
|
39
39
|
->Option.orElse(read("cognitoUserPoolId"))
|
|
40
40
|
->Option.map(id => {
|
|
41
41
|
id,
|
|
42
|
-
region: read("identityProviderRegion")->Option.orElse(read("cognitoRegion")),
|
|
42
|
+
region: ?(read("identityProviderRegion")->Option.orElse(read("cognitoRegion"))),
|
|
43
43
|
})
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -72,7 +72,7 @@ let resolvePool = async (~stackRef: option<Pulumi.StackReference.t>): option<poo
|
|
|
72
72
|
~cfg=Pulumi.Config.make(Some("platform")),
|
|
73
73
|
)->Option.map(id => {
|
|
74
74
|
id,
|
|
75
|
-
region: Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region"),
|
|
75
|
+
region: ?(Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region")),
|
|
76
76
|
})
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -86,7 +86,7 @@ let sendTo = (~region: option<string>): send => {
|
|
|
86
86
|
let load = async (~stackRef: option<Pulumi.StackReference.t>): unit =>
|
|
87
87
|
switch await resolvePool(~stackRef) {
|
|
88
88
|
| None => ()
|
|
89
|
-
| Some({id, region}) =>
|
|
89
|
+
| Some({id, ?region}) =>
|
|
90
90
|
let groups = try await listAll(~send=sendTo(~region), ~userPoolId=id) catch {
|
|
91
91
|
| exn if exn->Util_AwsError.hasCode(~code="AccessDeniedException") =>
|
|
92
92
|
JsError.throwWithMessage(
|
package/src/Platform_Stack.res
CHANGED
|
@@ -18,7 +18,7 @@ type cognitoUserPool = {
|
|
|
18
18
|
/** The sign-in attribute this stack created the pool with. `None` in BYO mode:
|
|
19
19
|
the pool's own choice was made elsewhere and no lookup here reads it back,
|
|
20
20
|
so reporting one would be a guess. */
|
|
21
|
-
loginIdentifier
|
|
21
|
+
loginIdentifier?: Auth_LoginIdentifier.t,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -250,7 +250,6 @@ let _resolveUncached = (): cognitoUserPool => {
|
|
|
250
250
|
managed: false,
|
|
251
251
|
activeRoleTable,
|
|
252
252
|
identityTable,
|
|
253
|
-
loginIdentifier: None,
|
|
254
253
|
}
|
|
255
254
|
|
|
256
255
|
| None =>
|
|
@@ -346,7 +345,7 @@ let _resolveUncached = (): cognitoUserPool => {
|
|
|
346
345
|
managed: true,
|
|
347
346
|
activeRoleTable,
|
|
348
347
|
identityTable,
|
|
349
|
-
loginIdentifier
|
|
348
|
+
loginIdentifier,
|
|
350
349
|
}
|
|
351
350
|
}
|
|
352
351
|
|
|
@@ -107,8 +107,7 @@ function _resolveUncached() {
|
|
|
107
107
|
poolArn: lookup.apply(r => r.arn),
|
|
108
108
|
managed: false,
|
|
109
109
|
activeRoleTable: activeRoleTable,
|
|
110
|
-
identityTable: identityTable
|
|
111
|
-
loginIdentifier: undefined
|
|
110
|
+
identityTable: identityTable
|
|
112
111
|
};
|
|
113
112
|
} else {
|
|
114
113
|
let loginIdentifier = _loginIdentifier(cfg);
|
|
@@ -23,13 +23,13 @@ let hmacFromBuf = (key: NodeCrypto.buffer, data: string): NodeCrypto.buffer =>
|
|
|
23
23
|
|
|
24
24
|
// ── SigV4 ───────────────────────────────────────────────────────────────────
|
|
25
25
|
|
|
26
|
-
type creds = {accessKeyId: string, secretAccessKey: string, sessionToken
|
|
26
|
+
type creds = {accessKeyId: string, secretAccessKey: string, sessionToken?: string}
|
|
27
27
|
|
|
28
28
|
// Ambient Lambda execution-role credentials (the managed runtime injects these).
|
|
29
29
|
let envCreds = (): creds => {
|
|
30
30
|
accessKeyId: NodeProcess.env->Dict.get("AWS_ACCESS_KEY_ID")->Option.getOr(""),
|
|
31
31
|
secretAccessKey: NodeProcess.env->Dict.get("AWS_SECRET_ACCESS_KEY")->Option.getOr(""),
|
|
32
|
-
sessionToken: NodeProcess.env->Dict.get("AWS_SESSION_TOKEN"),
|
|
32
|
+
sessionToken: ?(NodeProcess.env->Dict.get("AWS_SESSION_TOKEN")),
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
let region = (): string => NodeProcess.env->Dict.get("AWS_REGION")->Option.getOr("eu-west-1")
|
|
@@ -80,7 +80,7 @@ type t = {
|
|
|
80
80
|
/** Full AppSync Events API output — carry this through the stack. */
|
|
81
81
|
api: Api.t,
|
|
82
82
|
/** The `default` channel namespace created on the API. */
|
|
83
|
-
defaultNamespace
|
|
83
|
+
defaultNamespace?: ChannelNamespace.t,
|
|
84
84
|
/** The client-publishable `client` namespace. Absent on plugin-stack
|
|
85
85
|
phantoms (namespaces live on the platform stack's API). */
|
|
86
86
|
clientNamespace?: ChannelNamespace.t,
|
|
@@ -202,7 +202,7 @@ let make = (
|
|
|
202
202
|
~opts=Some({...opts, parent: api->Pulumi.Resource.makeFromJs}),
|
|
203
203
|
)
|
|
204
204
|
|
|
205
|
-
{name, api, defaultNamespace
|
|
205
|
+
{name, api, defaultNamespace, clientNamespace}
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
/** HTTP endpoint URL for use as Lambda `APPSYNC_ENDPOINT` env var.
|
|
@@ -334,9 +334,9 @@ let bakeSelection = (json: JSON.t): option<ReventlessCore.Platform_BakedManifest
|
|
|
334
334
|
->Option.flatMap(JSON.Decode.string)
|
|
335
335
|
->Option.map(plugin => {
|
|
336
336
|
ReventlessCore.Platform_BakedManifest.plugin,
|
|
337
|
-
views: strings(o, "views"),
|
|
338
|
-
commands: strings(o, "commands"),
|
|
339
|
-
derived: strings(o, "derived"),
|
|
337
|
+
views: ?strings(o, "views"),
|
|
338
|
+
commands: ?strings(o, "commands"),
|
|
339
|
+
derived: ?strings(o, "derived"),
|
|
340
340
|
})
|
|
341
341
|
)
|
|
342
342
|
}
|
|
@@ -502,8 +502,8 @@ type registrationState =
|
|
|
502
502
|
type registration = {
|
|
503
503
|
plugin: string,
|
|
504
504
|
expected: string,
|
|
505
|
-
found
|
|
506
|
-
writtenAt
|
|
505
|
+
found?: string,
|
|
506
|
+
writtenAt?: string,
|
|
507
507
|
state: registrationState,
|
|
508
508
|
}
|
|
509
509
|
|
|
@@ -550,7 +550,7 @@ let registrations = (
|
|
|
550
550
|
let row = current->Dict.get(plugin)
|
|
551
551
|
let found = row->Option.map(((key, _)) => key)
|
|
552
552
|
let writtenAt = row->Option.flatMap(((_, at)) => at)
|
|
553
|
-
{plugin, expected, found, writtenAt, state: classify(~expected, ~found, ~writtenAt, ~since)}
|
|
553
|
+
{plugin, expected, ?found, ?writtenAt, state: classify(~expected, ~found, ~writtenAt, ~since)}
|
|
554
554
|
})
|
|
555
555
|
}
|
|
556
556
|
|
|
@@ -64,7 +64,7 @@ let make = (
|
|
|
64
64
|
~id=name ++ "Policy",
|
|
65
65
|
~statements=[
|
|
66
66
|
{
|
|
67
|
-
sid: "AllowLambdaLogging",
|
|
67
|
+
PolicyDocument.sid: "AllowLambdaLogging",
|
|
68
68
|
effect: Allow,
|
|
69
69
|
actions: Actions([
|
|
70
70
|
"logs:CreateLogGroup",
|
|
@@ -79,13 +79,20 @@ let make = (
|
|
|
79
79
|
actions: Action("dynamodb:GetItem"),
|
|
80
80
|
resources: Resource(tableArn),
|
|
81
81
|
},
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
]->Array.concat(
|
|
83
|
+
// A supplied pool with no identity store yet: nothing to read, and
|
|
84
|
+
// an empty resource would make the policy invalid.
|
|
85
|
+
identityArn == ""
|
|
86
|
+
? []
|
|
87
|
+
: [
|
|
88
|
+
{
|
|
89
|
+
sid: "AllowReadingDomainId",
|
|
90
|
+
effect: Allow,
|
|
91
|
+
actions: Action("dynamodb:GetItem"),
|
|
92
|
+
resources: Resource(identityArn),
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
),
|
|
89
96
|
)
|
|
90
97
|
->PolicyDocument.toJsonString
|
|
91
98
|
->Pulumi.Input.make,
|
|
@@ -19,6 +19,7 @@ function make(activeRoleTableName, activeRoleTableArn, identityTableName, identi
|
|
|
19
19
|
activeRoleTableArn,
|
|
20
20
|
identityTableArn
|
|
21
21
|
]).apply(param => {
|
|
22
|
+
let identityArn = param[1];
|
|
22
23
|
new (Aws.iam.RolePolicy)(name + "Policy", {
|
|
23
24
|
policy: PolicyDocument$PulumiAws.toJsonString(PolicyDocument$PulumiAws.make(undefined, name + "Policy", [
|
|
24
25
|
{
|
|
@@ -36,14 +37,13 @@ function make(activeRoleTableName, activeRoleTableArn, identityTableName, identi
|
|
|
36
37
|
Effect: "Allow",
|
|
37
38
|
Action: "dynamodb:GetItem",
|
|
38
39
|
Resource: param[0]
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
Sid: "AllowReadingDomainId",
|
|
42
|
-
Effect: "Allow",
|
|
43
|
-
Action: "dynamodb:GetItem",
|
|
44
|
-
Resource: param[1]
|
|
45
40
|
}
|
|
46
|
-
]
|
|
41
|
+
].concat(identityArn === "" ? [] : [{
|
|
42
|
+
Sid: "AllowReadingDomainId",
|
|
43
|
+
Effect: "Allow",
|
|
44
|
+
Action: "dynamodb:GetItem",
|
|
45
|
+
Resource: identityArn
|
|
46
|
+
}]))),
|
|
47
47
|
role: lambdaRole.id
|
|
48
48
|
}, opts$1);
|
|
49
49
|
});
|
|
@@ -41,12 +41,51 @@ let makeTable = (
|
|
|
41
41
|
{name: table.name, arn: table.arn}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
let log = ReventlessCore.Logger.fromEnv()
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
The [ProviderScoped] table if `provision-identity` has created it, else an empty
|
|
48
|
+
name and ARN.
|
|
49
|
+
|
|
50
|
+
🚨 **Absent is a supported state, not a failed lookup** — unlike the active-role
|
|
51
|
+
store, which a supplied pool has always had. A pool provisioned before this store
|
|
52
|
+
existed has no table, and its deployments must keep deploying: the trigger then
|
|
53
|
+
adds no claim and every account keeps its `sub`, which is exactly what each one
|
|
54
|
+
did before. Running `provision-identity` again creates the table, and the next
|
|
55
|
+
deploy picks it up. A Pulumi `getTable` fails the whole program on a missing
|
|
56
|
+
table, so this asks DynamoDB directly.
|
|
57
|
+
*/
|
|
58
|
+
let lookupTableIfPresent = (~tableName: string): storeTable => {
|
|
59
|
+
let arn = Pulumi.Output.make(tableName)->Pulumi.Output.flatMap(name =>
|
|
60
|
+
(
|
|
61
|
+
async () =>
|
|
62
|
+
try {
|
|
63
|
+
let out = await AwsSdk.DynamoDb_DynamoDb.DescribeTableCommand.make({
|
|
64
|
+
tableName: name,
|
|
65
|
+
})->AwsSdk.DynamoDb_DynamoDb.DescribeTableCommand.send
|
|
66
|
+
out.table->Option.flatMap(t => t.tableArn)->Option.getOr("")
|
|
67
|
+
} catch {
|
|
68
|
+
| exn if Util_AwsError.isNotFound(exn) =>
|
|
69
|
+
log.warn(
|
|
70
|
+
~comp="IdentityStore",
|
|
71
|
+
`no identity store "${name}" on this provider — accounts keep their pool id. Run provision-identity to create it.`,
|
|
72
|
+
)
|
|
73
|
+
""
|
|
74
|
+
}
|
|
75
|
+
)()->Pulumi.Output.fromPromise
|
|
76
|
+
)
|
|
77
|
+
{
|
|
78
|
+
name: arn->Pulumi.Output.apply(found => found == "" ? "" : tableName),
|
|
79
|
+
arn,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The store a resolved provider calls for — created, or looked up if present. */
|
|
45
84
|
let resolveTable = (
|
|
46
85
|
~choice: Auth_ActiveRoleStore.storeChoice,
|
|
47
86
|
~opts: Pulumi.ComponentResource.options,
|
|
48
87
|
): storeTable =>
|
|
49
88
|
switch choice {
|
|
50
89
|
| StackScoped => makeTable(~opts)
|
|
51
|
-
| ProviderScoped(tableName) =>
|
|
90
|
+
| ProviderScoped(tableName) => lookupTableIfPresent(~tableName)
|
|
52
91
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Output$Pulumi from "@reventlessdev/rescript-pulumi-pulumi/src/Output.res.mjs";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Pulumi from "@pulumi/pulumi";
|
|
6
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
7
|
+
import * as Logger$ReventlessCore from "@reventlessdev/reventless-core/src/util/Logger.res.mjs";
|
|
3
8
|
import * as AWS_Tags$ReventlessAws from "../AWS_Tags.res.mjs";
|
|
9
|
+
import * as ClientDynamodb from "@aws-sdk/client-dynamodb";
|
|
10
|
+
import * as DynamoDb_DynamoDb$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/DynamoDb_DynamoDb.res.mjs";
|
|
4
11
|
import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
|
|
12
|
+
import * as Util_AwsError$ReventlessAws from "../../util/Util_AwsError.res.mjs";
|
|
5
13
|
import * as Util_DynamoDb$ReventlessAws from "../../util/Util_DynamoDb.res.mjs";
|
|
6
|
-
import * as Auth_ActiveRoleStore$ReventlessAws from "./Auth_ActiveRoleStore.res.mjs";
|
|
7
14
|
import * as Auth_IdentityStore_Schema$ReventlessAws from "./Auth_IdentityStore_Schema.res.mjs";
|
|
8
15
|
|
|
9
16
|
function chooseStore(identityProviderId) {
|
|
@@ -30,17 +37,49 @@ function makeTable(nameOpt, opts) {
|
|
|
30
37
|
};
|
|
31
38
|
}
|
|
32
39
|
|
|
40
|
+
let log = Logger$ReventlessCore.fromEnv();
|
|
41
|
+
|
|
42
|
+
function lookupTableIfPresent(tableName) {
|
|
43
|
+
let arn = Output$Pulumi.flatMap(Pulumi.output(tableName), name => (async () => {
|
|
44
|
+
try {
|
|
45
|
+
let out = await DynamoDb_DynamoDb$AwsSdk.DescribeTableCommand.send(new ClientDynamodb.DescribeTableCommand({
|
|
46
|
+
TableName: name
|
|
47
|
+
}));
|
|
48
|
+
return Stdlib_Option.getOr(Stdlib_Option.flatMap(out.Table, t => t.TableArn), "");
|
|
49
|
+
} catch (raw_exn) {
|
|
50
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
51
|
+
if (Util_AwsError$ReventlessAws.isNotFound(exn)) {
|
|
52
|
+
log.warn("IdentityStore", undefined, `no identity store "` + name + `" on this provider — accounts keep their pool id. Run provision-identity to create it.`);
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
throw exn;
|
|
56
|
+
}
|
|
57
|
+
})());
|
|
58
|
+
return {
|
|
59
|
+
name: arn.apply(found => {
|
|
60
|
+
if (found === "") {
|
|
61
|
+
return "";
|
|
62
|
+
} else {
|
|
63
|
+
return tableName;
|
|
64
|
+
}
|
|
65
|
+
}),
|
|
66
|
+
arn: arn
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
33
70
|
function resolveTable(choice, opts) {
|
|
34
71
|
if (typeof choice !== "object") {
|
|
35
72
|
return makeTable(undefined, opts);
|
|
36
73
|
} else {
|
|
37
|
-
return
|
|
74
|
+
return lookupTableIfPresent(choice._0);
|
|
38
75
|
}
|
|
39
76
|
}
|
|
40
77
|
|
|
41
78
|
export {
|
|
42
79
|
chooseStore,
|
|
43
80
|
makeTable,
|
|
81
|
+
log,
|
|
82
|
+
lookupTableIfPresent,
|
|
44
83
|
resolveTable,
|
|
45
84
|
}
|
|
46
|
-
/*
|
|
85
|
+
/* log Not a pure module */
|
|
@@ -53,8 +53,8 @@ let isPostgres = (): bool => selectionRef.contents->Option.isSome
|
|
|
53
53
|
type relayLogEntry = {
|
|
54
54
|
logName: string,
|
|
55
55
|
partitionTag: Reventless.DcbTag.derivedPartitionTag,
|
|
56
|
-
mutable collectorQueueUrl
|
|
57
|
-
mutable collectorQueueArn
|
|
56
|
+
mutable collectorQueueUrl?: Pulumi.Output.t<string>,
|
|
57
|
+
mutable collectorQueueArn?: Pulumi.Output.t<string>,
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
let relayLogs: array<relayLogEntry> = []
|
|
@@ -62,7 +62,7 @@ let relayLogs: array<relayLogEntry> = []
|
|
|
62
62
|
/** Step 1: record a Postgres DCB log and its partition tag (from the storage maker). */
|
|
63
63
|
let registerRelayLog = (~logName: string, ~partitionTag: Reventless.DcbTag.derivedPartitionTag) =>
|
|
64
64
|
relayLogs
|
|
65
|
-
->Array.push({logName, partitionTag
|
|
65
|
+
->Array.push({logName, partitionTag})
|
|
66
66
|
->ignore
|
|
67
67
|
|
|
68
68
|
/** Step 2: attach a plugin's EventCollector SQS queue to its DCB log's relay entry. */
|
|
@@ -265,9 +265,9 @@ let queryByCompositeTags = async (
|
|
|
265
265
|
|
|
266
266
|
// Filter clause shared by both scan paths.
|
|
267
267
|
type scanFilter = {
|
|
268
|
-
filterExpression
|
|
269
|
-
expressionAttributeNames
|
|
270
|
-
expressionAttributeValues
|
|
268
|
+
filterExpression?: string,
|
|
269
|
+
expressionAttributeNames?: Dict.t<string>,
|
|
270
|
+
expressionAttributeValues?: Dict.t<JSON.t>,
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
// Builds the scan FilterExpression. Always asserts `attribute_exists(event)` so
|
|
@@ -294,9 +294,9 @@ let buildScanFilter = (~eventTypes: option<array<string>>=?): scanFilter => {
|
|
|
294
294
|
|
|
295
295
|
let hasAttributeValues = expressionAttributeValues->Dict.keysToArray->Array.length > 0
|
|
296
296
|
{
|
|
297
|
-
filterExpression:
|
|
298
|
-
expressionAttributeNames
|
|
299
|
-
expressionAttributeValues: hasAttributeValues ? Some(expressionAttributeValues) : None,
|
|
297
|
+
filterExpression: filterParts->Array.join(" AND "),
|
|
298
|
+
expressionAttributeNames,
|
|
299
|
+
expressionAttributeValues: ?(hasAttributeValues ? Some(expressionAttributeValues) : None),
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
|
|
@@ -523,7 +523,7 @@ let deduplicateByPosition = (
|
|
|
523
523
|
|
|
524
524
|
type mergeSlot = {
|
|
525
525
|
queue: Queue.t<option<ReventlessCore.DcbEventLog_Adapter.rawSequencedEvent>>,
|
|
526
|
-
head
|
|
526
|
+
head?: ReventlessCore.DcbEventLog_Adapter.rawSequencedEvent,
|
|
527
527
|
}
|
|
528
528
|
|
|
529
529
|
// Wraps a sub-stream in a Queue(1) producer fiber and pulls the first element.
|
|
@@ -539,7 +539,9 @@ let initSlot = (
|
|
|
539
539
|
// unhandled-fiber-failure warning).
|
|
540
540
|
->Effect.ensuring(Queue.offer(queue, None)->Effect.map(_ => ()))
|
|
541
541
|
->Effect.catchAll(_ => Effect.succeed())
|
|
542
|
-
Effect.fork(producer)->Effect.flatMap(_ =>
|
|
542
|
+
Effect.fork(producer)->Effect.flatMap(_ =>
|
|
543
|
+
Queue.take(queue)->Effect.map(head => {queue, ?head})
|
|
544
|
+
)
|
|
543
545
|
})
|
|
544
546
|
|
|
545
547
|
// Returns the index of the slot with the smallest position, or None if all exhausted.
|
|
@@ -596,7 +598,7 @@ let mergeSortedEvents = (
|
|
|
596
598
|
let newSlots = slots->Array.mapWithIndex(
|
|
597
599
|
(s, i) =>
|
|
598
600
|
if i == idx {
|
|
599
|
-
{...s, head: nextHead}
|
|
601
|
+
{...s, head: ?nextHead}
|
|
600
602
|
} else {
|
|
601
603
|
s
|
|
602
604
|
},
|
|
@@ -468,14 +468,12 @@ function mergeSortedEvents(streams) {
|
|
|
468
468
|
let emitEvent = Stdlib_Option.getOrThrow(slot.head, undefined);
|
|
469
469
|
return Effect$1.map(Queue.take(slot.queue), nextHead => {
|
|
470
470
|
let newSlots = slots.map((s, i) => {
|
|
471
|
-
if (i
|
|
472
|
-
return {
|
|
473
|
-
queue: s.queue,
|
|
474
|
-
head: nextHead
|
|
475
|
-
};
|
|
476
|
-
} else {
|
|
471
|
+
if (i !== idx) {
|
|
477
472
|
return s;
|
|
478
473
|
}
|
|
474
|
+
let newrecord = {...s};
|
|
475
|
+
newrecord.head = nextHead;
|
|
476
|
+
return newrecord;
|
|
479
477
|
});
|
|
480
478
|
let hasActive = newSlots.some(s => Stdlib_Option.isSome(s.head));
|
|
481
479
|
return [
|
|
@@ -53,8 +53,8 @@ let isPostgres = (): bool => selectionRef.contents->Option.isSome
|
|
|
53
53
|
type relayLogEntry = {
|
|
54
54
|
logName: string,
|
|
55
55
|
aggregateName: string,
|
|
56
|
-
mutable collectorQueueUrl
|
|
57
|
-
mutable collectorQueueArn
|
|
56
|
+
mutable collectorQueueUrl?: Pulumi.Output.t<string>,
|
|
57
|
+
mutable collectorQueueArn?: Pulumi.Output.t<string>,
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
let relayLogs: array<relayLogEntry> = []
|
|
@@ -62,7 +62,7 @@ let relayLogs: array<relayLogEntry> = []
|
|
|
62
62
|
/** Step 1: record a Postgres classic log (from the storage maker). */
|
|
63
63
|
let registerRelayLog = (~logName: string, ~aggregateName: string) =>
|
|
64
64
|
relayLogs
|
|
65
|
-
->Array.push({logName, aggregateName
|
|
65
|
+
->Array.push({logName, aggregateName})
|
|
66
66
|
->ignore
|
|
67
67
|
|
|
68
68
|
/** Step 2: attach a plugin's EventCollector SQS queue to one aggregate's relay entry. */
|
|
@@ -23,9 +23,7 @@ let relayLogs = [];
|
|
|
23
23
|
function registerRelayLog(logName, aggregateName) {
|
|
24
24
|
relayLogs.push({
|
|
25
25
|
logName: logName,
|
|
26
|
-
aggregateName: aggregateName
|
|
27
|
-
collectorQueueUrl: undefined,
|
|
28
|
-
collectorQueueArn: undefined
|
|
26
|
+
aggregateName: aggregateName
|
|
29
27
|
});
|
|
30
28
|
}
|
|
31
29
|
|
|
@@ -57,7 +57,7 @@ let search = async (~indexName: string, ~text: string, ~maxResults: int=5): resu
|
|
|
57
57
|
Some({
|
|
58
58
|
Reventless.Geocoding.label: place.label->Option.getOr(""),
|
|
59
59
|
point,
|
|
60
|
-
relevance: r.relevance,
|
|
60
|
+
relevance: ?r.relevance,
|
|
61
61
|
})
|
|
62
62
|
// A coordinate that fails the range check is dropped rather than
|
|
63
63
|
// propagated: it cannot be stored, and one bad row should not lose
|
|
@@ -89,7 +89,7 @@ type binding = {
|
|
|
89
89
|
ops: ReventlessCore.QueryDb_Adapter.operations,
|
|
90
90
|
pushdowns: pushdowns,
|
|
91
91
|
indexes: array<Reventless.ReadModel.indexConfig>,
|
|
92
|
-
subIdField
|
|
92
|
+
subIdField?: string,
|
|
93
93
|
capability: ReventlessCore.GraphQL_FragmentGenerator.serverCapability,
|
|
94
94
|
labelField: string,
|
|
95
95
|
includeIdParam: bool,
|
|
@@ -97,9 +97,9 @@ type binding = {
|
|
|
97
97
|
/** The state's `@owner` field, when it declares one. Derived at Lambda init
|
|
98
98
|
from the same schema `capability` comes from, so the two cannot disagree
|
|
99
99
|
about which fields this read model has. */
|
|
100
|
-
ownerField
|
|
101
|
-
retiredField
|
|
102
|
-
retiredValues
|
|
100
|
+
ownerField?: string,
|
|
101
|
+
retiredField?: string,
|
|
102
|
+
retiredValues?: array<string>,
|
|
103
103
|
/** Whether a reference to a retired row of this read model still resolves its
|
|
104
104
|
name — the `@namedWhenRetired` opt-in. Read only by the reference door;
|
|
105
105
|
every other door narrows as it always did. */
|
|
@@ -107,7 +107,7 @@ type binding = {
|
|
|
107
107
|
/** The field a reference shows this row's picture from, derived from the same
|
|
108
108
|
schema as `capability` by `Reventless.RowImage`. `None` for a view that
|
|
109
109
|
declares no picture, which is most of them. */
|
|
110
|
-
imageSource
|
|
110
|
+
imageSource?: Reventless.RowImage.source,
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
// -- arg helpers -------------------------------------------------------------
|
|
@@ -11,7 +11,7 @@ type aggregateInfo = {
|
|
|
11
11
|
specModulePath: string,
|
|
12
12
|
decisionModulePath: string,
|
|
13
13
|
eventLogTableName: Pulumi.Output.t<string>,
|
|
14
|
-
mappingsModulePath
|
|
14
|
+
mappingsModulePath?: string,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
let aggregateInfos: dict<aggregateInfo> = Dict.make()
|
|
@@ -25,7 +25,7 @@ let registerAggregate = (
|
|
|
25
25
|
) =>
|
|
26
26
|
aggregateInfos->Dict.set(
|
|
27
27
|
aggregateName,
|
|
28
|
-
{specModulePath, decisionModulePath, eventLogTableName, mappingsModulePath},
|
|
28
|
+
{specModulePath, decisionModulePath, eventLogTableName, ?mappingsModulePath},
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
type storedSpec = {
|
|
@@ -15,7 +15,7 @@ type aggregateInfo = {
|
|
|
15
15
|
specModulePath: string,
|
|
16
16
|
decisionModulePath: string,
|
|
17
17
|
eventLogTableName: Pulumi.Output.t<string>,
|
|
18
|
-
mappingsModulePath
|
|
18
|
+
mappingsModulePath?: string,
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
let aggregateInfos: dict<aggregateInfo> = Dict.make()
|
|
@@ -29,7 +29,7 @@ let registerAggregate = (
|
|
|
29
29
|
) =>
|
|
30
30
|
aggregateInfos->Dict.set(
|
|
31
31
|
aggregateName,
|
|
32
|
-
{specModulePath, decisionModulePath, eventLogTableName, mappingsModulePath},
|
|
32
|
+
{specModulePath, decisionModulePath, eventLogTableName, ?mappingsModulePath},
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
type storedSpec = {
|