@go-to-k/cdkd 0.295.1 → 0.296.1

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.
Files changed (33) hide show
  1. package/dist/{asg-provider-CbwOK2TQ.js → asg-provider-BwWy0pBH.js} +8 -6
  2. package/dist/asg-provider-BwWy0pBH.js.map +1 -0
  3. package/dist/cli.js +2 -2
  4. package/dist/{deploy-engine-DG-oC9YK.js → deploy-engine-xlct0Hcm.js} +1015 -307
  5. package/dist/deploy-engine-xlct0Hcm.js.map +1 -0
  6. package/dist/{iam-policy-targets-CMSQGQnm.js → iam-policy-targets-DSDSdxXz.js} +145 -4
  7. package/dist/iam-policy-targets-DSDSdxXz.js.map +1 -0
  8. package/dist/{iam-role-provider-DUZtt9lH.js → iam-role-provider-BRVCTUZu.js} +11 -5
  9. package/dist/iam-role-provider-BRVCTUZu.js.map +1 -0
  10. package/dist/index.d.ts +28 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -4
  13. package/dist/{logger-B46YMG0h.js → logger-Dvc7ddKe.js} +19 -3
  14. package/dist/{logger-B46YMG0h.js.map → logger-Dvc7ddKe.js.map} +1 -1
  15. package/dist/{neptune-provider-TnGNCeLX.js → neptune-provider-Cdp4jX8S.js} +20 -14
  16. package/dist/neptune-provider-Cdp4jX8S.js.map +1 -0
  17. package/dist/{program-DfJFegS1.js → program-DXRavuSm.js} +6245 -5940
  18. package/dist/program-DXRavuSm.js.map +1 -0
  19. package/dist/{provider-classes-DUw5QAWI.js → provider-classes-DNkoEEo4.js} +754 -208
  20. package/dist/provider-classes-DNkoEEo4.js.map +1 -0
  21. package/dist/{rds-provider-COCDd7bS.js → rds-provider-McCDKyXN.js} +22 -15
  22. package/dist/rds-provider-McCDKyXN.js.map +1 -0
  23. package/dist/{version-Bqzsng8Y.js → version-Dpc_HYX0.js} +2 -2
  24. package/dist/{version-Bqzsng8Y.js.map → version-Dpc_HYX0.js.map} +1 -1
  25. package/package.json +1 -1
  26. package/dist/asg-provider-CbwOK2TQ.js.map +0 -1
  27. package/dist/deploy-engine-DG-oC9YK.js.map +0 -1
  28. package/dist/iam-policy-targets-CMSQGQnm.js.map +0 -1
  29. package/dist/iam-role-provider-DUZtt9lH.js.map +0 -1
  30. package/dist/neptune-provider-TnGNCeLX.js.map +0 -1
  31. package/dist/program-DfJFegS1.js.map +0 -1
  32. package/dist/provider-classes-DUw5QAWI.js.map +0 -1
  33. package/dist/rds-provider-COCDd7bS.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { r as getAwsClients, s as __exportAll } from "./aws-clients-CnmtbrxD.js";
2
- import { A as displaySafe, E as UNRENDERABLE, F as safeMsg, L as truncateCodePoints, M as isPasteableIdent, O as displayAwsMessage, P as plainIdentOr, S as withoutGeneratedFallbackName, T as STACK_REF_MAX_CODE_POINTS, _ as getCurrentSkipPrefix, b as withSkipPrefix, c as getLiveRenderer, f as applyDefaultNameForFallback, g as generateResourceNameWithFallback, h as generateResourceName, j as displayStackName, k as displayIdent, m as explicitNamePropertyFor, n as getLogger, r as isStdoutReservedForPayload, s as installLogLineMaskerSource, v as getCurrentStackName, w as SECRET_REF_MAX_CODE_POINTS, x as withStackName, y as looksLikeCdkdGeneratedName } from "./logger-B46YMG0h.js";
3
- import { $t as StateError, A as isTerminalDeleteFailure, An as isAmbiguousCcHandlerErrorCode, At as clientDefaultsFor, Bn as isMarkedNonRetryable, Bt as IntrinsicResolutionRefusalError, C as refusalTypeShown, Cn as isNameCollisionErrorFrom, D as ProtectionFlipRegistry, Dt as withPasteableAwsProfile, En as isReplayedNameCollisionFrom, Fn as retryClassificationText, Gt as MalformedProducerRecordRefusalError, H as pasteableAwsCommand, Hn as markNonRetryable, In as describeAwsFailure, It as CrossAccountSecretRefusalError, J as isInterruptedWaitError, Jt as ProvisioningError, Lt as DependencyError, M as observeThenDisableProtection, Mn as isIamPropagationError, Mt as AccountIdUnavailableError, N as protectionFlipKey, Nn as isRetryableTransientError, Nt as AssetError, O as compensateProtectionFlip, On as markReplayMayCollide, Ot as ambientClientDefaults, Pn as isTransientServerError, Pt as CdkdError, Q as canonicalizeRoute53QueryName, R as DELETION_PROTECTION_DOC_POINTER, Rn as safeStringify$1, S as quotedRemedyLogicalId, Sn as hasReplayMayCollide, St as injectiveKey, T as resolveExplicitPhysicalId, Tn as isRecreateRetryableError, Tt as producerRecordKey, U as protectedReplacementAdvice, Un as markRedactedCause, Ut as LockError, Vn as isThrottlingError, Wn as wrapMaskedAwsError, Wt as MacroExpansionError, X as ElapsedBudgetRegistry, Xt as ResourceUpdateNotSupportedError, Y as startInterruptWatch, Yt as ResourceTimeoutError, Z as monotonicNowMs, _n as shellQuote, _t as formatLockOperation, at as segmentAfterAnchor, b as isQuotableImportValue, bt as CUSTOM_RESOURCE_RESPONSE_PREFIX, cn as UNSHOWABLE_VALUE, ct as isSecretDerivedValue, d as prepareRemovalForUpdate, dn as isInertUnquoted, dt as withDerivedNameMasks, en as SynthesisError, et as compositeIdSeparatorRefusal, f as removalWarning, fn as pasteableCommand, ft as UNREPRODUCIBLE_LOCK_CLAUSE, g as assertRegionMatch, gn as shellBoundedDisplay, gt as formatLockExpiry, h as RESOURCE_NOT_FOUND, hn as quotedOrDescribed, i as holdsSecretDerivedEntry, it as resourceTypeShown, jn as isAmbiguousOutcomeError, jt as credentialFingerprint, k as deleteWithProtectionCompensation, kn as formatRetryClassificationSignals, kt as ambientCredentialConfig, l as withUnchangedSecretPrincipalLists, ln as commandHole, lt as maskDeep, m as withoutInjectedRemovals, mn as plainOrDescribed, nt as logicalIdShown, on as SHELL_ACTIVE, ot as createMaskedLogSinks, pn as physicalIdShownBesideCommand, pt as buildForceUnlockCommand, rn as normalizeAwsError, sn as SHELL_ACTIVE_WHY, st as createMaskedRetryLogger, ut as maskerOrIdentity, vn as withheldTargetClause, vt as formatLockOwner, wn as isNameCooldownError, x as normalizeAwsTagsToCfn, xn as isUpdateUnsupportedError, xt as DEFAULT_STATE_PREFIX, yt as sanitizeRecoveryValue, zt as DynamicReferenceRegionAmbiguousError } from "./iam-policy-targets-CMSQGQnm.js";
2
+ import { A as displaySafe, E as UNRENDERABLE, F as safeMsg, L as truncateCodePoints, M as isPasteableIdent, O as displayAwsMessage, P as plainIdentOr, S as withoutGeneratedFallbackName, T as STACK_REF_MAX_CODE_POINTS, _ as getCurrentSkipPrefix, b as withSkipPrefix, c as getLiveRenderer, f as applyDefaultNameForFallback, g as generateResourceNameWithFallback, h as generateResourceName, j as displayStackName, k as displayIdent, m as explicitNamePropertyFor, n as getLogger, r as isStdoutReservedForPayload, s as installLogLineMaskerSource, v as getCurrentStackName, w as SECRET_REF_MAX_CODE_POINTS, x as withStackName, y as looksLikeCdkdGeneratedName } from "./logger-Dvc7ddKe.js";
3
+ import { $n as markRedactedCause, $t as LockError, A as isTerminalDeleteFailure, At as CUSTOM_RESOURCE_RESPONSE_PREFIX, Bn as isAmbiguousCcHandlerErrorCode, Bt as clientDefaultsFor, C as refusalTypeShown, Cn as physicalIdShownBesideCommand, Ct as buildForceUnlockCommand, D as ProtectionFlipRegistry, Dn as shellQuote, Dt as formatLockOperation, En as shellBoundedDisplay, Et as formatLockExpiry, Fn as isRecreateRetryableError, Ft as producerRecordKey, Gn as retryClassificationText, H as pasteableAwsCommand, Hn as isIamPropagationError, Ht as AccountIdUnavailableError, In as isReplayedNameCollisionFrom, J as isInterruptedWaitError, Jn as safeStringify$1, Kn as describeAwsFailure, Kt as CrossAccountSecretRefusalError, Lt as withPasteableAwsProfile, M as observeThenDisableProtection, Mn as hasReplayMayCollide, Mt as injectiveKey, N as protectionFlipKey, Nn as isNameCollisionErrorFrom, O as compensateProtectionFlip, On as withheldTargetClause, Ot as formatLockOwner, Pn as isNameCooldownError, Q as canonicalizeRoute53QueryName, Qn as markNonRetryable, R as DELETION_PROTECTION_DOC_POINTER, Rn as markReplayMayCollide, Rt as ambientClientDefaults, S as quotedRemedyLogicalId, Sn as pasteableCommand, St as UNREPRODUCIBLE_LOCK_CLAUSE, T as resolveExplicitPhysicalId, Tn as quotedOrDescribed, U as protectedReplacementAdvice, Un as isRetryableTransientError, Ut as AssetError, Vn as isAmbiguousOutcomeError, Vt as credentialFingerprint, Wn as isTransientServerError, Wt as CdkdError, X as ElapsedBudgetRegistry, Xn as isMarkedNonRetryable, Xt as IntrinsicResolutionRefusalError, Y as startInterruptWatch, Yt as DynamicReferenceRegionAmbiguousError, Z as monotonicNowMs, Zn as isThrottlingError, _n as SHELL_ACTIVE_WHY, _t as hasCreatedBeforeFailure, an as ResourceTimeoutError, at as segmentAfterAnchor, b as isQuotableImportValue, bt as markAuxiliaryFailure, ct as createMaskedRetryLogger, d as prepareRemovalForUpdate, dt as maskerOrIdentity, en as MacroExpansionError, er as wrapMaskedAwsError, et as compositeIdSeparatorRefusal, f as removalWarning, ft as withDerivedNameMasks, g as assertRegionMatch, gn as SHELL_ACTIVE, gt as createdBeforeFailure, h as RESOURCE_NOT_FOUND, i as holdsSecretDerivedEntry, in as ProvisioningError, it as resourceTypeShown, jn as isUpdateUnsupportedError, jt as DEFAULT_STATE_PREFIX, k as deleteWithProtectionCompensation, kt as sanitizeRecoveryValue, l as withUnchangedSecretPrincipalLists, ln as StateError, lt as isSecretDerivedValue, m as withoutInjectedRemovals, mt as carryCreatedBeforeFailure, nt as logicalIdShown, on as ResourceUpdateNotSupportedError, ot as stateOrphanRecordRemedy, pn as normalizeAwsError, pt as RETRY_AUXILIARY_OWNER, qt as DependencyError, st as createMaskedLogSinks, tn as MalformedProducerRecordRefusalError, un as SynthesisError, ut as maskDeep, vn as UNSHOWABLE_VALUE, vt as isAuxiliaryFailure, wn as plainOrDescribed, x as normalizeAwsTagsToCfn, xn as isInertUnquoted, xt as markCreatedBeforeFailure, yn as commandHole, yt as isAuxiliaryMarkOf, zn as formatRetryClassificationSignals, zt as ambientCredentialConfig } from "./iam-policy-targets-DSDSdxXz.js";
4
4
  import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, s as ambientRegion, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-D0q0z4dG.js";
5
- import { t as getCdkdVersion } from "./version-Bqzsng8Y.js";
5
+ import { t as getCdkdVersion } from "./version-Dpc_HYX0.js";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
8
8
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -4976,7 +4976,7 @@ async function rebuildClientForBucketRegion(client, bucket, opts = {}) {
4976
4976
 
4977
4977
  //#endregion
4978
4978
  //#region src/state/s3-state-backend.ts
4979
- function errorDetail$1(error) {
4979
+ function errorDetail$2(error) {
4980
4980
  return displaySafe(error instanceof Error ? error.message : error, { asciiOnly: true }) || "<unrenderable>";
4981
4981
  }
4982
4982
  const LEGACY_KEY_DEPTH = 2;
@@ -5096,7 +5096,7 @@ var S3StateBackend = class {
5096
5096
  } catch (error) {
5097
5097
  if (!isNoSuchKey(error)) {
5098
5098
  if (error instanceof StateError) throw error;
5099
- throw new StateError(`Failed to get state for stack ${shownStackName} (${shownRegionName}): ${errorDetail$1(error)}`, error instanceof Error ? error : void 0);
5099
+ throw new StateError(`Failed to get state for stack ${shownStackName} (${shownRegionName}): ${errorDetail$2(error)}`, error instanceof Error ? error : void 0);
5100
5100
  }
5101
5101
  this.logger.debug(`No state at new key for stack: ${shownStackName} (${shownRegionName})`);
5102
5102
  }
@@ -5143,7 +5143,7 @@ var S3StateBackend = class {
5143
5143
  }));
5144
5144
  this.logger.info(`Migrated state for stack ${this.displayName(stackName)} to region-scoped layout (${displayIdent(region)})`);
5145
5145
  } catch (deleteError) {
5146
- this.logger.warn(`Migrated stack ${this.displayName(stackName)} to new key, but failed to delete legacy key: ${errorDetail$1(deleteError)}`);
5146
+ this.logger.warn(`Migrated stack ${this.displayName(stackName)} to new key, but failed to delete legacy key: ${errorDetail$2(deleteError)}`);
5147
5147
  }
5148
5148
  await notifyStateSaved(stackName, region);
5149
5149
  return response.ETag;
@@ -5153,7 +5153,7 @@ var S3StateBackend = class {
5153
5153
  bucket: this.config.bucket,
5154
5154
  operation: "PutObject"
5155
5155
  });
5156
- throw new StateError(`Failed to save state for stack ${this.stackRef(stackName, region)}: ${errorDetail$1(normalized)}`, normalized);
5156
+ throw new StateError(`Failed to save state for stack ${this.stackRef(stackName, region)}: ${errorDetail$2(normalized)}`, normalized);
5157
5157
  }
5158
5158
  }
5159
5159
  async deleteState(stackName, region) {
@@ -5185,7 +5185,7 @@ var S3StateBackend = class {
5185
5185
  bucket: this.config.bucket,
5186
5186
  operation: "DeleteObject"
5187
5187
  });
5188
- throw new StateError(`Failed to delete state for stack ${this.stackRef(stackName, region)}: ${errorDetail$1(normalized)}`, normalized);
5188
+ throw new StateError(`Failed to delete state for stack ${this.stackRef(stackName, region)}: ${errorDetail$2(normalized)}`, normalized);
5189
5189
  } finally {
5190
5190
  await this.deleteRollbackJournal(stackName, region);
5191
5191
  }
@@ -5207,7 +5207,7 @@ var S3StateBackend = class {
5207
5207
  bucket: this.config.bucket,
5208
5208
  operation: "DeleteObject"
5209
5209
  });
5210
- throw new StateError(`Failed to delete legacy state for stack ${displayStackName(stackName)}: ${errorDetail$1(normalized)}`, normalized);
5210
+ throw new StateError(`Failed to delete legacy state for stack ${displayStackName(stackName)}: ${errorDetail$2(normalized)}`, normalized);
5211
5211
  }
5212
5212
  }
5213
5213
  async listStacks() {
@@ -5378,7 +5378,7 @@ var S3StateBackend = class {
5378
5378
  });
5379
5379
  } catch (error) {
5380
5380
  const describing = options.objectDescription ? ` (${options.objectDescription})` : "";
5381
- this.logger.warn(`Could not purge noncurrent versions of ${keys.length} key(s) in bucket '${this.config.bucket}': the purge could not be started. Their previous versions survive and remain readable via GetObject with a VersionId${describing}. Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key(s) by hand. Underlying error: ${errorDetail$1(error)}`);
5381
+ this.logger.warn(`Could not purge noncurrent versions of ${keys.length} key(s) in bucket '${this.config.bucket}': the purge could not be started. Their previous versions survive and remain readable via GetObject with a VersionId${describing}. Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key(s) by hand. Underlying error: ${errorDetail$2(error)}`);
5382
5382
  }
5383
5383
  }
5384
5384
  async purgeNoncurrentVersionsUnderPrefix(keyPrefix, options = {}) {
@@ -5392,7 +5392,7 @@ var S3StateBackend = class {
5392
5392
  } catch (error) {
5393
5393
  const prefixShown = displayIdent(keyPrefix, { maxCodePoints: STACK_REF_MAX_CODE_POINTS });
5394
5394
  const describing = options.objectDescription ? ` (${options.objectDescription})` : "";
5395
- this.logger.warn(safeMsg`Could not purge noncurrent versions under the prefix ${prefixShown} in bucket ${this.config.bucket}: the purge could not be started. Their previous versions survive and remain readable via GetObject with a VersionId${describing}. Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the prefix by hand. Underlying error: ${errorDetail$1(error)}`);
5395
+ this.logger.warn(safeMsg`Could not purge noncurrent versions under the prefix ${prefixShown} in bucket ${this.config.bucket}: the purge could not be started. Their previous versions survive and remain readable via GetObject with a VersionId${describing}. Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the prefix by hand. Underlying error: ${errorDetail$2(error)}`);
5396
5396
  return {
5397
5397
  deletedBodies: 0,
5398
5398
  complete: false
@@ -5418,7 +5418,7 @@ var S3StateBackend = class {
5418
5418
  await this.saveCreateTokenLedger(stackName, region, ledger);
5419
5419
  } catch (error) {
5420
5420
  const normalized = normalizeAwsError(error, { bucket: this.config.bucket });
5421
- throw new StateError(`Failed to renew the create-token ledger of stack ${this.stackRef(stackName, region)}: ${errorDetail$1(normalized)}. The state record was left in place; re-run once the ledger can be written.`, normalized);
5421
+ throw new StateError(`Failed to renew the create-token ledger of stack ${this.stackRef(stackName, region)}: ${errorDetail$2(normalized)}. The state record was left in place; re-run once the ledger can be written.`, normalized);
5422
5422
  }
5423
5423
  }
5424
5424
  async deleteCreateTokenLedger(stackName, region) {
@@ -5435,7 +5435,7 @@ var S3StateBackend = class {
5435
5435
  bucket: this.config.bucket,
5436
5436
  operation: "DeleteObject"
5437
5437
  });
5438
- throw new StateError(`Failed to delete the create-token ledger for stack ${this.stackRef(stackName, region)}: ${errorDetail$1(normalized)}. The state record was left in place; re-run once the ledger can be deleted.`, normalized);
5438
+ throw new StateError(`Failed to delete the create-token ledger for stack ${this.stackRef(stackName, region)}: ${errorDetail$2(normalized)}. The state record was left in place; re-run once the ledger can be deleted.`, normalized);
5439
5439
  }
5440
5440
  }
5441
5441
  async loadRollbackJournal(stackName, region) {
@@ -5461,6 +5461,58 @@ var S3StateBackend = class {
5461
5461
  else newest.failedOperations = remaining;
5462
5462
  await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
5463
5463
  }
5464
+ async dropRollbackJournalFailedOperations(stackName, region, drop) {
5465
+ const journal = await this.loadRollbackJournal(stackName, region);
5466
+ if (!journal) return 0;
5467
+ let removed = 0;
5468
+ for (const segment of journal.segments) {
5469
+ if (!segment.failedOperations) continue;
5470
+ const kept = segment.failedOperations.filter((op) => !drop(op, segment));
5471
+ removed += segment.failedOperations.length - kept.length;
5472
+ if (kept.length === 0) delete segment.failedOperations;
5473
+ else segment.failedOperations = kept;
5474
+ }
5475
+ if (removed === 0) return 0;
5476
+ await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
5477
+ return removed;
5478
+ }
5479
+ async reduceRollbackJournalToFailedOperations(stackName, region, keep, supersededLogicalIds = [], demote = () => false) {
5480
+ const journal = await this.loadRollbackJournal(stackName, region);
5481
+ if (!journal) return 0;
5482
+ const carried = new Set(supersededLogicalIds);
5483
+ const kept = [];
5484
+ let count = 0;
5485
+ const keptBySegment = journal.segments.map((segment) => (segment.failedOperations ?? []).filter((op) => keep(op, segment)).map((op) => op.physicalIdRecoveredFromError === true && demote(op, segment) ? {
5486
+ ...op,
5487
+ physicalIdRecoveredFromError: false
5488
+ } : op));
5489
+ const keptIds = new Set(keptBySegment.flat().map((op) => op.logicalId));
5490
+ for (let s = journal.segments.length - 1; s >= 0; s--) {
5491
+ const segment = journal.segments[s];
5492
+ for (const op of segment.operations) carried.add(op.logicalId);
5493
+ for (const id of segment.supersededLogicalIds ?? []) carried.add(id);
5494
+ const failed = keptBySegment[s];
5495
+ if (failed.length === 0) continue;
5496
+ const reduced = {
5497
+ ...segment,
5498
+ initialDeploy: false,
5499
+ operations: [],
5500
+ failedOperations: failed
5501
+ };
5502
+ delete reduced.previousOutputs;
5503
+ delete reduced.previousCrossStackReads;
5504
+ addSupersededIds(reduced, [...carried].filter((id) => !keptIds.has(id) || segment.supersededLogicalIds?.includes(id)));
5505
+ kept.unshift(reduced);
5506
+ count += failed.length;
5507
+ }
5508
+ if (kept.length === 0) {
5509
+ await this.deleteRollbackJournal(stackName, region);
5510
+ return 0;
5511
+ }
5512
+ journal.segments = kept;
5513
+ await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
5514
+ return count;
5515
+ }
5464
5516
  async popRollbackJournalSegment(stackName, region) {
5465
5517
  const journal = await this.loadRollbackJournal(stackName, region);
5466
5518
  if (!journal || journal.segments.length === 0) {
@@ -5529,7 +5581,7 @@ var S3StateBackend = class {
5529
5581
  } catch (error) {
5530
5582
  if (!isNoSuchKey(error) && error.name !== "NotFound") {
5531
5583
  gone = false;
5532
- this.logger.warn(`Failed to delete rollback journal for ${this.stackRef(stackName, region)}: ${errorDetail$1(error)}`);
5584
+ this.logger.warn(`Failed to delete rollback journal for ${this.stackRef(stackName, region)}: ${errorDetail$2(error)}`);
5533
5585
  }
5534
5586
  }
5535
5587
  await this.purgeNoncurrentVersions([key], { objectDescription: "the rollback journal, whose `failedOperations[].attemptedProperties` records the properties of the failed write verbatim" });
@@ -5647,7 +5699,7 @@ var S3StateBackend = class {
5647
5699
  };
5648
5700
  } catch (error) {
5649
5701
  if (isNoSuchKey(error)) return null;
5650
- throw new StateError(`Failed to get legacy state for stack ${this.displayName(stackName)}: ${errorDetail$1(error)}`, error instanceof Error ? error : void 0);
5702
+ throw new StateError(`Failed to get legacy state for stack ${this.displayName(stackName)}: ${errorDetail$2(error)}`, error instanceof Error ? error : void 0);
5651
5703
  }
5652
5704
  }
5653
5705
  parseStateBody(bodyString, stackName) {
@@ -5699,7 +5751,7 @@ function safeSegment(value) {
5699
5751
  function stackRef(stackName, region) {
5700
5752
  return region === void 0 ? safeSegment(stackName) : `${safeSegment(stackName)} (${safeSegment(region)})`;
5701
5753
  }
5702
- function errorDetail(error) {
5754
+ function errorDetail$1(error) {
5703
5755
  return displaySafe(error instanceof Error ? error.message : error, { asciiOnly: true }) || "<unrenderable>";
5704
5756
  }
5705
5757
  function isLockInfoExpired(lockInfo) {
@@ -5835,7 +5887,7 @@ var LockManager = class {
5835
5887
  }
5836
5888
  return false;
5837
5889
  }
5838
- throw new LockError(`Failed to acquire lock for stack ${safeSegment(stackName)} (${safeSegment(region)}): ` + errorDetail(error), error instanceof Error ? error : void 0);
5890
+ throw new LockError(`Failed to acquire lock for stack ${safeSegment(stackName)} (${safeSegment(region)}): ` + errorDetail$1(error), error instanceof Error ? error : void 0);
5839
5891
  }
5840
5892
  }
5841
5893
  async putLockObject(key, lockInfo, condition = { IfNoneMatch: "*" }) {
@@ -5890,7 +5942,7 @@ var LockManager = class {
5890
5942
  return null;
5891
5943
  }
5892
5944
  if (error instanceof LockError) throw error;
5893
- throw new LockError(`Failed to get lock info for stack ${shownStack}: ${errorDetail(error)}`, error instanceof Error ? error : void 0);
5945
+ throw new LockError(`Failed to get lock info for stack ${shownStack}: ${errorDetail$1(error)}`, error instanceof Error ? error : void 0);
5894
5946
  }
5895
5947
  }
5896
5948
  async isLocked(stackName, region) {
@@ -5938,16 +5990,16 @@ var LockManager = class {
5938
5990
  this.logger.warn(`Not releasing the lock for stack ${stackRef(stackName, region)}: the conditional delete could not be evaluated here, and this process could not confirm the lock is still its own. Leaving it in place rather than risk deleting another process's lock. It expires on its own, or clear it with cdkd force-unlock. If this repeats, grant s3:GetObject on the lock key -- a delete conditioned on an ETag requires it.`);
5939
5991
  return;
5940
5992
  }
5941
- this.logger.debug(`Conditional lock release for stack ${stackRef(stackName, region)} is not supported here (${errorDetail(error)}); retrying unconditionally`);
5993
+ this.logger.debug(`Conditional lock release for stack ${stackRef(stackName, region)} is not supported here (${errorDetail$1(error)}); retrying unconditionally`);
5942
5994
  try {
5943
5995
  await this.deleteLock(stackName, region);
5944
5996
  this.logger.debug(`Lock released for stack: ${stackRef(stackName, region)}`);
5945
5997
  return;
5946
5998
  } catch (fallbackError) {
5947
- throw new LockError(`Failed to release lock for stack ${stackRef(stackName, region)}: ${errorDetail(fallbackError)}`, fallbackError instanceof Error ? fallbackError : void 0);
5999
+ throw new LockError(`Failed to release lock for stack ${stackRef(stackName, region)}: ${errorDetail$1(fallbackError)}`, fallbackError instanceof Error ? fallbackError : void 0);
5948
6000
  }
5949
6001
  }
5950
- throw new LockError(`Failed to release lock for stack ${stackRef(stackName, region)}: ${errorDetail(error)}`, error instanceof Error ? error : void 0);
6002
+ throw new LockError(`Failed to release lock for stack ${stackRef(stackName, region)}: ${errorDetail$1(error)}`, error instanceof Error ? error : void 0);
5951
6003
  } finally {
5952
6004
  await this.purgeLockVersions(this.getLockKey(stackName, region), "release");
5953
6005
  }
@@ -6006,7 +6058,7 @@ var LockManager = class {
6006
6058
  objectDescription: LOCK_OBJECT_DESCRIPTION
6007
6059
  });
6008
6060
  } catch (error) {
6009
- report(`Could not purge noncurrent versions of the lock key ${displayIdent(key, { maxCodePoints: STACK_REF_MAX_CODE_POINTS })} in bucket '${this.config.bucket}': the purge could not be started. Their previous versions survive and remain readable via GetObject with a VersionId (${LOCK_OBJECT_DESCRIPTION}). Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key by hand. Underlying error: ${errorDetail(error)}`);
6061
+ report(`Could not purge noncurrent versions of the lock key ${displayIdent(key, { maxCodePoints: STACK_REF_MAX_CODE_POINTS })} in bucket '${this.config.bucket}': the purge could not be started. Their previous versions survive and remain readable via GetObject with a VersionId (${LOCK_OBJECT_DESCRIPTION}). Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key by hand. Underlying error: ${errorDetail$1(error)}`);
6010
6062
  }
6011
6063
  }
6012
6064
  trackHeldLock(args) {
@@ -6086,7 +6138,7 @@ var LockManager = class {
6086
6138
  this.logger.warn(`Lost the lock for stack ${stackRef(held.stackName, held.region)} while the operation was still running: the lock object has been replaced or removed. Another cdkd process may now be writing to this stack concurrently. This process will not delete the current lock when it finishes.`);
6087
6139
  return;
6088
6140
  }
6089
- this.logger.debug(`Lock renewal for stack ${stackRef(held.stackName, held.region)} failed, will retry: ${errorDetail(error)}`);
6141
+ this.logger.debug(`Lock renewal for stack ${stackRef(held.stackName, held.region)} failed, will retry: ${errorDetail$1(error)}`);
6090
6142
  if (!held.warnedPastExpiry && Date.now() >= held.info.expiresAt) {
6091
6143
  held.warnedPastExpiry = true;
6092
6144
  this.logger.warn(`Lock renewal for stack ${stackRef(held.stackName, held.region)} has been failing long enough that the lock expired at ${new Date(held.info.expiresAt).toISOString()}. Another cdkd process can now take it while this operation is still running. Renewal keeps retrying.`);
@@ -7622,6 +7674,10 @@ const CLASSIFIER_IDENTIFIER_FIELDS = /* @__PURE__ */ new Set([
7622
7674
  function isAuxiliaryAnchor(key, descriptor) {
7623
7675
  return key === "logicalId" && descriptor.enumerable === false && descriptor.writable === false && typeof descriptor.value === "string" && descriptor.value.endsWith("/auxiliary");
7624
7676
  }
7677
+ const CREATED_BEFORE_FAILURE_MARK = Symbol.for("cdkd.createdBeforeFailure");
7678
+ function isCreatedBeforeFailureMark(key, descriptor) {
7679
+ return key === CREATED_BEFORE_FAILURE_MARK && descriptor.enumerable === false && descriptor.writable === false && typeof descriptor.value === "object" && descriptor.value !== null && Object.isFrozen(descriptor.value);
7680
+ }
7625
7681
  function isPlainContainer(value) {
7626
7682
  const proto = Object.getPrototypeOf(value);
7627
7683
  return Array.isArray(value) ? proto === Array.prototype : proto === Object.prototype || proto === null;
@@ -7709,7 +7765,7 @@ function maskSecretsInError(error, secrets, extraMask) {
7709
7765
  if (key === "message" || key === "cause" || key === "stack") continue;
7710
7766
  const descriptor = Object.getOwnPropertyDescriptor(link, key);
7711
7767
  if (!descriptor) continue;
7712
- descriptors[key] = typeof key === "string" && CLASSIFIER_IDENTIFIER_FIELDS.has(key) && typeof descriptor.value === "string" || isAuxiliaryAnchor(key, descriptor) ? descriptor : maskDescriptorValue(descriptor, maskText);
7768
+ descriptors[key] = typeof key === "string" && CLASSIFIER_IDENTIFIER_FIELDS.has(key) && typeof descriptor.value === "string" || isAuxiliaryAnchor(key, descriptor) || isCreatedBeforeFailureMark(key, descriptor) ? descriptor : maskDescriptorValue(descriptor, maskText);
7713
7769
  if (descriptors[key] !== descriptor) changed = true;
7714
7770
  }
7715
7771
  let cause = Object.getOwnPropertyDescriptor(link, "cause");
@@ -9107,129 +9163,6 @@ var ReplacementRulesRegistry = class {
9107
9163
  }
9108
9164
  };
9109
9165
 
9110
- //#endregion
9111
- //#region src/provisioning/auxiliary-failure.ts
9112
- const AUXILIARY_LOGICAL_ID_SUFFIX = "/auxiliary";
9113
- const MAX_DEPTH = 5;
9114
- function auxiliaryLogicalId(ownerLogicalId) {
9115
- return `${ownerLogicalId}${AUXILIARY_LOGICAL_ID_SUFFIX}`;
9116
- }
9117
- const RETRY_AUXILIARY_OWNER = "withRetry";
9118
- function isAuxiliaryMarkOf(link, ownerLogicalId) {
9119
- try {
9120
- if (typeof link !== "object" && typeof link !== "function" || link === null) return false;
9121
- const own = Object.getOwnPropertyDescriptor(link, "logicalId");
9122
- return isAuxiliaryMark(own) && own?.value === auxiliaryLogicalId(ownerLogicalId);
9123
- } catch {
9124
- return false;
9125
- }
9126
- }
9127
- function isAuxiliaryMark(descriptor) {
9128
- return descriptor !== void 0 && descriptor.enumerable === false && descriptor.writable === false && typeof descriptor.value === "string" && descriptor.value.endsWith(AUXILIARY_LOGICAL_ID_SUFFIX);
9129
- }
9130
- function isAuxiliaryFailure(error) {
9131
- try {
9132
- let current = error;
9133
- for (let depth = 0; depth < MAX_DEPTH && typeof current === "object" && current !== null; depth++) {
9134
- if (isAuxiliaryMark(Object.getOwnPropertyDescriptor(current, "logicalId"))) return true;
9135
- current = current.cause;
9136
- }
9137
- } catch {}
9138
- return false;
9139
- }
9140
- const CREATED_BEFORE_FAILURE = Symbol.for("cdkd.createdBeforeFailure");
9141
- function markCreatedBeforeFailure(error, ownerLogicalId, resourceType, physicalId) {
9142
- try {
9143
- if (typeof error !== "object" || error === null || !Object.isExtensible(error)) return error;
9144
- if (physicalId === "") return error;
9145
- Object.defineProperty(error, CREATED_BEFORE_FAILURE, {
9146
- value: Object.freeze({
9147
- logicalId: ownerLogicalId,
9148
- resourceType,
9149
- physicalId
9150
- }),
9151
- enumerable: false,
9152
- writable: false,
9153
- configurable: true
9154
- });
9155
- } catch {}
9156
- return error;
9157
- }
9158
- function createdMarkOn(link) {
9159
- const value = link[CREATED_BEFORE_FAILURE];
9160
- if (typeof value !== "object" || value === null) return void 0;
9161
- const { logicalId, resourceType, physicalId } = value;
9162
- if (typeof logicalId !== "string" || typeof resourceType !== "string" || typeof physicalId !== "string" || physicalId === "") return;
9163
- return {
9164
- logicalId,
9165
- resourceType,
9166
- physicalId
9167
- };
9168
- }
9169
- function createdBeforeFailure(error, logicalId, resourceType) {
9170
- try {
9171
- let current = error;
9172
- for (let depth = 0; depth < 10 && typeof current === "object" && current !== null; depth++) {
9173
- const mark = createdMarkOn(current);
9174
- if (mark) return mark.logicalId === logicalId && mark.resourceType === resourceType ? mark.physicalId : void 0;
9175
- const own = Object.getOwnPropertyDescriptor(current, "logicalId");
9176
- if (typeof own?.value === "string" && own.value !== logicalId && !isAuxiliaryMarkOf(current, logicalId)) return;
9177
- current = current.cause;
9178
- }
9179
- } catch {}
9180
- }
9181
- function hasCreatedBeforeFailure(error) {
9182
- try {
9183
- let current = error;
9184
- for (let depth = 0; depth < 10 && typeof current === "object" && current !== null; depth++) {
9185
- if (createdMarkOn(current)) return true;
9186
- current = current.cause;
9187
- }
9188
- } catch {}
9189
- return false;
9190
- }
9191
- function carryCreatedBeforeFailure(from, to) {
9192
- try {
9193
- if (typeof to !== "object" || to === null) return to;
9194
- let current = from;
9195
- let mark;
9196
- for (let depth = 0; depth < 10 && typeof current === "object" && current !== null && !mark; depth++) {
9197
- mark = createdMarkOn(current);
9198
- current = current.cause;
9199
- }
9200
- if (!mark) return to;
9201
- let probe = to;
9202
- for (let depth = 0; depth < 10 && typeof probe === "object" && probe !== null; depth++) {
9203
- if (createdMarkOn(probe)) return to;
9204
- probe = probe.cause;
9205
- }
9206
- return markCreatedBeforeFailure(to, mark.logicalId, mark.resourceType, mark.physicalId);
9207
- } catch {
9208
- return to;
9209
- }
9210
- }
9211
- function markAuxiliaryFailure(error, ownerLogicalId) {
9212
- try {
9213
- let current = error;
9214
- for (let depth = 0; depth < MAX_DEPTH && typeof current === "object" && current !== null; depth++) {
9215
- const own = Object.getOwnPropertyDescriptor(current, "logicalId");
9216
- if (typeof own?.value === "string") {
9217
- if (isAuxiliaryMark(own)) return error;
9218
- } else {
9219
- if (Object.isExtensible(current) && own?.configurable !== false) Object.defineProperty(current, "logicalId", {
9220
- value: auxiliaryLogicalId(ownerLogicalId),
9221
- enumerable: false,
9222
- writable: false,
9223
- configurable: true
9224
- });
9225
- return error;
9226
- }
9227
- current = current.cause;
9228
- }
9229
- } catch {}
9230
- return error;
9231
- }
9232
-
9233
9166
  //#endregion
9234
9167
  //#region src/deployment/retry.ts
9235
9168
  const IAM_PROPAGATION_INITIAL_DELAY_MS = 250;
@@ -15291,10 +15224,10 @@ function refuseMalformedResourcesForDestroy(state, stackName, region, recovery)
15291
15224
  throw markNonRetryable(new CdkdError(malformedDestroyResourcesRefusalMessage(stackName, region, recovery), STATE_RESOURCES_MALFORMED));
15292
15225
  }
15293
15226
  const STATE_REGION_DIVERGED = "STATE_REGION_DIVERGED";
15294
- function divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBodyRegion, resourceCount, recovery) {
15227
+ function divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBodyRegion, resourceCount, recovery, provenOrphans = 0) {
15295
15228
  const cap = STACK_REF_MAX_CODE_POINTS;
15296
15229
  const exact = rendersExactly(stackName, cap) && rendersExactly(keyRegion, cap) && isPasteableIdent(stackName) && isPasteableIdent(keyRegion);
15297
- const lists = resourceCount === void 0 ? "its resources map cannot be read" : `it still lists ${resourceCount} resource${resourceCount === 1 ? "" : "s"}`;
15230
+ const lists = resourceCount === void 0 ? "its resources map cannot be read" : resourceCount === 0 && provenOrphans > 0 ? `its rollback journal holds ${provenOrphans} failed create${provenOrphans === 1 ? "" : "s"} whose resource the destroy would delete` : `it still lists ${resourceCount} resource${resourceCount === 1 ? "" : "s"}`;
15298
15231
  const kind = describeRegionValueKind(divergentBodyRegion);
15299
15232
  const opening = exact ? `cdkd will not destroy stack ${shellQuote(safeIdentifier(stackName, cap))} (${shellQuote(safeIdentifier(keyRegion, cap))}): the state record read from that region's key carries a 'region' of its own (${kind}) that is not the key's, and ${lists}` : `cdkd will not destroy the state record this command loaded: it carries a 'region' of its own (${kind}) that is not the region of the key it was read from, and ${lists}`;
15300
15233
  const listing = withheldListingPointer(recovery);
@@ -15302,11 +15235,11 @@ function divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBody
15302
15235
  const remedy = exact ? "Re-run with --verbose to see what the record's region field holds, then either destroy against the region the resources are really in, or repair that field to match the key it is stored under and re-run. " + withheldAccountClause(withheldAccounts, "the command at the end of this message prints") + "To drop the record and leave the live resources standing, spelled out rather than pasteable because that command DELETES a record: " + dropRecordTemplate(recovery) : "This record's stack name or region does NOT render exactly — what any surrounding output shows is a sanitized form, and another record may render identically — so this message names no target and offers no command against one. List the records with " + (listing.line === void 0 ? `${WITHHELD_LISTING_POINTER}. Inspect it with: ${inspectCommand(void 0, void 0)}` : `${listing.pointer}.` + destroyAccountClause(recovery) + `\n${listing.line}\nInspect it with: ${inspectCommand(void 0, void 0, recovery)}`);
15303
15236
  return `${opening} ${resourceCount === void 0 ? `— so cdkd can neither count what it would delete nor tell which region it is in` : `— so cdkd cannot tell which region those resources are in`}. cdkd stamps the key's region into every record it writes, so this record was not written by cdkd. Destroying against the key's region would issue every delete there; if the record's own region is the honest half, each delete comes back not-found, which this command reads as ALREADY DELETED — it would report success, remove the record, and leave every resource standing in the other region with nothing naming it. ${remedy}`;
15304
15237
  }
15305
- function refuseDivergentRecordRegionForDestroy(state, stackName, keyRegion, divergentBodyRegion, recovery) {
15238
+ function refuseDivergentRecordRegionForDestroy(state, stackName, keyRegion, divergentBodyRegion, recovery, provenOrphans = 0) {
15306
15239
  if (divergentBodyRegion === void 0) return;
15307
15240
  const resourceCount = isReadableBag(state.resources) ? Object.keys(state.resources).length : void 0;
15308
- if (resourceCount === 0) return;
15309
- throw markNonRetryable(new CdkdError(divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBodyRegion, resourceCount, recovery), STATE_REGION_DIVERGED));
15241
+ if (resourceCount === 0 && provenOrphans === 0) return;
15242
+ throw markNonRetryable(new CdkdError(divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBodyRegion, resourceCount, recovery, provenOrphans), STATE_REGION_DIVERGED));
15310
15243
  }
15311
15244
  function malformedDeployResourcesRefusalMessage(rawStackName, rawRegion) {
15312
15245
  const stackName = absentIfEmpty(rawStackName);
@@ -15994,7 +15927,7 @@ function isPlainObject$2(value) {
15994
15927
  return value !== null && typeof value === "object" && !Array.isArray(value);
15995
15928
  }
15996
15929
  const DYNAMIC_REFERENCE_OPEN = "{{resolve:";
15997
- const NESTED_STACK_TYPE$2 = "AWS::CloudFormation::Stack";
15930
+ const NESTED_STACK_TYPE$3 = "AWS::CloudFormation::Stack";
15998
15931
  const NESTED_OUTPUT_PREFIX = "Outputs.";
15999
15932
  function carriesSecretValue(value, corpora) {
16000
15933
  if (carriesSecretMask(value)) return true;
@@ -16069,7 +16002,7 @@ function intrinsicKey(value) {
16069
16002
  const key = keys[0];
16070
16003
  return key === "Ref" || key.startsWith("Fn::") ? key : void 0;
16071
16004
  }
16072
- const OPAQUE_ATTRIBUTE_TYPES = /* @__PURE__ */ new Set(["AWS::CloudFormation::CustomResource", NESTED_STACK_TYPE$2]);
16005
+ const OPAQUE_ATTRIBUTE_TYPES = /* @__PURE__ */ new Set(["AWS::CloudFormation::CustomResource", NESTED_STACK_TYPE$3]);
16073
16006
  function hasOpaqueAttributes(logicalId, walk) {
16074
16007
  const definition = walk.resources[logicalId];
16075
16008
  const type = isPlainObject$2(definition) ? definition["Type"] : void 0;
@@ -16426,7 +16359,7 @@ function passedKey(passed) {
16426
16359
  function isNestedStackRow(logicalId, walk) {
16427
16360
  if (!Object.hasOwn(walk.resources, logicalId)) return false;
16428
16361
  const definition = walk.resources[logicalId];
16429
- return isPlainObject$2(definition) && definition["Type"] === NESTED_STACK_TYPE$2;
16362
+ return isPlainObject$2(definition) && definition["Type"] === NESTED_STACK_TYPE$3;
16430
16363
  }
16431
16364
  function getAttAttribute(operand, target) {
16432
16365
  if (Array.isArray(operand)) return operand.length === 2 && typeof operand[1] === "string" ? operand[1] : void 0;
@@ -18046,6 +17979,7 @@ async function resolveGetAtt(getAtt, context) {
18046
17979
  }
18047
17980
  const resource = this.lookupResourceRecord(logicalId, "Fn::GetAtt", context);
18048
17981
  if (!resource) throw markNonRetryable(/* @__PURE__ */ new Error(`Resource ${this.displayMasked(logicalId, context)} not found for Fn::GetAtt`));
17982
+ recordSecretNamedRead(logicalId, void 0, context);
18049
17983
  if (!(resource.resourceType === "AWS::EC2::VPC" && attributeName === "Ipv6CidrBlocks") && resource.attributes !== void 0) {
18050
17984
  const storedValue = Object.hasOwn(resource.attributes, attributeName) ? resource.attributes[attributeName] : void 0;
18051
17985
  const flatValue = isImpossibleEmptyStoredAttribute(resource.resourceType, attributeName, storedValue) ? void 0 : storedValue;
@@ -18099,6 +18033,7 @@ async function resolveGetAtt(getAtt, context) {
18099
18033
  throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${loggedLogicalId}, ${this.displayMasked(attributeName, context)}]: the nested stack ${quotedRender(loggedLogicalId, "'")} declares no output named ${quotedRender(this.displayMasked(this.outputNameLogText(attributeName, context), context), "'")}. Its outputs are ${this.displayMasked(declaredText, context)}. Check the output name in the nested stack's template, and deploy the child stack again if you have just added it.`));
18100
18034
  }
18101
18035
  const value = await this.constructWithStaleRecordHeal(resource, attributeName, context, logicalId);
18036
+ recordSecretNamedRead(logicalId, value, context);
18102
18037
  this.logger.debug(`Resolved Fn::GetAtt: ${this.logRender(logicalId, context)}.${this.logRender(attributeName, context)} resolved to ${this.logRender(stringifyAttributeForLog(attributeName, this.maskValueLeaves(value, context)), context, {
18103
18038
  structured: isStructured(value),
18104
18039
  redacted: isSensitiveAttributeName(attributeName)
@@ -18128,6 +18063,7 @@ function publicNoEchoTokens(context, producer) {
18128
18063
  return tokens;
18129
18064
  }
18130
18065
  function noteAttributeSecrecy(logicalId, attributeName, value, context) {
18066
+ recordSecretNamedRead(logicalId, value, context);
18131
18067
  const declared = context.noEchoAttributeResources?.get(logicalId);
18132
18068
  if ((declared === true || declared !== void 0 && declared.has(attributeName)) && context.recordedSecretValues) recordFreshNoEchoValuesIn(value, context.recordedSecretValues, void 0, this.publicNoEchoTokens(context, logicalId));
18133
18069
  if (context.redactedAttributeReads !== void 0 && carriesSecretMask(value)) {
@@ -18141,6 +18077,17 @@ function noteAttributeSecrecy(logicalId, attributeName, value, context) {
18141
18077
  }
18142
18078
  return value;
18143
18079
  }
18080
+ function recordSecretNamedRead(logicalId, value, context) {
18081
+ const bag = context.printingSecrets ?? context.recordedSecretValues;
18082
+ if (bag === void 0 || context.secretNameNeedles === void 0) return;
18083
+ const needles = context.secretNameNeedles(logicalId);
18084
+ if (needles === void 0) return;
18085
+ for (const needle of needles) recordLogOnlyValue(bag, needle);
18086
+ for (const leaf of wholeStringLeavesOf(value)) for (const needle of needles) if (needle.length >= 4 && leaf.includes(needle)) {
18087
+ recordLogOnlyValue(bag, leaf);
18088
+ break;
18089
+ }
18090
+ }
18144
18091
  function rejectPlaceholderArnAttribute(resource, attributeName, value, logicalId, context, healOutcome) {
18145
18092
  if (!isStalePlaceholderArnAttribute(resource.resourceType, attributeName, value)) return;
18146
18093
  throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${this.displayMasked(logicalId, context)}, ${this.displayMasked(attributeName, context)}] for ${resource.resourceType}: the recorded value ${quotedRender(stringifyValue(this.maskValueLeaves(value, context)), "\"")} is a placeholder written by a cdkd version older than issue #1681 — its region and account fields are literal wildcards, so it is not a usable ARN. ` + this.staleRecordRemedy(healOutcome, context)));
@@ -20268,6 +20215,7 @@ async function resolveRef(logicalId, context, onParameter) {
20268
20215
  const resource = this.lookupResourceRecord(logicalId, "Ref", context);
20269
20216
  if (resource) {
20270
20217
  const refValue = this.resolveRefValue(logicalId, resource, context);
20218
+ recordSecretNamedRead(logicalId, refValue, context);
20271
20219
  this.logger.debug(`Resolved Ref to resource: ${this.logRender(logicalId, context)} resolved to ${this.logRender(String(refValue), context)}`);
20272
20220
  return refValue;
20273
20221
  }
@@ -22068,7 +22016,7 @@ var CloudControlProvider = class {
22068
22016
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
22069
22017
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
22070
22018
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
22071
- const { ASGProvider } = await import("./asg-provider-CbwOK2TQ.js");
22019
+ const { ASGProvider } = await import("./asg-provider-BwWy0pBH.js");
22072
22020
  const delegateRegion = ambientRegion();
22073
22021
  let asgProvider = this.asgDeleteDelegates.get(delegateRegion);
22074
22022
  if (asgProvider === void 0) {
@@ -22174,7 +22122,7 @@ var CloudControlProvider = class {
22174
22122
  const family = SDK_DELETE_FAMILIES.get(resourceType);
22175
22123
  const cached = this.sdkDeleteDelegates.get(family);
22176
22124
  if (cached !== void 0 && cached.region === ccRegion) return cached.provider;
22177
- const provider = family === "rds" ? new (await (import("./rds-provider-COCDd7bS.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-TnGNCeLX.js"))).NeptuneProvider({ region: ccRegion });
22125
+ const provider = family === "rds" ? new (await (import("./rds-provider-McCDKyXN.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-Cdp4jX8S.js"))).NeptuneProvider({ region: ccRegion });
22178
22126
  this.sdkDeleteDelegates.set(family, {
22179
22127
  region: ccRegion,
22180
22128
  provider
@@ -22997,6 +22945,10 @@ function withCurrentResourceSecrets(secrets, fn) {
22997
22945
  const outer = boundSecretBagsStore.getStore() ?? [];
22998
22946
  return boundSecretBagsStore.run([...outer, secrets], () => currentResourceSecretsStore.run(secrets, fn));
22999
22947
  }
22948
+ function withPrintingSecrets(secrets, fn) {
22949
+ const outer = boundSecretBagsStore.getStore() ?? [];
22950
+ return boundSecretBagsStore.run([...outer, secrets], fn);
22951
+ }
23000
22952
  function getCurrentResourceSecrets() {
23001
22953
  return currentResourceSecretsStore.getStore();
23002
22954
  }
@@ -23073,8 +23025,34 @@ const CR_MASKED_SERVICE_TOKEN_SKIP_REASON = "masked ServiceToken in state — De
23073
23025
  const CR_REFERENCE_SERVICE_TOKEN_SKIP_REASON = "dynamic reference as ServiceToken in state — handler not invoked";
23074
23026
  const CR_DELETE_INVOKE_FAILED_SKIP_REASON = "Delete request to the handler did not complete — resource unproven";
23075
23027
  const CR_DELETE_HANDLER_FAILED_SKIP_REASON = "Delete handler reported FAILED — resource unproven";
23076
- const CR_SKIP_NOT_A_RETRY_CAVEAT = "NOTE this record is a POINTER, not a retry: the same destroy run deletes the backing Lambda, so the next 'cdkd destroy' finds the handler gone and DROPS this record (issue 804 pre-check). Tear the resource down by hand, then clear the stack's records with 'cdkd state orphan <stack> --stack-region <region>' — that command drops EVERY record for the stack in that region, not just this one.";
23028
+ const CR_BACKING_LAMBDA_GONE_SKIP_REASON = "backing Lambda function is gone — Delete handler not invoked";
23029
+ function crSkipNotARetryCaveat(context, logicalId) {
23030
+ return `NOTE this record is a POINTER, not a retry: the same destroy run deletes the backing Lambda, so the next 'cdkd destroy' cannot reach the handler either: it skips this resource again and keeps the record (issue 2115). Tear the resource down by hand, then drop the record with ${stateOrphanRecordRemedy(context, logicalId)}.`;
23031
+ }
23077
23032
  const DEPLOY_SKIP_CAVEAT = "NOTE this arm is ALSO reached from cdkd deploy. Since issue 1762 the DELETE of a resource removed from the template behaves like destroy — the record is KEPT and the next deploy re-attempts it — but a REPLACEMENT / rollback delete FAILS the resource instead (https://github.com/go-to-k/cdkd/issues/1762), leaving the old one untracked; there, tear the resource down by hand.";
23033
+ function crDeployNoStateOrphan(logicalId) {
23034
+ return `For a resource removed from the template, to give up on the delete and stop tracking it, drop the record with ${stateOrphanRecordRemedy(void 0, logicalId)}.`;
23035
+ }
23036
+ function crDeploySkipTail(logicalId) {
23037
+ return "Meanwhile 'cdkd deploy --allow-unaddressed' exits 0 (a deploy-only flag; 'cdkd rollback' has none); the record stays and each deploy re-attempts the delete. A delete-first REPLACEMENT or a rollback delete usually FAILS the resource and keeps the record (https://github.com/go-to-k/cdkd/issues/1762). Where the other copy already exists (a replacement that created the new resource first, or a rollback that re-created the old one first), the skip only warns and the surviving copy is no longer tracked, so tear it down by hand. " + crDeployNoStateOrphan(logicalId);
23038
+ }
23039
+ const CR_DEPLOY_HANDLER_SKIP_HEAD = "This delete is not part of a stack destroy (a 'cdkd deploy' template removal, replacement or rollback, or a 'cdkd rollback'). For a resource removed from the template the record is KEPT and the next 'cdkd deploy' re-sends the Delete: fix what made it fail (the handler's Delete logic, or what stopped the invoke) and re-deploy. That reaches the handler only while its function exists: if this deploy also deleted the backing Lambda, the next deploy finds it gone and DROPS the record with a warning, so tear down what the handler manages by hand. ";
23040
+ const CR_DEPLOY_UNADDRESSABLE_HEAD = "This delete is not part of a stack destroy (a 'cdkd deploy' template removal, replacement or rollback, or a 'cdkd rollback'). For a resource removed from the template the record is KEPT and every 'cdkd deploy' skips it again until ServiceToken is restored: put the provider's Lambda function or SNS topic ARN back in state.json and re-deploy, which sends the Delete while that handler exists. If its Lambda function is gone, that deploy DROPS the record with a warning instead, so tear down what the handler manages by hand. ";
23041
+ function crDestroyUnaddressableRemedy(context, logicalId) {
23042
+ return `Tear the resource down by hand, then drop the record with ${stateOrphanRecordRemedy(context, logicalId)}. Restoring ServiceToken (the provider's Lambda function or SNS topic ARN) in state.json and re-running helps only while that handler still exists: a destroy goes on to delete its backing Lambda.`;
23043
+ }
23044
+ function handlerSkipRemedy(context, logicalId) {
23045
+ return context?.stackDestroy === true ? ` — cdkd is KEEPING the state record and the run exits non-zero. ${crSkipNotARetryCaveat(context, logicalId)}` : `. ${CR_DEPLOY_HANDLER_SKIP_HEAD}${crDeploySkipTail(logicalId)}`;
23046
+ }
23047
+ function crUnresolvedTokenUpdateRemedy() {
23048
+ return "This indicates an unresolved value in the template, or, on a rollback, in the resource's recorded state. Check that the template resolves ServiceToken to the provider's Lambda function or SNS topic ARN and re-deploy; a rollback replays the recorded value, so restore the template and re-deploy instead. Do not drop this record with 'cdkd state orphan', with or without --resource: the template still declares the resource, so the next deploy would send the handler a fresh Create and leave what it already manages untracked.";
23049
+ }
23050
+ function unresolvedTokenDeleteRemedy(context, logicalId) {
23051
+ return context?.stackDestroy === true ? `re-run 'cdkd import', or drop the record with ${stateOrphanRecordRemedy(context, logicalId)}, to recover.` : `put the provider's Lambda function or SNS topic ARN back as ServiceToken in state.json and re-run to recover. ${crDeployNoStateOrphan(logicalId)}`;
23052
+ }
23053
+ function unaddressableServiceTokenRemedy(context, logicalId) {
23054
+ return context?.stackDestroy === true ? crDestroyUnaddressableRemedy(context, logicalId) : `${CR_DEPLOY_UNADDRESSABLE_HEAD}${crDeploySkipTail(logicalId)}`;
23055
+ }
23078
23056
  function isCustomResourceResponsePayload(value) {
23079
23057
  if (typeof value !== "object" || value === null) return false;
23080
23058
  const payload = value;
@@ -23417,7 +23395,7 @@ var CustomResourceProvider = class CustomResourceProvider {
23417
23395
  this.logger.debug(`Creating custom resource ${logicalId} (${resourceType})`);
23418
23396
  const serviceToken = properties["ServiceToken"];
23419
23397
  if (!serviceToken) throw new ProvisioningError(`ServiceToken is required for custom resource ${logicalId}`, resourceType, logicalId);
23420
- if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). This usually indicates state was written by a pre-fix cdkd import; re-run 'cdkd import' or 'cdkd state orphan <stack> --stack-region <region>' to recover.`, resourceType, logicalId);
23398
+ if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). This indicates an unresolved value in the template, or, on a rollback, in the resource's recorded state. Check that the template resolves ServiceToken to the provider's Lambda function or SNS topic ARN; a rollback replays the recorded value, so restore the template and re-deploy instead.`, resourceType, logicalId);
23421
23399
  this.refuseResolvedSecret(logicalId, resourceType, properties);
23422
23400
  try {
23423
23401
  const cfnResponse = await this.invokeCustomResourceWithRetry(serviceToken, logicalId, "Create", (invocation) => ({
@@ -23448,7 +23426,7 @@ var CustomResourceProvider = class CustomResourceProvider {
23448
23426
  this.logger.debug(`Updating custom resource ${logicalId}: ${physicalId} (${resourceType})`);
23449
23427
  const serviceToken = properties["ServiceToken"];
23450
23428
  if (!serviceToken) throw new ProvisioningError(`ServiceToken is required for custom resource ${logicalId}`, resourceType, logicalId, physicalId);
23451
- if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). This usually indicates state was written by a pre-fix cdkd import; re-run 'cdkd import' or 'cdkd state orphan <stack> --stack-region <region>' to recover.`, resourceType, logicalId, physicalId);
23429
+ if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). ` + crUnresolvedTokenUpdateRemedy(), resourceType, logicalId, physicalId);
23452
23430
  this.refuseResolvedSecret(logicalId, resourceType, properties, physicalId, previousProperties);
23453
23431
  try {
23454
23432
  const cfnResponse = await this.invokeCustomResourceWithRetry(serviceToken, logicalId, "Update", (invocation) => ({
@@ -23478,7 +23456,7 @@ var CustomResourceProvider = class CustomResourceProvider {
23478
23456
  throw new ProvisioningError(`Failed to update custom resource ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
23479
23457
  }
23480
23458
  }
23481
- async delete(logicalId, physicalId, resourceType, properties, _context) {
23459
+ async delete(logicalId, physicalId, resourceType, properties, context) {
23482
23460
  this.logger.debug(`Deleting custom resource ${logicalId}: ${physicalId} (${resourceType})`);
23483
23461
  if (!properties) {
23484
23462
  this.logger.warn(`No properties available for custom resource ${logicalId}, skipping deletion — the handler is never invoked, so anything this custom resource manages is LEFT IN PLACE. Restore the record's properties in state.json and re-run, or tear the resource down by hand. ${DEPLOY_SKIP_CAVEAT}`);
@@ -23495,23 +23473,30 @@ var CustomResourceProvider = class CustomResourceProvider {
23495
23473
  reason: CR_NO_SERVICE_TOKEN_SKIP_REASON
23496
23474
  };
23497
23475
  }
23498
- if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). This usually indicates state was written by a pre-fix cdkd import; re-run 'cdkd import' or 'cdkd state orphan <stack> --stack-region <region>' to recover.`, resourceType, logicalId, physicalId);
23476
+ if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). This usually indicates state was written by a pre-fix cdkd import; ` + unresolvedTokenDeleteRemedy(context, logicalId), resourceType, logicalId, physicalId);
23499
23477
  if (carriesSecretMask(serviceToken)) {
23500
- this.logger.warn(safeMsg`ServiceToken for custom resource ${logicalId} is recorded in state as the redaction ` + safeMsg`mask '${"***"}' (a NoEcho value this resource reads equals, or is contained ` + "in, its ServiceToken), so cdkd cannot address the handler; skipping deletion — anything this custom resource manages is LEFT IN PLACE. Re-deploying does not repair the record while that attribute still carries the value. Tear the resource down by hand, then clear the stack's records with 'cdkd state orphan <stack> --stack-region <region>' — that command drops EVERY record for the stack in that region, not just this one. Restoring ServiceToken (the provider's Lambda function or SNS topic ARN) in state.json and re-running helps only while that handler still exists: a destroy goes on to delete its backing Lambda. " + safeMsg`${DEPLOY_SKIP_CAVEAT}`);
23478
+ this.logger.warn(safeMsg`ServiceToken for custom resource ${logicalId} is recorded in state as the redaction ` + safeMsg`mask '${"***"}' (a NoEcho value this resource reads equals, or is contained ` + "in, its ServiceToken), so cdkd cannot address the handler; skipping deletion — anything this custom resource manages is LEFT IN PLACE. Re-deploying does not repair the record while that attribute still carries the value. " + safeMsg`${unaddressableServiceTokenRemedy(context, logicalId)}`);
23501
23479
  return {
23502
23480
  outcome: "skipped",
23503
23481
  reason: CR_MASKED_SERVICE_TOKEN_SKIP_REASON
23504
23482
  };
23505
23483
  }
23506
23484
  if (dynamicReferenceTokens(serviceToken).length > 0) {
23507
- this.logger.warn(safeMsg`ServiceToken for custom resource ${logicalId} is recorded in state as a ` + "'{{resolve:...}}' dynamic reference, which cdkd does not resolve on delete, so it cannot address the handler; skipping deletion — anything this custom resource manages is LEFT IN PLACE. CloudFormation does not support secure (secretsmanager / ssm-secure) dynamic references in custom resources, and cdkd now refuses such a template at deploy time. Tear the resource down by hand, then clear the stack's records with 'cdkd state orphan <stack> --stack-region <region>' — that command drops EVERY record for the stack in that region, not just this one. Restoring ServiceToken (the provider's Lambda function or SNS topic ARN) in state.json and re-running helps only while that handler still exists: a destroy goes on to delete its backing Lambda. " + safeMsg`${DEPLOY_SKIP_CAVEAT}`);
23485
+ this.logger.warn(safeMsg`ServiceToken for custom resource ${logicalId} is recorded in state as a ` + "'{{resolve:...}}' dynamic reference, which cdkd does not resolve on delete, so it cannot address the handler; skipping deletion — anything this custom resource manages is LEFT IN PLACE. CloudFormation does not support secure (secretsmanager / ssm-secure) dynamic references in custom resources, and cdkd now refuses such a template at deploy time. " + safeMsg`${unaddressableServiceTokenRemedy(context, logicalId)}`);
23508
23486
  return {
23509
23487
  outcome: "skipped",
23510
23488
  reason: CR_REFERENCE_SERVICE_TOKEN_SKIP_REASON
23511
23489
  };
23512
23490
  }
23513
23491
  if (!this.isSnsServiceToken(serviceToken) && await this.isBackingLambdaGone(serviceToken)) {
23514
- this.logger.warn(`Backing Lambda for custom resource ${logicalId} no longer exists (${serviceToken}); treating the custom resource as already deleted and DROPPING its state record. The handler can never run again, so if its teardown was never PROVEN — e.g. an earlier run reported this resource as skipped (issue 2054) — whatever it manages is still LIVE and is now untracked by cdkd. Check for leftovers before treating the stack as gone.`);
23492
+ if (context?.stackDestroy === true) {
23493
+ this.logger.warn(safeMsg`Backing Lambda for custom resource ${logicalId} no longer exists (${serviceToken}), so ` + "its Delete handler cannot be invoked and cdkd cannot confirm the resource was deleted; skipping deletion — anything this custom resource manages may still be LIVE. cdkd is KEEPING the state record and the run exits non-zero, as CloudFormation leaves such a stack DELETE_FAILED. A re-run skips it again unless a function with that exact ARN exists again (e.g. a shared provider stack destroyed before this one, then redeployed). Otherwise confirm by hand that whatever it manages is gone (or tear it down), then drop the record with " + safeMsg`${stateOrphanRecordRemedy(context, logicalId)}.`);
23494
+ return {
23495
+ outcome: "skipped",
23496
+ reason: CR_BACKING_LAMBDA_GONE_SKIP_REASON
23497
+ };
23498
+ }
23499
+ this.logger.warn(safeMsg`Backing Lambda for custom resource ${logicalId} no longer exists (${serviceToken}); ` + "treating the custom resource as already deleted and DROPPING its state record, as CloudFormation ignores a delete failure in an update's cleanup phase. The handler can never run again, so if its teardown was never PROVEN, whatever it manages may still be LIVE and is now untracked by cdkd. Check for leftovers by hand.");
23515
23500
  return;
23516
23501
  }
23517
23502
  try {
@@ -23526,7 +23511,7 @@ var CustomResourceProvider = class CustomResourceProvider {
23526
23511
  ResourceProperties: this.stringifyProperties(properties)
23527
23512
  }), DELETE_PATH_UNMASKED);
23528
23513
  if (cfnResponse.Status === "FAILED") {
23529
- this.logger.warn(`Custom resource delete handler returned FAILED for ${logicalId}: ${cfnResponse.Reason || "Unknown reason"}. The handler reported that it did NOT delete, so anything this custom resource manages is LEFT IN PLACE — cdkd is KEEPING the state record and the run exits non-zero. ${CR_SKIP_NOT_A_RETRY_CAVEAT} ('cdkd deploy' also accepts --allow-unaddressed, which forces exit 0; 'cdkd destroy' has no such flag.) ${DEPLOY_SKIP_CAVEAT}`);
23514
+ this.logger.warn(`Custom resource delete handler returned FAILED for ${logicalId}: ${cfnResponse.Reason || "Unknown reason"}. The handler reported that it did NOT delete, so anything this custom resource manages is LEFT IN PLACE${handlerSkipRemedy(context, logicalId)}`);
23530
23515
  return {
23531
23516
  outcome: "skipped",
23532
23517
  reason: CR_DELETE_HANDLER_FAILED_SKIP_REASON
@@ -23534,7 +23519,7 @@ var CustomResourceProvider = class CustomResourceProvider {
23534
23519
  }
23535
23520
  this.logger.debug(`Successfully deleted custom resource ${logicalId}`);
23536
23521
  } catch (error) {
23537
- this.logger.warn(`Failed to delete custom resource ${logicalId}, but continuing: ${describeAwsFailure(error).detail}. The Delete handler did not complete, so anything this custom resource manages may still be LIVE — cdkd is KEEPING the state record and the run exits non-zero. ${CR_SKIP_NOT_A_RETRY_CAVEAT} ${DEPLOY_SKIP_CAVEAT}`);
23522
+ this.logger.warn(`Failed to delete custom resource ${logicalId}, but continuing: ${describeAwsFailure(error).detail}. The Delete handler did not complete, so anything this custom resource manages may still be LIVE${handlerSkipRemedy(context, logicalId)}`);
23538
23523
  return {
23539
23524
  outcome: "skipped",
23540
23525
  reason: CR_DELETE_INVOKE_FAILED_SKIP_REASON
@@ -26482,6 +26467,81 @@ function ownPoliciesChange(change) {
26482
26467
  return (change?.propertyChanges ?? []).some((c) => c.path === "Policies" && c.inPlacePropagated !== true && c.replacementPropagated !== true);
26483
26468
  }
26484
26469
 
26470
+ //#endregion
26471
+ //#region src/analyzer/destructive-changes.ts
26472
+ const IGNORED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["AWS::CDK::Metadata"]);
26473
+ const PATH_METADATA_KEY = "aws:cdk:path";
26474
+ function findDestructiveChanges(stackName, changes, records, template, recreateTargets = /* @__PURE__ */ new Set()) {
26475
+ const found = [];
26476
+ for (const change of changes) {
26477
+ const record = Object.hasOwn(records, change.logicalId) ? records[change.logicalId] : void 0;
26478
+ const resourceType = record?.resourceType ?? change.resourceType;
26479
+ if (IGNORED_RESOURCE_TYPES.has(resourceType) || IGNORED_RESOURCE_TYPES.has(change.resourceType)) continue;
26480
+ const impact = change.changeType === "UPDATE" && recreateTargets.has(change.logicalId) ? "WILL_REPLACE" : destructiveImpactOf(change, record);
26481
+ if (impact === void 0) continue;
26482
+ const recorded = typeof record?.constructPath === "string" ? record.constructPath : void 0;
26483
+ const constructPath = constructPathOf(template, change.logicalId) ?? recorded;
26484
+ found.push({
26485
+ stackName,
26486
+ logicalId: change.logicalId,
26487
+ resourceType,
26488
+ ...constructPath !== void 0 && { constructPath },
26489
+ impact
26490
+ });
26491
+ }
26492
+ return found;
26493
+ }
26494
+ function destructiveImpactOf(change, record) {
26495
+ switch (change.changeType) {
26496
+ case "DELETE": return shouldRetainResource(record?.deletionPolicy) ? "WILL_ORPHAN" : "WILL_DESTROY";
26497
+ case "UPDATE": {
26498
+ if (record !== void 0 && record.resourceType !== change.resourceType) return "WILL_REPLACE";
26499
+ let mayReplace = false;
26500
+ for (const pc of change.propertyChanges ?? []) {
26501
+ if (!pc.requiresReplacement) continue;
26502
+ if (pc.inPlacePropagated === true || pc.replacementPropagated === true) mayReplace = true;
26503
+ else return "WILL_REPLACE";
26504
+ }
26505
+ return mayReplace ? "MAY_REPLACE" : void 0;
26506
+ }
26507
+ default: return;
26508
+ }
26509
+ }
26510
+ function constructPathOf(template, logicalId) {
26511
+ const resources = template?.Resources;
26512
+ if (resources === void 0 || !Object.hasOwn(resources, logicalId)) return void 0;
26513
+ const path = resources[logicalId]?.Metadata?.[PATH_METADATA_KEY];
26514
+ return typeof path === "string" && path !== "" ? path : void 0;
26515
+ }
26516
+ function describeDestructiveImpact(impact) {
26517
+ switch (impact) {
26518
+ case "WILL_REPLACE": return "will be replaced";
26519
+ case "MAY_REPLACE": return "may be replaced";
26520
+ case "WILL_DESTROY": return "will be destroyed";
26521
+ case "WILL_ORPHAN": return "will be orphaned";
26522
+ }
26523
+ }
26524
+ function formatDestructiveChange(change) {
26525
+ const path = change.constructPath !== void 0 ? `${displaySafe(displayPath(change.constructPath))} ` : "";
26526
+ return `${displayIdent(change.stackName)}: ${displaySafe(change.resourceType)} ${path}${displayIdent(change.logicalId)} ${describeDestructiveImpact(change.impact)}`;
26527
+ }
26528
+ function displayPath(constructPath) {
26529
+ let parts = constructPath.replace(/^\//, "").split("/");
26530
+ if (parts.length > 1) {
26531
+ parts = parts.slice(1);
26532
+ const last = parts[parts.length - 1];
26533
+ if (parts.length > 1 && (last === "Resource" || last === "Default")) parts = parts.slice(0, -1);
26534
+ }
26535
+ return parts.join("/");
26536
+ }
26537
+ function withConstructPath(record, path) {
26538
+ if (path === void 0 || record.constructPath === path) return record;
26539
+ return {
26540
+ ...record,
26541
+ constructPath: path
26542
+ };
26543
+ }
26544
+
26485
26545
  //#endregion
26486
26546
  //#region src/deployment/masking-retry-logger.ts
26487
26547
  function maskingRetryLogger(logger, secrets) {
@@ -26894,6 +26954,7 @@ async function resolveOutputs(template, resources, stackName, digestSource, para
26894
26954
  ...parameterValues && { parameters: parameterValues },
26895
26955
  ...conditions && { conditions }
26896
26956
  }, stackName);
26957
+ context.printingSecrets = /* @__PURE__ */ new Map();
26897
26958
  const refuseMaskedOutputReads = (outputKey, ownReads) => {
26898
26959
  const added = ownReads.filter((read) => read.kind === "ref-state-key");
26899
26960
  if (added.length === 0) return;
@@ -27377,9 +27438,9 @@ const REDACTED_DELETE_ADDRESS_SKIP_REASON = "redacted address property in state
27377
27438
  function redactedDeleteAddressFields(fields) {
27378
27439
  return Object.keys(fields).filter((key) => isRedactedRecordedValue(fields[key]));
27379
27440
  }
27380
- function redactedDeleteAddressSkip(logger, logicalId, what, redactedFields) {
27441
+ function redactedDeleteAddressSkip(logger, logicalId, what, redactedFields, context) {
27381
27442
  if (redactedFields.length === 0) return void 0;
27382
- logger.warn(safeMsg`${what} ${logicalId} is recorded in state with ${redactedFields.join(", ")} ` + "redacted (the '***' mask of a NoEcho value it read, or a secret '{{resolve:...}}' reference), which names nothing in AWS; skipping deletion — no AWS call is issued, so the resource is LEFT IN PLACE unless a parent resource this run also deletes removes it (then only the record is stale). Re-deploying records the same redaction again. The state record is KEPT and the run reports the skip: on 'cdkd destroy' / 'cdkd state destroy' (which exits non-zero) and, since issue 1762, on the plain DELETE of a resource removed from the template during cdkd deploy. Remove the resource by hand, then clear the stack's records with 'cdkd state orphan <stack>' — that command drops EVERY record for the stack, not just this one. NOTE a deploy-side REPLACEMENT or rollback delete instead FAILS the resource (https://github.com/go-to-k/cdkd/issues/1762) — the old resource is left untracked there, so remove it by hand.");
27443
+ logger.warn(safeMsg`${what} ${logicalId} is recorded in state with ${redactedFields.join(", ")} ` + "redacted (the '***' mask of a NoEcho value it read, or a secret '{{resolve:...}}' reference), which names nothing in AWS; skipping deletion — no AWS call is issued, so the resource is LEFT IN PLACE unless a parent resource this run also deletes removes it (then only the record is stale). Re-deploying records the same redaction again. The state record is KEPT and the run reports the skip: on 'cdkd destroy' / 'cdkd state destroy' (which exits non-zero) and, since issue 1762, on the plain DELETE of a resource removed from the template during cdkd deploy. Remove the resource by hand, " + safeMsg`then drop the record with ${stateOrphanRecordRemedy(context, logicalId)}. ` + "NOTE a deploy-side REPLACEMENT or rollback delete instead FAILS the resource (https://github.com/go-to-k/cdkd/issues/1762) — the old resource is left untracked there, so remove it by hand.");
27383
27444
  return {
27384
27445
  outcome: "skipped",
27385
27446
  reason: REDACTED_DELETE_ADDRESS_SKIP_REASON
@@ -28395,6 +28456,9 @@ function mayOwn(o, orphan, completed) {
28395
28456
  if (o.physicalId === orphan.physicalId) return true;
28396
28457
  return o.previousState?.physicalId === orphan.physicalId;
28397
28458
  }
28459
+ function isJournaledOrphan(op) {
28460
+ return op.changeType === "CREATE" && typeof op.physicalIdRecoveredFromError === "boolean";
28461
+ }
28398
28462
  function planFailedOps(failedOps, stateResources) {
28399
28463
  return failedOps.map((op) => ({
28400
28464
  op,
@@ -29278,7 +29342,7 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
29278
29342
  const takeFinalSnapshot = snapshotPolicy && ctx.skipFinalSnapshot !== true;
29279
29343
  let finalSnapshotIdentifier;
29280
29344
  if (takeFinalSnapshot) finalSnapshotIdentifier = await prepareCreateRollbackFinalSnapshot(op, deleteProvisionedBy, ctx, mask);
29281
- logger.info(` Rollback: deleting partially-created ${safe(op.logicalId)} (${safe(op.resourceType)}) (--revert-failed)` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
29345
+ logger.info(` Rollback: deleting partially-created ${safe(op.logicalId)} (${safe(op.resourceType)})` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
29282
29346
  const { provider, provisionedBy: deleteRoutedVia } = ctx.providerRegistry.getProviderFor({
29283
29347
  resourceType: op.resourceType,
29284
29348
  provisionedBy: deleteProvisionedBy
@@ -29292,7 +29356,7 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
29292
29356
  deletionPolicy: snapshotPolicy ? "Snapshot" : "Delete",
29293
29357
  recordedAttributes: stateResources[op.logicalId]?.attributes
29294
29358
  });
29295
- throwIfDeleteSkipped(failedCreateDelete, op.logicalId, op.physicalId, "while deleting the partially-created resource (--revert-failed)", {
29359
+ throwIfDeleteSkipped(failedCreateDelete, op.logicalId, op.physicalId, "while deleting the partially-created resource", {
29296
29360
  ctx,
29297
29361
  stackName,
29298
29362
  resourceType: op.resourceType,
@@ -29444,7 +29508,7 @@ async function collectNestedChildUnaddressed(fn) {
29444
29508
  //#endregion
29445
29509
  //#region src/deployment/nested-child-journal.ts
29446
29510
  const NESTED_PENDING_PARENT_REASON = "nested-pending-parent";
29447
- const NESTED_STACK_TYPE$1 = "AWS::CloudFormation::Stack";
29511
+ const NESTED_STACK_TYPE$2 = "AWS::CloudFormation::Stack";
29448
29512
  const MAX_NESTED_WALK_DEPTH = 32;
29449
29513
  function nestedChildStackName(parentStackName, logicalId) {
29450
29514
  return `${parentStackName}~${logicalId}`;
@@ -29500,7 +29564,7 @@ function recordDisplacedSkips(recordEvent, stackName, ops) {
29500
29564
  });
29501
29565
  }
29502
29566
  function revertedNestedRowIds(ops) {
29503
- return ops.filter((op) => op.resourceType === NESTED_STACK_TYPE$1 && op.changeType === "UPDATE").map((op) => op.logicalId);
29567
+ return ops.filter((op) => op.resourceType === NESTED_STACK_TYPE$2 && op.changeType === "UPDATE").map((op) => op.logicalId);
29504
29568
  }
29505
29569
  const revertRunStorage = new AsyncLocalStorage();
29506
29570
  function withNestedRevertRun(runId, fn) {
@@ -29526,7 +29590,7 @@ async function dropNestedChildJournals(args) {
29526
29590
  if (!isPlainRecord(resources)) return;
29527
29591
  if (depthExceeded(depth, parentStackName, logger)) return;
29528
29592
  for (const [logicalId, record] of Object.entries(resources)) {
29529
- if (!isPlainRecord(record) || record["resourceType"] !== NESTED_STACK_TYPE$1) continue;
29593
+ if (!isPlainRecord(record) || record["resourceType"] !== NESTED_STACK_TYPE$2) continue;
29530
29594
  const child = nestedChildStackName(parentStackName, logicalId);
29531
29595
  try {
29532
29596
  const data = await stateBackend.getState(child, region);
@@ -29540,13 +29604,34 @@ async function dropNestedChildJournals(args) {
29540
29604
  warnUncleared(logger, child, error);
29541
29605
  }
29542
29606
  try {
29543
- await withChildLock(args.lockManager, child, region, logger, () => stateBackend.deleteRollbackJournal(child, region));
29544
- logger.debug(safeMsg`Deleted the rollback journal of nested stack ${displaySafe(child)}`);
29607
+ if (await withChildLock(args.lockManager, child, region, logger, async () => {
29608
+ if (args.beforeDelete) {
29609
+ if (!await args.beforeDelete(child, await readOwnRecord(stateBackend, child, region))) return false;
29610
+ }
29611
+ let gone;
29612
+ try {
29613
+ gone = await stateBackend.deleteRollbackJournal(child, region);
29614
+ } catch (error) {
29615
+ await args.onDeleteFailed?.(child);
29616
+ throw error;
29617
+ }
29618
+ if (gone === false) {
29619
+ await args.onDeleteFailed?.(child);
29620
+ return false;
29621
+ }
29622
+ return true;
29623
+ })) logger.debug(safeMsg`Deleted the rollback journal of nested stack ${displaySafe(child)}`);
29545
29624
  } catch (error) {
29546
29625
  warnUncleared(logger, child, error);
29547
29626
  }
29548
29627
  }
29549
29628
  }
29629
+ async function readOwnRecord(stateBackend, child, region) {
29630
+ try {
29631
+ const data = await stateBackend.getState(child, region);
29632
+ if (data && isPlainRecord(data.state) && isPlainRecord(data.state.resources) && (data.state.stackName === void 0 || data.state.stackName === child)) return data.state;
29633
+ } catch {}
29634
+ }
29550
29635
  async function dropSettledNestedJournals(args) {
29551
29636
  const { stateBackend, parentStackName, region, runId, logger } = args;
29552
29637
  const depth = args.depth ?? 0;
@@ -29856,6 +29941,306 @@ function makeSiblingClaimReader(params) {
29856
29941
  };
29857
29942
  }
29858
29943
 
29944
+ //#endregion
29945
+ //#region src/deployment/rollback-executor/journaled-orphans.ts
29946
+ const NONE = {
29947
+ segments: [],
29948
+ count: 0
29949
+ };
29950
+ async function loadJournaledOrphans(stateBackend, stackName, region, rollbackOrphans, logger, options = {}) {
29951
+ let segments;
29952
+ try {
29953
+ const journal = await stateBackend.loadRollbackJournal(stackName, region);
29954
+ if (!journal) return NONE;
29955
+ segments = journal.segments;
29956
+ } catch (err) {
29957
+ const detail = err instanceof Error ? err.message : String(err);
29958
+ logger.warn(safeMsg`Could not read the stack's rollback journal (${displaySafe(detail)}); ` + safeMsg`no resource it records for a failed CREATE is deleted, and ${options.unreadableOutcome ?? "a destroy that proceeds removes the journal with the state"}.`);
29959
+ return {
29960
+ ...NONE,
29961
+ unreadable: true
29962
+ };
29963
+ }
29964
+ const physicalIdOnly = (ops) => ops.filter((op) => op.changeType !== "CREATE");
29965
+ const evidence = segments.map((segment) => options.deployRunId !== void 0 && segment.reason === "nested-pending-parent" && segment.runId === options.deployRunId ? {
29966
+ ...segment,
29967
+ operations: physicalIdOnly(segment.operations)
29968
+ } : segment);
29969
+ const newer = options.newerOperations ?? [];
29970
+ if (newer.length > 0) evidence.push({ operations: physicalIdOnly(newer) });
29971
+ demoteSupersededOrphans(evidence, Array.isArray(rollbackOrphans) ? rollbackOrphans : []);
29972
+ const deployLogicalIds = new Set(newer.map((op) => op.logicalId));
29973
+ for (const segment of segments) if (options.deployRunId !== void 0 && segment.reason === "nested-pending-parent" && segment.runId === options.deployRunId) for (const op of segment.operations) deployLogicalIds.add(op.logicalId);
29974
+ const out = [];
29975
+ let count = 0;
29976
+ for (let s = segments.length - 1; s >= 0; s--) {
29977
+ const segment = segments[s];
29978
+ if (segment.reason === "nested-pending-parent") continue;
29979
+ const ops = splitImportedOps(segment.failedOperations ?? [], segment).replay.filter(isJournaledOrphan);
29980
+ if (ops.length === 0) continue;
29981
+ out.push({
29982
+ segment,
29983
+ ops
29984
+ });
29985
+ count += ops.length;
29986
+ }
29987
+ return {
29988
+ segments: out,
29989
+ count,
29990
+ deployLogicalIds
29991
+ };
29992
+ }
29993
+ function journaledOrphanLines(orphans, logger) {
29994
+ return orphans.segments.flatMap(({ ops }) => ops.map((op) => ` - ${logicalIdShown(op.logicalId)} (${resourceTypeShown(op.resourceType)}) ${displacedPhysicalIdShown(op, logger) ?? "a physical id"}`));
29995
+ }
29996
+ async function deleteJournaledOrphans(orphans, stateResources, stackName, ctx, options = {}) {
29997
+ const total = {
29998
+ failures: 0,
29999
+ warnings: 0,
30000
+ interrupted: false,
30001
+ handled: []
30002
+ };
30003
+ const inlinePolicyWriters = new RollbackInlinePolicyWriters();
30004
+ for (const { segment, ops } of orphans.segments) {
30005
+ if (options.isInterrupted?.()) {
30006
+ total.interrupted = true;
30007
+ break;
30008
+ }
30009
+ const replay = () => withStackName(stackName, () => replayFailedOperations(ops, stateResources, stackName, ctx, {
30010
+ emitEnvelope: false,
30011
+ inlinePolicyWriters,
30012
+ ...options.isInterrupted && { isInterrupted: options.isInterrupted }
30013
+ }));
30014
+ const result = segment.skipPrefix === void 0 ? await replay() : await withSkipPrefix(segment.skipPrefix, replay);
30015
+ total.failures += result.failures;
30016
+ total.warnings += result.warnings;
30017
+ const pending = new Set(result.remainingFailedOps);
30018
+ for (const op of ops) if (!pending.has(op)) total.handled.push({
30019
+ segment,
30020
+ op
30021
+ });
30022
+ if (result.interrupted) {
30023
+ total.interrupted = true;
30024
+ break;
30025
+ }
30026
+ }
30027
+ return total;
30028
+ }
30029
+ async function settleJournaledOrphansOnSuccess(args) {
30030
+ const { stateBackend, stackName, region, stateResources, newerOperations, ctx, logger } = args;
30031
+ const stack = displayIdent(stackName);
30032
+ const newerIds = newerOperations.map((op) => op.logicalId);
30033
+ let orphans;
30034
+ try {
30035
+ orphans = await loadJournaledOrphans(stateBackend, stackName, region, args.rollbackOrphans, logger, {
30036
+ newerOperations,
30037
+ ...args.deployRunId !== void 0 && { deployRunId: args.deployRunId },
30038
+ unreadableOutcome: "the successful deploy removes the journal"
30039
+ });
30040
+ } catch (err) {
30041
+ logger.warn(safeMsg`Could not act on the rollback journal of stack ${stack}: ${errorDetail(err)}. It is kept.`);
30042
+ await markSuperseded(stateBackend, stackName, region, newerIds);
30043
+ return {
30044
+ unaddressed: 1,
30045
+ keepJournal: true
30046
+ };
30047
+ }
30048
+ if (orphans.count === 0) return {
30049
+ unaddressed: 0,
30050
+ keepJournal: false
30051
+ };
30052
+ const all = orphans.segments.flatMap(({ segment, ops }) => ops.map((op) => ({
30053
+ segment,
30054
+ op
30055
+ })));
30056
+ let kept = all;
30057
+ if (stateResources === void 0) logger.warn(safeMsg`The rollback journal of stack ${stack} records ${all.length} resource(s) a failed deploy ` + `created, but the stack's state cannot be read, so whether a record now owns them is unknown: none is deleted.`);
30058
+ else {
30059
+ logger.info(safeMsg`The rollback journal of stack ${stack} records ${all.length} resource(s) a failed deploy ` + `created that no state record holds; acting on them per their DeletionPolicy before the journal is removed:`);
30060
+ for (const line of journaledOrphanLines(orphans, logger)) logger.info(line);
30061
+ try {
30062
+ const { unreadable, tracked } = await applySuccessRule(orphans, stateResources, orphans.deployLogicalIds ?? /* @__PURE__ */ new Set(), args.foreignHolder, stack, logger, args.isInterrupted);
30063
+ const outcome = await deleteJournaledOrphans({
30064
+ segments: orphans.segments.map(({ segment, ops }) => ({
30065
+ segment,
30066
+ ops: ops.filter((op) => !unreadable.has(op) && !tracked.has(op))
30067
+ })).filter(({ ops }) => ops.length > 0),
30068
+ count: orphans.count - unreadable.size - tracked.size
30069
+ }, { ...stateResources }, stackName, ctx, args.isInterrupted ? { isInterrupted: args.isInterrupted } : {});
30070
+ kept = all.filter(({ segment, op }) => unreadable.has(op) || !tracked.has(op) && !isHandledOrphan(outcome.handled, segment, op));
30071
+ } catch (err) {
30072
+ logger.warn(safeMsg`Acting on the journaled resources of stack ${stack} failed: ${errorDetail(err)}`);
30073
+ }
30074
+ }
30075
+ const keptOps = new Set(kept.map(({ op }) => op));
30076
+ const skipped = all.filter(({ op }) => !keptOps.has(op) && op.physicalIdRecoveredFromError === false).length;
30077
+ const cleared = all.filter(({ op }) => !keptOps.has(op));
30078
+ const stripCleared = cleared.length === 0 ? void 0 : async () => {
30079
+ try {
30080
+ await stateBackend.dropRollbackJournalFailedOperations(stackName, region, (op, segment) => isHandledOrphan(cleared, segment, op));
30081
+ } catch (err) {
30082
+ logger.warn(safeMsg`Failed to remove the settled entries from the rollback journal of stack ${stack}: ` + safeMsg`${errorDetail(err)}. A cdkd rollback or cdkd destroy could act on them again; run a ` + "successful cdkd deploy of the stack first, which settles them again.");
30083
+ }
30084
+ };
30085
+ if (kept.length === 0) return {
30086
+ unaddressed: skipped,
30087
+ keepJournal: false,
30088
+ ...stripCleared && { stripCleared }
30089
+ };
30090
+ const keptIds = new Set(kept.map(({ op }) => op.logicalId));
30091
+ const supersededIds = newerIds.filter((id) => !keptIds.has(id));
30092
+ const demoted = kept.filter(({ op }) => op.physicalIdRecoveredFromError === false);
30093
+ const reduce = () => stateBackend.reduceRollbackJournalToFailedOperations(stackName, region, (op, segment) => isHandledOrphan(kept, segment, op), supersededIds, (op, segment) => isHandledOrphan(demoted, segment, op));
30094
+ let reduced = false;
30095
+ for (let attempt = 0; attempt < 2 && !reduced; attempt++) try {
30096
+ await reduce();
30097
+ reduced = true;
30098
+ } catch (err) {
30099
+ if (attempt === 1) logger.warn(safeMsg`Failed to reduce the rollback journal of stack ${stack} to its undeleted resources: ` + safeMsg`${errorDetail(err)}. The whole journal is kept.`);
30100
+ }
30101
+ if (!reduced) {
30102
+ await markSuperseded(stateBackend, stackName, region, supersededIds);
30103
+ await stripCleared?.();
30104
+ }
30105
+ logger.warn(safeMsg`${kept.length} resource(s) a failed deploy of stack ${stack} created were not deleted ` + (reduced ? "(see above). The rollback journal, their only record, is kept with just them; the next " : "(see above). The rollback journal, their only record, is kept; the next ") + "successful deploy retries.");
30106
+ return {
30107
+ unaddressed: kept.length + skipped,
30108
+ keepJournal: true
30109
+ };
30110
+ }
30111
+ async function applySuccessRule(orphans, stateResources, deployLogicalIds, foreignHolder, stack, logger, isInterrupted) {
30112
+ const unreadable = /* @__PURE__ */ new Set();
30113
+ const tracked = /* @__PURE__ */ new Set();
30114
+ let interrupted = false;
30115
+ for (const { ops } of orphans.segments) for (const op of ops) {
30116
+ if (op.physicalIdRecoveredFromError !== true || !op.physicalId) continue;
30117
+ if (interrupted || isInterrupted?.()) {
30118
+ interrupted = true;
30119
+ unreadable.add(op);
30120
+ continue;
30121
+ }
30122
+ if (Object.values(stateResources).some((r) => r?.resourceType === op.resourceType && r.physicalId === op.physicalId)) {
30123
+ tracked.add(op);
30124
+ continue;
30125
+ }
30126
+ if (Object.prototype.hasOwnProperty.call(stateResources, op.logicalId) || deployLogicalIds.has(op.logicalId)) {
30127
+ op.physicalIdRecoveredFromError = false;
30128
+ continue;
30129
+ }
30130
+ const holding = await foreignHolder(op.resourceType, op.physicalId);
30131
+ if (holding === void 0) continue;
30132
+ if (holding.kind === "held") {
30133
+ logger.warn(safeMsg`${logicalIdShown(op.logicalId)} (${resourceTypeShown(op.resourceType)}), which a failed deploy ` + safeMsg`of stack ${stack} created, is not deleted: ${holding.by} holds a resource of that type under ` + "the same physical id.");
30134
+ op.physicalIdRecoveredFromError = false;
30135
+ continue;
30136
+ }
30137
+ logger.warn(safeMsg`${logicalIdShown(op.logicalId)} (${resourceTypeShown(op.resourceType)}), which a failed deploy ` + safeMsg`of stack ${stack} created, is not deleted: ${holding.what}, so whether another stack holds it is unknown.`);
30138
+ unreadable.add(op);
30139
+ }
30140
+ return {
30141
+ unreadable,
30142
+ tracked
30143
+ };
30144
+ }
30145
+ function makeForeignHolderScan(stateBackend) {
30146
+ let scan;
30147
+ const key = (type, id) => JSON.stringify([type, id]);
30148
+ const run = async () => {
30149
+ const holders = /* @__PURE__ */ new Map();
30150
+ let refs;
30151
+ try {
30152
+ refs = await stateBackend.listStacks();
30153
+ } catch {
30154
+ return {
30155
+ holders,
30156
+ unreadable: "the state bucket listing (it could not be read)"
30157
+ };
30158
+ }
30159
+ let unreadable;
30160
+ await Promise.all(refs.map(async (ref) => {
30161
+ const named = (why) => safeMsg`the state record of stack ${displayIdent(ref.stackName)} (${why})`;
30162
+ if (ref.region === void 0) {
30163
+ unreadable ??= named("its region cannot be read");
30164
+ return;
30165
+ }
30166
+ const region = ref.region;
30167
+ let state;
30168
+ try {
30169
+ state = (await stateBackend.getState(ref.stackName, region))?.state;
30170
+ } catch {
30171
+ unreadable ??= named("it could not be read");
30172
+ return;
30173
+ }
30174
+ if (state === void 0) return;
30175
+ const resources = state.resources;
30176
+ if (resources !== void 0 && (typeof resources !== "object" || resources === null || Array.isArray(resources))) {
30177
+ unreadable ??= named("its resources cannot be read");
30178
+ return;
30179
+ }
30180
+ if (!hasReadableOrphans(state) || unreadableOrphanRecords(state).length > 0) {
30181
+ unreadable ??= named("its rollback-orphan records cannot be read");
30182
+ return;
30183
+ }
30184
+ const held = [...Object.values(resources ?? {}), ...(state.orphans ?? []).map((record) => record.state)];
30185
+ for (const record of held) {
30186
+ const r = record;
30187
+ if (typeof r?.resourceType !== "string" || typeof r.physicalId !== "string") continue;
30188
+ const k = key(r.resourceType, r.physicalId);
30189
+ const list = holders.get(k) ?? [];
30190
+ list.push({
30191
+ stackName: ref.stackName,
30192
+ region
30193
+ });
30194
+ holders.set(k, list);
30195
+ }
30196
+ }));
30197
+ return {
30198
+ holders,
30199
+ ...unreadable !== void 0 && { unreadable }
30200
+ };
30201
+ };
30202
+ return (self) => async (resourceType, physicalId) => {
30203
+ scan ??= run();
30204
+ const { holders, unreadable } = await scan;
30205
+ const other = (holders.get(key(resourceType, physicalId)) ?? []).find((h) => !(h.stackName === self.stackName && h.region === self.region));
30206
+ if (other) return {
30207
+ kind: "held",
30208
+ by: safeMsg`the state record of stack ${displayIdent(other.stackName)} (${displaySafe(other.region)})`
30209
+ };
30210
+ return unreadable === void 0 ? void 0 : {
30211
+ kind: "unreadable",
30212
+ what: unreadable
30213
+ };
30214
+ };
30215
+ }
30216
+ async function markSuperseded(stateBackend, stackName, region, ids) {
30217
+ try {
30218
+ await stateBackend.markRollbackJournalSuperseded(stackName, region, ids);
30219
+ } catch {}
30220
+ }
30221
+ function errorDetail(err) {
30222
+ return displaySafe(err instanceof Error ? err.message : String(err));
30223
+ }
30224
+ function isHandledOrphan(handled, segment, op) {
30225
+ return handled.some((h) => h.segment.timestamp === segment.timestamp && h.segment.runId === segment.runId && h.op.logicalId === op.logicalId && h.op.changeType === op.changeType && h.op.resourceType === op.resourceType && h.op.physicalId === op.physicalId);
30226
+ }
30227
+ function orphanKey(segment, op) {
30228
+ return JSON.stringify([
30229
+ segment.timestamp,
30230
+ segment.runId ?? null,
30231
+ op.logicalId,
30232
+ op.changeType,
30233
+ op.resourceType,
30234
+ op.physicalId ?? null
30235
+ ]);
30236
+ }
30237
+ function sameJournaledOrphans(a, b) {
30238
+ const keys = (o) => o.segments.flatMap(({ segment, ops }) => ops.map((op) => orphanKey(segment, op))).sort();
30239
+ const ka = keys(a);
30240
+ const kb = keys(b);
30241
+ return ka.length === kb.length && ka.every((k, i) => k === kb[i]);
30242
+ }
30243
+
29859
30244
  //#endregion
29860
30245
  //#region src/deployment/deploy-engine/rollback.ts
29861
30246
  function redactOperationsForJournal(operations) {
@@ -29904,33 +30289,109 @@ async function adoptRollbackOrphans(currentState, effectiveTemplate) {
29904
30289
  if (records.length > 0) currentState.orphans = plan.remaining;
29905
30290
  return plan;
29906
30291
  }
29907
- async function performRollback(completedOperations, stateResources, stackName, previousState) {
30292
+ async function performRollback(completedOperations, stateResources, stackName, previousState, failedOperations = [], priorOrphans = []) {
30293
+ const orphanIndexes = [];
30294
+ const orphanOps = [];
30295
+ failedOperations.forEach((op, i) => {
30296
+ if (!isJournaledOrphan(op)) return;
30297
+ orphanIndexes.push(i);
30298
+ orphanOps.push({ ...op });
30299
+ });
30300
+ demoteSupersededOrphans([{
30301
+ operations: completedOperations,
30302
+ failedOperations: orphanOps
30303
+ }], priorOrphans);
30304
+ const ctx = this.rollbackExecutorContext(previousState, stackName);
30305
+ const inlinePolicyWriters = new RollbackInlinePolicyWriters();
29908
30306
  const runId = this.options.eventRecorder?.runId;
29909
- const { result, run } = await withNestedRevertRun(runId, async (scope) => ({
29910
- result: await replayRollback(completedOperations, stateResources, stackName, this.rollbackExecutorContext(previousState, stackName)),
29911
- run: scope
29912
- }));
30307
+ const { result, failed, run } = await withNestedRevertRun(runId, async (scope) => {
30308
+ return {
30309
+ failed: orphanOps.length > 0 ? await replayFailedOperations(orphanOps, stateResources, stackName, ctx, {
30310
+ emitEnvelope: completedOperations.length === 0,
30311
+ inlinePolicyWriters
30312
+ }) : void 0,
30313
+ result: await replayRollback(completedOperations, stateResources, stackName, ctx, { inlinePolicyWriters }),
30314
+ run: scope
30315
+ };
30316
+ });
30317
+ const pendingOrphans = new Set(failed?.remainingFailedOps ?? []);
30318
+ const handled = new Set(orphanIndexes.filter((_, k) => !pendingOrphans.has(orphanOps[k])));
29913
30319
  return {
29914
- failures: result.failures,
29915
- warnings: result.warnings + run.warnings,
29916
- skipped: result.skipped,
29917
- orphaned: result.orphaned,
29918
- settledNested: run.settled
30320
+ failures: result.failures + (failed?.failures ?? 0),
30321
+ warnings: result.warnings + run.warnings + (failed?.warnings ?? 0),
30322
+ skipped: result.skipped + (failed?.skipped ?? 0),
30323
+ orphaned: [...failed?.orphaned ?? [], ...result.orphaned],
30324
+ settledNested: run.settled,
30325
+ remainingFailedOps: failedOperations.filter((_, i) => !handled.has(i))
29919
30326
  };
29920
30327
  }
29921
30328
  async function settleJournalAfterSuccess(stackName, completedOperations, previousState, finalResources, initialDeploy) {
29922
30329
  if (this.options.parentStackInfo) {
29923
30330
  await this.writeRollbackJournalSegment(stackName, completedOperations, [], NESTED_PENDING_PARENT_REASON, initialDeploy, nestedPendingSnapshot(previousState));
29924
- return;
29925
- }
29926
- await Promise.all([this.deleteRollbackJournalBestEffort(stackName, completedOperations.map((op) => op.logicalId)), dropNestedChildJournals({
30331
+ return 0;
30332
+ }
30333
+ let nestedLeft = 0;
30334
+ const foreignHolderFor = makeForeignHolderScan(this.stateBackend);
30335
+ const deployRunId = this.options.eventRecorder?.runId;
30336
+ const stripOnFailure = /* @__PURE__ */ new Map();
30337
+ const [ownLeft] = await Promise.all([(async () => {
30338
+ const own = await settleJournaledOrphansOnSuccess({
30339
+ stateBackend: this.stateBackend,
30340
+ stackName,
30341
+ region: this.stackRegion,
30342
+ stateResources: finalResources,
30343
+ rollbackOrphans: previousState.orphans,
30344
+ newerOperations: completedOperations,
30345
+ ...deployRunId !== void 0 && { deployRunId },
30346
+ foreignHolder: foreignHolderFor({
30347
+ stackName,
30348
+ region: this.stackRegion
30349
+ }),
30350
+ ctx: this.rollbackExecutorContext(previousState, stackName),
30351
+ isInterrupted: () => this.interrupted,
30352
+ logger: this.logger
30353
+ });
30354
+ if (own.keepJournal) return own.unaddressed;
30355
+ if (!await this.deleteRollbackJournalBestEffort(stackName, completedOperations.map((op) => op.logicalId))) await own.stripCleared?.();
30356
+ return own.unaddressed;
30357
+ })(), dropNestedChildJournals({
29927
30358
  stateBackend: this.stateBackend,
29928
30359
  lockManager: this.lockManager,
29929
30360
  parentStackName: stackName,
29930
30361
  region: this.stackRegion,
29931
30362
  resources: finalResources,
29932
- logger: this.logger
30363
+ logger: this.logger,
30364
+ beforeDelete: async (child, childRecord) => {
30365
+ const childState = childRecord !== void 0 && hasReadableOrphans(childRecord) ? childRecord : void 0;
30366
+ const settled = await settleJournaledOrphansOnSuccess({
30367
+ stateBackend: this.stateBackend,
30368
+ stackName: child,
30369
+ region: this.stackRegion,
30370
+ stateResources: childState?.resources,
30371
+ rollbackOrphans: childState?.orphans,
30372
+ newerOperations: [],
30373
+ ...deployRunId !== void 0 && { deployRunId },
30374
+ foreignHolder: foreignHolderFor({
30375
+ stackName: child,
30376
+ region: this.stackRegion
30377
+ }),
30378
+ isInterrupted: () => this.interrupted,
30379
+ ctx: {
30380
+ ...this.rollbackExecutorContext(childState ?? previousState, child),
30381
+ producerRegionsIncomplete: true,
30382
+ nestedChildStack: child
30383
+ },
30384
+ logger: this.logger
30385
+ });
30386
+ nestedLeft += settled.unaddressed;
30387
+ if (settled.stripCleared) stripOnFailure.set(child, settled.stripCleared);
30388
+ return !settled.keepJournal;
30389
+ },
30390
+ onDeleteFailed: async (child) => {
30391
+ await stripOnFailure.get(child)?.();
30392
+ }
29933
30393
  })]);
30394
+ return ownLeft + nestedLeft;
29934
30395
  }
29935
30396
  async function deleteRollbackJournalBestEffort(stackName, supersededLogicalIds = []) {
29936
30397
  let deleted;
@@ -29940,12 +30401,14 @@ async function deleteRollbackJournalBestEffort(stackName, supersededLogicalIds =
29940
30401
  this.logger.debug(safeMsg`Failed to delete rollback journal for ${stackName}: ${err instanceof Error ? err.message : String(err)}`);
29941
30402
  deleted = false;
29942
30403
  }
29943
- if (deleted !== false || supersededLogicalIds.length === 0) return;
30404
+ if (deleted !== false) return true;
30405
+ if (supersededLogicalIds.length === 0) return false;
29944
30406
  try {
29945
30407
  await this.stateBackend.markRollbackJournalSuperseded(stackName, this.stackRegion, supersededLogicalIds);
29946
30408
  } catch (markErr) {
29947
30409
  this.logger.debug(safeMsg`Failed to record superseded logical ids on the rollback journal for ${stackName}: ${markErr instanceof Error ? markErr.message : String(markErr)}`);
29948
30410
  }
30411
+ return false;
29949
30412
  }
29950
30413
  async function settleJournalAfterCleanRollback(stackName, failedOperations, initialDeploy) {
29951
30414
  if (failedOperations.length === 0) {
@@ -30623,7 +31086,88 @@ async function readReaderForFreshNoEchoCeiling(logicalId, currentResource, secre
30623
31086
  }
30624
31087
  }
30625
31088
  function maskForResource(logicalId, text) {
30626
- return maskSecretsInText(text, this.perResourceSecrets.get(logicalId) ?? EMPTY_SECRETS);
31089
+ return maskSecretsInText(text, this.printingSecretsFor(logicalId) ?? EMPTY_SECRETS);
31090
+ }
31091
+ function secretNameNeedlesOf(logicalId, record, secrets, options) {
31092
+ const physicalId = typeof record?.physicalId === "string" && record.physicalId !== "" ? record.physicalId : void 0;
31093
+ const bag = secrets !== void 0 && hasMaskableValues(secrets) ? secrets : void 0;
31094
+ const mask = (text) => bag === void 0 ? text : maskSecretsInText(text, bag);
31095
+ const unresolved = (value) => value.includes("{{resolve:") || value === "***";
31096
+ const named = {
31097
+ resourceType: record?.resourceType,
31098
+ properties: record?.properties,
31099
+ logicalId
31100
+ };
31101
+ const needles = /* @__PURE__ */ new Set();
31102
+ const add = (needle) => {
31103
+ if (typeof needle === "string" && needle !== "") needles.add(needle);
31104
+ };
31105
+ for (const [raw, derived] of secretDerivedNamePairs({
31106
+ ...named,
31107
+ physicalIds: []
31108
+ })) if (typeof raw === "string" && !unresolved(raw) && isSecretDerivedValue(raw, mask)) add(derived);
31109
+ for (const [raw, spelling] of secretDerivedNamePairs({
31110
+ ...named,
31111
+ physicalIds: [physicalId ?? "cdkd-no-physical-id-yet"]
31112
+ })) {
31113
+ if (!isSecretDerivedValue(raw, mask)) continue;
31114
+ if (unresolved(raw)) {
31115
+ if (physicalId === void 0) continue;
31116
+ add(spelling);
31117
+ } else {
31118
+ add(raw);
31119
+ if (raw.toLowerCase() !== raw && raw.length >= 4) add(raw.toLowerCase());
31120
+ }
31121
+ }
31122
+ const properties = record?.properties;
31123
+ const path = properties !== null && typeof properties === "object" && Object.hasOwn(properties, "Path") ? properties["Path"] : void 0;
31124
+ if (physicalId !== void 0 && isSecretDerivedValue(path, mask)) add(physicalId);
31125
+ const embedded = options === void 0 ? secrets : options.embedded;
31126
+ const embeddedBag = embedded !== void 0 && hasMaskableValues(embedded) ? embedded : void 0;
31127
+ if (embeddedBag !== void 0 && physicalId !== void 0) {
31128
+ for (const needle of printingCorpusOf(embeddedBag).keys()) if (needle !== "" && (needle === physicalId || needle.length >= 4 && physicalId.includes(needle))) add(needle);
31129
+ }
31130
+ return needles.size > 0 ? needles : void 0;
31131
+ }
31132
+ function secretNameBagFor(logicalId) {
31133
+ let bag = this.secretNameNeedles.get(logicalId);
31134
+ if (bag === void 0) {
31135
+ bag = /* @__PURE__ */ new Map();
31136
+ this.secretNameNeedles.set(logicalId, bag);
31137
+ }
31138
+ return bag;
31139
+ }
31140
+ function noteSecretNamedRecord(logicalId, record) {
31141
+ const needles = secretNameNeedlesOf(logicalId, record, this.namingSecretsFor(logicalId), { embedded: this.perResourceSecrets.get(logicalId) });
31142
+ if (needles === void 0) return void 0;
31143
+ const registry = this.secretNameBagFor(logicalId);
31144
+ for (const needle of needles) recordLogOnlyValue(registry, needle);
31145
+ return needles;
31146
+ }
31147
+ function namingSecretsFor(logicalId) {
31148
+ const own = this.perResourceSecrets.get(logicalId);
31149
+ const noEcho = this.fingerprintNoEchoValues;
31150
+ if (!hasMaskableValues(noEcho)) return own;
31151
+ return unionOfSecretBags([own, noEcho]);
31152
+ }
31153
+ function noteSecretNamedReads(logicalId, record, resources) {
31154
+ const leaves = [...wholeStringLeavesOf(record?.properties)].filter((leaf) => leaf !== "");
31155
+ if (leaves.length === 0) return;
31156
+ for (const [otherId, other] of Object.entries(resources)) {
31157
+ if (otherId === logicalId) continue;
31158
+ const needles = secretNameNeedlesOf(otherId, other, this.namingSecretsFor(otherId), { embedded: this.perResourceSecrets.get(otherId) });
31159
+ if (needles === void 0) continue;
31160
+ const read = [...needles].filter((needle) => leaves.some((leaf) => leaf === needle || needle.length >= 4 && leaf.includes(needle)));
31161
+ if (read.length === 0) continue;
31162
+ const registry = this.secretNameBagFor(logicalId);
31163
+ for (const needle of read) recordLogOnlyValue(registry, needle);
31164
+ }
31165
+ }
31166
+ function printingSecretsFor(logicalId) {
31167
+ const secrets = this.perResourceSecrets.get(logicalId);
31168
+ const registry = this.secretNameNeedles.get(logicalId);
31169
+ if (!hasMaskableValues(registry)) return secrets;
31170
+ return unionOfSecretBags([secrets, registry]);
30627
31171
  }
30628
31172
  function maskedRecordRemedyFor(reads, resources, causeScoped = false) {
30629
31173
  const NESTED_STACK_RESOURCE_TYPE = "AWS::CloudFormation::Stack";
@@ -31117,6 +31661,82 @@ function isRefusedBeforeApplying(error, logicalId) {
31117
31661
  return false;
31118
31662
  }
31119
31663
 
31664
+ //#endregion
31665
+ //#region src/deployment/deploy-engine/resolver-context.ts
31666
+ function buildResolverContext(base, stackName) {
31667
+ const recordedSecretValues = /* @__PURE__ */ new Map();
31668
+ if (this.options.inheritedSecrets && this.options.inheritedSecrets.size > 0) inheritNestedStackParameterAssociations(recordedSecretValues, this.options.inheritedSecrets);
31669
+ return {
31670
+ template: base.template,
31671
+ resources: base.resources,
31672
+ ...base.parameters && Object.keys(base.parameters).length > 0 && { parameters: base.parameters },
31673
+ ...base.conditions && Object.keys(base.conditions).length > 0 && { conditions: base.conditions },
31674
+ stateBackend: this.stateBackend,
31675
+ stackName,
31676
+ ...this.exportIndexStore && { exportIndex: this.exportIndexStore },
31677
+ recordedImports: this.recordedImports,
31678
+ recordedOutputReads: this.recordedOutputReads,
31679
+ attributeHealer: (logicalId, resource) => this.healStaleAttributes(logicalId, resource, stackName),
31680
+ ...this.options.inheritedSecrets && hasMaskableValues(this.options.inheritedSecrets) && { inheritedSecrets: this.options.inheritedSecrets },
31681
+ recordedSecretValues,
31682
+ noEchoAttributeResources: this.noEchoAttributeResources,
31683
+ secretNameNeedles: (logicalId) => this.noteSecretNamedRecord(logicalId, Object.hasOwn(base.resources, logicalId) ? base.resources[logicalId] : void 0),
31684
+ ...base.redactedAttributeReads && { redactedAttributeReads: base.redactedAttributeReads }
31685
+ };
31686
+ }
31687
+ function printNestedStackReadsOnly(context, resourceType) {
31688
+ if (resourceType === "AWS::CloudFormation::Stack") context.printingSecrets = /* @__PURE__ */ new Map();
31689
+ }
31690
+ function getAttTargetOf(node) {
31691
+ if (node === null || typeof node !== "object" || Array.isArray(node)) return void 0;
31692
+ const getAtt = node["Fn::GetAtt"];
31693
+ if (Array.isArray(getAtt) && typeof getAtt[0] === "string") return getAtt[0];
31694
+ if (typeof getAtt === "string") return getAtt.split(".")[0];
31695
+ }
31696
+ function maskedInputSources(template, resources, conditions, stackName) {
31697
+ const parameters = this.fingerprintParameters;
31698
+ if (parameters === void 0) return void 0;
31699
+ return {
31700
+ template,
31701
+ parameterInput: parameters.parameterInput,
31702
+ conditions,
31703
+ childTemplate: this.fingerprintChildTemplates,
31704
+ resolve: async (node) => {
31705
+ const { attributeHealer: _healer, ...base } = this.buildResolverContext({
31706
+ template,
31707
+ resources,
31708
+ parameters: parameters.bound,
31709
+ ...conditions && { conditions }
31710
+ }, stackName);
31711
+ const context = {
31712
+ ...base,
31713
+ recordedImports: [],
31714
+ recordedOutputReads: [],
31715
+ bestEffort: true,
31716
+ skipDynamicReferences: true,
31717
+ staleAttributeHeal: { phase: "probe" },
31718
+ printingSecrets: /* @__PURE__ */ new Map()
31719
+ };
31720
+ const value = await this.resolver.resolve(structuredClone(node), context);
31721
+ const secrets = context.recordedSecretValues;
31722
+ const target = getAttTargetOf(node);
31723
+ const targetSecrets = target === void 0 ? void 0 : this.perResourceSecrets.get(target);
31724
+ if (targetSecrets !== void 0 && hasMaskableValues(targetSecrets)) {
31725
+ const probe = { value };
31726
+ const redacted = redactSecretsForState(probe, targetSecrets);
31727
+ if (JSON.stringify(redacted) !== JSON.stringify(probe)) return {
31728
+ value,
31729
+ keepAsWritten: true
31730
+ };
31731
+ }
31732
+ return {
31733
+ value,
31734
+ ...secrets && { secrets }
31735
+ };
31736
+ }
31737
+ };
31738
+ }
31739
+
31120
31740
  //#endregion
31121
31741
  //#region src/deployment/deploy-engine/create.ts
31122
31742
  async function provisionCreate(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress) {
@@ -31131,7 +31751,12 @@ async function provisionCreate(logicalId, change, stateResources, stackName, tem
31131
31751
  redactedAttributeReads: []
31132
31752
  }, stackName);
31133
31753
  if (context.recordedSecretValues) this.perResourceSecrets.set(logicalId, context.recordedSecretValues);
31754
+ printNestedStackReadsOnly(context, resourceType);
31134
31755
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
31756
+ this.noteSecretNamedRecord(logicalId, {
31757
+ resourceType,
31758
+ properties: resolvedProps
31759
+ });
31135
31760
  this.refuseRedactedAttributeReads(logicalId, resourceType, context);
31136
31761
  this.perResourceTemplateProps.set(logicalId, desiredProps);
31137
31762
  const fingerprintSources = template && this.maskedInputSources(template, stateResources, conditions, stackName);
@@ -31737,6 +32362,7 @@ var DynamoDBGlobalTableProvider = class {
31737
32362
  };
31738
32363
  } catch (wiringError) {
31739
32364
  warn(`Wiring failed after CreateTable for ${tableName}; attempting best-effort cleanup`);
32365
+ let tableLeftBehind = false;
31740
32366
  try {
31741
32367
  const replicasForCleanup = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName }))).Table?.Replicas ?? [];
31742
32368
  for (const replica of replicasForCleanup) {
@@ -31755,12 +32381,15 @@ var DynamoDBGlobalTableProvider = class {
31755
32381
  }
31756
32382
  await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
31757
32383
  } catch (cleanupErr) {
32384
+ tableLeftBehind = true;
31758
32385
  const cleanupMsg = describeAwsFailure(cleanupErr).detail;
31759
32386
  warn(`Partial-create cleanup failed for ${tableName}: ${cleanupMsg}. To remove the orphaned AWS-side table, run: ` + pasteableAwsCommand(maskSecrets)`aws dynamodb delete-table --table-name ${tableName}`.render());
31760
32387
  }
31761
32388
  markAuxiliaryFailure(wiringError, logicalId);
31762
32389
  const cause = wiringError instanceof Error ? wiringError : void 0;
31763
- throw this.wrapMaskedError(log, wiringError, (text) => new ProvisioningError(`Failed to create DynamoDB GlobalTable ${logicalId}: ${text}`, resourceType, logicalId, tableName, cause));
32390
+ const thrown = this.wrapMaskedError(log, wiringError, (text) => new ProvisioningError(`Failed to create DynamoDB GlobalTable ${logicalId}: ${text}`, resourceType, logicalId, tableName, cause));
32391
+ if (tableLeftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, tableName);
32392
+ throw thrown;
31764
32393
  }
31765
32394
  }
31766
32395
  reportThroughputDiagnostics(diagnostics, logicalId, physicalId, maskSecrets = (text) => text) {
@@ -34019,7 +34648,13 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
34019
34648
  }, stackName);
34020
34649
  const updateSecrets = context.recordedSecretValues ?? /* @__PURE__ */ new Map();
34021
34650
  this.perResourceSecrets.set(logicalId, updateSecrets);
34651
+ printNestedStackReadsOnly(context, resourceType);
34022
34652
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
34653
+ this.noteSecretNamedRecord(logicalId, {
34654
+ resourceType,
34655
+ physicalId: stateResources[logicalId]?.physicalId,
34656
+ properties: resolvedProps
34657
+ });
34023
34658
  this.perResourceTemplateProps.set(logicalId, desiredProps);
34024
34659
  this.perResourceResolvedType.set(logicalId, resourceType);
34025
34660
  recordNestedStackParameterExpressions(updateSecrets, resourceType, resolvedProps, desiredProps);
@@ -34645,7 +35280,14 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
34645
35280
  captureProvider = replProvider;
34646
35281
  } else throw updateError;
34647
35282
  }
34648
- if (result.wasReplaced) this.logger.info(`Resource ${logicalId} was replaced: ${currentResource.physicalId} -> ${result.physicalId}`);
35283
+ if (result.wasReplaced) {
35284
+ this.noteSecretNamedRecord(logicalId, {
35285
+ resourceType,
35286
+ physicalId: result.physicalId,
35287
+ properties: resolvedProps
35288
+ });
35289
+ this.logger.info(`Resource ${logicalId} was replaced: ${currentResource.physicalId} -> ${result.physicalId}`);
35290
+ }
34649
35291
  const dischargedByReplacement = result.wasReplaced === true && result.physicalId !== currentResource.physicalId;
34650
35292
  const keepsParameterRefusal = !dischargedByReplacement && hasUnverifiableParameterRefusal(currentResource);
34651
35293
  const carriedAttributes = result.attributes ?? (result.wasReplaced ? void 0 : currentResource.attributes);
@@ -34741,21 +35383,32 @@ async function provisionDelete(logicalId, change, stateResources, stackName, tem
34741
35383
  const skipPrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
34742
35384
  renderer.removeTask(logicalId);
34743
35385
  this.logger.info(`${skipPrefix}${formatResourceLine("skipped", logicalId, resourceType, `skipped (${deleteSkipped})`)}`);
34744
- this.logger.warn(deleteSkippedMessage(logicalId, currentResource.physicalId, deleteSkipped, "while removing it from the template") + `. Its cdkd state record was KEPT, so the next 'cdkd deploy' re-attempts the delete. Repair the record first (for a nested stack it is the CHILD's own state, whose other resources may already be gone), or delete the resource by hand and drop the record.\nInspect it with: ${pasteableCommand("cdkd state show", [{
34745
- value: stackName,
34746
- hole: "stack"
34747
- }, {
34748
- flag: "--stack-region",
34749
- value: this.stackRegion,
34750
- hole: "region"
34751
- }]).command}\nDrop the record with: ${pasteableCommand("cdkd state orphan", [{
34752
- value: stackName,
34753
- hole: "stack"
34754
- }, {
35386
+ const nested = resourceType === "AWS::CloudFormation::Stack";
35387
+ const recordStack = nested ? nestedChildStackName(stackName, logicalId) : stackName;
35388
+ const interrupted = nested && deleteSkipped.endsWith(" was interrupted");
35389
+ const stackArg = {
35390
+ value: recordStack,
35391
+ hole: nested ? "child-stack" : "stack",
35392
+ opts: { plainIdent: true }
35393
+ };
35394
+ this.logger.warn(deleteSkippedMessage(logicalId, currentResource.physicalId, deleteSkipped, "while removing it from the template") + ". Its cdkd state record was KEPT, so the next 'cdkd deploy' re-attempts the delete. Repair the record first (for a nested stack it is the CHILD's own state, whose other resources may already be gone), or delete the resource by hand and drop the record." + (interrupted ? " The commands name the child stack record. Its destroy was interrupted: re-run 'cdkd deploy' to resume it, and drop the child record only if that cannot finish, after deleting by hand what the child still holds (the inspect command with --show-nested lists every level; a child with nested stacks of its own has records under '<child>~<logicalId>' too, each needing the same drop)." : nested ? " The commands name the child stack record. Dropping it drops every record the child still has and nothing reaches those resources again, so first delete by hand what the child still holds (the inspect command with --show-nested lists every level; a child with nested stacks of its own has records under '<child>~<logicalId>' too, each needing the same drop). The next 'cdkd deploy' then removes this row." : " Keep '--resource' on the drop: without it the command drops the record of every resource in this still-deployed stack.") + `\nInspect it with: ${pasteableCommand("cdkd state show", [stackArg, {
34755
35395
  flag: "--stack-region",
34756
35396
  value: this.stackRegion,
34757
35397
  hole: "region"
34758
- }]).command}`);
35398
+ }]).command}\nDrop the record with: ${pasteableCommand("cdkd state orphan", [
35399
+ stackArg,
35400
+ {
35401
+ flag: "--stack-region",
35402
+ value: this.stackRegion,
35403
+ hole: "region"
35404
+ },
35405
+ ...nested ? [] : [{
35406
+ flag: "--resource",
35407
+ value: logicalId,
35408
+ hole: "logicalId",
35409
+ opts: { plainIdent: true }
35410
+ }]
35411
+ ]).command}`);
34759
35412
  if (counts) counts.deleteSkipped++;
34760
35413
  return { deleteSkipped };
34761
35414
  }
@@ -34782,31 +35435,61 @@ function validateOptions(opts) {
34782
35435
  }
34783
35436
  async function withResourceDeadline(operation, opts) {
34784
35437
  validateOptions(opts);
34785
- const startedAt = Date.now();
34786
35438
  return new Promise((resolve, reject) => {
34787
35439
  let settled = false;
35440
+ let timedOut = false;
35441
+ let warned = false;
34788
35442
  let warnTimer;
34789
35443
  let timeoutTimer;
35444
+ let elapsedBeforePause = 0;
35445
+ let runningSince = Date.now();
35446
+ let pauses = 0;
35447
+ const elapsed = () => elapsedBeforePause + (pauses > 0 ? 0 : Date.now() - runningSince);
34790
35448
  const cleanup = () => {
34791
35449
  if (warnTimer !== void 0) clearTimeout(warnTimer);
34792
35450
  if (timeoutTimer !== void 0) clearTimeout(timeoutTimer);
34793
35451
  warnTimer = void 0;
34794
35452
  timeoutTimer = void 0;
34795
35453
  };
34796
- if (opts.onWarn) warnTimer = setTimeout(() => {
34797
- if (settled) return;
34798
- try {
34799
- opts.onWarn(Date.now() - startedAt);
34800
- } catch {}
34801
- }, opts.warnAfterMs);
34802
- timeoutTimer = setTimeout(() => {
34803
- if (settled) return;
34804
- settled = true;
34805
- cleanup();
34806
- const elapsed = Date.now() - startedAt;
34807
- reject(opts.onTimeout(elapsed));
34808
- }, opts.timeoutMs);
34809
- Promise.resolve().then(() => operation()).then((value) => {
35454
+ const arm = () => {
35455
+ if (opts.onWarn && !warned) warnTimer = setTimeout(() => {
35456
+ if (settled) return;
35457
+ warned = true;
35458
+ try {
35459
+ opts.onWarn(elapsed());
35460
+ } catch {}
35461
+ }, Math.max(0, opts.warnAfterMs - elapsed()));
35462
+ timeoutTimer = setTimeout(() => {
35463
+ if (settled) return;
35464
+ settled = true;
35465
+ timedOut = true;
35466
+ cleanup();
35467
+ reject(opts.onTimeout(elapsed()));
35468
+ }, Math.max(0, opts.timeoutMs - elapsed()));
35469
+ };
35470
+ arm();
35471
+ const outer = deadlineScope.getStore();
35472
+ const control = {
35473
+ pause: () => {
35474
+ pauses += 1;
35475
+ if (pauses === 1) {
35476
+ elapsedBeforePause += Date.now() - runningSince;
35477
+ cleanup();
35478
+ }
35479
+ outer?.pause();
35480
+ },
35481
+ resume: () => {
35482
+ if (pauses === 0) return;
35483
+ pauses -= 1;
35484
+ if (pauses === 0) {
35485
+ runningSince = Date.now();
35486
+ if (!settled) arm();
35487
+ }
35488
+ outer?.resume();
35489
+ },
35490
+ expired: () => timedOut || (outer?.expired() ?? false)
35491
+ };
35492
+ Promise.resolve().then(() => deadlineScope.run(control, operation)).then((value) => {
34810
35493
  if (settled) return;
34811
35494
  settled = true;
34812
35495
  cleanup();
@@ -34819,6 +35502,20 @@ async function withResourceDeadline(operation, opts) {
34819
35502
  });
34820
35503
  });
34821
35504
  }
35505
+ const deadlineScope = new AsyncLocalStorage();
35506
+ async function whileEnclosingDeadlinesPaused(fn) {
35507
+ const control = deadlineScope.getStore();
35508
+ if (control === void 0) return fn();
35509
+ control.pause();
35510
+ try {
35511
+ return await fn();
35512
+ } finally {
35513
+ control.resume();
35514
+ }
35515
+ }
35516
+ function enclosingDeadlineExpired() {
35517
+ return deadlineScope.getStore()?.expired() ?? false;
35518
+ }
34822
35519
 
34823
35520
  //#endregion
34824
35521
  //#region src/deployment/deploy-engine/provision.ts
@@ -34856,10 +35553,13 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
34856
35553
  let updatePartial;
34857
35554
  const physicalIdBeforeUpdate = stateResources[logicalId]?.physicalId;
34858
35555
  const provisionedByBeforeUpdate = stateResources[logicalId]?.provisionedBy;
35556
+ this.noteSecretNamedRecord(logicalId, stateResources[logicalId]);
35557
+ if (change.changeType === "DELETE") this.noteSecretNamedReads(logicalId, stateResources[logicalId], stateResources);
35558
+ const printingRegistry = this.secretNameBagFor(logicalId);
34859
35559
  let nestedChildUnaddressed;
34860
35560
  const deleteGuards = [];
34861
35561
  try {
34862
- await withResourceDeadline(async () => {
35562
+ await withPrintingSecrets(printingRegistry, () => withResourceDeadline(async () => {
34863
35563
  try {
34864
35564
  const { value: bodyResult, unaddressed } = await collectDeleteGuards(deleteGuards, () => collectNestedChildUnaddressed(() => this.provisionResourceBody(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress)));
34865
35565
  deleteSkipped = bodyResult?.deleteSkipped;
@@ -34873,7 +35573,7 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
34873
35573
  logicalId,
34874
35574
  resourceType: guard.resourceType,
34875
35575
  ...guard.provisionedBy && { provisionedBy: guard.provisionedBy },
34876
- ...guard.physicalId && { physicalId: this.maskForResource(logicalId, guard.physicalId) },
35576
+ ...guard.physicalId && { physicalId: maskSecretsInText(guard.physicalId, this.perResourceSecrets.get(logicalId) ?? EMPTY_SECRETS) },
34877
35577
  guard: guard.guard,
34878
35578
  reason: guard.reason
34879
35579
  });
@@ -34892,7 +35592,7 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
34892
35592
  });
34893
35593
  },
34894
35594
  onTimeout: (elapsedMs) => new ResourceTimeoutError(logicalId, resourceType, this.stackRegion, elapsedMs, operationKind, timeoutMs)
34895
- });
35595
+ }));
34896
35596
  if (counts && nestedChildUnaddressed) {
34897
35597
  counts.deleteSkipped += nestedChildUnaddressed.deleteSkipped;
34898
35598
  counts.updatePartial += nestedChildUnaddressed.updatePartial;
@@ -34949,7 +35649,7 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
34949
35649
  durationMs: Date.now() - resourceStartedAt,
34950
35650
  error: extractDeploymentEventError(error)
34951
35651
  });
34952
- throw new ProvisioningError(`Failed to ${change.changeType.toLowerCase()} resource ${logicalId}`, resourceType, logicalId, stateResources[logicalId]?.physicalId, error instanceof Error ? maskSecretsInError(error, this.perResourceSecrets.get(logicalId) ?? EMPTY_SECRETS) : void 0);
35652
+ throw new ProvisioningError(`Failed to ${change.changeType.toLowerCase()} resource ${logicalId}`, resourceType, logicalId, stateResources[logicalId]?.physicalId, error instanceof Error ? maskSecretsInError(error, this.printingSecretsFor(logicalId) ?? EMPTY_SECRETS) : void 0);
34953
35653
  } finally {
34954
35654
  renderer.removeTask(logicalId);
34955
35655
  }
@@ -35381,6 +36081,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
35381
36081
  let autoRollbackJournaled = false;
35382
36082
  let rollbackOrphans = [];
35383
36083
  let rollbackSettledNested = /* @__PURE__ */ new Map();
36084
+ let rollbackRemainingFailedOps = failedOperations;
35384
36085
  if (error instanceof InterruptedError || isInterruptedWaitError(error) || this.interruptCause === "user") {
35385
36086
  await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "interrupted", initialDeploy);
35386
36087
  this.logger.info(`Partial state saved (${Object.keys(newResources).length} resources). Run deploy again to resume, 'cdkd rollback' to revert, or destroy to clean up.`);
@@ -35392,7 +36093,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
35392
36093
  this.logger.warn(safeMsg`Partial state has been saved. ${this.recoveryHint("Run 'cdkd deploy' to resume, 'cdkd rollback' to revert, or destroy to clean up.")}`);
35393
36094
  } else {
35394
36095
  autoRollbackJournaled = await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "auto-rollback-started", initialDeploy);
35395
- const rollbackResult = await this.performRollback(completedOperations, newResources, stackName, currentState);
36096
+ const rollbackResult = await this.performRollback(completedOperations, newResources, stackName, currentState, failedOperations, currentState.orphans ?? []);
35396
36097
  autoRollbackClean = autoRollbackJournaled && rollbackResult.failures === 0 && rollbackResult.skipped === 0;
35397
36098
  if (rollbackResult.failures === 0 && rollbackResult.skipped > 0) {
35398
36099
  this.logger.warn(safeMsg`The automatic rollback could not revert ${rollbackResult.skipped} operation(s) ` + `(see the warnings above; each is recorded as a ROLLBACK_RESOURCE_SKIPPED event).` + (autoRollbackJournaled ? ` The rollback journal keeps them.` : ""));
@@ -35403,6 +36104,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
35403
36104
  }
35404
36105
  rollbackOrphans = rollbackResult.orphaned;
35405
36106
  rollbackSettledNested = rollbackResult.settledNested;
36107
+ rollbackRemainingFailedOps = rollbackResult.remainingFailedOps;
35406
36108
  }
35407
36109
  try {
35408
36110
  const postRollbackState = {
@@ -35419,7 +36121,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
35419
36121
  };
35420
36122
  await this.stateBackend.saveState(stackName, this.stackRegion, this.withParentInfo(postRollbackState), { ...currentEtag !== void 0 && { expectedEtag: currentEtag } });
35421
36123
  this.logger.debug("State saved after deployment failure");
35422
- if (autoRollbackClean) await this.settleNestedChildrenAfterCleanRollback(stackName, rollbackSettledNested, await this.settleJournalAfterCleanRollback(stackName, failedOperations, initialDeploy));
36124
+ if (autoRollbackClean) await this.settleNestedChildrenAfterCleanRollback(stackName, rollbackSettledNested, await this.settleJournalAfterCleanRollback(stackName, rollbackRemainingFailedOps, initialDeploy));
35423
36125
  } catch (saveError) {
35424
36126
  this.logger.debug(`Retrying state save after rollback (ETag mismatch): ${saveError instanceof Error ? saveError.message : String(saveError)}`);
35425
36127
  try {
@@ -35438,7 +36140,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
35438
36140
  };
35439
36141
  await this.stateBackend.saveState(stackName, this.stackRegion, this.withParentInfo(postRollbackState), { ...freshEtag !== void 0 && { expectedEtag: freshEtag } });
35440
36142
  this.logger.debug("State saved after deployment failure (retry succeeded)");
35441
- if (autoRollbackClean) await this.settleNestedChildrenAfterCleanRollback(stackName, rollbackSettledNested, await this.settleJournalAfterCleanRollback(stackName, failedOperations, initialDeploy));
36143
+ if (autoRollbackClean) await this.settleNestedChildrenAfterCleanRollback(stackName, rollbackSettledNested, await this.settleJournalAfterCleanRollback(stackName, rollbackRemainingFailedOps, initialDeploy));
35442
36144
  } catch (retryError) {
35443
36145
  this.logger.warn(`Failed to save state after rollback: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
35444
36146
  }
@@ -35610,6 +36312,62 @@ function refuseNoValueOutputs(outputs, conditions) {
35610
36312
  throw markNonRetryable(/* @__PURE__ */ new Error(`Output ${offending.join(", ")} evaluates to AWS::NoValue, and CloudFormation rejects the template for it ("The Value field of every Outputs member must evaluate to a String") before creating anything. To publish an Output only sometimes, give it a Condition instead of selecting AWS::NoValue in its Value.`));
35611
36313
  }
35612
36314
 
36315
+ //#endregion
36316
+ //#region src/deployment/deployment-approval.ts
36317
+ const NESTED_STACK_TYPE$1 = "AWS::CloudFormation::Stack";
36318
+ async function requireDeploymentApproval(args) {
36319
+ const level = args.options.requireApproval ?? "never";
36320
+ const approve = args.options.approveDeployment;
36321
+ if (level === "never" || approve === void 0) return;
36322
+ const changes = [...args.changes].filter((c) => c.changeType !== "NO_CHANGE");
36323
+ const destructiveChanges = findDestructiveChanges(args.stackName, changes, args.records, args.template, new Set(args.recreateTargetIds ?? []));
36324
+ const onlyNestedUpdates = changes.every((c) => c.changeType === "UPDATE" && c.resourceType === NESTED_STACK_TYPE$1);
36325
+ if (!(level === "destructive" ? destructiveChanges.length > 0 : changes.length > 0 && !onlyNestedUpdates)) return;
36326
+ const count = (type) => changes.filter((c) => c.changeType === type).length;
36327
+ if (enclosingDeadlineExpired()) throw approvalAfterTimeout(args.stackName);
36328
+ let approved;
36329
+ try {
36330
+ approved = await whileEnclosingDeadlinesPaused(() => approve({
36331
+ stackName: args.stackName,
36332
+ level,
36333
+ counts: {
36334
+ create: count("CREATE"),
36335
+ update: count("UPDATE"),
36336
+ delete: count("DELETE")
36337
+ },
36338
+ destructiveChanges
36339
+ }));
36340
+ } catch (error) {
36341
+ throw error instanceof Error ? markNonRetryable(error) : error;
36342
+ }
36343
+ if (!approved) throw markNonRetryable(new CdkdError(safeMsg`Deployment of stack ${args.stackName} was not approved (--require-approval=${level}). Nothing was changed.`, "DEPLOY_NOT_APPROVED"));
36344
+ }
36345
+ function approvalAfterTimeout(stackName) {
36346
+ return markNonRetryable(new CdkdError(safeMsg`Deployment of stack ${stackName} was not started: its parent's nested-stack row already timed out (--resource-timeout). Nothing was changed.`, "DEPLOY_APPROVAL_AFTER_TIMEOUT"));
36347
+ }
36348
+ async function requireOutputsOnlyApproval(args) {
36349
+ const approve = args.options.approveDeployment;
36350
+ if (args.options.requireApproval !== "any-change" || approve === void 0) return;
36351
+ if (enclosingDeadlineExpired()) throw approvalAfterTimeout(args.stackName);
36352
+ let approved;
36353
+ try {
36354
+ approved = await whileEnclosingDeadlinesPaused(() => approve({
36355
+ stackName: args.stackName,
36356
+ level: "any-change",
36357
+ counts: {
36358
+ create: 0,
36359
+ update: 0,
36360
+ delete: 0
36361
+ },
36362
+ destructiveChanges: [],
36363
+ outputsOnly: true
36364
+ }));
36365
+ } catch (error) {
36366
+ throw error instanceof Error ? markNonRetryable(error) : error;
36367
+ }
36368
+ if (!approved) throw markNonRetryable(new CdkdError(safeMsg`Deployment of stack ${args.stackName} was not approved (--require-approval=any-change). Nothing was changed.`, "DEPLOY_NOT_APPROVED"));
36369
+ }
36370
+
35613
36371
  //#endregion
35614
36372
  //#region src/deployment/condition-verdicts.ts
35615
36373
  function conditionInputsFrom(args) {
@@ -36137,6 +36895,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36137
36895
  }));
36138
36896
  }
36139
36897
  const effectiveTemplate = this.templateParser.filterResourcesByCondition(template, conditions);
36898
+ this.constructPathTemplate = effectiveTemplate;
36140
36899
  const orphanCountBeforeAdoption = (currentState.orphans ?? []).length;
36141
36900
  const orphanPlan = await this.adoptRollbackOrphans(currentState, effectiveTemplate);
36142
36901
  if (Object.keys(orphanPlan.adopted).length > 0) {
@@ -36230,6 +36989,10 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36230
36989
  const skippedOutputsChanged = !skippedOutputsEqual(currentState.skippedOutputs, this.skippedOutputs);
36231
36990
  const healedAttributesPending = this.hasUnpersistedHeals(currentState.resources);
36232
36991
  const conditionVerdictsChanged = !conditionVerdictRecordsEqual(readRecordedConditionVerdicts(currentState), conditionVerdicts);
36992
+ if (outputsChanged || exportSetChanged && currentState.exportNames !== void 0) await requireOutputsOnlyApproval({
36993
+ options: this.options,
36994
+ stackName
36995
+ });
36233
36996
  if (observedRefresh || maskedFingerprintsBackfilled || conditionVerdictsChanged || outputsChanged || exportSetChanged || skippedOutputsChanged || orphansChanged || healedAttributesPending) try {
36234
36997
  const refreshedState = {
36235
36998
  version: 10,
@@ -36263,13 +37026,12 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36263
37026
  this.logger.warn(`Failed to persist no-change state update: ${saveError instanceof Error ? saveError.message : String(saveError)} — drift baseline / outputs will be re-resolved on next deploy.`);
36264
37027
  }
36265
37028
  }
36266
- if (!this.options.dryRun) await this.settleJournalAfterSuccess(stackName, [], currentState, currentState.resources, currentEtag === void 0);
36267
37029
  return {
36268
37030
  stackName,
36269
37031
  created: 0,
36270
37032
  updated: 0,
36271
37033
  deleted: 0,
36272
- deleteSkipped: 0,
37034
+ deleteSkipped: this.options.dryRun ? 0 : await this.settleJournalAfterSuccess(stackName, [], currentState, currentState.resources, currentEtag === void 0),
36273
37035
  updatePartial: 0,
36274
37036
  unchanged: Object.keys(currentState.resources).length,
36275
37037
  durationMs: Date.now() - startTime,
@@ -36295,6 +37057,14 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36295
37057
  attributeFallbackCount: this.resolver.getPhysicalIdFallbackCount()
36296
37058
  };
36297
37059
  }
37060
+ await requireDeploymentApproval({
37061
+ options: this.options,
37062
+ stackName,
37063
+ changes: changes.values(),
37064
+ records: currentState.resources,
37065
+ template: effectiveTemplate,
37066
+ recreateTargetIds: recreateTargetIdsFor(this.options.recreateTargets, stackName)
37067
+ });
36298
37068
  this.resolver.resetPhysicalIdFallbackCount();
36299
37069
  const progress = {
36300
37070
  current: 0,
@@ -36308,7 +37078,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36308
37078
  } : newState));
36309
37079
  this.logger.debug(`State saved (ETag: ${newEtag})`);
36310
37080
  await forgetRecordedCreateTokens(Object.keys(newState.resources));
36311
- await Promise.all([this.settleJournalAfterSuccess(stackName, completedOperations, currentState, newState.resources, currentEtag === void 0), this.exportIndexStore ? this.exportIndexStore.updateForStack(stackName, this.stackRegion, importableOutputs({
37081
+ const [journaledOrphansLeft] = await Promise.all([this.settleJournalAfterSuccess(stackName, completedOperations, currentState, newState.resources, currentEtag === void 0), this.exportIndexStore ? this.exportIndexStore.updateForStack(stackName, this.stackRegion, importableOutputs({
36312
37082
  ...newState,
36313
37083
  outputs: this.redactOutputs(newState.outputs)
36314
37084
  })) : Promise.resolve()]);
@@ -36319,7 +37089,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36319
37089
  created: actualCounts.created,
36320
37090
  updated: actualCounts.updated,
36321
37091
  deleted: actualCounts.deleted,
36322
- deleteSkipped: actualCounts.deleteSkipped,
37092
+ deleteSkipped: actualCounts.deleteSkipped + journaledOrphansLeft,
36323
37093
  updatePartial: actualCounts.updatePartial,
36324
37094
  nestedUpdatePartial: actualCounts.nestedUpdatePartial,
36325
37095
  unchanged: unchangedCount,
@@ -36342,77 +37112,6 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
36342
37112
  }
36343
37113
  }
36344
37114
 
36345
- //#endregion
36346
- //#region src/deployment/deploy-engine/resolver-context.ts
36347
- function buildResolverContext(base, stackName) {
36348
- const recordedSecretValues = /* @__PURE__ */ new Map();
36349
- if (this.options.inheritedSecrets && this.options.inheritedSecrets.size > 0) inheritNestedStackParameterAssociations(recordedSecretValues, this.options.inheritedSecrets);
36350
- return {
36351
- template: base.template,
36352
- resources: base.resources,
36353
- ...base.parameters && Object.keys(base.parameters).length > 0 && { parameters: base.parameters },
36354
- ...base.conditions && Object.keys(base.conditions).length > 0 && { conditions: base.conditions },
36355
- stateBackend: this.stateBackend,
36356
- stackName,
36357
- ...this.exportIndexStore && { exportIndex: this.exportIndexStore },
36358
- recordedImports: this.recordedImports,
36359
- recordedOutputReads: this.recordedOutputReads,
36360
- attributeHealer: (logicalId, resource) => this.healStaleAttributes(logicalId, resource, stackName),
36361
- ...this.options.inheritedSecrets && hasMaskableValues(this.options.inheritedSecrets) && { inheritedSecrets: this.options.inheritedSecrets },
36362
- recordedSecretValues,
36363
- noEchoAttributeResources: this.noEchoAttributeResources,
36364
- ...base.redactedAttributeReads && { redactedAttributeReads: base.redactedAttributeReads }
36365
- };
36366
- }
36367
- function getAttTargetOf(node) {
36368
- if (node === null || typeof node !== "object" || Array.isArray(node)) return void 0;
36369
- const getAtt = node["Fn::GetAtt"];
36370
- if (Array.isArray(getAtt) && typeof getAtt[0] === "string") return getAtt[0];
36371
- if (typeof getAtt === "string") return getAtt.split(".")[0];
36372
- }
36373
- function maskedInputSources(template, resources, conditions, stackName) {
36374
- const parameters = this.fingerprintParameters;
36375
- if (parameters === void 0) return void 0;
36376
- return {
36377
- template,
36378
- parameterInput: parameters.parameterInput,
36379
- conditions,
36380
- childTemplate: this.fingerprintChildTemplates,
36381
- resolve: async (node) => {
36382
- const { attributeHealer: _healer, ...base } = this.buildResolverContext({
36383
- template,
36384
- resources,
36385
- parameters: parameters.bound,
36386
- ...conditions && { conditions }
36387
- }, stackName);
36388
- const context = {
36389
- ...base,
36390
- recordedImports: [],
36391
- recordedOutputReads: [],
36392
- bestEffort: true,
36393
- skipDynamicReferences: true,
36394
- staleAttributeHeal: { phase: "probe" }
36395
- };
36396
- const value = await this.resolver.resolve(structuredClone(node), context);
36397
- const secrets = context.recordedSecretValues;
36398
- const target = getAttTargetOf(node);
36399
- const targetSecrets = target === void 0 ? void 0 : this.perResourceSecrets.get(target);
36400
- if (targetSecrets !== void 0 && hasMaskableValues(targetSecrets)) {
36401
- const probe = { value };
36402
- const redacted = redactSecretsForState(probe, targetSecrets);
36403
- if (JSON.stringify(redacted) !== JSON.stringify(probe)) return {
36404
- value,
36405
- keepAsWritten: true
36406
- };
36407
- }
36408
- return {
36409
- value,
36410
- ...secrets && { secrets }
36411
- };
36412
- }
36413
- };
36414
- }
36415
-
36416
37115
  //#endregion
36417
37116
  //#region src/deployment/label-routing.ts
36418
37117
  function deriveLabelRouting(change, existingState, registry, forceCcApi = false) {
@@ -36633,6 +37332,7 @@ var DeployEngine = class {
36633
37332
  recordedOutputReads = [];
36634
37333
  perResourceSecrets = /* @__PURE__ */ new Map();
36635
37334
  noEchoAttributeResources = /* @__PURE__ */ new Map();
37335
+ secretNameNeedles = /* @__PURE__ */ new Map();
36636
37336
  perResourceTemplateProps = /* @__PURE__ */ new Map();
36637
37337
  perResourceResolvedType = /* @__PURE__ */ new Map();
36638
37338
  fingerprintNoEchoValues = void 0;
@@ -36644,6 +37344,7 @@ var DeployEngine = class {
36644
37344
  outputsTemplateSource = Object.create(null);
36645
37345
  resolvedExportNames = [];
36646
37346
  skippedOutputs;
37347
+ constructPathTemplate;
36647
37348
  outputsSourceUsable = true;
36648
37349
  attemptedResolvedProps = /* @__PURE__ */ new Map();
36649
37350
  liveTaskLabels = /* @__PURE__ */ new Map();
@@ -36684,7 +37385,9 @@ var DeployEngine = class {
36684
37385
  this.recordedOutputReads = [];
36685
37386
  this.perResourceSecrets = /* @__PURE__ */ new Map();
36686
37387
  this.noEchoAttributeResources = /* @__PURE__ */ new Map();
37388
+ this.secretNameNeedles = /* @__PURE__ */ new Map();
36687
37389
  this.perResourceTemplateProps = /* @__PURE__ */ new Map();
37390
+ this.constructPathTemplate = void 0;
36688
37391
  this.perResourceResolvedType = /* @__PURE__ */ new Map();
36689
37392
  this.fingerprintNoEchoValues = void 0;
36690
37393
  this.fingerprintParameters = void 0;
@@ -36717,7 +37420,7 @@ var DeployEngine = class {
36717
37420
  const secrets = this.perResourceSecrets.get(logicalId);
36718
37421
  const templateProps = this.perResourceTemplateProps.get(logicalId);
36719
37422
  const scrubbed = scrubResourceRecord(this.withHealedAttributes(logicalId, record), secrets ?? /* @__PURE__ */ new Map(), templateProps);
36720
- resources[logicalId] = withMaskedPropertyFingerprints(scrubbed, record.properties, templateProps, secrets, this.fingerprintNoEchoValues, this.perResourceInputFingerprints.get(logicalId));
37423
+ resources[logicalId] = withConstructPath(withMaskedPropertyFingerprints(scrubbed, record.properties, templateProps, secrets, this.fingerprintNoEchoValues, this.perResourceInputFingerprints.get(logicalId)), constructPathOf(this.constructPathTemplate, logicalId));
36721
37424
  }
36722
37425
  const orphans = state.orphans?.map((entry) => {
36723
37426
  const sameResource = this.perResourceResolvedType.get(entry.logicalId) === entry.state.resourceType;
@@ -36798,7 +37501,7 @@ var DeployEngine = class {
36798
37501
  } catch {}
36799
37502
  }
36800
37503
  maskSecretsInEvent(event) {
36801
- const secrets = event.logicalId ? this.perResourceSecrets.get(event.logicalId) : void 0;
37504
+ const secrets = event.logicalId ? this.printingSecretsFor(event.logicalId) : void 0;
36802
37505
  if (!secrets || !hasMaskableValues(secrets)) return event;
36803
37506
  const next = { ...event };
36804
37507
  if (next.error?.message) next.error = {
@@ -36874,6 +37577,11 @@ DeployEngine.prototype.refuseRedactedAttributeReads = refuseRedactedAttributeRea
36874
37577
  DeployEngine.prototype.allRecordedSecrets = allRecordedSecrets;
36875
37578
  DeployEngine.prototype.readReaderForFreshNoEchoCeiling = readReaderForFreshNoEchoCeiling;
36876
37579
  DeployEngine.prototype.maskForResource = maskForResource;
37580
+ DeployEngine.prototype.secretNameBagFor = secretNameBagFor;
37581
+ DeployEngine.prototype.noteSecretNamedRecord = noteSecretNamedRecord;
37582
+ DeployEngine.prototype.printingSecretsFor = printingSecretsFor;
37583
+ DeployEngine.prototype.namingSecretsFor = namingSecretsFor;
37584
+ DeployEngine.prototype.noteSecretNamedReads = noteSecretNamedReads;
36877
37585
  DeployEngine.prototype.kickOffObservedCapture = kickOffObservedCapture;
36878
37586
  DeployEngine.prototype.drainObservedCaptures = drainObservedCaptures;
36879
37587
  DeployEngine.prototype.buildObservedCaptureSiblings = buildObservedCaptureSiblings;
@@ -36898,5 +37606,5 @@ DeployEngine.prototype.replacementNameOrigin = replacementNameOrigin;
36898
37606
  DeployEngine.prototype.orphanedNameCollisionAdvice = orphanedNameCollisionAdvice;
36899
37607
 
36900
37608
  //#endregion
36901
- export { resourcesNamingDeclaredParameter as $, recordMaskOnlyValuesIn as $a, WARM_THROUGHPUT_MEMBERS as $i, assertSendableRoleArn as $n, getDockerCmd as $o, malformedOutputsRefusalMessage as $r, isWholeDynamicReferenceValue as $t, resolveDynamoDbDeleteBudgetClock as A, hasMaskableValues as Aa, refuseMalformedResourcesForExport as Ai, slowCcOperationTimeoutMs as An, buildAssetRedirectMap as Ao, JSON_LISTING_HOLE_VALUE as Ar, uploadCfnTemplate as As, buildFinalSnapshotIdentifier as At, getPriorAttempts as B, maskSecretsInText as Ba, unreadableResourceEntries as Bi, ec2InstanceProtectionSite as Bn, parseBootstrapMarker as Bo, isReadableOrphanRecord as Br, defineOwnKey as Bs, redactedDeleteAddressSkip as Bt, perType as C, DagBuilder as Ca, refuseMalformedResourceEntriesForOrphan as Ci, CC_BROKEN_REASON as Cn, orphansAfterRollback as Co, cfnRefValueFromPhysicalId as Cr, stateBucketExistenceConfirmed as Cs, planRollback as Ct, beginDeleteWait as D, recordNestedStackParameterExpressions as Da, refuseMalformedResourcePropertiesForOrphan as Di, isCustomResourceType as Dn, isSensitiveAttributeName as Do, withSharedDrainBudget as Dr, CFN_TEMPLATE_URL_LIMIT as Ds, inheritProducerRegions as Dt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as E, inheritNestedStackParameterAssociations as Ea, refuseMalformedResourcePropertiesForExport as Ei, wouldReturnToSdkProvider as En, AssetPublisher as Eo, parseWebACLArn as Er, CFN_TEMPLATE_BODY_LIMIT as Es, getCurrentProducerRegions as Et, waitForIndexesSettled as F, recordLogOnlyValue as Fa, repairMalformedResourceEntriesForReadOnly as Fi, deleteSkipReason as Fn, BOOTSTRAP_MARKER_PREFIX as Fo, deployRefusesOrphanRowsReason as Fr, canonicalizeRegion as Fs, refusesFinalSnapshot as Ft, cyan as G, DYNAMIC_REFERENCE_TOKEN_SCAN as Ga, NO_CC_HANDLERS_REASON as Gi, DiffCalculator as Gn, buildDockerImage as Go, malformedLocalOutputsWarning as Gr, absoluteAssemblyPathEscape as Gs, extractDeploymentEventError as Gt, formatResourceLine as H, redactSecretsForState as Ha, findSilentDropProperties as Hi, observeThenDisableInstanceApiTermination as Hn, validateAssetBucketName as Ho, malformedDriftResourcePropertiesWarning as Hr, hasPlainPrototype$1 as Hs, updatePartialReason as Ht, ECR_AUTO_DELETE_IMAGES_TAG as I, shareLogOnlyValues as Ia, repairMalformedResourcePropertiesForReadOnly as Ii, withIndeterminateGuard as In, assertAssetBucketRegion as Io, displayLogicalId as Ir, derivePartitionAndUrlSuffix as Is, unsupportedFinalSnapshotError as It, red as J, pathCrossesDottedKey as Ja, shownType as Ji, classifyReplaySecretRegion as Jn, describeDockerExecFailure as Jo, malformedOrphanRecordsRefusalMessage as Jr, renderAssemblyPathEscape as Js, exportAliasCollisionScrubWarning as Jt, gray as K, dynamicReferenceTokens as Ka, hasNoCloudControlHandlers as Ki, INTRINSIC_KEYS as Kn, resolveDockerContextDirectory as Ko, malformedLocalResourceEntriesWarning as Kr, describeFileReadFailure as Ks, WITHHELD_NAME_DISPLAY as Kt, S3_AUTO_DELETE_OBJECTS_TAG as L, createSecretMasker as La, repairMalformedResourcesForReadOnly as Li, isWaitAbandonedError as Ln, ensureAssetStorage as Lo, hasReadableOrphans as Lr, AssemblyReader as Ls, REDACTED_DELETE_ADDRESS_SKIP_REASON as Lt, DELETE_INDEX_WAIT_PROCEED_NOTE as M, logOnlyValueCount as Ma, repairMalformedOrphanRecordsForReadOnly as Mi, unchangedBehindSecretReference as Mn, loadPublishableAssetManifest as Mo, STATE_RESOURCES_MALFORMED as Mr, decodeListingKey as Ms, createPreDeleteFinalSnapshot as Mt, INDEX_SETTLE_POLL_INTERVAL_MS as N, printingCorpusOf as Na, repairMalformedOrphansForReadOnly as Ni, UNSPECIFIED_SKIP_REASON as Nn, rewriteTemplateAssetReferences as No, UNREADABLE_ORPHANS_CONTAINER_ROW as Nr, expectedOwnerParam as Ns, effectiveDeletionPolicy as Nt, compensateRemovedDeletionProtection as O, carryLogOnlyValues as Oa, refuseMalformedResourcesForDeploy as Oi, getCurrentResourceSecrets as On, stringifyValue as Oo, parameterInputsFor as Or, MIGRATE_TMP_PREFIX as Os, ATOMIC_FINAL_SNAPSHOT_TYPES as Ot, deleteTableWithIndexBusyRetry as P, recordLogOnlyParameterValue as Pa, repairMalformedOutputsForReadOnly as Pi, deleteIndeterminateGuards as Pn, AssetModeResolver as Po, UNREADABLE_RESOURCES_MAP_ROW as Pr, PARTITION_TABLE as Ps, isFinalSnapshotError as Pt, reachableDivergentParameters as Q, recordMaskOnlyValue as Qa, renderStatefulReason as Qi, assertFlagRoleArn as Qn, formatDockerLoginError as Qo, malformedOrphansWarning as Qr, exportNameSecretExposure as Qt, hasCdkAutoDeleteTag as R, errorCauseChain as Ra, unpreviewableOrphanRecords as Ri, markWaitAbandoned as Rn, getBootstrapMarkerKey as Ro, hasReadableOutputs as Rr, StageLoadError as Rs, isRedactedRecordedValue as Rt, isProtectionValueActive as S, sameLambdaFunctionAddress as Sa, refuseMalformedResourceEntriesForImportSave as Si, stringifyIfAssigned as Sn, isReadableBag as So, AWS_NO_VALUE as Sr, resolveUseCdkBootstrapAssets as Ss, planFailedOps as St, DynamoDBGlobalTableProvider as T, liveMatchesUnresolvedTokenFrame as Ta, refuseMalformedResourcePropertiesForDrift as Ti, ccBrokenReason as Tn, shouldRetainResource as To, refStateLookupFromResource as Tr, ssmResolvedValueType as Ts, findNestedStackTypeChanges as Tt, createReadOnlyAttributeHealerFactory as U, scrubResourceRecord as Ua, unwrittenCreateOnlyReplacement as Ui, reDisableInstanceApiTermination as Un, validateContainerRepoName as Uo, malformedExportNamesWarning as Ur, nullPrototypeRecord as Us, DeploymentEventsReader as Ut, markRefusedBeforeApplying as V, markSameGenerationBag as Va, findActionableSilentDrops as Vi, isTerminationProtectionPropagationError as Vn, readBootstrapMarkerBody as Vo, isReadableResourceEntry as Vr, hasOwnKey as Vs, updatePartialMessage as Vt, bold as W, recoverMaskedOutput as Wa, withoutSilentDropProperties as Wi, reEnableInstanceApiTermination as Wn, buildDenyExternalAccessPolicy as Wo, malformedExportSourceWarning as Wr, ownValue as Ws, DeploymentEventsStore as Wt, computeParameterTaint as X, carriesSecretMask as Xa, isStatefulRecreateTargetForReplace as Xi, regionLessSecretName as Xn, dockerSpawnEnvWithSensitive as Xo, malformedOrphanRowsKeptWarning as Xr, clearBucketRegionCache as Xs, secretBearingStateKeyWarning as Xt, yellow as Y, identityKeyFor as Ya, MULTI_REGION_RECREATE_BLOCKED_TYPES as Yi, producerRegionsFromState as Yn, describeDockerFailure as Yo, malformedOrphanRecordsWarning as Yr, resolveAssemblyPath as Ys, secretBearing as Yt, namesAnyDeclaredParameter as Z, provenPublicValue as Za, isStatefulRecreateTargetSync as Zi, applyRoleArnIfSet as Zn, finchSecretArgvRefusal as Zo, malformedOrphansRefusalMessage as Zr, resolveBucketRegion as Zs, secretSafeKeyDisplay as Zt, makeCanonicalizePropertiesFn as _, withRetry as _a, refuseMalformedResourceAttributesForOrphan as _i, readTagList as _n, hasReadableExportSet as _o, isImpossibleEmptyStoredAttribute as _r, resolveAutoAssetStorage as _s, destroyStackRecordsView as _t, findNestedTemplateTreeDefect as a, coerceCfnInteger as aa, malformedScrubResourceEntriesRefusalMessage as ai, DEFAULT_RESOURCE_TIMEOUT_MS as an, STATE_SOURCED_READBACK_RULES as ao, callerEnvCredentials as ar, runDockerForeground as as, dropSettledNestedJournals as at, recordedProtectionNote as b, canonicalLambdaFunctionName as ba, refuseMalformedResourceEntriesForDestroy as bi, tagPlanWarning as bn, importableOutputKeys as bo, isNamelessDynamicReferenceError as br, resolveStateBucketWithDefault as bs, recordAfterRollbackUpdate as bt, renderNestedTemplateTreeDefect as c, configStringRefusal as ca, refuseDivergentRecordRegionForDestroy as ci, RollbackInlinePolicyWriters as cn, isSingleDynamicReferenceToken as co, s3BucketArn as cr, escapeRegExp$3 as cs, recordDisplacedSkips as ct, conditionInputsFrom as d, requireConfigArray as da, refuseMalformedOrphanRecordsForDestroy as di, reserveStackCreateToken as dn, S3StateBackend as do, s3BucketRegionalDomainName as dr, getDockerImageBySourceHash as ds, withNestedRevertRun as dt, coerceWarmThroughput as ea, malformedOutputsWarning as ei, noEchoParameterValueSeed as en, recordNoEchoAttributeValues as eo, explicitRoleArnOrThrow as er, isDockerClientEnvKey as es, makeSiblingClaimReader as et, parentSuppliedValues as f, requireConfigObject as fa, refuseMalformedOrphans as fi, withCreateTokenLedger as fn, rebuildClientForBucketRegion as fo, s3BucketWebsiteUrl as fr, Synthesizer as fs, getCurrentNestedStackContext as ft, mergeNoChangeOutputs as g, describeTypeWithThrottleRetry as ga, refuseMalformedOutputsForDestroy as gi, planTagDiff as gn, exportNamesCarriedFrom as go, getAccountInfo as gr, resolveApp as gs, awaitInFlightSibling as gt, keptWholeReasonText as h, templateResourceTypes as ha, refuseMalformedOutputs as hi, DBPROXY_TAG_OPTIONS as hn, describeRegionValueKind as ho, parameterTypeMayLoseSecretIdentity as hr, getLegacyStateBucketName as hs, replayRollback as ht, childTemplateLoader as i, coerceCfnBoolean as ia, malformedResourcesWarning as ii, bindingSkippedOutputs as in, STATE_SOURCED_CROSS_GENERATION_RULES as io, applyCallerIdentityCredentials as ir, redactedDockerCause as is, displacedPhysicalIdShown as it, resolveDynamoDbDeleteBudgetMs as j, literalSplitDelimitersOf as ja, refuseMalformedState as ji, ccProtectionRegistryTypes as jn, createAssetRedirectResolver as jo, STATE_REGION_DIVERGED as jr, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as js, ccRoutedFinalSnapshotError as jt, deleteBudgetKey as k, createUnionSecretMasker as ka, refuseMalformedResourcesForDestroy as ki, CloudControlProvider as kn, WorkGraph as ko, passedParameterClassesOf as kr, findLargeInlineResources as ks, PRE_DELETE_SNAPSHOT_TYPES as kt, templateIdentity as l, readConfigString as la, refuseMalformedNestedChildOutputs as li, earliestDefined as ln, LockManager as lo, s3BucketDomainName as lr, stripControlChars as ls, revertNestedChildFromJournal as lt, isSecretBearingReferenceString as m, prefetchCreateOnlyPropertyPaths as ma, refuseMalformedOrphansForOrphan as mi, DBPROXY_TAGS_WHAT as mn, acceptedCreateOnlyDropsOf as mo, isUnboundTemplateParameter as mr, getDefaultStateBucketName as ms, replayFailedOperations as mt, IMPLICIT_DELETE_DEPENDENCIES as n, toCfnInteger as na, malformedResourceEntriesWarning as ni, collectPublishedOutputNames as nn, wholeStringLeavesOf as no, sendableAssumeRoleCommand as nr, partitionSensitiveEnv as ns, NESTED_PENDING_PARENT_REASON as nt, isAbsoluteAssetPath as o, configBooleanRefusal as oa, malformedStateRefusalMessage as oi, DEFAULT_RESOURCE_WARN_AFTER_MS as on, TEMPLATE_SOURCED_RULES as oo, envCredentialsAreAssumedRole as or, runDockerStreaming as os, getNestedRevertRun as ot, readRecordedConditionVerdicts as p, requireConfigString as pa, refuseMalformedOrphansForDestroy as pi, acquireIdempotencyToken as pn, splitImportedOps as po, coerceParameterTypedValue as pr, synthesisStatusMessage as ps, withNestedStackContext as pt, green as q, isUncertifiedBaselineMaskPosition as qa, findReplacedReadersOfRecreateTargets as qi, IntrinsicFunctionResolver as qn, describeDockerCapturedOutput as qo, malformedLocalResourcesWarning as qr, displayAssemblyPath as qs, displayTextOrWithheld as qt, computeImplicitDeleteEdges as r, toFiniteNumber as ra, malformedResourcePropertiesWarning as ri, isExportAliasCollision as rn, STATE_SOURCED_BASELINE_RULES as ro, AWS_CREDENTIAL_ENV_KEYS as rr, redactDockerArgvValues as rs, displacedOpClause as rt, listNestedTemplateRows as s, configIntegerRefusal as sa, previewableOrphanRecords as si, maskingRetryLogger as sn, WHOLE_DYNAMIC_REFERENCE_PATTERN as so, isSettledInstanceState as sr, warnFinchArgvExposure as ss, nestedChildStackName as st, DeployEngine as t, isWarmThroughputDecrease as ta, malformedRenderedContainersWarning as ti, collectDeclaredOutputNames as tn, recordProvenPublicExpression as to, isIamRoleArn as tr, isMalformedEnvKey as ts, planOrphanAdoption as tt, conditionFingerprint as u, replayWarn as ua, refuseMalformedOrphanRecords as ui, ledgerForStack as un, isLockInfoExpired as uo, s3BucketDualStackDomainName as ur, AssetManifestLoader as us, revertedNestedRowIds as ut, withResourceDeadline as v, markAuxiliaryFailure as va, refuseMalformedResourceEntries as vi, refuseMalformedDesiredTags as vn, hasReasonlessBaselineRefusal as vo, carriesDynamicReference as vr, resolveCaptureObservedState as vs, getStackRecords as vt, readProtection as w, TemplateParser as wa, refuseMalformedResourcePropertiesForDestroy as wi, ProviderRegistry as wn, orphansCarriedFrom as wo, isStalePlaceholderArnAttribute as wr, warnDeprecatedNoPrefixCliFlag as ws, resolveReplacementOldType as wt, PROTECTION_PROPERTY_BY_TYPE as x, lambdaFunctionNameForMask as xa, refuseMalformedResourceEntriesForImport as xi, definedAttributes as xn, importableOutputs as xo, keepsSecretReferenceToken as xr, resolveStateBucketWithDefaultAndSource as xs, demoteSupersededOrphans as xt, recordedProtectionEvidence as y, markCreatedBeforeFailure as ya, refuseMalformedResourceEntriesForDeploy as yi, tagMapAsList as yn, hasUnverifiableParameterRefusal as yo, carriesFetchableDynamicReference as yr, resolveSkipPrefix as ys, withStackRecords as yt, isTruthyCfnBoolean as z, maskSecretsInError as za, unreadableOrphanRecords as zi, disableInstanceApiTermination as zn, isCrossRegionRedirect as zo, hasReadableResources as zr, processStackMessages as zs, redactedDeleteAddressFields as zt };
36902
- //# sourceMappingURL=deploy-engine-DG-oC9YK.js.map
37609
+ export { resourcesNamingDeclaredParameter as $, dynamicReferenceTokens as $a, withoutSilentDropProperties as $i, reEnableInstanceApiTermination as $n, resolveDockerContextDirectory as $o, malformedExportSourceWarning as $r, absoluteAssemblyPathEscape as $s, displayTextOrWithheld as $t, resolveDynamoDbDeleteBudgetClock as A, DagBuilder as Aa, refuseMalformedResourceEntriesForImport as Ai, definedAttributes as An, orphansAfterRollback as Ao, keepsSecretReferenceToken as Ar, resolveUseCdkBootstrapAssets as As, resolveReplacementOldType as At, getPriorAttempts as B, printingCorpusOf as Ba, refuseMalformedState as Bi, ccProtectionRegistryTypes as Bn, rewriteTemplateAssetReferences as Bo, STATE_REGION_DIVERGED as Br, decodeListingKey as Bs, isFinalSnapshotError as Bt, perType as C, prefetchCreateOnlyPropertyPaths as Ca, refuseMalformedOrphansForOrphan as Ci, DBPROXY_TAGS_WHAT as Cn, exportNamesCarriedFrom as Co, isUnboundTemplateParameter as Cr, loadCdkJson as Cs, getStackRecords as Ct, beginDeleteWait as D, canonicalLambdaFunctionName as Da, refuseMalformedResourceEntries as Di, refuseMalformedDesiredTags as Dn, importableOutputKeys as Do, carriesDynamicReference as Dr, resolveSkipPrefix as Ds, isJournaledOrphan as Dt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as E, withRetry as Ea, refuseMalformedResourceAttributesForOrphan as Ei, readTagList as En, hasUnverifiableParameterRefusal as Eo, isImpossibleEmptyStoredAttribute as Er, resolveCaptureObservedState as Es, demoteSupersededOrphans as Et, waitForIndexesSettled as F, carryLogOnlyValues as Fa, refuseMalformedResourcePropertiesForExport as Fi, wouldReturnToSdkProvider as Fn, stringifyValue as Fo, parseWebACLArn as Fr, CFN_TEMPLATE_URL_LIMIT as Fs, PRE_DELETE_SNAPSHOT_TYPES as Ft, cyan as G, errorCauseChain as Ga, repairMalformedResourcePropertiesForReadOnly as Gi, withIndeterminateGuard as Gn, getBootstrapMarkerKey as Go, displayLogicalId as Gr, AssemblyReader as Gs, redactedDeleteAddressFields as Gt, formatResourceLine as H, recordLogOnlyValue as Ha, repairMalformedOrphansForReadOnly as Hi, UNSPECIFIED_SKIP_REASON as Hn, BOOTSTRAP_MARKER_PREFIX as Ho, UNREADABLE_ORPHANS_CONTAINER_ROW as Hr, PARTITION_TABLE as Hs, unsupportedFinalSnapshotError as Ht, ECR_AUTO_DELETE_IMAGES_TAG as I, createUnionSecretMasker as Ia, refuseMalformedResourcePropertiesForOrphan as Ii, isCustomResourceType as In, WorkGraph as Io, withSharedDrainBudget as Ir, MIGRATE_TMP_PREFIX as Is, buildFinalSnapshotIdentifier as It, red as J, markSameGenerationBag as Ja, unreadableOrphanRecords as Ji, disableInstanceApiTermination as Jn, readBootstrapMarkerBody as Jo, hasReadableResources as Jr, defineOwnKey as Js, updatePartialReason as Jt, gray as K, maskSecretsInError as Ka, repairMalformedResourcesForReadOnly as Ki, isWaitAbandonedError as Kn, isCrossRegionRedirect as Ko, hasReadableOrphans as Kr, StageLoadError as Ks, redactedDeleteAddressSkip as Kt, S3_AUTO_DELETE_OBJECTS_TAG as L, hasMaskableValues as La, refuseMalformedResourcesForDeploy as Li, getCurrentResourceSecrets as Ln, buildAssetRedirectMap as Lo, parameterInputsFor as Lr, findLargeInlineResources as Ls, ccRoutedFinalSnapshotError as Lt, DELETE_INDEX_WAIT_PROCEED_NOTE as M, liveMatchesUnresolvedTokenFrame as Ma, refuseMalformedResourceEntriesForOrphan as Mi, CC_BROKEN_REASON as Mn, shouldRetainResource as Mo, cfnRefValueFromPhysicalId as Mr, warnDeprecatedNoPrefixCliFlag as Ms, getCurrentProducerRegions as Mt, INDEX_SETTLE_POLL_INTERVAL_MS as N, inheritNestedStackParameterAssociations as Na, refuseMalformedResourcePropertiesForDestroy as Ni, ProviderRegistry as Nn, AssetPublisher as No, isStalePlaceholderArnAttribute as Nr, ssmResolvedValueType as Ns, inheritProducerRegions as Nt, compensateRemovedDeletionProtection as O, lambdaFunctionNameForMask as Oa, refuseMalformedResourceEntriesForDeploy as Oi, tagMapAsList as On, importableOutputs as Oo, carriesFetchableDynamicReference as Or, resolveStateBucketWithDefault as Os, planFailedOps as Ot, deleteTableWithIndexBusyRetry as P, recordNestedStackParameterExpressions as Pa, refuseMalformedResourcePropertiesForDrift as Pi, ccBrokenReason as Pn, isSensitiveAttributeName as Po, refStateLookupFromResource as Pr, CFN_TEMPLATE_BODY_LIMIT as Ps, ATOMIC_FINAL_SNAPSHOT_TYPES as Pt, reachableDivergentParameters as Q, DYNAMIC_REFERENCE_TOKEN_SCAN as Qa, unwrittenCreateOnlyReplacement as Qi, reDisableInstanceApiTermination as Qn, buildDockerImage as Qo, malformedExportNamesWarning as Qr, ownValue as Qs, WITHHELD_NAME_DISPLAY as Qt, hasCdkAutoDeleteTag as R, literalSplitDelimitersOf as Ra, refuseMalformedResourcesForDestroy as Ri, CloudControlProvider as Rn, createAssetRedirectResolver as Ro, passedParameterClassesOf as Rr, uploadCfnTemplate as Rs, createPreDeleteFinalSnapshot as Rt, isProtectionValueActive as S, requireConfigString as Sa, refuseMalformedOrphansForDestroy as Si, acquireIdempotencyToken as Sn, describeRegionValueKind as So, coerceParameterTypedValue as Sr, getLegacyStateBucketName as Ss, destroyStackRecordsView as St, DynamoDBGlobalTableProvider as T, describeTypeWithThrottleRetry as Ta, refuseMalformedOutputsForDestroy as Ti, planTagDiff as Tn, hasReasonlessBaselineRefusal as To, getAccountInfo as Tr, resolveAutoAssetStorage as Ts, recordAfterRollbackUpdate as Tt, createReadOnlyAttributeHealerFactory as U, shareLogOnlyValues as Ua, repairMalformedOutputsForReadOnly as Ui, deleteIndeterminateGuards as Un, assertAssetBucketRegion as Uo, UNREADABLE_RESOURCES_MAP_ROW as Ur, canonicalizeRegion as Us, REDACTED_DELETE_ADDRESS_SKIP_REASON as Ut, markRefusedBeforeApplying as V, recordLogOnlyParameterValue as Va, repairMalformedOrphanRecordsForReadOnly as Vi, unchangedBehindSecretReference as Vn, AssetModeResolver as Vo, STATE_RESOURCES_MALFORMED as Vr, expectedOwnerParam as Vs, refusesFinalSnapshot as Vt, bold as W, createSecretMasker as Wa, repairMalformedResourceEntriesForReadOnly as Wi, deleteSkipReason as Wn, ensureAssetStorage as Wo, deployRefusesOrphanRowsReason as Wr, derivePartitionAndUrlSuffix as Ws, isRedactedRecordedValue as Wt, computeParameterTaint as X, scrubResourceRecord as Xa, findActionableSilentDrops as Xi, isTerminationProtectionPropagationError as Xn, validateContainerRepoName as Xo, isReadableResourceEntry as Xr, hasPlainPrototype$1 as Xs, DeploymentEventsStore as Xt, yellow as Y, redactSecretsForState as Ya, unreadableResourceEntries as Yi, ec2InstanceProtectionSite as Yn, validateAssetBucketName as Yo, isReadableOrphanRecord as Yr, hasOwnKey as Ys, DeploymentEventsReader as Yt, namesAnyDeclaredParameter as Z, recoverMaskedOutput as Za, findSilentDropProperties as Zi, observeThenDisableInstanceApiTermination as Zn, buildDenyExternalAccessPolicy as Zo, malformedDriftResourcePropertiesWarning as Zr, nullPrototypeRecord as Zs, extractDeploymentEventError as Zt, makeCanonicalizePropertiesFn as _, configStringRefusal as _a, refuseDivergentRecordRegionForDestroy as _i, RollbackInlinePolicyWriters as _n, isLockInfoExpired as _o, s3BucketArn as _r, AssetManifestLoader as _s, getCurrentNestedStackContext as _t, findNestedTemplateTreeDefect as a, isStatefulRecreateTargetForReplace as aa, resolveBucketRegion as ac, malformedOrphanRowsKeptWarning as ai, isWholeDynamicReferenceValue as an, recordMaskOnlyValue as ao, regionLessSecretName as ar, formatDockerLoginError as as, makeSiblingClaimReader as at, recordedProtectionNote as b, requireConfigArray as ba, refuseMalformedOrphanRecordsForDestroy as bi, reserveStackCreateToken as bn, splitImportedOps as bo, s3BucketRegionalDomainName as br, synthesisStatusMessage as bs, replayRollback as bt, renderNestedTemplateTreeDefect as c, WARM_THROUGHPUT_MEMBERS as ca, malformedOutputsRefusalMessage as ci, collectPublishedOutputNames as cn, recordProvenPublicExpression as co, assertSendableRoleArn as cr, isMalformedEnvKey as cs, displacedOpClause as ct, conditionInputsFrom as d, toCfnInteger as da, malformedResourceEntriesWarning as di, DEFAULT_RESOURCE_TIMEOUT_MS as dn, STATE_SOURCED_CROSS_GENERATION_RULES as do, sendableAssumeRoleCommand as dr, redactedDockerCause as ds, getNestedRevertRun as dt, NO_CC_HANDLERS_REASON as ea, describeFileReadFailure as ec, malformedLocalOutputsWarning as ei, exportAliasCollisionScrubWarning as en, isUncertifiedBaselineMaskPosition as eo, DiffCalculator as er, describeDockerCapturedOutput as es, deleteJournaledOrphans as et, parentSuppliedValues as f, toFiniteNumber as fa, malformedResourcePropertiesWarning as fi, DEFAULT_RESOURCE_WARN_AFTER_MS as fn, STATE_SOURCED_READBACK_RULES as fo, AWS_CREDENTIAL_ENV_KEYS as fr, runDockerForeground as fs, nestedChildStackName as ft, mergeNoChangeOutputs as g, configIntegerRefusal as ga, previewableOrphanRecords as gi, formatDestructiveChange as gn, LockManager as go, isSettledInstanceState as gr, stripControlChars as gs, withNestedRevertRun as gt, keptWholeReasonText as h, configBooleanRefusal as ha, malformedStateRefusalMessage as hi, findDestructiveChanges as hn, isSingleDynamicReferenceToken as ho, envCredentialsAreAssumedRole as hr, escapeRegExp$3 as hs, revertedNestedRowIds as ht, childTemplateLoader as i, MULTI_REGION_RECREATE_BLOCKED_TYPES as ia, clearBucketRegionCache as ic, malformedOrphanRecordsWarning as ii, exportNameSecretExposure as in, provenPublicValue as io, producerRegionsFromState as ir, finchSecretArgvRefusal as is, sameJournaledOrphans as it, resolveDynamoDbDeleteBudgetMs as j, TemplateParser as ja, refuseMalformedResourceEntriesForImportSave as ji, stringifyIfAssigned as jn, orphansCarriedFrom as jo, AWS_NO_VALUE as jr, stateBucketExistenceConfirmed as js, findNestedStackTypeChanges as jt, deleteBudgetKey as k, sameLambdaFunctionAddress as ka, refuseMalformedResourceEntriesForDestroy as ki, tagPlanWarning as kn, isReadableBag as ko, isNamelessDynamicReferenceError as kr, resolveStateBucketWithDefaultAndSource as ks, planRollback as kt, templateIdentity as l, coerceWarmThroughput as la, malformedOutputsWarning as li, isExportAliasCollision as ln, wholeStringLeavesOf as lo, explicitRoleArnOrThrow as lr, partitionSensitiveEnv as ls, displacedPhysicalIdShown as lt, isSecretBearingReferenceString as m, coerceCfnInteger as ma, malformedScrubResourceEntriesRefusalMessage as mi, constructPathOf as mn, WHOLE_DYNAMIC_REFERENCE_PATTERN as mo, callerEnvCredentials as mr, warnFinchArgvExposure as ms, revertNestedChildFromJournal as mt, IMPLICIT_DELETE_DEPENDENCIES as n, findReplacedReadersOfRecreateTargets as na, renderAssemblyPathEscape as nc, malformedLocalResourcesWarning as ni, secretBearingStateKeyWarning as nn, identityKeyFor as no, IntrinsicFunctionResolver as nr, describeDockerFailure as ns, journaledOrphanLines as nt, isAbsoluteAssetPath as o, isStatefulRecreateTargetSync as oa, malformedOrphansRefusalMessage as oi, noEchoParameterValueSeed as on, recordMaskOnlyValuesIn as oo, applyRoleArnIfSet as or, getDockerCmd as os, planOrphanAdoption as ot, readRecordedConditionVerdicts as p, coerceCfnBoolean as pa, malformedResourcesWarning as pi, maskingRetryLogger as pn, TEMPLATE_SOURCED_RULES as po, applyCallerIdentityCredentials as pr, runDockerStreaming as ps, recordDisplacedSkips as pt, green as q, maskSecretsInText as qa, unpreviewableOrphanRecords as qi, markWaitAbandoned as qn, parseBootstrapMarker as qo, hasReadableOutputs as qr, processStackMessages as qs, updatePartialMessage as qt, computeImplicitDeleteEdges as r, shownType as ra, resolveAssemblyPath as rc, malformedOrphanRecordsRefusalMessage as ri, secretSafeKeyDisplay as rn, carriesSecretMask as ro, classifyReplaySecretRegion as rr, dockerSpawnEnvWithSensitive as rs, loadJournaledOrphans as rt, listNestedTemplateRows as s, renderStatefulReason as sa, malformedOrphansWarning as si, collectDeclaredOutputNames as sn, recordNoEchoAttributeValues as so, assertFlagRoleArn as sr, isDockerClientEnvKey as ss, NESTED_PENDING_PARENT_REASON as st, DeployEngine as t, hasNoCloudControlHandlers as ta, displayAssemblyPath as tc, malformedLocalResourceEntriesWarning as ti, secretBearing as tn, pathCrossesDottedKey as to, INTRINSIC_KEYS as tr, describeDockerExecFailure as ts, isHandledOrphan as tt, conditionFingerprint as u, isWarmThroughputDecrease as ua, malformedRenderedContainersWarning as ui, bindingSkippedOutputs as un, STATE_SOURCED_BASELINE_RULES as uo, isIamRoleArn as ur, redactDockerArgvValues as us, dropSettledNestedJournals as ut, withResourceDeadline as v, readConfigString as va, refuseMalformedNestedChildOutputs as vi, earliestDefined as vn, S3StateBackend as vo, s3BucketDomainName as vr, getDockerImageBySourceHash as vs, withNestedStackContext as vt, readProtection as w, templateResourceTypes as wa, refuseMalformedOutputs as wi, DBPROXY_TAG_OPTIONS as wn, hasReadableExportSet as wo, parameterTypeMayLoseSecretIdentity as wr, resolveApp as ws, withStackRecords as wt, PROTECTION_PROPERTY_BY_TYPE as x, requireConfigObject as xa, refuseMalformedOrphans as xi, withCreateTokenLedger as xn, acceptedCreateOnlyDropsOf as xo, s3BucketWebsiteUrl as xr, getDefaultStateBucketName as xs, awaitInFlightSibling as xt, recordedProtectionEvidence as y, replayWarn as ya, refuseMalformedOrphanRecords as yi, ledgerForStack as yn, rebuildClientForBucketRegion as yo, s3BucketDualStackDomainName as yr, Synthesizer as ys, replayFailedOperations as yt, isTruthyCfnBoolean as z, logOnlyValueCount as za, refuseMalformedResourcesForExport as zi, slowCcOperationTimeoutMs as zn, loadPublishableAssetManifest as zo, JSON_LISTING_HOLE_VALUE as zr, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as zs, effectiveDeletionPolicy as zt };
37610
+ //# sourceMappingURL=deploy-engine-xlct0Hcm.js.map