@go-to-k/cdkd 0.294.11 → 0.294.13

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.
@@ -2,7 +2,7 @@ import { r as getAwsClients, s as __exportAll } from "./aws-clients-CnmtbrxD.js"
2
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
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";
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-DIQcU8CA.js";
5
+ import { t as getCdkdVersion } from "./version-CKLiAWMw.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";
@@ -1675,21 +1675,56 @@ function recordFailure(failed, key, reason) {
1675
1675
  else failed.set(key, [reason]);
1676
1676
  }
1677
1677
  const describe$1 = (error) => error instanceof Error ? error.message : String(error);
1678
+ const PREFIX_HANDLE_SUFFIX = "* (every key under this prefix)";
1679
+ async function purgeNoncurrentVersionsUnderPrefix(s3Client, bucket, prefix, options = {}) {
1680
+ const logger = options.logger ?? getLogger().child("s3-version-purge");
1681
+ if (!prefix.endsWith("/") || prefix.replace(/\/+/g, "") === "") {
1682
+ logger.warn(safeMsg`Refused to purge noncurrent versions under ${JSON.stringify(prefix)}: ` + `a prefix-wide purge needs a non-empty prefix ending in '/'. Nothing was purged.`);
1683
+ return {
1684
+ deletedBodies: 0,
1685
+ complete: false
1686
+ };
1687
+ }
1688
+ const handle = `${prefix}${PREFIX_HANDLE_SUFFIX}`;
1689
+ return purgeWalk(s3Client, bucket, [prefix], {
1690
+ scope: {
1691
+ covers: (key) => key.startsWith(prefix),
1692
+ unsettledUnder: () => [handle],
1693
+ ownsEveryListedKey: true
1694
+ },
1695
+ listingFailureHandles: () => [handle],
1696
+ options: {
1697
+ ...options,
1698
+ logger
1699
+ }
1700
+ });
1701
+ }
1678
1702
  async function purgeNoncurrentKeyVersions(s3Client, bucket, keys, options = {}) {
1679
1703
  if (keys.length === 0) return;
1704
+ const wanted = new Set(keys);
1705
+ await purgeWalk(s3Client, bucket, options.listPrefix !== void 0 ? [options.listPrefix] : keys, {
1706
+ scope: {
1707
+ covers: (key) => wanted.has(key),
1708
+ unsettledUnder: (prefix) => [...wanted].filter((key) => key.startsWith(prefix)),
1709
+ ownsEveryListedKey: false
1710
+ },
1711
+ listingFailureHandles: (prefix) => options.listPrefix !== void 0 ? [...keys] : [prefix],
1712
+ options
1713
+ });
1714
+ }
1715
+ async function purgeWalk(s3Client, bucket, prefixes, params) {
1716
+ const { scope, listingFailureHandles, options } = params;
1680
1717
  const logger = options.logger ?? getLogger().child("s3-version-purge");
1681
1718
  const requestFields = options.requestFields ?? {};
1682
- const wanted = new Set(keys);
1683
- const prefixes = options.listPrefix !== void 0 ? [options.listPrefix] : keys;
1684
1719
  const failed = /* @__PURE__ */ new Map();
1685
1720
  const unknown = { n: 0 };
1686
1721
  const purged = /* @__PURE__ */ new Set();
1687
1722
  const unsettledBodies = /* @__PURE__ */ new Set();
1723
+ const removed = { n: 0 };
1688
1724
  for (const prefix of prefixes) try {
1689
- await purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields, failed, unknown, purged, unsettledBodies);
1725
+ await purgeUnderPrefix(s3Client, bucket, prefix, scope, requestFields, failed, unknown, purged, unsettledBodies, removed);
1690
1726
  } catch (error) {
1691
- const affected = options.listPrefix !== void 0 ? keys : [prefix];
1692
- for (const key of affected) {
1727
+ for (const key of listingFailureHandles(prefix)) {
1693
1728
  recordFailure(failed, key, describe$1(error));
1694
1729
  unsettledBodies.add(key);
1695
1730
  }
@@ -1697,7 +1732,10 @@ async function purgeNoncurrentKeyVersions(s3Client, bucket, keys, options = {})
1697
1732
  if (failed.size > 0) {
1698
1733
  const named = [...failed.entries()].slice(0, MAX_NAMED_FAILURES).map(([key, reasons]) => displaySafe(`${key} (${reasons.join("; ")})`));
1699
1734
  const elided = failed.size - named.length;
1700
- logger.warn(`Could not purge noncurrent versions of ${failed.size} key(s) in s3://${displaySafe(bucket, { asciiOnly: true })}. Their previous versions survive and remain readable via GetObject with a VersionId (${options.objectDescription ?? "the body of an object cdkd has just reported as removed"}). Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key(s) by hand. Failures: ${named.join(", ")}` + (elided > 0 ? ` (and ${elided} more)` : ""));
1735
+ const prefixCount = [...failed.keys()].filter((k) => k.endsWith(PREFIX_HANDLE_SUFFIX)).length;
1736
+ const keyCount = failed.size - prefixCount;
1737
+ const subject = [keyCount > 0 ? `${keyCount} key(s)` : "", prefixCount > 0 ? `every key under ${prefixCount} prefix(es)` : ""].filter((part) => part !== "").join(" and ");
1738
+ logger.warn(`Could not purge noncurrent versions of ${subject} in s3://${displaySafe(bucket, { asciiOnly: true })}. Their previous versions survive and remain readable via GetObject with a VersionId (${options.objectDescription ?? "the body of an object cdkd has just reported as removed"}). Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key(s) by hand. Failures: ${named.join(", ")}` + (elided > 0 ? ` (and ${elided} more)` : ""));
1701
1739
  }
1702
1740
  const replicationKeys = [.../* @__PURE__ */ new Set([...purged, ...unsettledBodies])];
1703
1741
  await warnIfPurgeIsReplicated(s3Client, bucket, replicationKeys, {
@@ -1705,8 +1743,12 @@ async function purgeNoncurrentKeyVersions(s3Client, bucket, keys, options = {})
1705
1743
  logger,
1706
1744
  ...options.objectDescription !== void 0 && { objectDescription: options.objectDescription }
1707
1745
  });
1746
+ return {
1747
+ deletedBodies: removed.n,
1748
+ complete: failed.size === 0
1749
+ };
1708
1750
  }
1709
- async function purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields, failed, unknown, purged, unsettledBodies) {
1751
+ async function purgeUnderPrefix(s3Client, bucket, prefix, scope, requestFields, failed, unknown, purged, unsettledBodies, removed) {
1710
1752
  let keyMarker;
1711
1753
  let versionIdMarker;
1712
1754
  do {
@@ -1719,6 +1761,8 @@ async function purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields,
1719
1761
  ...versionIdMarker !== void 0 && { VersionIdMarker: versionIdMarker }
1720
1762
  }));
1721
1763
  const stale = [];
1764
+ const staleBodies = /* @__PURE__ */ new Map();
1765
+ const isStaleBody = (key, versionId) => key !== void 0 && versionId !== void 0 && staleBodies.get(key)?.has(versionId) === true;
1722
1766
  const entries = [...(resp.Versions ?? []).map((entry) => ({
1723
1767
  entry,
1724
1768
  hasBody: true
@@ -1732,9 +1776,10 @@ async function purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields,
1732
1776
  decodedKey = decodeListingKey(entry.Key);
1733
1777
  } catch {
1734
1778
  if (hasBody && entry.Key !== void 0) unsettledBodies.add(`${entry.Key} [key not decodable; shown as S3 returned it]`);
1779
+ if (scope.ownsEveryListedKey && entry.Key !== void 0 && entry.IsLatest !== true) recordFailure(failed, `${entry.Key} [key not decodable; shown as S3 returned it]`, `version ${entry.VersionId ?? "<unknown>"}: listing key could not be decoded, so the entry was left alone`);
1735
1780
  continue;
1736
1781
  }
1737
- if (decodedKey === void 0 || !wanted.has(decodedKey)) continue;
1782
+ if (decodedKey === void 0 || !scope.covers(decodedKey)) continue;
1738
1783
  if (entry.IsLatest === void 0) {
1739
1784
  recordFailure(failed, decodedKey, `version ${entry.VersionId ?? "<unknown>"}: listing omitted IsLatest, so the entry was left alone rather than risk deleting a current version`);
1740
1785
  if (hasBody) unsettledBodies.add(decodedKey);
@@ -1749,6 +1794,11 @@ async function purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields,
1749
1794
  Key: decodedKey,
1750
1795
  VersionId: entry.VersionId
1751
1796
  });
1797
+ if (hasBody) {
1798
+ const ids = staleBodies.get(decodedKey) ?? /* @__PURE__ */ new Set();
1799
+ ids.add(entry.VersionId);
1800
+ staleBodies.set(decodedKey, ids);
1801
+ }
1752
1802
  if (hasBody) purged.add(decodedKey);
1753
1803
  }
1754
1804
  for (let i = 0; i < stale.length; i += DELETE_BATCH_SIZE) {
@@ -1762,6 +1812,9 @@ async function purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields,
1762
1812
  Quiet: true
1763
1813
  }
1764
1814
  }));
1815
+ let bodiesRemoved = batch.filter((o) => isStaleBody(o.Key, o.VersionId)).length;
1816
+ for (const err of deleted.Errors ?? []) if (err.Key === void 0 || err.VersionId === void 0 || isStaleBody(err.Key, err.VersionId)) bodiesRemoved -= 1;
1817
+ removed.n += Math.max(0, bodiesRemoved);
1765
1818
  for (const err of deleted.Errors ?? []) {
1766
1819
  if (err.Code === "NoSuchVersion") continue;
1767
1820
  const reason = `version ${err.VersionId ?? "<unknown>"}: ${err.Code ?? "Error"}` + (err.Message ? ` - ${err.Message}` : "");
@@ -1775,11 +1828,9 @@ async function purgeUnderPrefix(s3Client, bucket, prefix, wanted, requestFields,
1775
1828
  for (const object of batch) recordFailure(failed, object.Key, describe$1(error));
1776
1829
  }
1777
1830
  }
1778
- if (resp.IsTruncated === true && resp.NextKeyMarker === void 0) {
1779
- for (const key of wanted) if (key.startsWith(prefix)) {
1780
- recordFailure(failed, key, TRUNCATED_NO_MARKER);
1781
- unsettledBodies.add(key);
1782
- }
1831
+ if (resp.IsTruncated === true && resp.NextKeyMarker === void 0) for (const key of scope.unsettledUnder(prefix)) {
1832
+ recordFailure(failed, key, TRUNCATED_NO_MARKER);
1833
+ unsettledBodies.add(key);
1783
1834
  }
1784
1835
  keyMarker = resp.IsTruncated === true ? decodeListingKey(resp.NextKeyMarker) : void 0;
1785
1836
  versionIdMarker = keyMarker !== void 0 ? resp.NextVersionIdMarker : void 0;
@@ -5322,6 +5373,24 @@ var S3StateBackend = class {
5322
5373
  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)}`);
5323
5374
  }
5324
5375
  }
5376
+ async purgeNoncurrentVersionsUnderPrefix(keyPrefix, options = {}) {
5377
+ try {
5378
+ await this.ensureClientForBucket();
5379
+ return await purgeNoncurrentVersionsUnderPrefix(this.s3Client, this.config.bucket, keyPrefix, {
5380
+ ...options,
5381
+ requestFields: await this.ownerParam(),
5382
+ logger: this.logger
5383
+ });
5384
+ } catch (error) {
5385
+ const prefixShown = displayIdent(keyPrefix, { maxCodePoints: STACK_REF_MAX_CODE_POINTS });
5386
+ const describing = options.objectDescription ? ` (${options.objectDescription})` : "";
5387
+ 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)}`);
5388
+ return {
5389
+ deletedBodies: 0,
5390
+ complete: false
5391
+ };
5392
+ }
5393
+ }
5325
5394
  async loadCreateTokenLedger(stackName, region) {
5326
5395
  const body = await this.getRawObject(this.getCreateTokenLedgerKey(stackName, region));
5327
5396
  if (body === null) return null;
@@ -21828,7 +21897,7 @@ var CloudControlProvider = class {
21828
21897
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
21829
21898
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
21830
21899
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
21831
- const { ASGProvider } = await import("./asg-provider-CbHiTBaE.js");
21900
+ const { ASGProvider } = await import("./asg-provider-DYk4gHU2.js");
21832
21901
  const delegateRegion = ambientRegion();
21833
21902
  let asgProvider = this.asgDeleteDelegates.get(delegateRegion);
21834
21903
  if (asgProvider === void 0) {
@@ -21934,7 +22003,7 @@ var CloudControlProvider = class {
21934
22003
  const family = SDK_DELETE_FAMILIES.get(resourceType);
21935
22004
  const cached = this.sdkDeleteDelegates.get(family);
21936
22005
  if (cached !== void 0 && cached.region === ccRegion) return cached.provider;
21937
- const provider = family === "rds" ? new (await (import("./rds-provider-l9F4Y8YY.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-CS-r4Ufj.js"))).NeptuneProvider({ region: ccRegion });
22006
+ const provider = family === "rds" ? new (await (import("./rds-provider-BeG3nAP_.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-BtKWZD6O.js"))).NeptuneProvider({ region: ccRegion });
21938
22007
  this.sdkDeleteDelegates.set(family, {
21939
22008
  region: ccRegion,
21940
22009
  provider
@@ -26713,16 +26782,19 @@ function deploymentsDirPrefix(prefix, stackName, region) {
26713
26782
  return `${prefix}/${stackName}/${region}/deployments/`;
26714
26783
  }
26715
26784
  const DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION = "deployment-event streams and their index, whose recorded error messages can quote values the secret mask does not catch";
26716
- async function deleteAndPurgeEventObjects(backend, keys, dirPrefix) {
26717
- if (keys.length === 0) return;
26785
+ async function deleteAndPurgeEventObjects(backend, keys, dirPrefix, scope = "deleted-keys") {
26786
+ if (keys.length === 0) return void 0;
26787
+ let swept;
26718
26788
  try {
26719
26789
  await backend.deleteRawObjects(keys);
26720
26790
  } finally {
26721
- await backend.purgeNoncurrentVersions(keys, {
26791
+ if (scope === "whole-dir") swept = await backend.purgeNoncurrentVersionsUnderPrefix(dirPrefix, { objectDescription: DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION });
26792
+ else await backend.purgeNoncurrentVersions(keys, {
26722
26793
  ...keys.length > 1 && { listPrefix: dirPrefix },
26723
26794
  objectDescription: DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION
26724
26795
  });
26725
26796
  }
26797
+ return swept;
26726
26798
  }
26727
26799
  function runIdTimestampMs(runId) {
26728
26800
  const m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})Z/.exec(runId);
@@ -26960,11 +27032,12 @@ var DeploymentEventsReader = class {
26960
27032
  const indexExisted = keys.includes(indexKey);
26961
27033
  if (opts.all === true) {
26962
27034
  const toDelete = runIdsDesc.map((id) => deploymentEventsKey(this.backend.prefix, stackName, region, id));
26963
- await deleteAndPurgeEventObjects(this.backend, [...toDelete, indexKey], dirPrefix);
27035
+ const earlierVersions = await deleteAndPurgeEventObjects(this.backend, [...toDelete, indexKey], dirPrefix, "whole-dir");
26964
27036
  return {
26965
27037
  deletedRunIds: runIdsDesc,
26966
27038
  remainingRunIds: [],
26967
- indexDeleted: indexExisted
27039
+ indexDeleted: indexExisted,
27040
+ ...earlierVersions !== void 0 && { earlierVersions }
26968
27041
  };
26969
27042
  }
26970
27043
  const noGuards = opts.keep === void 0 && opts.olderThanMs === void 0;
@@ -27397,11 +27470,25 @@ const nonEmptyString = (v) => typeof v === "string" && v.length > 0;
27397
27470
 
27398
27471
  //#endregion
27399
27472
  //#region src/deployment/rollback-executor/messages.ts
27400
- function throwIfDeleteSkipped(result, logicalId, physicalId, duringClause) {
27473
+ function throwIfDeleteSkipped(result, logicalId, physicalId, duringClause, guardScope) {
27474
+ recordRollbackDeleteGuards(result, logicalId, physicalId, guardScope);
27401
27475
  const reason = deleteSkipReason(result);
27402
27476
  if (reason === void 0) return;
27403
27477
  throw new Error(deleteSkippedMessage(logicalId, physicalId, reason, duringClause));
27404
27478
  }
27479
+ function recordRollbackDeleteGuards(result, logicalId, physicalId, scope) {
27480
+ for (const guard of deleteIndeterminateGuards(result)) scope.ctx.recordEvent?.({
27481
+ eventType: "RESOURCE_GUARD_INDETERMINATE",
27482
+ stackName: scope.stackName,
27483
+ operation: "DELETE",
27484
+ logicalId,
27485
+ resourceType: scope.resourceType,
27486
+ ...scope.provisionedBy && { provisionedBy: scope.provisionedBy },
27487
+ ...physicalId && { physicalId: scope.mask(physicalId) },
27488
+ guard: guard.guard,
27489
+ reason: scope.mask(guard.reason)
27490
+ });
27491
+ }
27405
27492
  const SKIP_FINAL_SNAPSHOT_FLAG = "--skip-final-snapshot";
27406
27493
  const REPLAYING_STATE_CREATE_CONTEXT = { replayingState: true };
27407
27494
  function replayingStateCreateContext(secrets) {
@@ -28286,7 +28373,7 @@ async function replayDelete(s) {
28286
28373
  let finalSnapshotIdentifier;
28287
28374
  if (takeFinalSnapshot) finalSnapshotIdentifier = await prepareCreateRollbackFinalSnapshot(op, deleteProvisionedBy, ctx, mask);
28288
28375
  logger.info(` Rollback: Deleting created resource ${safe(op.logicalId)} (${safe(op.resourceType)})` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
28289
- const { provider } = ctx.providerRegistry.getProviderFor({
28376
+ const { provider, provisionedBy: deleteRoutedVia } = ctx.providerRegistry.getProviderFor({
28290
28377
  resourceType: op.resourceType,
28291
28378
  provisionedBy: deleteProvisionedBy
28292
28379
  });
@@ -28299,7 +28386,13 @@ async function replayDelete(s) {
28299
28386
  deletionPolicy: snapshotPolicy ? "Snapshot" : "Delete",
28300
28387
  recordedAttributes: stateResources[op.logicalId]?.attributes
28301
28388
  });
28302
- throwIfDeleteSkipped(createRollbackDelete, op.logicalId, op.physicalId, "while rolling back its CREATE");
28389
+ throwIfDeleteSkipped(createRollbackDelete, op.logicalId, op.physicalId, "while rolling back its CREATE", {
28390
+ ctx,
28391
+ stackName,
28392
+ resourceType: op.resourceType,
28393
+ provisionedBy: deleteRoutedVia,
28394
+ mask
28395
+ });
28303
28396
  delete stateResources[op.logicalId];
28304
28397
  logger.info(` Rollback: ${safe(op.logicalId)} deleted successfully`);
28305
28398
  await afterOp?.(op.logicalId);
@@ -28327,7 +28420,7 @@ async function replayReadopt(s) {
28327
28420
  survivorReason = survivorMessages.reason;
28328
28421
  result.warnings++;
28329
28422
  } else {
28330
- const { provider: newDeleteProvider } = ctx.providerRegistry.getProviderFor({
28423
+ const { provider: newDeleteProvider, provisionedBy: newDeleteVia } = ctx.providerRegistry.getProviderFor({
28331
28424
  resourceType: op.resourceType,
28332
28425
  provisionedBy: current.provisionedBy ?? op.provisionedBy
28333
28426
  });
@@ -28340,7 +28433,13 @@ async function replayReadopt(s) {
28340
28433
  deletionPolicy: replacementDeletePolicy(current.updateReplacePolicy),
28341
28434
  recordedAttributes: current.attributes
28342
28435
  });
28343
- throwIfDeleteSkipped(readoptDelete, op.logicalId, current.physicalId, "while reversing its replacement (re-adopting the retained old resource)");
28436
+ throwIfDeleteSkipped(readoptDelete, op.logicalId, current.physicalId, "while reversing its replacement (re-adopting the retained old resource)", {
28437
+ ctx,
28438
+ stackName,
28439
+ resourceType: op.resourceType,
28440
+ provisionedBy: newDeleteVia,
28441
+ mask
28442
+ });
28344
28443
  }
28345
28444
  stateResources[op.logicalId] = prev;
28346
28445
  logger.info(` Rollback: ${safe(op.logicalId)} restored to the retained old resource`);
@@ -28485,10 +28584,17 @@ async function replayReverseReplacement(s) {
28485
28584
  physicalId: prev.physicalId,
28486
28585
  via: createProvisionedBy
28487
28586
  }, logger, mask, true);
28488
- const resolveNewDeleteProvider = () => ctx.providerRegistry.getProviderFor({
28587
+ const resolveNewDeleteRoute = () => ctx.providerRegistry.getProviderFor({
28489
28588
  resourceType: op.resourceType,
28490
28589
  provisionedBy: current.provisionedBy ?? op.provisionedBy
28491
- }).provider;
28590
+ });
28591
+ const newDeleteGuardScope = (provisionedBy) => ({
28592
+ ctx,
28593
+ stackName,
28594
+ resourceType: op.resourceType,
28595
+ provisionedBy,
28596
+ mask
28597
+ });
28492
28598
  const newCopyClaimed = inlinePolicyWriters.claimedFor(op.resourceType, op.logicalId, stateResources);
28493
28599
  let deletedNewFirst = false;
28494
28600
  let createResult;
@@ -28526,13 +28632,14 @@ async function replayReverseReplacement(s) {
28526
28632
  logger.info(` Rollback: re-create collided with the new resource's name — deleting the new resource (${displaySafe(mask(current.physicalId))}) first...` + (typeChanged ? ` (this op changed the resource's Type, ${safe(op.resourceType)} -> ${safe(oldType)}, which share a name space)` : ""));
28527
28633
  {
28528
28634
  const finalSnapshotIdentifier = rollbackFinalSnapshotId(op.resourceType, current, op.provisionedBy);
28529
- const deleteNewFirst = await resolveNewDeleteProvider().delete(op.logicalId, current.physicalId, op.resourceType, current.properties, {
28635
+ const deleteNewFirstRoute = resolveNewDeleteRoute();
28636
+ const deleteNewFirst = await deleteNewFirstRoute.provider.delete(op.logicalId, current.physicalId, op.resourceType, current.properties, {
28530
28637
  expectedRegion: ctx.region,
28531
28638
  ...finalSnapshotIdentifier !== void 0 && { finalSnapshotIdentifier },
28532
28639
  deletionPolicy: replacementDeletePolicy(current.updateReplacePolicy),
28533
28640
  recordedAttributes: current.attributes
28534
28641
  });
28535
- throwIfDeleteSkipped(deleteNewFirst, op.logicalId, current.physicalId, "while clearing the new resource so the old one could be re-created");
28642
+ throwIfDeleteSkipped(deleteNewFirst, op.logicalId, current.physicalId, "while clearing the new resource so the old one could be re-created", newDeleteGuardScope(deleteNewFirstRoute.provisionedBy));
28536
28643
  }
28537
28644
  deletedNewFirst = true;
28538
28645
  delete stateResources[op.logicalId];
@@ -28591,14 +28698,15 @@ async function replayReverseReplacement(s) {
28591
28698
  await noteRetainedResource(op.resourceType, op.logicalId);
28592
28699
  } else if (!deletedNewFirst && !adoptedLiveNewResource) try {
28593
28700
  const finalSnapshotIdentifier = rollbackFinalSnapshotId(op.resourceType, current, op.provisionedBy);
28594
- const deleteNewAfterRecreate = await resolveNewDeleteProvider().delete(op.logicalId, current.physicalId, op.resourceType, current.properties, {
28701
+ const deleteNewAfterRecreateRoute = resolveNewDeleteRoute();
28702
+ const deleteNewAfterRecreate = await deleteNewAfterRecreateRoute.provider.delete(op.logicalId, current.physicalId, op.resourceType, current.properties, {
28595
28703
  expectedRegion: ctx.region,
28596
28704
  ...newCopyClaimed && { inlinePolicyClaimed: newCopyClaimed },
28597
28705
  ...finalSnapshotIdentifier !== void 0 && { finalSnapshotIdentifier },
28598
28706
  deletionPolicy: replacementDeletePolicy(current.updateReplacePolicy),
28599
28707
  recordedAttributes: current.attributes
28600
28708
  });
28601
- throwIfDeleteSkipped(deleteNewAfterRecreate, op.logicalId, current.physicalId, "while deleting the new resource after re-creating the old one");
28709
+ throwIfDeleteSkipped(deleteNewAfterRecreate, op.logicalId, current.physicalId, "while deleting the new resource after re-creating the old one", newDeleteGuardScope(deleteNewAfterRecreateRoute.provisionedBy));
28602
28710
  } catch (deleteError) {
28603
28711
  logger.warn(mask(` Rollback: old ${safe(op.logicalId)} re-created, but deleting the new resource (${displaySafe(mask(current.physicalId))}) failed: ${displaySafe(deleteError instanceof Error ? deleteError.message : String(deleteError))}. Delete it manually — it is no longer tracked in state.`));
28604
28712
  survivorReason = `The replacement's new ${op.resourceType} (${current.physicalId}) could not be deleted after the old resource was re-created: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}. It is live, still billing, and no longer tracked by cdkd — delete it yourself.`;
@@ -28891,7 +28999,7 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
28891
28999
  let finalSnapshotIdentifier;
28892
29000
  if (takeFinalSnapshot) finalSnapshotIdentifier = await prepareCreateRollbackFinalSnapshot(op, deleteProvisionedBy, ctx, mask);
28893
29001
  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)" : ""));
28894
- const { provider } = ctx.providerRegistry.getProviderFor({
29002
+ const { provider, provisionedBy: deleteRoutedVia } = ctx.providerRegistry.getProviderFor({
28895
29003
  resourceType: op.resourceType,
28896
29004
  provisionedBy: deleteProvisionedBy
28897
29005
  });
@@ -28904,7 +29012,13 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
28904
29012
  deletionPolicy: snapshotPolicy ? "Snapshot" : "Delete",
28905
29013
  recordedAttributes: stateResources[op.logicalId]?.attributes
28906
29014
  });
28907
- throwIfDeleteSkipped(failedCreateDelete, op.logicalId, op.physicalId, "while deleting the partially-created resource (--revert-failed)");
29015
+ throwIfDeleteSkipped(failedCreateDelete, op.logicalId, op.physicalId, "while deleting the partially-created resource (--revert-failed)", {
29016
+ ctx,
29017
+ stackName,
29018
+ resourceType: op.resourceType,
29019
+ provisionedBy: deleteRoutedVia,
29020
+ mask
29021
+ });
28908
29022
  delete stateResources[op.logicalId];
28909
29023
  await options.afterOp?.(op.logicalId);
28910
29024
  ctx.recordEvent?.({
@@ -29024,22 +29138,22 @@ async function replayFailedOperations(...args) {
29024
29138
 
29025
29139
  //#endregion
29026
29140
  //#region src/provisioning/nested-stack-context.ts
29027
- const storage = new AsyncLocalStorage();
29141
+ const storage$1 = new AsyncLocalStorage();
29028
29142
  function withNestedStackContext(ctx, fn) {
29029
- return storage.run(ctx, fn);
29143
+ return storage$1.run(ctx, fn);
29030
29144
  }
29031
29145
  function getCurrentNestedStackContext() {
29032
- return storage.getStore();
29146
+ return storage$1.getStore();
29033
29147
  }
29034
29148
  async function collectNestedChildUnaddressed(fn) {
29035
- const ctx = storage.getStore();
29149
+ const ctx = storage$1.getStore();
29036
29150
  if (!ctx) return {
29037
29151
  value: await fn(),
29038
29152
  unaddressed: void 0
29039
29153
  };
29040
29154
  const slot = {};
29041
29155
  return {
29042
- value: await storage.run({
29156
+ value: await storage$1.run({
29043
29157
  ...ctx,
29044
29158
  childUnaddressed: slot
29045
29159
  }, fn),
@@ -30292,6 +30406,24 @@ const cyan = (s) => `${codes.cyan}${s}${codes.reset}`;
30292
30406
  const gray = (s) => `${codes.gray}${s}${codes.reset}`;
30293
30407
  const bold = (s) => `${codes.bright}${s}${codes.reset}`;
30294
30408
 
30409
+ //#endregion
30410
+ //#region src/deployment/delete-guard-scope.ts
30411
+ const storage = new AsyncLocalStorage();
30412
+ function collectDeleteGuards(sink, fn) {
30413
+ return storage.run(sink, fn);
30414
+ }
30415
+ function reportDeleteGuards(result, target) {
30416
+ const sink = storage.getStore();
30417
+ if (!sink) return;
30418
+ for (const guard of deleteIndeterminateGuards(result)) sink.push({
30419
+ guard: guard.guard,
30420
+ reason: guard.reason,
30421
+ physicalId: target.physicalId,
30422
+ resourceType: target.resourceType,
30423
+ ...target.provisionedBy && { provisionedBy: target.provisionedBy }
30424
+ });
30425
+ }
30426
+
30295
30427
  //#endregion
30296
30428
  //#region src/deployment/deploy-engine/replacement.ts
30297
30429
  function replacementDeleteContext(updateReplacePolicy) {
@@ -30310,7 +30442,7 @@ async function prepareFinalSnapshotForDelete(logicalId, resourceType, currentRes
30310
30442
  }
30311
30443
  throw unsupportedFinalSnapshotError(logicalId, resourceType, "--skip-final-snapshot");
30312
30444
  }
30313
- async function replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, secrets, updateReplacePolicy) {
30445
+ async function replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, secrets, updateReplacePolicy, oldDeleteProvisionedBy) {
30314
30446
  const createContext = { maskSecrets: createSecretMasker(secrets) };
30315
30447
  const finalSnapshotIdentifier = await this.prepareFinalSnapshotForDelete(logicalId, oldResourceType, currentResource, updateReplacePolicy);
30316
30448
  let deleteResult;
@@ -30325,6 +30457,11 @@ async function replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourc
30325
30457
  } catch (deleteError) {
30326
30458
  throw new Error(maskSecretsInText(`Failed to delete old resource ${logicalId} (${currentResource.physicalId}) during the --replace delete-first fallback: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`, secrets));
30327
30459
  }
30460
+ reportDeleteGuards(deleteResult, {
30461
+ physicalId: currentResource.physicalId,
30462
+ resourceType: oldResourceType,
30463
+ provisionedBy: oldDeleteProvisionedBy
30464
+ });
30328
30465
  const replaceSkipReason = deleteSkipReason(deleteResult);
30329
30466
  if (replaceSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, replaceSkipReason, "during the --replace delete-first fallback"));
30330
30467
  this.logger.info(` ${green("✓")} Old resource deleted`);
@@ -30429,10 +30566,10 @@ async function createFirstThenDeleteOld(input) {
30429
30566
  if (input.equalIdIsSameResource && createResult.physicalId === currentResource.physicalId) throw markNonRetryable(new CdkdError(maskName(`${displaySafe(logicalId)} (${displaySafe(resourceType)}) requires replacement (${input.trigger}) under a new name, but the create returned the resource being replaced (${displaySafe(currentResource.physicalId)}) instead of a new one, so cdkd cannot tell which name it holds. Nothing was deleted. Delete that resource by hand if it is yours, then re-run the deploy.`), "NAMED_REPLACEMENT_IDEMPOTENT_CREATE"));
30430
30567
  if (retainOld) return createResult;
30431
30568
  this.logger.info(safeMsg` Deleting old ${logicalId} (${currentResource.physicalId})...`);
30432
- await this.deleteReplacedAfterCreate(logicalId, input.oldResourceType, currentResource, input.deleteProvider, input.deleteProperties, finalSnapshotIdentifier, input.deletePolicy, secrets);
30569
+ await this.deleteReplacedAfterCreate(logicalId, input.oldResourceType, currentResource, input.deleteProvider, input.deleteProperties, finalSnapshotIdentifier, input.deletePolicy, secrets, input.deleteProvisionedBy);
30433
30570
  return createResult;
30434
30571
  }
30435
- async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, deleteProvider, deleteProperties, finalSnapshotIdentifier, updateReplacePolicy, secrets) {
30572
+ async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, deleteProvider, deleteProperties, finalSnapshotIdentifier, updateReplacePolicy, secrets, deleteProvisionedBy) {
30436
30573
  let deleteResult = void 0;
30437
30574
  let deleteFailed = false;
30438
30575
  try {
@@ -30448,6 +30585,11 @@ async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentReso
30448
30585
  deleteFailed = true;
30449
30586
  this.logger.warn(safeMsg` ⚠ Failed to delete old resource ${logicalId} (${currentResource.physicalId}): ${deleteMsg}`);
30450
30587
  }
30588
+ reportDeleteGuards(deleteResult, {
30589
+ physicalId: currentResource.physicalId,
30590
+ resourceType: oldResourceType,
30591
+ provisionedBy: deleteProvisionedBy
30592
+ });
30451
30593
  const skipReason = deleteSkipReason(deleteResult);
30452
30594
  if (skipReason !== void 0) this.logger.warn(` ⚠ ${deleteSkippedMessage(logicalId, currentResource.physicalId, skipReason, "while cleaning up the replaced resource", { commandFreeLine: true })}. Delete it manually — it is no longer tracked in state.`);
30453
30595
  else if (!deleteFailed) this.logger.info(` ${green("✓")} Old resource deleted`);
@@ -33842,10 +33984,11 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
33842
33984
  });
33843
33985
  const replaceProvider = replaceDecision.provider;
33844
33986
  const replaceProps = replaceDecision.provisionedBy === "cc-api" ? this.preparePropertiesForCcApi(resourceType, resolvedProps, logicalId) : resolvedProps;
33845
- const oldDeleteProvider = this.providerRegistry.getProviderFor({
33987
+ const oldDeleteRoute = this.providerRegistry.getProviderFor({
33846
33988
  resourceType: oldResourceType,
33847
33989
  provisionedBy: currentResource.provisionedBy
33848
- }).provider;
33990
+ });
33991
+ const oldDeleteProvider = oldDeleteRoute.provider;
33849
33992
  const equalIdIsSameResource = equalIdNamesSameResource({
33850
33993
  oldType: oldResourceType,
33851
33994
  newType: resourceType,
@@ -33884,6 +34027,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
33884
34027
  createProvider: replaceProvider,
33885
34028
  createProps: replaceProps,
33886
34029
  deleteProvider: oldDeleteProvider,
34030
+ deleteProvisionedBy: oldDeleteRoute.provisionedBy,
33887
34031
  deleteProperties: currentResource.properties,
33888
34032
  secrets: updateSecrets,
33889
34033
  change: nameChange,
@@ -33913,6 +34057,11 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
33913
34057
  } catch (deleteError) {
33914
34058
  throw new Error(`Failed to destroy old resource ${logicalId} (${currentResource.physicalId}) during ${recreateFlagName}: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`);
33915
34059
  }
34060
+ reportDeleteGuards(recreateDeleteResult, {
34061
+ physicalId: currentResource.physicalId,
34062
+ resourceType: oldResourceType,
34063
+ provisionedBy: oldDeleteRoute.provisionedBy
34064
+ });
33916
34065
  const recreateSkipReason = deleteSkipReason(recreateDeleteResult);
33917
34066
  if (recreateSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, recreateSkipReason, `during ${recreateFlagName}`));
33918
34067
  this.logger.info(` ${green("✓")} Old resource deleted`);
@@ -33968,7 +34117,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
33968
34117
  if (this.options.replace !== true) throw new CdkdError(`${logicalId} (${resourceType}) requires replacement, but the create-first attempt collided with the existing resource: ${createMsg}. ${nameOrigin.descriptor}, so the CloudFormation-style safe replacement order (create the new resource before deleting the old) cannot reuse the occupied name — CloudFormation refuses this shape with "cannot update a stack when a custom-named resource requires replacing". ${nameOrigin.remedy}, or re-run with \`cdkd deploy --replace\` to delete the old resource FIRST and recreate it under the same name (the resource is briefly unavailable while it is recreated).`, "NAMED_REPLACEMENT_COLLISION");
33969
34118
  this.logger.info(` Create-first collided with the existing resource's name and --replace is set — deleting old ${logicalId} (${currentResource.physicalId}) first...`);
33970
34119
  deletedOldFirst = true;
33971
- createResult = await this.replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, updateSecrets, updateReplacePolicy);
34120
+ createResult = await this.replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, updateSecrets, updateReplacePolicy, oldDeleteRoute.provisionedBy);
33972
34121
  }
33973
34122
  if (equalIdIsSameResource && !deletedOldFirst && createResult.physicalId === currentResource.physicalId) {
33974
34123
  const idempotentNameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
@@ -33976,7 +34125,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
33976
34125
  if (this.options.replace !== true) throw new CdkdError(`${logicalId} (${resourceType}) requires replacement, but its Create API is name-idempotent: the create-first attempt returned the EXISTING resource (${currentResource.physicalId}) instead of creating a new one, so deleting the "old" resource would silently destroy the resource the deploy just reported as created. ${idempotentNameOrigin.descriptor}; ${idempotentNameOrigin.remedy}, or re-run with \`cdkd deploy --replace\` to delete the old resource FIRST and recreate it under the same name (the resource is briefly unavailable while it is recreated). Note: this branch is also reached when the old resource was deleted out-of-band and the physical id is name-derived — there the create was a genuine fresh create; \`--replace\` converges that case too.`, "NAMED_REPLACEMENT_IDEMPOTENT_CREATE");
33977
34126
  this.logger.info(` Create-first returned the existing resource (name-idempotent Create API) and --replace is set — deleting old ${logicalId} (${currentResource.physicalId}) first...`);
33978
34127
  deletedOldFirst = true;
33979
- createResult = await this.replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, updateSecrets, updateReplacePolicy);
34128
+ createResult = await this.replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, updateSecrets, updateReplacePolicy, oldDeleteRoute.provisionedBy);
33980
34129
  }
33981
34130
  if (deletedOldFirst) {} else if (updateReplacePolicy === "Retain") {
33982
34131
  this.retainedOldOnReplacement.add(logicalId);
@@ -33993,7 +34142,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
33993
34142
  snapshotBlockedDelete = true;
33994
34143
  this.logger.warn(` ⚠ Final snapshot for old ${logicalId} (${currentResource.physicalId}) failed: ${snapshotError instanceof Error ? snapshotError.message : String(snapshotError)}. The old resource was NOT deleted (UpdateReplacePolicy: Snapshot) — delete it manually once you have a snapshot; it is no longer tracked in state.`);
33995
34144
  }
33996
- if (!snapshotBlockedDelete) await this.deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, oldDeleteProvider, currentResource.properties, cleanupFinalSnapshotId, updateReplacePolicy, updateSecrets);
34145
+ if (!snapshotBlockedDelete) await this.deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, oldDeleteProvider, currentResource.properties, cleanupFinalSnapshotId, updateReplacePolicy, updateSecrets, oldDeleteRoute.provisionedBy);
33997
34146
  }
33998
34147
  }
33999
34148
  this.registerNoEchoAttributes(logicalId, createResult, updateSecrets, resolvedProps);
@@ -34129,6 +34278,11 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
34129
34278
  if (!isWaitAbandonedError(deleteError) && !isInterruptedWaitError(deleteError) && !isMarkedNonRetryable(deleteError) && (deleteMsg.includes("does not exist") || deleteMsg.includes("not found") || deleteMsg.includes("NotFound"))) this.logger.debug(`Old resource ${logicalId} already gone, proceeding with CREATE`);
34130
34279
  else throw deleteError;
34131
34280
  }
34281
+ reportDeleteGuards(fallbackDeleteResult, {
34282
+ physicalId: currentResource.physicalId,
34283
+ resourceType,
34284
+ provisionedBy: updateDecision.provisionedBy
34285
+ });
34132
34286
  const fallbackSkipReason = deleteSkipReason(fallbackDeleteResult);
34133
34287
  if (fallbackSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, fallbackSkipReason, "during the UPDATE-not-supported replacement"));
34134
34288
  }
@@ -34143,6 +34297,7 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
34143
34297
  createProvider: replProvider,
34144
34298
  createProps: replProps,
34145
34299
  deleteProvider: updateProvider,
34300
+ deleteProvisionedBy: updateDecision.provisionedBy,
34146
34301
  deleteProperties: currentProps,
34147
34302
  secrets: updateSecrets,
34148
34303
  change: fallbackNameChange,
@@ -34272,10 +34427,11 @@ async function provisionDelete(logicalId, change, stateResources, stackName, tem
34272
34427
  }
34273
34428
  const governingPolicy = effectiveDeletionPolicy(resourceType, deletionPolicy, currentResource.properties);
34274
34429
  const finalSnapshotIdentifier = await this.prepareFinalSnapshotForDelete(logicalId, resourceType, currentResource, governingPolicy);
34275
- const deleteProvider = this.providerRegistry.getProviderFor({
34430
+ const deleteRoute = this.providerRegistry.getProviderFor({
34276
34431
  resourceType,
34277
34432
  provisionedBy: currentResource.provisionedBy
34278
- }).provider;
34433
+ });
34434
+ const deleteProvider = deleteRoute.provider;
34279
34435
  this.logger.debug(`Deleting ${logicalId} (${resourceType})`);
34280
34436
  let deleteResult = void 0;
34281
34437
  const inlinePolicyClaimed = this.inlinePolicyClaimedFor(resourceType, logicalId, stateResources);
@@ -34293,6 +34449,11 @@ async function provisionDelete(logicalId, change, stateResources, stackName, tem
34293
34449
  if (!isInterruptedWaitError(deleteError) && !isMarkedNonRetryable(deleteError) && !isWaitAbandonedError(deleteError) && (msg.includes("does not exist") || msg.includes("was not found") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException") || msg.includes("ResourceNotFoundException"))) this.logger.debug(`Resource ${logicalId} already deleted (${msg}), removing from state`);
34294
34450
  else throw deleteError;
34295
34451
  }
34452
+ reportDeleteGuards(deleteResult, {
34453
+ physicalId: currentResource.physicalId,
34454
+ resourceType,
34455
+ provisionedBy: deleteRoute.provisionedBy
34456
+ });
34296
34457
  const deleteSkipped = deleteSkipReason(deleteResult);
34297
34458
  if (deleteSkipped !== void 0) {
34298
34459
  if (progress) progress.current++;
@@ -34415,12 +34576,27 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
34415
34576
  const physicalIdBeforeUpdate = stateResources[logicalId]?.physicalId;
34416
34577
  const provisionedByBeforeUpdate = stateResources[logicalId]?.provisionedBy;
34417
34578
  let nestedChildUnaddressed;
34579
+ const deleteGuards = [];
34418
34580
  try {
34419
34581
  await withResourceDeadline(async () => {
34420
- const { value: bodyResult, unaddressed } = await collectNestedChildUnaddressed(() => this.provisionResourceBody(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress));
34421
- deleteSkipped = bodyResult?.deleteSkipped;
34422
- updatePartial = bodyResult?.updatePartial;
34423
- nestedChildUnaddressed = unaddressed;
34582
+ try {
34583
+ const { value: bodyResult, unaddressed } = await collectDeleteGuards(deleteGuards, () => collectNestedChildUnaddressed(() => this.provisionResourceBody(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress)));
34584
+ deleteSkipped = bodyResult?.deleteSkipped;
34585
+ updatePartial = bodyResult?.updatePartial;
34586
+ nestedChildUnaddressed = unaddressed;
34587
+ } finally {
34588
+ for (const guard of deleteGuards.splice(0)) this.recordEvent({
34589
+ eventType: "RESOURCE_GUARD_INDETERMINATE",
34590
+ stackName,
34591
+ operation: "DELETE",
34592
+ logicalId,
34593
+ resourceType: guard.resourceType,
34594
+ ...guard.provisionedBy && { provisionedBy: guard.provisionedBy },
34595
+ ...guard.physicalId && { physicalId: this.maskForResource(logicalId, guard.physicalId) },
34596
+ guard: guard.guard,
34597
+ reason: guard.reason
34598
+ });
34599
+ }
34424
34600
  }, {
34425
34601
  warnAfterMs,
34426
34602
  timeoutMs,
@@ -36433,4 +36609,4 @@ DeployEngine.prototype.orphanedNameCollisionAdvice = orphanedNameCollisionAdvice
36433
36609
 
36434
36610
  //#endregion
36435
36611
  export { resourcesNamingDeclaredParameter as $, STATE_SOURCED_READBACK_RULES as $a, isWarmThroughputDecrease as $i, explicitRoleArnOrThrow as $n, runDockerForeground as $o, malformedOutputsWarning as $r, noEchoParameterValueSeed as $t, resolveDynamoDbDeleteBudgetClock as A, printingCorpusOf as Aa, repairMalformedOrphanRecordsForReadOnly as Ai, ccProtectionRegistryTypes as An, assertAssetBucketRegion as Ao, STATE_REGION_DIVERGED as Ar, derivePartitionAndUrlSuffix as As, ccRoutedFinalSnapshotError as At, getPriorAttempts as B, scrubResourceRecord as Ba, findSilentDropProperties as Bi, isTerminationProtectionPropagationError as Bn, resolveDockerContextDirectory as Bo, isReadableResourceEntry as Br, describeFileReadFailure as Bs, updatePartialMessage as Bt, perType as C, inheritNestedStackParameterAssociations as Ca, refuseMalformedResourcePropertiesForDrift as Ci, ProviderRegistry as Cn, WorkGraph as Co, isStalePlaceholderArnAttribute as Cr, findLargeInlineResources as Cs, resolveReplacementOldType as Ct, beginDeleteWait as D, hasMaskableValues as Da, refuseMalformedResourcesForDestroy as Di, getCurrentResourceSecrets as Dn, rewriteTemplateAssetReferences as Do, parameterInputsFor as Dr, expectedOwnerParam as Ds, ATOMIC_FINAL_SNAPSHOT_TYPES as Dt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as E, createUnionSecretMasker as Ea, refuseMalformedResourcesForDeploy as Ei, isCustomResourceType as En, loadPublishableAssetManifest as Eo, withSharedDrainBudget as Er, decodeListingKey as Es, inheritProducerRegions as Et, waitForIndexesSettled as F, errorCauseChain as Fa, repairMalformedResourcesForReadOnly as Fi, withIndeterminateGuard as Fn, readBootstrapMarkerBody as Fo, displayLogicalId as Fr, hasOwnKey as Fs, unsupportedFinalSnapshotError as Ft, cyan as G, pathCrossesDottedKey as Ga, findReplacedReadersOfRecreateTargets as Gi, INTRINSIC_KEYS as Gn, finchSecretArgvRefusal as Go, malformedLocalResourceEntriesWarning as Gr, resolveBucketRegion as Gs, WITHHELD_NAME_DISPLAY as Gt, formatResourceLine as H, DYNAMIC_REFERENCE_TOKEN_SCAN as Ha, withoutSilentDropProperties as Hi, reDisableInstanceApiTermination as Hn, describeDockerExecFailure as Ho, malformedExportNamesWarning as Hr, renderAssemblyPathEscape as Hs, DeploymentEventsReader as Ht, ECR_AUTO_DELETE_IMAGES_TAG as I, maskSecretsInError as Ia, unpreviewableOrphanRecords as Ii, isWaitAbandonedError as In, validateAssetBucketName as Io, hasReadableOrphans as Ir, hasPlainPrototype$1 as Is, REDACTED_DELETE_ADDRESS_SKIP_REASON as It, red as J, recordMaskOnlyValue as Ja, isStatefulRecreateTargetForReplace as Ji, producerRegionsFromState as Jn, isDockerClientEnvKey as Jo, malformedOrphanRecordsWarning as Jr, secretBearing as Jt, gray as K, identityKeyFor as Ka, shownType as Ki, IntrinsicFunctionResolver as Kn, formatDockerLoginError as Ko, malformedLocalResourcesWarning as Kr, displayTextOrWithheld as Kt, S3_AUTO_DELETE_OBJECTS_TAG as L, maskSecretsInText as La, unreadableOrphanRecords as Li, markWaitAbandoned as Ln, validateContainerRepoName as Lo, hasReadableOutputs as Lr, nullPrototypeRecord as Ls, isRedactedRecordedValue as Lt, DELETE_INDEX_WAIT_PROCEED_NOTE as M, recordLogOnlyValue as Ma, repairMalformedOutputsForReadOnly as Mi, UNSPECIFIED_SKIP_REASON as Mn, getBootstrapMarkerKey as Mo, UNREADABLE_ORPHANS_CONTAINER_ROW as Mr, StageLoadError as Ms, effectiveDeletionPolicy as Mt, INDEX_SETTLE_POLL_INTERVAL_MS as N, shareLogOnlyValues as Na, repairMalformedResourceEntriesForReadOnly as Ni, deleteIndeterminateGuards as Nn, isCrossRegionRedirect as No, UNREADABLE_RESOURCES_MAP_ROW as Nr, processStackMessages as Ns, isFinalSnapshotError as Nt, compensateRemovedDeletionProtection as O, literalSplitDelimitersOf as Oa, refuseMalformedResourcesForExport as Oi, CloudControlProvider as On, AssetModeResolver as Oo, passedParameterClassesOf as Or, PARTITION_TABLE as Os, PRE_DELETE_SNAPSHOT_TYPES as Ot, deleteTableWithIndexBusyRetry as P, createSecretMasker as Pa, repairMalformedResourcePropertiesForReadOnly as Pi, deleteSkipReason as Pn, parseBootstrapMarker as Po, deployRefusesOrphanRowsReason as Pr, defineOwnKey as Ps, refusesFinalSnapshot as Pt, reachableDivergentParameters as Q, STATE_SOURCED_CROSS_GENERATION_RULES as Qa, coerceWarmThroughput as Qi, assertSendableRoleArn as Qn, redactedDockerCause as Qo, malformedOutputsRefusalMessage as Qr, isWholeDynamicReferenceValue as Qt, hasCdkAutoDeleteTag as R, markSameGenerationBag as Ra, unreadableResourceEntries as Ri, disableInstanceApiTermination as Rn, buildDenyExternalAccessPolicy as Ro, hasReadableResources as Rr, ownValue as Rs, redactedDeleteAddressFields as Rt, isProtectionValueActive as S, liveMatchesUnresolvedTokenFrame as Sa, refuseMalformedResourceEntriesForOrphan as Si, CC_BROKEN_REASON as Sn, stringifyValue as So, cfnRefValueFromPhysicalId as Sr, MIGRATE_TMP_PREFIX as Ss, planRollback as St, DynamoDBGlobalTableProvider as T, carryLogOnlyValues as Ta, refuseMalformedResourcePropertiesForOrphan as Ti, wouldReturnToSdkProvider as Tn, createAssetRedirectResolver as To, parseWebACLArn as Tr, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Ts, getCurrentProducerRegions as Tt, createReadOnlyAttributeHealerFactory as U, dynamicReferenceTokens as Ua, NO_CC_HANDLERS_REASON as Ui, reEnableInstanceApiTermination as Un, describeDockerFailure as Uo, malformedExportSourceWarning as Ur, resolveAssemblyPath as Us, DeploymentEventsStore as Ut, markRefusedBeforeApplying as V, recoverMaskedOutput as Va, unwrittenCreateOnlyReplacement as Vi, observeThenDisableInstanceApiTermination as Vn, describeDockerCapturedOutput as Vo, malformedDriftResourcePropertiesWarning as Vr, displayAssemblyPath as Vs, updatePartialReason as Vt, bold as W, isUncertifiedBaselineMaskPosition as Wa, hasNoCloudControlHandlers as Wi, DiffCalculator as Wn, dockerSpawnEnvWithSensitive as Wo, malformedLocalOutputsWarning as Wr, clearBucketRegionCache as Ws, extractDeploymentEventError as Wt, computeParameterTaint as X, recordNoEchoAttributeValues as Xa, renderStatefulReason as Xi, applyRoleArnIfSet as Xn, partitionSensitiveEnv as Xo, malformedOrphansRefusalMessage as Xr, secretSafeKeyDisplay as Xt, yellow as Y, recordMaskOnlyValuesIn as Ya, isStatefulRecreateTargetSync as Yi, regionLessSecretName as Yn, isMalformedEnvKey as Yo, malformedOrphanRowsKeptWarning as Yr, secretBearingStateKeyWarning as Yt, namesAnyDeclaredParameter as Z, STATE_SOURCED_BASELINE_RULES as Za, WARM_THROUGHPUT_MEMBERS as Zi, assertFlagRoleArn as Zn, redactDockerArgvValues as Zo, malformedOrphansWarning as Zr, exportNameSecretExposure as Zt, makeCanonicalizePropertiesFn as _, canonicalLambdaFunctionName as _a, refuseMalformedResourceEntries as _i, refuseMalformedDesiredTags as _n, orphansAfterRollback as _o, carriesDynamicReference as _r, stateBucketExistenceConfirmed as _s, destroyStackRecordsView as _t, findNestedTemplateTreeDefect as a, configIntegerRefusal as aa, malformedStateRefusalMessage as ai, DEFAULT_RESOURCE_WARN_AFTER_MS as an, S3StateBackend as ao, envCredentialsAreAssumedRole as ar, getDockerImageBySourceHash as as, dropSettledNestedJournals as at, recordedProtectionNote as b, DagBuilder as ba, refuseMalformedResourceEntriesForImport as bi, definedAttributes as bn, AssetPublisher as bo, keepsSecretReferenceToken as br, CFN_TEMPLATE_BODY_LIMIT as bs, recordAfterRollbackUpdate as bt, renderNestedTemplateTreeDefect as c, replayWarn as ca, refuseMalformedNestedChildOutputs as ci, earliestDefined as cn, acceptedCreateOnlyDropsOf as co, s3BucketDomainName as cr, getDefaultStateBucketName as cs, recordDisplacedSkips as ct, conditionInputsFrom as d, requireConfigString as da, refuseMalformedOrphans as di, withCreateTokenLedger as dn, hasReadableExportSet as do, s3BucketWebsiteUrl as dr, resolveAutoAssetStorage as ds, withNestedRevertRun as dt, toCfnInteger as ea, malformedRenderedContainersWarning as ei, collectDeclaredOutputNames as en, TEMPLATE_SOURCED_RULES as eo, isIamRoleArn as er, runDockerStreaming as es, makeSiblingClaimReader as et, parentSuppliedValues as f, prefetchCreateOnlyPropertyPaths as fa, refuseMalformedOrphansForDestroy as fi, acquireIdempotencyToken as fn, hasReasonlessBaselineRefusal as fo, coerceParameterTypedValue as fr, resolveCaptureObservedState as fs, getCurrentNestedStackContext as ft, mergeNoChangeOutputs as g, markAuxiliaryFailure as ga, refuseMalformedResourceAttributesForOrphan as gi, readTagList as gn, isReadableBag as go, isImpossibleEmptyStoredAttribute as gr, resolveUseCdkBootstrapAssets as gs, awaitInFlightSibling as gt, keptWholeReasonText as h, withRetry as ha, refuseMalformedOutputsForDestroy as hi, planTagDiff as hn, importableOutputs as ho, getAccountInfo as hr, resolveStateBucketWithDefaultAndSource as hs, replayRollback as ht, childTemplateLoader as i, configBooleanRefusal as ia, malformedScrubResourceEntriesRefusalMessage as ii, DEFAULT_RESOURCE_TIMEOUT_MS as in, isLockInfoExpired as io, callerEnvCredentials as ir, AssetManifestLoader as is, displacedPhysicalIdShown as it, resolveDynamoDbDeleteBudgetMs as j, recordLogOnlyParameterValue as ja, repairMalformedOrphansForReadOnly as ji, unchangedBehindSecretReference as jn, ensureAssetStorage as jo, STATE_RESOURCES_MALFORMED as jr, AssemblyReader as js, createPreDeleteFinalSnapshot as jt, deleteBudgetKey as k, logOnlyValueCount as ka, refuseMalformedState as ki, slowCcOperationTimeoutMs as kn, BOOTSTRAP_MARKER_PREFIX as ko, JSON_LISTING_HOLE_VALUE as kr, canonicalizeRegion as ks, buildFinalSnapshotIdentifier as kt, templateIdentity as l, requireConfigArray as la, refuseMalformedOrphanRecords as li, ledgerForStack as ln, describeRegionValueKind as lo, s3BucketDualStackDomainName as lr, getLegacyStateBucketName as ls, revertNestedChildFromJournal as lt, isSecretBearingReferenceString as m, describeTypeWithThrottleRetry as ma, refuseMalformedOutputs as mi, DBPROXY_TAG_OPTIONS as mn, importableOutputKeys as mo, parameterTypeMayLoseSecretIdentity as mr, resolveStateBucketWithDefault as ms, replayFailedOperations as mt, IMPLICIT_DELETE_DEPENDENCIES as n, coerceCfnBoolean as na, malformedResourcePropertiesWarning as ni, isExportAliasCollision as nn, isSingleDynamicReferenceToken as no, AWS_CREDENTIAL_ENV_KEYS as nr, escapeRegExp$2 as ns, NESTED_PENDING_PARENT_REASON as nt, isAbsoluteAssetPath as o, configStringRefusal as oa, previewableOrphanRecords as oi, maskingRetryLogger as on, rebuildClientForBucketRegion as oo, isSettledInstanceState as or, Synthesizer as os, getNestedRevertRun as ot, readRecordedConditionVerdicts as p, templateResourceTypes as pa, refuseMalformedOrphansForOrphan as pi, DBPROXY_TAGS_WHAT as pn, hasUnverifiableParameterRefusal as po, isUnboundTemplateParameter as pr, resolveSkipPrefix as ps, withNestedStackContext as pt, green as q, carriesSecretMask as qa, MULTI_REGION_RECREATE_BLOCKED_TYPES as qi, classifyReplaySecretRegion as qn, getDockerCmd as qo, malformedOrphanRecordsRefusalMessage as qr, exportAliasCollisionScrubWarning as qt, computeImplicitDeleteEdges as r, coerceCfnInteger as ra, malformedResourcesWarning as ri, bindingSkippedOutputs as rn, LockManager as ro, applyCallerIdentityCredentials as rr, stripControlChars as rs, displacedOpClause as rt, listNestedTemplateRows as s, readConfigString as sa, refuseDivergentRecordRegionForDestroy as si, RollbackInlinePolicyWriters as sn, splitImportedOps as so, s3BucketArn as sr, synthesisStatusMessage as ss, nestedChildStackName as st, DeployEngine as t, toFiniteNumber as ta, malformedResourceEntriesWarning as ti, collectPublishedOutputNames as tn, WHOLE_DYNAMIC_REFERENCE_PATTERN as to, sendableAssumeRoleCommand as tr, warnFinchArgvExposure as ts, planOrphanAdoption as tt, conditionFingerprint as u, requireConfigObject as ua, refuseMalformedOrphanRecordsForDestroy as ui, reserveStackCreateToken as un, exportNamesCarriedFrom as uo, s3BucketRegionalDomainName as ur, resolveApp as us, revertedNestedRowIds as ut, withResourceDeadline as v, lambdaFunctionNameForMask as va, refuseMalformedResourceEntriesForDeploy as vi, tagMapAsList as vn, orphansCarriedFrom as vo, carriesFetchableDynamicReference as vr, warnDeprecatedNoPrefixCliFlag as vs, getStackRecords as vt, readProtection as w, recordNestedStackParameterExpressions as wa, refuseMalformedResourcePropertiesForExport as wi, ccBrokenReason as wn, buildAssetRedirectMap as wo, refStateLookupFromResource as wr, uploadCfnTemplate as ws, findNestedStackTypeChanges as wt, PROTECTION_PROPERTY_BY_TYPE as x, TemplateParser as xa, refuseMalformedResourceEntriesForImportSave as xi, stringifyIfAssigned as xn, isSensitiveAttributeName as xo, AWS_NO_VALUE as xr, CFN_TEMPLATE_URL_LIMIT as xs, planFailedOps as xt, recordedProtectionEvidence as y, sameLambdaFunctionAddress as ya, refuseMalformedResourceEntriesForDestroy as yi, tagPlanWarning as yn, shouldRetainResource as yo, isNamelessDynamicReferenceError as yr, ssmResolvedValueType as ys, withStackRecords as yt, isTruthyCfnBoolean as z, redactSecretsForState as za, findActionableSilentDrops as zi, ec2InstanceProtectionSite as zn, buildDockerImage as zo, isReadableOrphanRecord as zr, absoluteAssemblyPathEscape as zs, redactedDeleteAddressSkip as zt };
36436
- //# sourceMappingURL=deploy-engine-CMRU0DTu.js.map
36612
+ //# sourceMappingURL=deploy-engine-BiA8Ud6-.js.map