@wraps.dev/cli 2.11.7 → 2.11.9

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/dist/cli.js CHANGED
@@ -95,7 +95,7 @@ async function stateBucketExists(accountId, region) {
95
95
  await client.send(new HeadBucketCommand({ Bucket: bucketName }));
96
96
  return true;
97
97
  } catch (error) {
98
- if (error.name === "NotFound" || error.name === "NoSuchBucket" || error.$metadata?.httpStatusCode === 404) {
98
+ if (error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchBucket" || error.$metadata?.httpStatusCode === 404)) {
99
99
  return false;
100
100
  }
101
101
  throw error;
@@ -117,7 +117,8 @@ async function ensureStateBucket(accountId, region) {
117
117
  await client.send(new HeadBucketCommand({ Bucket: bucketName }));
118
118
  return bucketName;
119
119
  } catch (error) {
120
- if (error.name !== "NotFound" && error.name !== "NoSuchBucket" && error.$metadata?.httpStatusCode !== 404) {
120
+ const isNotFound = error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchBucket" || error.$metadata?.httpStatusCode === 404);
121
+ if (!isNotFound) {
121
122
  throw error;
122
123
  }
123
124
  }
@@ -204,7 +205,7 @@ async function downloadMetadata(bucketName, accountId, region) {
204
205
  }
205
206
  return JSON.parse(body);
206
207
  } catch (error) {
207
- if (error.name === "NoSuchKey" || error.$metadata?.httpStatusCode === 404) {
208
+ if (error instanceof Error && (error.name === "NoSuchKey" || error.$metadata?.httpStatusCode === 404)) {
208
209
  return null;
209
210
  }
210
211
  throw error;
@@ -277,7 +278,7 @@ async function migrateLocalPulumiState(localPulumiDir, bucketName, accountId, re
277
278
  await s3Stack.importStack(state);
278
279
  } catch (error) {
279
280
  console.error(
280
- `Warning: Failed to migrate stack ${stackName}: ${error.message}`
281
+ `Warning: Failed to migrate stack ${stackName}: ${error instanceof Error ? error.message : error}`
281
282
  );
282
283
  }
283
284
  }
@@ -351,7 +352,7 @@ async function ensurePulumiWorkDir(options) {
351
352
  } catch (error) {
352
353
  const clack47 = await import("@clack/prompts");
353
354
  clack47.log.warn(
354
- `S3 state backend unavailable (${error.message}). Using local state.`
355
+ `S3 state backend unavailable (${error instanceof Error ? error.message : error}). Using local state.`
355
356
  );
356
357
  }
357
358
  }
@@ -825,8 +826,8 @@ async function isAWSCLIInstalled() {
825
826
  }
826
827
  async function getAWSCLIVersion() {
827
828
  try {
828
- const output4 = execSync("aws --version", { encoding: "utf-8" });
829
- const match = output4.match(/aws-cli\/(\d+\.\d+\.\d+)/);
829
+ const output3 = execSync("aws --version", { encoding: "utf-8" });
830
+ const match = output3.match(/aws-cli\/(\d+\.\d+\.\d+)/);
830
831
  return match ? match[1] : null;
831
832
  } catch {
832
833
  return null;
@@ -1815,7 +1816,7 @@ async function isSESSandbox(region) {
1815
1816
  );
1816
1817
  return false;
1817
1818
  } catch (error) {
1818
- if (error.name === "InvalidParameterValue") {
1819
+ if (error instanceof Error && error.name === "InvalidParameterValue") {
1819
1820
  return true;
1820
1821
  }
1821
1822
  throw error;
@@ -4057,7 +4058,10 @@ async function loadConnectionMetadata(accountId, region) {
4057
4058
  localData = data;
4058
4059
  }
4059
4060
  } catch (error) {
4060
- console.error("Error loading connection metadata:", error.message);
4061
+ console.error(
4062
+ "Error loading connection metadata:",
4063
+ error instanceof Error ? error.message : error
4064
+ );
4061
4065
  }
4062
4066
  }
4063
4067
  if (process.env.WRAPS_LOCAL_ONLY !== "1") {
@@ -4115,7 +4119,10 @@ async function saveConnectionMetadata(metadata) {
4115
4119
  const content = JSON.stringify(metadata, null, 2);
4116
4120
  await writeFile3(metadataPath, content, "utf-8");
4117
4121
  } catch (error) {
4118
- console.error("Error saving connection metadata:", error.message);
4122
+ console.error(
4123
+ "Error saving connection metadata:",
4124
+ error instanceof Error ? error.message : error
4125
+ );
4119
4126
  throw error;
4120
4127
  }
4121
4128
  if (process.env.WRAPS_LOCAL_ONLY !== "1") {
@@ -4165,7 +4172,10 @@ async function listConnections() {
4165
4172
  }
4166
4173
  return connections;
4167
4174
  } catch (error) {
4168
- console.error("Error listing connections:", error.message);
4175
+ console.error(
4176
+ "Error listing connections:",
4177
+ error instanceof Error ? error.message : error
4178
+ );
4169
4179
  return [];
4170
4180
  }
4171
4181
  }
@@ -4467,10 +4477,10 @@ var init_metadata = __esm({
4467
4477
  async function roleExists(roleName) {
4468
4478
  try {
4469
4479
  const { IAMClient: IAMClient4, GetRoleCommand: GetRoleCommand3 } = await import("@aws-sdk/client-iam");
4470
- const iam10 = new IAMClient4({
4480
+ const iam9 = new IAMClient4({
4471
4481
  region: process.env.AWS_REGION || "us-east-1"
4472
4482
  });
4473
- await iam10.send(new GetRoleCommand3({ RoleName: roleName }));
4483
+ await iam9.send(new GetRoleCommand3({ RoleName: roleName }));
4474
4484
  return true;
4475
4485
  } catch (error) {
4476
4486
  if (error instanceof Error && (error.name === "NoSuchEntityException" || error.Code === "NoSuchEntity" || error.Error?.Code === "NoSuchEntity")) {
@@ -4760,7 +4770,7 @@ import { builtinModules } from "module";
4760
4770
  import { tmpdir } from "os";
4761
4771
  import { dirname as dirname2, join as join7 } from "path";
4762
4772
  import { fileURLToPath as fileURLToPath3 } from "url";
4763
- import * as aws8 from "@pulumi/aws";
4773
+ import * as aws7 from "@pulumi/aws";
4764
4774
  import * as pulumi11 from "@pulumi/pulumi";
4765
4775
  import { build } from "esbuild";
4766
4776
  function getPackageRoot() {
@@ -4835,7 +4845,7 @@ Try running: pnpm build`
4835
4845
  }
4836
4846
  async function deployLambdaFunctions(config2) {
4837
4847
  const eventProcessorCode = await getLambdaCode("event-processor");
4838
- const lambdaRole = new aws8.iam.Role("wraps-email-lambda-role", {
4848
+ const lambdaRole = new aws7.iam.Role("wraps-email-lambda-role", {
4839
4849
  assumeRolePolicy: JSON.stringify({
4840
4850
  Version: "2012-10-17",
4841
4851
  Statement: [
@@ -4850,11 +4860,11 @@ async function deployLambdaFunctions(config2) {
4850
4860
  ManagedBy: "wraps-cli"
4851
4861
  }
4852
4862
  });
4853
- new aws8.iam.RolePolicyAttachment("wraps-email-lambda-basic-execution", {
4863
+ new aws7.iam.RolePolicyAttachment("wraps-email-lambda-basic-execution", {
4854
4864
  role: lambdaRole.name,
4855
4865
  policyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
4856
4866
  });
4857
- new aws8.iam.RolePolicy("wraps-email-lambda-policy", {
4867
+ new aws7.iam.RolePolicy("wraps-email-lambda-policy", {
4858
4868
  role: lambdaRole.name,
4859
4869
  policy: pulumi11.all([config2.tableName, config2.queueArn]).apply(
4860
4870
  ([tableName, queueArn]) => JSON.stringify({
@@ -4898,7 +4908,7 @@ async function deployLambdaFunctions(config2) {
4898
4908
  RETENTION_DAYS: config2.retentionDays.toString()
4899
4909
  }
4900
4910
  };
4901
- const eventProcessor = exists ? new aws8.lambda.Function(
4911
+ const eventProcessor = exists ? new aws7.lambda.Function(
4902
4912
  functionName,
4903
4913
  {
4904
4914
  name: functionName,
@@ -4919,7 +4929,7 @@ async function deployLambdaFunctions(config2) {
4919
4929
  import: functionName
4920
4930
  // Import existing function
4921
4931
  }
4922
- ) : new aws8.lambda.Function(functionName, {
4932
+ ) : new aws7.lambda.Function(functionName, {
4923
4933
  name: functionName,
4924
4934
  runtime: "nodejs24.x",
4925
4935
  handler: "index.handler",
@@ -4949,14 +4959,14 @@ async function deployLambdaFunctions(config2) {
4949
4959
  functionResponseTypes: ["ReportBatchItemFailures"]
4950
4960
  // Enable partial batch responses
4951
4961
  };
4952
- const eventSourceMapping = existingMappingUuid ? new aws8.lambda.EventSourceMapping(
4962
+ const eventSourceMapping = existingMappingUuid ? new aws7.lambda.EventSourceMapping(
4953
4963
  "wraps-email-event-source-mapping",
4954
4964
  mappingConfig,
4955
4965
  {
4956
4966
  import: existingMappingUuid
4957
4967
  // Import with the UUID
4958
4968
  }
4959
- ) : new aws8.lambda.EventSourceMapping(
4969
+ ) : new aws7.lambda.EventSourceMapping(
4960
4970
  "wraps-email-event-source-mapping",
4961
4971
  mappingConfig
4962
4972
  );
@@ -4982,7 +4992,7 @@ __export(acm_exports, {
4982
4992
  createACMCertificate: () => createACMCertificate
4983
4993
  });
4984
4994
  import { ACMClient as ACMClient2, DescribeCertificateCommand as DescribeCertificateCommand2 } from "@aws-sdk/client-acm";
4985
- import * as aws12 from "@pulumi/aws";
4995
+ import * as aws11 from "@pulumi/aws";
4986
4996
  async function checkCertificateValidation(domain) {
4987
4997
  try {
4988
4998
  const acm3 = new ACMClient2({ region: "us-east-1" });
@@ -5009,10 +5019,10 @@ async function checkCertificateValidation(domain) {
5009
5019
  }
5010
5020
  }
5011
5021
  async function createACMCertificate(config2) {
5012
- const usEast1Provider = new aws12.Provider("acm-us-east-1", {
5022
+ const usEast1Provider = new aws11.Provider("acm-us-east-1", {
5013
5023
  region: "us-east-1"
5014
5024
  });
5015
- const certificate = new aws12.acm.Certificate(
5025
+ const certificate = new aws11.acm.Certificate(
5016
5026
  "wraps-email-tracking-cert",
5017
5027
  {
5018
5028
  domainName: config2.domain,
@@ -5035,7 +5045,7 @@ async function createACMCertificate(config2) {
5035
5045
  );
5036
5046
  let certificateValidation;
5037
5047
  if (config2.hostedZoneId) {
5038
- const validationRecord = new aws12.route53.Record(
5048
+ const validationRecord = new aws11.route53.Record(
5039
5049
  "wraps-email-tracking-cert-validation",
5040
5050
  {
5041
5051
  zoneId: config2.hostedZoneId,
@@ -5045,7 +5055,7 @@ async function createACMCertificate(config2) {
5045
5055
  ttl: 60
5046
5056
  }
5047
5057
  );
5048
- certificateValidation = new aws12.acm.CertificateValidation(
5058
+ certificateValidation = new aws11.acm.CertificateValidation(
5049
5059
  "wraps-email-tracking-cert-validation-waiter",
5050
5060
  {
5051
5061
  certificateArn: certificate.arn,
@@ -5074,7 +5084,7 @@ var cloudfront_exports = {};
5074
5084
  __export(cloudfront_exports, {
5075
5085
  createCloudFrontTracking: () => createCloudFrontTracking
5076
5086
  });
5077
- import * as aws13 from "@pulumi/aws";
5087
+ import * as aws12 from "@pulumi/aws";
5078
5088
  async function findDistributionByAlias(alias) {
5079
5089
  try {
5080
5090
  const { CloudFrontClient, ListDistributionsCommand } = await import("@aws-sdk/client-cloudfront");
@@ -5090,10 +5100,10 @@ async function findDistributionByAlias(alias) {
5090
5100
  }
5091
5101
  }
5092
5102
  async function createWAFWebACL() {
5093
- const usEast1Provider = new aws13.Provider("waf-us-east-1", {
5103
+ const usEast1Provider = new aws12.Provider("waf-us-east-1", {
5094
5104
  region: "us-east-1"
5095
5105
  });
5096
- const webAcl = new aws13.wafv2.WebAcl(
5106
+ const webAcl = new aws12.wafv2.WebAcl(
5097
5107
  "wraps-email-tracking-waf",
5098
5108
  {
5099
5109
  scope: "CLOUDFRONT",
@@ -5208,14 +5218,14 @@ async function createCloudFrontTracking(config2) {
5208
5218
  Description: "Wraps email tracking CloudFront distribution"
5209
5219
  }
5210
5220
  };
5211
- const distribution = existingDistributionId ? new aws13.cloudfront.Distribution(
5221
+ const distribution = existingDistributionId ? new aws12.cloudfront.Distribution(
5212
5222
  "wraps-email-tracking-cdn",
5213
5223
  distributionConfig,
5214
5224
  {
5215
5225
  import: existingDistributionId
5216
5226
  // Import existing distribution
5217
5227
  }
5218
- ) : new aws13.cloudfront.Distribution(
5228
+ ) : new aws12.cloudfront.Distribution(
5219
5229
  "wraps-email-tracking-cdn",
5220
5230
  distributionConfig
5221
5231
  );
@@ -5396,10 +5406,10 @@ var s3_inbound_exports = {};
5396
5406
  __export(s3_inbound_exports, {
5397
5407
  createS3InboundResources: () => createS3InboundResources
5398
5408
  });
5399
- import * as aws14 from "@pulumi/aws";
5409
+ import * as aws13 from "@pulumi/aws";
5400
5410
  async function createS3InboundResources(config2) {
5401
5411
  const bucketName = `wraps-inbound-${config2.accountId}-${config2.region}`;
5402
- const bucket = new aws14.s3.BucketV2("wraps-inbound-bucket", {
5412
+ const bucket = new aws13.s3.BucketV2("wraps-inbound-bucket", {
5403
5413
  bucket: bucketName,
5404
5414
  forceDestroy: true,
5405
5415
  tags: {
@@ -5407,14 +5417,14 @@ async function createS3InboundResources(config2) {
5407
5417
  Service: "email-inbound"
5408
5418
  }
5409
5419
  });
5410
- new aws14.s3.BucketPublicAccessBlock("wraps-inbound-public-access-block", {
5420
+ new aws13.s3.BucketPublicAccessBlock("wraps-inbound-public-access-block", {
5411
5421
  bucket: bucket.id,
5412
5422
  blockPublicAcls: true,
5413
5423
  blockPublicPolicy: true,
5414
5424
  ignorePublicAcls: true,
5415
5425
  restrictPublicBuckets: true
5416
5426
  });
5417
- new aws14.s3.BucketServerSideEncryptionConfigurationV2(
5427
+ new aws13.s3.BucketServerSideEncryptionConfigurationV2(
5418
5428
  "wraps-inbound-encryption",
5419
5429
  {
5420
5430
  bucket: bucket.id,
@@ -5430,7 +5440,7 @@ async function createS3InboundResources(config2) {
5430
5440
  if (config2.retention) {
5431
5441
  const retentionDays = retentionToDays2(config2.retention);
5432
5442
  if (retentionDays > 0) {
5433
- new aws14.s3.BucketLifecycleConfigurationV2("wraps-inbound-lifecycle", {
5443
+ new aws13.s3.BucketLifecycleConfigurationV2("wraps-inbound-lifecycle", {
5434
5444
  bucket: bucket.id,
5435
5445
  rules: [
5436
5446
  {
@@ -5444,8 +5454,8 @@ async function createS3InboundResources(config2) {
5444
5454
  });
5445
5455
  }
5446
5456
  }
5447
- const identity = await aws14.getCallerIdentity();
5448
- new aws14.s3.BucketPolicy("wraps-inbound-bucket-policy", {
5457
+ const identity = await aws13.getCallerIdentity();
5458
+ new aws13.s3.BucketPolicy("wraps-inbound-bucket-policy", {
5449
5459
  bucket: bucket.id,
5450
5460
  policy: bucket.arn.apply(
5451
5461
  (arn) => JSON.stringify({
@@ -5487,9 +5497,9 @@ var sqs_inbound_exports = {};
5487
5497
  __export(sqs_inbound_exports, {
5488
5498
  createSQSInboundResources: () => createSQSInboundResources
5489
5499
  });
5490
- import * as aws15 from "@pulumi/aws";
5500
+ import * as aws14 from "@pulumi/aws";
5491
5501
  function createSQSInboundResources() {
5492
- const dlq = new aws15.sqs.Queue("wraps-inbound-events-dlq", {
5502
+ const dlq = new aws14.sqs.Queue("wraps-inbound-events-dlq", {
5493
5503
  name: "wraps-inbound-events-dlq",
5494
5504
  messageRetentionSeconds: 1209600,
5495
5505
  // 14 days
@@ -5499,7 +5509,7 @@ function createSQSInboundResources() {
5499
5509
  Description: "Dead letter queue for failed inbound email processing"
5500
5510
  }
5501
5511
  });
5502
- const queue = new aws15.sqs.Queue("wraps-inbound-events", {
5512
+ const queue = new aws14.sqs.Queue("wraps-inbound-events", {
5503
5513
  name: "wraps-inbound-events",
5504
5514
  visibilityTimeoutSeconds: 300,
5505
5515
  // Must be >= Lambda timeout (120s) * 2 + buffer
@@ -5536,11 +5546,11 @@ var lambda_inbound_exports = {};
5536
5546
  __export(lambda_inbound_exports, {
5537
5547
  deployInboundLambda: () => deployInboundLambda
5538
5548
  });
5539
- import * as aws16 from "@pulumi/aws";
5549
+ import * as aws15 from "@pulumi/aws";
5540
5550
  import * as pulumi12 from "@pulumi/pulumi";
5541
5551
  async function deployInboundLambda(config2) {
5542
5552
  const inboundProcessorCode = await getLambdaCode("inbound-processor");
5543
- const lambdaRole = new aws16.iam.Role("wraps-inbound-lambda-role", {
5553
+ const lambdaRole = new aws15.iam.Role("wraps-inbound-lambda-role", {
5544
5554
  name: "wraps-inbound-lambda-role",
5545
5555
  assumeRolePolicy: JSON.stringify({
5546
5556
  Version: "2012-10-17",
@@ -5557,11 +5567,11 @@ async function deployInboundLambda(config2) {
5557
5567
  Service: "email-inbound"
5558
5568
  }
5559
5569
  });
5560
- new aws16.iam.RolePolicyAttachment("wraps-inbound-lambda-basic-execution", {
5570
+ new aws15.iam.RolePolicyAttachment("wraps-inbound-lambda-basic-execution", {
5561
5571
  role: lambdaRole.name,
5562
5572
  policyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
5563
5573
  });
5564
- new aws16.iam.RolePolicy("wraps-inbound-lambda-policy", {
5574
+ new aws15.iam.RolePolicy("wraps-inbound-lambda-policy", {
5565
5575
  role: lambdaRole.name,
5566
5576
  policy: pulumi12.all([config2.bucketArn, config2.dlqArn]).apply(
5567
5577
  ([bucketArn, dlqArn]) => JSON.stringify({
@@ -5590,7 +5600,7 @@ async function deployInboundLambda(config2) {
5590
5600
  )
5591
5601
  });
5592
5602
  const functionName = "wraps-inbound-email-processor";
5593
- const lambdaFunction = new aws16.lambda.Function(functionName, {
5603
+ const lambdaFunction = new aws15.lambda.Function(functionName, {
5594
5604
  name: functionName,
5595
5605
  runtime: "nodejs20.x",
5596
5606
  handler: "index.handler",
@@ -5612,7 +5622,7 @@ async function deployInboundLambda(config2) {
5612
5622
  Service: "email-inbound"
5613
5623
  }
5614
5624
  });
5615
- const s3InvokePermission = new aws16.lambda.Permission(
5625
+ const s3InvokePermission = new aws15.lambda.Permission(
5616
5626
  "wraps-inbound-s3-invoke",
5617
5627
  {
5618
5628
  action: "lambda:InvokeFunction",
@@ -5640,9 +5650,9 @@ var eventbridge_inbound_exports = {};
5640
5650
  __export(eventbridge_inbound_exports, {
5641
5651
  createEventBridgeInboundResources: () => createEventBridgeInboundResources
5642
5652
  });
5643
- import * as aws17 from "@pulumi/aws";
5653
+ import * as aws16 from "@pulumi/aws";
5644
5654
  function createEventBridgeInboundResources(config2) {
5645
- const rule = new aws17.cloudwatch.EventRule("wraps-inbound-events-rule", {
5655
+ const rule = new aws16.cloudwatch.EventRule("wraps-inbound-events-rule", {
5646
5656
  name: "wraps-inbound-events-to-webhook",
5647
5657
  description: "Route inbound email events to webhook",
5648
5658
  eventBusName: "default",
@@ -5659,7 +5669,7 @@ function createEventBridgeInboundResources(config2) {
5659
5669
  let webhookApiDestination;
5660
5670
  let webhookTarget;
5661
5671
  if (config2.webhookUrl && config2.webhookSecret) {
5662
- webhookConnection = new aws17.cloudwatch.EventConnection(
5672
+ webhookConnection = new aws16.cloudwatch.EventConnection(
5663
5673
  "wraps-inbound-webhook-connection",
5664
5674
  {
5665
5675
  name: "wraps-inbound-webhook-connection",
@@ -5673,7 +5683,7 @@ function createEventBridgeInboundResources(config2) {
5673
5683
  }
5674
5684
  }
5675
5685
  );
5676
- webhookApiDestination = new aws17.cloudwatch.EventApiDestination(
5686
+ webhookApiDestination = new aws16.cloudwatch.EventApiDestination(
5677
5687
  "wraps-inbound-webhook-destination",
5678
5688
  {
5679
5689
  name: "wraps-inbound-webhook-destination",
@@ -5684,7 +5694,7 @@ function createEventBridgeInboundResources(config2) {
5684
5694
  invocationRateLimitPerSecond: 100
5685
5695
  }
5686
5696
  );
5687
- const webhookRole = new aws17.iam.Role("wraps-inbound-webhook-role", {
5697
+ const webhookRole = new aws16.iam.Role("wraps-inbound-webhook-role", {
5688
5698
  name: "wraps-inbound-eventbridge-webhook-role",
5689
5699
  assumeRolePolicy: JSON.stringify({
5690
5700
  Version: "2012-10-17",
@@ -5703,7 +5713,7 @@ function createEventBridgeInboundResources(config2) {
5703
5713
  Service: "email-inbound"
5704
5714
  }
5705
5715
  });
5706
- new aws17.iam.RolePolicy("wraps-inbound-webhook-policy", {
5716
+ new aws16.iam.RolePolicy("wraps-inbound-webhook-policy", {
5707
5717
  role: webhookRole.name,
5708
5718
  policy: webhookApiDestination.arn.apply(
5709
5719
  (destArn) => JSON.stringify({
@@ -5718,7 +5728,7 @@ function createEventBridgeInboundResources(config2) {
5718
5728
  })
5719
5729
  )
5720
5730
  });
5721
- webhookTarget = new aws17.cloudwatch.EventTarget(
5731
+ webhookTarget = new aws16.cloudwatch.EventTarget(
5722
5732
  "wraps-inbound-webhook-target",
5723
5733
  {
5724
5734
  rule: rule.name,
@@ -9419,13 +9429,12 @@ async function deleteCdnDNSRecords(hostedZoneId, customDomain) {
9419
9429
  // src/commands/cdn/init.ts
9420
9430
  init_esm_shims();
9421
9431
  import * as clack10 from "@clack/prompts";
9422
- import * as pulumi4 from "@pulumi/pulumi";
9432
+ import * as pulumi5 from "@pulumi/pulumi";
9423
9433
  import pc11 from "picocolors";
9424
9434
 
9425
9435
  // src/infrastructure/cdn-stack.ts
9426
9436
  init_esm_shims();
9427
- import * as aws3 from "@pulumi/aws";
9428
- import * as pulumi3 from "@pulumi/pulumi";
9437
+ import * as pulumi4 from "@pulumi/pulumi";
9429
9438
 
9430
9439
  // src/infrastructure/resources/s3-cdn.ts
9431
9440
  init_esm_shims();
@@ -9749,19 +9758,133 @@ async function createCdnACMCertificate(config2) {
9749
9758
  };
9750
9759
  }
9751
9760
 
9752
- // src/infrastructure/cdn-stack.ts
9761
+ // src/infrastructure/shared/iam.ts
9762
+ init_esm_shims();
9753
9763
  init_resource_checks();
9764
+ import * as aws2 from "@pulumi/aws";
9765
+ import * as pulumi3 from "@pulumi/pulumi";
9766
+ async function createServiceIAMRole(config2) {
9767
+ let assumeRolePolicy;
9768
+ if (config2.provider === "vercel" && config2.oidcProvider) {
9769
+ const hasAdditionalPrincipals = config2.additionalVercelPrincipals && config2.additionalVercelPrincipals.length > 0;
9770
+ if (hasAdditionalPrincipals) {
9771
+ const serviceStatement = JSON.stringify({
9772
+ Effect: "Allow",
9773
+ Principal: {
9774
+ Service: config2.additionalVercelPrincipals.length === 1 ? config2.additionalVercelPrincipals[0] : config2.additionalVercelPrincipals
9775
+ },
9776
+ Action: "sts:AssumeRole"
9777
+ });
9778
+ assumeRolePolicy = pulumi3.interpolate`{
9779
+ "Version": "2012-10-17",
9780
+ "Statement": [
9781
+ {
9782
+ "Effect": "Allow",
9783
+ "Principal": {
9784
+ "Federated": "${config2.oidcProvider.arn}"
9785
+ },
9786
+ "Action": "sts:AssumeRoleWithWebIdentity",
9787
+ "Condition": {
9788
+ "StringEquals": {
9789
+ "oidc.vercel.com/${config2.vercelTeamSlug}:aud": "https://vercel.com/${config2.vercelTeamSlug}"
9790
+ },
9791
+ "StringLike": {
9792
+ "oidc.vercel.com/${config2.vercelTeamSlug}:sub": "owner:${config2.vercelTeamSlug}:project:${config2.vercelProjectName}:environment:*"
9793
+ }
9794
+ }
9795
+ },
9796
+ ${serviceStatement}
9797
+ ]
9798
+ }`;
9799
+ } else {
9800
+ assumeRolePolicy = pulumi3.interpolate`{
9801
+ "Version": "2012-10-17",
9802
+ "Statement": [{
9803
+ "Effect": "Allow",
9804
+ "Principal": {
9805
+ "Federated": "${config2.oidcProvider.arn}"
9806
+ },
9807
+ "Action": "sts:AssumeRoleWithWebIdentity",
9808
+ "Condition": {
9809
+ "StringEquals": {
9810
+ "oidc.vercel.com/${config2.vercelTeamSlug}:aud": "https://vercel.com/${config2.vercelTeamSlug}"
9811
+ },
9812
+ "StringLike": {
9813
+ "oidc.vercel.com/${config2.vercelTeamSlug}:sub": "owner:${config2.vercelTeamSlug}:project:${config2.vercelProjectName}:environment:*"
9814
+ }
9815
+ }
9816
+ }]
9817
+ }`;
9818
+ }
9819
+ } else if (config2.provider === "aws") {
9820
+ assumeRolePolicy = pulumi3.output(`{
9821
+ "Version": "2012-10-17",
9822
+ "Statement": [{
9823
+ "Effect": "Allow",
9824
+ "Principal": {
9825
+ "Service": ["lambda.amazonaws.com", "ec2.amazonaws.com", "ecs-tasks.amazonaws.com"]
9826
+ },
9827
+ "Action": "sts:AssumeRole"
9828
+ }]
9829
+ }`);
9830
+ } else {
9831
+ throw new Error("Other providers not yet implemented");
9832
+ }
9833
+ const roleName = `wraps-${config2.serviceName}-role`;
9834
+ const exists = await roleExists(roleName);
9835
+ const tags = {
9836
+ ManagedBy: "wraps-cli",
9837
+ Provider: config2.provider,
9838
+ ...config2.extraTags
9839
+ };
9840
+ const role = exists ? new aws2.iam.Role(
9841
+ roleName,
9842
+ { name: roleName, assumeRolePolicy, tags },
9843
+ {
9844
+ import: roleName,
9845
+ ...config2.customTimeouts && {
9846
+ customTimeouts: config2.customTimeouts
9847
+ }
9848
+ }
9849
+ ) : new aws2.iam.Role(
9850
+ roleName,
9851
+ { name: roleName, assumeRolePolicy, tags },
9852
+ config2.customTimeouts ? { customTimeouts: config2.customTimeouts } : void 0
9853
+ );
9854
+ const policyName = `wraps-${config2.serviceName}-policy`;
9855
+ const isOutputStatements = pulumi3.Output.isInstance(config2.policyStatements);
9856
+ if (isOutputStatements) {
9857
+ new aws2.iam.RolePolicy(policyName, {
9858
+ role: role.name,
9859
+ policy: config2.policyStatements.apply(
9860
+ (stmts) => JSON.stringify({
9861
+ Version: "2012-10-17",
9862
+ Statement: stmts
9863
+ })
9864
+ )
9865
+ });
9866
+ } else {
9867
+ new aws2.iam.RolePolicy(policyName, {
9868
+ role: role.name,
9869
+ policy: JSON.stringify({
9870
+ Version: "2012-10-17",
9871
+ Statement: config2.policyStatements
9872
+ })
9873
+ });
9874
+ }
9875
+ return role;
9876
+ }
9754
9877
 
9755
9878
  // src/infrastructure/vercel-oidc.ts
9756
9879
  init_esm_shims();
9757
- import * as aws2 from "@pulumi/aws";
9880
+ import * as aws3 from "@pulumi/aws";
9758
9881
  async function getExistingOIDCProviderArn(url) {
9759
9882
  try {
9760
9883
  const { IAMClient: IAMClient4, ListOpenIDConnectProvidersCommand } = await import("@aws-sdk/client-iam");
9761
- const iam10 = new IAMClient4({
9884
+ const iam9 = new IAMClient4({
9762
9885
  region: process.env.AWS_REGION || "us-east-1"
9763
9886
  });
9764
- const response = await iam10.send(new ListOpenIDConnectProvidersCommand({}));
9887
+ const response = await iam9.send(new ListOpenIDConnectProvidersCommand({}));
9765
9888
  const expectedArnSuffix = url.replace("https://", "");
9766
9889
  const provider = response.OpenIDConnectProviderList?.find(
9767
9890
  (p) => p.Arn?.endsWith(expectedArnSuffix)
@@ -9776,7 +9899,7 @@ async function createVercelOIDC(config2) {
9776
9899
  const url = `https://oidc.vercel.com/${config2.teamSlug}`;
9777
9900
  const existingArn = await getExistingOIDCProviderArn(url);
9778
9901
  if (existingArn) {
9779
- return new aws2.iam.OpenIdConnectProvider(
9902
+ return new aws3.iam.OpenIdConnectProvider(
9780
9903
  "wraps-vercel-oidc",
9781
9904
  {
9782
9905
  url,
@@ -9797,7 +9920,7 @@ async function createVercelOIDC(config2) {
9797
9920
  }
9798
9921
  );
9799
9922
  }
9800
- return new aws2.iam.OpenIdConnectProvider("wraps-vercel-oidc", {
9923
+ return new aws3.iam.OpenIdConnectProvider("wraps-vercel-oidc", {
9801
9924
  url,
9802
9925
  clientIdLists: [`https://vercel.com/${config2.teamSlug}`],
9803
9926
  thumbprintLists: [
@@ -9814,104 +9937,46 @@ async function createVercelOIDC(config2) {
9814
9937
 
9815
9938
  // src/infrastructure/cdn-stack.ts
9816
9939
  async function createCdnIAMRole(config2) {
9817
- let assumeRolePolicy;
9818
- if (config2.provider === "vercel" && config2.oidcProvider) {
9819
- assumeRolePolicy = pulumi3.interpolate`{
9820
- "Version": "2012-10-17",
9821
- "Statement": [{
9822
- "Effect": "Allow",
9823
- "Principal": {
9824
- "Federated": "${config2.oidcProvider.arn}"
9825
- },
9826
- "Action": "sts:AssumeRoleWithWebIdentity",
9827
- "Condition": {
9828
- "StringEquals": {
9829
- "oidc.vercel.com/${config2.vercelTeamSlug}:aud": "https://vercel.com/${config2.vercelTeamSlug}"
9830
- },
9831
- "StringLike": {
9832
- "oidc.vercel.com/${config2.vercelTeamSlug}:sub": "owner:${config2.vercelTeamSlug}:project:${config2.vercelProjectName}:environment:*"
9833
- }
9834
- }
9835
- }]
9836
- }`;
9837
- } else if (config2.provider === "aws") {
9838
- assumeRolePolicy = pulumi3.output(`{
9839
- "Version": "2012-10-17",
9840
- "Statement": [{
9841
- "Effect": "Allow",
9842
- "Principal": {
9843
- "Service": ["lambda.amazonaws.com", "ec2.amazonaws.com", "ecs-tasks.amazonaws.com"]
9844
- },
9845
- "Action": "sts:AssumeRole"
9846
- }]
9847
- }`);
9848
- } else {
9849
- throw new Error("Other providers not yet implemented");
9850
- }
9851
- const roleName = "wraps-cdn-role";
9852
- const exists = await roleExists(roleName);
9853
- const role = exists ? new aws3.iam.Role(
9854
- roleName,
9855
- {
9856
- name: roleName,
9857
- assumeRolePolicy,
9858
- tags: {
9859
- ManagedBy: "wraps-cli",
9860
- Service: "cdn",
9861
- Provider: config2.provider
9940
+ const resolvedStatements = pulumi4.all([config2.bucketArn, config2.distributionArn]).apply(([bucketArn, distributionArn]) => {
9941
+ const statements = [
9942
+ {
9943
+ Sid: "StorageBucketAccess",
9944
+ Effect: "Allow",
9945
+ Action: [
9946
+ "s3:PutObject",
9947
+ "s3:GetObject",
9948
+ "s3:DeleteObject",
9949
+ "s3:ListBucket",
9950
+ "s3:GetBucketLocation",
9951
+ "s3:GetObjectTagging",
9952
+ "s3:PutObjectTagging"
9953
+ ],
9954
+ Resource: [bucketArn, `${bucketArn}/*`]
9862
9955
  }
9863
- },
9864
- {
9865
- import: roleName
9866
- }
9867
- ) : new aws3.iam.Role(roleName, {
9868
- name: roleName,
9869
- assumeRolePolicy,
9870
- tags: {
9871
- ManagedBy: "wraps-cli",
9872
- Service: "cdn",
9873
- Provider: config2.provider
9956
+ ];
9957
+ if (distributionArn) {
9958
+ statements.push({
9959
+ Sid: "CloudFrontInvalidation",
9960
+ Effect: "Allow",
9961
+ Action: [
9962
+ "cloudfront:CreateInvalidation",
9963
+ "cloudfront:GetInvalidation",
9964
+ "cloudfront:ListInvalidations"
9965
+ ],
9966
+ Resource: distributionArn
9967
+ });
9874
9968
  }
9969
+ return statements;
9875
9970
  });
9876
- const statements = [
9877
- // S3 bucket access
9878
- {
9879
- Sid: "StorageBucketAccess",
9880
- Effect: "Allow",
9881
- Action: [
9882
- "s3:PutObject",
9883
- "s3:GetObject",
9884
- "s3:DeleteObject",
9885
- "s3:ListBucket",
9886
- "s3:GetBucketLocation",
9887
- "s3:GetObjectTagging",
9888
- "s3:PutObjectTagging"
9889
- ],
9890
- Resource: [config2.bucketArn, pulumi3.interpolate`${config2.bucketArn}/*`]
9891
- }
9892
- ];
9893
- if (config2.distributionArn) {
9894
- statements.push({
9895
- Sid: "CloudFrontInvalidation",
9896
- Effect: "Allow",
9897
- Action: [
9898
- "cloudfront:CreateInvalidation",
9899
- "cloudfront:GetInvalidation",
9900
- "cloudfront:ListInvalidations"
9901
- ],
9902
- Resource: config2.distributionArn
9903
- });
9904
- }
9905
- new aws3.iam.RolePolicy("wraps-cdn-policy", {
9906
- role: role.name,
9907
- policy: pulumi3.all([statements]).apply(
9908
- ([stmts]) => JSON.stringify({
9909
- Version: "2012-10-17",
9910
- Statement: stmts
9911
- })
9912
- )
9971
+ return createServiceIAMRole({
9972
+ serviceName: "cdn",
9973
+ provider: config2.provider,
9974
+ oidcProvider: config2.oidcProvider,
9975
+ vercelTeamSlug: config2.vercelTeamSlug,
9976
+ vercelProjectName: config2.vercelProjectName,
9977
+ policyStatements: resolvedStatements,
9978
+ extraTags: { Service: "cdn" }
9913
9979
  });
9914
- return role;
9915
9980
  }
9916
9981
  async function deployCdnStack(config2) {
9917
9982
  const accountId = config2.accountId;
@@ -9943,7 +10008,7 @@ async function deployCdnStack(config2) {
9943
10008
  if (config2.cdnConfig.cdn.enabled) {
9944
10009
  const hasAutoValidation2 = acmResources?.certificateValidation;
9945
10010
  const useCertFromUpgrade = config2.certValidated && config2.existingCertArn;
9946
- const certificateArn = useCertFromUpgrade ? pulumi3.output(config2.existingCertArn) : hasAutoValidation2 ? acmResources?.certificateValidation?.certificateArn : void 0;
10011
+ const certificateArn = useCertFromUpgrade ? pulumi4.output(config2.existingCertArn) : hasAutoValidation2 ? acmResources?.certificateValidation?.certificateArn : void 0;
9947
10012
  const customDomainForCdn = useCertFromUpgrade || hasAutoValidation2 ? config2.cdnConfig.cdn.customDomain : void 0;
9948
10013
  cdnResources = await createCdnDistribution({
9949
10014
  bucket: bucketResources.bucket,
@@ -10529,7 +10594,7 @@ ${pc11.yellow(pc11.bold("Configuration Notes:"))}`);
10529
10594
  "Generating infrastructure preview",
10530
10595
  async () => {
10531
10596
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
10532
- const stack = await pulumi4.automation.LocalWorkspace.createOrSelectStack(
10597
+ const stack = await pulumi5.automation.LocalWorkspace.createOrSelectStack(
10533
10598
  {
10534
10599
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
10535
10600
  projectName: "wraps-cdn",
@@ -10594,7 +10659,7 @@ ${pc11.yellow(pc11.bold("Configuration Notes:"))}`);
10594
10659
  "Deploying CDN infrastructure (this may take 2-3 minutes)",
10595
10660
  async () => {
10596
10661
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
10597
- const stack = await pulumi4.automation.LocalWorkspace.createOrSelectStack(
10662
+ const stack = await pulumi5.automation.LocalWorkspace.createOrSelectStack(
10598
10663
  {
10599
10664
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
10600
10665
  projectName: "wraps-cdn",
@@ -10929,7 +10994,7 @@ init_aws();
10929
10994
  init_fs();
10930
10995
  init_metadata();
10931
10996
  import * as clack11 from "@clack/prompts";
10932
- import * as pulumi5 from "@pulumi/pulumi";
10997
+ import * as pulumi6 from "@pulumi/pulumi";
10933
10998
  import pc12 from "picocolors";
10934
10999
  async function cdnStatus(options) {
10935
11000
  const startTime = Date.now();
@@ -10965,7 +11030,7 @@ async function cdnStatus(options) {
10965
11030
  let stackOutputs = {};
10966
11031
  try {
10967
11032
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
10968
- const stack = await pulumi5.automation.LocalWorkspace.selectStack({
11033
+ const stack = await pulumi6.automation.LocalWorkspace.selectStack({
10969
11034
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
10970
11035
  workDir: getPulumiWorkDir()
10971
11036
  });
@@ -11087,7 +11152,7 @@ ${pc12.bold("Commands:")}`);
11087
11152
  // src/commands/cdn/sync.ts
11088
11153
  init_esm_shims();
11089
11154
  import * as clack12 from "@clack/prompts";
11090
- import * as pulumi6 from "@pulumi/pulumi";
11155
+ import * as pulumi7 from "@pulumi/pulumi";
11091
11156
  import pc13 from "picocolors";
11092
11157
  init_client();
11093
11158
  init_events();
@@ -11143,7 +11208,7 @@ async function cdnSync(options) {
11143
11208
  if (cdnConfig.cdn.customDomain) {
11144
11209
  try {
11145
11210
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
11146
- const checkStack = await pulumi6.automation.LocalWorkspace.selectStack({
11211
+ const checkStack = await pulumi7.automation.LocalWorkspace.selectStack({
11147
11212
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
11148
11213
  workDir: getPulumiWorkDir()
11149
11214
  });
@@ -11180,7 +11245,7 @@ async function cdnSync(options) {
11180
11245
  try {
11181
11246
  await progress.execute("Syncing CDN infrastructure", async () => {
11182
11247
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
11183
- const stack = await pulumi6.automation.LocalWorkspace.createOrSelectStack(
11248
+ const stack = await pulumi7.automation.LocalWorkspace.createOrSelectStack(
11184
11249
  {
11185
11250
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
11186
11251
  projectName: "wraps-cdn",
@@ -11242,7 +11307,7 @@ async function cdnSync(options) {
11242
11307
  // src/commands/cdn/upgrade.ts
11243
11308
  init_esm_shims();
11244
11309
  import * as clack13 from "@clack/prompts";
11245
- import * as pulumi7 from "@pulumi/pulumi";
11310
+ import * as pulumi8 from "@pulumi/pulumi";
11246
11311
  import pc14 from "picocolors";
11247
11312
  init_client();
11248
11313
  init_events();
@@ -11298,7 +11363,7 @@ async function cdnUpgrade(options) {
11298
11363
  let stackOutputs = {};
11299
11364
  try {
11300
11365
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
11301
- const stack = await pulumi7.automation.LocalWorkspace.selectStack({
11366
+ const stack = await pulumi8.automation.LocalWorkspace.selectStack({
11302
11367
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
11303
11368
  workDir: getPulumiWorkDir()
11304
11369
  });
@@ -11436,7 +11501,7 @@ Ready to add custom domain: ${pc14.cyan(pendingDomain)}`);
11436
11501
  "Updating CloudFront distribution (this may take 2-3 minutes)",
11437
11502
  async () => {
11438
11503
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
11439
- const stack = await pulumi7.automation.LocalWorkspace.createOrSelectStack(
11504
+ const stack = await pulumi8.automation.LocalWorkspace.createOrSelectStack(
11440
11505
  {
11441
11506
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
11442
11507
  projectName: "wraps-cdn",
@@ -11524,7 +11589,7 @@ init_aws();
11524
11589
  init_fs();
11525
11590
  init_metadata();
11526
11591
  import * as clack14 from "@clack/prompts";
11527
- import * as pulumi8 from "@pulumi/pulumi";
11592
+ import * as pulumi9 from "@pulumi/pulumi";
11528
11593
  import pc15 from "picocolors";
11529
11594
  async function checkDNSRecord(hostname, expectedValue) {
11530
11595
  try {
@@ -11607,7 +11672,7 @@ async function cdnVerify(options) {
11607
11672
  let stackOutputs = {};
11608
11673
  try {
11609
11674
  await ensurePulumiWorkDir({ accountId: identity.accountId, region });
11610
- const stack = await pulumi8.automation.LocalWorkspace.selectStack({
11675
+ const stack = await pulumi9.automation.LocalWorkspace.selectStack({
11611
11676
  stackName: `wraps-cdn-${identity.accountId}-${region}`,
11612
11677
  workDir: getPulumiWorkDir()
11613
11678
  });
@@ -14754,7 +14819,7 @@ import pc17 from "picocolors";
14754
14819
  // src/infrastructure/email-stack.ts
14755
14820
  init_esm_shims();
14756
14821
  init_dist();
14757
- import * as aws18 from "@pulumi/aws";
14822
+ import * as aws17 from "@pulumi/aws";
14758
14823
 
14759
14824
  // src/infrastructure/resources/alerting.ts
14760
14825
  init_esm_shims();
@@ -15022,7 +15087,7 @@ async function createDynamoDBTables(_config) {
15022
15087
  // src/infrastructure/resources/eventbridge.ts
15023
15088
  init_esm_shims();
15024
15089
  import * as aws6 from "@pulumi/aws";
15025
- import * as pulumi9 from "@pulumi/pulumi";
15090
+ import * as pulumi10 from "@pulumi/pulumi";
15026
15091
  async function createEventBridgeResources(config2) {
15027
15092
  const eventBusName = config2.eventBusArn.apply((arn) => arn.split("/").pop());
15028
15093
  const rule = new aws6.cloudwatch.EventRule("wraps-email-events-rule", {
@@ -15040,7 +15105,7 @@ async function createEventBridgeResources(config2) {
15040
15105
  });
15041
15106
  new aws6.sqs.QueuePolicy("wraps-email-events-queue-policy", {
15042
15107
  queueUrl: config2.queueUrl,
15043
- policy: pulumi9.all([config2.queueArn, rule.arn]).apply(
15108
+ policy: pulumi10.all([config2.queueArn, rule.arn]).apply(
15044
15109
  ([queueArn, ruleArn]) => JSON.stringify({
15045
15110
  Version: "2012-10-17",
15046
15111
  Statement: [
@@ -15149,68 +15214,7 @@ async function createEventBridgeResources(config2) {
15149
15214
 
15150
15215
  // src/infrastructure/resources/iam.ts
15151
15216
  init_esm_shims();
15152
- init_resource_checks();
15153
- import * as aws7 from "@pulumi/aws";
15154
- import * as pulumi10 from "@pulumi/pulumi";
15155
15217
  async function createIAMRole(config2) {
15156
- let assumeRolePolicy;
15157
- if (config2.provider === "vercel" && config2.oidcProvider) {
15158
- assumeRolePolicy = pulumi10.interpolate`{
15159
- "Version": "2012-10-17",
15160
- "Statement": [{
15161
- "Effect": "Allow",
15162
- "Principal": {
15163
- "Federated": "${config2.oidcProvider.arn}"
15164
- },
15165
- "Action": "sts:AssumeRoleWithWebIdentity",
15166
- "Condition": {
15167
- "StringEquals": {
15168
- "oidc.vercel.com/${config2.vercelTeamSlug}:aud": "https://vercel.com/${config2.vercelTeamSlug}"
15169
- },
15170
- "StringLike": {
15171
- "oidc.vercel.com/${config2.vercelTeamSlug}:sub": "owner:${config2.vercelTeamSlug}:project:${config2.vercelProjectName}:environment:*"
15172
- }
15173
- }
15174
- }]
15175
- }`;
15176
- } else if (config2.provider === "aws") {
15177
- assumeRolePolicy = pulumi10.output(`{
15178
- "Version": "2012-10-17",
15179
- "Statement": [{
15180
- "Effect": "Allow",
15181
- "Principal": {
15182
- "Service": ["lambda.amazonaws.com", "ec2.amazonaws.com", "ecs-tasks.amazonaws.com"]
15183
- },
15184
- "Action": "sts:AssumeRole"
15185
- }]
15186
- }`);
15187
- } else {
15188
- throw new Error("Other providers not yet implemented");
15189
- }
15190
- const roleName = "wraps-email-role";
15191
- const exists = await roleExists(roleName);
15192
- const role = exists ? new aws7.iam.Role(
15193
- roleName,
15194
- {
15195
- name: roleName,
15196
- assumeRolePolicy,
15197
- tags: {
15198
- ManagedBy: "wraps-cli",
15199
- Provider: config2.provider
15200
- }
15201
- },
15202
- {
15203
- import: roleName
15204
- // Import existing role (use role name, not ARN)
15205
- }
15206
- ) : new aws7.iam.Role(roleName, {
15207
- name: roleName,
15208
- assumeRolePolicy,
15209
- tags: {
15210
- ManagedBy: "wraps-cli",
15211
- Provider: config2.provider
15212
- }
15213
- });
15214
15218
  const statements = [];
15215
15219
  statements.push({
15216
15220
  Effect: "Allow",
@@ -15316,14 +15320,14 @@ async function createIAMRole(config2) {
15316
15320
  Resource: "arn:aws:ses:*:*:mailmanager-archive/*"
15317
15321
  });
15318
15322
  }
15319
- new aws7.iam.RolePolicy("wraps-email-policy", {
15320
- role: role.name,
15321
- policy: JSON.stringify({
15322
- Version: "2012-10-17",
15323
- Statement: statements
15324
- })
15323
+ return createServiceIAMRole({
15324
+ serviceName: "email",
15325
+ provider: config2.provider,
15326
+ oidcProvider: config2.oidcProvider,
15327
+ vercelTeamSlug: config2.vercelTeamSlug,
15328
+ vercelProjectName: config2.vercelProjectName,
15329
+ policyStatements: statements
15325
15330
  });
15326
- return role;
15327
15331
  }
15328
15332
 
15329
15333
  // src/infrastructure/email-stack.ts
@@ -15331,7 +15335,7 @@ init_lambda();
15331
15335
 
15332
15336
  // src/infrastructure/resources/ses.ts
15333
15337
  init_esm_shims();
15334
- import * as aws9 from "@pulumi/aws";
15338
+ import * as aws8 from "@pulumi/aws";
15335
15339
  async function configurationSetExists(configSetName, region) {
15336
15340
  try {
15337
15341
  const { SESv2Client: SESv2Client6, GetConfigurationSetCommand: GetConfigurationSetCommand2 } = await import("@aws-sdk/client-sesv2");
@@ -15341,7 +15345,7 @@ async function configurationSetExists(configSetName, region) {
15341
15345
  );
15342
15346
  return true;
15343
15347
  } catch (error) {
15344
- if (error.name === "NotFoundException") {
15348
+ if (error instanceof Error && error.name === "NotFoundException") {
15345
15349
  return false;
15346
15350
  }
15347
15351
  console.error("Error checking for existing configuration set:", error);
@@ -15359,7 +15363,7 @@ async function eventDestinationExists(configSetName, eventDestName, region) {
15359
15363
  );
15360
15364
  return response.EventDestinations?.some((dest) => dest.Name === eventDestName) ?? false;
15361
15365
  } catch (error) {
15362
- if (error.name === "NotFoundException") {
15366
+ if (error instanceof Error && error.name === "NotFoundException") {
15363
15367
  return false;
15364
15368
  }
15365
15369
  return false;
@@ -15374,7 +15378,7 @@ async function emailIdentityExists(emailIdentity, region) {
15374
15378
  );
15375
15379
  return true;
15376
15380
  } catch (error) {
15377
- if (error.name === "NotFoundException") {
15381
+ if (error instanceof Error && error.name === "NotFoundException") {
15378
15382
  return false;
15379
15383
  }
15380
15384
  console.error("Error checking for existing email identity:", error);
@@ -15409,16 +15413,16 @@ async function createSESResources(config2) {
15409
15413
  }
15410
15414
  const configSetName = "wraps-email-tracking";
15411
15415
  const exists = await configurationSetExists(configSetName, config2.region);
15412
- const configSet = exists ? new aws9.sesv2.ConfigurationSet(configSetName, configSetOptions, {
15416
+ const configSet = exists ? new aws8.sesv2.ConfigurationSet(configSetName, configSetOptions, {
15413
15417
  import: configSetName
15414
15418
  // Import existing configuration set
15415
- }) : new aws9.sesv2.ConfigurationSet(configSetName, configSetOptions);
15416
- const defaultEventBus = aws9.cloudwatch.getEventBusOutput({
15419
+ }) : new aws8.sesv2.ConfigurationSet(configSetName, configSetOptions);
15420
+ const defaultEventBus = aws8.cloudwatch.getEventBusOutput({
15417
15421
  name: "default"
15418
15422
  });
15419
15423
  if (config2.eventTrackingEnabled) {
15420
15424
  const eventDestName = "wraps-email-eventbridge";
15421
- new aws9.sesv2.ConfigurationSetEventDestination(
15425
+ new aws8.sesv2.ConfigurationSetEventDestination(
15422
15426
  "wraps-email-all-events",
15423
15427
  {
15424
15428
  configurationSetName: configSet.configurationSetName,
@@ -15458,7 +15462,7 @@ async function createSESResources(config2) {
15458
15462
  config2.domain,
15459
15463
  config2.region
15460
15464
  );
15461
- domainIdentity = identityExists ? new aws9.sesv2.EmailIdentity(
15465
+ domainIdentity = identityExists ? new aws8.sesv2.EmailIdentity(
15462
15466
  "wraps-email-domain",
15463
15467
  {
15464
15468
  emailIdentity: config2.domain,
@@ -15475,7 +15479,7 @@ async function createSESResources(config2) {
15475
15479
  import: config2.domain
15476
15480
  // Import existing identity
15477
15481
  }
15478
- ) : new aws9.sesv2.EmailIdentity("wraps-email-domain", {
15482
+ ) : new aws8.sesv2.EmailIdentity("wraps-email-domain", {
15479
15483
  emailIdentity: config2.domain,
15480
15484
  configurationSetName: configSet.configurationSetName,
15481
15485
  // Link configuration set to domain
@@ -15491,7 +15495,7 @@ async function createSESResources(config2) {
15491
15495
  );
15492
15496
  if (config2.mailFromDomain) {
15493
15497
  mailFromDomain = config2.mailFromDomain;
15494
- new aws9.sesv2.EmailIdentityMailFromAttributes(
15498
+ new aws8.sesv2.EmailIdentityMailFromAttributes(
15495
15499
  "wraps-email-mail-from",
15496
15500
  {
15497
15501
  emailIdentity: config2.domain,
@@ -15522,7 +15526,7 @@ async function createSESResources(config2) {
15522
15526
  // src/infrastructure/resources/smtp-credentials.ts
15523
15527
  init_esm_shims();
15524
15528
  import { createHmac as createHmac2 } from "crypto";
15525
- import * as aws10 from "@pulumi/aws";
15529
+ import * as aws9 from "@pulumi/aws";
15526
15530
  function convertToSMTPPassword2(secretAccessKey, region) {
15527
15531
  const DATE = "11111111";
15528
15532
  const SERVICE = "ses";
@@ -15543,13 +15547,13 @@ function convertToSMTPPassword2(secretAccessKey, region) {
15543
15547
  async function userExists(userName) {
15544
15548
  try {
15545
15549
  const { IAMClient: IAMClient4, GetUserCommand } = await import("@aws-sdk/client-iam");
15546
- const iam10 = new IAMClient4({
15550
+ const iam9 = new IAMClient4({
15547
15551
  region: process.env.AWS_REGION || "us-east-1"
15548
15552
  });
15549
- await iam10.send(new GetUserCommand({ UserName: userName }));
15553
+ await iam9.send(new GetUserCommand({ UserName: userName }));
15550
15554
  return true;
15551
15555
  } catch (error) {
15552
- if (error.name === "NoSuchEntityException" || error.Code === "NoSuchEntity") {
15556
+ if (error instanceof Error && (error.name === "NoSuchEntityException" || error.Code === "NoSuchEntity")) {
15553
15557
  return false;
15554
15558
  }
15555
15559
  return false;
@@ -15558,7 +15562,7 @@ async function userExists(userName) {
15558
15562
  async function createSMTPCredentials(config2) {
15559
15563
  const userName = "wraps-email-smtp-user";
15560
15564
  const userAlreadyExists = await userExists(userName);
15561
- const iamUser = userAlreadyExists ? new aws10.iam.User(
15565
+ const iamUser = userAlreadyExists ? new aws9.iam.User(
15562
15566
  userName,
15563
15567
  {
15564
15568
  name: userName,
@@ -15568,14 +15572,14 @@ async function createSMTPCredentials(config2) {
15568
15572
  }
15569
15573
  },
15570
15574
  { import: userName }
15571
- ) : new aws10.iam.User(userName, {
15575
+ ) : new aws9.iam.User(userName, {
15572
15576
  name: userName,
15573
15577
  tags: {
15574
15578
  ManagedBy: "wraps-cli",
15575
15579
  Purpose: "SES SMTP Authentication"
15576
15580
  }
15577
15581
  });
15578
- new aws10.iam.UserPolicy("wraps-email-smtp-policy", {
15582
+ new aws9.iam.UserPolicy("wraps-email-smtp-policy", {
15579
15583
  user: iamUser.name,
15580
15584
  policy: JSON.stringify({
15581
15585
  Version: "2012-10-17",
@@ -15593,7 +15597,7 @@ async function createSMTPCredentials(config2) {
15593
15597
  ]
15594
15598
  })
15595
15599
  });
15596
- const accessKey = new aws10.iam.AccessKey("wraps-email-smtp-key", {
15600
+ const accessKey = new aws9.iam.AccessKey("wraps-email-smtp-key", {
15597
15601
  user: iamUser.name
15598
15602
  });
15599
15603
  const smtpPassword = accessKey.secret.apply(
@@ -15608,9 +15612,9 @@ async function createSMTPCredentials(config2) {
15608
15612
 
15609
15613
  // src/infrastructure/resources/sqs.ts
15610
15614
  init_esm_shims();
15611
- import * as aws11 from "@pulumi/aws";
15615
+ import * as aws10 from "@pulumi/aws";
15612
15616
  async function createSQSResources() {
15613
- const dlq = new aws11.sqs.Queue("wraps-email-events-dlq", {
15617
+ const dlq = new aws10.sqs.Queue("wraps-email-events-dlq", {
15614
15618
  name: "wraps-email-events-dlq",
15615
15619
  messageRetentionSeconds: 1209600,
15616
15620
  // 14 days
@@ -15619,7 +15623,7 @@ async function createSQSResources() {
15619
15623
  Description: "Dead letter queue for failed SES event processing"
15620
15624
  }
15621
15625
  });
15622
- const queue = new aws11.sqs.Queue("wraps-email-events", {
15626
+ const queue = new aws10.sqs.Queue("wraps-email-events", {
15623
15627
  name: "wraps-email-events",
15624
15628
  visibilityTimeoutSeconds: 60,
15625
15629
  // Must be >= Lambda timeout
@@ -15647,7 +15651,7 @@ async function createSQSResources() {
15647
15651
 
15648
15652
  // src/infrastructure/email-stack.ts
15649
15653
  async function deployEmailStack(config2) {
15650
- const identity = await aws18.getCallerIdentity();
15654
+ const identity = await aws17.getCallerIdentity();
15651
15655
  const accountId = identity.accountId;
15652
15656
  let oidcProvider;
15653
15657
  if (config2.provider === "vercel" && config2.vercel) {
@@ -15810,7 +15814,7 @@ async function deployEmailStack(config2) {
15810
15814
  region: config2.region,
15811
15815
  dlqArn: sqsInbound.dlq.arn
15812
15816
  });
15813
- new aws18.s3.BucketNotification(
15817
+ new aws17.s3.BucketNotification(
15814
15818
  "wraps-inbound-s3-notification",
15815
15819
  {
15816
15820
  bucket: s3Inbound.bucket.id,
@@ -16200,7 +16204,10 @@ async function scanSESIdentities(region) {
16200
16204
  }
16201
16205
  return identities;
16202
16206
  } catch (error) {
16203
- console.error("Error scanning SES identities:", error.message);
16207
+ console.error(
16208
+ "Error scanning SES identities:",
16209
+ error instanceof Error ? error.message : error
16210
+ );
16204
16211
  return [];
16205
16212
  }
16206
16213
  }
@@ -16227,12 +16234,18 @@ async function scanSESConfigurationSets(region) {
16227
16234
  eventDestinations
16228
16235
  });
16229
16236
  } catch (error) {
16230
- console.error(`Error describing config set ${name}:`, error.message);
16237
+ console.error(
16238
+ `Error describing config set ${name}:`,
16239
+ error instanceof Error ? error.message : error
16240
+ );
16231
16241
  }
16232
16242
  }
16233
16243
  return configSets;
16234
16244
  } catch (error) {
16235
- console.error("Error scanning SES configuration sets:", error.message);
16245
+ console.error(
16246
+ "Error scanning SES configuration sets:",
16247
+ error instanceof Error ? error.message : error
16248
+ );
16236
16249
  return [];
16237
16250
  }
16238
16251
  }
@@ -16260,13 +16273,16 @@ async function scanSNSTopics(region) {
16260
16273
  } catch (error) {
16261
16274
  console.error(
16262
16275
  `Error getting topic attributes for ${arn}:`,
16263
- error.message
16276
+ error instanceof Error ? error.message : error
16264
16277
  );
16265
16278
  }
16266
16279
  }
16267
16280
  return topics;
16268
16281
  } catch (error) {
16269
- console.error("Error scanning SNS topics:", error.message);
16282
+ console.error(
16283
+ "Error scanning SNS topics:",
16284
+ error instanceof Error ? error.message : error
16285
+ );
16270
16286
  return [];
16271
16287
  }
16272
16288
  }
@@ -16291,12 +16307,18 @@ async function scanDynamoTables(region) {
16291
16307
  });
16292
16308
  }
16293
16309
  } catch (error) {
16294
- console.error(`Error describing table ${name}:`, error.message);
16310
+ console.error(
16311
+ `Error describing table ${name}:`,
16312
+ error instanceof Error ? error.message : error
16313
+ );
16295
16314
  }
16296
16315
  }
16297
16316
  return tables;
16298
16317
  } catch (error) {
16299
- console.error("Error scanning DynamoDB tables:", error.message);
16318
+ console.error(
16319
+ "Error scanning DynamoDB tables:",
16320
+ error instanceof Error ? error.message : error
16321
+ );
16300
16322
  return [];
16301
16323
  }
16302
16324
  }
@@ -16318,18 +16340,21 @@ async function scanLambdaFunctions(region) {
16318
16340
  }
16319
16341
  return functions;
16320
16342
  } catch (error) {
16321
- console.error("Error scanning Lambda functions:", error.message);
16343
+ console.error(
16344
+ "Error scanning Lambda functions:",
16345
+ error instanceof Error ? error.message : error
16346
+ );
16322
16347
  return [];
16323
16348
  }
16324
16349
  }
16325
16350
  async function scanIAMRoles(region) {
16326
- const iam10 = new IAMClient({ region });
16351
+ const iam9 = new IAMClient({ region });
16327
16352
  const roles = [];
16328
16353
  try {
16329
16354
  let marker;
16330
16355
  let hasMore = true;
16331
16356
  while (hasMore) {
16332
- const listResponse = await iam10.send(
16357
+ const listResponse = await iam9.send(
16333
16358
  new ListRolesCommand({
16334
16359
  Marker: marker,
16335
16360
  MaxItems: 100
@@ -16350,7 +16375,10 @@ async function scanIAMRoles(region) {
16350
16375
  }
16351
16376
  return roles;
16352
16377
  } catch (error) {
16353
- console.error("Error scanning IAM roles:", error.message);
16378
+ console.error(
16379
+ "Error scanning IAM roles:",
16380
+ error instanceof Error ? error.message : error
16381
+ );
16354
16382
  return [];
16355
16383
  }
16356
16384
  }
@@ -16757,7 +16785,7 @@ async function getEmailIdentityInfo(domain, region) {
16757
16785
  mailFromDomain: response.MailFromAttributes?.MailFromDomain
16758
16786
  };
16759
16787
  } catch (error) {
16760
- if (isAWSError(error)) {
16788
+ if (isAWSNotFoundError(error)) {
16761
16789
  return { dkimTokens: [] };
16762
16790
  }
16763
16791
  throw error;
@@ -17549,11 +17577,11 @@ Run ${pc20.cyan("wraps email domains add")} to add a domain.
17549
17577
  verified: details.VerifiedForSendingStatus,
17550
17578
  dkimStatus: details.DkimAttributes?.Status || "PENDING"
17551
17579
  };
17552
- } catch {
17580
+ } catch (error) {
17553
17581
  return {
17554
17582
  name: domain.IdentityName,
17555
17583
  verified: false,
17556
- dkimStatus: "UNKNOWN"
17584
+ dkimStatus: isAWSNotFoundError(error) ? "UNKNOWN" : "ERROR"
17557
17585
  };
17558
17586
  }
17559
17587
  })
@@ -19415,7 +19443,7 @@ Run ${pc24.cyan("wraps email init")} to deploy email infrastructure.
19415
19443
  purpose: tracked?.purpose
19416
19444
  };
19417
19445
  } catch (error) {
19418
- if (isAWSError(error)) {
19446
+ if (isAWSNotFoundError(error)) {
19419
19447
  return {
19420
19448
  domain: d.domain,
19421
19449
  status: d.verified ? "verified" : "pending",
@@ -22459,9 +22487,9 @@ ${pc28.green("\u2713")} ${pc28.bold("Upgrade complete!")}
22459
22487
  iamUserArn: outputs.smtpUserArn,
22460
22488
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
22461
22489
  };
22462
- await saveConnectionMetadata(metadata);
22463
22490
  }
22464
22491
  }
22492
+ await saveConnectionMetadata(metadata);
22465
22493
  const enabledFeatures = [];
22466
22494
  if (updatedConfig.tracking?.enabled) {
22467
22495
  enabledFeatures.push("tracking");
@@ -24574,10 +24602,10 @@ async function deployEventBridge(metadata, region, identity, webhookSecret, prog
24574
24602
  var WRAPS_PLATFORM_ACCOUNT_ID = "905130073023";
24575
24603
  async function updatePlatformRole(metadata, progress, externalId) {
24576
24604
  const roleName = "wraps-console-access-role";
24577
- const iam10 = new IAMClient2({ region: "us-east-1" });
24605
+ const iam9 = new IAMClient2({ region: "us-east-1" });
24578
24606
  let roleExists2 = false;
24579
24607
  try {
24580
- await iam10.send(new GetRoleCommand({ RoleName: roleName }));
24608
+ await iam9.send(new GetRoleCommand({ RoleName: roleName }));
24581
24609
  roleExists2 = true;
24582
24610
  } catch (error) {
24583
24611
  const isNotFound = error instanceof Error && (error.name === "NoSuchEntityException" || error.name === "NoSuchEntity" || error.message.includes("NoSuchEntity"));
@@ -24590,7 +24618,7 @@ async function updatePlatformRole(metadata, progress, externalId) {
24590
24618
  const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
24591
24619
  if (roleExists2) {
24592
24620
  await progress.execute("Updating platform access role", async () => {
24593
- await iam10.send(
24621
+ await iam9.send(
24594
24622
  new PutRolePolicyCommand({
24595
24623
  RoleName: roleName,
24596
24624
  PolicyName: "wraps-console-access-policy",
@@ -24618,7 +24646,7 @@ async function updatePlatformRole(metadata, progress, externalId) {
24618
24646
  }
24619
24647
  ]
24620
24648
  };
24621
- await iam10.send(
24649
+ await iam9.send(
24622
24650
  new CreateRoleCommand({
24623
24651
  RoleName: roleName,
24624
24652
  Description: "Allows Wraps dashboard to access CloudWatch metrics and SES data",
@@ -24629,7 +24657,7 @@ async function updatePlatformRole(metadata, progress, externalId) {
24629
24657
  ]
24630
24658
  })
24631
24659
  );
24632
- await iam10.send(
24660
+ await iam9.send(
24633
24661
  new PutRolePolicyCommand({
24634
24662
  RoleName: roleName,
24635
24663
  PolicyName: "wraps-console-access-policy",
@@ -25045,10 +25073,10 @@ Run ${pc33.cyan("wraps email init")} or ${pc33.cyan("wraps sms init")} first.
25045
25073
  progress.succeed("Event streaming already configured");
25046
25074
  }
25047
25075
  const roleName = "wraps-console-access-role";
25048
- const iam10 = new IAMClient2({ region: "us-east-1" });
25076
+ const iam9 = new IAMClient2({ region: "us-east-1" });
25049
25077
  let roleExists2 = false;
25050
25078
  try {
25051
- await iam10.send(new GetRoleCommand({ RoleName: roleName }));
25079
+ await iam9.send(new GetRoleCommand({ RoleName: roleName }));
25052
25080
  roleExists2 = true;
25053
25081
  } catch (error) {
25054
25082
  const isNotFound = error instanceof Error && (error.name === "NoSuchEntityException" || error.name === "NoSuchEntity" || error.message.includes("NoSuchEntity"));
@@ -25061,7 +25089,7 @@ Run ${pc33.cyan("wraps email init")} or ${pc33.cyan("wraps sms init")} first.
25061
25089
  const smsConfig = metadata.services.sms?.config;
25062
25090
  const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
25063
25091
  await progress.execute("Updating platform access role", async () => {
25064
- await iam10.send(
25092
+ await iam9.send(
25065
25093
  new PutRolePolicyCommand({
25066
25094
  RoleName: roleName,
25067
25095
  PolicyName: "wraps-console-access-policy",
@@ -25212,10 +25240,10 @@ Run ${pc35.cyan("wraps email init")} to deploy infrastructure first.
25212
25240
  process.exit(1);
25213
25241
  }
25214
25242
  const roleName = "wraps-console-access-role";
25215
- const iam10 = new IAMClient3({ region: "us-east-1" });
25243
+ const iam9 = new IAMClient3({ region: "us-east-1" });
25216
25244
  let roleExists2 = false;
25217
25245
  try {
25218
- await iam10.send(new GetRoleCommand2({ RoleName: roleName }));
25246
+ await iam9.send(new GetRoleCommand2({ RoleName: roleName }));
25219
25247
  roleExists2 = true;
25220
25248
  } catch (error) {
25221
25249
  const isNotFound = error instanceof Error && (error.name === "NoSuchEntityException" || error.name === "NoSuchEntity" || error.message.includes("NoSuchEntity"));
@@ -25284,7 +25312,7 @@ Run ${pc35.cyan("wraps email init")} to deploy infrastructure first.
25284
25312
  }
25285
25313
  ]
25286
25314
  };
25287
- await iam10.send(
25315
+ await iam9.send(
25288
25316
  new CreateRoleCommand2({
25289
25317
  RoleName: roleName,
25290
25318
  Description: "Allows Wraps dashboard to access CloudWatch metrics and SES data",
@@ -25296,7 +25324,7 @@ Run ${pc35.cyan("wraps email init")} to deploy infrastructure first.
25296
25324
  })
25297
25325
  );
25298
25326
  const { PutRolePolicyCommand: PutRolePolicyCommand2 } = await import("@aws-sdk/client-iam");
25299
- await iam10.send(
25327
+ await iam9.send(
25300
25328
  new PutRolePolicyCommand2({
25301
25329
  RoleName: roleName,
25302
25330
  PolicyName: "wraps-console-access-policy",
@@ -25307,7 +25335,7 @@ Run ${pc35.cyan("wraps email init")} to deploy infrastructure first.
25307
25335
  } else {
25308
25336
  await progress.execute("Updating IAM role permissions", async () => {
25309
25337
  const { PutRolePolicyCommand: PutRolePolicyCommand2 } = await import("@aws-sdk/client-iam");
25310
- await iam10.send(
25338
+ await iam9.send(
25311
25339
  new PutRolePolicyCommand2({
25312
25340
  RoleName: roleName,
25313
25341
  PolicyName: "wraps-console-access-policy",
@@ -27041,7 +27069,7 @@ function createSettingsRouter(config2) {
27041
27069
  });
27042
27070
  } catch (error) {
27043
27071
  console.error("[Verify] Error verifying tracking domain:", error);
27044
- if (error.code === "ENODATA" || error.code === "ENOTFOUND") {
27072
+ if (error instanceof Error && (error.code === "ENODATA" || error.code === "ENOTFOUND")) {
27045
27073
  return res.json({
27046
27074
  verified: false,
27047
27075
  error: "No CNAME record found for this domain"
@@ -27075,7 +27103,7 @@ function createSettingsRouter(config2) {
27075
27103
  });
27076
27104
  } catch (error) {
27077
27105
  console.error("[Verify] Error verifying DMARC:", error);
27078
- if (error.code === "ENODATA" || error.code === "ENOTFOUND") {
27106
+ if (error instanceof Error && (error.code === "ENODATA" || error.code === "ENOTFOUND")) {
27079
27107
  return res.json({
27080
27108
  verified: false,
27081
27109
  error: "No DMARC record found for this domain"
@@ -28501,85 +28529,10 @@ import pc39 from "picocolors";
28501
28529
 
28502
28530
  // src/infrastructure/sms-stack.ts
28503
28531
  init_esm_shims();
28504
- init_resource_checks();
28505
- import * as aws19 from "@pulumi/aws";
28532
+ import * as aws18 from "@pulumi/aws";
28506
28533
  import * as pulumi24 from "@pulumi/pulumi";
28534
+ init_resource_checks();
28507
28535
  async function createSMSIAMRole(config2) {
28508
- let assumeRolePolicy;
28509
- if (config2.provider === "vercel" && config2.oidcProvider) {
28510
- assumeRolePolicy = pulumi24.interpolate`{
28511
- "Version": "2012-10-17",
28512
- "Statement": [
28513
- {
28514
- "Effect": "Allow",
28515
- "Principal": {
28516
- "Federated": "${config2.oidcProvider.arn}"
28517
- },
28518
- "Action": "sts:AssumeRoleWithWebIdentity",
28519
- "Condition": {
28520
- "StringEquals": {
28521
- "oidc.vercel.com/${config2.vercelTeamSlug}:aud": "https://vercel.com/${config2.vercelTeamSlug}"
28522
- },
28523
- "StringLike": {
28524
- "oidc.vercel.com/${config2.vercelTeamSlug}:sub": "owner:${config2.vercelTeamSlug}:project:${config2.vercelProjectName}:environment:*"
28525
- }
28526
- }
28527
- },
28528
- {
28529
- "Effect": "Allow",
28530
- "Principal": {
28531
- "Service": "lambda.amazonaws.com"
28532
- },
28533
- "Action": "sts:AssumeRole"
28534
- }
28535
- ]
28536
- }`;
28537
- } else if (config2.provider === "aws") {
28538
- assumeRolePolicy = pulumi24.output(`{
28539
- "Version": "2012-10-17",
28540
- "Statement": [{
28541
- "Effect": "Allow",
28542
- "Principal": {
28543
- "Service": ["lambda.amazonaws.com", "ec2.amazonaws.com", "ecs-tasks.amazonaws.com"]
28544
- },
28545
- "Action": "sts:AssumeRole"
28546
- }]
28547
- }`);
28548
- } else {
28549
- throw new Error("Other providers not yet implemented");
28550
- }
28551
- const roleName = "wraps-sms-role";
28552
- const exists = await roleExists(roleName);
28553
- const role = exists ? new aws19.iam.Role(
28554
- roleName,
28555
- {
28556
- name: roleName,
28557
- assumeRolePolicy,
28558
- tags: {
28559
- ManagedBy: "wraps-cli",
28560
- Service: "sms",
28561
- Provider: config2.provider
28562
- }
28563
- },
28564
- {
28565
- import: roleName,
28566
- customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28567
- }
28568
- ) : new aws19.iam.Role(
28569
- roleName,
28570
- {
28571
- name: roleName,
28572
- assumeRolePolicy,
28573
- tags: {
28574
- ManagedBy: "wraps-cli",
28575
- Service: "sms",
28576
- Provider: config2.provider
28577
- }
28578
- },
28579
- {
28580
- customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28581
- }
28582
- );
28583
28536
  const statements = [];
28584
28537
  statements.push({
28585
28538
  Effect: "Allow",
@@ -28660,17 +28613,20 @@ async function createSMSIAMRole(config2) {
28660
28613
  Resource: "arn:aws:logs:*:*:log-group:/aws/lambda/wraps-sms-*"
28661
28614
  });
28662
28615
  }
28663
- new aws19.iam.RolePolicy("wraps-sms-policy", {
28664
- role: role.name,
28665
- policy: JSON.stringify({
28666
- Version: "2012-10-17",
28667
- Statement: statements
28668
- })
28616
+ return createServiceIAMRole({
28617
+ serviceName: "sms",
28618
+ provider: config2.provider,
28619
+ oidcProvider: config2.oidcProvider,
28620
+ vercelTeamSlug: config2.vercelTeamSlug,
28621
+ vercelProjectName: config2.vercelProjectName,
28622
+ additionalVercelPrincipals: ["lambda.amazonaws.com"],
28623
+ policyStatements: statements,
28624
+ extraTags: { Service: "sms" },
28625
+ customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28669
28626
  });
28670
- return role;
28671
28627
  }
28672
28628
  function createSMSConfigurationSet() {
28673
- return new aws19.pinpoint.Smsvoicev2ConfigurationSet("wraps-sms-config", {
28629
+ return new aws18.pinpoint.Smsvoicev2ConfigurationSet("wraps-sms-config", {
28674
28630
  name: "wraps-sms-config",
28675
28631
  defaultMessageType: "TRANSACTIONAL",
28676
28632
  tags: {
@@ -28680,7 +28636,7 @@ function createSMSConfigurationSet() {
28680
28636
  });
28681
28637
  }
28682
28638
  function createSMSOptOutList() {
28683
- return new aws19.pinpoint.Smsvoicev2OptOutList("wraps-sms-optouts", {
28639
+ return new aws18.pinpoint.Smsvoicev2OptOutList("wraps-sms-optouts", {
28684
28640
  name: "wraps-sms-optouts",
28685
28641
  tags: {
28686
28642
  ManagedBy: "wraps-cli",
@@ -28744,7 +28700,7 @@ async function createSMSPhoneNumber(phoneNumberType, optOutList) {
28744
28700
  }
28745
28701
  };
28746
28702
  if (existingArn) {
28747
- return new aws19.pinpoint.Smsvoicev2PhoneNumber(
28703
+ return new aws18.pinpoint.Smsvoicev2PhoneNumber(
28748
28704
  "wraps-sms-number",
28749
28705
  phoneConfig,
28750
28706
  {
@@ -28753,7 +28709,7 @@ async function createSMSPhoneNumber(phoneNumberType, optOutList) {
28753
28709
  }
28754
28710
  );
28755
28711
  }
28756
- return new aws19.pinpoint.Smsvoicev2PhoneNumber(
28712
+ return new aws18.pinpoint.Smsvoicev2PhoneNumber(
28757
28713
  "wraps-sms-number",
28758
28714
  phoneConfig,
28759
28715
  {
@@ -28782,10 +28738,10 @@ async function createSMSSQSResources() {
28782
28738
  Description: "Dead letter queue for failed SMS event processing"
28783
28739
  }
28784
28740
  };
28785
- const dlq = dlqUrl ? new aws19.sqs.Queue(dlqName, dlqConfig, {
28741
+ const dlq = dlqUrl ? new aws18.sqs.Queue(dlqName, dlqConfig, {
28786
28742
  import: dlqUrl,
28787
28743
  customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28788
- }) : new aws19.sqs.Queue(dlqName, dlqConfig, {
28744
+ }) : new aws18.sqs.Queue(dlqName, dlqConfig, {
28789
28745
  customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28790
28746
  });
28791
28747
  const queueConfig = {
@@ -28808,10 +28764,10 @@ async function createSMSSQSResources() {
28808
28764
  Description: "Queue for SMS events from SNS"
28809
28765
  }
28810
28766
  };
28811
- const queue = queueUrl ? new aws19.sqs.Queue(queueName, queueConfig, {
28767
+ const queue = queueUrl ? new aws18.sqs.Queue(queueName, queueConfig, {
28812
28768
  import: queueUrl,
28813
28769
  customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28814
- }) : new aws19.sqs.Queue(queueName, queueConfig, {
28770
+ }) : new aws18.sqs.Queue(queueName, queueConfig, {
28815
28771
  customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28816
28772
  });
28817
28773
  return { queue, dlq };
@@ -28827,13 +28783,13 @@ async function createSMSSNSResources(config2) {
28827
28783
  Description: "SNS topic for SMS delivery events"
28828
28784
  }
28829
28785
  };
28830
- const topic = topicArn ? new aws19.sns.Topic("wraps-sms-events-topic", topicConfig, {
28786
+ const topic = topicArn ? new aws18.sns.Topic("wraps-sms-events-topic", topicConfig, {
28831
28787
  import: topicArn,
28832
28788
  customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28833
- }) : new aws19.sns.Topic("wraps-sms-events-topic", topicConfig, {
28789
+ }) : new aws18.sns.Topic("wraps-sms-events-topic", topicConfig, {
28834
28790
  customTimeouts: { create: "2m", update: "2m", delete: "2m" }
28835
28791
  });
28836
- new aws19.sns.TopicPolicy("wraps-sms-events-topic-policy", {
28792
+ new aws18.sns.TopicPolicy("wraps-sms-events-topic-policy", {
28837
28793
  arn: topic.arn,
28838
28794
  policy: topic.arn.apply(
28839
28795
  (topicArn2) => JSON.stringify({
@@ -28850,7 +28806,7 @@ async function createSMSSNSResources(config2) {
28850
28806
  })
28851
28807
  )
28852
28808
  });
28853
- new aws19.sqs.QueuePolicy("wraps-sms-events-queue-policy", {
28809
+ new aws18.sqs.QueuePolicy("wraps-sms-events-queue-policy", {
28854
28810
  queueUrl: config2.queueUrl,
28855
28811
  policy: pulumi24.all([config2.queueArn, topic.arn]).apply(
28856
28812
  ([queueArn, topicArn2]) => JSON.stringify({
@@ -28869,7 +28825,7 @@ async function createSMSSNSResources(config2) {
28869
28825
  })
28870
28826
  )
28871
28827
  });
28872
- const subscription = new aws19.sns.TopicSubscription(
28828
+ const subscription = new aws18.sns.TopicSubscription(
28873
28829
  "wraps-sms-events-subscription",
28874
28830
  {
28875
28831
  topic: topic.arn,
@@ -28918,17 +28874,17 @@ async function createSMSDynamoDBTable() {
28918
28874
  Service: "sms"
28919
28875
  }
28920
28876
  };
28921
- return exists ? new aws19.dynamodb.Table(tableName, tableConfig, {
28877
+ return exists ? new aws18.dynamodb.Table(tableName, tableConfig, {
28922
28878
  import: tableName,
28923
28879
  customTimeouts: { create: "5m", update: "5m", delete: "5m" }
28924
- }) : new aws19.dynamodb.Table(tableName, tableConfig, {
28880
+ }) : new aws18.dynamodb.Table(tableName, tableConfig, {
28925
28881
  customTimeouts: { create: "5m", update: "5m", delete: "5m" }
28926
28882
  });
28927
28883
  }
28928
28884
  async function deploySMSLambdaFunction(config2) {
28929
28885
  const { getLambdaCode: getLambdaCode2 } = await Promise.resolve().then(() => (init_lambda(), lambda_exports));
28930
28886
  const codeDir = await getLambdaCode2("sms-event-processor");
28931
- const lambdaRole = new aws19.iam.Role("wraps-sms-lambda-role", {
28887
+ const lambdaRole = new aws18.iam.Role("wraps-sms-lambda-role", {
28932
28888
  name: "wraps-sms-lambda-role",
28933
28889
  assumeRolePolicy: JSON.stringify({
28934
28890
  Version: "2012-10-17",
@@ -28945,11 +28901,11 @@ async function deploySMSLambdaFunction(config2) {
28945
28901
  Service: "sms"
28946
28902
  }
28947
28903
  });
28948
- new aws19.iam.RolePolicyAttachment("wraps-sms-lambda-basic-execution", {
28904
+ new aws18.iam.RolePolicyAttachment("wraps-sms-lambda-basic-execution", {
28949
28905
  role: lambdaRole.name,
28950
28906
  policyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
28951
28907
  });
28952
- new aws19.iam.RolePolicy("wraps-sms-lambda-policy", {
28908
+ new aws18.iam.RolePolicy("wraps-sms-lambda-policy", {
28953
28909
  role: lambdaRole.name,
28954
28910
  policy: pulumi24.all([config2.tableName, config2.queueArn]).apply(
28955
28911
  ([tableName, queueArn]) => JSON.stringify({
@@ -28981,7 +28937,7 @@ async function deploySMSLambdaFunction(config2) {
28981
28937
  })
28982
28938
  )
28983
28939
  });
28984
- const eventProcessor = new aws19.lambda.Function(
28940
+ const eventProcessor = new aws18.lambda.Function(
28985
28941
  "wraps-sms-event-processor",
28986
28942
  {
28987
28943
  name: "wraps-sms-event-processor",
@@ -29009,7 +28965,7 @@ async function deploySMSLambdaFunction(config2) {
29009
28965
  customTimeouts: { create: "5m", update: "5m", delete: "2m" }
29010
28966
  }
29011
28967
  );
29012
- new aws19.lambda.EventSourceMapping(
28968
+ new aws18.lambda.EventSourceMapping(
29013
28969
  "wraps-sms-event-source-mapping",
29014
28970
  {
29015
28971
  eventSourceArn: config2.queueArn,
@@ -29025,7 +28981,7 @@ async function deploySMSLambdaFunction(config2) {
29025
28981
  return eventProcessor;
29026
28982
  }
29027
28983
  async function deploySMSStack(config2) {
29028
- const identity = await aws19.getCallerIdentity();
28984
+ const identity = await aws18.getCallerIdentity();
29029
28985
  const accountId = identity.accountId;
29030
28986
  let oidcProvider;
29031
28987
  if (config2.provider === "vercel" && config2.vercel) {