effortless-aws 0.14.1 → 0.14.3

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/index.js CHANGED
@@ -70916,13 +70916,20 @@ var makeTags = (ctx, type2) => ({
70916
70916
  var toAwsTagList = (tags2) => Object.entries(tags2).map(([Key2, Value]) => ({ Key: Key2, Value }));
70917
70917
  var resolveStage = (input) => input ?? process.env.EFFORTLESS_STAGE ?? "dev";
70918
70918
  var getResourcesByTags = (project2, stage) => Effect_exports.gen(function* () {
70919
- const result = yield* resource_groups_tagging_api_exports.make("get_resources", {
70920
- TagFilters: [
70921
- { Key: "effortless:project", Values: [project2] },
70922
- { Key: "effortless:stage", Values: [stage] }
70923
- ]
70924
- });
70925
- return result.ResourceTagMappingList ?? [];
70919
+ const all13 = [];
70920
+ let token;
70921
+ do {
70922
+ const result = yield* resource_groups_tagging_api_exports.make("get_resources", {
70923
+ TagFilters: [
70924
+ { Key: "effortless:project", Values: [project2] },
70925
+ { Key: "effortless:stage", Values: [stage] }
70926
+ ],
70927
+ ...token ? { PaginationToken: token } : {}
70928
+ });
70929
+ all13.push(...result.ResourceTagMappingList ?? []);
70930
+ token = result.PaginationToken;
70931
+ } while (token);
70932
+ return all13;
70926
70933
  });
70927
70934
  var getAllResourcesByTags = (project2, stage, region) => Effect_exports.gen(function* () {
70928
70935
  const tagFilters = [
@@ -70931,13 +70938,19 @@ var getAllResourcesByTags = (project2, stage, region) => Effect_exports.gen(func
70931
70938
  ];
70932
70939
  const regional = yield* getResourcesByTags(project2, stage);
70933
70940
  if (region === "us-east-1") return regional;
70934
- const globalResult = yield* resource_groups_tagging_api_exports.make("get_resources", {
70935
- TagFilters: tagFilters
70936
- }).pipe(
70937
- Effect_exports.provide(resource_groups_tagging_api_exports.ResourceGroupsTaggingAPIClient.Default({ region: "us-east-1" })),
70938
- Effect_exports.catchAll(() => Effect_exports.succeed({ ResourceTagMappingList: [] }))
70939
- );
70940
- const global = globalResult.ResourceTagMappingList ?? [];
70941
+ const global = [];
70942
+ let globalToken;
70943
+ do {
70944
+ const globalResult = yield* resource_groups_tagging_api_exports.make("get_resources", {
70945
+ TagFilters: tagFilters,
70946
+ ...globalToken ? { PaginationToken: globalToken } : {}
70947
+ }).pipe(
70948
+ Effect_exports.provide(resource_groups_tagging_api_exports.ResourceGroupsTaggingAPIClient.Default({ region: "us-east-1" })),
70949
+ Effect_exports.catchAll(() => Effect_exports.succeed({ ResourceTagMappingList: [], PaginationToken: void 0 }))
70950
+ );
70951
+ global.push(...globalResult.ResourceTagMappingList ?? []);
70952
+ globalToken = globalResult.PaginationToken;
70953
+ } while (globalToken);
70941
70954
  const seen = new Set(regional.map((r) => r.ResourceARN));
70942
70955
  return [...regional, ...global.filter((r) => !seen.has(r.ResourceARN))];
70943
70956
  });
@@ -72258,46 +72271,68 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72258
72271
  };
72259
72272
  }
72260
72273
  yield* Effect_exports.logDebug("Creating CloudFront distribution (first deploy may take 5-15 minutes)...");
72274
+ const distConfig = {
72275
+ CallerReference: `${project2}-${stage}-${handlerName}-${Date.now()}`,
72276
+ Comment: comment,
72277
+ Origins: {
72278
+ Quantity: 1,
72279
+ Items: [
72280
+ {
72281
+ Id: originId,
72282
+ DomainName: originDomain,
72283
+ OriginAccessControlId: oacId,
72284
+ S3OriginConfig: { OriginAccessIdentity: "" }
72285
+ }
72286
+ ]
72287
+ },
72288
+ DefaultCacheBehavior: {
72289
+ TargetOriginId: originId,
72290
+ ViewerProtocolPolicy: "redirect-to-https",
72291
+ AllowedMethods: {
72292
+ Quantity: 2,
72293
+ Items: ["GET", "HEAD"],
72294
+ CachedMethods: { Quantity: 2, Items: ["GET", "HEAD"] }
72295
+ },
72296
+ Compress: true,
72297
+ CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
72298
+ FunctionAssociations: functionAssociations,
72299
+ LambdaFunctionAssociations: lambdaFunctionAssociations
72300
+ },
72301
+ Aliases: aliasesConfig,
72302
+ ...viewerCertificate ? { ViewerCertificate: viewerCertificate } : {},
72303
+ DefaultRootObject: index,
72304
+ Enabled: true,
72305
+ CustomErrorResponses: customErrorResponses,
72306
+ PriceClass: "PriceClass_All",
72307
+ HttpVersion: "http2and3"
72308
+ };
72261
72309
  const createResult = yield* cloudfront_exports.make("create_distribution_with_tags", {
72262
72310
  DistributionConfigWithTags: {
72263
- DistributionConfig: {
72264
- CallerReference: `${project2}-${stage}-${handlerName}-${Date.now()}`,
72265
- Comment: comment,
72266
- Origins: {
72267
- Quantity: 1,
72268
- Items: [
72269
- {
72270
- Id: originId,
72271
- DomainName: originDomain,
72272
- OriginAccessControlId: oacId,
72273
- S3OriginConfig: { OriginAccessIdentity: "" }
72274
- }
72275
- ]
72276
- },
72277
- DefaultCacheBehavior: {
72278
- TargetOriginId: originId,
72279
- ViewerProtocolPolicy: "redirect-to-https",
72280
- AllowedMethods: {
72281
- Quantity: 2,
72282
- Items: ["GET", "HEAD"],
72283
- CachedMethods: { Quantity: 2, Items: ["GET", "HEAD"] }
72284
- },
72285
- Compress: true,
72286
- CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
72287
- FunctionAssociations: functionAssociations,
72288
- LambdaFunctionAssociations: lambdaFunctionAssociations
72289
- },
72290
- Aliases: aliasesConfig,
72291
- ...viewerCertificate ? { ViewerCertificate: viewerCertificate } : {},
72292
- DefaultRootObject: index,
72293
- Enabled: true,
72294
- CustomErrorResponses: customErrorResponses,
72295
- PriceClass: "PriceClass_All",
72296
- HttpVersion: "http2and3"
72297
- },
72311
+ DistributionConfig: distConfig,
72298
72312
  Tags: { Items: toAwsTagList(tags2) }
72299
72313
  }
72300
- });
72314
+ }).pipe(
72315
+ // If CNAME is claimed by another distribution (e.g. DNS still points elsewhere),
72316
+ // retry without aliases so the deploy doesn't fail
72317
+ Effect_exports.catchIf(
72318
+ (e) => e._tag === "CloudFrontError" && e.is("CNAMEAlreadyExists"),
72319
+ () => Effect_exports.gen(function* () {
72320
+ const cnameList = aliases?.join(", ") ?? "";
72321
+ yield* Effect_exports.logWarning(
72322
+ `Domain ${cnameList} is still associated with another CloudFront distribution (DNS points elsewhere). Creating distribution without custom domain. Update your DNS records and redeploy to attach the domain.`
72323
+ );
72324
+ return yield* cloudfront_exports.make("create_distribution_with_tags", {
72325
+ DistributionConfigWithTags: {
72326
+ DistributionConfig: {
72327
+ ...distConfig,
72328
+ Aliases: { Quantity: 0, Items: [] }
72329
+ },
72330
+ Tags: { Items: toAwsTagList(tags2) }
72331
+ }
72332
+ });
72333
+ })
72334
+ )
72335
+ );
72301
72336
  const dist = createResult.Distribution;
72302
72337
  return {
72303
72338
  distributionId: dist.Id,
@@ -72307,24 +72342,30 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72307
72342
  });
72308
72343
  var findDistributionByTags = (project2, stage, handlerName) => Effect_exports.gen(function* () {
72309
72344
  const resources = yield* getResourcesByTags(project2, stage);
72310
- const dist = resources.find((r) => {
72345
+ const candidates = resources.filter((r) => {
72311
72346
  const isDistribution = r.ResourceARN?.includes(":distribution/");
72312
72347
  const handlerTag = r.Tags?.find((t) => t.Key === "effortless:handler");
72313
72348
  return isDistribution && handlerTag?.Value === handlerName;
72314
72349
  });
72315
- if (!dist?.ResourceARN) return void 0;
72316
- const distributionId = dist.ResourceARN.split("/").pop();
72317
- const result = yield* cloudfront_exports.make("get_distribution", { Id: distributionId }).pipe(
72318
- Effect_exports.catchIf(
72319
- (e) => e._tag === "CloudFrontError" && e.is("NoSuchDistribution"),
72320
- () => Effect_exports.succeed(void 0)
72321
- )
72322
- );
72323
- if (!result) return void 0;
72324
- return {
72325
- Id: distributionId,
72326
- DomainName: result.Distribution.DomainName
72327
- };
72350
+ for (const dist of candidates) {
72351
+ const distributionId = dist.ResourceARN.split("/").pop();
72352
+ const result = yield* cloudfront_exports.make("get_distribution", { Id: distributionId }).pipe(
72353
+ Effect_exports.catchIf(
72354
+ (e) => e._tag === "CloudFrontError" && e.is("NoSuchDistribution"),
72355
+ () => {
72356
+ Effect_exports.logDebug(`Distribution ${distributionId} no longer exists (stale tag), skipping`);
72357
+ return Effect_exports.succeed(void 0);
72358
+ }
72359
+ )
72360
+ );
72361
+ if (result) {
72362
+ return {
72363
+ Id: distributionId,
72364
+ DomainName: result.Distribution.DomainName
72365
+ };
72366
+ }
72367
+ }
72368
+ return void 0;
72328
72369
  });
72329
72370
  var invalidateDistribution = (distributionId) => Effect_exports.gen(function* () {
72330
72371
  yield* Effect_exports.logDebug(`Invalidating CloudFront distribution: ${distributionId}`);
@@ -73369,17 +73410,22 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73369
73410
  if (domain) {
73370
73411
  const certResult = yield* findCertificate(domain);
73371
73412
  acmCertificateArn = certResult.certificateArn;
73372
- const wwwCandidate = `www.${domain}`;
73373
- const certCoversWww = certResult.coveredDomains.includes(wwwCandidate) || certResult.coveredDomains.includes(`*.${domain}`);
73374
- if (certCoversWww) {
73375
- aliases = [domain, wwwCandidate];
73376
- wwwDomain = wwwCandidate;
73377
- yield* Effect_exports.logDebug(`ACM certificate covers ${wwwCandidate}, enabling www \u2192 non-www redirect`);
73413
+ const isRootDomain = domain.split(".").length === 2;
73414
+ if (isRootDomain) {
73415
+ const wwwCandidate = `www.${domain}`;
73416
+ const certCoversWww = certResult.coveredDomains.includes(wwwCandidate) || certResult.coveredDomains.includes(`*.${domain}`);
73417
+ if (certCoversWww) {
73418
+ aliases = [domain, wwwCandidate];
73419
+ wwwDomain = wwwCandidate;
73420
+ yield* Effect_exports.logDebug(`ACM certificate covers ${wwwCandidate}, enabling www \u2192 non-www redirect`);
73421
+ } else {
73422
+ aliases = [domain];
73423
+ yield* Effect_exports.logWarning(
73424
+ `ACM certificate does not cover ${wwwCandidate}. For SEO, add ${wwwCandidate} to your ACM certificate in us-east-1 to enable www \u2192 non-www redirect.`
73425
+ );
73426
+ }
73378
73427
  } else {
73379
73428
  aliases = [domain];
73380
- yield* Effect_exports.logWarning(
73381
- `ACM certificate does not cover ${wwwCandidate}. For SEO, add ${wwwCandidate} to your ACM certificate in us-east-1 to enable www \u2192 non-www redirect.`
73382
- );
73383
73429
  }
73384
73430
  }
73385
73431
  const isSpa = config2.spa ?? false;