@go-to-k/cdkd 0.255.0 → 0.257.0

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { $ as BOOTSTRAP_MARKER_PREFIX, A as refStateLookupFromResource, At as AssemblyReader, B as TemplateParser, C as ProviderRegistry, Ct as warnDeprecatedNoPrefixCliFlag, D as isTerminationProtectionPropagationError, Dt as findLargeInlineResources, E as disableInstanceApiTermination, Et as MIGRATE_TMP_PREFIX, F as resolveExplicitPhysicalId, Ft as resetAwsClients, G as AssetPublisher, Gt as MissingCdkCliError, H as S3StateBackend, Ht as LocalMigrateError, I as assertRegionMatch, It as setAwsClients, J as buildAssetRedirectMap, Jt as ProvisioningError, K as stringifyValue, Kt as NestedStackChildDirectDestroyError, L as applyRoleArnIfSet, M as CDK_PATH_TAG, Mt as resolveBucketRegion, N as matchesCdkPath, Nt as AwsClients, O as IntrinsicFunctionResolver, Ot as uploadCfnTemplate, P as normalizeAwsTagsToCfn, Pt as getAwsClients, Q as AssetModeResolver, Qt as StackTerminationProtectionError, R as DiffCalculator, Rt as CdkdError, S as isRetryableTransientError, St as resolveUseCdkBootstrapAssets, T as CloudControlProvider, Tt as CFN_TEMPLATE_URL_LIMIT, U as rebuildClientForBucketRegion, Ut as LocalStartServiceError, V as LockManager, Vt as LocalInvokeBuildError$1, W as shouldRetainResource, X as loadPublishableAssetManifest, Xt as ResourceUpdateNotSupportedError, Y as createAssetRedirectResolver, Yt as ResourceTimeoutError, Z as rewriteTemplateAssetReferences, Zt as StackHasActiveImportsError, _ as yellow, _t as resolveAutoAssetStorage, a as IMPLICIT_DELETE_DEPENDENCIES, at as buildDockerImage, b as importTagWalk, bt as resolveStateBucketWithDefault, c as MULTI_REGION_RECREATE_BLOCKED_TYPES, ct as runDockerForeground, d as formatResourceLine, dt as getDockerImageBySourceHash, et as ensureAssetStorage, f as bold, ft as Synthesizer, g as red, gt as resolveApp, h as green, ht as getLegacyStateBucketName, i as withResourceDeadline, in as withErrorHandling, it as validateContainerRepoName, j as WAFv2WebACLProvider, k as cfnRefValueFromPhysicalId, kt as expectedOwnerParam, l as isStatefulRecreateTargetSync, lt as runDockerStreaming, m as gray, mt as getDefaultStateBucketName, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as parseBootstrapMarker, o as computeImplicitDeleteEdges, ot as formatDockerLoginError, p as cyan, pt as synthesisStatusMessage, q as WorkGraph, qt as PartialFailureError, r as DeployEngine, rn as normalizeAwsError, rt as validateAssetBucketName, s as extractDeploymentEventError, st as getDockerCmd, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as getBootstrapMarkerKey, u as renderStatefulReason, ut as AssetManifestLoader, v as IAMRoleProvider, vt as resolveCaptureObservedState, w as findActionableSilentDrops, wt as CFN_TEMPLATE_BODY_LIMIT, x as withRetry, xt as resolveStateBucketWithDefaultAndSource, y as collectInlinePolicyNamesManagedBySiblings, yt as resolveSkipPrefix, z as DagBuilder } from "./deploy-engine-CFUNbwD1.js";
2
+ import { $ as BOOTSTRAP_MARKER_PREFIX, A as withRetry, At as AssemblyReader, B as TemplateParser, C as disableInstanceApiTermination, Ct as warnDeprecatedNoPrefixCliFlag, D as refStateLookupFromResource, Dt as findLargeInlineResources, E as cfnRefValueFromPhysicalId, Et as MIGRATE_TMP_PREFIX, F as resolveExplicitPhysicalId, Ft as resetAwsClients, G as AssetPublisher, Gt as MissingCdkCliError, H as S3StateBackend, Ht as LocalMigrateError, I as assertRegionMatch, It as setAwsClients, J as buildAssetRedirectMap, Jt as ProvisioningError, K as stringifyValue, Kt as NestedStackChildDirectDestroyError, L as applyRoleArnIfSet, M as CDK_PATH_TAG, Mt as resolveBucketRegion, N as matchesCdkPath, Nt as AwsClients, O as WAFv2WebACLProvider, Ot as uploadCfnTemplate, P as normalizeAwsTagsToCfn, Pt as getAwsClients, Q as AssetModeResolver, Qt as StackTerminationProtectionError, R as DiffCalculator, Rt as CdkdError, S as CloudControlProvider, St as resolveUseCdkBootstrapAssets, T as IntrinsicFunctionResolver, Tt as CFN_TEMPLATE_URL_LIMIT, U as rebuildClientForBucketRegion, Ut as LocalStartServiceError, V as LockManager, Vt as LocalInvokeBuildError$1, W as shouldRetainResource, X as loadPublishableAssetManifest, Xt as ResourceUpdateNotSupportedError, Y as createAssetRedirectResolver, Yt as ResourceTimeoutError, Z as rewriteTemplateAssetReferences, Zt as StackHasActiveImportsError, _ as yellow, _t as resolveAutoAssetStorage, a as IMPLICIT_DELETE_DEPENDENCIES, at as buildDockerImage, b as ProviderRegistry, bt as resolveStateBucketWithDefault, c as MULTI_REGION_RECREATE_BLOCKED_TYPES, ct as runDockerForeground, d as formatResourceLine, dt as getDockerImageBySourceHash, et as ensureAssetStorage, f as bold, ft as Synthesizer, g as red, gt as resolveApp, h as green, ht as getLegacyStateBucketName, i as withResourceDeadline, in as withErrorHandling, it as validateContainerRepoName, j as isRetryableTransientError, k as importTagWalk, kt as expectedOwnerParam, l as isStatefulRecreateTargetSync, lt as runDockerStreaming, m as gray, mt as getDefaultStateBucketName, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as parseBootstrapMarker, o as computeImplicitDeleteEdges, ot as formatDockerLoginError, p as cyan, pt as synthesisStatusMessage, q as WorkGraph, qt as PartialFailureError, r as DeployEngine, rn as normalizeAwsError, rt as validateAssetBucketName, s as extractDeploymentEventError, st as getDockerCmd, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as getBootstrapMarkerKey, u as renderStatefulReason, ut as AssetManifestLoader, v as IAMRoleProvider, vt as resolveCaptureObservedState, w as isTerminationProtectionPropagationError, wt as CFN_TEMPLATE_BODY_LIMIT, x as findActionableSilentDrops, xt as resolveStateBucketWithDefaultAndSource, y as collectInlinePolicyNamesManagedBySiblings, yt as resolveSkipPrefix, z as DagBuilder } from "./deploy-engine-DOPBIRKR.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as withSkipPrefix, i as runStackBuffered, n as getLogger, o as PATTERN_B_NAME_OPTIONS, p as withStackName, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-BYMEE-BS.js";
4
- import { t as ASGProvider } from "./asg-provider-BPtdM67j.js";
4
+ import { t as ASGProvider } from "./asg-provider-6IZKZOKp.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListBucketsCommand, ListDirectoryBucketsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -505,6 +505,16 @@ const replaceOption = new Option("--replace", "Replace (DELETE + CREATE) a resou
505
505
  * (see `resolveUseCdkBootstrapAssets` in config-loader.ts).
506
506
  */
507
507
  const useCdkBootstrapAssetsOption = new Option("--use-cdk-bootstrap-assets", "Publish assets to the CDK bootstrap bucket/repo named by the asset manifest verbatim, skipping the cdkd asset-storage redirection even when this region is opted in via 'cdkd bootstrap'. For apps deployed via both CloudFormation and cdkd during a migration window. Per-app pin: cdk.json context.cdkd.useCdkBootstrapAssets. Also suppresses the legacy-mode 'cdk gc' notice.").default(false);
508
+ /**
509
+ * Issue #1111 — `--strict-getatt` (deploy only). By default, an
510
+ * `Fn::GetAtt` for an attribute cdkd cannot construct falls back to the
511
+ * resource's physical ID with a warning (hard-failing only on knowably-wrong
512
+ * shapes: `*Arn` attributes with a non-ARN fallback, `*Url` with a
513
+ * non-http(s) fallback — issue #1106). This flag promotes EVERY such
514
+ * fallback to a hard error, and additionally fails the deploy when a stack
515
+ * Output cannot be resolved (default: warn and store no value).
516
+ */
517
+ const strictGetattOption = new Option("--strict-getatt", "Fail the deploy on ANY Fn::GetAtt that falls back to the physical ID because cdkd cannot construct the attribute (default: warn and use the physical ID, hard-failing only when the fallback is knowably wrong — an *Arn attribute with a non-ARN value or a *Url attribute with a non-http(s) value). Also fails the deploy when a stack Output cannot be resolved (default: warn and store no value).").default(false);
508
518
  const deployOptions = [
509
519
  new Option("--concurrency <number>", "Maximum concurrent resource operations").default(10).argParser((value) => parseInt(value, 10)),
510
520
  new Option("--stack-concurrency <number>", "Maximum concurrent stack deployments").default(4).argParser((value) => parseInt(value, 10)),
@@ -526,6 +536,7 @@ const deployOptions = [
526
536
  forceStatefulRecreationOption,
527
537
  replaceOption,
528
538
  useCdkBootstrapAssetsOption,
539
+ strictGetattOption,
529
540
  ...resourceTimeoutOptions
530
541
  ];
531
542
  /**
@@ -1888,7 +1899,7 @@ const FLUSH_INTERVAL_MS = 2e3;
1888
1899
  const FLUSH_EVENT_THRESHOLD = 50;
1889
1900
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
1890
1901
  function getCdkdVersion() {
1891
- return "0.255.0";
1902
+ return "0.257.0";
1892
1903
  }
1893
1904
  /**
1894
1905
  * Generate a time-sortable unique run id, e.g.
@@ -12687,24 +12698,33 @@ var DynamoDBGlobalTableProvider = class {
12687
12698
  if (err instanceof ResourceNotFoundException$1) return null;
12688
12699
  throw err;
12689
12700
  }
12690
- if (!input.cdkPath) return null;
12691
- let exclusiveStartTableName;
12692
- do {
12693
- const list = await this.dynamoDBClient.send(new ListTablesCommand({ ...exclusiveStartTableName && { ExclusiveStartTableName: exclusiveStartTableName } }));
12694
- for (const name of list.TableNames ?? []) try {
12695
- const arn = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: name }))).Table?.TableArn;
12696
- if (!arn) continue;
12697
- if (matchesCdkPath((await this.dynamoDBClient.send(new ListTagsOfResourceCommand({ ResourceArn: arn }))).Tags, input.cdkPath)) return {
12698
- physicalId: name,
12699
- attributes: {}
12701
+ const match = await importTagWalk({
12702
+ cdkPath: input.cdkPath,
12703
+ logicalId: input.logicalId,
12704
+ listPage: async (marker) => {
12705
+ const list = await this.dynamoDBClient.send(new ListTablesCommand({ ...marker && { ExclusiveStartTableName: marker } }));
12706
+ return {
12707
+ items: list.TableNames,
12708
+ nextMarker: list.LastEvaluatedTableName
12700
12709
  };
12701
- } catch (err) {
12702
- if (err instanceof ResourceNotFoundException$1) continue;
12703
- throw err;
12704
- }
12705
- exclusiveStartTableName = list.LastEvaluatedTableName;
12706
- } while (exclusiveStartTableName);
12707
- return null;
12710
+ },
12711
+ describe: async (name) => {
12712
+ try {
12713
+ const arn = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: name }))).Table?.TableArn;
12714
+ if (!arn) return void 0;
12715
+ return await this.dynamoDBClient.send(new ListTagsOfResourceCommand({ ResourceArn: arn }));
12716
+ } catch (err) {
12717
+ if (err instanceof ResourceNotFoundException$1) return void 0;
12718
+ throw err;
12719
+ }
12720
+ },
12721
+ tagsOf: (tagsResp) => tagsResp.Tags
12722
+ });
12723
+ if (!match) return null;
12724
+ return {
12725
+ physicalId: match.summary,
12726
+ attributes: {}
12727
+ };
12708
12728
  }
12709
12729
  async waitForTableActive(tableName, logicalId, maxAttempts = 120) {
12710
12730
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
@@ -14568,23 +14588,30 @@ var EventBridgeRuleProvider = class {
14568
14588
  if (err instanceof ResourceNotFoundException$2) return null;
14569
14589
  throw err;
14570
14590
  }
14571
- if (!input.cdkPath) return null;
14572
- let nextToken;
14573
- do {
14574
- const list = await this.eventBridgeClient.send(new ListRulesCommand({
14575
- ...eventBusName && { EventBusName: eventBusName },
14576
- ...nextToken && { NextToken: nextToken }
14577
- }));
14578
- for (const rule of list.Rules ?? []) {
14579
- if (!rule.Arn) continue;
14580
- if (matchesCdkPath((await this.eventBridgeClient.send(new ListTagsForResourceCommand$1({ ResourceARN: rule.Arn }))).Tags, input.cdkPath)) return {
14581
- physicalId: rule.Arn,
14582
- attributes: {}
14591
+ const match = await importTagWalk({
14592
+ cdkPath: input.cdkPath,
14593
+ logicalId: input.logicalId,
14594
+ listPage: async (marker) => {
14595
+ const list = await this.eventBridgeClient.send(new ListRulesCommand({
14596
+ ...eventBusName && { EventBusName: eventBusName },
14597
+ ...marker && { NextToken: marker }
14598
+ }));
14599
+ return {
14600
+ items: list.Rules,
14601
+ nextMarker: list.NextToken
14583
14602
  };
14584
- }
14585
- nextToken = list.NextToken;
14586
- } while (nextToken);
14587
- return null;
14603
+ },
14604
+ describe: async (rule) => {
14605
+ if (!rule.Arn) return void 0;
14606
+ return await this.eventBridgeClient.send(new ListTagsForResourceCommand$1({ ResourceARN: rule.Arn }));
14607
+ },
14608
+ tagsOf: (tagsResp) => tagsResp.Tags
14609
+ });
14610
+ if (!match) return null;
14611
+ return {
14612
+ physicalId: match.summary.Arn,
14613
+ attributes: {}
14614
+ };
14588
14615
  }
14589
14616
  /**
14590
14617
  * Extract rule name from an ARN
@@ -14869,25 +14896,32 @@ var EventBridgeBusProvider = class {
14869
14896
  if (err instanceof ResourceNotFoundException$2) return null;
14870
14897
  throw err;
14871
14898
  }
14872
- if (!input.cdkPath) return null;
14873
- let nextToken;
14874
- do {
14875
- const list = await this.eventBridgeClient.send(new ListEventBusesCommand({ ...nextToken && { NextToken: nextToken } }));
14876
- for (const bus of list.EventBuses ?? []) {
14877
- if (!bus.Name || !bus.Arn) continue;
14899
+ const match = await importTagWalk({
14900
+ cdkPath: input.cdkPath,
14901
+ logicalId: input.logicalId,
14902
+ listPage: async (marker) => {
14903
+ const list = await this.eventBridgeClient.send(new ListEventBusesCommand({ ...marker && { NextToken: marker } }));
14904
+ return {
14905
+ items: list.EventBuses,
14906
+ nextMarker: list.NextToken
14907
+ };
14908
+ },
14909
+ describe: async (bus) => {
14910
+ if (!bus.Name || !bus.Arn) return void 0;
14878
14911
  try {
14879
- if (matchesCdkPath((await this.eventBridgeClient.send(new ListTagsForResourceCommand$1({ ResourceARN: bus.Arn }))).Tags, input.cdkPath)) return {
14880
- physicalId: bus.Name,
14881
- attributes: {}
14882
- };
14912
+ return await this.eventBridgeClient.send(new ListTagsForResourceCommand$1({ ResourceARN: bus.Arn }));
14883
14913
  } catch (err) {
14884
- if (err instanceof ResourceNotFoundException$2) continue;
14914
+ if (err instanceof ResourceNotFoundException$2) return void 0;
14885
14915
  throw err;
14886
14916
  }
14887
- }
14888
- nextToken = list.NextToken;
14889
- } while (nextToken);
14890
- return null;
14917
+ },
14918
+ tagsOf: (tagsResp) => tagsResp.Tags
14919
+ });
14920
+ if (!match) return null;
14921
+ return {
14922
+ physicalId: match.summary.Name,
14923
+ attributes: {}
14924
+ };
14891
14925
  }
14892
14926
  };
14893
14927
 
@@ -20438,25 +20472,32 @@ var CloudFrontDistributionProvider = class {
20438
20472
  if (err instanceof NoSuchDistribution) return null;
20439
20473
  throw err;
20440
20474
  }
20441
- if (!input.cdkPath) return null;
20442
- let marker;
20443
- do {
20444
- const list = await this.cloudFrontClient.send(new ListDistributionsCommand({ ...marker && { Marker: marker } }));
20445
- for (const d of list.DistributionList?.Items ?? []) {
20446
- if (!d.Id || !d.ARN) continue;
20475
+ const match = await importTagWalk({
20476
+ cdkPath: input.cdkPath,
20477
+ logicalId: input.logicalId,
20478
+ listPage: async (marker) => {
20479
+ const list = await this.cloudFrontClient.send(new ListDistributionsCommand({ ...marker && { Marker: marker } }));
20480
+ return {
20481
+ items: list.DistributionList?.Items,
20482
+ nextMarker: list.DistributionList?.IsTruncated ? list.DistributionList?.NextMarker : void 0
20483
+ };
20484
+ },
20485
+ describe: async (d) => {
20486
+ if (!d.Id || !d.ARN) return void 0;
20447
20487
  try {
20448
- if (matchesCdkPath((await this.cloudFrontClient.send(new ListTagsForResourceCommand$3({ Resource: d.ARN }))).Tags?.Items, input.cdkPath)) return {
20449
- physicalId: d.Id,
20450
- attributes: {}
20451
- };
20488
+ return await this.cloudFrontClient.send(new ListTagsForResourceCommand$3({ Resource: d.ARN }));
20452
20489
  } catch (err) {
20453
- if (err instanceof NoSuchDistribution) continue;
20490
+ if (err instanceof NoSuchDistribution) return void 0;
20454
20491
  throw err;
20455
20492
  }
20456
- }
20457
- marker = list.DistributionList?.IsTruncated ? list.DistributionList?.NextMarker : void 0;
20458
- } while (marker);
20459
- return null;
20493
+ },
20494
+ tagsOf: (tagsResp) => tagsResp.Tags?.Items
20495
+ });
20496
+ if (!match) return null;
20497
+ return {
20498
+ physicalId: match.summary.Id,
20499
+ attributes: {}
20500
+ };
20460
20501
  }
20461
20502
  };
20462
20503
 
@@ -21457,10 +21498,10 @@ var StepFunctionsProvider = class {
21457
21498
  *
21458
21499
  * Lookup order:
21459
21500
  * 1. `--resource <id>=<arn>` override → verify with `DescribeStateMachine`.
21460
- * 2. Walk `ListStateMachines` paginator → `ListTagsForResource(arn)`,
21461
- * match the lowercase `key`/`value` `aws:cdk:path` tag (SFN uses
21462
- * lowercase tags, so `matchesCdkPath` from import-helpers does not
21463
- * apply directly).
21501
+ * 2. Walk `ListStateMachines` → `ListTagsForResource(arn)` via the shared
21502
+ * `importTagWalk` helper. SFN returns lowercase `key`/`value` tags, so
21503
+ * `tagsOf` maps them to the `Key`/`Value` shape the walk's
21504
+ * `aws:cdk:path` matcher expects.
21464
21505
  *
21465
21506
  * SFN state machines do not expose a template-supplied name field
21466
21507
  * usable as a stable physicalId — the physicalId is the ARN — so the
@@ -21478,21 +21519,30 @@ var StepFunctionsProvider = class {
21478
21519
  if (err instanceof StateMachineDoesNotExist) return null;
21479
21520
  throw err;
21480
21521
  }
21481
- if (!input.cdkPath) return null;
21482
- let nextToken;
21483
- do {
21484
- const list = await this.getClient().send(new ListStateMachinesCommand({ ...nextToken && { nextToken } }));
21485
- for (const sm of list.stateMachines ?? []) {
21486
- if (!sm.stateMachineArn) continue;
21487
- const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$11({ resourceArn: sm.stateMachineArn }));
21488
- if (this.tagsMatchCdkPath(tagsResp.tags, input.cdkPath)) return {
21489
- physicalId: sm.stateMachineArn,
21490
- attributes: {}
21522
+ const match = await importTagWalk({
21523
+ cdkPath: input.cdkPath,
21524
+ logicalId: input.logicalId,
21525
+ listPage: async (marker) => {
21526
+ const list = await this.getClient().send(new ListStateMachinesCommand({ ...marker && { nextToken: marker } }));
21527
+ return {
21528
+ items: list.stateMachines,
21529
+ nextMarker: list.nextToken
21491
21530
  };
21492
- }
21493
- nextToken = list.nextToken;
21494
- } while (nextToken);
21495
- return null;
21531
+ },
21532
+ describe: async (sm) => {
21533
+ if (!sm.stateMachineArn) return void 0;
21534
+ return await this.getClient().send(new ListTagsForResourceCommand$11({ resourceArn: sm.stateMachineArn }));
21535
+ },
21536
+ tagsOf: (tagsResp) => (tagsResp.tags ?? []).map((t) => ({
21537
+ Key: t.key,
21538
+ Value: t.value
21539
+ }))
21540
+ });
21541
+ if (!match) return null;
21542
+ return {
21543
+ physicalId: match.summary.stateMachineArn,
21544
+ attributes: {}
21545
+ };
21496
21546
  }
21497
21547
  /**
21498
21548
  * Apply a diff between old and new CFn-shape Tags arrays via SFN's
@@ -21530,14 +21580,6 @@ var StepFunctionsProvider = class {
21530
21580
  }
21531
21581
  }
21532
21582
  /**
21533
- * Match SFN's lowercase `key`/`value` tag shape against the CDK path.
21534
- */
21535
- tagsMatchCdkPath(tags, cdkPath) {
21536
- if (!tags) return false;
21537
- for (const t of tags) if (t.key === "aws:cdk:path" && t.value === cdkPath) return true;
21538
- return false;
21539
- }
21540
- /**
21541
21583
  * Build the state-machine definition string from CDK properties.
21542
21584
  *
21543
21585
  * Precedence (mirrors CloudFormation): an inline `DefinitionString` /
@@ -27948,6 +27990,16 @@ var CognitoUserPoolProvider = class {
27948
27990
  * 3. `aws:cdk:path` tag match via `ListUserPools` +
27949
27991
  * `ListTagsForResource(<arn>)`. Cognito's tag map uses the same
27950
27992
  * `Tags: { [key]: value }` shape as Lambda.
27993
+ *
27994
+ * Steps 2 and 3 share ONE `ListUserPools` walk (per candidate: name check
27995
+ * first, then the two tag reads, only when a `cdkPath` is present), which
27996
+ * runs through the shared `importTagWalk` helper so the N+1 read burst
27997
+ * (DescribeUserPool for the ARN, then ListTagsForResource) is retried with
27998
+ * exponential backoff when AWS throttles it instead of aborting the whole
27999
+ * import. The name match is expressed to the walk as a synthetic
28000
+ * `aws:cdk:path` tag carrying the walk's own lookup key, so a name-only
28001
+ * template (no CDK path metadata) still resolves without any per-candidate
28002
+ * API call, matching the previous inline loop.
27951
28003
  */
27952
28004
  async import(input) {
27953
28005
  if (input.knownPhysicalId) try {
@@ -27961,33 +28013,48 @@ var CognitoUserPoolProvider = class {
27961
28013
  throw err;
27962
28014
  }
27963
28015
  const desiredName = typeof input.properties?.["UserPoolName"] === "string" ? input.properties["UserPoolName"] : void 0;
27964
- let nextToken;
27965
- do {
27966
- const list = await this.getClient().send(new ListUserPoolsCommand({
27967
- MaxResults: 60,
27968
- ...nextToken && { NextToken: nextToken }
27969
- }));
27970
- for (const pool of list.UserPools ?? []) {
27971
- if (!pool.Id) continue;
27972
- if (desiredName && pool.Name === desiredName) return {
27973
- physicalId: pool.Id,
27974
- attributes: {}
28016
+ const walkCdkPath = input.cdkPath || (desiredName ? `cdkd:cognito-user-pool-name:${desiredName}` : void 0);
28017
+ /** Sentinel detail for a candidate matched by its user pool name. */
28018
+ const NAME_MATCH = { nameMatch: true };
28019
+ const match = await importTagWalk({
28020
+ cdkPath: walkCdkPath,
28021
+ logicalId: input.logicalId,
28022
+ listPage: async (marker) => {
28023
+ const list = await this.getClient().send(new ListUserPoolsCommand({
28024
+ MaxResults: 60,
28025
+ ...marker && { NextToken: marker }
28026
+ }));
28027
+ return {
28028
+ items: list.UserPools,
28029
+ nextMarker: list.NextToken
27975
28030
  };
27976
- if (input.cdkPath) try {
28031
+ },
28032
+ describe: async (pool) => {
28033
+ if (!pool.Id) return void 0;
28034
+ if (desiredName && pool.Name === desiredName) return NAME_MATCH;
28035
+ if (!input.cdkPath) return void 0;
28036
+ try {
27977
28037
  const arn = (await this.getClient().send(new DescribeUserPoolCommand({ UserPoolId: pool.Id }))).UserPool?.Arn;
27978
- if (!arn) continue;
27979
- if ((await this.getClient().send(new ListTagsForResourceCommand$15({ ResourceArn: arn }))).Tags?.["aws:cdk:path"] === input.cdkPath) return {
27980
- physicalId: pool.Id,
27981
- attributes: {}
27982
- };
28038
+ if (!arn) return void 0;
28039
+ return await this.getClient().send(new ListTagsForResourceCommand$15({ ResourceArn: arn }));
27983
28040
  } catch (err) {
27984
- if (err instanceof ResourceNotFoundException$7) continue;
28041
+ if (err instanceof ResourceNotFoundException$7) return void 0;
27985
28042
  throw err;
27986
28043
  }
27987
- }
27988
- nextToken = list.NextToken;
27989
- } while (nextToken);
27990
- return null;
28044
+ },
28045
+ tagsOf: (detail) => "nameMatch" in detail ? [{
28046
+ Key: CDK_PATH_TAG,
28047
+ Value: walkCdkPath
28048
+ }] : Object.entries(detail.Tags ?? {}).map(([Key, Value]) => ({
28049
+ Key,
28050
+ Value
28051
+ }))
28052
+ });
28053
+ if (!match) return null;
28054
+ return {
28055
+ physicalId: match.summary.Id,
28056
+ attributes: {}
28057
+ };
27991
28058
  }
27992
28059
  };
27993
28060
 
@@ -32973,23 +33040,31 @@ var BudgetsBudgetProvider = class {
32973
33040
  if (error instanceof NotFoundException$5) return null;
32974
33041
  throw error;
32975
33042
  }
32976
- if (!input.cdkPath) return null;
32977
- let nextToken;
32978
- do {
32979
- const list = await client.send(new DescribeBudgetsCommand({
32980
- AccountId: accountId,
32981
- ...nextToken && { NextToken: nextToken }
32982
- }));
32983
- for (const budget of list.Budgets ?? []) {
32984
- if (!budget.BudgetName) continue;
32985
- if (matchesCdkPath((await client.send(new ListTagsForResourceCommand$17({ ResourceARN: this.budgetArn(accountId, budget.BudgetName) }))).ResourceTags, input.cdkPath)) return {
32986
- physicalId: budget.BudgetName,
32987
- attributes: { Arn: this.budgetArn(accountId, budget.BudgetName) }
33043
+ const match = await importTagWalk({
33044
+ cdkPath: input.cdkPath,
33045
+ logicalId: input.logicalId,
33046
+ listPage: async (marker) => {
33047
+ const list = await client.send(new DescribeBudgetsCommand({
33048
+ AccountId: accountId,
33049
+ ...marker && { NextToken: marker }
33050
+ }));
33051
+ return {
33052
+ items: list.Budgets,
33053
+ nextMarker: list.NextToken
32988
33054
  };
32989
- }
32990
- nextToken = list.NextToken;
32991
- } while (nextToken);
32992
- return null;
33055
+ },
33056
+ describe: async (budget) => {
33057
+ if (!budget.BudgetName) return void 0;
33058
+ return await client.send(new ListTagsForResourceCommand$17({ ResourceARN: this.budgetArn(accountId, budget.BudgetName) }));
33059
+ },
33060
+ tagsOf: (tags) => tags.ResourceTags
33061
+ });
33062
+ if (!match) return null;
33063
+ const budgetName = match.summary.BudgetName;
33064
+ return {
33065
+ physicalId: budgetName,
33066
+ attributes: { Arn: this.budgetArn(accountId, budgetName) }
33067
+ };
32993
33068
  }
32994
33069
  };
32995
33070
 
@@ -38189,19 +38264,25 @@ var FirehoseProvider = class {
38189
38264
  if (err instanceof ResourceNotFoundException$10) return null;
38190
38265
  throw err;
38191
38266
  }
38192
- if (!input.cdkPath) return null;
38193
- let exclusiveStartDeliveryStreamName;
38194
- while (true) {
38195
- const list = await this.getClient().send(new ListDeliveryStreamsCommand({ ...exclusiveStartDeliveryStreamName && { ExclusiveStartDeliveryStreamName: exclusiveStartDeliveryStreamName } }));
38196
- const names = list.DeliveryStreamNames ?? [];
38197
- for (const name of names) if (matchesCdkPath((await this.getClient().send(new ListTagsForDeliveryStreamCommand({ DeliveryStreamName: name }))).Tags, input.cdkPath)) return {
38198
- physicalId: name,
38199
- attributes: {}
38200
- };
38201
- if (!list.HasMoreDeliveryStreams || names.length === 0) break;
38202
- exclusiveStartDeliveryStreamName = names[names.length - 1];
38203
- }
38204
- return null;
38267
+ const match = await importTagWalk({
38268
+ cdkPath: input.cdkPath,
38269
+ logicalId: input.logicalId,
38270
+ listPage: async (marker) => {
38271
+ const list = await this.getClient().send(new ListDeliveryStreamsCommand({ ...marker && { ExclusiveStartDeliveryStreamName: marker } }));
38272
+ const names = list.DeliveryStreamNames ?? [];
38273
+ return {
38274
+ items: names,
38275
+ nextMarker: list.HasMoreDeliveryStreams && names.length > 0 ? names[names.length - 1] : void 0
38276
+ };
38277
+ },
38278
+ describe: async (name) => await this.getClient().send(new ListTagsForDeliveryStreamCommand({ DeliveryStreamName: name })),
38279
+ tagsOf: (tagsResp) => tagsResp.Tags
38280
+ });
38281
+ if (!match) return null;
38282
+ return {
38283
+ physicalId: match.summary,
38284
+ attributes: {}
38285
+ };
38205
38286
  }
38206
38287
  /**
38207
38288
  * Wait for a delivery stream to become ACTIVE.
@@ -38707,26 +38788,32 @@ var CloudTrailProvider = class {
38707
38788
  if (err instanceof TrailNotFoundException) return null;
38708
38789
  throw err;
38709
38790
  }
38710
- if (!input.cdkPath) return null;
38711
- let nextToken;
38712
- do {
38713
- const list = await this.getClient().send(new ListTrailsCommand({ ...nextToken && { NextToken: nextToken } }));
38714
- for (const trail of list.Trails ?? []) {
38715
- if (!trail.TrailARN || !trail.Name) continue;
38791
+ const match = await importTagWalk({
38792
+ cdkPath: input.cdkPath,
38793
+ logicalId: input.logicalId,
38794
+ listPage: async (marker) => {
38795
+ const list = await this.getClient().send(new ListTrailsCommand({ ...marker && { NextToken: marker } }));
38796
+ return {
38797
+ items: list.Trails,
38798
+ nextMarker: list.NextToken
38799
+ };
38800
+ },
38801
+ describe: async (trail) => {
38802
+ if (!trail.TrailARN || !trail.Name) return void 0;
38716
38803
  try {
38717
- const list2 = (await this.getClient().send(new ListTagsCommand$1({ ResourceIdList: [trail.TrailARN] }))).ResourceTagList?.[0];
38718
- if (matchesCdkPath(list2?.TagsList, input.cdkPath)) return {
38719
- physicalId: trail.Name,
38720
- attributes: {}
38721
- };
38804
+ return await this.getClient().send(new ListTagsCommand$1({ ResourceIdList: [trail.TrailARN] }));
38722
38805
  } catch (err) {
38723
- if (err instanceof TrailNotFoundException) continue;
38806
+ if (err instanceof TrailNotFoundException) return void 0;
38724
38807
  throw err;
38725
38808
  }
38726
- }
38727
- nextToken = list.NextToken;
38728
- } while (nextToken);
38729
- return null;
38809
+ },
38810
+ tagsOf: (tagsResp) => tagsResp.ResourceTagList?.[0]?.TagsList
38811
+ });
38812
+ if (!match) return null;
38813
+ return {
38814
+ physicalId: match.summary.Name,
38815
+ attributes: {}
38816
+ };
38730
38817
  }
38731
38818
  };
38732
38819
 
@@ -40447,26 +40534,33 @@ var S3DirectoryBucketProvider = class {
40447
40534
  if (e.name === "NotFound" || e.name === "NoSuchBucket") return null;
40448
40535
  throw err;
40449
40536
  }
40450
- if (!input.cdkPath) return null;
40451
- let token;
40452
- do {
40453
- const list = await this.s3Client.send(new ListDirectoryBucketsCommand({ ...token && { ContinuationToken: token } }));
40454
- for (const b of list.Buckets ?? []) {
40455
- if (!b.Name) continue;
40537
+ const match = await importTagWalk({
40538
+ cdkPath: input.cdkPath,
40539
+ logicalId: input.logicalId,
40540
+ listPage: async (token) => {
40541
+ const list = await this.s3Client.send(new ListDirectoryBucketsCommand({ ...token && { ContinuationToken: token } }));
40542
+ return {
40543
+ items: list.Buckets,
40544
+ nextMarker: list.ContinuationToken
40545
+ };
40546
+ },
40547
+ describe: async (b) => {
40548
+ if (!b.Name) return void 0;
40456
40549
  try {
40457
- if (matchesCdkPath((await this.s3Client.send(new GetBucketTaggingCommand({ Bucket: b.Name }))).TagSet, input.cdkPath)) return {
40458
- physicalId: b.Name,
40459
- attributes: {}
40460
- };
40550
+ return await this.s3Client.send(new GetBucketTaggingCommand({ Bucket: b.Name }));
40461
40551
  } catch (err) {
40462
40552
  const e = err;
40463
- if (e.name === "NoSuchTagSet" || e.name === "AccessDenied") continue;
40553
+ if (e.name === "NoSuchTagSet" || e.name === "AccessDenied") return void 0;
40464
40554
  throw err;
40465
40555
  }
40466
- }
40467
- token = list.ContinuationToken;
40468
- } while (token);
40469
- return null;
40556
+ },
40557
+ tagsOf: (tagging) => tagging.TagSet
40558
+ });
40559
+ if (!match) return null;
40560
+ return {
40561
+ physicalId: match.summary.Name,
40562
+ attributes: {}
40563
+ };
40470
40564
  }
40471
40565
  };
40472
40566
 
@@ -42499,28 +42593,36 @@ var ACMCertificateProvider = class {
42499
42593
  throw err;
42500
42594
  }
42501
42595
  }
42502
- if (!input.cdkPath) return null;
42503
- let nextToken;
42504
- do {
42505
- const list = await this.acmClient.send(new ListCertificatesCommand({ ...nextToken ? { NextToken: nextToken } : {} }));
42506
- for (const summary of list.CertificateSummaryList ?? []) {
42507
- if (!summary.CertificateArn) continue;
42596
+ const match = await importTagWalk({
42597
+ cdkPath: input.cdkPath,
42598
+ logicalId: input.logicalId,
42599
+ listPage: async (marker) => {
42600
+ const list = await this.acmClient.send(new ListCertificatesCommand({ ...marker && { NextToken: marker } }));
42601
+ return {
42602
+ items: list.CertificateSummaryList,
42603
+ nextMarker: list.NextToken
42604
+ };
42605
+ },
42606
+ describe: async (summary) => {
42607
+ if (!summary.CertificateArn) return void 0;
42508
42608
  try {
42509
- if (matchesCdkPath((await this.acmClient.send(new ListTagsForCertificateCommand({ CertificateArn: summary.CertificateArn }))).Tags, input.cdkPath)) return {
42510
- physicalId: summary.CertificateArn,
42511
- attributes: {
42512
- Arn: summary.CertificateArn,
42513
- CertificateArn: summary.CertificateArn
42514
- }
42515
- };
42609
+ return await this.acmClient.send(new ListTagsForCertificateCommand({ CertificateArn: summary.CertificateArn }));
42516
42610
  } catch (err) {
42517
- if (err instanceof ResourceNotFoundException$6) continue;
42611
+ if (err instanceof ResourceNotFoundException$6) return void 0;
42518
42612
  throw err;
42519
42613
  }
42614
+ },
42615
+ tagsOf: (tagsResp) => tagsResp.Tags
42616
+ });
42617
+ if (!match) return null;
42618
+ const arn = match.summary.CertificateArn;
42619
+ return {
42620
+ physicalId: arn,
42621
+ attributes: {
42622
+ Arn: arn,
42623
+ CertificateArn: arn
42520
42624
  }
42521
- nextToken = list.NextToken;
42522
- } while (nextToken);
42523
- return null;
42625
+ };
42524
42626
  }
42525
42627
  /**
42526
42628
  * Poll `DescribeCertificate` until status === `ISSUED`. On the FIRST poll
@@ -43168,6 +43270,7 @@ async function deployCommand(stacks, options) {
43168
43270
  ...recreateViaSdkProviderTargets && recreateViaSdkProviderTargets.size > 0 && { recreateViaSdkProviderTargets },
43169
43271
  ...options.replace && { replace: true },
43170
43272
  ...options.forceStatefulRecreation && { forceStatefulRecreation: true },
43273
+ ...options.strictGetatt && { strictGetAtt: true },
43171
43274
  captureObservedState: resolveCaptureObservedState(options.captureObservedState),
43172
43275
  ...options.resourceWarnAfter?.globalMs !== void 0 && { resourceWarnAfterMs: options.resourceWarnAfter.globalMs },
43173
43276
  ...options.resourceTimeout?.globalMs !== void 0 && { resourceTimeoutMs: options.resourceTimeout.globalMs },
@@ -43198,6 +43301,7 @@ async function deployCommand(stacks, options) {
43198
43301
  logger.info(` Deleted: ${deployResult.deleted > 0 ? red(deployResult.deleted) : gray(deployResult.deleted)}`);
43199
43302
  logger.info(` Unchanged: ${gray(deployResult.unchanged)}`);
43200
43303
  logger.info(` Duration: ${cyan((deployResult.durationMs / 1e3).toFixed(2) + "s")}`);
43304
+ if (deployResult.attributeFallbackCount > 0) logger.warn(`${deployResult.attributeFallbackCount} attribute resolution(s) fell back to the physical ID (potentially wrong values); re-run with --strict-getatt to fail on these`);
43201
43305
  if (deployResult.outputs && Object.keys(deployResult.outputs).length > 0) {
43202
43306
  logger.info("\nOutputs:");
43203
43307
  for (const [key, value] of Object.entries(deployResult.outputs)) logger.info(` ${deployResult.stackName}.${key} = ${String(value)}`);
@@ -62068,7 +62172,7 @@ function createMigrateCommand() {
62068
62172
  */
62069
62173
  function buildProgram() {
62070
62174
  const program = new Command();
62071
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.255.0");
62175
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.257.0");
62072
62176
  program.addCommand(createBootstrapCommand());
62073
62177
  program.addCommand(createSynthCommand());
62074
62178
  program.addCommand(createListCommand());