@reventlessdev/reventless-aws 3.0.0-alpha.211 → 3.0.0-alpha.213

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 CHANGED
@@ -3,6 +3,27 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.213 (2026-07-15)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/reventless-aws
9
+
10
+
11
+
12
+
13
+
14
+ # 3.0.0-alpha.212 (2026-07-14)
15
+
16
+ ### Bug Fixes
17
+
18
+ * **aws:** create EC publishToAggregates SendMessage grants — cross-plugin extension→DCB publishes no longer AccessDenied ([c2126df](https://github.com/ReventlessDev/reventless-core/commit/c2126df0b9af4a79a980f2668ffc18a7760ef4c3))
19
+ * **aws:** create heartbeat SendMessage grant at top level; document the pulumi.all side-channel gotcha ([6ffa06a](https://github.com/ReventlessDev/reventless-core/commit/6ffa06ac87070af4027ba5753ac7c2cb216a76d0))
20
+ * **aws:** filter Internal read models from Platform_ComponentDefinitions ([fda1a81](https://github.com/ReventlessDev/reventless-core/commit/fda1a81f420f64bf4bdf3c988f84829719ffc0d1))
21
+ ### Features
22
+
23
+ * **core:** thread ~comp through Projection.handleAction for attributed action logging ([fa32d93](https://github.com/ReventlessDev/reventless-core/commit/fa32d93dedabea1b1f655f01a4ea769a5908b143))
24
+ * surface masked GraphQL resolver errors server-side (local + AWS) ([b3bca51](https://github.com/ReventlessDev/reventless-core/commit/b3bca51b539e40c604b3db338d570de6215ea837))
25
+
26
+
6
27
  # 3.0.0-alpha.211 (2026-07-14)
7
28
 
8
29
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-aws",
3
- "version": "3.0.0-alpha.211",
3
+ "version": "3.0.0-alpha.213",
4
4
  "description": "AWS adapters for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "dependencies": {
@@ -10,15 +10,15 @@
10
10
  "uuid": "^13.0.0",
11
11
  "@reventlessdev/rescript-aws-sdk": "2.2.0-alpha.21",
12
12
  "@reventlessdev/rescript-effect": "0.1.0-alpha.27",
13
- "@reventlessdev/rescript-jest": "1.0.0-alpha.7",
14
- "@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.52",
13
+ "@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.53",
15
14
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.15",
16
- "@reventlessdev/reventless-core": "3.0.0-alpha.167",
17
- "@reventlessdev/reventless-infra": "3.0.0-alpha.99",
15
+ "@reventlessdev/rescript-jest": "1.0.0-alpha.7",
16
+ "@reventlessdev/reventless-core": "3.0.0-alpha.169",
17
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.33",
18
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.100",
18
19
  "@reventlessdev/rescript-uuid": "1.1.0-alpha.15",
19
- "@reventlessdev/reventless-interop": "3.0.0-alpha.26",
20
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.31",
21
- "@reventlessdev/reventless-spec": "3.0.0-alpha.76"
20
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.77",
21
+ "@reventlessdev/reventless-interop": "3.0.0-alpha.26"
22
22
  },
23
23
  "devDependencies": {
24
24
  "rescript": "^12.3.0",
@@ -5,8 +5,11 @@
5
5
  // field. The persisted structure is sury-encoded with the exact same shape
6
6
  // the in-memory adapter's `Platform_ComponentDefinitionsApi.encodePluginStructureEntry`
7
7
  // produces (literal-string `commandLevel`, `null`-encoded options), so the
8
- // handler simply wraps each persisted structure with `pluginId` no decoding
9
- // or re-encoding needed.
8
+ // handler wraps each persisted structure with `pluginId` without decoding.
9
+ // One caveat: the persisted structure is PRE-filter — it still carries Internal
10
+ // ReadModels / StateViewSlices for developer tooling. The handler re-applies the
11
+ // `isPublicQueryable` filter (mirroring `encodePluginStructureEntry`) so Internal
12
+ // components stay out of the deployed AutoUI, matching the in-memory adapter.
10
13
 
11
14
  open PulumiAws
12
15
 
@@ -64,6 +67,16 @@ export async function handler() {
64
67
  }
65
68
  return 0;
66
69
  };
70
+ // The persisted structure carries Internal ReadModels / StateViewSlices for
71
+ // developer tooling; they must stay out of the deployed AutoUI. Mirror
72
+ // ReventlessCore.Platform_ComponentDefinitionsApi.isPublicQueryable here on the
73
+ // read path (the persisted structure is pre-filter — it is NOT re-encoded).
74
+ const isPublicQueryable = (q) => q?.visibility !== "Internal";
75
+ const filterStructure = (s) => ({
76
+ ...s,
77
+ readModels: (s.readModels ?? []).filter(isPublicQueryable),
78
+ stateViewSlices: (s.stateViewSlices ?? []).filter(isPublicQueryable),
79
+ });
67
80
  const latestByName = new Map();
68
81
  for (const item of items) {
69
82
  if (!item || !item.structure) continue;
@@ -71,7 +84,7 @@ export async function handler() {
71
84
  const version = String(item.name).split("@")[1] ?? "";
72
85
  const prev = latestByName.get(name);
73
86
  if (!prev || cmpVer(version, prev.version) > 0) {
74
- latestByName.set(name, { version, entry: { pluginId: name, ...item.structure } });
87
+ latestByName.set(name, { version, entry: { pluginId: name, ...filterStructure(item.structure) } });
75
88
  }
76
89
  }
77
90
  const userEntries = [...latestByName.values()].map(v => v.entry);
@@ -65,6 +65,16 @@ export async function handler() {
65
65
  }
66
66
  return 0;
67
67
  };
68
+ // The persisted structure carries Internal ReadModels / StateViewSlices for
69
+ // developer tooling; they must stay out of the deployed AutoUI. Mirror
70
+ // ReventlessCore.Platform_ComponentDefinitionsApi.isPublicQueryable here on the
71
+ // read path (the persisted structure is pre-filter — it is NOT re-encoded).
72
+ const isPublicQueryable = (q) => q?.visibility !== "Internal";
73
+ const filterStructure = (s) => ({
74
+ ...s,
75
+ readModels: (s.readModels ?? []).filter(isPublicQueryable),
76
+ stateViewSlices: (s.stateViewSlices ?? []).filter(isPublicQueryable),
77
+ });
68
78
  const latestByName = new Map();
69
79
  for (const item of items) {
70
80
  if (!item || !item.structure) continue;
@@ -72,7 +82,7 @@ export async function handler() {
72
82
  const version = String(item.name).split("@")[1] ?? "";
73
83
  const prev = latestByName.get(name);
74
84
  if (!prev || cmpVer(version, prev.version) > 0) {
75
- latestByName.set(name, { version, entry: { pluginId: name, ...item.structure } });
85
+ latestByName.set(name, { version, entry: { pluginId: name, ...filterStructure(item.structure) } });
76
86
  }
77
87
  }
78
88
  const userEntries = [...latestByName.values()].map(v => v.entry);
@@ -91,7 +91,10 @@ export function buildJsonEventsHandler(specModule, projectionModule, queryDbTabl
91
91
  // every such action hit the `MissingSubIdConfig` guard and silently write nothing,
92
92
  // while the test-harness callback path (which threads it) stayed green. `undefined`
93
93
  // for slices without an `@subId` is correct — those never emit sub-id actions.
94
- Effect.promise(() => handleAction(action, queryDbOps, specModule.subIdConfig)),
94
+ // First positional arg is the compiled `~comp=` optional (attribution
95
+ // for Projection.handleAction's debug-lazy action log) — the slice's
96
+ // spec name. Compiled shape: (comp, action, operations, subIdConfig).
97
+ Effect.promise(() => handleAction(specModule.name, action, queryDbOps, specModule.subIdConfig)),
95
98
  _ => {}
96
99
  )
97
100
  );
@@ -486,6 +486,24 @@ let _makeApiResourceWith = (
486
486
  ~opts=Some(customOpts),
487
487
  )
488
488
 
489
+ // Let AppSync push field-resolver errors to CloudWatch. The API's own service
490
+ // role is already assumable by appsync.amazonaws.com, so attach the AWS-managed
491
+ // push policy to it and reuse it as the logging role. `fieldLogLevel = ERROR`
492
+ // (below) then captures resolver failures AppSync otherwise swallows into the
493
+ // client's `errors[]` — e.g. a non-null coercion on a stale read-model row.
494
+ let _appsyncCwLogsAttachment = IAM.RolePolicyAttachment.make(
495
+ ~name=`${name}-appsync-cwlogs`,
496
+ ~args={
497
+ role: iamRole.name->Pulumi.Output.asInput,
498
+ policyArn: "arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs"->Pulumi.Input.make,
499
+ },
500
+ ~opts=Some(customOpts),
501
+ )
502
+ let appsyncLogConfig: AppSync.GraphQLApi.logConfig = {
503
+ cloudwatchLogsRoleArn: iamRole.arn->Pulumi.Output.asInput,
504
+ fieldLogLevel: AppSync.GraphQLApi.ERROR->Pulumi.Input.make,
505
+ }
506
+
489
507
  // Resolve the Cognito UserPool — either supplied by the caller (plugin-stack
490
508
  // source APIs read it from the platform's StackReference exports so they
491
509
  // never provision pool/client resources of their own) or resolved via
@@ -520,6 +538,7 @@ let _makeApiResourceWith = (
520
538
  )->Pulumi.Input.make,
521
539
  ]->Pulumi.Input.make,
522
540
  schema: ?(schema->Option.map(Pulumi.Input.make)),
541
+ logConfig: appsyncLogConfig->Pulumi.Input.make,
523
542
  }
524
543
  let graphQLApi = AppSync.GraphQLApi.make(~name, ~args=apiArgs, ~opts=Some(customOpts))
525
544
 
@@ -276,6 +276,15 @@ function _makeApiResourceWith(name, schema, userPoolConfig, opts) {
276
276
  let iamRole = new (Aws.iam.Role)(name + `-appsync-role`, {
277
277
  assumeRolePolicy: `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"appsync.amazonaws.com"},"Action":"sts:AssumeRole"}]}`
278
278
  }, customOpts);
279
+ new (Aws.iam.RolePolicyAttachment)(name + `-appsync-cwlogs`, {
280
+ policyArn: "arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs",
281
+ role: iamRole.name
282
+ }, customOpts);
283
+ let appsyncLogConfig_cloudwatchLogsRoleArn = iamRole.arn;
284
+ let appsyncLogConfig = {
285
+ cloudwatchLogsRoleArn: appsyncLogConfig_cloudwatchLogsRoleArn,
286
+ fieldLogLevel: "ERROR"
287
+ };
279
288
  let userPoolConfigOut = userPoolConfig !== undefined ? userPoolConfig : Auth_Cognito$ReventlessAws.make(name + `-auth`, undefined).apply(c => ({
280
289
  userPoolId: c.userPoolId,
281
290
  defaultAction: "ALLOW",
@@ -286,11 +295,13 @@ function _makeApiResourceWith(name, schema, userPoolConfig, opts) {
286
295
  let apiArgs_additionalAuthenticationProviders = [{
287
296
  authenticationType: "AWS_IAM"
288
297
  }];
298
+ let apiArgs_logConfig = appsyncLogConfig;
289
299
  let apiArgs = {
290
300
  authenticationType: "AMAZON_COGNITO_USER_POOLS",
291
301
  schema: apiArgs_schema,
292
302
  userPoolConfig: apiArgs_userPoolConfig,
293
- additionalAuthenticationProviders: apiArgs_additionalAuthenticationProviders
303
+ additionalAuthenticationProviders: apiArgs_additionalAuthenticationProviders,
304
+ logConfig: apiArgs_logConfig
294
305
  };
295
306
  let graphQLApi = new (Aws.appsync.GraphQLApi)(name, apiArgs, customOpts);
296
307
  return [
@@ -25,16 +25,48 @@ let make: ReventlessCore.Heartbeat_Adapter.runnerMaker<runtimeParts> = (
25
25
  let lambdaRole = runtime.parts.lambdaRole
26
26
  let coreSqsQueue = remoteChannel.resources->Util_SQS.findResolvedResource
27
27
 
28
- let _attachPoliciesAndSetEventTarget =
29
- (
30
- lambda->Pulumi.Output.flatMap(lambda => lambda.arn),
31
- lambda->Pulumi.Output.flatMap(lambda => lambda.name),
32
- lambdaRole.id,
28
+ // Grant sqs:SendMessage on the Core Plugin ExtensionPoint command topic at
29
+ // TOP LEVEL. Previously this RolePolicy was created inside the
30
+ // `Pulumi.Output.apply` below — and a resource created inside an apply
31
+ // callback does not reliably register with the engine, which intermittently
32
+ // left the heartbeat Lambda without this grant (IAM AccessDenied:
33
+ // `sqs:sendmessage on CorePluginExtPointCmdTopic`). `coreSqsQueue.urn` is an
34
+ // already-resolved ARN string from the remote channel and `lambdaRole.id` an
35
+ // Output, so neither needs an apply. Mirrors the EC `pta` grant fix — see
36
+ // docs/analysis/ec-publish-to-aggregates-grant-broken.md.
37
+ let _attachHeartbeatLambdaPolicy = {
38
+ open PulumiAws.PolicyDocument
39
+ let heartbeatLambdaSendMessagePolicyDocument = PulumiAws.PolicyDocument.make(
40
+ ~statements=[
41
+ {
42
+ sid: "AllowLambdaToSendSQS",
43
+ effect: Allow,
44
+ actions: Action("sqs:SendMessage"),
45
+ resources: Resource(coreSqsQueue.urn),
46
+ },
47
+ ],
33
48
  )
34
- ->Pulumi.Output.all3
35
- ->Pulumi.Output.apply(((lambdaArn, lambdaName, heartbeatRoleId)) => {
36
- open PulumiAws.PolicyDocument
49
+ PulumiAws.IAM.RolePolicy.make(
50
+ ~name=name ++ "RolePolicy",
51
+ ~args={
52
+ policy: PulumiAws.PolicyDocument.mergePolicyDocuments(
53
+ name ++ "Policy",
54
+ [
55
+ PulumiAws.Lambda.defaultLoggingPolicyDocument,
56
+ heartbeatLambdaSendMessagePolicyDocument,
57
+ ],
58
+ )->Pulumi.Output.asInput,
59
+ role: lambdaRole.id->Pulumi.Output.asInput,
60
+ },
61
+ )
62
+ }
37
63
 
64
+ // The Lambda permission and CloudWatch event target genuinely need the
65
+ // Lambda's resolved arn/name, so they stay inside an apply.
66
+ let _permissionAndEventTarget =
67
+ (lambda->Pulumi.Output.flatMap(lambda => lambda.arn), lambda->Pulumi.Output.flatMap(lambda => lambda.name))
68
+ ->Pulumi.Output.all2
69
+ ->Pulumi.Output.apply(((lambdaArn, lambdaName)) => {
38
70
  let _addHeartbeatLambdaPermission = PulumiAws.Lambda.Permission.make(
39
71
  ~name,
40
72
  ~args={
@@ -45,33 +77,6 @@ let make: ReventlessCore.Heartbeat_Adapter.runnerMaker<runtimeParts> = (
45
77
  ~opts,
46
78
  )
47
79
 
48
- let heartbeatLambdaSendMessagePolicyDocument = {
49
- PulumiAws.PolicyDocument.make(
50
- ~statements=[
51
- {
52
- sid: "AllowLambdaToSendSQS",
53
- effect: Allow,
54
- actions: Action("sqs:SendMessage"),
55
- resources: Resource(coreSqsQueue.urn),
56
- },
57
- ],
58
- )
59
- }
60
-
61
- let _attachHeartbeatLambdaPolicy = PulumiAws.IAM.RolePolicy.make(
62
- ~name=name ++ "RolePolicy",
63
- ~args={
64
- policy: PulumiAws.PolicyDocument.mergePolicyDocuments(
65
- name ++ "Policy",
66
- [
67
- PulumiAws.Lambda.defaultLoggingPolicyDocument,
68
- heartbeatLambdaSendMessagePolicyDocument,
69
- ],
70
- )->Pulumi.Output.asInput,
71
- role: heartbeatRoleId->Pulumi.Input.make,
72
- },
73
- )
74
-
75
80
  let _cloudwatchEventTarget = {
76
81
  open PulumiAws.Cloudwatch
77
82
  EventTarget.make(
@@ -27,29 +27,28 @@ function make(name, remoteChannel, timeout, runtime, opts) {
27
27
  let lambda = runtime.parts.lambda;
28
28
  let lambdaRole = runtime.parts.lambdaRole;
29
29
  let coreSqsQueue = Util_SQS$ReventlessAws.findResolvedResource(remoteChannel.resources);
30
+ let heartbeatLambdaSendMessagePolicyDocument = PolicyDocument$PulumiAws.make(undefined, undefined, [{
31
+ Sid: "AllowLambdaToSendSQS",
32
+ Effect: "Allow",
33
+ Action: "sqs:SendMessage",
34
+ Resource: coreSqsQueue.urn
35
+ }]);
36
+ new (Aws.iam.RolePolicy)(name + "RolePolicy", {
37
+ policy: PolicyDocument$PulumiAws.mergePolicyDocuments(name + "Policy", [
38
+ Lambda$PulumiAws.defaultLoggingPolicyDocument,
39
+ heartbeatLambdaSendMessagePolicyDocument
40
+ ]),
41
+ role: lambdaRole.id
42
+ });
30
43
  Pulumi.all([
31
44
  Output$Pulumi.flatMap(lambda, lambda => lambda.arn),
32
- Output$Pulumi.flatMap(lambda, lambda => lambda.name),
33
- lambdaRole.id
45
+ Output$Pulumi.flatMap(lambda, lambda => lambda.name)
34
46
  ]).apply(param => {
35
47
  new (Aws.lambda.Permission)(name, {
36
48
  action: "lambda:InvokeFunction",
37
49
  function: param[1],
38
50
  principal: AWS$ReventlessAws.CloudwatchEventRule.principal
39
51
  }, opts$1);
40
- let heartbeatLambdaSendMessagePolicyDocument = PolicyDocument$PulumiAws.make(undefined, undefined, [{
41
- Sid: "AllowLambdaToSendSQS",
42
- Effect: "Allow",
43
- Action: "sqs:SendMessage",
44
- Resource: coreSqsQueue.urn
45
- }]);
46
- new (Aws.iam.RolePolicy)(name + "RolePolicy", {
47
- policy: PolicyDocument$PulumiAws.mergePolicyDocuments(name + "Policy", [
48
- Lambda$PulumiAws.defaultLoggingPolicyDocument,
49
- heartbeatLambdaSendMessagePolicyDocument
50
- ]),
51
- role: param[2]
52
- });
53
52
  new (Aws.cloudwatch.EventTarget)(name, {
54
53
  rule: Cloudwatch_EventTarget$PulumiAws.Rule.ofEventRule(cloudwatchEventRule),
55
54
  arn: param[0]
@@ -622,79 +622,68 @@ module Make = (
622
622
  aggregateNameSet->Dict.set(aggName, ())
623
623
  )
624
624
  )
625
- let queueUrlOutputs =
626
- aggregateNameSet
627
- ->Dict.keysToArray
628
- ->Array.filterMap(aggName => context.publishToAggregates->Dict.get(aggName))
629
- let _ = if queueUrlOutputs->Array.length > 0 {
630
- // The dict is declared as `dict<Pulumi.Output.t<string>>` but the
631
- // DCB slice path (Dcb_Builder.dcbCommandTopicQueueUrl) can leak the
632
- // `{BS_PRIVATE_NESTED_SOME_NONE: 0}` nested-option sentinel as a
633
- // value when the SQS Queue's .id is still unresolved during early
634
- // CustomResource construction. Pulumi.all happily wraps & resolves
635
- // it as Output<sentinel>, so .apply hands us a non-string. Drop
636
- // anything that isn't actually a stringan extension targeting
637
- // the affected slice will need a separate grant out-of-band until
638
- // the resource is fully provisioned and a subsequent preview/up
639
- // produces a real ARN. We build the policy document inline so an
640
- // empty filtered ARN array skips RolePolicy creation entirely
641
- // (PutRolePolicy rejects empty Resource arrays with
642
- // MalformedPolicyDocument).
643
- let policyJsonOutput =
644
- queueUrlOutputs
645
- ->Pulumi.Output.all
646
- ->Pulumi.Output.apply(urls => {
647
- let queueArns =
648
- urls
649
- ->Array.filter(url => typeof(url) === #string)
650
- ->Array.map(url =>
651
- // queue URL → ARN: https://sqs.<region>.amazonaws.com/<acct>/<name>
652
- // → arn:aws:sqs:<region>:<acct>:<name>
653
- switch url->String.split("/") {
654
- | [_, _, host, acct, name] =>
655
- let region =
656
- host->String.split(".")->Array.get(1)->Option.getOr("eu-west-1")
657
- `arn:aws:sqs:${region}:${acct}:${name}`
658
- | _ => url
659
- }
660
- )
661
- if queueArns->Array.length == 0 {
662
- None
625
+ // One RolePolicy per extension target, each derived through a SINGLE
626
+ // `.apply` on that target's queue-URL Output. `Pulumi.Output.all` is
627
+ // deliberately NOT used here: the DCB slice's URL is an `.apply`-lifted
628
+ // Output (Dcb_Builder reads the queue id via `operations.apply(_ =>
629
+ // resources[0].id)`), and `Pulumi.Output.all` mis-resolves such lifted
630
+ // Outputs to the `{BS_PRIVATE_NESTED_SOME_NONE: 0}` sentinel (both at
631
+ // preview and up) while a direct `.apply` on the same Output resolves the
632
+ // real URL verified by deploying both variants. RolePolicy creation
633
+ // happens at TOP LEVEL: calling `RolePolicy.make` inside a
634
+ // `Pulumi.Output.apply` callback does not reliably register the resource
635
+ // (the previous inside-apply variant existed on no collector role in the
636
+ // account). Dict values are heterogeneous at runtime plain resolved URL
637
+ // strings for aggregate targets, Outputs for DCB-slice targets; anything
638
+ // else is skipped. Inside the apply a non-string URL falls back to a
639
+ // benign placeholder ARN so the policy document stays valid (IAM rejects
640
+ // empty Resource entries with MalformedPolicyDocument).
641
+ // See docs/analysis/ec-publish-to-aggregates-grant-broken.md.
642
+ aggregateNameSet
643
+ ->Dict.keysToArray
644
+ ->Array.forEach(aggName => {
645
+ let urlOutput = switch context.publishToAggregates->Dict.get(aggName) {
646
+ | Some(o) if Pulumi.Output.isOutput(o) => Some(o)
647
+ | Some(o) if typeof(o) === #string => Some(Pulumi.Output.make((o->Obj.magic: string)))
648
+ | _ => None
649
+ }
650
+ switch urlOutput {
651
+ | Some(urlOutput) =>
652
+ let policyJson = urlOutput->Pulumi.Output.apply(url => {
653
+ let arn = if typeof(url) === #string {
654
+ // queue URL ARN: https://sqs.<region>.amazonaws.com/<acct>/<name>
655
+ // arn:aws:sqs:<region>:<acct>:<name>
656
+ switch url->String.split("/") {
657
+ | [_, _, host, acct, name] =>
658
+ let region = host->String.split(".")->Array.get(1)->Option.getOr("eu-west-1")
659
+ `arn:aws:sqs:${region}:${acct}:${name}`
660
+ | _ => url
661
+ }
663
662
  } else {
664
- Some(
665
- PulumiAws.PolicyDocument.make(
666
- ~id=`${name}PublishToAggregatesPolicy`,
667
- ~statements=[
668
- {
669
- sid: "AllowEcPublishToAggregateCmdTopics",
670
- effect: Allow,
671
- actions: Action("sqs:SendMessage"),
672
- resources: Resources(queueArns),
673
- },
674
- ],
675
- )->PulumiAws.PolicyDocument.toJsonString,
676
- )
663
+ "arn:aws:sqs:eu-west-1:000000000000:reventless-unresolved-cmd-topic"
677
664
  }
678
- })
679
- // Pulumi.all wraps a Some(string)/None and resolves to either the
680
- // policy JSON or undefined — the latter makes PutRolePolicy a no-op
681
- // by failing fast in the provider, so guard RolePolicy creation on
682
- // the resolved value being Some.
683
- let _ =
684
- policyJsonOutput->Pulumi.Output.apply(policyOpt =>
685
- switch policyOpt {
686
- | Some(policyJson) =>
687
- let _ = PulumiAws.IAM.RolePolicy.make(
688
- ~name=`${name}-publishToAggregates`,
689
- ~args={
690
- policy: policyJson->Pulumi.Input.make,
691
- role: runtime.parts.lambdaRole.id->Pulumi.Output.asInput,
665
+ PulumiAws.PolicyDocument.make(
666
+ ~id=`${name}Pta${aggName}Policy`,
667
+ ~statements=[
668
+ {
669
+ sid: "AllowEcPublishToAggregateCmdTopic",
670
+ effect: Allow,
671
+ actions: Action("sqs:SendMessage"),
672
+ resources: Resource(arn),
692
673
  },
693
- )
694
- | None => ()
695
- }
674
+ ],
675
+ )->PulumiAws.PolicyDocument.toJsonString
676
+ })
677
+ let _ = PulumiAws.IAM.RolePolicy.make(
678
+ ~name=`${name}-pta-${aggName}`,
679
+ ~args={
680
+ policy: policyJson->Pulumi.Output.asInput,
681
+ role: runtime.parts.lambdaRole.id->Pulumi.Output.asInput,
682
+ },
696
683
  )
697
- }
684
+ | None => ()
685
+ }
686
+ })
698
687
  }
699
688
 
700
689
  let forPluginHeartbeat: ReventlessCore.Runtime.forComponent<
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Aws from "@pulumi/aws";
4
- import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
5
  import * as Pulumi from "@pulumi/pulumi";
7
6
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
@@ -366,41 +365,44 @@ function Make(EventCollectorChannel) {
366
365
  aggregateNameSet[aggName] = undefined;
367
366
  });
368
367
  });
369
- let queueUrlOutputs = Stdlib_Array.filterMap(Object.keys(aggregateNameSet), aggName => context.publishToAggregates[aggName]);
370
- if (queueUrlOutputs.length !== 0) {
371
- let policyJsonOutput = Pulumi.all(queueUrlOutputs).apply(urls => {
372
- let queueArns = urls.filter(url => typeof url === "string").map(url => {
368
+ Object.keys(aggregateNameSet).forEach(aggName => {
369
+ let o = context.publishToAggregates[aggName];
370
+ let urlOutput = o !== undefined ? (
371
+ Pulumi.Output.isInstance(o) ? o : (
372
+ typeof o === "string" ? Pulumi.output(o) : undefined
373
+ )
374
+ ) : undefined;
375
+ if (urlOutput === undefined) {
376
+ return;
377
+ }
378
+ let policyJson = urlOutput.apply(url => {
379
+ let arn;
380
+ if (typeof url === "string") {
373
381
  let match = url.split("/");
374
382
  if (match.length !== 5) {
375
- return url;
383
+ arn = url;
384
+ } else {
385
+ let host = match[2];
386
+ let acct = match[3];
387
+ let name$1 = match[4];
388
+ let region = Stdlib_Option.getOr(host.split(".")[1], "eu-west-1");
389
+ arn = `arn:aws:sqs:` + region + `:` + acct + `:` + name$1;
376
390
  }
377
- let host = match[2];
378
- let acct = match[3];
379
- let name = match[4];
380
- let region = Stdlib_Option.getOr(host.split(".")[1], "eu-west-1");
381
- return `arn:aws:sqs:` + region + `:` + acct + `:` + name;
382
- });
383
- if (queueArns.length === 0) {
384
- return;
385
391
  } else {
386
- return PolicyDocument$PulumiAws.toJsonString(PolicyDocument$PulumiAws.make(undefined, name + `PublishToAggregatesPolicy`, [{
387
- Sid: "AllowEcPublishToAggregateCmdTopics",
388
- Effect: "Allow",
389
- Action: "sqs:SendMessage",
390
- Resource: queueArns
391
- }]));
392
+ arn = "arn:aws:sqs:eu-west-1:000000000000:reventless-unresolved-cmd-topic";
392
393
  }
394
+ return PolicyDocument$PulumiAws.toJsonString(PolicyDocument$PulumiAws.make(undefined, name + `Pta` + aggName + `Policy`, [{
395
+ Sid: "AllowEcPublishToAggregateCmdTopic",
396
+ Effect: "Allow",
397
+ Action: "sqs:SendMessage",
398
+ Resource: arn
399
+ }]));
393
400
  });
394
- policyJsonOutput.apply(policyOpt => {
395
- if (policyOpt !== undefined) {
396
- new (Aws.iam.RolePolicy)(name + `-publishToAggregates`, {
397
- policy: policyOpt,
398
- role: runtime.parts.lambdaRole.id
399
- });
400
- return;
401
- }
401
+ new (Aws.iam.RolePolicy)(name + `-pta-` + aggName, {
402
+ policy: policyJson,
403
+ role: runtime.parts.lambdaRole.id
402
404
  });
403
- }
405
+ });
404
406
  };
405
407
  let forPluginHeartbeat = (param, connect, memorySizeOpt, timeoutOpt, heartbeat) => {
406
408
  let memorySize = memorySizeOpt !== undefined ? memorySizeOpt : 1024;