@reventlessdev/reventless-aws 3.0.0-alpha.345 → 3.0.0-alpha.347
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 +54 -0
- package/package.json +19 -12
- package/rescript.json +2 -1
- package/run-bake-manifest.mjs +3 -0
- package/run-deploy-app.mjs +3 -0
- package/run-provision-accounts.mjs +3 -0
- package/run-provision-admin.mjs +3 -0
- package/scripts/BakeManifest.res +395 -0
- package/scripts/BakeManifest.res.mjs +487 -0
- package/scripts/DeployApp.res +708 -0
- package/scripts/DeployApp.res.mjs +1015 -0
- package/scripts/DeployManifest.res +84 -0
- package/scripts/DeployManifest.res.mjs +112 -0
- package/scripts/ProvisionAccounts.res +339 -0
- package/scripts/ProvisionAccounts.res.mjs +351 -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 +76 -11
- package/scripts/ProvisionIdentity.res.mjs +72 -7
- package/scripts/ProvisionProvider.res +104 -0
- package/scripts/ProvisionProvider.res.mjs +123 -0
- package/scripts/PulumiCli.res +43 -0
- package/scripts/PulumiCli.res.mjs +106 -0
- package/src/Platform.res +51 -4
- package/src/Platform.res.mjs +32 -14
- package/src/Platform_Stack.res +119 -9
- package/src/Platform_Stack.res.mjs +42 -4
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +1 -5
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +1 -1
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +1 -5
- package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -5
- package/src/adapter/Auth/Auth_ActiveRoleStore.res.mjs +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res +1 -5
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +1 -2
- 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/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +52 -31
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +75 -44
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +1 -5
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +1 -2
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +1 -5
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res.mjs +1 -2
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +5 -4
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res.mjs +1 -1
- package/src/adapter/Postgres/PgMigration_Builder.res +1 -1
- package/src/adapter/Postgres/PgMigration_Builder.res.mjs +1 -2
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +5 -0
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +5 -1
- package/src/adapter/Runtime/CommandGeneratorEntryPoint_Ops.res +2 -0
- package/src/adapter/Runtime/CommandGeneratorEntryPoint_Ops.res.mjs +2 -2
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +15 -6
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +51 -30
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +31 -14
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +1 -5
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +1 -1
- package/src/adapter/StateTopic/StateTopic_AppSync.res +1 -5
- package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +1 -1
- package/src/adapter/Task/TaskBucket_S3.res +1 -3
- package/src/adapter/Task/TaskBucket_S3.res.mjs +1 -1
- package/src/adapter/Upload/Upload_Claim_S3.res +1 -5
- package/src/adapter/Upload/Upload_Claim_S3.res.mjs +1 -1
- package/src/adapter/Upload/Upload_Presign_S3.res +1 -5
- package/src/adapter/Upload/Upload_Presign_S3.res.mjs +1 -2
- package/src/capability/Capability_Geocoding_AwsLocation.res +5 -1
- package/src/capability/Capability_Geocoding_AwsLocation.res.mjs +7 -1
- package/src/components/Api/AppSync_Adapter.res +56 -72
- package/src/components/Api/AppSync_Adapter.res.mjs +26 -60
- package/src/components/Api/AppSync_SdlDecorate.res +82 -1
- package/src/components/Api/AppSync_SdlDecorate.res.mjs +45 -0
- package/src/plugin/cloner/ClonerRunner_Fargate.res +1 -5
- package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +1 -1
- package/src/plugin/stack/Plugin_Stack.res +4 -0
- package/src/plugin/stack/Plugin_Stack.res.mjs +2 -0
- package/src/util/Util_DeadLetterQueue.res +1 -5
- package/src/util/Util_DeadLetterQueue.res.mjs +1 -2
- package/src/util/Util_StoreLayout.res +15 -2
- package/src/util/Util_StoreLayout.res.mjs +11 -3
- package/tests/AppSync_AdapterTest.res +83 -0
- package/tests/AppSync_AdapterTest.res.mjs +69 -0
- 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/BakeManifestTest.res +204 -0
- package/tests/BakeManifestTest.res.mjs +259 -0
- package/tests/DcbColdStartPartitionTest.res +32 -0
- package/tests/DcbColdStartPartitionTest.res.mjs +33 -0
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +88 -0
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res.mjs +112 -0
- package/tests/DcbUnresolvedPartitionSlice.res +28 -0
- package/tests/DcbUnresolvedPartitionSlice.res.mjs +38 -0
- package/tests/DeployAppTest.res +90 -0
- package/tests/DeployAppTest.res.mjs +133 -0
- package/tests/LambdaLayerLookupTest.res +104 -0
- package/tests/LambdaLayerLookupTest.res.mjs +117 -0
- package/tests/ProvisionAccountsTest.res +168 -0
- package/tests/ProvisionAccountsTest.res.mjs +184 -0
- package/tests/ProvisionAdminTest.res +55 -0
- package/tests/ProvisionAdminTest.res.mjs +66 -0
- package/tests/ProvisionIdentityTest.res +89 -3
- package/tests/ProvisionIdentityTest.res.mjs +66 -1
- package/tests/Util_OwnerScopeEnvTest.res +25 -0
- package/tests/Util_OwnerScopeEnvTest.res.mjs +13 -0
- package/tests/Util_StoreLayoutTest.res +6 -0
- package/tests/Util_StoreLayoutTest.res.mjs +7 -4
- package/tests/dcbColdStartPartition.mjs +66 -0
- package/tests/setup/layerArn.cjs +5 -0
|
@@ -328,6 +328,11 @@ let capabilities = (): Reventless.Capabilities.t => {
|
|
|
328
328
|
~text,
|
|
329
329
|
),
|
|
330
330
|
messaging: messagingEmailProvider(),
|
|
331
|
+
// Refusing until the Cognito backend lands. The pool is provisioned, but the
|
|
332
|
+
// store mapping a domain user id to a provider handle is not, and creating a
|
|
333
|
+
// principal before that exists would write a handle with nowhere to live.
|
|
334
|
+
identityProvider: Reventless.Capabilities.none.identityProvider,
|
|
335
|
+
secrets: ReventlessCore.Secrets_Node_Backend.provider,
|
|
331
336
|
}
|
|
332
337
|
|
|
333
338
|
// ── Phase-1/phase-2 pipelines ───────────────────────────────────────────────
|
|
@@ -12,9 +12,11 @@ import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/compon
|
|
|
12
12
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
13
13
|
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
14
14
|
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
15
|
+
import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
|
|
15
16
|
import * as EffectLogger$ReventlessCore from "@reventlessdev/reventless-core/src/util/EffectLogger.res.mjs";
|
|
16
17
|
import * as DynamoDb_Error$ReventlessAws from "../../errors/DynamoDb_Error.res.mjs";
|
|
17
18
|
import * as Messaging_Ses_Backend$ReventlessAws from "../Messaging/Messaging_Ses_Backend.res.mjs";
|
|
19
|
+
import * as Secrets_Node_Backend$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/Secrets/Secrets_Node_Backend.res.mjs";
|
|
18
20
|
import * as Util_DynamoDb_Runtime$ReventlessAws from "../../util/Util_DynamoDb_Runtime.res.mjs";
|
|
19
21
|
import * as Messaging_Log_Backend$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/Messaging/Messaging_Log_Backend.res.mjs";
|
|
20
22
|
import * as AutomationSlice_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs";
|
|
@@ -199,7 +201,9 @@ function messagingEmailProvider() {
|
|
|
199
201
|
function capabilities() {
|
|
200
202
|
return {
|
|
201
203
|
geocode: text => Geocoder_AwsLocation_Backend$ReventlessAws.search(Stdlib_Option.getOr(process.env["PLACE_INDEX_NAME"], ""), text, undefined),
|
|
202
|
-
messaging: messagingEmailProvider()
|
|
204
|
+
messaging: messagingEmailProvider(),
|
|
205
|
+
identityProvider: Capabilities$Reventless.none.identityProvider,
|
|
206
|
+
secrets: Secrets_Node_Backend$ReventlessCore.provider
|
|
203
207
|
};
|
|
204
208
|
}
|
|
205
209
|
|
|
@@ -22,6 +22,7 @@ let makeCommandGenerator = (
|
|
|
22
22
|
~commandSchema,
|
|
23
23
|
~componentKind: ReventlessCore.CommandGenerator_Callback.commandComponentKind,
|
|
24
24
|
~stripIdFromParams: bool,
|
|
25
|
+
~partitionTag: option<Reventless.DcbTag.derivedPartitionTag>=?,
|
|
25
26
|
): ReventlessCore.CommandGenerator.commandGenerator =>
|
|
26
27
|
ReventlessCore.CommandGenerator_Callback.makeGenerateCommand(
|
|
27
28
|
~publishJsons,
|
|
@@ -30,4 +31,5 @@ let makeCommandGenerator = (
|
|
|
30
31
|
~commandSchema,
|
|
31
32
|
~componentKind,
|
|
32
33
|
~stripIdFromParams,
|
|
34
|
+
~partitionTag?,
|
|
33
35
|
)
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as CommandGenerator_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandGenerator/CommandGenerator_Callback.res.mjs";
|
|
4
4
|
|
|
5
|
-
function makeCommandGenerator(publishJsons, publishJsonsAndWait, serviceName, commandSchema, componentKind, stripIdFromParams) {
|
|
6
|
-
return CommandGenerator_Callback$ReventlessCore.makeGenerateCommand(publishJsons, publishJsonsAndWait, serviceName, commandSchema, componentKind, stripIdFromParams);
|
|
5
|
+
function makeCommandGenerator(publishJsons, publishJsonsAndWait, serviceName, commandSchema, componentKind, stripIdFromParams, partitionTag) {
|
|
6
|
+
return CommandGenerator_Callback$ReventlessCore.makeGenerateCommand(publishJsons, publishJsonsAndWait, serviceName, commandSchema, componentKind, stripIdFromParams, partitionTag);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export {
|
|
@@ -26,7 +26,7 @@ import { commandOutcomeToJson, runInlineAndCollect } from "@reventlessdev/revent
|
|
|
26
26
|
// re-exporting it in sury 11. This is the same binding the compiled ReScript uses.
|
|
27
27
|
import { json as jsonSchema } from "sury";
|
|
28
28
|
import { handleQueueEvent, publishJsons as sqsPublishJsons } from "@reventlessdev/reventless-aws/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
29
|
-
// Typed cold-start core — scope/
|
|
29
|
+
// Typed cold-start core — scope/partition derivation, storage-ops wiring, and
|
|
30
30
|
// per-slice handler building (functor + decode + handleCommands), all
|
|
31
31
|
// compiler-checked against the framework signatures (see the module header and
|
|
32
32
|
// docs/plans/done/minimize-lambda-entrypoint-mjs-shell.md).
|
|
@@ -89,7 +89,6 @@ export async function buildHandlersForConfig(config, opts = {}) {
|
|
|
89
89
|
// as `dcb_event.log_name`); absence keeps the DynamoDB path byte-identical.
|
|
90
90
|
const specs = loadedSlices.map(({ patchedSpec }) => patchedSpec);
|
|
91
91
|
const scope = deriveScope(specs);
|
|
92
|
-
const { crossPartitionTagKeys, tagKeysByEventType } = scope;
|
|
93
92
|
const rawStorageOps = makeStorageOps(
|
|
94
93
|
config.dcbEventLogTableName,
|
|
95
94
|
config.pgConnection,
|
|
@@ -98,6 +97,7 @@ export async function buildHandlersForConfig(config, opts = {}) {
|
|
|
98
97
|
|
|
99
98
|
const handlersByType = {};
|
|
100
99
|
const commandSchemasByType = {};
|
|
100
|
+
const partitionTagsByType = {};
|
|
101
101
|
const sharedDcbEventLogOps = dcbEventLogOperationsMake({
|
|
102
102
|
name: config.pluginName,
|
|
103
103
|
// Mirrors DcbEventLog_Builder.res's `name ++ "DcbEventLog"` — the
|
|
@@ -116,8 +116,7 @@ export async function buildHandlersForConfig(config, opts = {}) {
|
|
|
116
116
|
const jsonHandler = buildSliceHandler(
|
|
117
117
|
patchedSpec,
|
|
118
118
|
behaviorModule,
|
|
119
|
-
|
|
120
|
-
crossPartitionTagKeys,
|
|
119
|
+
scope,
|
|
121
120
|
sharedDcbEventLogOps,
|
|
122
121
|
);
|
|
123
122
|
for (const typeName of commandTypeNames(patchedSpec)) {
|
|
@@ -134,6 +133,8 @@ export async function buildHandlersForConfig(config, opts = {}) {
|
|
|
134
133
|
);
|
|
135
134
|
} else {
|
|
136
135
|
commandSchemasByType[typeName] = patchedSpec.commandSchema;
|
|
136
|
+
// The envelope id is the command's value of its slice's partition key.
|
|
137
|
+
partitionTagsByType[typeName] = scope.partitionTagBySlice[patchedSpec.name];
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
});
|
|
@@ -225,17 +226,21 @@ export async function buildHandlersForConfig(config, opts = {}) {
|
|
|
225
226
|
// reads a command's `@owner` fields from: given `S.json` it finds none, for every
|
|
226
227
|
// command, and the write keeps whatever owner the CLIENT sent. Validation was
|
|
227
228
|
// never the only job.
|
|
228
|
-
const makeGeneratorFor = (commandSchema) => makeCommandGenerator(
|
|
229
|
+
const makeGeneratorFor = (commandSchema, partitionTag) => makeCommandGenerator(
|
|
229
230
|
publishJsons,
|
|
230
231
|
publishJsonsAndWait,
|
|
231
232
|
config.pluginName,
|
|
232
233
|
commandSchema,
|
|
233
234
|
"StateChangeSlice",
|
|
234
235
|
false,
|
|
236
|
+
partitionTag,
|
|
235
237
|
);
|
|
236
238
|
const generatorsByType = {};
|
|
237
239
|
for (const typeName of Object.keys(commandSchemasByType)) {
|
|
238
|
-
generatorsByType[typeName] = makeGeneratorFor(
|
|
240
|
+
generatorsByType[typeName] = makeGeneratorFor(
|
|
241
|
+
commandSchemasByType[typeName],
|
|
242
|
+
partitionTagsByType[typeName],
|
|
243
|
+
);
|
|
239
244
|
}
|
|
240
245
|
// A command no loaded slice claims keeps the permissive generator — what every
|
|
241
246
|
// command got before this change — so anything reaching this handler by another
|
|
@@ -301,6 +306,10 @@ async function buildHandler() {
|
|
|
301
306
|
}
|
|
302
307
|
|
|
303
308
|
const initPromise = buildHandler();
|
|
309
|
+
// Startup runs at module load, before any invocation awaits it. A failure left
|
|
310
|
+
// unhandled until then can surface as a bare `Runtime.UnhandledPromiseRejection`
|
|
311
|
+
// and a restart; handled here, every invocation rethrows the same clear error.
|
|
312
|
+
initPromise.catch(() => {});
|
|
304
313
|
|
|
305
314
|
export async function handler(event, context) {
|
|
306
315
|
setRequestId(context?.awsRequestId);
|
|
@@ -37,47 +37,62 @@ type pgConnectionJson
|
|
|
37
37
|
@get external pgLockStrategy: pgConnectionJson => Nullable.t<string> = "lockStrategy"
|
|
38
38
|
external asConnectionConfig: pgConnectionJson => PgConnection.connectionConfig = "%identity"
|
|
39
39
|
|
|
40
|
-
// The decision-read scope + storage partition
|
|
40
|
+
// The decision-read scope + storage partition for one consistency boundary,
|
|
41
41
|
// derived exactly the way the deploy-time `Dcb_Builder` does (both call the same
|
|
42
42
|
// `Reventless.DcbTag` functions — the single source of truth), so the runtime
|
|
43
43
|
// query can't diverge from the storage/GSI scope.
|
|
44
44
|
type derivedScope = {
|
|
45
45
|
crossPartitionTagKeys: array<string>,
|
|
46
46
|
tagKeysByEventType: dict<array<string>>,
|
|
47
|
+
/** `None` only for a Lambda hosting no StateChangeSlices, which never appends. */
|
|
47
48
|
partitionTag: option<Reventless.DcbTag.derivedPartitionTag>,
|
|
49
|
+
/** Slice name -> its partition: the handler's entity id and each command's envelope id. */
|
|
50
|
+
partitionTagBySlice: dict<Reventless.DcbTag.derivedPartitionTag>,
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
let deriveScope = (specs: array<specModule>): derivedScope =>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
let deriveScope = (specs: array<specModule>): derivedScope =>
|
|
54
|
+
switch specs {
|
|
55
|
+
| [] => {
|
|
56
|
+
crossPartitionTagKeys: [],
|
|
57
|
+
tagKeysByEventType: Dict.make(),
|
|
58
|
+
partitionTag: None,
|
|
59
|
+
partitionTagBySlice: Dict.make(),
|
|
60
|
+
}
|
|
61
|
+
| _ =>
|
|
62
|
+
let slices = specs->Array.map(s => {
|
|
53
63
|
Reventless.DcbTag.name: specName(s),
|
|
54
64
|
commandSchema: specCommandSchema(s),
|
|
55
65
|
consumedEventSchema: specConsumedEventSchema(s),
|
|
56
66
|
eventSchema: specEventSchema(s),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
67
|
+
moduleUrl: ?(specModuleUrl(s)->Nullable.toOption),
|
|
68
|
+
})
|
|
69
|
+
let scope = Reventless.DcbTag.deriveEffectiveScope(slices)
|
|
70
|
+
// Deploy derives this from the same slice list, so on the same code it cannot
|
|
71
|
+
// fail here. It can when the framework in the Lambda layer differs from the
|
|
72
|
+
// one deploy used — and then carrying on would file events under the wrong
|
|
73
|
+
// keys. Refuse to start instead, saying why before the rejection can be lost.
|
|
74
|
+
// Rethrown as the original JS error, so each invocation reports its message.
|
|
75
|
+
let boundary = try Reventless.DcbTag.deriveBoundaryPartition(slices) catch {
|
|
76
|
+
| JsExn(err) =>
|
|
77
|
+
ReventlessCore.EffectLogger.logError(
|
|
78
|
+
~comp="DcbCommandTopicRuntime",
|
|
79
|
+
`refusing to start: ${err->JsExn.message->Option.getOr("unknown error")}`,
|
|
80
|
+
)->Effect.runSync
|
|
81
|
+
JsExn.throw(err)
|
|
82
|
+
}
|
|
83
|
+
let partitionTagBySlice = Dict.make()
|
|
84
|
+
slices->Array.forEach(s =>
|
|
85
|
+
boundary
|
|
86
|
+
->Reventless.DcbTag.slicePartitionTag(s.name)
|
|
87
|
+
->Option.forEach(tag => partitionTagBySlice->Dict.set(s.name, tag))
|
|
88
|
+
)
|
|
89
|
+
{
|
|
90
|
+
crossPartitionTagKeys: scope.crossPartitionTagKeys,
|
|
91
|
+
tagKeysByEventType: scope.tagKeysByEventType,
|
|
92
|
+
partitionTag: Some(boundary.partitionTag),
|
|
93
|
+
partitionTagBySlice,
|
|
94
|
+
}
|
|
79
95
|
}
|
|
80
|
-
}
|
|
81
96
|
|
|
82
97
|
// The command TAG names this slice handles — used by the shell to build its
|
|
83
98
|
// `handlersByType` routing map.
|
|
@@ -166,6 +181,7 @@ type sliceCallback = {
|
|
|
166
181
|
handleCommands: (
|
|
167
182
|
~tagKeysByEventType: dict<array<string>>=?,
|
|
168
183
|
~crossPartitionTagKeys: array<string>=?,
|
|
184
|
+
~partitionTag: Reventless.DcbTag.derivedPartitionTag=?,
|
|
169
185
|
ReventlessInfra.DcbEventLog.operations,
|
|
170
186
|
Stream.t<
|
|
171
187
|
ReventlessInfra.CommandTopic.topicItem<
|
|
@@ -188,8 +204,7 @@ external makeSliceCallback: specModule => behaviorModule => sliceCallback = "Mak
|
|
|
188
204
|
let buildSliceHandler = (
|
|
189
205
|
spec: specModule,
|
|
190
206
|
behavior: behaviorModule,
|
|
191
|
-
|
|
192
|
-
~crossPartitionTagKeys: array<string>,
|
|
207
|
+
scope: derivedScope,
|
|
193
208
|
dcbEventLog: ReventlessInfra.DcbEventLog.operations,
|
|
194
209
|
) => {
|
|
195
210
|
let callback = makeSliceCallback(spec)(behavior)
|
|
@@ -220,7 +235,13 @@ let buildSliceHandler = (
|
|
|
220
235
|
| None => Stream.empty
|
|
221
236
|
}
|
|
222
237
|
)
|
|
223
|
-
callback.handleCommands(
|
|
238
|
+
callback.handleCommands(
|
|
239
|
+
~tagKeysByEventType=scope.tagKeysByEventType,
|
|
240
|
+
~crossPartitionTagKeys=scope.crossPartitionTagKeys,
|
|
241
|
+
~partitionTag=?scope.partitionTagBySlice->Dict.get(specName(spec)),
|
|
242
|
+
dcbEventLog,
|
|
243
|
+
decodedStream,
|
|
244
|
+
)
|
|
224
245
|
}
|
|
225
246
|
}
|
|
226
247
|
|
|
@@ -20,26 +20,43 @@ import * as StateChangeSlice_CallbackResMjs from "@reventlessdev/reventless-core
|
|
|
20
20
|
import * as InboundTranslationSlice_CallbackResMjs from "@reventlessdev/reventless-core/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs";
|
|
21
21
|
|
|
22
22
|
function deriveScope(specs) {
|
|
23
|
-
|
|
23
|
+
if (specs.length === 0) {
|
|
24
|
+
return {
|
|
25
|
+
crossPartitionTagKeys: [],
|
|
26
|
+
tagKeysByEventType: {},
|
|
27
|
+
partitionTag: undefined,
|
|
28
|
+
partitionTagBySlice: {}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
let slices = specs.map(s => ({
|
|
24
32
|
name: s.name,
|
|
25
33
|
commandSchema: s.commandSchema,
|
|
26
34
|
consumedEventSchema: s.consumedEventSchema,
|
|
27
|
-
eventSchema: s.eventSchema
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
eventSchema: s.eventSchema,
|
|
36
|
+
moduleUrl: Primitive_option.fromNullable(s.moduleUrl)
|
|
37
|
+
}));
|
|
38
|
+
let scope = DcbTag$Reventless.deriveEffectiveScope(slices);
|
|
39
|
+
let boundary;
|
|
30
40
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
boundary = DcbTag$Reventless.deriveBoundaryPartition(slices);
|
|
42
|
+
} catch (raw_err) {
|
|
43
|
+
let err = Primitive_exceptions.internalToException(raw_err);
|
|
44
|
+
if (err.RE_EXN_ID === "JsExn") {
|
|
45
|
+
let err$1 = err._1;
|
|
46
|
+
Effect.runSync(EffectLogger$ReventlessCore.logError("DcbCommandTopicRuntime", undefined, `refusing to start: ` + Stdlib_Option.getOr(Stdlib_JsExn.message(err$1), "unknown error")));
|
|
47
|
+
throw err$1;
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
38
50
|
}
|
|
51
|
+
let partitionTagBySlice = {};
|
|
52
|
+
slices.forEach(s => Stdlib_Option.forEach(DcbTag$Reventless.slicePartitionTag(boundary, s.name), tag => {
|
|
53
|
+
partitionTagBySlice[s.name] = tag;
|
|
54
|
+
}));
|
|
39
55
|
return {
|
|
40
56
|
crossPartitionTagKeys: scope.crossPartitionTagKeys,
|
|
41
57
|
tagKeysByEventType: scope.tagKeysByEventType,
|
|
42
|
-
partitionTag: partitionTag
|
|
58
|
+
partitionTag: boundary.partitionTag,
|
|
59
|
+
partitionTagBySlice: partitionTagBySlice
|
|
43
60
|
};
|
|
44
61
|
}
|
|
45
62
|
|
|
@@ -75,7 +92,7 @@ function makeStorageOps(tableName, pgConnection, scope) {
|
|
|
75
92
|
}
|
|
76
93
|
}
|
|
77
94
|
|
|
78
|
-
function buildSliceHandler(spec, behavior,
|
|
95
|
+
function buildSliceHandler(spec, behavior, scope, dcbEventLog) {
|
|
79
96
|
let callback = StateChangeSlice_CallbackResMjs.Make(spec)(behavior);
|
|
80
97
|
let commandSchema = spec.commandSchema;
|
|
81
98
|
return jsonStream => {
|
|
@@ -97,7 +114,7 @@ function buildSliceHandler(spec, behavior, tagKeysByEventType, crossPartitionTag
|
|
|
97
114
|
return Stream.empty;
|
|
98
115
|
}
|
|
99
116
|
});
|
|
100
|
-
return callback.handleCommands(tagKeysByEventType, crossPartitionTagKeys, dcbEventLog, decodedStream);
|
|
117
|
+
return callback.handleCommands(scope.tagKeysByEventType, scope.crossPartitionTagKeys, scope.partitionTagBySlice[spec.name], dcbEventLog, decodedStream);
|
|
101
118
|
};
|
|
102
119
|
}
|
|
103
120
|
|
|
@@ -224,11 +224,7 @@ let makeFromCodeAsset: (
|
|
|
224
224
|
})
|
|
225
225
|
})
|
|
226
226
|
|
|
227
|
-
let layers =
|
|
228
|
-
Lambda.reventlessLayerArn
|
|
229
|
-
->Option.map(arn => [arn->Pulumi.Input.make])
|
|
230
|
-
->Option.getOr([])
|
|
231
|
-
->Pulumi.Input.make
|
|
227
|
+
let layers = Lambda.reventlessLayers()
|
|
232
228
|
|
|
233
229
|
let variables = Dict.fromArray([("Environment", stack->Pulumi.Input.make)])
|
|
234
230
|
envVars->Dict.forEachWithKey((value, key) => {
|
|
@@ -91,7 +91,7 @@ function makeFromCodeAsset(name, unitKind, componentKind, code, sourceCodeHash,
|
|
|
91
91
|
});
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
|
-
let layers =
|
|
94
|
+
let layers = Lambda$PulumiAws.reventlessLayers();
|
|
95
95
|
let variables = Object.fromEntries([[
|
|
96
96
|
"Environment",
|
|
97
97
|
stack
|
|
@@ -332,11 +332,7 @@ let finish = (~eventsApi: AppSync_EventsApi.t, ~opts: Pulumi.CustomResourceOptio
|
|
|
332
332
|
~bundleRuntimeExtensions=false,
|
|
333
333
|
)
|
|
334
334
|
|
|
335
|
-
let layers =
|
|
336
|
-
Lambda.reventlessLayerArn
|
|
337
|
-
->Option.map(arn => [arn->Pulumi.Input.make])
|
|
338
|
-
->Option.getOr([])
|
|
339
|
-
->Pulumi.Input.make
|
|
335
|
+
let layers = Lambda.reventlessLayers()
|
|
340
336
|
|
|
341
337
|
let appsyncEndpoint = AppSync_EventsApi.httpEndpoint(eventsApi)
|
|
342
338
|
|
|
@@ -120,7 +120,7 @@ function finish(eventsApi, opts) {
|
|
|
120
120
|
Util_Bundle$ReventlessAws.resolvePackageRoot(undefined, "@reventlessdev/reventless-aws")
|
|
121
121
|
]]);
|
|
122
122
|
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/StateTopic/StateTopic_AppSync_Ops.res.mjs", packageDirs, undefined, false);
|
|
123
|
-
let layers =
|
|
123
|
+
let layers = Lambda$PulumiAws.reventlessLayers();
|
|
124
124
|
let appsyncEndpoint = AppSync_EventsApi$ReventlessAws.httpEndpoint(eventsApi);
|
|
125
125
|
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name + "StateTopicPublisher", undefined, AWS_Tags$ReventlessAws.make(name + "StateTopicPublisherLogGroup", QueryDb$ReventlessCore.componentType, "Logs", undefined, name, undefined, undefined, undefined), opts, undefined);
|
|
126
126
|
let lambda = new (Aws.lambda.Function)(name + "StateTopicPublisher", {
|
|
@@ -136,9 +136,7 @@ let make: ReventlessCore.Task_Adapter.bucketMaker<bucketParts> = (~name, ~opts)
|
|
|
136
136
|
// bucket fails the deploy with `BucketNotEmpty` — which would wedge precisely
|
|
137
137
|
// the throwaway stacks that are recreated most often. Protected stacks keep
|
|
138
138
|
// the safe default and drain by hand.
|
|
139
|
-
let forceDestroy =
|
|
140
|
-
Util_StoreLayout.protectionFor(~stack=Pulumi.Pulumi.getStackName()) ==
|
|
141
|
-
Util_StoreLayout.Unprotected
|
|
139
|
+
let forceDestroy = Util_StoreLayout.protectionOfDeployedStack() == Util_StoreLayout.Unprotected
|
|
142
140
|
|
|
143
141
|
let bucket = {
|
|
144
142
|
PulumiAws.S3.Bucket.make(
|
|
@@ -76,7 +76,7 @@ function connect(name, bucket, bucketMode, commandTopics, runtime, opts) {
|
|
|
76
76
|
|
|
77
77
|
function make(name, opts) {
|
|
78
78
|
let opts$1 = Util_Pulumi$ReventlessCore.ComponentResourceOptions.toCustomResourceOptions(opts);
|
|
79
|
-
let forceDestroy = Util_StoreLayout$ReventlessAws.
|
|
79
|
+
let forceDestroy = Util_StoreLayout$ReventlessAws.protectionOfDeployedStack() === "Unprotected";
|
|
80
80
|
let bucket = new (Aws.s3.Bucket)(name, {
|
|
81
81
|
corsRules: [{
|
|
82
82
|
allowedHeaders: ["*"],
|
|
@@ -257,11 +257,7 @@ let finish = (
|
|
|
257
257
|
~bundleRuntimeExtensions=false,
|
|
258
258
|
)
|
|
259
259
|
|
|
260
|
-
let layers =
|
|
261
|
-
Lambda.reventlessLayerArn
|
|
262
|
-
->Option.map(arn => [arn->Pulumi.Input.make])
|
|
263
|
-
->Option.getOr([])
|
|
264
|
-
->Pulumi.Input.make
|
|
260
|
+
let layers = Lambda.reventlessLayers()
|
|
265
261
|
|
|
266
262
|
// Created before the function that writes to it — see
|
|
267
263
|
// `Util_LambdaLogging.makeManagedLogGroup` for why the ordering matters.
|
|
@@ -124,7 +124,7 @@ function finish(plugin, stores, iteratorAgeAlarmMsOpt, opts) {
|
|
|
124
124
|
Util_Bundle$ReventlessAws.resolvePackageRoot(undefined, "@reventlessdev/reventless-aws")
|
|
125
125
|
]]);
|
|
126
126
|
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Upload/Upload_Claim_S3_Ops.res.mjs", packageDirs, undefined, false);
|
|
127
|
-
let layers =
|
|
127
|
+
let layers = Lambda$PulumiAws.reventlessLayers();
|
|
128
128
|
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name, undefined, AWS_Tags$ReventlessAws.make(name + "LogGroup", "Plugin", "Logs", undefined, name, undefined, undefined, undefined), opts, undefined);
|
|
129
129
|
let lambda = new (Aws.lambda.Function)(name, {
|
|
130
130
|
handler: "index.handler",
|
|
@@ -180,11 +180,7 @@ let make = (
|
|
|
180
180
|
~bundleRuntimeExtensions=false,
|
|
181
181
|
)
|
|
182
182
|
|
|
183
|
-
let layers =
|
|
184
|
-
Lambda.reventlessLayerArn
|
|
185
|
-
->Option.map(arn => [arn->Pulumi.Input.make])
|
|
186
|
-
->Option.getOr([])
|
|
187
|
-
->Pulumi.Input.make
|
|
183
|
+
let layers = Lambda.reventlessLayers()
|
|
188
184
|
|
|
189
185
|
// Created before the function that writes to it — see
|
|
190
186
|
// `Util_LambdaLogging.makeManagedLogGroup` for why the ordering matters.
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import * as Aws from "@pulumi/aws";
|
|
4
4
|
import * as IAM$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/IAM/IAM.res.mjs";
|
|
5
5
|
import * as Output$Pulumi from "@reventlessdev/rescript-pulumi-pulumi/src/Output.res.mjs";
|
|
6
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
6
|
import * as Pulumi from "@pulumi/pulumi";
|
|
8
7
|
import * as Lambda$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/Lambda/Lambda.res.mjs";
|
|
9
8
|
import * as AWS$ReventlessAws from "../AWS.res.mjs";
|
|
@@ -93,7 +92,7 @@ function make(api, stores, releaseWindowSecondsOpt, nameOpt, opts) {
|
|
|
93
92
|
Util_Bundle$ReventlessAws.resolvePackageRoot(undefined, "@reventlessdev/reventless-aws")
|
|
94
93
|
]]);
|
|
95
94
|
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Upload/Upload_Presign_S3_Ops.res.mjs", packageDirs, undefined, false);
|
|
96
|
-
let layers =
|
|
95
|
+
let layers = Lambda$PulumiAws.reventlessLayers();
|
|
97
96
|
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name + "Lambda", undefined, AWS_Tags$ReventlessAws.make(name + "LambdaLogGroup", "Platform", "Logs", "Platform", undefined, undefined, undefined, undefined), opts$1, undefined);
|
|
98
97
|
let lambda = new (Aws.lambda.Function)(name + "Lambda", {
|
|
99
98
|
handler: "index.handler",
|
|
@@ -23,6 +23,8 @@ open PulumiAws
|
|
|
23
23
|
let defaultDataSource = "Esri"
|
|
24
24
|
let defaultIntendedUse = "SingleUse"
|
|
25
25
|
|
|
26
|
+
let physicalName = (~name: string, ~stack: string): string => `${name}-${stack}`
|
|
27
|
+
|
|
26
28
|
/** Create a place index with framework attribution tags and config-driven
|
|
27
29
|
provider/retention settings. */
|
|
28
30
|
let make = (
|
|
@@ -35,7 +37,9 @@ let make = (
|
|
|
35
37
|
let index = Location.PlaceIndex.make(
|
|
36
38
|
~name,
|
|
37
39
|
~args={
|
|
38
|
-
|
|
40
|
+
// Stack-scoped: an index name is unique per account and region, so two
|
|
41
|
+
// stacks of one app in the same place would otherwise collide.
|
|
42
|
+
indexName: Pulumi.Input.make(physicalName(~name, ~stack=Pulumi.Pulumi.getStackName())),
|
|
39
43
|
dataSource: Pulumi.Input.make(dataSource),
|
|
40
44
|
dataSourceConfiguration: Pulumi.Input.make({
|
|
41
45
|
Location.PlaceIndex.intendedUse: Pulumi.Input.make(intendedUse),
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Aws from "@pulumi/aws";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Pulumi from "@pulumi/pulumi";
|
|
5
6
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
6
7
|
import * as AWS_Tags$ReventlessAws from "../adapter/AWS_Tags.res.mjs";
|
|
7
8
|
import * as Util_LocalConfig$ReventlessAws from "../util/Util_LocalConfig.res.mjs";
|
|
@@ -10,11 +11,15 @@ let defaultDataSource = "Esri";
|
|
|
10
11
|
|
|
11
12
|
let defaultIntendedUse = "SingleUse";
|
|
12
13
|
|
|
14
|
+
function physicalName(name, stack) {
|
|
15
|
+
return name + `-` + stack;
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
function make(name, opts) {
|
|
14
19
|
let dataSource = Stdlib_Option.getOr(Util_LocalConfig$ReventlessAws.get("geocoderDataSource"), defaultDataSource);
|
|
15
20
|
let intendedUse = Stdlib_Option.getOr(Util_LocalConfig$ReventlessAws.get("geocoderIntendedUse"), defaultIntendedUse);
|
|
16
21
|
let index = new (Aws.location.PlaceIndex)(name, {
|
|
17
|
-
indexName: name,
|
|
22
|
+
indexName: physicalName(name, Pulumi.getStack()),
|
|
18
23
|
dataSource: dataSource,
|
|
19
24
|
dataSourceConfiguration: {
|
|
20
25
|
intendedUse: intendedUse
|
|
@@ -32,6 +37,7 @@ function make(name, opts) {
|
|
|
32
37
|
export {
|
|
33
38
|
defaultDataSource,
|
|
34
39
|
defaultIntendedUse,
|
|
40
|
+
physicalName,
|
|
35
41
|
make,
|
|
36
42
|
}
|
|
37
43
|
/* @pulumi/aws Not a pure module */
|