@go-to-k/cdkd 0.280.46 → 0.281.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.
@@ -9,7 +9,7 @@ import { GetFunctionCommand, GetFunctionUrlConfigCommand, InvokeCommand, LambdaC
9
9
  import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
10
10
  import { CreateSnapshotCommand, DescribeAvailabilityZonesCommand, DescribeImagesCommand, DescribeInstancesCommand, DescribeLaunchTemplatesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSnapshotsCommand, DescribeSubnetsCommand, DescribeVpcsCommand, DescribeVpnGatewaysCommand, EC2Client, ModifyInstanceAttributeCommand } from "@aws-sdk/client-ec2";
11
11
  import { DescribeTableCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";
12
- import { CloudFormationClient, CreateChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, DescribeTypeCommand, GetTemplateCommand, waitUntilChangeSetCreateComplete } from "@aws-sdk/client-cloudformation";
12
+ import { CloudFormationClient, CreateChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, DescribeStacksCommand, DescribeTypeCommand, GetTemplateCommand, ListExportsCommand, waitUntilChangeSetCreateComplete } from "@aws-sdk/client-cloudformation";
13
13
  import { APIGatewayClient, GetRestApiCommand } from "@aws-sdk/client-api-gateway";
14
14
  import { DescribeApiDestinationCommand, DescribeConnectionCommand, EventBridgeClient } from "@aws-sdk/client-eventbridge";
15
15
  import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
@@ -10687,6 +10687,34 @@ var IntrinsicFunctionResolver = class {
10687
10687
  logger = getLogger().child("IntrinsicFunctionResolver");
10688
10688
  resolverRegion;
10689
10689
  strictGetAtt;
10690
+ cfnFallback;
10691
+ /**
10692
+ * Per-region CloudFormation clients for the cross-stack fallback
10693
+ * lookups (issue #1697). Keyed by region because `Fn::GetStackOutput`
10694
+ * may target a region different from the consumer's deploy region.
10695
+ */
10696
+ cfnClients = {};
10697
+ /**
10698
+ * Memoized full `ListExports` listing for the `Fn::ImportValue`
10699
+ * fallback (issue #1697 review). Without it, EVERY cdkd-miss import
10700
+ * re-paginates the whole region's export list — a deploy consuming N
10701
+ * values from CFn producers pays N full walks and exposes itself to
10702
+ * ListExports throttling. Resolver instances are per-deploy (the
10703
+ * engine constructs one per stack), so the cache lifetime matches the
10704
+ * exports-index philosophy: stable within a deploy, fresh across
10705
+ * deploys. FAILED fetches are not cached (the rejection handler
10706
+ * clears the slot) so a transient throttle does not poison the rest
10707
+ * of the deploy's lookups.
10708
+ */
10709
+ cfnExportsPromise;
10710
+ /**
10711
+ * Memoized per-(region, stack) `DescribeStacks` outputs for the
10712
+ * `Fn::GetStackOutput` fallback (issue #1697 review) — a stack
10713
+ * referencing the same CFn producer N times pays one call. Successful
10714
+ * lookups (including the definitive "stack does not exist" miss) are
10715
+ * cached; lookup FAILURES are evicted so they are retried.
10716
+ */
10717
+ cfnStackOutputsCache = /* @__PURE__ */ new Map();
10690
10718
  /**
10691
10719
  * Number of unknown-attribute resolutions that fell back to the physical
10692
10720
  * ID (the warn path) since construction / the last
@@ -10709,6 +10737,7 @@ var IntrinsicFunctionResolver = class {
10709
10737
  constructor(region, options) {
10710
10738
  this.resolverRegion = region || process.env["AWS_REGION"] || "us-east-1";
10711
10739
  this.strictGetAtt = options?.strictGetAtt ?? false;
10740
+ this.cfnFallback = options?.cfnFallback ?? true;
10712
10741
  }
10713
10742
  /** Unknown-attribute physicalId fallbacks recorded since the last reset. */
10714
10743
  getPhysicalIdFallbackCount() {
@@ -11604,7 +11633,113 @@ var IntrinsicFunctionResolver = class {
11604
11633
  continue;
11605
11634
  }
11606
11635
  }
11607
- throw new Error(`Fn::ImportValue: export '${exportName}' not found in any stack. Searched ${allStacks.length} state record(s). Make sure the exporting stack has been deployed and the Output has an Export.Name property.`);
11636
+ if (this.cfnFallback) {
11637
+ const cfnExport = await this.lookupCfnExport(exportName);
11638
+ if (cfnExport) {
11639
+ this.logger.info(`Resolved Fn::ImportValue: ${exportName} = ${JSON.stringify(cfnExport.value)} (from CloudFormation exports${cfnExport.exportingStackId ? `; exporting stack: ${cfnExport.exportingStackId}` : ""}; weak reference — producer is not cdkd-managed)`);
11640
+ return cfnExport.value;
11641
+ }
11642
+ }
11643
+ throw new Error(`Fn::ImportValue: export '${exportName}' not found in any stack. Searched ${allStacks.length} cdkd state record(s)${this.cfnFallback ? " and CloudFormation exports" : ""}. Make sure the exporting stack has been deployed and the Output has an Export.Name property.`);
11644
+ }
11645
+ /**
11646
+ * CloudFormation `ListExports` fallback lookup for `Fn::ImportValue`
11647
+ * (issue #1697). Searches the consumer's deploy region (CFn exports are
11648
+ * region-scoped, same as cdkd's `Fn::ImportValue` semantics).
11649
+ *
11650
+ * Returns `undefined` both when the export does not exist AND when the
11651
+ * lookup itself failed (a warning is logged for the latter — e.g. the
11652
+ * caller's credentials lack `cloudformation:ListExports`), so the caller
11653
+ * surfaces its own not-found error either way. Graceful degradation is
11654
+ * deliberate: without this fallback the deploy would have failed with
11655
+ * the same not-found error anyway.
11656
+ */
11657
+ async lookupCfnExport(exportName) {
11658
+ let listing = this.cfnExportsPromise;
11659
+ if (!listing) {
11660
+ listing = this.fetchAllCfnExports();
11661
+ this.cfnExportsPromise = listing;
11662
+ listing.catch(() => {
11663
+ if (this.cfnExportsPromise === listing) this.cfnExportsPromise = void 0;
11664
+ });
11665
+ }
11666
+ try {
11667
+ const exports = await listing;
11668
+ for (const exp of exports) if (exp.Name === exportName && exp.Value !== void 0) return {
11669
+ value: exp.Value,
11670
+ ...exp.ExportingStackId && { exportingStackId: exp.ExportingStackId }
11671
+ };
11672
+ return;
11673
+ } catch (error) {
11674
+ this.logger.warn(`Fn::ImportValue: CloudFormation ListExports fallback failed for export '${exportName}' (region ${this.resolverRegion}): ${error instanceof Error ? error.message : String(error)}. Grant cloudformation:ListExports to resolve exports from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
11675
+ return;
11676
+ }
11677
+ }
11678
+ /** Full paginated ListExports walk backing {@link lookupCfnExport}'s memo. */
11679
+ async fetchAllCfnExports() {
11680
+ const client = this.getCfnClient(this.resolverRegion);
11681
+ const exports = [];
11682
+ let nextToken;
11683
+ do {
11684
+ const res = await client.send(new ListExportsCommand({ NextToken: nextToken }));
11685
+ exports.push(...res.Exports ?? []);
11686
+ nextToken = res.NextToken;
11687
+ } while (nextToken);
11688
+ return exports;
11689
+ }
11690
+ /**
11691
+ * CloudFormation `DescribeStacks` fallback lookup for
11692
+ * `Fn::GetStackOutput` (issue #1697). Region-pinned because the
11693
+ * intrinsic may target a region different from the consumer's.
11694
+ *
11695
+ * Returns the stack's outputs map when the CFn stack exists;
11696
+ * `undefined` when it does not exist OR the lookup failed (a warning is
11697
+ * logged for non-not-found failures). Same graceful-degradation
11698
+ * contract as {@link lookupCfnExport}.
11699
+ */
11700
+ async lookupCfnStackOutputs(stackName, region) {
11701
+ const cacheKey = `${region}\0${stackName}`;
11702
+ let fetch = this.cfnStackOutputsCache.get(cacheKey);
11703
+ if (!fetch) {
11704
+ fetch = this.fetchCfnStackOutputs(stackName, region);
11705
+ this.cfnStackOutputsCache.set(cacheKey, fetch);
11706
+ fetch.catch(() => {
11707
+ if (this.cfnStackOutputsCache.get(cacheKey) === fetch) this.cfnStackOutputsCache.delete(cacheKey);
11708
+ });
11709
+ }
11710
+ try {
11711
+ return await fetch;
11712
+ } catch (error) {
11713
+ const message = error instanceof Error ? error.message : String(error);
11714
+ this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${stackName}' (${region}): ${message}. Grant cloudformation:DescribeStacks to resolve outputs from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
11715
+ return;
11716
+ }
11717
+ }
11718
+ /**
11719
+ * Single DescribeStacks read backing {@link lookupCfnStackOutputs}'s memo.
11720
+ * Resolves to the outputs map, `undefined` for the definitive
11721
+ * does-not-exist miss, and REJECTS on any other failure.
11722
+ */
11723
+ async fetchCfnStackOutputs(stackName, region) {
11724
+ try {
11725
+ const stack = (await this.getCfnClient(region).send(new DescribeStacksCommand({ StackName: stackName }))).Stacks?.[0];
11726
+ if (!stack) return void 0;
11727
+ const outputs = {};
11728
+ for (const out of stack.Outputs ?? []) if (out.OutputKey && out.OutputValue !== void 0) outputs[out.OutputKey] = out.OutputValue;
11729
+ return outputs;
11730
+ } catch (error) {
11731
+ if (error instanceof Error && error.name === "ValidationError" && /does not exist/i.test(error.message)) return;
11732
+ throw error;
11733
+ }
11734
+ }
11735
+ /** Lazily-constructed per-region CloudFormation client (issue #1697). */
11736
+ getCfnClient(region) {
11737
+ let client = this.cfnClients[region];
11738
+ if (!client) {
11739
+ client = new CloudFormationClient({ region });
11740
+ this.cfnClients[region] = client;
11741
+ }
11742
+ return client;
11608
11743
  }
11609
11744
  /**
11610
11745
  * Push a resolved `Fn::ImportValue` into the consumer's recorded-imports
@@ -11691,7 +11826,21 @@ var IntrinsicFunctionResolver = class {
11691
11826
  if (!roleArn && context.stackName && context.stackName === stackName && region === this.resolverRegion) throw new Error(`Fn::GetStackOutput: cannot reference own stack '${stackName}' in the same region '${region}'`);
11692
11827
  this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${stackName}, Region=${region}, OutputName=${outputName}${roleArn ? `, RoleArn=${roleArn}` : ""}`);
11693
11828
  const stateData = roleArn ? await this.getCrossAccountStackState(roleArn, stackName, region, context) : await this.getSameAccountStackState(stackName, region, context);
11694
- if (!stateData) throw new Error(`Fn::GetStackOutput: stack '${stackName}' not found in region '${region}'${roleArn ? ` (cross-account via ${roleArn})` : ""}. Make sure the producer stack has been deployed via cdkd.`);
11829
+ if (!stateData) {
11830
+ if (!roleArn && this.cfnFallback) {
11831
+ const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region);
11832
+ if (cfnOutputs) {
11833
+ if (!(outputName in cfnOutputs)) {
11834
+ const available = Object.keys(cfnOutputs).join(", ") || "(none)";
11835
+ throw new Error(`Fn::GetStackOutput: output '${outputName}' not found in CloudFormation stack '${stackName}' (${region}). Available outputs: ${available}`);
11836
+ }
11837
+ const value = cfnOutputs[outputName];
11838
+ this.logger.info(`Resolved Fn::GetStackOutput: StackName=${stackName}, Region=${region}, OutputName=${outputName} -> ${JSON.stringify(value)} (from CloudFormation stack outputs; weak reference — producer is not cdkd-managed)`);
11839
+ return value;
11840
+ }
11841
+ }
11842
+ throw new Error(`Fn::GetStackOutput: stack '${stackName}' not found in region '${region}'${roleArn ? ` (cross-account via ${roleArn})` : ""}. ${!roleArn && this.cfnFallback ? "Searched cdkd state and CloudFormation stacks. Make sure the producer stack has been deployed (via cdkd or CloudFormation)." : `Make sure the producer stack has been deployed via cdkd.`}`);
11843
+ }
11695
11844
  const outputs = stateData.state.outputs ?? {};
11696
11845
  if (!(outputName in outputs)) {
11697
11846
  const available = Object.keys(outputs).join(", ") || "(none)";
@@ -12915,7 +13064,7 @@ var CloudControlProvider = class {
12915
13064
  if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
12916
13065
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
12917
13066
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
12918
- const { ASGProvider } = await import("./asg-provider-DGHuyUA8.js").then((n) => n.n);
13067
+ const { ASGProvider } = await import("./asg-provider-BSx4Vrth.js").then((n) => n.n);
12919
13068
  await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
12920
13069
  return;
12921
13070
  }
@@ -19791,7 +19940,7 @@ const FLUSH_INTERVAL_MS = 2e3;
19791
19940
  const FLUSH_EVENT_THRESHOLD = 50;
19792
19941
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
19793
19942
  function getCdkdVersion() {
19794
- return "0.280.46";
19943
+ return "0.281.0";
19795
19944
  }
19796
19945
  /**
19797
19946
  * Generate a time-sortable unique run id, e.g.
@@ -20410,7 +20559,10 @@ var DeployEngine = class {
20410
20559
  this.options = options;
20411
20560
  this.stackRegion = stackRegion;
20412
20561
  this.exportIndexStore = exportIndexStore;
20413
- this.resolver = new IntrinsicFunctionResolver(stackRegion, { strictGetAtt: options.strictGetAtt ?? false });
20562
+ this.resolver = new IntrinsicFunctionResolver(stackRegion, {
20563
+ strictGetAtt: options.strictGetAtt ?? false,
20564
+ cfnFallback: options.cfnFallback ?? true
20565
+ });
20414
20566
  this.options.concurrency = options.concurrency ?? 10;
20415
20567
  this.options.dryRun = options.dryRun ?? false;
20416
20568
  this.options.lockTimeout = options.lockTimeout ?? 300 * 1e3;
@@ -21957,4 +22109,4 @@ var DeployEngine = class {
21957
22109
 
21958
22110
  //#endregion
21959
22111
  export { requireConfigArray as $, expectedOwnerParam as $t, green as A, withErrorHandling as An, getDockerCmd as At, slowCcOperationTimeoutMs as B, resolveAutoAssetStorage as Bt, MULTI_REGION_RECREATE_BLOCKED_TYPES as C, StackHasActiveImportsError as Cn, ensureAssetStorage as Ct, bold as D, formatError as Dn, validateContainerRepoName as Dt, formatResourceLine as E, SynthesisError as En, validateAssetBucketName as Et, clearOnUpdateRemoval as F, Synthesizer as Ft, refStateLookupFromResource as G, resolveUseCdkBootstrapAssets as Gt, isTerminationProtectionPropagationError as H, resolveSkipPrefix as Ht, ProviderRegistry as I, synthesisStatusMessage as It, resolveExplicitPhysicalId as J, CFN_TEMPLATE_BODY_LIMIT as Jt, WAFv2WebACLProvider as K, stateBucketExistenceConfirmed as Kt, findActionableSilentDrops as L, getDefaultStateBucketName as Lt, yellow as M, runDockerStreaming as Mt, IAMRoleProvider as N, AssetManifestLoader as Nt, cyan as O, isCdkdError as On, buildDockerImage as Ot, collectInlinePolicyNamesManagedBySiblings as P, getDockerImageBySourceHash as Pt, replayWarn as Q, uploadCfnTemplate as Qt, findSilentDropProperties as R, getLegacyStateBucketName as Rt, extractDeploymentEventError as S, ResourceUpdateNotSupportedError as Sn, BOOTSTRAP_MARKER_PREFIX as St, renderStatefulReason as T, StateError as Tn, parseBootstrapMarker as Tt, IntrinsicFunctionResolver as U, resolveStateBucketWithDefault as Ut, disableInstanceApiTermination as V, resolveCaptureObservedState as Vt, cfnRefValueFromPhysicalId as W, resolveStateBucketWithDefaultAndSource as Wt, configStringRefusal as X, MIGRATE_TMP_PREFIX as Xt, assertRegionMatch as Y, CFN_TEMPLATE_URL_LIMIT as Yt, readConfigString as Z, findLargeInlineResources as Zt, createPreDeleteFinalSnapshot as _, MissingCdkCliError as _n, buildAssetRedirectMap as _t, DeploymentEventsStore as a, getAwsClients as an, withRetry as at, unsupportedFinalSnapshotError as b, ProvisioningError as bn, rewriteTemplateAssetReferences as bt, replayFailedOperations as c, AssetError as cn, DagBuilder as ct, IMPLICIT_DELETE_DEPENDENCIES as d, DependencyError as dn, S3StateBackend as dt, AssemblyReader as en, requireConfigObject as et, computeImplicitDeleteEdges as f, DeployCancelledError as fn, rebuildClientForBucketRegion as ft, ccRoutedFinalSnapshotError as g, LockError as gn, WorkGraph as gt, buildFinalSnapshotIdentifier as h, LocalStartServiceError as hn, stringifyValue as ht, DeploymentEventsReader as i, AwsClients as in, describeTypeWithThrottleRetry as it, red as j, __exportAll as jn, runDockerForeground as jt, gray as k, normalizeAwsError as kn, formatDockerLoginError as kt, replayRollback as l, CdkdError as ln, TemplateParser as lt, PRE_DELETE_SNAPSHOT_TYPES as m, LocalMigrateError as mn, AssetPublisher as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, clearBucketRegionCache as nn, applyRoleArnIfSet as nt, planFailedOps as o, resetAwsClients as on, isRetryableTransientError as ot, ATOMIC_FINAL_SNAPSHOT_TYPES as p, LocalInvokeBuildError as pn, shouldRetainResource as pt, normalizeAwsTagsToCfn as q, warnDeprecatedNoPrefixCliFlag as qt, DeployEngine as r, resolveBucketRegion as rn, DiffCalculator as rt, planRollback as s, setAwsClients as sn, isThrottlingError as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, processStackMessages as tn, requireConfigString as tt, withResourceDeadline as u, ConfigError as un, LockManager as ut, isFinalSnapshotError as v, NestedStackChildDirectDestroyError as vn, createAssetRedirectResolver as vt, isStatefulRecreateTargetSync as w, StackTerminationProtectionError as wn, getBootstrapMarkerKey as wt, makeCanonicalizePropertiesFn as x, ResourceTimeoutError as xn, AssetModeResolver as xt, refusesFinalSnapshot as y, PartialFailureError as yn, loadPublishableAssetManifest as yt, CloudControlProvider as z, resolveApp as zt };
21960
- //# sourceMappingURL=deploy-engine-E_JV4UqE.js.map
22112
+ //# sourceMappingURL=deploy-engine-Bebl98bx.js.map