@reventlessdev/reventless-aws 3.0.0-alpha.219 → 3.0.0-alpha.221
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 +18 -0
- package/package.json +8 -8
- package/src/Platform.res.mjs +4 -0
- package/src/Platform_Stack.res +6 -0
- package/src/Platform_Stack.res.mjs +3 -1
- package/src/adapter/AWS_Tags.res +127 -12
- package/src/adapter/AWS_Tags.res.mjs +58 -17
- package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +26 -1
- package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res.mjs +12 -1
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +13 -1
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +3 -4
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +13 -1
- package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +3 -4
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +12 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res.mjs +4 -2
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +6 -0
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res.mjs +2 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res.mjs +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res.mjs +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res.mjs +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +2 -2
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res.mjs +2 -2
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +1 -0
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res.mjs +1 -1
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +1 -1
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res.mjs +1 -2
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +1 -1
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res.mjs +1 -1
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +2 -2
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res.mjs +2 -2
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +2 -2
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res.mjs +2 -2
- package/src/adapter/EventLog/EventLogStorage.res +3 -3
- package/src/adapter/EventLog/EventLogStorage.res.mjs +3 -3
- package/src/adapter/EventLog/EventLogStorage_DynamoDb.res +2 -2
- package/src/adapter/EventLog/EventLogStorage_DynamoDb.res.mjs +2 -2
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +2 -2
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res.mjs +2 -2
- package/src/adapter/EventLog/EventLogStorage_Postgres.res +1 -1
- package/src/adapter/EventLog/EventLogStorage_Postgres.res.mjs +1 -1
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +7 -1
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +2 -2
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +1 -1
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res.mjs +1 -1
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +2 -2
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res.mjs +2 -2
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +2 -2
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res.mjs +2 -2
- package/src/adapter/Mcp/MCP_Lambda.res.mjs +1 -1
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +7 -0
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res.mjs +4 -2
- package/src/adapter/Postgres/PgMigration_Builder.res +1 -0
- package/src/adapter/Postgres/PgMigration_Builder.res.mjs +1 -1
- package/src/adapter/QueryDb/PgQueryResolver_Builder.res +7 -0
- package/src/adapter/QueryDb/PgQueryResolver_Builder.res.mjs +4 -2
- package/src/adapter/QueryDb/QueryDbStorage.res +6 -6
- package/src/adapter/QueryDb/QueryDbStorage.res.mjs +6 -6
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +2 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res.mjs +2 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +2 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res.mjs +2 -2
- package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +1 -1
- package/src/adapter/QueryDb/QueryDbStorage_Postgres.res.mjs +1 -1
- package/src/adapter/Runtime/AdminEventCollectorEntryPoint.mjs +24 -41
- package/src/adapter/Runtime/AggregateEntryPoint.mjs +52 -45
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +19 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res.mjs +8 -5
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +19 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res.mjs +8 -5
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +9 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res.mjs +4 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +9 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res.mjs +4 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +9 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res.mjs +4 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +9 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res.mjs +4 -2
- package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +36 -22
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +1 -0
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +1 -1
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +39 -42
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +7 -1
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res.mjs +4 -2
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +19 -1
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res.mjs +5 -2
- package/src/adapter/Runtime/EventMapperEntryPoint.mjs +25 -23
- package/src/adapter/Runtime/ExtensionPointEntryPoint.mjs +25 -41
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +1 -0
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res.mjs +1 -1
- package/src/adapter/Runtime/HandlerFactoryHelpers.mjs +126 -0
- package/src/adapter/Runtime/PluginExtensionPointEntryPoint.mjs +24 -41
- package/src/adapter/Runtime/ReadModelEntryPoint.mjs +33 -24
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +52 -2
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +25 -7
- package/src/adapter/Runtime/SideEffectEntryPoint.mjs +25 -24
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +9 -1
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res.mjs +4 -2
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +1 -0
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res.mjs +1 -1
- package/src/adapter/Runtime/StateViewSliceEntryPoint.mjs +26 -21
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +2 -1
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res.mjs +2 -2
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +1 -0
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res.mjs +1 -1
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +12 -0
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res.mjs +4 -2
- package/src/adapter/StateTopic/StateTopic_AppSync.res +7 -1
- package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +2 -2
- package/src/adapter/Task/TaskBucket_S3.res +1 -0
- package/src/adapter/Task/TaskBucket_S3.res.mjs +7 -1
- package/src/components/Aggregate_Builder_Micro.res.mjs +2 -0
- package/src/components/Aggregate_Builder_NoResolver.res.mjs +2 -0
- package/src/components/Aggregate_Builder_PerAggregate.res.mjs +2 -0
- package/src/components/Aggregate_Builder_Single.res.mjs +2 -0
- package/src/components/Aggregate_Builder_Single_Async.res.mjs +2 -0
- package/src/components/Api/AppSync_Adapter.res +12 -0
- package/src/components/Api/AppSync_Adapter.res.mjs +6 -2
- package/src/components/Api/AppSync_MergedApi.res +12 -0
- package/src/components/Api/AppSync_MergedApi.res.mjs +5 -2
- package/src/components/AutomationSlice_Builder.res.mjs +2 -0
- package/src/components/ExtensionPoint_Builder.res.mjs +2 -0
- package/src/components/ForeignReadModel_Builder.res.mjs +4 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +2 -0
- package/src/components/Plugin.res.mjs +2 -0
- package/src/components/ReadModel_Builder_NoResolver.res.mjs +2 -0
- package/src/components/ReadModel_Builder_NoResolver_Stream.res.mjs +2 -0
- package/src/components/ReadModel_Builder_PerReadModel.res.mjs +2 -0
- package/src/components/ReadModel_Builder_Single.res.mjs +2 -0
- package/src/components/ReadModel_Builder_Single_Stream.res.mjs +2 -0
- package/src/components/SideEffectHandler_PerSideEffectHandler.res.mjs +6 -0
- package/src/components/SideEffectHandler_Single.res.mjs +4 -0
- package/src/components/StateViewSlice_Builder.res.mjs +2 -0
- package/src/components/StateViewSlice_Builder_Stream.res.mjs +2 -0
- package/src/components/Task_Builder_PerBucket.res.mjs +4 -0
- package/src/components/Vpc.res +10 -1
- package/src/components/Vpc.res.mjs +3 -1
- package/src/plugin/cloner/ClonerRunner_Fargate.res +26 -1
- package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +9 -6
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +6 -0
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res.mjs +4 -1
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +1 -0
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res.mjs +1 -1
- package/src/plugin/runtime/PluginRuntime_Builder.res +2 -0
- package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +2 -2
- package/src/plugin/stack/Plugin_ExtensionPoint_Builder.res.mjs +4 -0
- package/src/plugin/stack/Plugin_Stack.res +26 -1
- package/src/plugin/stack/Plugin_Stack.res.mjs +8 -3
- package/src/util/Util_CognitoGroupUser.res +6 -0
- package/src/util/Util_CognitoGroupUser.res.mjs +3 -1
- package/src/util/Util_DeadLetterQueue.res +8 -2
- package/src/util/Util_DeadLetterQueue.res.mjs +3 -4
- package/src/util/Util_LogAttribution.res +31 -0
- package/src/util/Util_LogAttribution.res.mjs +27 -0
- package/tests/AWS_TagsTest.res +236 -0
- package/tests/AWS_TagsTest.res.mjs +153 -0
- package/tests/AppSync_SourceApiAssociation_RetryingTest.res +26 -0
- package/tests/AppSync_SourceApiAssociation_RetryingTest.res.mjs +20 -0
- package/tests/HandlerFactoryDispatchTest.res +190 -0
- package/tests/HandlerFactoryDispatchTest.res.mjs +135 -0
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res +5 -3
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res.mjs +5 -3
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Aws from "@pulumi/aws";
|
|
4
4
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
5
|
+
import * as AWS_Tags$ReventlessAws from "../adapter/AWS_Tags.res.mjs";
|
|
5
6
|
import * as PolicyDocument$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/IAM/PolicyDocument.res.mjs";
|
|
6
7
|
|
|
7
8
|
function addUserGroup(name, userPoolId) {
|
|
@@ -21,7 +22,8 @@ function makeAddRemoveUserToGroupPolicy(name, userPoolArn, opts) {
|
|
|
21
22
|
"cognito-idp:AdminRemoveUserFromGroup"
|
|
22
23
|
],
|
|
23
24
|
Resource: userPoolArn
|
|
24
|
-
}]))
|
|
25
|
+
}])),
|
|
26
|
+
tags: AWS_Tags$ReventlessAws.make(name + "AddRemoveUserToGroup", "Platform", "Identity", "Platform", undefined, undefined, undefined, undefined)
|
|
25
27
|
}, opts !== undefined ? Primitive_option.valFromOption(opts) : undefined));
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -26,6 +26,12 @@ let opts = {Pulumi.CustomResourceOptions.parent: queue->PulumiAws.SQS.Queue.toRe
|
|
|
26
26
|
let lambdaRole = IAM.Role.makeWithDefaultPolicy(
|
|
27
27
|
~name,
|
|
28
28
|
~servicePrincipal=AWS.Lambda.principal->Pulumi.Output.make,
|
|
29
|
+
~tags=AWS.Tags.make(
|
|
30
|
+
~name,
|
|
31
|
+
~kind=ReventlessCore.ComponentType.Plugin,
|
|
32
|
+
~role=Identity,
|
|
33
|
+
~scope=Plugin,
|
|
34
|
+
),
|
|
29
35
|
~opts,
|
|
30
36
|
)
|
|
31
37
|
|
|
@@ -58,7 +64,7 @@ let handler = Lambda.Function.make(
|
|
|
58
64
|
memorySize: 128->Pulumi.Input.make,
|
|
59
65
|
timeout: 30->Pulumi.Input.make,
|
|
60
66
|
layers,
|
|
61
|
-
tags: AWS.Tags.make(~name, ReventlessCore.
|
|
67
|
+
tags: AWS.Tags.make(~name, ~kind=ReventlessCore.ComponentType.Plugin, ~role=DeadLetter, ~scope=Plugin),
|
|
62
68
|
environment: (
|
|
63
69
|
{
|
|
64
70
|
Lambda.Function.variables: Dict.fromArray([
|
|
@@ -77,7 +83,7 @@ ReventlessCore.Monitoring.notify(
|
|
|
77
83
|
~name,
|
|
78
84
|
~component=Util_Lambda.functionToResource(
|
|
79
85
|
handler,
|
|
80
|
-
~tags=AWS.Tags.make(~name, ReventlessCore.
|
|
86
|
+
~tags=AWS.Tags.make(~name, ~kind=ReventlessCore.ComponentType.Plugin, ~role=DeadLetter, ~scope=Plugin)->Pulumi.Output.fromInput,
|
|
81
87
|
),
|
|
82
88
|
)
|
|
83
89
|
|
|
@@ -11,7 +11,6 @@ import * as PolicyDocument$PulumiAws from "@reventlessdev/rescript-pulumi-aws/sr
|
|
|
11
11
|
import * as Monitoring$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/Monitoring/Monitoring.res.mjs";
|
|
12
12
|
import * as Util_Bundle$ReventlessAws from "./Util_Bundle.res.mjs";
|
|
13
13
|
import * as Util_Lambda$ReventlessAws from "./Util_Lambda.res.mjs";
|
|
14
|
-
import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
|
|
15
14
|
import * as Util_EventSourceMapping$ReventlessAws from "./Util_EventSourceMapping.res.mjs";
|
|
16
15
|
|
|
17
16
|
let name = "DeadLetterQueue";
|
|
@@ -36,7 +35,7 @@ let opts = {
|
|
|
36
35
|
parent: opts_parent
|
|
37
36
|
};
|
|
38
37
|
|
|
39
|
-
let lambdaRole = IAM$PulumiAws.Role.makeWithDefaultPolicy(name, Pulumi.output(AWS$ReventlessAws.Lambda.principal), opts);
|
|
38
|
+
let lambdaRole = IAM$PulumiAws.Role.makeWithDefaultPolicy(name, Pulumi.output(AWS$ReventlessAws.Lambda.principal), AWS_Tags$ReventlessAws.make(name, "Plugin", "Identity", "Plugin", undefined, undefined, undefined, undefined), opts);
|
|
40
39
|
|
|
41
40
|
let entryPointCode = `export const handler = async (event) => {
|
|
42
41
|
console.error("DEAD LETTER ITEM:", JSON.stringify(event));
|
|
@@ -60,7 +59,7 @@ let handler = new (Aws.lambda.Function)(name, {
|
|
|
60
59
|
memorySize: 128,
|
|
61
60
|
timeout: 30,
|
|
62
61
|
layers: layers,
|
|
63
|
-
tags: AWS_Tags$ReventlessAws.make(name,
|
|
62
|
+
tags: AWS_Tags$ReventlessAws.make(name, "Plugin", "DeadLetter", "Plugin", undefined, undefined, undefined, undefined),
|
|
64
63
|
environment: {
|
|
65
64
|
variables: Object.fromEntries([[
|
|
66
65
|
"Environment",
|
|
@@ -70,7 +69,7 @@ let handler = new (Aws.lambda.Function)(name, {
|
|
|
70
69
|
sourceCodeHash: sourceCodeHash
|
|
71
70
|
}, opts);
|
|
72
71
|
|
|
73
|
-
Monitoring$ReventlessCore.notify("DeadLetterSink", name, Util_Lambda$ReventlessAws.functionToResource(AWS_Tags$ReventlessAws.make(name,
|
|
72
|
+
Monitoring$ReventlessCore.notify("DeadLetterSink", name, Util_Lambda$ReventlessAws.functionToResource(AWS_Tags$ReventlessAws.make(name, "Plugin", "DeadLetter", "Plugin", undefined, undefined, undefined, undefined), handler));
|
|
74
73
|
|
|
75
74
|
let lambda = Pulumi.output(handler);
|
|
76
75
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Deploy-time log attribution baked into HANDLER_CONFIG.
|
|
2
|
+
//
|
|
3
|
+
// The deployed entry points annotate each invocation with `comp` and `plugin`
|
|
4
|
+
// (HandlerFactoryHelpers.runEffect). `comp` a shell can usually derive itself
|
|
5
|
+
// from the spec name it loads; `plugin` it cannot — resolution goes through
|
|
6
|
+
// LogPrefix's component→plugin registry, which `Plugin_Builder.construct`
|
|
7
|
+
// populates at **deploy** time and which is empty inside a Lambda. And the
|
|
8
|
+
// Lambda-name fallback (`derivePluginFromLambdaName`) only works for Lambdas
|
|
9
|
+
// named `<Plugin>Plugin<Suffix>`: it yields nothing for a shared multi-plugin
|
|
10
|
+
// Lambda (`AllAggregatesCmdHandler`, `AllReadModels`) or a per-component one
|
|
11
|
+
// (`<Aggregate>Aggr`) — exactly the cases where the field matters most.
|
|
12
|
+
//
|
|
13
|
+
// So resolve it here, where the registry exists, and ship it in the config.
|
|
14
|
+
// See docs/plans/entrypoint-dispatch-parity-and-latency-fields.md.
|
|
15
|
+
|
|
16
|
+
/** `,"plugin":"<Name>"` for a HANDLER_CONFIG entry, or `""` when the comp
|
|
17
|
+
resolves to no plugin (the shell then falls back to the Lambda name). */
|
|
18
|
+
let pluginFragment = (~comp: string): string =>
|
|
19
|
+
switch ReventlessCore.Logger.resolvePlugin(~comp, ()) {
|
|
20
|
+
| Some(plugin) => `,"plugin":${plugin->JSON.Encode.string->JSON.stringify}`
|
|
21
|
+
| None => ""
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** `,"comp":"<Kind(Name)>"` for a HANDLER_CONFIG entry. For the shells that
|
|
25
|
+
cannot name the element themselves — a read model or side-effect handler is
|
|
26
|
+
known to its shell only by module path, while the aggregate/slice shells read
|
|
27
|
+
the name off the spec they load. */
|
|
28
|
+
let compFragment = (~comp: string): string => `,"comp":${comp->JSON.Encode.string->JSON.stringify}`
|
|
29
|
+
|
|
30
|
+
/** Both fragments, in the order the entry points expect. */
|
|
31
|
+
let fragments = (~comp: string): string => compFragment(~comp) ++ pluginFragment(~comp)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Logger$ReventlessCore from "@reventlessdev/reventless-core/src/util/Logger.res.mjs";
|
|
4
|
+
|
|
5
|
+
function pluginFragment(comp) {
|
|
6
|
+
let plugin = Logger$ReventlessCore.resolvePlugin(comp, undefined);
|
|
7
|
+
if (plugin !== undefined) {
|
|
8
|
+
return `,"plugin":` + JSON.stringify(plugin);
|
|
9
|
+
} else {
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function compFragment(comp) {
|
|
15
|
+
return `,"comp":` + JSON.stringify(comp);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function fragments(comp) {
|
|
19
|
+
return compFragment(comp) + pluginFragment(comp);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
pluginFragment,
|
|
24
|
+
compFragment,
|
|
25
|
+
fragments,
|
|
26
|
+
}
|
|
27
|
+
/* Logger-ReventlessCore Not a pure module */
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
open JestGlobals
|
|
2
|
+
|
|
3
|
+
// Guards the resource-attribution tag schema. A downstream inventory answers
|
|
4
|
+
// "which model component owns this resource, in what role, at what scope" purely
|
|
5
|
+
// from these keys, so the key set and its namespacing are load-bearing.
|
|
6
|
+
// See docs/plans/resource-attribution-tag-schema.md.
|
|
7
|
+
|
|
8
|
+
module Attribution = ReventlessCore.ResourceAttribution
|
|
9
|
+
|
|
10
|
+
// Pulumi.Input.make is %identity, so the tags value is the underlying dict.
|
|
11
|
+
external toDict: Pulumi.Input.t<dict<string>> => dict<string> = "%identity"
|
|
12
|
+
|
|
13
|
+
let tagsFor = (
|
|
14
|
+
~name,
|
|
15
|
+
~kind,
|
|
16
|
+
~role,
|
|
17
|
+
~scope: Attribution.Scope.t=Component,
|
|
18
|
+
~component=?,
|
|
19
|
+
~plugin=?,
|
|
20
|
+
~platform=?,
|
|
21
|
+
) =>
|
|
22
|
+
AWS_Tags.make(~name, ~kind, ~role, ~scope, ~component?, ~plugin?, ~platform?)->toDict
|
|
23
|
+
|
|
24
|
+
describe("AWS_Tags — key set", () => {
|
|
25
|
+
testSync("emits every reventless: fact exactly once, plus the bare Name", () => {
|
|
26
|
+
let keys =
|
|
27
|
+
tagsFor(
|
|
28
|
+
~name="ProductsQueryDb",
|
|
29
|
+
~kind=ReventlessCore.ComponentType.ReadModel,
|
|
30
|
+
~role=QueryDb,
|
|
31
|
+
~plugin="Catalog",
|
|
32
|
+
~platform="online-shop",
|
|
33
|
+
)
|
|
34
|
+
->Dict.keysToArray
|
|
35
|
+
->Array.toSorted(String.compare)
|
|
36
|
+
expect(keys)->toEqual([
|
|
37
|
+
"Name",
|
|
38
|
+
"reventless:component",
|
|
39
|
+
"reventless:environment",
|
|
40
|
+
"reventless:kind",
|
|
41
|
+
"reventless:platform",
|
|
42
|
+
"reventless:plugin",
|
|
43
|
+
"reventless:role",
|
|
44
|
+
"reventless:scope",
|
|
45
|
+
])
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
testSync("the dropped bare duplicates stay dropped", () => {
|
|
49
|
+
// `Type` and `Plugin` were exact duplicates of reventless:kind / :plugin, and
|
|
50
|
+
// `Environment` was a framework fact wearing an un-namespaced name. One
|
|
51
|
+
// authoritative name per fact — `Name` is the sole bare key, because the AWS
|
|
52
|
+
// console reads that literal spelling for its resource-name column.
|
|
53
|
+
let tags = tagsFor(~name="Products", ~kind=ReventlessCore.ComponentType.ReadModel, ~role=QueryDb)
|
|
54
|
+
expect(tags->Dict.get("Type"))->toEqual(None)
|
|
55
|
+
expect(tags->Dict.get("Plugin"))->toEqual(None)
|
|
56
|
+
expect(tags->Dict.get("Environment"))->toEqual(None)
|
|
57
|
+
expect(tags->Dict.get("Name"))->toEqual(Some("Products"))
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe("AWS_Tags — role and kind are independent facts", () => {
|
|
62
|
+
testSync("one component kind spans several piece roles", () => {
|
|
63
|
+
let kind = ReventlessCore.ComponentType.Aggregate
|
|
64
|
+
let eventLog = tagsFor(~name="OrderEventLog", ~kind, ~role=EventLog)
|
|
65
|
+
let commandTopic = tagsFor(~name="OrderCmdTopic", ~kind, ~role=CommandTopic)
|
|
66
|
+
expect(eventLog->Dict.get("reventless:kind"))->toEqual(Some("Aggregate"))
|
|
67
|
+
expect(commandTopic->Dict.get("reventless:kind"))->toEqual(Some("Aggregate"))
|
|
68
|
+
expect(eventLog->Dict.get("reventless:role"))->toEqual(Some("EventLog"))
|
|
69
|
+
expect(commandTopic->Dict.get("reventless:role"))->toEqual(Some("CommandTopic"))
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
testSync("one piece role spans several component kinds — the Lambda mis-tag", () => {
|
|
73
|
+
// Regression guard for the defect this schema exists to fix: every runtime
|
|
74
|
+
// Lambda used to report kind=role=CommandTopic regardless of what it ran.
|
|
75
|
+
let aggregate = tagsFor(
|
|
76
|
+
~name="AllAggregatesCmdHandler",
|
|
77
|
+
~kind=ReventlessCore.ComponentType.Aggregate,
|
|
78
|
+
~role=Runtime,
|
|
79
|
+
)
|
|
80
|
+
let projection = tagsFor(
|
|
81
|
+
~name="ProductsProjection",
|
|
82
|
+
~kind=ReventlessCore.ComponentType.StateViewSlice,
|
|
83
|
+
~role=Runtime,
|
|
84
|
+
)
|
|
85
|
+
expect(aggregate->Dict.get("reventless:role"))->toEqual(Some("Runtime"))
|
|
86
|
+
expect(projection->Dict.get("reventless:role"))->toEqual(Some("Runtime"))
|
|
87
|
+
expect(aggregate->Dict.get("reventless:kind"))->toEqual(Some("Aggregate"))
|
|
88
|
+
expect(projection->Dict.get("reventless:kind"))->toEqual(Some("StateViewSlice"))
|
|
89
|
+
// …and neither reports the old hardcoded lie.
|
|
90
|
+
expect(aggregate->Dict.get("reventless:kind") == Some("CommandTopic"))->toBe(false)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe("AWS_Tags — owner overrides the piece adapter's own kind", () => {
|
|
95
|
+
// The piece adapters pass their OWN ComponentType as ~kind, which names the
|
|
96
|
+
// piece and so collapses onto ~role. A QueryDb is instantiated by six different
|
|
97
|
+
// component kinds, so without the owner a reader cannot tell a ReadModel's
|
|
98
|
+
// table from a StateViewSlice's. See docs/plans/resource-attribution-owner-kind.md.
|
|
99
|
+
let queryDbTagsFor = (~owner=?) =>
|
|
100
|
+
AWS_Tags.make(
|
|
101
|
+
~name="ProductsQueryDb",
|
|
102
|
+
~kind=ReventlessCore.ComponentType.QueryDb,
|
|
103
|
+
~role=QueryDb,
|
|
104
|
+
~owner?,
|
|
105
|
+
)->toDict
|
|
106
|
+
|
|
107
|
+
testSync("without an owner, kind still names the piece", () => {
|
|
108
|
+
let tags = queryDbTagsFor()
|
|
109
|
+
expect(tags->Dict.get("reventless:kind"))->toEqual(Some("QueryDB"))
|
|
110
|
+
expect(tags->Dict.get("reventless:role"))->toEqual(Some("QueryDb"))
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
testSync("two QueryDb tables under different owners differ in kind", () => {
|
|
114
|
+
let readModel = queryDbTagsFor(
|
|
115
|
+
~owner={kind: ReventlessCore.ComponentType.ReadModel, name: "Products"},
|
|
116
|
+
)
|
|
117
|
+
let stateView = queryDbTagsFor(
|
|
118
|
+
~owner={kind: ReventlessCore.ComponentType.StateViewSlice, name: "ProductAvailability"},
|
|
119
|
+
)
|
|
120
|
+
expect(readModel->Dict.get("reventless:kind"))->toEqual(Some("ReadModel"))
|
|
121
|
+
expect(stateView->Dict.get("reventless:kind"))->toEqual(Some("StateViewSlice"))
|
|
122
|
+
// …while both still report the same piece role.
|
|
123
|
+
expect(readModel->Dict.get("reventless:role"))->toEqual(Some("QueryDb"))
|
|
124
|
+
expect(stateView->Dict.get("reventless:role"))->toEqual(Some("QueryDb"))
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
testSync("the owner also supplies the component stem, not the resource name", () => {
|
|
128
|
+
let tags = queryDbTagsFor(
|
|
129
|
+
~owner={kind: ReventlessCore.ComponentType.ReadModel, name: "Products"},
|
|
130
|
+
)
|
|
131
|
+
expect(tags->Dict.get("Name"))->toEqual(Some("ProductsQueryDb"))
|
|
132
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some("Products"))
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
testSync("a Plugin-kinded owner attributes substrate to the plugin", () => {
|
|
136
|
+
// A plugin IS a model element, so shared substrate is owned by it rather than
|
|
137
|
+
// by nothing. The owner implies plugin scope even though the piece adapter
|
|
138
|
+
// passed no ~scope, and it names the plugin.
|
|
139
|
+
let tags =
|
|
140
|
+
AWS_Tags.make(
|
|
141
|
+
~name="OrderingDcbEventTopic",
|
|
142
|
+
~kind=ReventlessCore.ComponentType.EventTopic,
|
|
143
|
+
~role=EventTopic,
|
|
144
|
+
~owner={kind: ReventlessCore.ComponentType.Plugin, name: "Ordering"},
|
|
145
|
+
)->toDict
|
|
146
|
+
expect(tags->Dict.get("reventless:kind"))->toEqual(Some("Plugin"))
|
|
147
|
+
expect(tags->Dict.get("reventless:scope"))->toEqual(Some("plugin"))
|
|
148
|
+
expect(tags->Dict.get("reventless:plugin"))->toEqual(Some("Ordering"))
|
|
149
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some(""))
|
|
150
|
+
// …and the piece it plays is still legible.
|
|
151
|
+
expect(tags->Dict.get("reventless:role"))->toEqual(Some("EventTopic"))
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
testSync("an owner does not leak a component onto plugin substrate", () => {
|
|
155
|
+
let tags =
|
|
156
|
+
AWS_Tags.make(
|
|
157
|
+
~name="OrderingDcbEventLog",
|
|
158
|
+
~kind=ReventlessCore.ComponentType.DcbEventLog,
|
|
159
|
+
~role=DcbEventLog,
|
|
160
|
+
~scope=Plugin,
|
|
161
|
+
~owner={kind: ReventlessCore.ComponentType.Aggregate, name: "Order"},
|
|
162
|
+
)->toDict
|
|
163
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some(""))
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
describe("AWS_Tags — scope", () => {
|
|
168
|
+
testSync("component scope names the component, defaulting to the resource name", () => {
|
|
169
|
+
let tags = tagsFor(~name="Products", ~kind=ReventlessCore.ComponentType.ReadModel, ~role=QueryDb)
|
|
170
|
+
expect(tags->Dict.get("reventless:scope"))->toEqual(Some("component"))
|
|
171
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some("Products"))
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
testSync("an explicit component stem survives a suffixed resource name", () => {
|
|
175
|
+
let tags = tagsFor(
|
|
176
|
+
~name="ProductsStateTopic",
|
|
177
|
+
~kind=ReventlessCore.ComponentType.ReadModel,
|
|
178
|
+
~role=StateTopic,
|
|
179
|
+
~component="Products",
|
|
180
|
+
)
|
|
181
|
+
expect(tags->Dict.get("Name"))->toEqual(Some("ProductsStateTopic"))
|
|
182
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some("Products"))
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
testSync("plugin substrate carries no component, but keeps its plugin", () => {
|
|
186
|
+
let tags = tagsFor(
|
|
187
|
+
~name="OrderingDcbEventLog",
|
|
188
|
+
~kind=ReventlessCore.ComponentType.DcbEventLog,
|
|
189
|
+
~role=DcbEventLog,
|
|
190
|
+
~scope=Plugin,
|
|
191
|
+
~plugin="Ordering",
|
|
192
|
+
)
|
|
193
|
+
expect(tags->Dict.get("reventless:scope"))->toEqual(Some("plugin"))
|
|
194
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some(""))
|
|
195
|
+
expect(tags->Dict.get("reventless:plugin"))->toEqual(Some("Ordering"))
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
testSync("platform substrate carries neither component nor plugin", () => {
|
|
199
|
+
let tags = tagsFor(
|
|
200
|
+
~name="UIFragmentsLambda",
|
|
201
|
+
~kind=ReventlessCore.ComponentType.ReadModel,
|
|
202
|
+
~role=Runtime,
|
|
203
|
+
~scope=Platform,
|
|
204
|
+
~plugin="Ordering",
|
|
205
|
+
~platform="online-shop",
|
|
206
|
+
)
|
|
207
|
+
expect(tags->Dict.get("reventless:scope"))->toEqual(Some("platform"))
|
|
208
|
+
expect(tags->Dict.get("reventless:component"))->toEqual(Some(""))
|
|
209
|
+
expect(tags->Dict.get("reventless:plugin"))->toEqual(Some(""))
|
|
210
|
+
expect(tags->Dict.get("reventless:platform"))->toEqual(Some("online-shop"))
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
describe("AWS_Tags — plugin attribution", () => {
|
|
215
|
+
testSync("falls back to the ambient plugin published by Plugin_Builder", () => {
|
|
216
|
+
// Adapters sit far below the builder that knows the plugin name, so the
|
|
217
|
+
// ambient context is how a DynamoDB table learns it belongs to Ordering.
|
|
218
|
+
let previous = Attribution.enter(~platform="online-shop", ~plugin="Ordering")
|
|
219
|
+
let tags = tagsFor(~name="OrderEventLog", ~kind=ReventlessCore.ComponentType.Aggregate, ~role=EventLog)
|
|
220
|
+
Attribution.restore(previous)
|
|
221
|
+
expect(tags->Dict.get("reventless:plugin"))->toEqual(Some("Ordering"))
|
|
222
|
+
expect(tags->Dict.get("reventless:platform"))->toEqual(Some("online-shop"))
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
testSync("an explicit plugin beats the ambient one", () => {
|
|
226
|
+
let previous = Attribution.enter(~platform="online-shop", ~plugin="Ordering")
|
|
227
|
+
let tags = tagsFor(
|
|
228
|
+
~name="CatalogTable",
|
|
229
|
+
~kind=ReventlessCore.ComponentType.ReadModel,
|
|
230
|
+
~role=QueryDb,
|
|
231
|
+
~plugin="Catalog",
|
|
232
|
+
)
|
|
233
|
+
Attribution.restore(previous)
|
|
234
|
+
expect(tags->Dict.get("reventless:plugin"))->toEqual(Some("Catalog"))
|
|
235
|
+
})
|
|
236
|
+
})
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
4
|
+
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
5
|
+
import * as AWS_Tags$ReventlessAws from "../src/adapter/AWS_Tags.res.mjs";
|
|
6
|
+
import * as ResourceAttribution$ReventlessCore from "@reventlessdev/reventless-core/src/ResourceAttribution.res.mjs";
|
|
7
|
+
|
|
8
|
+
function tagsFor(name, kind, role, scopeOpt, component, plugin, platform) {
|
|
9
|
+
let scope = scopeOpt !== undefined ? scopeOpt : "Component";
|
|
10
|
+
return AWS_Tags$ReventlessAws.make(name, kind, role, scope, component, undefined, plugin, platform);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
globalThis.describe("AWS_Tags — key set", () => {
|
|
14
|
+
globalThis.test("emits every reventless: fact exactly once, plus the bare Name", () => {
|
|
15
|
+
let keys = Object.keys(tagsFor("ProductsQueryDb", "ReadModel", "QueryDb", undefined, undefined, "Catalog", "online-shop")).toSorted(Primitive_string.compare);
|
|
16
|
+
globalThis.expect(keys).toEqual([
|
|
17
|
+
"Name",
|
|
18
|
+
"reventless:component",
|
|
19
|
+
"reventless:environment",
|
|
20
|
+
"reventless:kind",
|
|
21
|
+
"reventless:platform",
|
|
22
|
+
"reventless:plugin",
|
|
23
|
+
"reventless:role",
|
|
24
|
+
"reventless:scope"
|
|
25
|
+
]);
|
|
26
|
+
});
|
|
27
|
+
globalThis.test("the dropped bare duplicates stay dropped", () => {
|
|
28
|
+
let tags = tagsFor("Products", "ReadModel", "QueryDb", undefined, undefined, undefined, undefined);
|
|
29
|
+
globalThis.expect(tags["Type"]).toEqual(undefined);
|
|
30
|
+
globalThis.expect(tags["Plugin"]).toEqual(undefined);
|
|
31
|
+
globalThis.expect(tags["Environment"]).toEqual(undefined);
|
|
32
|
+
globalThis.expect(tags["Name"]).toEqual("Products");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
globalThis.describe("AWS_Tags — role and kind are independent facts", () => {
|
|
37
|
+
globalThis.test("one component kind spans several piece roles", () => {
|
|
38
|
+
let eventLog = tagsFor("OrderEventLog", "Aggregate", "EventLog", undefined, undefined, undefined, undefined);
|
|
39
|
+
let commandTopic = tagsFor("OrderCmdTopic", "Aggregate", "CommandTopic", undefined, undefined, undefined, undefined);
|
|
40
|
+
globalThis.expect(eventLog["reventless:kind"]).toEqual("Aggregate");
|
|
41
|
+
globalThis.expect(commandTopic["reventless:kind"]).toEqual("Aggregate");
|
|
42
|
+
globalThis.expect(eventLog["reventless:role"]).toEqual("EventLog");
|
|
43
|
+
globalThis.expect(commandTopic["reventless:role"]).toEqual("CommandTopic");
|
|
44
|
+
});
|
|
45
|
+
globalThis.test("one piece role spans several component kinds — the Lambda mis-tag", () => {
|
|
46
|
+
let aggregate = tagsFor("AllAggregatesCmdHandler", "Aggregate", "Runtime", undefined, undefined, undefined, undefined);
|
|
47
|
+
let projection = tagsFor("ProductsProjection", "StateViewSlice", "Runtime", undefined, undefined, undefined, undefined);
|
|
48
|
+
globalThis.expect(aggregate["reventless:role"]).toEqual("Runtime");
|
|
49
|
+
globalThis.expect(projection["reventless:role"]).toEqual("Runtime");
|
|
50
|
+
globalThis.expect(aggregate["reventless:kind"]).toEqual("Aggregate");
|
|
51
|
+
globalThis.expect(projection["reventless:kind"]).toEqual("StateViewSlice");
|
|
52
|
+
globalThis.expect(Primitive_object.equal(aggregate["reventless:kind"], "CommandTopic")).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
globalThis.describe("AWS_Tags — owner overrides the piece adapter's own kind", () => {
|
|
57
|
+
let queryDbTagsFor = owner => AWS_Tags$ReventlessAws.make("ProductsQueryDb", "QueryDb", "QueryDb", undefined, undefined, owner, undefined, undefined);
|
|
58
|
+
globalThis.test("without an owner, kind still names the piece", () => {
|
|
59
|
+
let tags = queryDbTagsFor(undefined);
|
|
60
|
+
globalThis.expect(tags["reventless:kind"]).toEqual("QueryDB");
|
|
61
|
+
globalThis.expect(tags["reventless:role"]).toEqual("QueryDb");
|
|
62
|
+
});
|
|
63
|
+
globalThis.test("two QueryDb tables under different owners differ in kind", () => {
|
|
64
|
+
let readModel = queryDbTagsFor({
|
|
65
|
+
kind: "ReadModel",
|
|
66
|
+
name: "Products"
|
|
67
|
+
});
|
|
68
|
+
let stateView = queryDbTagsFor({
|
|
69
|
+
kind: "StateViewSlice",
|
|
70
|
+
name: "ProductAvailability"
|
|
71
|
+
});
|
|
72
|
+
globalThis.expect(readModel["reventless:kind"]).toEqual("ReadModel");
|
|
73
|
+
globalThis.expect(stateView["reventless:kind"]).toEqual("StateViewSlice");
|
|
74
|
+
globalThis.expect(readModel["reventless:role"]).toEqual("QueryDb");
|
|
75
|
+
globalThis.expect(stateView["reventless:role"]).toEqual("QueryDb");
|
|
76
|
+
});
|
|
77
|
+
globalThis.test("the owner also supplies the component stem, not the resource name", () => {
|
|
78
|
+
let tags = queryDbTagsFor({
|
|
79
|
+
kind: "ReadModel",
|
|
80
|
+
name: "Products"
|
|
81
|
+
});
|
|
82
|
+
globalThis.expect(tags["Name"]).toEqual("ProductsQueryDb");
|
|
83
|
+
globalThis.expect(tags["reventless:component"]).toEqual("Products");
|
|
84
|
+
});
|
|
85
|
+
globalThis.test("a Plugin-kinded owner attributes substrate to the plugin", () => {
|
|
86
|
+
let tags = AWS_Tags$ReventlessAws.make("OrderingDcbEventTopic", "EventTopic", "EventTopic", undefined, undefined, {
|
|
87
|
+
kind: "Plugin",
|
|
88
|
+
name: "Ordering"
|
|
89
|
+
}, undefined, undefined);
|
|
90
|
+
globalThis.expect(tags["reventless:kind"]).toEqual("Plugin");
|
|
91
|
+
globalThis.expect(tags["reventless:scope"]).toEqual("plugin");
|
|
92
|
+
globalThis.expect(tags["reventless:plugin"]).toEqual("Ordering");
|
|
93
|
+
globalThis.expect(tags["reventless:component"]).toEqual("");
|
|
94
|
+
globalThis.expect(tags["reventless:role"]).toEqual("EventTopic");
|
|
95
|
+
});
|
|
96
|
+
globalThis.test("an owner does not leak a component onto plugin substrate", () => {
|
|
97
|
+
let tags = AWS_Tags$ReventlessAws.make("OrderingDcbEventLog", "DcbEventLog", "DcbEventLog", "Plugin", undefined, {
|
|
98
|
+
kind: "Aggregate",
|
|
99
|
+
name: "Order"
|
|
100
|
+
}, undefined, undefined);
|
|
101
|
+
globalThis.expect(tags["reventless:component"]).toEqual("");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
globalThis.describe("AWS_Tags — scope", () => {
|
|
106
|
+
globalThis.test("component scope names the component, defaulting to the resource name", () => {
|
|
107
|
+
let tags = tagsFor("Products", "ReadModel", "QueryDb", undefined, undefined, undefined, undefined);
|
|
108
|
+
globalThis.expect(tags["reventless:scope"]).toEqual("component");
|
|
109
|
+
globalThis.expect(tags["reventless:component"]).toEqual("Products");
|
|
110
|
+
});
|
|
111
|
+
globalThis.test("an explicit component stem survives a suffixed resource name", () => {
|
|
112
|
+
let tags = tagsFor("ProductsStateTopic", "ReadModel", "StateTopic", undefined, "Products", undefined, undefined);
|
|
113
|
+
globalThis.expect(tags["Name"]).toEqual("ProductsStateTopic");
|
|
114
|
+
globalThis.expect(tags["reventless:component"]).toEqual("Products");
|
|
115
|
+
});
|
|
116
|
+
globalThis.test("plugin substrate carries no component, but keeps its plugin", () => {
|
|
117
|
+
let tags = tagsFor("OrderingDcbEventLog", "DcbEventLog", "DcbEventLog", "Plugin", undefined, "Ordering", undefined);
|
|
118
|
+
globalThis.expect(tags["reventless:scope"]).toEqual("plugin");
|
|
119
|
+
globalThis.expect(tags["reventless:component"]).toEqual("");
|
|
120
|
+
globalThis.expect(tags["reventless:plugin"]).toEqual("Ordering");
|
|
121
|
+
});
|
|
122
|
+
globalThis.test("platform substrate carries neither component nor plugin", () => {
|
|
123
|
+
let tags = tagsFor("UIFragmentsLambda", "ReadModel", "Runtime", "Platform", undefined, "Ordering", "online-shop");
|
|
124
|
+
globalThis.expect(tags["reventless:scope"]).toEqual("platform");
|
|
125
|
+
globalThis.expect(tags["reventless:component"]).toEqual("");
|
|
126
|
+
globalThis.expect(tags["reventless:plugin"]).toEqual("");
|
|
127
|
+
globalThis.expect(tags["reventless:platform"]).toEqual("online-shop");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
globalThis.describe("AWS_Tags — plugin attribution", () => {
|
|
132
|
+
globalThis.test("falls back to the ambient plugin published by Plugin_Builder", () => {
|
|
133
|
+
let previous = ResourceAttribution$ReventlessCore.enter("online-shop", "Ordering");
|
|
134
|
+
let tags = tagsFor("OrderEventLog", "Aggregate", "EventLog", undefined, undefined, undefined, undefined);
|
|
135
|
+
ResourceAttribution$ReventlessCore.restore(previous);
|
|
136
|
+
globalThis.expect(tags["reventless:plugin"]).toEqual("Ordering");
|
|
137
|
+
globalThis.expect(tags["reventless:platform"]).toEqual("online-shop");
|
|
138
|
+
});
|
|
139
|
+
globalThis.test("an explicit plugin beats the ambient one", () => {
|
|
140
|
+
let previous = ResourceAttribution$ReventlessCore.enter("online-shop", "Ordering");
|
|
141
|
+
let tags = tagsFor("CatalogTable", "ReadModel", "QueryDb", undefined, undefined, "Catalog", undefined);
|
|
142
|
+
ResourceAttribution$ReventlessCore.restore(previous);
|
|
143
|
+
globalThis.expect(tags["reventless:plugin"]).toEqual("Catalog");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
let Attribution;
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
Attribution,
|
|
151
|
+
tagsFor,
|
|
152
|
+
}
|
|
153
|
+
/* Not a pure module */
|
|
@@ -110,3 +110,29 @@ describe("AppSync_SourceApiAssociation_Retrying.idsFromComposite", () => {
|
|
|
110
110
|
expect(Assoc.idsFromComposite("just-one-value")->Option.isNone)->toBe(true)
|
|
111
111
|
})
|
|
112
112
|
})
|
|
113
|
+
|
|
114
|
+
// pulumi.dynamic.Resource defines a resource property per KEY of the props
|
|
115
|
+
// object, so the output-only fields must be present (with an undefined value)
|
|
116
|
+
// or `association.associationId` is a bare `undefined` and the merge gate
|
|
117
|
+
// calls GetSourceApiAssociation without an id.
|
|
118
|
+
describe("AppSync_SourceApiAssociation_Retrying.resourcePropsOf", () => {
|
|
119
|
+
let keysOf: Assoc.resourceProps => array<string> = p => Object.keysToArray(Obj.magic(p))
|
|
120
|
+
let props = Assoc.resourcePropsOf({
|
|
121
|
+
mergedApiIdentifier: Obj.magic("merged-arn"),
|
|
122
|
+
sourceApiIdentifier: Obj.magic("src123"),
|
|
123
|
+
mergeType: Obj.magic("AUTO_MERGE"),
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
testSync("declares arn + associationId as output-only keys", () => {
|
|
127
|
+
expect(props->keysOf->Array.includes("arn"))->toBe(true)
|
|
128
|
+
expect(props->keysOf->Array.includes("associationId"))->toBe(true)
|
|
129
|
+
expect(props.arn->Nullable.toOption->Option.isNone)->toBe(true)
|
|
130
|
+
expect(props.associationId->Nullable.toOption->Option.isNone)->toBe(true)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
testSync("passes the three real inputs through", () => {
|
|
134
|
+
expect((props.mergedApiIdentifier->Obj.magic: string))->toBe("merged-arn")
|
|
135
|
+
expect((props.sourceApiIdentifier->Obj.magic: string))->toBe("src123")
|
|
136
|
+
expect((props.mergeType->Obj.magic: string))->toBe("AUTO_MERGE")
|
|
137
|
+
})
|
|
138
|
+
})
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as JestGlobals from "@reventlessdev/rescript-jest/src/JestGlobals.res.mjs";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
5
6
|
import * as AppSync_SourceApiAssociation_Retrying$ReventlessAws from "../src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res.mjs";
|
|
6
7
|
|
|
7
8
|
function mkErr(name, message) {
|
|
@@ -124,6 +125,25 @@ globalThis.describe("AppSync_SourceApiAssociation_Retrying.idsFromComposite", ()
|
|
|
124
125
|
});
|
|
125
126
|
});
|
|
126
127
|
|
|
128
|
+
globalThis.describe("AppSync_SourceApiAssociation_Retrying.resourcePropsOf", () => {
|
|
129
|
+
let props = AppSync_SourceApiAssociation_Retrying$ReventlessAws.resourcePropsOf({
|
|
130
|
+
mergedApiIdentifier: "merged-arn",
|
|
131
|
+
sourceApiIdentifier: "src123",
|
|
132
|
+
mergeType: "AUTO_MERGE"
|
|
133
|
+
});
|
|
134
|
+
globalThis.test("declares arn + associationId as output-only keys", () => {
|
|
135
|
+
globalThis.expect(Object.keys(props).includes("arn")).toBe(true);
|
|
136
|
+
globalThis.expect(Object.keys(props).includes("associationId")).toBe(true);
|
|
137
|
+
globalThis.expect(Stdlib_Option.isNone(Primitive_option.fromNullable(props.arn))).toBe(true);
|
|
138
|
+
globalThis.expect(Stdlib_Option.isNone(Primitive_option.fromNullable(props.associationId))).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
globalThis.test("passes the three real inputs through", () => {
|
|
141
|
+
globalThis.expect(props.mergedApiIdentifier).toBe("merged-arn");
|
|
142
|
+
globalThis.expect(props.sourceApiIdentifier).toBe("src123");
|
|
143
|
+
globalThis.expect(props.mergeType).toBe("AUTO_MERGE");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
127
147
|
let Assoc;
|
|
128
148
|
|
|
129
149
|
export {
|