@go-to-k/cdkd 0.299.3 → 0.299.5

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 (29) hide show
  1. package/dist/{asg-provider-CsBxbRlH.js → asg-provider-DZv4iAmI.js} +4 -4
  2. package/dist/{asg-provider-CsBxbRlH.js.map → asg-provider-DZv4iAmI.js.map} +1 -1
  3. package/dist/{aws-failure-text-DtvlUugx.js → aws-failure-text-BEQfs6za.js} +12 -3
  4. package/dist/aws-failure-text-BEQfs6za.js.map +1 -0
  5. package/dist/cli.js +2 -2
  6. package/dist/{deploy-engine-DEBgHf6Z.js → deploy-engine-D6CSo8Gj.js} +945 -272
  7. package/dist/deploy-engine-D6CSo8Gj.js.map +1 -0
  8. package/dist/{iam-policy-targets-Pn2m0R67.js → iam-policy-targets-dAY3-gXJ.js} +2 -2
  9. package/dist/{iam-policy-targets-Pn2m0R67.js.map → iam-policy-targets-dAY3-gXJ.js.map} +1 -1
  10. package/dist/{iam-role-provider-CXfEJz94.js → iam-role-provider-vd8u3waQ.js} +4 -4
  11. package/dist/{iam-role-provider-CXfEJz94.js.map → iam-role-provider-vd8u3waQ.js.map} +1 -1
  12. package/dist/index.d.ts +17 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +4 -4
  15. package/dist/{neptune-provider-C81KkPPG.js → neptune-provider-BHEUW4UW.js} +4 -4
  16. package/dist/{neptune-provider-C81KkPPG.js.map → neptune-provider-BHEUW4UW.js.map} +1 -1
  17. package/dist/{program-B4pWdUfl.js → program-iNas59nt.js} +67 -24
  18. package/dist/program-iNas59nt.js.map +1 -0
  19. package/dist/{provider-classes-BFHOZwKd.js → provider-classes-ec1KOg_1.js} +30 -19
  20. package/dist/provider-classes-ec1KOg_1.js.map +1 -0
  21. package/dist/{rds-provider-d15q7Rp5.js → rds-provider-J60TlCOp.js} +4 -4
  22. package/dist/{rds-provider-d15q7Rp5.js.map → rds-provider-J60TlCOp.js.map} +1 -1
  23. package/dist/{version-B7Gzz6TR.js → version-FFcDgFAc.js} +2 -2
  24. package/dist/{version-B7Gzz6TR.js.map → version-FFcDgFAc.js.map} +1 -1
  25. package/package.json +1 -1
  26. package/dist/aws-failure-text-DtvlUugx.js.map +0 -1
  27. package/dist/deploy-engine-DEBgHf6Z.js.map +0 -1
  28. package/dist/program-B4pWdUfl.js.map +0 -1
  29. package/dist/provider-classes-BFHOZwKd.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { r as getAwsClients, s as __exportAll } from "./aws-clients-Bj7qH5Ph.js";
2
- import { A as UNRENDERABLE, C as looksLikeCdkdGeneratedName, E as withoutGeneratedFallbackName, F as displayStackName, H as truncateCodePoints, I as isPasteableIdent, M as displayAwsMessage, N as displayIdent, O as SECRET_REF_MAX_CODE_POINTS, P as displaySafe, R as plainIdentOr, S as getCurrentStackName, T as withStackName, V as terminalSafe, a as getLogger, b as generateResourceNameWithFallback, d as installLogLineMaskerSource, f as getLiveRenderer, g as applyDefaultNameForFallback, k as STACK_REF_MAX_CODE_POINTS, o as isStdoutReservedForPayload, r as safeStringify$1, t as describeAwsFailure, u as currentLogLineMasker, v as explicitNamePropertyFor, w as withSkipPrefix, x as getCurrentSkipPrefix, y as generateResourceName, z as safeMsg } from "./aws-failure-text-DtvlUugx.js";
3
- import { $ as protectedReplacementAdvice, $n as isAmbiguousOutcomeError, $t as credentialFingerprint, A as isQuotableImportValue, An as UNSHOWABLE_VALUE, At as isAuxiliaryMarkOf, B as isTerminalDeleteFailure, Bn as withheldTargetClause, Bt as recoveryCommandFlags, Ct as RETRY_AUXILIARY_OWNER, Dt as createdResourceIdentityBeforeFailure, E as assertRegionMatch, Et as createdBeforeFailure, F as resolveExplicitPhysicalId, Fn as physicalIdShownBesideCommand, G as runDeleteAttempt, Gn as isNameCollisionErrorFrom, H as observeThenDisableProtection, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, J as DELETION_PROTECTION_DOC_POINTER, Jn as isReplayedNameCollisionFrom, Kn as isNameCooldownError, L as ProtectionFlipRegistry, Ln as quotedOrDescribed, Lt as formatLockExpiry, M as quotedRemedyLogicalId, Mt as markCreatedBeforeFailure, N as refusalTypeShown, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, On as SHELL_ACTIVE, Ot as hasCreatedBeforeFailure, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Q as pasteableAwsCommand, Qn as isAmbiguousCcHandlerErrorCode, Qt as clientDefaultsFor, R as compensateProtectionFlip, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, St as withDerivedNameMasks, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, U as protectionFlipKey, Un as isUpdateUnsupportedError, Ut as DEFAULT_STATE_PREFIX, Vt as sanitizeRecoveryValue, Wn as hasReplayMayCollide, Wt as injectiveKey, Xn as markReplayMayCollide, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Zn as formatRetryClassificationSignals, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, _t as createMaskedLogSinks, an as DependencyError, ar as isMarkedNonRetryable, at as startInterruptWatch, bt as maskDeep, cn as IntrinsicResolutionRefusalError, cr as markRedactedCause, ct as canonicalizeRoute53QueryName, d as prepareRemovalForUpdate, dn as LockError, en as AccountIdUnavailableError, er as isIamPropagationError, f as removalWarning, fn as MacroExpansionError, ft as logicalIdShown, gn as ProvisioningError, gt as stateOrphanRecordRemedy, ht as segmentAfterAnchor, i as holdsSecretDerivedEntry, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, j as normalizeAwsTagsToCfn, jn as commandHole, jt as markAuxiliaryFailure, kn as SHELL_ACTIVE_WHY, kt as isAuxiliaryFailure, l as withUnchangedSecretPrincipalLists, lr as wrapMaskedAwsError, m as withoutInjectedRemovals, mt as resourceTypeShown, nn as CdkdError, nr as isTransientServerError, or as isThrottlingError, ot as ElapsedBudgetRegistry, pn as MalformedProducerRecordRefusalError, qn as isRecreateRetryableError, qt as producerRecordKey, rr as retryClassificationText, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, st as monotonicNowMs, tn as AssetError, tr as isRetryableTransientError, ut as compositeIdSeparatorRefusal, vn as ResourceUpdateNotSupportedError, vt as createMaskedRetryLogger, w as withoutServerErrorRetries, wt as carryCreatedBeforeFailure, xn as StateError, xt as maskerOrIdentity, yt as isSecretDerivedValue, z as deleteWithProtectionCompensation, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-Pn2m0R67.js";
2
+ import { A as UNRENDERABLE, B as safeMsg, C as looksLikeCdkdGeneratedName, D as SAFE_MSG_ALTERED_CHAR, E as withoutGeneratedFallbackName, F as displaySafe, H as terminalSafe, I as displayStackName, L as isPasteableIdent, N as displayAwsMessage, O as SECRET_REF_MAX_CODE_POINTS, P as displayIdent, S as getCurrentStackName, T as withStackName, U as truncateCodePoints, a as getLogger, b as generateResourceNameWithFallback, d as installLogLineMaskerSource, f as getLiveRenderer, g as applyDefaultNameForFallback, j as asIsMessage, k as STACK_REF_MAX_CODE_POINTS, o as isStdoutReservedForPayload, r as safeStringify$1, t as describeAwsFailure, u as currentLogLineMasker, v as explicitNamePropertyFor, w as withSkipPrefix, x as getCurrentSkipPrefix, y as generateResourceName, z as plainIdentOr } from "./aws-failure-text-BEQfs6za.js";
3
+ import { $ as protectedReplacementAdvice, $n as isAmbiguousOutcomeError, $t as credentialFingerprint, A as isQuotableImportValue, An as UNSHOWABLE_VALUE, At as isAuxiliaryMarkOf, B as isTerminalDeleteFailure, Bn as withheldTargetClause, Bt as recoveryCommandFlags, Ct as RETRY_AUXILIARY_OWNER, Dt as createdResourceIdentityBeforeFailure, E as assertRegionMatch, Et as createdBeforeFailure, F as resolveExplicitPhysicalId, Fn as physicalIdShownBesideCommand, G as runDeleteAttempt, Gn as isNameCollisionErrorFrom, H as observeThenDisableProtection, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, J as DELETION_PROTECTION_DOC_POINTER, Jn as isReplayedNameCollisionFrom, Kn as isNameCooldownError, L as ProtectionFlipRegistry, Ln as quotedOrDescribed, Lt as formatLockExpiry, M as quotedRemedyLogicalId, Mt as markCreatedBeforeFailure, N as refusalTypeShown, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, On as SHELL_ACTIVE, Ot as hasCreatedBeforeFailure, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Q as pasteableAwsCommand, Qn as isAmbiguousCcHandlerErrorCode, Qt as clientDefaultsFor, R as compensateProtectionFlip, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, St as withDerivedNameMasks, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, U as protectionFlipKey, Un as isUpdateUnsupportedError, Ut as DEFAULT_STATE_PREFIX, Vt as sanitizeRecoveryValue, Wn as hasReplayMayCollide, Wt as injectiveKey, Xn as markReplayMayCollide, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Zn as formatRetryClassificationSignals, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, _t as createMaskedLogSinks, an as DependencyError, ar as isMarkedNonRetryable, at as startInterruptWatch, bt as maskDeep, cn as IntrinsicResolutionRefusalError, cr as markRedactedCause, ct as canonicalizeRoute53QueryName, d as prepareRemovalForUpdate, dn as LockError, en as AccountIdUnavailableError, er as isIamPropagationError, f as removalWarning, fn as MacroExpansionError, ft as logicalIdShown, gn as ProvisioningError, gt as stateOrphanRecordRemedy, ht as segmentAfterAnchor, i as holdsSecretDerivedEntry, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, j as normalizeAwsTagsToCfn, jn as commandHole, jt as markAuxiliaryFailure, kn as SHELL_ACTIVE_WHY, kt as isAuxiliaryFailure, l as withUnchangedSecretPrincipalLists, lr as wrapMaskedAwsError, m as withoutInjectedRemovals, mt as resourceTypeShown, nn as CdkdError, nr as isTransientServerError, or as isThrottlingError, ot as ElapsedBudgetRegistry, pn as MalformedProducerRecordRefusalError, qn as isRecreateRetryableError, qt as producerRecordKey, rr as retryClassificationText, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, st as monotonicNowMs, tn as AssetError, tr as isRetryableTransientError, ut as compositeIdSeparatorRefusal, vn as ResourceUpdateNotSupportedError, vt as createMaskedRetryLogger, w as withoutServerErrorRetries, wt as carryCreatedBeforeFailure, xn as StateError, xt as maskerOrIdentity, yt as isSecretDerivedValue, z as deleteWithProtectionCompensation, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-dAY3-gXJ.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-DBXBcg0J.js";
5
- import { t as getCdkdVersion } from "./version-B7Gzz6TR.js";
5
+ import { t as getCdkdVersion } from "./version-FFcDgFAc.js";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
8
8
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketLifecycleConfigurationCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -5427,6 +5427,46 @@ async function readEarlierStateResources(s3, bucket, owner, key, max) {
5427
5427
  }
5428
5428
  }))).filter((r) => r !== void 0);
5429
5429
  }
5430
+ async function keyMayHaveVersions(s3, bucket, owner, key) {
5431
+ try {
5432
+ const listed = await s3.send(new ListObjectVersionsCommand({
5433
+ Bucket: bucket,
5434
+ ...await owner(),
5435
+ Prefix: key,
5436
+ EncodingType: "url",
5437
+ MaxKeys: 1
5438
+ }));
5439
+ return (listed.Versions ?? []).length + (listed.DeleteMarkers ?? []).length > 0 || listed.IsTruncated === true;
5440
+ } catch {
5441
+ return true;
5442
+ }
5443
+ }
5444
+ async function listVersionedSubdirectories(s3, bucket, owner, prefix) {
5445
+ const out = [];
5446
+ let keyMarker;
5447
+ let versionIdMarker;
5448
+ for (;;) {
5449
+ const listed = await s3.send(new ListObjectVersionsCommand({
5450
+ Bucket: bucket,
5451
+ ...await owner(),
5452
+ Prefix: prefix,
5453
+ Delimiter: "/",
5454
+ EncodingType: "url",
5455
+ ...keyMarker !== void 0 && { KeyMarker: keyMarker },
5456
+ ...versionIdMarker !== void 0 && { VersionIdMarker: versionIdMarker }
5457
+ }));
5458
+ for (const cp of listed.CommonPrefixes ?? []) {
5459
+ const decoded = decodeListingKey(cp.Prefix);
5460
+ if (decoded === void 0 || !decoded.startsWith(prefix)) continue;
5461
+ const segment = decoded.slice(prefix.length).replace(/\/$/, "");
5462
+ if (segment !== "") out.push(segment);
5463
+ }
5464
+ if (listed.IsTruncated !== true) return out;
5465
+ if (listed.NextKeyMarker === void 0) throw new Error("a truncated version listing returned no NextKeyMarker");
5466
+ keyMarker = decodeListingKey(listed.NextKeyMarker);
5467
+ versionIdMarker = listed.NextVersionIdMarker;
5468
+ }
5469
+ }
5430
5470
 
5431
5471
  //#endregion
5432
5472
  //#region src/state/retained-time.ts
@@ -5513,6 +5553,7 @@ function legacyProbeBelongsTo(probe, region) {
5513
5553
  }
5514
5554
  const KEPT_AT_CLOCK_TOLERANCE_MS = 2e3;
5515
5555
  const ROLLBACK_JOURNAL_OBJECT_DESCRIPTION = "the rollback journal, whose `failedOperations[].attemptedProperties` records the properties of the failed write verbatim";
5556
+ const STATE_RECORD_OBJECT_DESCRIPTION = "the stack's state record, which carries every resource's recorded properties and attributes";
5516
5557
  var S3StateBackend = class S3StateBackend {
5517
5558
  logger = getLogger().child("S3StateBackend");
5518
5559
  s3Client;
@@ -5767,6 +5808,49 @@ var S3StateBackend = class S3StateBackend {
5767
5808
  await this.deleteRollbackJournal(stackName, region);
5768
5809
  }
5769
5810
  }
5811
+ async purgeDeletedStateHistory(stackName, region) {
5812
+ try {
5813
+ await this.ensureClientForBucket();
5814
+ const stateKey = this.getStateKey(stackName, region);
5815
+ const shown = displayStackName(stackName);
5816
+ let recordBack;
5817
+ try {
5818
+ recordBack = await this.headObject(stateKey);
5819
+ } catch {
5820
+ recordBack = true;
5821
+ }
5822
+ if (recordBack) {
5823
+ this.logger.warn(safeMsg`Kept the earlier versions of the state record for ${shown}: the record exists again, or its absence could not be confirmed, so they may belong to a live record.`);
5824
+ return;
5825
+ }
5826
+ const keys = [stateKey];
5827
+ const legacyKey = this.getLegacyStateKey(stackName);
5828
+ const mayHave = (key) => keyMayHaveVersions(this.s3Client, this.config.bucket, () => this.ownerParam(), key);
5829
+ if (await mayHave(legacyKey)) {
5830
+ const legacyProbe = await this.probeLegacyState(stackName);
5831
+ const keptBecause = legacyProbe.kind === "unreadable" ? `the legacy record could not be read (${legacyProbe.reason})` : legacyProbe.kind !== "absent" ? "its current body belongs to another record of the stack" : await this.otherRegionHistoryState(stackName, region, mayHave);
5832
+ if (keptBecause === "none") keys.push(legacyKey);
5833
+ else {
5834
+ const why = keptBecause === "exists" ? "another region of the stack still has state record versions, current or earlier, and the legacy versions may be that region's" : keptBecause === "unknown" ? "could not list the stack's other regions to confirm none of them still owns that history" : keptBecause;
5835
+ this.logger.warn(safeMsg`Kept the earlier versions of the legacy state record for ${shown}: ${why}. cdkd state destroy purges them only once no other region of the stack has state record versions and the legacy record can be read; otherwise delete them by hand.`);
5836
+ }
5837
+ }
5838
+ await this.purgeNoncurrentVersions(keys, { objectDescription: STATE_RECORD_OBJECT_DESCRIPTION });
5839
+ } catch (error) {
5840
+ this.logger.warn(safeMsg`Could not purge the earlier versions of the state record for ${displayStackName(stackName)}: ${describeAwsFailure(error).summary}. They remain readable via GetObject with a VersionId.`);
5841
+ }
5842
+ }
5843
+ async otherRegionHistoryState(stackName, region, mayHave) {
5844
+ const stackPrefix = `${this.config.prefix}/${stackName}/`;
5845
+ try {
5846
+ const regions = (await listVersionedSubdirectories(this.s3Client, this.config.bucket, () => this.ownerParam(), stackPrefix)).filter((segment) => segment !== region);
5847
+ for (const other of regions) if (await mayHave(this.getStateKey(stackName, other))) return "exists";
5848
+ return "none";
5849
+ } catch (error) {
5850
+ this.logger.debug(safeMsg`Could not list the other regions of ${displayStackName(stackName)}: ${displaySafe(describeAwsFailure(error).detail, { asciiOnly: true }) || "<unrenderable>"}`);
5851
+ return "unknown";
5852
+ }
5853
+ }
5770
5854
  async deleteLegacyState(stackName) {
5771
5855
  await this.ensureClientForBucket();
5772
5856
  const key = this.getLegacyStateKey(stackName);
@@ -7122,6 +7206,28 @@ function nanIfUncoercible(value) {
7122
7206
  //#endregion
7123
7207
  //#region src/deployment/secret-redaction/rules.ts
7124
7208
  const MIN_NEEDLE_LENGTH = 4;
7209
+ function printingNeedles(values) {
7210
+ const out = /* @__PURE__ */ new Set();
7211
+ for (const value of values) {
7212
+ if (value.length < 4) continue;
7213
+ out.add(value);
7214
+ const flat = flattenedSpelling(value);
7215
+ if (flat !== void 0 && flat.trim().length >= 4) out.add(flat);
7216
+ }
7217
+ return [...out];
7218
+ }
7219
+ const FLATTENED_MEMO_CAP = 4096;
7220
+ const flattenedMemo = /* @__PURE__ */ new Map();
7221
+ function flattenedSpelling(value) {
7222
+ if (!SAFE_MSG_ALTERED_CHAR.test(value)) return void 0;
7223
+ let flat = flattenedMemo.get(value);
7224
+ if (flat === void 0) {
7225
+ flat = safeMsg`${value}`;
7226
+ if (flattenedMemo.size >= FLATTENED_MEMO_CAP) flattenedMemo.clear();
7227
+ flattenedMemo.set(value, flat);
7228
+ }
7229
+ return flat === value ? void 0 : flat;
7230
+ }
7125
7231
  function escapeRegExp$2(value) {
7126
7232
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7127
7233
  }
@@ -7189,7 +7295,7 @@ const WHOLE_DYNAMIC_REFERENCE_PATTERN = new RegExp(`^\\{\\{resolve:${DYNAMIC_REF
7189
7295
  function isSingleDynamicReferenceToken(value) {
7190
7296
  return WHOLE_DYNAMIC_REFERENCE_PATTERN.test(value);
7191
7297
  }
7192
- function isPlainObject$5(value) {
7298
+ function isPlainObject$7(value) {
7193
7299
  return value !== null && typeof value === "object" && !Array.isArray(value);
7194
7300
  }
7195
7301
 
@@ -7438,7 +7544,7 @@ function crossStackSourceKey(source) {
7438
7544
  }
7439
7545
  if (key === "Fn::GetStackOutput") {
7440
7546
  const args = source[key];
7441
- if (!isPlainObject$5(args)) return void 0;
7547
+ if (!isPlainObject$7(args)) return void 0;
7442
7548
  const stackName = Object.hasOwn(args, "StackName") ? literalStringOrUndefined(args["StackName"]) : void 0;
7443
7549
  const outputName = Object.hasOwn(args, "OutputName") ? literalStringOrUndefined(args["OutputName"]) : void 0;
7444
7550
  if (stackName === void 0 || outputName === void 0) return void 0;
@@ -7484,7 +7590,7 @@ function crossStackSourceKey(source) {
7484
7590
  let template;
7485
7591
  let variables;
7486
7592
  if (typeof raw === "string") template = raw;
7487
- else if (Array.isArray(raw) && raw.length === 2 && isPlainObject$5(raw[1])) {
7593
+ else if (Array.isArray(raw) && raw.length === 2 && isPlainObject$7(raw[1])) {
7488
7594
  if (typeof raw[0] !== "string") return void 0;
7489
7595
  template = raw[0];
7490
7596
  variables = raw[1];
@@ -7727,12 +7833,12 @@ const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
7727
7833
  function recordNestedStackParameterExpressions(secrets, resourceType, resolvedProperties, sourceProperties, rules = TEMPLATE_DERIVED_RULES) {
7728
7834
  if (resourceType !== NESTED_STACK_RESOURCE_TYPE$4) return;
7729
7835
  if (secrets.size === 0) return;
7730
- if (!isPlainObject$5(resolvedProperties) || !isPlainObject$5(sourceProperties)) return;
7836
+ if (!isPlainObject$7(resolvedProperties) || !isPlainObject$7(sourceProperties)) return;
7731
7837
  if (!Object.hasOwn(resolvedProperties, "Parameters")) return;
7732
7838
  if (!Object.hasOwn(sourceProperties, "Parameters")) return;
7733
7839
  const resolvedParameters = resolvedProperties["Parameters"];
7734
7840
  const sourceParameters = sourceProperties["Parameters"];
7735
- if (!isPlainObject$5(resolvedParameters) || !isPlainObject$5(sourceParameters)) return;
7841
+ if (!isPlainObject$7(resolvedParameters) || !isPlainObject$7(sourceParameters)) return;
7736
7842
  const positioned = redactSecretsForState(markSameGenerationBag({ ...resolvedParameters }), secrets, sourceParameters, rules);
7737
7843
  let table = nestedStackParameterExpressions.get(secrets);
7738
7844
  for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
@@ -7781,7 +7887,7 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
7781
7887
  if (typeof resolvedValue !== "string") return void 0;
7782
7888
  const sourceLeaf = sourceParameters[name];
7783
7889
  if (typeof sourceLeaf === "string") return sourceLeaf;
7784
- if (!isPlainObject$5(sourceLeaf)) return void 0;
7890
+ if (!isPlainObject$7(sourceLeaf)) return void 0;
7785
7891
  const written = positioned[name];
7786
7892
  if (typeof written !== "string") return void 0;
7787
7893
  const rendered = intrinsicSkeletonSegments(sourceLeaf)?.map((s) => s === UNKNOWN_PART ? "\0" : s).join("");
@@ -7992,7 +8098,7 @@ function appendValuePlaceholderParts(value, out, budget, depth) {
7992
8098
  if (budget.exhausted) return;
7993
8099
  const literal = joinPartLiteralText(value);
7994
8100
  if (literal !== void 0) return pushPlaceholderPart(out, literal, budget);
7995
- if (isPlainObject$5(value) && Object.keys(value).length === 1) {
8101
+ if (isPlainObject$7(value) && Object.keys(value).length === 1) {
7996
8102
  const ref = value["Ref"];
7997
8103
  if (typeof ref === "string" && ref !== "") return pushPlaceholderPart(out, keyedPart({ Ref: ref }), budget);
7998
8104
  if (depth >= MAX_PLACEHOLDER_DEPTH) {
@@ -8024,7 +8130,7 @@ function appendParameterPlaceholderParts(source, out, budget, depth) {
8024
8130
  let template;
8025
8131
  let variables = {};
8026
8132
  if (typeof args === "string") template = args;
8027
- else if (Array.isArray(args) && args.length === 2 && isPlainObject$5(args[1])) {
8133
+ else if (Array.isArray(args) && args.length === 2 && isPlainObject$7(args[1])) {
8028
8134
  template = args[0];
8029
8135
  variables = args[1];
8030
8136
  } else return false;
@@ -8172,7 +8278,7 @@ function isUniquelyKeyedBy(items, key) {
8172
8278
  if (items.length === 0) return false;
8173
8279
  const seen = /* @__PURE__ */ new Set();
8174
8280
  for (const item of items) {
8175
- if (!isPlainObject$5(item) || !Object.hasOwn(item, key)) return false;
8281
+ if (!isPlainObject$7(item) || !Object.hasOwn(item, key)) return false;
8176
8282
  const id = item[key];
8177
8283
  if (typeof id !== "string" || id === "") return false;
8178
8284
  if (seen.has(id)) return false;
@@ -8202,11 +8308,11 @@ function redactByPath(bag, source, secrets, rules, secretExpressions, bagIsSameG
8202
8308
  }
8203
8309
  return positionByEmbeddedSpan(bag, source, secrets, bagIsSameGeneration);
8204
8310
  }
8205
- if ((typeof bag === "string" || Array.isArray(bag)) && isPlainObject$5(source)) {
8311
+ if ((typeof bag === "string" || Array.isArray(bag)) && isPlainObject$7(source)) {
8206
8312
  const inherited = positionByInheritedParameter(bag, source, secrets);
8207
8313
  if (inherited !== void 0) return inherited;
8208
8314
  }
8209
- if (typeof bag === "string" && isPlainObject$5(source)) {
8315
+ if (typeof bag === "string" && isPlainObject$7(source)) {
8210
8316
  const certified = positionByCrossStackSource(bag, source, secrets);
8211
8317
  if (certified !== void 0) return certified;
8212
8318
  const placeheld = positionByParameterPlaceholders(bag, source, secrets);
@@ -8216,7 +8322,7 @@ function redactByPath(bag, source, secrets, rules, secretExpressions, bagIsSameG
8216
8322
  const framed = positionByIntrinsicFrame(bag, source, secrets, secretExpressions, bagIsSameGeneration);
8217
8323
  if (framed !== void 0) return framed;
8218
8324
  }
8219
- if (Array.isArray(bag) && isPlainObject$5(source)) {
8325
+ if (Array.isArray(bag) && isPlainObject$7(source)) {
8220
8326
  const positionedList = positionListByCrossStackSource(bag, source, secrets);
8221
8327
  if (positionedList !== void 0) return positionedList;
8222
8328
  }
@@ -8244,7 +8350,7 @@ function redactByPath(bag, source, secrets, rules, secretExpressions, bagIsSameG
8244
8350
  }
8245
8351
  if (rules.descendArrays && bag.length === source.length) return bag.map((item, i) => redactByPath(item, source[i], secrets, rules, secretExpressions, bagIsSameGeneration));
8246
8352
  }
8247
- if (isPlainObject$5(bag) && hasPlainPrototype(bag) && isPlainObject$5(source)) {
8353
+ if (isPlainObject$7(bag) && hasPlainPrototype(bag) && isPlainObject$7(source)) {
8248
8354
  const out = Object.create(null);
8249
8355
  for (const [k, v] of Object.entries(bag)) out[k] = Object.hasOwn(source, k) ? redactByPath(v, source[k], secrets, rules, secretExpressions, bagIsSameGeneration) : redactSecretsForState(v, secrets);
8250
8356
  return out;
@@ -8257,7 +8363,7 @@ function isReadbackProjectedFromState(rules) {
8257
8363
  function subtreeHasDynamicReference(value) {
8258
8364
  if (isDynamicReferenceString(value)) return true;
8259
8365
  if (Array.isArray(value)) return value.some(subtreeHasDynamicReference);
8260
- if (isPlainObject$5(value)) return Object.values(value).some(subtreeHasDynamicReference);
8366
+ if (isPlainObject$7(value)) return Object.values(value).some(subtreeHasDynamicReference);
8261
8367
  return false;
8262
8368
  }
8263
8369
  function pathCrossesDottedKey(bag, path) {
@@ -8332,8 +8438,8 @@ function deepEqualJsonValue(a, b) {
8332
8438
  if (!Array.isArray(b) || a.length !== b.length) return false;
8333
8439
  return a.every((item, i) => deepEqualJsonValue(item, b[i]));
8334
8440
  }
8335
- if (isPlainObject$5(a)) {
8336
- if (!isPlainObject$5(b)) return false;
8441
+ if (isPlainObject$7(a)) {
8442
+ if (!isPlainObject$7(b)) return false;
8337
8443
  if (!hasPlainPrototype(a) || !hasPlainPrototype(b)) return false;
8338
8444
  const keys = Object.keys(a);
8339
8445
  if (keys.length !== Object.keys(b).length) return false;
@@ -8359,7 +8465,7 @@ function refuseUncertifiedSubtree(value, sourceLiterals, mark, seen = /* @__PURE
8359
8465
  for (const item of value) out.push(refuseUncertifiedSubtree(item, sourceLiterals, mark, seen));
8360
8466
  return out;
8361
8467
  }
8362
- if (isPlainObject$5(value) && hasPlainPrototype(value)) {
8468
+ if (isPlainObject$7(value) && hasPlainPrototype(value)) {
8363
8469
  const out = Object.create(null);
8364
8470
  seen.set(value, out);
8365
8471
  for (const [k, v] of Object.entries(value)) out[k] = refuseUncertifiedSubtree(v, sourceLiterals, mark, seen);
@@ -8387,7 +8493,7 @@ function refuseUncertifiedReadbackPositions(bag, source, secrets, failClosed, le
8387
8493
  return mark ? POSITION_DECIDED : source;
8388
8494
  }
8389
8495
  if (!subtreeHasDynamicReference(source)) return bag;
8390
- if (isPlainObject$5(bag) && hasPlainPrototype(bag) && isPlainObject$5(source)) {
8496
+ if (isPlainObject$7(bag) && hasPlainPrototype(bag) && isPlainObject$7(source)) {
8391
8497
  const out = Object.create(null);
8392
8498
  for (const [k, v] of Object.entries(bag)) out[k] = Object.hasOwn(source, k) ? refuseUncertifiedReadbackPositions(v, source[k], secrets, failClosed, learn, mark) : v;
8393
8499
  return out;
@@ -8414,14 +8520,14 @@ function refuseUncertifiedReadbackPositions(bag, source, secrets, failClosed, le
8414
8520
  function isDistinguishingAnchor(value) {
8415
8521
  if (typeof value === "string") return value !== "";
8416
8522
  if (Array.isArray(value)) return value.some(isDistinguishingAnchor);
8417
- if (isPlainObject$5(value)) return Object.values(value).some(isDistinguishingAnchor);
8523
+ if (isPlainObject$7(value)) return Object.values(value).some(isDistinguishingAnchor);
8418
8524
  return false;
8419
8525
  }
8420
8526
  const ANCHOR_REFERENCE_MASK = "<ref>";
8421
8527
  function anchorSignature(source) {
8422
8528
  if (isDynamicReferenceString(source)) return ANCHOR_REFERENCE_MASK;
8423
8529
  if (Array.isArray(source)) return `[${source.map(anchorSignature).sort().join(",")}]`;
8424
- if (isPlainObject$5(source)) return `{${Object.keys(source).sort().map((k) => `${JSON.stringify(k)}:${anchorSignature(source[k])}`).join(",")}}`;
8530
+ if (isPlainObject$7(source)) return `{${Object.keys(source).sort().map((k) => `${JSON.stringify(k)}:${anchorSignature(source[k])}`).join(",")}}`;
8425
8531
  return JSON.stringify(source) ?? "undefined";
8426
8532
  }
8427
8533
  function anchorsCorroboratePairing(bag, source, anchors) {
@@ -8431,8 +8537,8 @@ function anchorsCorroboratePairing(bag, source, anchors) {
8431
8537
  return true;
8432
8538
  }
8433
8539
  if (isDynamicReferenceString(source)) return typeof bag === "string";
8434
- if (isPlainObject$5(source)) {
8435
- if (!isPlainObject$5(bag)) return false;
8540
+ if (isPlainObject$7(source)) {
8541
+ if (!isPlainObject$7(bag)) return false;
8436
8542
  return Object.keys(source).every((k) => Object.hasOwn(bag, k) && anchorsCorroboratePairing(bag[k], source[k], anchors));
8437
8543
  }
8438
8544
  if (Array.isArray(source)) {
@@ -8523,13 +8629,13 @@ function learnMixedLeafNeedle(collector, bag, source) {
8523
8629
  learnNeedle(collector, plaintext, token);
8524
8630
  }
8525
8631
  function asChild(marks, key) {
8526
- return isPlainObject$5(marks) && hasPlainPrototype(marks) ? marks[key] : void 0;
8632
+ return isPlainObject$7(marks) && hasPlainPrototype(marks) ? marks[key] : void 0;
8527
8633
  }
8528
8634
  function asIndex(marks, index) {
8529
8635
  return Array.isArray(marks) ? marks[index] : void 0;
8530
8636
  }
8531
8637
  function preferPositionDecisions(scanned, refused, bag, marks, inferred) {
8532
- if (isPlainObject$5(bag) && hasPlainPrototype(bag) && isPlainObject$5(refused) && isPlainObject$5(scanned)) {
8638
+ if (isPlainObject$7(bag) && hasPlainPrototype(bag) && isPlainObject$7(refused) && isPlainObject$7(scanned)) {
8533
8639
  const out = Object.create(null);
8534
8640
  for (const [k, v] of Object.entries(refused)) out[k] = preferPositionDecisions(scanned[k], v, bag[k], asChild(marks, k), inferred);
8535
8641
  return out;
@@ -9039,6 +9145,11 @@ function passProvenanceFor(secrets, token) {
9039
9145
  if (entry === void 0) return void 0;
9040
9146
  return finalize(entry);
9041
9147
  }
9148
+ function passReadVersionsFor(secrets, token) {
9149
+ if (secrets === void 0) return void 0;
9150
+ const read = passProvenanceOf.get(secrets)?.get(token)?.readVersions;
9151
+ return read === void 0 || read.size === 0 ? void 0 : read;
9152
+ }
9042
9153
  function finalize(entry) {
9043
9154
  const out = {};
9044
9155
  if (!entry.regionUnknown && entry.regions.size === 1) out.region = [...entry.regions][0];
@@ -9171,9 +9282,10 @@ function isSameGenerationBag(bag) {
9171
9282
  //#region src/deployment/secret-redaction/mask-errors.ts
9172
9283
  function maskSecretsInText(text, secrets) {
9173
9284
  const logOnly = logOnlyValuesOf.get(secrets);
9174
- if (logOnly === void 0 || logOnly.size === 0) return maskRecordedSecretsInText(text, secrets);
9175
- if (text !== "" && (secrets.has(text) || logOnly.has(text))) return "***";
9176
- return maskMatchSpans(text, substringNeedles([...secrets.keys(), ...logOnly]), "***");
9285
+ const noLogOnly = logOnly === void 0 || logOnly.size === 0;
9286
+ if (secrets.size === 0 && noLogOnly) return text;
9287
+ if (text !== "" && (secrets.has(text) || logOnly?.has(text) === true)) return "***";
9288
+ return maskMatchSpans(text, printingNeedles(noLogOnly ? secrets.keys() : [...secrets.keys(), ...logOnly]), "***");
9177
9289
  }
9178
9290
  function maskRecordedSecretsInText(text, secrets) {
9179
9291
  if (secrets.size === 0) return text;
@@ -9537,7 +9649,7 @@ function createUnionSecretMasker(bags) {
9537
9649
  for (const plaintext of bag.keys()) needles.add(plaintext);
9538
9650
  for (const plaintext of logOnlyValuesOf.get(bag) ?? []) needles.add(plaintext);
9539
9651
  }
9540
- scanned = [...needles].filter((needle) => needle.length >= 4);
9652
+ scanned = printingNeedles(needles);
9541
9653
  stamp = now;
9542
9654
  }
9543
9655
  if (text !== "" && needles.has(text)) return "***";
@@ -9648,7 +9760,7 @@ function readsNoEchoSource(node, sources) {
9648
9760
  if (typeof argument === "string") return subStringReadsNoEcho(argument, void 0, sources);
9649
9761
  if (Array.isArray(argument)) {
9650
9762
  const [text, variables] = argument;
9651
- const vars = isPlainObject$5(variables) ? variables : void 0;
9763
+ const vars = isPlainObject$7(variables) ? variables : void 0;
9652
9764
  if (typeof text === "string" && subStringReadsNoEcho(text, vars, sources)) return true;
9653
9765
  return vars !== void 0 && Object.values(vars).some(walk);
9654
9766
  }
@@ -9682,7 +9794,7 @@ function noEchoCoordinatesOf(template, resolved, sources, onCoordinate) {
9682
9794
  parameters: sources.parameters,
9683
9795
  ...sources.conditions !== void 0 && { conditions: sources.conditions }
9684
9796
  };
9685
- const isBareDeclaredGetAtt = (node) => isPlainObject$5(node) && intrinsicKeyOf(node) === "Fn::GetAtt" && getAttReadsNoEcho(node["Fn::GetAtt"], sources);
9797
+ const isBareDeclaredGetAtt = (node) => isPlainObject$7(node) && intrinsicKeyOf(node) === "Fn::GetAtt" && getAttReadsNoEcho(node["Fn::GetAtt"], sources);
9686
9798
  const walk = (source, value, path) => {
9687
9799
  if (value === void 0) return;
9688
9800
  if (source === null || typeof source !== "object") return;
@@ -9698,7 +9810,7 @@ function noEchoCoordinatesOf(template, resolved, sources, onCoordinate) {
9698
9810
  const record = source;
9699
9811
  const intrinsic = intrinsicKeyOf(record);
9700
9812
  if (intrinsic === void 0) {
9701
- if (!isPlainObject$5(value)) {
9813
+ if (!isPlainObject$7(value)) {
9702
9814
  if (readsNoEchoSource(record, parametersOnly)) push(path, source);
9703
9815
  return;
9704
9816
  }
@@ -9746,7 +9858,7 @@ function maskWholeValue(value) {
9746
9858
  if (value === null || value === void 0) return value;
9747
9859
  if (typeof value === "string" && isSingleDynamicReferenceToken(value)) return value;
9748
9860
  if (Array.isArray(value)) return value.map(maskWholeValue);
9749
- if (isPlainObject$5(value)) {
9861
+ if (isPlainObject$7(value)) {
9750
9862
  const out = {};
9751
9863
  for (const [key, child] of Object.entries(value)) Object.defineProperty(out, key, {
9752
9864
  value: maskWholeValue(child),
@@ -9769,7 +9881,7 @@ function readAt(bag, coordinate) {
9769
9881
  node = node[segment];
9770
9882
  continue;
9771
9883
  }
9772
- if (!isPlainObject$5(node) || !Object.hasOwn(node, segment)) return {
9884
+ if (!isPlainObject$7(node) || !Object.hasOwn(node, segment)) return {
9773
9885
  found: false,
9774
9886
  value: void 0
9775
9887
  };
@@ -9785,7 +9897,7 @@ function valueAtCoordinate(bag, coordinate) {
9785
9897
  }
9786
9898
  function cloneContainer(node) {
9787
9899
  if (Array.isArray(node)) return [...node];
9788
- if (isPlainObject$5(node)) return { ...node };
9900
+ if (isPlainObject$7(node)) return { ...node };
9789
9901
  return node;
9790
9902
  }
9791
9903
  function maskAtCoordinates(bag, coordinates) {
@@ -9852,20 +9964,20 @@ function readbackPathFor(readback, properties, coordinate) {
9852
9964
  if (!Array.isArray(live)) return path.length === 0 ? void 0 : path;
9853
9965
  const key = Array.isArray(desired) ? identityKeyFor(live, desired) : void 0;
9854
9966
  const element = Array.isArray(desired) ? desired[segment] : void 0;
9855
- if (key === void 0 || !isPlainObject$5(element)) return path;
9967
+ if (key === void 0 || !isPlainObject$7(element)) return path;
9856
9968
  const identity = element[key];
9857
- const index = live.findIndex((item) => isPlainObject$5(item) && item[key] === identity);
9969
+ const index = live.findIndex((item) => isPlainObject$7(item) && item[key] === identity);
9858
9970
  if (index < 0) return path;
9859
9971
  path.push(index);
9860
9972
  live = live[index];
9861
9973
  desired = element;
9862
9974
  continue;
9863
9975
  }
9864
- if (!isPlainObject$5(live)) return path.length === 0 ? void 0 : path;
9976
+ if (!isPlainObject$7(live)) return path.length === 0 ? void 0 : path;
9865
9977
  if (!Object.hasOwn(live, segment)) return void 0;
9866
9978
  path.push(segment);
9867
9979
  live = live[segment];
9868
- desired = isPlainObject$5(desired) ? desired[segment] : void 0;
9980
+ desired = isPlainObject$7(desired) ? desired[segment] : void 0;
9869
9981
  }
9870
9982
  return path;
9871
9983
  }
@@ -9894,7 +10006,7 @@ function witnessNormalize(stored, today, v11) {
9894
10006
  const confirmed = [];
9895
10007
  const differing = [];
9896
10008
  const walk = (s, t, v, path) => {
9897
- if (v !== "***" && containsMask(v) && (Array.isArray(v) ? !Array.isArray(s) || s.length !== v.length : isPlainObject$5(v) ? !isPlainObject$5(s) : false)) {
10009
+ if (v !== "***" && containsMask(v) && (Array.isArray(v) ? !Array.isArray(s) || s.length !== v.length : isPlainObject$7(v) ? !isPlainObject$7(s) : false)) {
9898
10010
  if (s === void 0 || containsMask(s)) return s;
9899
10011
  if (jsonEqual(s, t)) {
9900
10012
  confirmed.push(path);
@@ -9923,8 +10035,8 @@ function witnessNormalize(stored, today, v11) {
9923
10035
  });
9924
10036
  return changed ? out : s;
9925
10037
  }
9926
- if (isPlainObject$5(v) && isPlainObject$5(s)) {
9927
- const tt = isPlainObject$5(t) ? t : {};
10038
+ if (isPlainObject$7(v) && isPlainObject$7(s)) {
10039
+ const tt = isPlainObject$7(t) ? t : {};
9928
10040
  let out;
9929
10041
  for (const key of Object.keys(v)) {
9930
10042
  if (!Object.hasOwn(s, key)) continue;
@@ -9947,7 +10059,7 @@ function witnessNormalize(stored, today, v11) {
9947
10059
  function containsMask(value) {
9948
10060
  if (value === "***") return true;
9949
10061
  if (Array.isArray(value)) return value.some(containsMask);
9950
- if (isPlainObject$5(value)) return Object.values(value).some(containsMask);
10062
+ if (isPlainObject$7(value)) return Object.values(value).some(containsMask);
9951
10063
  return false;
9952
10064
  }
9953
10065
  function jsonEqual(a, b) {
@@ -9991,7 +10103,7 @@ function noEchoComparison(options) {
9991
10103
  const out = node.map(walk);
9992
10104
  return out.some((item, i) => item !== node[i]) ? out : node;
9993
10105
  }
9994
- if (isPlainObject$5(node)) {
10106
+ if (isPlainObject$7(node)) {
9995
10107
  let out;
9996
10108
  for (const [key, child] of Object.entries(node)) {
9997
10109
  const next = walk(child);
@@ -11357,7 +11469,7 @@ const CREATE_ONLY_PATHS_SNAPSHOT = /* @__PURE__ */ new Map([
11357
11469
  ["AWS::AppSync::ApiKey", [["ApiId"]]],
11358
11470
  ["AWS::AppSync::DataSource", [["ApiId"], ["Name"]]],
11359
11471
  ["AWS::AppSync::GraphQLApi", []],
11360
- ["AWS::AppSync::GraphQLSchema", [["ApiId"]]],
11472
+ ["AWS::AppSync::GraphQLSchema", []],
11361
11473
  ["AWS::AppSync::Resolver", [
11362
11474
  ["ApiId"],
11363
11475
  ["FieldName"],
@@ -11372,7 +11484,7 @@ const CREATE_ONLY_PATHS_SNAPSHOT = /* @__PURE__ */ new Map([
11372
11484
  "BaseEvaluatorId"
11373
11485
  ], ["EvaluatorName"]]],
11374
11486
  ["AWS::BedrockAgentCore::Runtime", [["AgentRuntimeName"]]],
11375
- ["AWS::Budgets::Budget", [["NotificationsWithSubscribers"]]],
11487
+ ["AWS::Budgets::Budget", [["Budget", "BudgetName"], ["NotificationsWithSubscribers"]]],
11376
11488
  ["AWS::CertificateManager::Certificate", [
11377
11489
  ["CertificateAuthorityArn"],
11378
11490
  ["CertificateExport"],
@@ -11863,7 +11975,7 @@ const CREATE_ONLY_PATHS_SNAPSHOT = /* @__PURE__ */ new Map([
11863
11975
  ]],
11864
11976
  ["AWS::RDS::DBProxyTargetGroup", [["DBProxyName"], ["TargetGroupName"]]],
11865
11977
  ["AWS::RDS::DBSubnetGroup", [["DBSubnetGroupName"]]],
11866
- ["AWS::Route53::HostedZone", [["Name"]]],
11978
+ ["AWS::Route53::HostedZone", [["DelegationSetId"], ["Name"]]],
11867
11979
  ["AWS::Route53::RecordSet", [["HostedZoneId"], ["HostedZoneName"]]],
11868
11980
  ["AWS::S3::Bucket", [
11869
11981
  ["BucketName"],
@@ -12878,7 +12990,7 @@ function probeFoundSameId(resourceType, a, b) {
12878
12990
  //#region src/provisioning/config-shape.ts
12879
12991
  function readConfigString(container, key, fallback, containerPath, options) {
12880
12992
  if (container === void 0 || container === null) return fallback;
12881
- if (!isPlainObject$4(container) || isUnresolvedIntrinsicContainer(container)) {
12993
+ if (!isPlainObject$6(container) || isUnresolvedIntrinsicContainer(container)) {
12882
12994
  const detail = malformedShapeDetail(container);
12883
12995
  if (options?.onUnusable) {
12884
12996
  const named = fallback === "" ? "" : ` (${fallback})`;
@@ -12918,7 +13030,7 @@ function requireConfigArray(value, path, options) {
12918
13030
  return value;
12919
13031
  }
12920
13032
  function requireConfigObject(value, path, options) {
12921
- if (!isPlainObject$4(value) || isUnresolvedIntrinsicContainer(value)) {
13033
+ if (!isPlainObject$6(value) || isUnresolvedIntrinsicContainer(value)) {
12922
13034
  const detail = malformedShapeDetail(value);
12923
13035
  if (options?.onUnusable) {
12924
13036
  options.onUnusable(`${path} must be an object ${detail}. Leaving this configuration unapplied here; the same value is REFUSED on a template-path create.`);
@@ -12930,7 +13042,7 @@ function requireConfigObject(value, path, options) {
12930
13042
  }
12931
13043
  function configStringRefusal(container, key, fallback, containerPath, options) {
12932
13044
  if (container === void 0 || container === null) return void 0;
12933
- if (!isPlainObject$4(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
13045
+ if (!isPlainObject$6(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
12934
13046
  return configValueRefusal(container[key], fallback, `${containerPath}.${key}`, options);
12935
13047
  }
12936
13048
  function coerceCfnBoolean(value) {
@@ -12943,7 +13055,7 @@ function coerceCfnBoolean(value) {
12943
13055
  }
12944
13056
  function configBooleanRefusal(container, key, containerPath) {
12945
13057
  if (container === void 0 || container === null) return void 0;
12946
- if (!isPlainObject$4(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
13058
+ if (!isPlainObject$6(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
12947
13059
  const value = container[key];
12948
13060
  if (value === void 0) return void 0;
12949
13061
  if (coerceCfnBoolean(value) !== void 0) return void 0;
@@ -12957,7 +13069,7 @@ function coerceCfnInteger(value) {
12957
13069
  }
12958
13070
  function configIntegerRefusal(container, key, containerPath, min, max) {
12959
13071
  if (container === void 0 || container === null) return void 0;
12960
- if (!isPlainObject$4(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
13072
+ if (!isPlainObject$6(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
12961
13073
  const value = container[key];
12962
13074
  if (value === void 0) return void 0;
12963
13075
  const n = coerceCfnInteger(value);
@@ -12971,10 +13083,10 @@ function configValueRefusal(value, fallback, path, options) {
12971
13083
  if (typeof value !== "string" || value.trim() === "") return `${path} must be a non-empty string ${malformedShapeDetail(value)}`;
12972
13084
  }
12973
13085
  function malformedShapeDetail(value) {
12974
- if (isPlainObject$4(value) && isUnresolvedIntrinsicContainer(value)) return `(got ${describe(value)} — nothing substituted it before this call)`;
13086
+ if (isPlainObject$6(value) && isUnresolvedIntrinsicContainer(value)) return `(got ${describe(value)} — nothing substituted it before this call)`;
12975
13087
  return `(got ${describe(value)}) — check for an unresolved intrinsic or a mis-nested template value`;
12976
13088
  }
12977
- function isPlainObject$4(value) {
13089
+ function isPlainObject$6(value) {
12978
13090
  return typeof value === "object" && value !== null && !Array.isArray(value);
12979
13091
  }
12980
13092
  const NAMEABLE_INTRINSIC_KEYS = /* @__PURE__ */ new Set([
@@ -13001,7 +13113,7 @@ function describe(value) {
13001
13113
  if (value === null) return "null";
13002
13114
  if (Array.isArray(value)) return "an array";
13003
13115
  if (typeof value === "string") return value.trim() === "" ? "a blank string" : "a string";
13004
- if (isPlainObject$4(value) && isUnresolvedIntrinsicContainer(value)) {
13116
+ if (isPlainObject$6(value) && isUnresolvedIntrinsicContainer(value)) {
13005
13117
  const key = Object.keys(value)[0];
13006
13118
  return NAMEABLE_INTRINSIC_KEYS.has(key) ? `an unresolved ${key} intrinsic` : "an unresolved intrinsic";
13007
13119
  }
@@ -14323,7 +14435,7 @@ const PROPERTY_COVERAGE_BY_TYPE = /* @__PURE__ */ new Map([
14323
14435
  ]),
14324
14436
  silentDrop: /* @__PURE__ */ new Map(),
14325
14437
  createOnlyDrops: /* @__PURE__ */ new Set(),
14326
- readOnly: /* @__PURE__ */ new Set(["AnomalyDetectorId"]),
14438
+ readOnly: /* @__PURE__ */ new Set(["Id"]),
14327
14439
  ccRouteUnavailable: true
14328
14440
  }],
14329
14441
  ["AWS::CodeBuild::Project", {
@@ -16186,8 +16298,8 @@ const PROPERTY_COVERAGE_BY_TYPE = /* @__PURE__ */ new Map([
16186
16298
  "QueryLoggingConfig",
16187
16299
  "VPCs"
16188
16300
  ]),
16189
- silentDrop: /* @__PURE__ */ new Map(),
16190
- createOnlyDrops: /* @__PURE__ */ new Set(),
16301
+ silentDrop: /* @__PURE__ */ new Map([["DelegationSetId", "not yet implemented by cdkd"]]),
16302
+ createOnlyDrops: /* @__PURE__ */ new Set(["DelegationSetId"]),
16191
16303
  readOnly: /* @__PURE__ */ new Set(["Id", "NameServers"]),
16192
16304
  ccRouteUnavailable: false
16193
16305
  }],
@@ -17891,7 +18003,7 @@ function maskedPropertyFingerprint(templateValue) {
17891
18003
  return `${FINGERPRINT_PREFIX}${digest}`;
17892
18004
  }
17893
18005
  var UnknownInput = class extends Error {};
17894
- function isPlainObject$3(value) {
18006
+ function isPlainObject$5(value) {
17895
18007
  return value !== null && typeof value === "object" && !Array.isArray(value);
17896
18008
  }
17897
18009
  const DYNAMIC_REFERENCE_OPEN = "{{resolve:";
@@ -17911,7 +18023,7 @@ function carriesSecretValue(value, corpora) {
17911
18023
  return false;
17912
18024
  }
17913
18025
  function parameterInputsFor(args) {
17914
- const declared = isPlainObject$3(args.template.Parameters) ? args.template.Parameters : {};
18026
+ const declared = isPlainObject$5(args.template.Parameters) ? args.template.Parameters : {};
17915
18027
  const values = args.values ?? {};
17916
18028
  const inputs = /* @__PURE__ */ new Map();
17917
18029
  const bound = {};
@@ -17922,7 +18034,7 @@ function parameterInputsFor(args) {
17922
18034
  continue;
17923
18035
  }
17924
18036
  const value = values[name];
17925
- let secret = isPlainObject$3(definition) && declaresNoEcho(definition) || carriesSecretValue(value, []);
18037
+ let secret = isPlainObject$5(definition) && declaresNoEcho(definition) || carriesSecretValue(value, []);
17926
18038
  if (!secret && args.nestedChild === true && args.supplied !== void 0) {
17927
18039
  if (Object.hasOwn(args.supplied, name)) {
17928
18040
  const passed = args.passedClasses?.get(name);
@@ -17973,7 +18085,7 @@ function intrinsicKey(value) {
17973
18085
  const OPAQUE_ATTRIBUTE_TYPES = /* @__PURE__ */ new Set(["AWS::CloudFormation::CustomResource", NESTED_STACK_TYPE$4]);
17974
18086
  function hasOpaqueAttributes(logicalId, walk) {
17975
18087
  const definition = walk.resources[logicalId];
17976
- const type = isPlainObject$3(definition) ? definition["Type"] : void 0;
18088
+ const type = isPlainObject$5(definition) ? definition["Type"] : void 0;
17977
18089
  return typeof type === "string" && (type.startsWith("Custom::") || OPAQUE_ATTRIBUTE_TYPES.has(type));
17978
18090
  }
17979
18091
  function getAttTarget(operand) {
@@ -17998,7 +18110,7 @@ function taintOf(logicalId, walk) {
17998
18110
  const visit = (value) => {
17999
18111
  if (typeof value === "string") return value.includes(DYNAMIC_REFERENCE_OPEN);
18000
18112
  if (Array.isArray(value)) return value.some(visit);
18001
- if (!isPlainObject$3(value)) return false;
18113
+ if (!isPlainObject$5(value)) return false;
18002
18114
  const key = intrinsicKey(value);
18003
18115
  const operand = key === void 0 ? void 0 : value[key];
18004
18116
  let verdict = "clean";
@@ -18010,7 +18122,7 @@ function taintOf(logicalId, walk) {
18010
18122
  else if (key === "Fn::FindInMap" && mapReadClass(operand, walk.sources.template) !== "clean") verdict = "tainted";
18011
18123
  else if (key === "Fn::Sub") {
18012
18124
  const text = Array.isArray(operand) ? operand[0] : operand;
18013
- const vars = Array.isArray(operand) && isPlainObject$3(operand[1]) ? operand[1] : {};
18125
+ const vars = Array.isArray(operand) && isPlainObject$5(operand[1]) ? operand[1] : {};
18014
18126
  if (typeof text === "string") for (const name of subPlaceholders(text)) {
18015
18127
  if (Object.hasOwn(vars, name)) continue;
18016
18128
  const owner = name.includes(".") ? name.split(".")[0] : name;
@@ -18024,7 +18136,7 @@ function taintOf(logicalId, walk) {
18024
18136
  return Object.values(value).some(visit);
18025
18137
  };
18026
18138
  const definition = walk.resources[logicalId];
18027
- const result = visit(isPlainObject$3(definition) ? definition["Properties"] : void 0) ? "tainted" : unknown ? "unknown" : "clean";
18139
+ const result = visit(isPlainObject$5(definition) ? definition["Properties"] : void 0) ? "tainted" : unknown ? "unknown" : "clean";
18028
18140
  walk.inProgress.delete(logicalId);
18029
18141
  walk.taint.set(logicalId, result);
18030
18142
  return result;
@@ -18040,7 +18152,7 @@ function conditionInput(name, walk) {
18040
18152
  return typeof verdict === "boolean" ? verdict : "unknown";
18041
18153
  }
18042
18154
  function conditionClosure(name, walk) {
18043
- const definitions = isPlainObject$3(walk.sources.template.Conditions) ? walk.sources.template.Conditions : {};
18155
+ const definitions = isPlainObject$5(walk.sources.template.Conditions) ? walk.sources.template.Conditions : {};
18044
18156
  let secret = false;
18045
18157
  let unknown = false;
18046
18158
  let unread = false;
@@ -18055,7 +18167,7 @@ function conditionClosure(name, walk) {
18055
18167
  value.forEach(visit);
18056
18168
  return;
18057
18169
  }
18058
- if (!isPlainObject$3(value)) return;
18170
+ if (!isPlainObject$5(value)) return;
18059
18171
  const keys = Object.keys(value);
18060
18172
  if (keys.length === 1 && keys[0] === "Condition" && typeof value["Condition"] === "string") {
18061
18173
  pending.push(value["Condition"]);
@@ -18088,7 +18200,7 @@ function conditionClosure(name, walk) {
18088
18200
  if (key === "Fn::Sub") {
18089
18201
  const operand = value["Fn::Sub"];
18090
18202
  const text = Array.isArray(operand) ? operand[0] : operand;
18091
- const vars = Array.isArray(operand) && isPlainObject$3(operand[1]) ? operand[1] : {};
18203
+ const vars = Array.isArray(operand) && isPlainObject$5(operand[1]) ? operand[1] : {};
18092
18204
  if (typeof text === "string") for (const name of subPlaceholders(text)) {
18093
18205
  if (Object.hasOwn(vars, name)) continue;
18094
18206
  if (name.includes(".") && !name.startsWith("AWS::")) secret = true;
@@ -18117,8 +18229,8 @@ function mapReadClass(operand, template) {
18117
18229
  const mapName = Array.isArray(operand) ? operand[0] : void 0;
18118
18230
  if (typeof mapName !== "string") return "unknown";
18119
18231
  const mappings = template.Mappings;
18120
- const map = isPlainObject$3(mappings) && Object.hasOwn(mappings, mapName) ? mappings[mapName] : void 0;
18121
- if (!isPlainObject$3(map)) return "unknown";
18232
+ const map = isPlainObject$5(mappings) && Object.hasOwn(mappings, mapName) ? mappings[mapName] : void 0;
18233
+ if (!isPlainObject$5(map)) return "unknown";
18122
18234
  return carriesSecretValue(map, []) ? "secret" : "clean";
18123
18235
  }
18124
18236
  async function resolvedInput(node, walk) {
@@ -18186,7 +18298,7 @@ async function inputForm(value, walk) {
18186
18298
  concrete: parts.every((p) => p.concrete)
18187
18299
  };
18188
18300
  }
18189
- if (!isPlainObject$3(value)) return {
18301
+ if (!isPlainObject$5(value)) return {
18190
18302
  form: value,
18191
18303
  concrete: true
18192
18304
  };
@@ -18249,7 +18361,7 @@ async function inputForm(value, walk) {
18249
18361
  concrete: false
18250
18362
  };
18251
18363
  }
18252
- const explicit = Array.isArray(operand) && isPlainObject$3(operand[1]) ? operand[1] : {};
18364
+ const explicit = Array.isArray(operand) && isPlainObject$5(operand[1]) ? operand[1] : {};
18253
18365
  const vars = await inputForm(explicit, walk);
18254
18366
  const placeholders = [];
18255
18367
  let concrete = vars.concrete && !text.includes(DYNAMIC_REFERENCE_OPEN);
@@ -18302,8 +18414,8 @@ function newWalk(sources, nested = {
18302
18414
  }) {
18303
18415
  return {
18304
18416
  sources,
18305
- resources: isPlainObject$3(sources.template.Resources) ? sources.template.Resources : {},
18306
- parameters: isPlainObject$3(sources.template.Parameters) ? sources.template.Parameters : {},
18417
+ resources: isPlainObject$5(sources.template.Resources) ? sources.template.Resources : {},
18418
+ parameters: isPlainObject$5(sources.template.Parameters) ? sources.template.Parameters : {},
18307
18419
  taint: /* @__PURE__ */ new Map(),
18308
18420
  inProgress: /* @__PURE__ */ new Set(),
18309
18421
  stackChain: nested.stackChain,
@@ -18327,34 +18439,34 @@ function passedKey(passed) {
18327
18439
  function isNestedStackRow(logicalId, walk) {
18328
18440
  if (!Object.hasOwn(walk.resources, logicalId)) return false;
18329
18441
  const definition = walk.resources[logicalId];
18330
- return isPlainObject$3(definition) && definition["Type"] === NESTED_STACK_TYPE$4;
18442
+ return isPlainObject$5(definition) && definition["Type"] === NESTED_STACK_TYPE$4;
18331
18443
  }
18332
18444
  function getAttAttribute(operand, target) {
18333
18445
  if (Array.isArray(operand)) return operand.length === 2 && typeof operand[1] === "string" ? operand[1] : void 0;
18334
18446
  return typeof operand === "string" ? operand.slice(target.length + 1) : void 0;
18335
18447
  }
18336
18448
  function rowParameters(definition) {
18337
- const properties = isPlainObject$3(definition) ? definition["Properties"] : void 0;
18449
+ const properties = isPlainObject$5(definition) ? definition["Properties"] : void 0;
18338
18450
  if (properties === void 0) return {};
18339
- if (!isPlainObject$3(properties)) return "unknown";
18451
+ if (!isPlainObject$5(properties)) return "unknown";
18340
18452
  const parameters = properties["Parameters"];
18341
18453
  if (parameters === void 0) return {};
18342
- if (!isPlainObject$3(parameters) || intrinsicKey(parameters) !== void 0) return "unknown";
18454
+ if (!isPlainObject$5(parameters) || intrinsicKey(parameters) !== void 0) return "unknown";
18343
18455
  return parameters;
18344
18456
  }
18345
18457
  function childParameterInputs(template, passed) {
18346
- const declared = isPlainObject$3(template.Parameters) ? template.Parameters : {};
18458
+ const declared = isPlainObject$5(template.Parameters) ? template.Parameters : {};
18347
18459
  const inputs = /* @__PURE__ */ new Map();
18348
18460
  for (const name of Object.keys(declared)) {
18349
18461
  const definition = declared[name];
18350
- if (isPlainObject$3(definition) && declaresNoEcho(definition)) inputs.set(name, { kind: "secret" });
18462
+ if (isPlainObject$5(definition) && declaresNoEcho(definition)) inputs.set(name, { kind: "secret" });
18351
18463
  else if (passed.has(name)) {
18352
18464
  const passedClass = passed.get(name);
18353
18465
  inputs.set(name, passedClass === "clean" ? {
18354
18466
  kind: "value",
18355
18467
  value: void 0
18356
18468
  } : passedClass === "unknown" ? { kind: "unknown" } : { kind: "secret" });
18357
- } else if (isPlainObject$3(definition) && Object.hasOwn(definition, "Default") && !carriesSecretValue(definition["Default"], [])) inputs.set(name, {
18469
+ } else if (isPlainObject$5(definition) && Object.hasOwn(definition, "Default") && !carriesSecretValue(definition["Default"], [])) inputs.set(name, {
18358
18470
  kind: "value",
18359
18471
  value: definition["Default"]
18360
18472
  });
@@ -18371,7 +18483,7 @@ function closureClass(closure) {
18371
18483
  return closure.unread ? "unread" : "clean";
18372
18484
  }
18373
18485
  async function childOutputClass(loaded, outputName, passed, chain, shared) {
18374
- if (loaded === void 0 || !isPlainObject$3(loaded.template)) return "unknown";
18486
+ if (loaded === void 0 || !isPlainObject$5(loaded.template)) return "unknown";
18375
18487
  const scopeKey = JSON.stringify([loaded.identity, passedKey(passed)]);
18376
18488
  const memoKey = JSON.stringify([scopeKey, outputName]);
18377
18489
  const memo = shared.outputs.get(memoKey);
@@ -18384,8 +18496,8 @@ async function classifyChildOutput(loaded, outputName, passed, chain, shared, sc
18384
18496
  if (++shared.steps > MAX_NESTED_OUTPUT_STEPS) return "unknown";
18385
18497
  if (chain.includes(loaded.identity) || chain.length >= MAX_NESTED_OUTPUT_DEPTH) return "unknown";
18386
18498
  const template = loaded.template;
18387
- const output = (isPlainObject$3(template.Outputs) ? template.Outputs : {})[outputName];
18388
- if (!isPlainObject$3(output) || !Object.hasOwn(output, "Value")) return "unknown";
18499
+ const output = (isPlainObject$5(template.Outputs) ? template.Outputs : {})[outputName];
18500
+ if (!isPlainObject$5(output) || !Object.hasOwn(output, "Value")) return "unknown";
18389
18501
  const scope = {
18390
18502
  walk: newWalk({
18391
18503
  template,
@@ -18457,7 +18569,7 @@ async function expressionClass(value, scope) {
18457
18569
  return result;
18458
18570
  };
18459
18571
  if (Array.isArray(value)) return all(value);
18460
- if (!isPlainObject$3(value)) return "clean";
18572
+ if (!isPlainObject$5(value)) return "clean";
18461
18573
  const key = intrinsicKey(value);
18462
18574
  if (key === void 0) return all(Object.values(value));
18463
18575
  const operand = value[key];
@@ -18472,7 +18584,7 @@ async function expressionClass(value, scope) {
18472
18584
  case "Fn::Sub": {
18473
18585
  const text = Array.isArray(operand) ? operand[0] : operand;
18474
18586
  if (typeof text !== "string") return worseOf("unknown", await expressionClass(operand, scope));
18475
- const vars = Array.isArray(operand) && isPlainObject$3(operand[1]) ? operand[1] : {};
18587
+ const vars = Array.isArray(operand) && isPlainObject$5(operand[1]) ? operand[1] : {};
18476
18588
  let result = text.includes(DYNAMIC_REFERENCE_OPEN) ? "secret" : "clean";
18477
18589
  result = worseOf(result, await all(Object.values(vars)));
18478
18590
  for (const name of subPlaceholders(text)) {
@@ -18550,7 +18662,7 @@ async function classifyPassedParameters(parameters, sources) {
18550
18662
  }
18551
18663
  async function classifyPassed(parameters, sources, nested) {
18552
18664
  const classes = /* @__PURE__ */ new Map();
18553
- if (!isPlainObject$3(parameters)) return classes;
18665
+ if (!isPlainObject$5(parameters)) return classes;
18554
18666
  for (const [name, expression] of Object.entries(parameters)) {
18555
18667
  let passedClass;
18556
18668
  try {
@@ -18591,7 +18703,7 @@ function possiblyMaskedKeys(resolvedProps, corpora) {
18591
18703
  const wholeShortLeaf = (value) => {
18592
18704
  if (typeof value === "string") return short.includes(value);
18593
18705
  if (Array.isArray(value)) return value.some(wholeShortLeaf);
18594
- if (isPlainObject$3(value)) return Object.values(value).some(wholeShortLeaf);
18706
+ if (isPlainObject$5(value)) return Object.values(value).some(wholeShortLeaf);
18595
18707
  return false;
18596
18708
  };
18597
18709
  return Object.keys(resolvedProps).filter((key) => {
@@ -18622,7 +18734,7 @@ function maskedPropertyFingerprintsOf(record) {
18622
18734
  const read = /* @__PURE__ */ new Map();
18623
18735
  if (record === null || typeof record !== "object") return read;
18624
18736
  const field = record.maskedPropertyFingerprints;
18625
- if (!isPlainObject$3(field)) return read;
18737
+ if (!isPlainObject$5(field)) return read;
18626
18738
  for (const [key, value] of Object.entries(field)) if (typeof value === "string" && value.startsWith(FINGERPRINT_PREFIX)) read.set(key, value);
18627
18739
  return read;
18628
18740
  }
@@ -18630,7 +18742,7 @@ function maskedPropertyInputFingerprintsOf(record) {
18630
18742
  const read = /* @__PURE__ */ new Map();
18631
18743
  if (record === null || typeof record !== "object") return read;
18632
18744
  const field = record.maskedPropertyInputFingerprints;
18633
- if (!isPlainObject$3(field)) return read;
18745
+ if (!isPlainObject$5(field)) return read;
18634
18746
  const text = maskedPropertyFingerprintsOf(record);
18635
18747
  for (const [key, value] of Object.entries(field)) {
18636
18748
  if (typeof value !== "string" || !value.startsWith(INPUT_FINGERPRINT_PREFIX)) continue;
@@ -18677,7 +18789,7 @@ async function movedMaskedProperties(record, templateProps, fingerprinter, onReb
18677
18789
  function withRebaselinedFingerprints(record, fingerprints) {
18678
18790
  const text = maskedPropertyFingerprintsOf(record);
18679
18791
  const field = record.maskedPropertyInputFingerprints;
18680
- const next = isPlainObject$3(field) ? Object.entries(field) : [];
18792
+ const next = isPlainObject$5(field) ? Object.entries(field) : [];
18681
18793
  let changed = false;
18682
18794
  for (const [key, value] of Object.entries(fingerprints)) {
18683
18795
  if (text.get(key) !== splitInputFingerprint(value).text) continue;
@@ -18710,10 +18822,10 @@ function withMaskedPropertyFingerprints(scrubbed, writtenBag, templateProps, sec
18710
18822
  fingerprints = maskedPropertyFingerprintsFor(scrubbed.properties, templateProps);
18711
18823
  inputs = boundInputFingerprints(fingerprints, inputFingerprints);
18712
18824
  } else {
18713
- if (!isPlainObject$3(previous)) return scrubbed;
18825
+ if (!isPlainObject$5(previous)) return scrubbed;
18714
18826
  if (corpora.length === 0) return scrubbed;
18715
18827
  fingerprints = { ...previous };
18716
- inputs = isPlainObject$3(previousInputs) ? { ...previousInputs } : void 0;
18828
+ inputs = isPlainObject$5(previousInputs) ? { ...previousInputs } : void 0;
18717
18829
  }
18718
18830
  if (fingerprints !== void 0 && corpora.length > 0) {
18719
18831
  const refused = Object.keys(fingerprints).filter((key) => Object.hasOwn(templateProps, key) && corpora.some((corpus) => templateCarriesNeedle(templateProps[key], corpus)));
@@ -19697,11 +19809,11 @@ function validReferenceRegion(region) {
19697
19809
  if (typeof region !== "string") return void 0;
19698
19810
  return canonicalizeRegion(region) === region && isClientSafeRegion(region) ? region : void 0;
19699
19811
  }
19700
- function isPlainObject$2(value) {
19812
+ function isPlainObject$4(value) {
19701
19813
  return value !== null && typeof value === "object" && !Array.isArray(value);
19702
19814
  }
19703
19815
  function validateReferenceProvenance(token, raw) {
19704
- if (!isSingleDynamicReferenceToken(token) || !isPlainObject$2(raw)) return void 0;
19816
+ if (!isSingleDynamicReferenceToken(token) || !isPlainObject$4(raw)) return void 0;
19705
19817
  const versionsRaw = Object.hasOwn(raw, "versions") ? raw["versions"] : void 0;
19706
19818
  const readRaw = Object.hasOwn(raw, "readVersions") ? raw["readVersions"] : void 0;
19707
19819
  if (readRaw !== void 0) {
@@ -19719,11 +19831,11 @@ function validateReferenceProvenance(token, raw) {
19719
19831
  return out;
19720
19832
  }
19721
19833
  function referenceProvenanceOf(record) {
19722
- if (!isPlainObject$2(record) || !Object.hasOwn(record, "referenceProvenance")) return void 0;
19834
+ if (!isPlainObject$4(record) || !Object.hasOwn(record, "referenceProvenance")) return void 0;
19723
19835
  return validatedBag(record["referenceProvenance"]);
19724
19836
  }
19725
19837
  function validatedBag(field) {
19726
- if (!isPlainObject$2(field)) return void 0;
19838
+ if (!isPlainObject$4(field)) return void 0;
19727
19839
  const out = Object.create(null);
19728
19840
  for (const [token, raw] of Object.entries(field)) {
19729
19841
  const entry = validateReferenceProvenance(token, raw);
@@ -19732,9 +19844,9 @@ function validatedBag(field) {
19732
19844
  return { ...out };
19733
19845
  }
19734
19846
  function recordedProvenanceOf(record, token) {
19735
- if (!isPlainObject$2(record) || !Object.hasOwn(record, "referenceProvenance")) return void 0;
19847
+ if (!isPlainObject$4(record) || !Object.hasOwn(record, "referenceProvenance")) return void 0;
19736
19848
  const field = record["referenceProvenance"];
19737
- if (!isPlainObject$2(field) || !Object.hasOwn(field, token)) return void 0;
19849
+ if (!isPlainObject$4(field) || !Object.hasOwn(field, token)) return void 0;
19738
19850
  return validateReferenceProvenance(token, field[token]);
19739
19851
  }
19740
19852
  function recordedReferenceRegions(record) {
@@ -19756,7 +19868,7 @@ function regionsOf(field) {
19756
19868
  function keepHeldTokenProvenance(record) {
19757
19869
  if (!hasReferenceProvenanceField(record)) return record;
19758
19870
  const field = record.referenceProvenance;
19759
- if (!isPlainObject$2(field)) return record;
19871
+ if (!isPlainObject$4(field)) return record;
19760
19872
  const held = recordReferenceTokens(record);
19761
19873
  const keys = Object.keys(field);
19762
19874
  if (keys.every((token) => held.has(token))) return record;
@@ -19768,12 +19880,12 @@ function keepHeldTokenProvenance(record) {
19768
19880
  };
19769
19881
  }
19770
19882
  function hasReferenceProvenanceField(record) {
19771
- return isPlainObject$2(record) && Object.hasOwn(record, "referenceProvenance") && record["referenceProvenance"] !== void 0;
19883
+ return isPlainObject$4(record) && Object.hasOwn(record, "referenceProvenance") && record["referenceProvenance"] !== void 0;
19772
19884
  }
19773
19885
  function outputReferenceProvenanceOf(state, outputKey) {
19774
- if (!isPlainObject$2(state) || !Object.hasOwn(state, "outputReferenceProvenance")) return;
19886
+ if (!isPlainObject$4(state) || !Object.hasOwn(state, "outputReferenceProvenance")) return;
19775
19887
  const field = state["outputReferenceProvenance"];
19776
- if (!isPlainObject$2(field) || !Object.hasOwn(field, outputKey)) return void 0;
19888
+ if (!isPlainObject$4(field) || !Object.hasOwn(field, outputKey)) return void 0;
19777
19889
  return validatedBag(field[outputKey]);
19778
19890
  }
19779
19891
  function persistable(token, entry) {
@@ -19791,7 +19903,7 @@ function tokensUnderPaths(properties, paths) {
19791
19903
  for (const item of value) descend(item, path, next);
19792
19904
  return;
19793
19905
  }
19794
- if (isPlainObject$2(value) && Object.hasOwn(value, path[at])) descend(value[path[at]], path, at + 1);
19906
+ if (isPlainObject$4(value) && Object.hasOwn(value, path[at])) descend(value[path[at]], path, at + 1);
19795
19907
  };
19796
19908
  for (const path of paths) descend(properties, path, 0);
19797
19909
  return out;
@@ -19834,7 +19946,7 @@ function unionWithPrevious(pass, before) {
19834
19946
  }
19835
19947
  function outputProvenanceForPersist(args) {
19836
19948
  const { outputs, resolvedThisRun, carriedFrom, sinkOf } = args;
19837
- if (!resolvedThisRun) return carriedFrom !== void 0 && isPlainObject$2(carriedFrom.outputReferenceProvenance) ? carriedFrom.outputReferenceProvenance : void 0;
19949
+ if (!resolvedThisRun) return carriedFrom !== void 0 && isPlainObject$4(carriedFrom.outputReferenceProvenance) ? carriedFrom.outputReferenceProvenance : void 0;
19838
19950
  let out;
19839
19951
  for (const [outputKey, value] of Object.entries(outputs)) {
19840
19952
  const sink = sinkOf(outputKey);
@@ -19868,20 +19980,37 @@ function tokensOf(value) {
19868
19980
  }
19869
19981
  function recordedTokenRoutes(value, record) {
19870
19982
  if (!hasReferenceProvenanceField(record)) return void 0;
19983
+ return routesOf(tokensOf(value), (token) => recordedProvenanceOf(record, token));
19984
+ }
19985
+ function provenanceTokenRoutes(value, bag) {
19986
+ if (bag === void 0) return void 0;
19987
+ return routesOf(tokensOf(value), (token) => Object.hasOwn(bag, token) ? bag[token] : void 0);
19988
+ }
19989
+ function routesOf(tokens, entryOf) {
19871
19990
  const routes = /* @__PURE__ */ new Map();
19872
19991
  let recorded = false;
19873
- for (const token of tokensOf(value)) {
19874
- const entry = recordedProvenanceOf(record, token);
19992
+ for (const token of tokens) {
19993
+ const entry = entryOf(token);
19875
19994
  const region = entry?.region;
19876
19995
  const pin = entry?.versions?.length === 1 ? entry.versions[0] : void 0;
19877
19996
  if (region !== void 0 || pin !== void 0) recorded = true;
19878
19997
  routes.set(token, {
19879
19998
  region,
19880
- pin
19999
+ pin,
20000
+ ...entry?.versions !== void 0 && { versions: entry.versions }
19881
20001
  });
19882
20002
  }
19883
20003
  return recorded ? routes : void 0;
19884
20004
  }
20005
+ function recordedTokenVersions(value, record) {
20006
+ if (!hasReferenceProvenanceField(record)) return void 0;
20007
+ let out;
20008
+ for (const token of tokensOf(value)) {
20009
+ const versions = recordedProvenanceOf(record, token)?.versions;
20010
+ if (versions !== void 0 && versions.length > 0) (out ??= /* @__PURE__ */ new Map()).set(token, versions);
20011
+ }
20012
+ return out;
20013
+ }
19885
20014
  async function reresolveByRecordedRoutes(resolver, value, logicalId, context, origin, sourceKey, routes, defaults) {
19886
20015
  const tokens = [...routes.keys()];
19887
20016
  const regionOf = (token) => routes.get(token)?.region ?? defaults.region;
@@ -19918,9 +20047,12 @@ async function reresolveByRecordedRoutes(resolver, value, logicalId, context, or
19918
20047
  return value;
19919
20048
  }
19920
20049
  }
19921
- const walkContext = pins.size > 0 ? {
20050
+ const readVersions = /* @__PURE__ */ new Map();
20051
+ for (const [token, route] of routes) if (route.versions !== void 0 && route.versions.length > 0) readVersions.set(token, route.versions);
20052
+ const walkContext = pins.size > 0 || readVersions.size > 0 ? {
19922
20053
  ...context,
19923
- referencePins: pins
20054
+ ...pins.size > 0 && { referencePins: pins },
20055
+ ...readVersions.size > 0 && { recordedReadVersions: readVersions }
19924
20056
  } : context;
19925
20057
  const regions = new Set(tokens.map((token) => regionOf(token) ?? ""));
19926
20058
  if (regions.size <= 1) {
@@ -20545,7 +20677,11 @@ async function reresolveRecordedReferences(value, logicalId, context, origin, so
20545
20677
  servingAsRecordedLine();
20546
20678
  return value;
20547
20679
  }
20548
- return await this.reresolveCrossStackValue(value, void 0, context, origin, sourceKey);
20680
+ const readVersions = recordedTokenVersions(value, record);
20681
+ return await this.reresolveCrossStackValue(value, void 0, readVersions === void 0 ? context : {
20682
+ ...context,
20683
+ recordedReadVersions: readVersions
20684
+ }, origin, sourceKey);
20549
20685
  }
20550
20686
  async function referencesMatchPhysicalId(value, logicalId, context, routeOf) {
20551
20687
  const record = Object.hasOwn(context.resources, logicalId) ? context.resources[logicalId] : void 0;
@@ -20800,6 +20936,13 @@ function healMaskedOwnIdAttribute(logicalId, resource, attributeName, stored, co
20800
20936
  //#endregion
20801
20937
  //#region src/deployment/intrinsic-resolver/cross-stack.ts
20802
20938
  async function reresolveCrossStackValue(value, producerRegion, context, origin, sourceKey, producerOutput, producerRegionLogText) {
20939
+ if (context.crossStackReads !== void 0 && producerOutput !== void 0 && producerOutput.crossAccount !== true && sourceKey !== void 0) context.crossStackReads.set(sourceKey, {
20940
+ stackName: producerOutput.stackName,
20941
+ region: producerOutput.region || this.resolverRegion || "",
20942
+ outputKey: producerOutput.outputKey,
20943
+ carriesToken: carriesDynamicReference(value),
20944
+ ...producerOutput.state !== void 0 && { state: producerOutput.state }
20945
+ });
20803
20946
  if (carriesSecretMask(value)) {
20804
20947
  const recovered = producerOutput === void 0 || producerOutput.crossAccount === true ? void 0 : recoverMaskedOutput(credentialFingerprint(ambientCredentialConfig()), producerOutput.stackName, producerOutput.region, producerOutput.outputKey);
20805
20948
  if (recovered !== void 0) {
@@ -20824,11 +20967,16 @@ async function reresolveCrossStackValue(value, producerRegion, context, origin,
20824
20967
  if (context.recordedSecretValues !== void 0 && producerOutput !== void 0 && producerOutput.crossAccount !== true && context.stateBackend !== void 0 && context.skipDynamicReferences !== true) {
20825
20968
  const plain = [...wholeStringLeavesOf(value)].filter((leaf) => !leaf.includes("{{resolve:") && !carriesSecretMask(leaf));
20826
20969
  if (plain.length > 0) {
20827
- const ids = await producerPhysicalIds(context.recordedImports ?? context.recordedSecretValues, context.stateBackend, producerOutput.stackName, producerOutput.region || this.resolverRegion, () => this.logger.debug(safeMsg`Could not read the state of producer ${this.displayMasked(producerOutput.stackName, context)} for its physical ids; no cross-stack copy of one is kept (go-to-k/cdkd#4819)`));
20970
+ const ids = physicalIdsOf(await producerStateOnce(this.resolverRegion, context, producerOutput, () => this.logger.debug(safeMsg`Could not read the state of producer ${this.displayMasked(producerOutput.stackName, context)} for its physical ids; no cross-stack copy of one is kept (go-to-k/cdkd#4819)`)));
20828
20971
  for (const leaf of plain) if (ids.has(leaf)) recordPhysicalNameCopy(context.recordedSecretValues, leaf);
20829
20972
  }
20830
20973
  }
20831
20974
  if (!carriesDynamicReference(value)) return value;
20975
+ if (producerOutput !== void 0 && producerOutput.crossAccount !== true && context.recordedSecretValues !== void 0 && context.skipDynamicReferences !== true && context.provenanceCapture !== true) {
20976
+ const state = await producerStateOnce(this.resolverRegion, context, producerOutput, () => this.logger.debug(safeMsg`Could not read the state of producer ${this.displayMasked(producerOutput.stackName, context)} for its recorded secret versions; its output is resolved at the current version`));
20977
+ const routes = provenanceTokenRoutes(value, outputReferenceProvenanceOf(state, producerOutput.outputKey));
20978
+ if (routes !== void 0) return await reresolveByRecordedRoutes(this, value, producerOutput.stackName, context, origin, sourceKey, routes, { region: producerRegion || void 0 });
20979
+ }
20832
20980
  const resolver = this.resolverForProducerRegion(producerRegion, context, producerRegionLogText);
20833
20981
  const pinnedContext = {
20834
20982
  ...producerRegion ? withoutProducerRegions(context) : context,
@@ -20917,7 +21065,8 @@ async function resolveImportValue(importValueArg, context) {
20917
21065
  found = {
20918
21066
  value,
20919
21067
  refStack,
20920
- lookupRegion
21068
+ lookupRegion,
21069
+ state
20921
21070
  };
20922
21071
  break;
20923
21072
  }
@@ -20929,7 +21078,8 @@ async function resolveImportValue(importValueArg, context) {
20929
21078
  if (found) return await this.reresolveCrossStackValue(found.value, found.lookupRegion, context, `Fn::ImportValue ${quotedRender(this.displayLeaf(exportName, context), "'")} (producer ${this.displayLeaf(found.refStack, context)} / ${this.displayLeaf(found.lookupRegion, context)})`, sourceKey, {
20930
21079
  stackName: found.refStack,
20931
21080
  region: found.lookupRegion,
20932
- outputKey: exportName
21081
+ outputKey: exportName,
21082
+ state: found.state
20933
21083
  });
20934
21084
  if (this.cfnFallback) {
20935
21085
  const cfnExport = await this.lookupCfnExport(exportName, context);
@@ -20949,32 +21099,60 @@ function recordImport(context, exportName, producerStack, producerRegion) {
20949
21099
  sourceRegion: producerRegion
20950
21100
  });
20951
21101
  }
20952
- const producerPhysicalIdReads = /* @__PURE__ */ new WeakMap();
20953
- function producerPhysicalIds(scope, stateBackend, stackName, region, onFailure) {
20954
- let reads = producerPhysicalIdReads.get(scope);
21102
+ const producerStateReads = /* @__PURE__ */ new WeakMap();
21103
+ async function readProducerStateOnce(scope, stateBackend, stackName, region, onFailure, inHand) {
21104
+ let reads = producerStateReads.get(scope);
20955
21105
  if (reads === void 0) {
20956
21106
  reads = /* @__PURE__ */ new Map();
20957
- producerPhysicalIdReads.set(scope, reads);
21107
+ producerStateReads.set(scope, reads);
20958
21108
  }
20959
21109
  const key = JSON.stringify([stackName, region]);
20960
21110
  let read = reads.get(key);
20961
21111
  if (read === void 0) {
20962
- read = (async () => {
20963
- const ids = /* @__PURE__ */ new Set();
21112
+ read = inHand !== void 0 ? Promise.resolve({
21113
+ state: inHand,
21114
+ failed: false
21115
+ }) : (async () => {
21116
+ if (stateBackend === void 0) return {
21117
+ state: void 0,
21118
+ failed: false
21119
+ };
20964
21120
  try {
20965
- const data = await stateBackend.getState(stackName, region);
20966
- for (const record of Object.values(data?.state.resources ?? {})) {
20967
- const id = record?.physicalId;
20968
- if (typeof id === "string" && id !== "") ids.add(id);
20969
- }
21121
+ return {
21122
+ state: (await stateBackend.getState(stackName, region))?.state ?? void 0,
21123
+ failed: false
21124
+ };
20970
21125
  } catch {
20971
- onFailure();
21126
+ return {
21127
+ state: void 0,
21128
+ failed: true
21129
+ };
20972
21130
  }
20973
- return ids;
20974
21131
  })();
20975
21132
  reads.set(key, read);
20976
21133
  }
20977
- return read;
21134
+ const { state, failed } = await read;
21135
+ if (failed) onFailure();
21136
+ return state;
21137
+ }
21138
+ function producerStateOnce(resolverRegion, context, producerOutput, onFailure) {
21139
+ return readProducerStateOnce(context.recordedImports ?? context.recordedSecretValues ?? context, context.stateBackend, producerOutput.stackName, producerOutput.region || resolverRegion || "", onFailure, producerOutput.state);
21140
+ }
21141
+ const physicalIdsByState = /* @__PURE__ */ new WeakMap();
21142
+ function physicalIdsOf(state) {
21143
+ if (state === void 0) return /* @__PURE__ */ new Set();
21144
+ let ids = physicalIdsByState.get(state);
21145
+ if (ids === void 0) {
21146
+ const out = /* @__PURE__ */ new Set();
21147
+ const resources = state.resources;
21148
+ if (resources !== null && typeof resources === "object") for (const record of Object.values(resources)) {
21149
+ const id = record?.physicalId;
21150
+ if (typeof id === "string" && id !== "") out.add(id);
21151
+ }
21152
+ ids = out;
21153
+ physicalIdsByState.set(state, ids);
21154
+ }
21155
+ return ids;
20978
21156
  }
20979
21157
 
20980
21158
  //#endregion
@@ -21517,7 +21695,7 @@ async function resolveGetStackOutput(arg, context) {
21517
21695
  stackName,
21518
21696
  region,
21519
21697
  outputKey: outputName,
21520
- ...roleArn ? { crossAccount: true } : {}
21698
+ ...roleArn ? { crossAccount: true } : { state: stateData.state }
21521
21699
  }, loggedRegionText);
21522
21700
  }
21523
21701
  function recordOutputRead(context, producerStack, producerRegion, outputName) {
@@ -21637,13 +21815,19 @@ function secretVerdictScope(resolver) {
21637
21815
  }
21638
21816
  function recordProvenanceOfResolution(resolver, context, token, version) {
21639
21817
  if (context === void 0 || context.provenanceSuppressed === true) return;
21640
- const resolution = {
21641
- region: canonicalizeRegion(resolver.explicitRegion),
21642
- version,
21643
- route: context.provenanceRoute ?? "literal"
21644
- };
21645
- if (context.recordedSecretValues !== void 0) recordReferenceResolution(context.recordedSecretValues, token, resolution);
21646
- if (context.provenanceSink !== void 0) recordReferenceResolution(context.provenanceSink, token, resolution);
21818
+ const route = context.provenanceRoute ?? "literal";
21819
+ const region = canonicalizeRegion(resolver.explicitRegion);
21820
+ const recorded = route === "read" ? context.recordedReadVersions?.get(token) : void 0;
21821
+ const versions = recorded !== void 0 && recorded.length > 0 ? recorded : [version];
21822
+ for (const one of versions) {
21823
+ const resolution = {
21824
+ region,
21825
+ version: one,
21826
+ route
21827
+ };
21828
+ if (context.recordedSecretValues !== void 0) recordReferenceResolution(context.recordedSecretValues, token, resolution);
21829
+ if (context.provenanceSink !== void 0) recordReferenceResolution(context.provenanceSink, token, resolution);
21830
+ }
21647
21831
  }
21648
21832
  async function resolveDynamicReferences(value, context) {
21649
21833
  return (await this.resolveDynamicReferencesWithLogTwin(value, value, context, void 0, true)).result;
@@ -23426,6 +23610,101 @@ IntrinsicFunctionResolver.prototype.noteRefStateMask = noteRefStateMask;
23426
23610
  IntrinsicFunctionResolver.prototype.clientsForRegion = clientsForRegion;
23427
23611
  IntrinsicFunctionResolver.prototype.serviceDiscoveryClient = serviceDiscoveryClient;
23428
23612
 
23613
+ //#endregion
23614
+ //#region src/analyzer/read-provenance-promotion.ts
23615
+ function isPlainObject$3(value) {
23616
+ return value !== null && typeof value === "object" && !Array.isArray(value);
23617
+ }
23618
+ function readsAcrossStacks(value) {
23619
+ if (Array.isArray(value)) return value.some(readsAcrossStacks);
23620
+ if (!isPlainObject$3(value)) return false;
23621
+ if (Object.hasOwn(value, "Fn::ImportValue") || Object.hasOwn(value, "Fn::GetStackOutput")) return true;
23622
+ return Object.values(value).some(readsAcrossStacks);
23623
+ }
23624
+ function recordedReadVersions(record) {
23625
+ if (!isPlainObject$3(record) || !Object.hasOwn(record, "referenceProvenance")) return void 0;
23626
+ const field = referenceProvenanceOf(record);
23627
+ if (field === void 0) return void 0;
23628
+ let out;
23629
+ for (const [token, entry] of Object.entries(field)) if (entry.readVersions !== void 0 && entry.readVersions.length > 0) (out ??= /* @__PURE__ */ new Map()).set(token, entry.readVersions);
23630
+ return out;
23631
+ }
23632
+ async function readProvenancePromotions(args) {
23633
+ const { currentState, desiredTemplate, sources } = args;
23634
+ const parser = args.parser ?? new TemplateParser();
23635
+ const records = currentState.resources;
23636
+ const parameters = isPlainObject$3(desiredTemplate.Parameters) ? desiredTemplate.Parameters : void 0;
23637
+ const out = [];
23638
+ for (const { logicalId, changeType } of args.rows) {
23639
+ if (changeType !== "NO_CHANGE" && changeType !== "UPDATE") continue;
23640
+ const record = Object.hasOwn(records, logicalId) ? records[logicalId] : void 0;
23641
+ const readVersions = recordedReadVersions(record);
23642
+ if (readVersions === void 0) continue;
23643
+ const resource = Object.hasOwn(desiredTemplate.Resources, logicalId) ? desiredTemplate.Resources[logicalId] : void 0;
23644
+ const properties = isPlainObject$3(resource?.Properties) ? resource.Properties : {};
23645
+ const reads = [];
23646
+ for (const [key, value] of Object.entries(properties)) {
23647
+ const referenced = [...parser.extractReferences(value)].filter((id) => id !== logicalId);
23648
+ const resourceIds = referenced.filter((id) => Object.hasOwn(desiredTemplate.Resources, id));
23649
+ const readsParameter = parameters !== void 0 && referenced.some((id) => Object.hasOwn(parameters, id));
23650
+ const crossStack = readsAcrossStacks(value);
23651
+ if (resourceIds.length === 0 && !readsParameter && !crossStack) continue;
23652
+ reads.push({
23653
+ key,
23654
+ value,
23655
+ resources: resourceIds,
23656
+ parameters: readsParameter,
23657
+ crossStack
23658
+ });
23659
+ }
23660
+ if (reads.length === 0) continue;
23661
+ let crossStackBags = [];
23662
+ if (sources?.crossStackOutputs !== void 0) {
23663
+ const crossValues = reads.filter((r) => r.crossStack).map((r) => r.value);
23664
+ if (crossValues.length > 0) crossStackBags = await sources.crossStackOutputs(crossValues);
23665
+ }
23666
+ const upstreamIds = new Set(reads.flatMap((r) => r.resources));
23667
+ const readsAnyParameter = reads.some((r) => r.parameters);
23668
+ const moved = [];
23669
+ for (const [token, recorded] of readVersions) {
23670
+ const domain = /* @__PURE__ */ new Set();
23671
+ let member = false;
23672
+ const join = (versions) => {
23673
+ if (versions === void 0 || versions.length === 0) return;
23674
+ member = true;
23675
+ for (const version of versions) domain.add(version);
23676
+ };
23677
+ for (const id of upstreamIds) {
23678
+ const upstream = Object.hasOwn(records, id) ? records[id] : void 0;
23679
+ join(recordedProvenanceOf(upstream, token)?.versions);
23680
+ }
23681
+ if (readsAnyParameter && sources?.inherited !== void 0) join(sources.inherited.get(token)?.versions);
23682
+ for (const bag of crossStackBags) if (Object.hasOwn(bag, token)) join(bag[token]?.versions);
23683
+ if (!member) continue;
23684
+ if (recorded.some((version) => !domain.has(version))) moved.push(token);
23685
+ }
23686
+ if (moved.length === 0) continue;
23687
+ const recordProperties = isPlainObject$3(record?.properties) ? record.properties : {};
23688
+ const keys = [];
23689
+ for (const r of reads) {
23690
+ if (!Object.hasOwn(recordProperties, r.key)) continue;
23691
+ const held = referenceTokensIn(recordProperties[r.key]);
23692
+ if (!moved.some((token) => held.has(token))) continue;
23693
+ keys.push({
23694
+ key: r.key,
23695
+ upstreams: r.resources
23696
+ });
23697
+ }
23698
+ if (keys.length === 0) continue;
23699
+ out.push({
23700
+ logicalId,
23701
+ keys,
23702
+ tokens: moved
23703
+ });
23704
+ }
23705
+ return out;
23706
+ }
23707
+
23429
23708
  //#endregion
23430
23709
  //#region src/analyzer/diff-calculator.ts
23431
23710
  const INTRINSIC_KEYS = /* @__PURE__ */ new Set([
@@ -23470,7 +23749,7 @@ var DiffCalculator = class DiffCalculator {
23470
23749
  conditionalReplacementVerdict(resourceType, propertyPath, oldValue, newValue) {
23471
23750
  return this.replacementRules.conditionalReplacementVerdict(resourceType, propertyPath, oldValue, newValue);
23472
23751
  }
23473
- async calculateDiff(currentState, desiredTemplate, resolveFn, canonicalizeProperties, allowedUnsupportedProperties, freshParameters, maskForLog, recreateTargets, maskedInputs, refusalRecovery, noEchoCompare) {
23752
+ async calculateDiff(currentState, desiredTemplate, resolveFn, canonicalizeProperties, allowedUnsupportedProperties, freshParameters, maskForLog, recreateTargets, maskedInputs, refusalRecovery, noEchoCompare, readProvenance) {
23474
23753
  const changes = /* @__PURE__ */ new Map();
23475
23754
  refuseMalformedResourceEntriesForDeploy(currentState, void 0, void 0, refusalRecovery);
23476
23755
  refuseMalformedResourceProperties(currentState, void 0, void 0, refusalRecovery);
@@ -23600,7 +23879,12 @@ var DiffCalculator = class DiffCalculator {
23600
23879
  const changeType = changes.get(logicalId)?.changeType;
23601
23880
  if (changeType === "NO_CHANGE" || changeType === "UPDATE") forcedReplacements.add(logicalId);
23602
23881
  }
23882
+ const provenanceChanges = await this.promoteReadProvenanceDependents(changes, currentState, desiredTemplate, readProvenance);
23603
23883
  const syntheticCreateOnlyPaths = await this.loadSyntheticCreateOnlyPaths(changes, desiredTemplate, rawGetAttRefs, freshParameters, forcedReplacements);
23884
+ for (const { change, pc, upstreams } of provenanceChanges) {
23885
+ const templateValue = desiredTemplate.Resources[change.logicalId]?.Properties?.[pc.path];
23886
+ pc.requiresReplacement = this.syntheticRequiresReplacement(change.resourceType, pc.path, syntheticCreateOnlyPaths, upstreams.some((id) => isPlainReferenceTo(templateValue, id, desiredTemplate.Resources[id]?.Type)));
23887
+ }
23604
23888
  do
23605
23889
  this.promoteReplacementDependents(changes, desiredTemplate, syntheticCreateOnlyPaths, forcedReplacements);
23606
23890
  while (this.promoteInPlaceAttributeDependents(changes, desiredTemplate, rawGetAttRefs, syntheticCreateOnlyPaths, freshParameters));
@@ -23608,6 +23892,47 @@ var DiffCalculator = class DiffCalculator {
23608
23892
  this.logger.debug(`Diff calculated: ${summary.create} CREATE, ${summary.update} UPDATE, ${summary.delete} DELETE, ${summary.noChange} NO_CHANGE`);
23609
23893
  return changes;
23610
23894
  }
23895
+ async promoteReadProvenanceDependents(changes, currentState, desiredTemplate, sources) {
23896
+ if (isKnownTokenFreeState(currentState)) return [];
23897
+ const promotions = await readProvenancePromotions({
23898
+ rows: changes.values(),
23899
+ currentState,
23900
+ desiredTemplate,
23901
+ sources,
23902
+ parser: this.parser
23903
+ });
23904
+ const out = [];
23905
+ for (const promotion of promotions) {
23906
+ const change = changes.get(promotion.logicalId);
23907
+ if (change === void 0) continue;
23908
+ const existingPaths = new Set((change.propertyChanges ?? []).map((pc) => pc.path));
23909
+ const synthetic = [];
23910
+ for (const { key, upstreams } of promotion.keys) {
23911
+ if (existingPaths.has(key)) continue;
23912
+ const pc = {
23913
+ path: key,
23914
+ oldValue: change.currentProperties?.[key],
23915
+ newValue: change.desiredProperties?.[key],
23916
+ requiresReplacement: false,
23917
+ inPlacePropagated: true,
23918
+ readProvenancePromoted: true
23919
+ };
23920
+ synthetic.push(pc);
23921
+ out.push({
23922
+ change,
23923
+ pc,
23924
+ upstreams
23925
+ });
23926
+ }
23927
+ if (synthetic.length === 0) continue;
23928
+ if (change.changeType === "NO_CHANGE") {
23929
+ change.changeType = "UPDATE";
23930
+ change.propertyChanges = synthetic;
23931
+ } else change.propertyChanges = [...change.propertyChanges ?? [], ...synthetic];
23932
+ this.logger.debug(safeMsg`UPDATE (promoted): ${promotion.logicalId} holds a secret reference read at a version its upstream no longer records (${synthetic.map((pc) => pc.path).join(", ")})`);
23933
+ }
23934
+ return out;
23935
+ }
23611
23936
  async loadSyntheticCreateOnlyPaths(changes, desiredTemplate, rawGetAttRefs, freshParameters, forcedReplacements) {
23612
23937
  const loaded = /* @__PURE__ */ new Map();
23613
23938
  const queue = [...freshParameters ?? []];
@@ -24809,8 +25134,8 @@ function compare(desired, previous, mask) {
24809
25134
  if (!Array.isArray(desired) || desired.length !== previous.length) return "differs";
24810
25135
  return combine(previous.map((item, i) => compare(desired[i], item, mask)));
24811
25136
  }
24812
- if (isPlainObject$1(previous)) {
24813
- if (!isPlainObject$1(desired)) return "differs";
25137
+ if (isPlainObject$2(previous)) {
25138
+ if (!isPlainObject$2(desired)) return "differs";
24814
25139
  if (!Object.keys(desired).every((k) => Object.prototype.hasOwnProperty.call(previous, k))) return "differs";
24815
25140
  return combine(Object.keys(previous).map((k) => compare(desired[k], previous[k], mask)));
24816
25141
  }
@@ -24836,7 +25161,7 @@ function resolvesReference(desired, previous, mask) {
24836
25161
  const pattern = literals.map(escapeRegExp$1).join("[\\s\\S]*");
24837
25162
  return new RegExp(`^${pattern}$`).test(desired);
24838
25163
  }
24839
- function isPlainObject$1(value) {
25164
+ function isPlainObject$2(value) {
24840
25165
  return typeof value === "object" && value !== null && !Array.isArray(value);
24841
25166
  }
24842
25167
  function escapeRegExp$1(text) {
@@ -25627,7 +25952,7 @@ var CloudControlProvider = class {
25627
25952
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
25628
25953
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
25629
25954
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
25630
- const { ASGProvider } = await import("./asg-provider-CsBxbRlH.js");
25955
+ const { ASGProvider } = await import("./asg-provider-DZv4iAmI.js");
25631
25956
  const delegateRegion = ambientRegion();
25632
25957
  let asgProvider = this.asgDeleteDelegates.get(delegateRegion);
25633
25958
  if (asgProvider === void 0) {
@@ -25733,7 +26058,7 @@ var CloudControlProvider = class {
25733
26058
  const family = SDK_DELETE_FAMILIES.get(resourceType);
25734
26059
  const cached = this.sdkDeleteDelegates.get(family);
25735
26060
  if (cached !== void 0 && cached.region === ccRegion) return cached.provider;
25736
- const provider = family === "rds" ? new (await (import("./rds-provider-d15q7Rp5.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-C81KkPPG.js"))).NeptuneProvider({ region: ccRegion });
26061
+ const provider = family === "rds" ? new (await (import("./rds-provider-J60TlCOp.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-BHEUW4UW.js"))).NeptuneProvider({ region: ccRegion });
25737
26062
  this.sdkDeleteDelegates.set(family, {
25738
26063
  region: ccRegion,
25739
26064
  provider
@@ -25961,7 +26286,8 @@ var CloudControlProvider = class {
25961
26286
  const causeText = safeDisplay === "" ? "" : `: ${safeDisplay}`;
25962
26287
  if (described.detail !== "") this.logger.debug(`${operation} ${logicalId}: the abandoned operation's underlying failure was: ${displaySafe(described.detail)}`);
25963
26288
  const identifierClause = lastSeenIdentifier === void 0 ? "" : ` The last status cdkd read named the resource ${displaySafe(lastSeenIdentifier, { asciiOnly: true })}.`;
25964
- const error = new CloudControlWaitAbandonedError(`${operation} of ${logicalId} was accepted by Cloud Control API, but cdkd stopped waiting for it (${reason}${causeText}). The operation may still be running in AWS, and ${operation === "CREATE" ? "cdkd has NO state record for it, so any resource it creates is untracked by rollback and by cdkd destroy" : operation === "DELETE" ? "the resource may or may not have been removed; its state record is kept so a re-run can finish the delete" : "its state record still holds the PREVIOUS properties, so the record may no longer describe the live resource"}.${identifierClause} Check what it did with:\n ${await this.buildResumeCommand(requestToken)}`, resourceType, logicalId, requestToken, operation, lastSeenIdentifier, cause instanceof Error ? cause : void 0);
26289
+ const consequence = operation === "CREATE" ? "cdkd has NO state record for it, so any resource it creates is untracked by rollback and by cdkd destroy" : operation === "DELETE" ? "the resource may or may not have been removed; its state record is kept so a re-run can finish the delete" : "its state record still holds the PREVIOUS properties, so the record may no longer describe the live resource";
26290
+ const error = new CloudControlWaitAbandonedError(safeMsg`${operation} of ${logicalId} was accepted by Cloud Control API, but cdkd stopped waiting for it ` + safeMsg`(${reason}${causeText}). The operation may still be running in AWS, and ${consequence}.` + `${identifierClause} Check what it did with:\n ${await this.buildResumeCommand(requestToken)}`, resourceType, logicalId, requestToken, operation, lastSeenIdentifier, cause instanceof Error ? cause : void 0);
25965
26291
  if (described.marker) markRedactedCause(error);
25966
26292
  return operation === "CREATE" ? markNonRetryable(error) : error;
25967
26293
  }
@@ -29545,6 +29871,7 @@ const PROPERTY_SHAPES = /* @__PURE__ */ new Map([
29545
29871
  ["AWS::AutoScaling::AutoScalingGroup", "{\"AvailabilityZoneDistribution\":\"object\",\"AvailabilityZoneIds\":\"array\",\"AvailabilityZoneImpairmentPolicy\":\"object\",\"AvailabilityZones\":\"array\",\"CapacityReservationSpecification\":\"object\",\"CapacityReservationSpecification.CapacityReservationTarget\":\"object\",\"CapacityReservationSpecification.CapacityReservationTarget.CapacityReservationIds\":\"array\",\"CapacityReservationSpecification.CapacityReservationTarget.CapacityReservationResourceGroupArns\":\"array\",\"InstanceLifecyclePolicy\":\"object\",\"InstanceLifecyclePolicy.RetentionTriggers\":\"object\",\"InstanceMaintenancePolicy\":\"object\",\"LaunchTemplate\":\"object\",\"LifecycleHookSpecificationList\":\"array\",\"LifecycleHookSpecificationList[]\":\"object\",\"LoadBalancerNames\":\"array\",\"MetricsCollection\":\"array\",\"MetricsCollection[]\":\"object\",\"MetricsCollection[].Metrics\":\"array\",\"MixedInstancesPolicy\":\"object\",\"MixedInstancesPolicy.InstancesDistribution\":\"object\",\"MixedInstancesPolicy.InstancesDistribution.DistributionSegments\":\"array\",\"MixedInstancesPolicy.InstancesDistribution.DistributionSegments[]\":\"object\",\"MixedInstancesPolicy.InstancesDistribution.DistributionSegments[].TargetCapacityTypes\":\"array\",\"MixedInstancesPolicy.LaunchTemplate\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[]\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.AcceleratorCount\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.AcceleratorManufacturers\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.AcceleratorNames\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.AcceleratorTotalMemoryMiB\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.AcceleratorTypes\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.AllowedInstanceTypes\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.BaselineEbsBandwidthMbps\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.BaselinePerformanceFactors\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.BaselinePerformanceFactors.Cpu\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.BaselinePerformanceFactors.Cpu.References\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.BaselinePerformanceFactors.Cpu.References[]\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.CpuManufacturers\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.ExcludedInstanceTypes\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.InstanceGenerations\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.LocalStorageTypes\":\"array\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.MemoryGiBPerVCpu\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.MemoryMiB\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.NetworkBandwidthGbps\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.NetworkInterfaceCount\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.TotalLocalStorageGB\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].InstanceRequirements.VCpuCount\":\"object\",\"MixedInstancesPolicy.LaunchTemplate.Overrides[].LaunchTemplateSpecification\":\"object\",\"NotificationConfiguration\":\"object\",\"NotificationConfiguration.NotificationTypes\":\"array\",\"NotificationConfigurations\":\"array\",\"NotificationConfigurations[]\":\"object\",\"NotificationConfigurations[].NotificationTypes\":\"array\",\"Tags\":\"array\",\"Tags[]\":\"object\",\"TargetGroupARNs\":\"array\",\"TerminationPolicies\":\"array\",\"TrafficSources\":\"array\",\"TrafficSources[]\":\"object\",\"VPCZoneIdentifier\":\"array\"}"],
29546
29872
  ["AWS::BedrockAgentCore::Evaluator", "{\"EvaluatorConfig\":\"object\",\"EvaluatorConfig.CodeBased\":\"object\",\"EvaluatorConfig.CodeBased.LambdaConfig\":\"object\",\"EvaluatorConfig.Derived\":\"object\",\"EvaluatorConfig.Derived.ModelConfig\":\"object\",\"EvaluatorConfig.Derived.ModelConfig.BedrockEvaluatorModelConfig\":\"object\",\"EvaluatorConfig.Derived.ModelConfig.BedrockEvaluatorModelConfig.AdditionalModelRequestFields\":\"object\",\"EvaluatorConfig.Derived.ModelConfig.BedrockEvaluatorModelConfig.InferenceConfig\":\"object\",\"EvaluatorConfig.Derived.ModelConfig.BedrockEvaluatorModelConfig.InferenceConfig.StopSequences\":\"array\",\"EvaluatorConfig.Derived.ModelConfig.ResponsesEvaluatorModelConfig\":\"object\",\"EvaluatorConfig.Derived.ModelConfig.ResponsesEvaluatorModelConfig.Reasoning\":\"object\",\"EvaluatorConfig.LlmAsAJudge\":\"object\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig\":\"object\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig.BedrockEvaluatorModelConfig\":\"object\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig.BedrockEvaluatorModelConfig.AdditionalModelRequestFields\":\"object\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig.BedrockEvaluatorModelConfig.InferenceConfig\":\"object\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig.BedrockEvaluatorModelConfig.InferenceConfig.StopSequences\":\"array\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig.ResponsesEvaluatorModelConfig\":\"object\",\"EvaluatorConfig.LlmAsAJudge.ModelConfig.ResponsesEvaluatorModelConfig.Reasoning\":\"object\",\"EvaluatorConfig.LlmAsAJudge.RatingScale\":\"object\",\"EvaluatorConfig.LlmAsAJudge.RatingScale.Categorical\":\"array\",\"EvaluatorConfig.LlmAsAJudge.RatingScale.Categorical[]\":\"object\",\"EvaluatorConfig.LlmAsAJudge.RatingScale.Numerical\":\"array\",\"EvaluatorConfig.LlmAsAJudge.RatingScale.Numerical[]\":\"object\",\"Tags\":\"array\",\"Tags[]\":\"object\"}"],
29547
29873
  ["AWS::BedrockAgentCore::Runtime", "{\"AgentRuntimeArtifact\":\"object\",\"AgentRuntimeArtifact.CodeConfiguration\":\"object\",\"AgentRuntimeArtifact.CodeConfiguration.Code\":\"object\",\"AgentRuntimeArtifact.CodeConfiguration.Code.S3\":\"object\",\"AgentRuntimeArtifact.CodeConfiguration.EntryPoint\":\"array\",\"AgentRuntimeArtifact.ContainerConfiguration\":\"object\",\"AuthorizerConfiguration\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedAudience\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedClients\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedScopes\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedWorkloadConfiguration\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedWorkloadConfiguration.HostingEnvironments\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedWorkloadConfiguration.HostingEnvironments[]\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.AllowedWorkloadConfiguration.WorkloadIdentities\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.CustomClaims\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.CustomClaims[]\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.CustomClaims[].AuthorizingClaimMatchValue\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.CustomClaims[].AuthorizingClaimMatchValue.ClaimMatchValue\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.CustomClaims[].AuthorizingClaimMatchValue.ClaimMatchValue.MatchValueStringList\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpoint\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpoint.ManagedVpcResource\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpoint.ManagedVpcResource.SecurityGroupIds\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpoint.ManagedVpcResource.SubnetIds\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpoint.ManagedVpcResource.Tags\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpoint.SelfManagedLatticeResource\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[]\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[].PrivateEndpoint\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[].PrivateEndpoint.ManagedVpcResource\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[].PrivateEndpoint.ManagedVpcResource.SecurityGroupIds\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[].PrivateEndpoint.ManagedVpcResource.SubnetIds\":\"array\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[].PrivateEndpoint.ManagedVpcResource.Tags\":\"object\",\"AuthorizerConfiguration.CustomJWTAuthorizer.PrivateEndpointOverrides[].PrivateEndpoint.SelfManagedLatticeResource\":\"object\",\"CapacityProviderConfiguration\":\"object\",\"EnvironmentVariables\":\"object\",\"FilesystemConfigurations\":\"array\",\"FilesystemConfigurations[]\":\"object\",\"FilesystemConfigurations[].CapacityProviderVolume\":\"object\",\"FilesystemConfigurations[].EfsAccessPoint\":\"object\",\"FilesystemConfigurations[].S3FilesAccessPoint\":\"object\",\"FilesystemConfigurations[].SessionStorage\":\"object\",\"LifecycleConfiguration\":\"object\",\"NetworkConfiguration\":\"object\",\"NetworkConfiguration.NetworkModeConfig\":\"object\",\"NetworkConfiguration.NetworkModeConfig.SecurityGroups\":\"array\",\"NetworkConfiguration.NetworkModeConfig.Subnets\":\"array\",\"RequestHeaderConfiguration\":\"object\",\"RequestHeaderConfiguration.RequestHeaderAllowlist\":\"array\",\"Tags\":\"object\",\"WorkloadIdentityDetails\":\"object\"}"],
29874
+ ["AWS::Budgets::Budget", "{\"Budget\":\"object\",\"Budget.AutoAdjustData\":\"object\",\"Budget.AutoAdjustData.HistoricalOptions\":\"object\",\"Budget.BudgetLimit\":\"object\",\"Budget.CostFilters\":\"object\",\"Budget.CostTypes\":\"object\",\"Budget.FilterExpression\":\"object\",\"Budget.FilterExpression.And\":\"array\",\"Budget.FilterExpression.CostCategories\":\"object\",\"Budget.FilterExpression.CostCategories.MatchOptions\":\"array\",\"Budget.FilterExpression.CostCategories.Values\":\"array\",\"Budget.FilterExpression.Dimensions\":\"object\",\"Budget.FilterExpression.Dimensions.MatchOptions\":\"array\",\"Budget.FilterExpression.Dimensions.Values\":\"array\",\"Budget.FilterExpression.Or\":\"array\",\"Budget.FilterExpression.Tags\":\"object\",\"Budget.FilterExpression.Tags.MatchOptions\":\"array\",\"Budget.FilterExpression.Tags.Values\":\"array\",\"Budget.Metrics\":\"array\",\"Budget.PlannedBudgetLimits\":\"object\",\"Budget.TimePeriod\":\"object\",\"NotificationsWithSubscribers\":\"array\",\"NotificationsWithSubscribers[]\":\"object\",\"NotificationsWithSubscribers[].Notification\":\"object\",\"NotificationsWithSubscribers[].Subscribers\":\"array\",\"NotificationsWithSubscribers[].Subscribers[]\":\"object\",\"ResourceTags\":\"array\",\"ResourceTags[]\":\"object\"}"],
29548
29875
  ["AWS::CertificateManager::Certificate", "{\"DomainValidationOptions\":\"array\",\"DomainValidationOptions[]\":\"object\",\"SubjectAlternativeNames\":\"array\",\"Tags\":\"array\",\"Tags[]\":\"object\"}"],
29549
29876
  ["AWS::CloudFormation::Stack", "{\"Capabilities\":\"array\",\"NotificationARNs\":\"array\",\"Outputs\":\"array\",\"Outputs[]\":\"object\",\"Parameters\":\"object\",\"StackPolicyBody\":\"object\",\"Tags\":\"array\",\"Tags[]\":\"object\"}"],
29550
29877
  ["AWS::CloudFront::CloudFrontOriginAccessIdentity", "{\"CloudFrontOriginAccessIdentityConfig\":\"object\"}"],
@@ -29552,7 +29879,6 @@ const PROPERTY_SHAPES = /* @__PURE__ */ new Map([
29552
29879
  ["AWS::CloudFront::OriginAccessControl", "{\"OriginAccessControlConfig\":\"object\"}"],
29553
29880
  ["AWS::CloudTrail::Trail", "{\"AdvancedEventSelectors\":\"array\",\"AdvancedEventSelectors[]\":\"object\",\"AdvancedEventSelectors[].FieldSelectors\":\"array\",\"AdvancedEventSelectors[].FieldSelectors[]\":\"object\",\"AdvancedEventSelectors[].FieldSelectors[].EndsWith\":\"array\",\"AdvancedEventSelectors[].FieldSelectors[].Equals\":\"array\",\"AdvancedEventSelectors[].FieldSelectors[].NotEndsWith\":\"array\",\"AdvancedEventSelectors[].FieldSelectors[].NotEquals\":\"array\",\"AdvancedEventSelectors[].FieldSelectors[].NotStartsWith\":\"array\",\"AdvancedEventSelectors[].FieldSelectors[].StartsWith\":\"array\",\"AggregationConfigurations\":\"array\",\"AggregationConfigurations[]\":\"object\",\"AggregationConfigurations[].Templates\":\"array\",\"EventSelectors\":\"array\",\"EventSelectors[]\":\"object\",\"EventSelectors[].DataResources\":\"array\",\"EventSelectors[].DataResources[]\":\"object\",\"EventSelectors[].DataResources[].Values\":\"array\",\"EventSelectors[].ExcludeManagementEventSources\":\"array\",\"InsightSelectors\":\"array\",\"InsightSelectors[]\":\"object\",\"InsightSelectors[].EventCategories\":\"array\",\"Tags\":\"array\",\"Tags[]\":\"object\"}"],
29554
29881
  ["AWS::CloudWatch::Alarm", "{\"AlarmActions\":\"array\",\"Dimensions\":\"array\",\"Dimensions[]\":\"object\",\"EvaluationCriteria\":\"object\",\"EvaluationCriteria.PromQLCriteria\":\"object\",\"EvaluationWindow\":\"object\",\"EvaluationWindow.SlidingWindow\":\"object\",\"EvaluationWindow.WallClockWindow\":\"object\",\"InsufficientDataActions\":\"array\",\"Metrics\":\"array\",\"Metrics[]\":\"object\",\"Metrics[].MetricStat\":\"object\",\"Metrics[].MetricStat.Metric\":\"object\",\"Metrics[].MetricStat.Metric.Dimensions\":\"array\",\"Metrics[].MetricStat.Metric.Dimensions[]\":\"object\",\"OKActions\":\"array\",\"Tags\":\"array\",\"Tags[]\":\"object\",\"WarmUpConfiguration\":\"object\"}"],
29555
- ["AWS::CloudWatch::AnomalyDetector", "{\"Configuration\":\"object\",\"Configuration.ExcludedTimeRanges\":\"array\",\"Configuration.ExcludedTimeRanges[]\":\"object\",\"Dimensions\":\"array\",\"Dimensions[]\":\"object\",\"MetricCharacteristics\":\"object\",\"MetricMathAnomalyDetector\":\"object\",\"MetricMathAnomalyDetector.MetricDataQueries\":\"array\",\"MetricMathAnomalyDetector.MetricDataQueries[]\":\"object\",\"MetricMathAnomalyDetector.MetricDataQueries[].MetricStat\":\"object\",\"MetricMathAnomalyDetector.MetricDataQueries[].MetricStat.Metric\":\"object\",\"MetricMathAnomalyDetector.MetricDataQueries[].MetricStat.Metric.Dimensions\":\"array\",\"MetricMathAnomalyDetector.MetricDataQueries[].MetricStat.Metric.Dimensions[]\":\"object\",\"SingleMetricAnomalyDetector\":\"object\",\"SingleMetricAnomalyDetector.Dimensions\":\"array\",\"SingleMetricAnomalyDetector.Dimensions[]\":\"object\"}"],
29556
29882
  ["AWS::CodeCommit::Repository", "{\"Code\":\"object\",\"Code.S3\":\"object\",\"Tags\":\"array\",\"Tags[]\":\"object\",\"Triggers\":\"array\",\"Triggers[]\":\"object\",\"Triggers[].Branches\":\"array\",\"Triggers[].Events\":\"array\"}"],
29557
29883
  ["AWS::Cognito::UserPool", "{\"AccountRecoverySetting\":\"object\",\"AccountRecoverySetting.RecoveryMechanisms\":\"array\",\"AccountRecoverySetting.RecoveryMechanisms[]\":\"object\",\"AdminCreateUserConfig\":\"object\",\"AdminCreateUserConfig.InviteMessageTemplate\":\"object\",\"AliasAttributes\":\"array\",\"AutoVerifiedAttributes\":\"array\",\"DeviceConfiguration\":\"object\",\"EmailConfiguration\":\"object\",\"EnabledMfas\":\"array\",\"IssuerConfiguration\":\"object\",\"KeyConfiguration\":\"object\",\"LambdaConfig\":\"object\",\"LambdaConfig.CustomEmailSender\":\"object\",\"LambdaConfig.CustomSMSSender\":\"object\",\"LambdaConfig.InboundFederation\":\"object\",\"LambdaConfig.PreTokenGenerationConfig\":\"object\",\"Policies\":\"object\",\"Policies.PasswordPolicy\":\"object\",\"Policies.SignInPolicy\":\"object\",\"Policies.SignInPolicy.AllowedFirstAuthFactors\":\"array\",\"Schema\":\"array\",\"Schema[]\":\"object\",\"Schema[].NumberAttributeConstraints\":\"object\",\"Schema[].StringAttributeConstraints\":\"object\",\"SmsConfiguration\":\"object\",\"SmsConfiguration.EumsSms\":\"object\",\"UserAttributeUpdateSettings\":\"object\",\"UserAttributeUpdateSettings.AttributesRequireVerificationBeforeUpdate\":\"array\",\"UserPoolAddOns\":\"object\",\"UserPoolAddOns.AdvancedSecurityAdditionalFlows\":\"object\",\"UserPoolTags\":\"object\",\"UsernameAttributes\":\"array\",\"UsernameConfiguration\":\"object\",\"VerificationMessageTemplate\":\"object\"}"],
29558
29884
  ["AWS::DLM::LifecyclePolicy", "{\"CrossRegionCopyTargets\":\"array\",\"CrossRegionCopyTargets[]\":\"object\",\"Exclusions\":\"object\",\"Exclusions.ExcludeTags\":\"array\",\"Exclusions.ExcludeTags[]\":\"object\",\"Exclusions.ExcludeVolumeTypes\":\"array\",\"PolicyDetails\":\"object\",\"PolicyDetails.Actions\":\"array\",\"PolicyDetails.Actions[]\":\"object\",\"PolicyDetails.Actions[].CrossRegionCopy\":\"array\",\"PolicyDetails.Actions[].CrossRegionCopy[]\":\"object\",\"PolicyDetails.Actions[].CrossRegionCopy[].EncryptionConfiguration\":\"object\",\"PolicyDetails.Actions[].CrossRegionCopy[].RetainRule\":\"object\",\"PolicyDetails.CrossRegionCopyTargets\":\"array\",\"PolicyDetails.CrossRegionCopyTargets[]\":\"object\",\"PolicyDetails.EventSource\":\"object\",\"PolicyDetails.EventSource.Parameters\":\"object\",\"PolicyDetails.EventSource.Parameters.SnapshotOwner\":\"array\",\"PolicyDetails.Exclusions\":\"object\",\"PolicyDetails.Exclusions.ExcludeTags\":\"array\",\"PolicyDetails.Exclusions.ExcludeTags[]\":\"object\",\"PolicyDetails.Exclusions.ExcludeVolumeTypes\":\"array\",\"PolicyDetails.Parameters\":\"object\",\"PolicyDetails.Parameters.ExcludeDataVolumeTags\":\"array\",\"PolicyDetails.Parameters.ExcludeDataVolumeTags[]\":\"object\",\"PolicyDetails.ResourceLocations\":\"array\",\"PolicyDetails.ResourceTypes\":\"array\",\"PolicyDetails.Schedules\":\"array\",\"PolicyDetails.Schedules[]\":\"object\",\"PolicyDetails.Schedules[].ArchiveRule\":\"object\",\"PolicyDetails.Schedules[].ArchiveRule.RetainRule\":\"object\",\"PolicyDetails.Schedules[].ArchiveRule.RetainRule.RetentionArchiveTier\":\"object\",\"PolicyDetails.Schedules[].CreateRule\":\"object\",\"PolicyDetails.Schedules[].CreateRule.Scripts\":\"array\",\"PolicyDetails.Schedules[].CreateRule.Scripts[]\":\"object\",\"PolicyDetails.Schedules[].CreateRule.Scripts[].Stages\":\"array\",\"PolicyDetails.Schedules[].CreateRule.Times\":\"array\",\"PolicyDetails.Schedules[].CrossRegionCopyRules\":\"array\",\"PolicyDetails.Schedules[].CrossRegionCopyRules[]\":\"object\",\"PolicyDetails.Schedules[].CrossRegionCopyRules[].DeprecateRule\":\"object\",\"PolicyDetails.Schedules[].CrossRegionCopyRules[].RetainRule\":\"object\",\"PolicyDetails.Schedules[].DeprecateRule\":\"object\",\"PolicyDetails.Schedules[].FastRestoreRule\":\"object\",\"PolicyDetails.Schedules[].FastRestoreRule.AvailabilityZoneIds\":\"array\",\"PolicyDetails.Schedules[].FastRestoreRule.AvailabilityZones\":\"array\",\"PolicyDetails.Schedules[].RetainRule\":\"object\",\"PolicyDetails.Schedules[].ShareRules\":\"array\",\"PolicyDetails.Schedules[].ShareRules[]\":\"object\",\"PolicyDetails.Schedules[].ShareRules[].TargetAccounts\":\"array\",\"PolicyDetails.Schedules[].TagsToAdd\":\"array\",\"PolicyDetails.Schedules[].TagsToAdd[]\":\"object\",\"PolicyDetails.Schedules[].VariableTags\":\"array\",\"PolicyDetails.Schedules[].VariableTags[]\":\"object\",\"PolicyDetails.TargetTags\":\"array\",\"PolicyDetails.TargetTags[]\":\"object\",\"Tags\":\"array\",\"Tags[]\":\"object\"}"],
@@ -29911,7 +30237,9 @@ var ProviderRegistry = class {
29911
30237
  if (this.providers.get(resourceType)?.disableCcApiFallback === true) return "the type's SDK provider opts out of the Cloud Control fallback (disableCcApiFallback)";
29912
30238
  }
29913
30239
  buildUnroutableSilentDropMessage(resourceType, drops, reason) {
29914
- return `${resourceType} uses properties cdkd's SDK Provider does not handle, and this type cannot fall back to Cloud Control API (${reason}):\n${drops.map((d) => ` - ${d.property}: ${d.rationale}`).join("\n")}\nRemove the properties, or force the SDK provider path and accept the drop via --prefer-sdk-route ${drops.map((d) => `${resourceType}:${d.property}`).join(",")} (the provider may still reject the resource if the property is required).`;
30240
+ const details = drops.map((d) => safeMsg` - ${d.property}: ${d.rationale}`).join("\n");
30241
+ const overrideHint = drops.map((d) => safeMsg`${resourceType}:${d.property}`).join(",");
30242
+ return safeMsg`${resourceType} uses properties cdkd's SDK Provider does not handle, and ` + safeMsg`this type cannot fall back to Cloud Control API (${reason}):\n` + `${details}\nRemove the properties, or force the SDK provider path and accept the drop via --prefer-sdk-route ${overrideHint} (the provider may still reject the resource if the property is required).`;
29915
30243
  }
29916
30244
  getProvider(resourceType) {
29917
30245
  return this.getProviderFor({ resourceType }).provider;
@@ -29985,7 +30313,7 @@ var ProviderRegistry = class {
29985
30313
  const autoRouted = [...drops.map(({ property }) => property).filter((property) => !this.allowedUnsupportedProperties.has(`${resourceType}:${property}`)), ...unrecognizedRoute].sort((a, b) => a.localeCompare(b));
29986
30314
  if (autoRouted.length > 0) {
29987
30315
  const unroutable = this.ccRouteUnavailableReason(resourceType);
29988
- if (unroutable !== void 0) throw new Error(`${logicalId}: ${this.buildUnroutableSilentDropMessage(resourceType, drops.filter((d) => autoRouted.includes(d.property)), unroutable)}`);
30316
+ if (unroutable !== void 0) throw new Error(safeMsg`${logicalId}: ` + this.buildUnroutableSilentDropMessage(resourceType, drops.filter((d) => autoRouted.includes(d.property)), unroutable));
29989
30317
  const propList = autoRouted.join(", ");
29990
30318
  const overrideHint = autoRouted.map((p) => `${resourceType}:${p}`).join(",");
29991
30319
  const message = `${logicalId} (${resourceType}): routing via Cloud Control API (cdkd's SDK Provider does not yet wire ${propList} — CC API will forward the full property map.${unrecognizedRoute.length === 0 ? "" : ` ${unrecognizedRoute.join(", ")} ${unrecognizedRoute.length === 1 ? "is" : "are"} not in cdkd's CFn schema snapshot: Cloud Control applies a property AWS published since, and rejects a misspelled one as CloudFormation does.`} Override via --prefer-sdk-route ${overrideHint}.)`;
@@ -32135,9 +32463,9 @@ function handleOutputResolutionFailure(error, outputKey, outputs, secrets, inher
32135
32463
  const detail = maskSecretsInText(error instanceof Error ? error.message || error.name : String(error), union);
32136
32464
  if (this.options.strictGetAtt) {
32137
32465
  const cause = typeof error === "string" ? maskSecretsInText(error, union) : maskSecretsInError(error, union);
32138
- throw new Error(`Failed to resolve output ${outputKey}: ${detail} (--strict-getatt promotes output resolution failures to deploy errors; drop the flag to skip the output instead)`, cause instanceof Error || typeof cause === "string" ? { cause } : {});
32466
+ throw new Error(safeMsg`Failed to resolve output ${outputKey} ` + `(--strict-getatt promotes output resolution failures to deploy errors; ` + safeMsg`drop the flag to skip the output instead): ${asIsMessage(detail)}`, cause instanceof Error || typeof cause === "string" ? { cause } : {});
32139
32467
  }
32140
- this.logger.warn(`Failed to resolve output ${outputKey}: ${detail}`);
32468
+ this.logger.warn(safeMsg`Failed to resolve output ${outputKey}: ${asIsMessage(detail)}`);
32141
32469
  outputs[outputKey] = void 0;
32142
32470
  }
32143
32471
  async function resolveOutputs(template, resources, stackName, digestSource, parameterValues, conditions) {
@@ -32158,7 +32486,7 @@ async function resolveOutputs(template, resources, stackName, digestSource, para
32158
32486
  const refuseMaskedOutputReads = (outputKey, ownReads) => {
32159
32487
  const added = ownReads.filter((read) => read.kind === "ref-state-key");
32160
32488
  if (added.length === 0) return;
32161
- throw markNonRetryable(/* @__PURE__ */ new Error(`Cannot resolve ${added.map((read) => read.display).join(", ")} for output ${outputKey}: cdkd's recorded state holds only the redaction mask there, so this output would publish a value cdkd cannot confirm (for most such types the resource's raw physical id) instead of the value CloudFormation's Ref returns — a possibly wrong value that a consuming stack's Fn::ImportValue would accept and send to AWS. The output is not published. ${DeployEngine.maskedRecordRemedyFor(added, context.resources)}`));
32489
+ throw markNonRetryable(/* @__PURE__ */ new Error(safeMsg`Cannot resolve ${added.map((read) => read.display).join(", ")} for output ${outputKey}: cdkd's recorded state ` + `holds only the redaction mask there, so this output would publish a value cdkd cannot confirm (for most such types the resource's raw physical id) instead of the value CloudFormation's Ref returns — a possibly wrong value that a consuming stack's Fn::ImportValue would accept and send to AWS. The output is not published. ${DeployEngine.maskedRecordRemedyFor(added, context.resources)}`));
32162
32490
  };
32163
32491
  const outputsPassSecrets = context.recordedSecretValues ?? EMPTY_SECRETS;
32164
32492
  const outputsPassInherited = context.inheritedSecrets ?? EMPTY_SECRETS;
@@ -32168,7 +32496,7 @@ async function resolveOutputs(template, resources, stackName, digestSource, para
32168
32496
  try {
32169
32497
  for (const [outputKey, output] of Object.entries(template.Outputs)) {
32170
32498
  if (isOutputSuppressedByCondition(output, conditions)) {
32171
- this.logger.debug(`Skipping output ${outputKey} — condition ${output.Condition} is false`);
32499
+ this.logger.debug(safeMsg`Skipping output ${outputKey} — condition ${output.Condition} is false`);
32172
32500
  continue;
32173
32501
  }
32174
32502
  const ownReads = [];
@@ -33556,11 +33884,16 @@ async function resolveReplayProps(props, resolvers, secrets, execCtx, logicalId,
33556
33884
  resources: {},
33557
33885
  recordedSecretValues: secrets
33558
33886
  };
33887
+ const pins = new ReplayPins(record, resolvers, execCtx, logicalId);
33559
33888
  const walk = async (v, path) => {
33560
33889
  if (typeof v === "string") {
33561
33890
  if (!v.includes("{{resolve:")) return v;
33562
33891
  refuseUnprovenReplaySecret(v, path, logicalId, execCtx, recordedRegions);
33563
- return await resolveLeafByRegion(v, path, logicalId, execCtx, resolvers, resolverContext, recordedRegions);
33892
+ const leafPins = await pins.forLeaf(v, recordedRegions);
33893
+ return await resolveLeafByRegion(v, path, logicalId, execCtx, resolvers, leafPins === void 0 ? resolverContext : {
33894
+ ...resolverContext,
33895
+ referencePins: leafPins
33896
+ }, recordedRegions);
33564
33897
  }
33565
33898
  if (Array.isArray(v)) {
33566
33899
  const out = new Array(v.length);
@@ -33576,6 +33909,66 @@ async function resolveReplayProps(props, resolvers, secrets, execCtx, logicalId,
33576
33909
  };
33577
33910
  return await walk(props, "");
33578
33911
  }
33912
+ var ReplayPins = class {
33913
+ recorded = /* @__PURE__ */ new Map();
33914
+ verdicts = /* @__PURE__ */ new Map();
33915
+ resolvers;
33916
+ execCtx;
33917
+ logicalId;
33918
+ constructor(record, resolvers, execCtx, logicalId) {
33919
+ this.resolvers = resolvers;
33920
+ this.execCtx = execCtx;
33921
+ this.logicalId = logicalId;
33922
+ const field = referenceProvenanceOf(record);
33923
+ for (const [token, entry] of Object.entries(field ?? {})) if (entry.versions?.length === 1) this.recorded.set(token, entry.versions[0]);
33924
+ }
33925
+ async forLeaf(leaf, recordedRegions) {
33926
+ if (this.recorded.size === 0) return void 0;
33927
+ let out;
33928
+ for (const token of dynamicReferenceTokens(leaf)) {
33929
+ const pin = this.recorded.get(token);
33930
+ if (pin === void 0) continue;
33931
+ if (!await this.usable(token, pin, recordedRegions)) continue;
33932
+ (out ??= /* @__PURE__ */ new Map()).set(token, pin);
33933
+ }
33934
+ return out;
33935
+ }
33936
+ async usable(token, pin, recordedRegions) {
33937
+ const known = this.verdicts.get(token);
33938
+ if (known !== void 0) return known;
33939
+ const verdict = classifyRecordedSecretRegion(token, this.execCtx.region, this.execCtx.importedProducerRegions, recordedRegions);
33940
+ if (verdict.kind === "ambiguous") return false;
33941
+ const resolver = verdict.kind === "named-region" ? this.resolvers.forRegion(verdict.region) : verdict.kind === "recorded-region" ? this.resolvers.forRecordedRegion(verdict.region) : this.resolvers.primary;
33942
+ let ok;
33943
+ try {
33944
+ await resolver.resolveDynamicReferences(token, {
33945
+ template: { Resources: {} },
33946
+ resources: {},
33947
+ recordedSecretValues: /* @__PURE__ */ new Map(),
33948
+ provenanceSuppressed: true
33949
+ });
33950
+ } catch (err) {
33951
+ if (isDeliberateResolutionRefusal(err)) throw err;
33952
+ }
33953
+ try {
33954
+ const served = await resolver.resolveDynamicReferences(token, {
33955
+ template: { Resources: {} },
33956
+ resources: {},
33957
+ recordedSecretValues: /* @__PURE__ */ new Map(),
33958
+ provenanceSuppressed: true,
33959
+ referencePins: /* @__PURE__ */ new Map([[token, pin]])
33960
+ });
33961
+ ok = served.includes("{{resolve:") || served.length >= 4;
33962
+ if (!ok) getLogger().warn(safeMsg`Rollback of ${this.logicalId} restores a secret reference at its current version, not the version its record names: that value is shorter than four characters, so cdkd could not keep it out of state.`);
33963
+ } catch (err) {
33964
+ if (isDeliberateResolutionRefusal(err)) throw err;
33965
+ getLogger().warn(safeMsg`Rollback of ${this.logicalId} could not read a secret at the version its record names (it may have been deprecated or deleted); restoring the current value instead.`);
33966
+ ok = false;
33967
+ }
33968
+ this.verdicts.set(token, ok);
33969
+ return ok;
33970
+ }
33971
+ };
33579
33972
  function refuseMaskedReplayBaseline(props, logicalId, inert = []) {
33580
33973
  if (props === void 0 || !carriesSecretMask(props)) return;
33581
33974
  if (inert.length > 0 && masksOnlyAt(props, inert)) return;
@@ -35697,11 +36090,11 @@ async function adoptRollbackOrphans(currentState, effectiveTemplate) {
35697
36090
  for (const notice of plan.notices) this.logger.info(maskSecretsInText(notice, named));
35698
36091
  const adoptedFrom = /* @__PURE__ */ new Map();
35699
36092
  adoptedOrphanRecords.set(this, adoptedFrom);
35700
- if (plan.refusals.length > 0) throw new Error(`Deploy refused — cdkd left ${plan.refusals.length} resource(s) in AWS that it cannot safely re-adopt:\n ${plan.refusals.map((r) => maskSecretsInText(r, named)).join("\n ")}`);
36093
+ if (plan.refusals.length > 0) throw new Error(safeMsg`Deploy refused — cdkd left ${plan.refusals.length} resource(s) in AWS that it cannot ` + "safely re-adopt:" + plan.refusals.map((r) => safeMsg`\n ${maskSecretsInText(r, named)}`).join(""));
35701
36094
  for (const [logicalId, record] of Object.entries(plan.adopted)) {
35702
36095
  adoptedFrom.set(logicalId, records.findLast((r) => r.logicalId === logicalId)?.state);
35703
36096
  currentState.resources[logicalId] = record;
35704
- this.logger.info(`Adopting ${displayIdent(logicalId)} (${displayIdent(record.resourceType)}) left in AWS by an earlier rollback as ${displaySafe(maskSecretsInText(record.physicalId, named))}`);
36097
+ this.logger.info(safeMsg`Adopting ${displayIdent(logicalId)} (${displayIdent(record.resourceType)}) left in AWS ` + safeMsg`by an earlier rollback as ${displaySafe(maskSecretsInText(record.physicalId, named))}`);
35705
36098
  }
35706
36099
  if (records.length > 0) currentState.orphans = plan.remaining;
35707
36100
  return plan;
@@ -35878,7 +36271,7 @@ async function deleteRollbackJournalBestEffort(stackName, supersededLogicalIds =
35878
36271
  try {
35879
36272
  deleted = await this.stateBackend.deleteRollbackJournal(stackName, this.stackRegion);
35880
36273
  } catch (err) {
35881
- this.logger.debug(safeMsg`Failed to delete rollback journal for ${stackName}: ${err instanceof Error ? err.message : String(err)}`);
36274
+ this.logger.debug(safeMsg`Failed to delete rollback journal for ${displayStackName(stackName)}: ${err instanceof Error ? err.message : String(err)}`);
35882
36275
  deleted = false;
35883
36276
  }
35884
36277
  if (deleted !== false) return true;
@@ -35886,7 +36279,7 @@ async function deleteRollbackJournalBestEffort(stackName, supersededLogicalIds =
35886
36279
  try {
35887
36280
  await this.stateBackend.markRollbackJournalSuperseded(stackName, this.stackRegion, supersededLogicalIds);
35888
36281
  } catch (markErr) {
35889
- this.logger.debug(safeMsg`Failed to record superseded logical ids on the rollback journal for ${stackName}: ${markErr instanceof Error ? markErr.message : String(markErr)}`);
36282
+ this.logger.debug(safeMsg`Failed to record superseded logical ids on the rollback journal for ${displayStackName(stackName)}: ${markErr instanceof Error ? markErr.message : String(markErr)}`);
35890
36283
  }
35891
36284
  return false;
35892
36285
  }
@@ -35895,7 +36288,7 @@ async function settleJournalAfterCleanRollback(stackName, failedOperations, init
35895
36288
  try {
35896
36289
  await this.stateBackend.popRollbackJournalSegment(stackName, this.stackRegion);
35897
36290
  } catch (err) {
35898
- this.logger.debug(`Failed to pop the rollback journal segment after the clean rollback: ${err instanceof Error ? err.message : String(err)}`);
36291
+ this.logger.debug(safeMsg`Failed to pop the rollback journal segment after the clean rollback: ${asIsMessage(err instanceof Error ? err.message : String(err))}`);
35899
36292
  return false;
35900
36293
  }
35901
36294
  return true;
@@ -35907,7 +36300,7 @@ async function settleJournalAfterCleanRollback(stackName, failedOperations, init
35907
36300
  return false;
35908
36301
  }
35909
36302
  if (!await this.writeRollbackJournalSegment(stackName, [], failedOperations, "auto-rollback-clean", initialDeploy)) return true;
35910
- this.logger.info(`The automatic rollback restored the pre-deploy state. The failed resource's pre-failure record was kept — if it was left partially applied, revert it.\nRevert it with: ${pasteableCommand("cdkd rollback", [{
36303
+ this.logger.info("The automatic rollback restored the pre-deploy state. The failed resource's pre-failure record was kept — if it was left partially applied, revert it." + safeMsg`\nRevert it with: ${pasteableCommand("cdkd rollback", [{
35911
36304
  value: stackName,
35912
36305
  hole: "stack"
35913
36306
  }, { literal: "--revert-failed" }]).command}`);
@@ -35975,10 +36368,10 @@ async function writeRollbackJournalSegment(stackName, completedOperations, faile
35975
36368
  ...nestedPending?.previousCrossStackReads && { previousCrossStackReads: nestedPending.previousCrossStackReads }
35976
36369
  };
35977
36370
  await this.stateBackend.appendRollbackJournalSegment(stackName, this.stackRegion, segment);
35978
- this.logger.debug(`Rollback journal segment written (${reason})`);
36371
+ this.logger.debug(safeMsg`Rollback journal segment written (${reason})`);
35979
36372
  return true;
35980
36373
  } catch (journalError) {
35981
- this.logger.warn(`Failed to write rollback journal: ${journalError instanceof Error ? journalError.message : String(journalError)}. 'cdkd rollback' will NOT be able to revert this deploy — use 'cdkd deploy' to resume or 'cdkd destroy' to clean up.`);
36374
+ this.logger.warn(safeMsg`Failed to write rollback journal: ${asIsMessage(journalError instanceof Error ? journalError.message : String(journalError))}. ` + `'cdkd rollback' will NOT be able to revert this deploy — use 'cdkd deploy' to resume or 'cdkd destroy' to clean up.`);
35982
36375
  return false;
35983
36376
  }
35984
36377
  }
@@ -36293,7 +36686,7 @@ function kickOffObservedCapture(provider, logicalId, physicalId, resourceType, r
36293
36686
  this.printingSecretsFor(logicalId),
36294
36687
  this.fingerprintNoEchoValues
36295
36688
  ]);
36296
- this.logger.debug(mask(`observedProperties capture for ${logicalId} (${resourceType}) failed: ${err instanceof Error ? err.message : String(err)} — drift will fall back to template properties for this resource until the next successful deploy.`));
36689
+ this.logger.debug(safeMsg`observedProperties capture for ${mask(logicalId)} (${mask(resourceType)}) failed: ${asIsMessage(mask(err instanceof Error ? err.message : String(err)))} — drift will fall back to template properties for this resource until the next successful deploy.`);
36297
36690
  });
36298
36691
  const promise = secrets === void 0 ? read() : withCurrentResourceSecrets(secrets, read);
36299
36692
  this.observedCaptureTasks.set(logicalId, promise);
@@ -36387,8 +36780,8 @@ function stampReasonlessParameterRefusals(stateResources, template) {
36387
36780
  };
36388
36781
  stamped++;
36389
36782
  }
36390
- if (namesParameter?.failedClosed !== void 0) this.logger.debug(`The template's parameter dependence could not be judged (${namesParameter.failedClosed}): every observed-baseline refusal recorded without a reason is treated as an unverifiable-parameter refusal (${stamped} stamped).`);
36391
- if (stamped > 0) this.logger.debug(`${stamped} resource(s) carry an observed-baseline refusal recorded without a reason by an older cdkd, and their template definition reads a template parameter: treated as an unverifiable-parameter refusal (kept until the resource is replaced or re-imported against a CloudFormation stack that proves the parameter).`);
36783
+ if (namesParameter?.failedClosed !== void 0) this.logger.debug(safeMsg`The template's parameter dependence could not be judged (${namesParameter.failedClosed}): every observed-baseline refusal recorded without a reason is treated as an unverifiable-parameter refusal (${stamped} stamped).`);
36784
+ if (stamped > 0) this.logger.debug(safeMsg`${stamped} resource(s) carry an observed-baseline refusal recorded without a reason by an older cdkd, and their template definition reads a template parameter: treated as an unverifiable-parameter refusal (kept until the resource is replaced or re-imported against a CloudFormation stack that proves the parameter).`);
36392
36785
  }
36393
36786
  function kickOffAutoRefreshObservedProperties(stateResources, crossStackReads) {
36394
36787
  if (this.options.captureObservedState !== true) return;
@@ -36415,7 +36808,7 @@ function kickOffAutoRefreshObservedProperties(stateResources, crossStackReads) {
36415
36808
  resource
36416
36809
  });
36417
36810
  }
36418
- if (refused > 0) this.logger.debug(`observed-properties auto-refresh SKIPPED for ${refused} resource(s) whose baseline a 'cdkd import' run refused: their recorded properties cannot position the redaction, so capturing an AWS readback against them could persist a resolved secret in plaintext. A deploy that actually CHANGES one of them restores its baseline, unless the refusal is an unverifiable-parameter one (only a replacement or a proving re-import discharges that); a NO_CHANGE deploy never does.`);
36811
+ if (refused > 0) this.logger.debug(safeMsg`observed-properties auto-refresh SKIPPED for ${refused} resource(s) whose baseline a 'cdkd import' run refused: their recorded properties cannot position the redaction, so capturing an AWS readback against them could persist a resolved secret in plaintext. A deploy that actually CHANGES one of them restores its baseline, unless the refusal is an unverifiable-parameter one (only a replacement or a proving re-import discharges that); a NO_CHANGE deploy never does.`);
36419
36812
  if (candidates.length === 0 && masked.length === 0) return;
36420
36813
  const allSiblings = {};
36421
36814
  for (const [lid, res] of Object.entries(stateResources)) allSiblings[lid] = {
@@ -36443,7 +36836,7 @@ function kickOffAutoRefreshObservedProperties(stateResources, crossStackReads) {
36443
36836
  } : void 0);
36444
36837
  toRefresh++;
36445
36838
  }
36446
- if (toRefresh > 0) this.logger.warn(`cdkd state schema upgrade detected — refreshing observed-properties baseline for ${toRefresh} resource(s) (one-time, runs in parallel with deploy)`);
36839
+ if (toRefresh > 0) this.logger.warn(safeMsg`cdkd state schema upgrade detected — refreshing observed-properties baseline for ${toRefresh} resource(s) (one-time, runs in parallel with deploy)`);
36447
36840
  let producerRegions = [];
36448
36841
  if (masked.length > 0) try {
36449
36842
  producerRegions = producerRegionsFromState(crossStackReads);
@@ -36607,9 +37000,9 @@ function refuseRedactedAttributeReads(logicalId, resourceType, context) {
36607
37000
  if (reads === void 0 || reads.length === 0) return;
36608
37001
  if (reads.every((read) => read.kind === "attribute" && read.declaredNoEcho === true)) {
36609
37002
  const producers = [...new Set(reads.map((read) => read.logicalId).filter((id) => !!id))];
36610
- throw new ProvisioningError(`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: ${producers.map((id) => displayIdent(id)).join(", ")} declared ${reads.length === 1 ? "that attribute" : "those attributes"} NoEcho, so cdkd's recorded state holds only the redaction mask for ${reads.length === 1 ? "it" : "them"}, and cdkd does not re-run a producer to recover a value. Remedy: deploy a change to the producer in the SAME run as ${logicalId} (for a custom resource, change one of its properties, e.g. a nonce / version property, so its handler runs again and supplies the value), or stop declaring the value NoEcho.`, resourceType, logicalId);
37003
+ throw new ProvisioningError(safeMsg`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: ` + safeMsg`${producers.map((id) => displayIdent(id)).join(", ")} declared ${reads.length === 1 ? "that attribute" : "those attributes"} NoEcho, ` + safeMsg`so cdkd's recorded state holds only the redaction mask for ${reads.length === 1 ? "it" : "them"}, ` + `and cdkd does not re-run a producer to recover a value. Remedy: deploy a change to the ` + safeMsg`producer in the SAME run as ${logicalId} (for a custom resource, change one of its ` + "properties, e.g. a nonce / version property, so its handler runs again and supplies the value), or stop declaring the value NoEcho.", resourceType, logicalId);
36611
37004
  }
36612
- throw new ProvisioningError(`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: cdkd's recorded state holds only the redaction mask there, and the value is not recoverable from state. There are three ways a record comes to hold the mask. (1) A custom resource handler declared its response NoEcho: true — the value is generated by the handler, so cdkd has nothing to re-derive it from and must not write the literal mask to AWS. Remedies: force that custom resource to update (change one of its properties, e.g. a nonce / version property) so its handler runs again and supplies the value in this same run; or stop setting NoEcho on that response. If the value comes from ANOTHER stack, the producer and this stack must deploy in ONE run (cdkd deploy --all, or cdkd deploy '**' when either is inside a CDK Stage) with the producer's custom resource actually running — re-deploying the producer by itself does not help, because it re-masks the value on the way into its own state. (2) The value holds the Fn::Base64 encoding of a secret value (a {{resolve:...}} dynamic reference under Fn::Base64, such as EC2 UserData), which cdkd never records — so a deploy that leaves the resource or output holding it unchanged reads the mask again, and a re-import does not recover it. Remedy: have this resource build the value itself from the SECRET's own reference (the {{resolve:secretsmanager:...}} or {{resolve:ssm-secure:...}} reference, or a {{resolve:ssm:...}} of a SecureString parameter, that the encoding was made from) under its own Fn::Base64, instead of reading it from another resource's attribute or another stack's output — not by a {{resolve:ssm:...}} read of a String parameter holding the encoding, which cdkd treats as public and would record in state in the clear. (3) The resource is recorded through the Cloud Control fallback (by a deploy or by 'cdkd import'), which keeps in the clear only the Fn::GetAtt attributes it can vouch for and masks the rest. If the name above is not an Fn::GetAtt attribute CloudFormation accepts for that resource type, no record will ever hold it: stop reading it. If it is one, 'cdkd import' masked it because it could not vouch for the value, or could not read the schema and warned about it when it happened (if that warning named a missing cloudformation:DescribeType permission, grant it first); a deploy that creates or updates the resource records it, unless its value came from a secret. See https://github.com/go-to-k/cdkd/issues/2449. ${DeployEngine.maskedRecordRemedyFor(reads, context.resources, true)}`, resourceType, logicalId);
37005
+ throw new ProvisioningError(safeMsg`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: cdkd's recorded state holds only the ` + `redaction mask there, and the value is not recoverable from state. There are three ways a record comes to hold the mask. (1) A custom resource handler declared its response NoEcho: true — the value is generated by the handler, so cdkd has nothing to re-derive it from and must not write the literal mask to AWS. Remedies: force that custom resource to update (change one of its properties, e.g. a nonce / version property) so its handler runs again and supplies the value in this same run; or stop setting NoEcho on that response. If the value comes from ANOTHER stack, the producer and this stack must deploy in ONE run (cdkd deploy --all, or cdkd deploy '**' when either is inside a CDK Stage) with the producer's custom resource actually running — re-deploying the producer by itself does not help, because it re-masks the value on the way into its own state. (2) The value holds the Fn::Base64 encoding of a secret value (a {{resolve:...}} dynamic reference under Fn::Base64, such as EC2 UserData), which cdkd never records — so a deploy that leaves the resource or output holding it unchanged reads the mask again, and a re-import does not recover it. Remedy: have this resource build the value itself from the SECRET's own reference (the {{resolve:secretsmanager:...}} or {{resolve:ssm-secure:...}} reference, or a {{resolve:ssm:...}} of a SecureString parameter, that the encoding was made from) under its own Fn::Base64, instead of reading it from another resource's attribute or another stack's output — not by a {{resolve:ssm:...}} read of a String parameter holding the encoding, which cdkd treats as public and would record in state in the clear. (3) The resource is recorded through the Cloud Control fallback (by a deploy or by 'cdkd import'), which keeps in the clear only the Fn::GetAtt attributes it can vouch for and masks the rest. If the name above is not an Fn::GetAtt attribute CloudFormation accepts for that resource type, no record will ever hold it: stop reading it. If it is one, 'cdkd import' masked it because it could not vouch for the value, or could not read the schema and warned about it when it happened (if that warning named a missing cloudformation:DescribeType permission, grant it first); a deploy that creates or updates the resource records it, unless its value came from a secret. See https://github.com/go-to-k/cdkd/issues/2449. ${DeployEngine.maskedRecordRemedyFor(reads, context.resources, true)}`, resourceType, logicalId);
36613
37006
  }
36614
37007
  function allRecordedSecrets() {
36615
37008
  const all = /* @__PURE__ */ new Map();
@@ -36801,7 +37194,8 @@ async function replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourc
36801
37194
  maskSecrets: createUnionSecretMasker([secrets, this.secretNameBagFor(logicalId)])
36802
37195
  }));
36803
37196
  } catch (deleteError) {
36804
- 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), { cause: deleteError instanceof Error ? maskSecretsInError(deleteError, secrets) : void 0 });
37197
+ const shownSecrets = unionOfSecretBags([secrets, this.printingSecretsFor(logicalId)]);
37198
+ throw new Error(safeMsg`Failed to delete old resource ${maskSecretsInText(logicalId, shownSecrets)} ` + safeMsg`(${maskSecretsInText(currentResource.physicalId, shownSecrets)}) ` + `during the --replace delete-first fallback: ` + safeMsg`${asIsMessage(maskSecretsInText(deleteError instanceof Error ? deleteError.message : String(deleteError), shownSecrets))}`, { cause: deleteError instanceof Error ? maskSecretsInError(deleteError, secrets) : void 0 });
36805
37199
  }
36806
37200
  reportDeleteGuards(deleteResult, {
36807
37201
  physicalId: currentResource.physicalId,
@@ -36810,9 +37204,9 @@ async function replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourc
36810
37204
  });
36811
37205
  const replaceSkipReason = deleteSkipReason(deleteResult);
36812
37206
  if (replaceSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, replaceSkipReason, "during the --replace delete-first fallback"));
36813
- this.logger.info(` ${green("✓")} Old resource deleted`);
37207
+ this.logger.info(safeMsg` ${green("✓")} Old resource deleted`);
36814
37208
  this.oldDeletedBeforeCreate.add(logicalId);
36815
- this.logger.info(` Re-creating ${logicalId}...`);
37209
+ this.logger.info(safeMsg` Re-creating ${logicalId}...`);
36816
37210
  try {
36817
37211
  return await withRetry(() => this.withRetry(() => withCurrentResourceSecrets(secrets, () => replaceProvider.create(logicalId, resourceType, replaceProps, createContext)), logicalId, void 0, void 0, replaceProvider), logicalId, {
36818
37212
  maxRetries: 8,
@@ -36824,7 +37218,8 @@ async function replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourc
36824
37218
  isRetryable: isRecreateRetryableError
36825
37219
  });
36826
37220
  } catch (recreateError) {
36827
- throw new Error(maskSecretsInText(`Failed to re-create ${logicalId} after the --replace delete-first fallback already deleted the old resource (${currentResource.physicalId}): ${recreateError instanceof Error ? recreateError.message : String(recreateError)}. Re-run the deploy to create it fresh.`, secrets), { cause: recreateError instanceof Error ? maskSecretsInError(recreateError, secrets) : void 0 });
37221
+ const shownSecrets = unionOfSecretBags([secrets, this.printingSecretsFor(logicalId)]);
37222
+ throw new Error(safeMsg`Failed to re-create ${maskSecretsInText(logicalId, shownSecrets)} after the ` + safeMsg`--replace delete-first fallback already deleted the old resource (${maskSecretsInText(currentResource.physicalId, shownSecrets)}). ` + safeMsg`Re-run the deploy to create it fresh. Cause: ${asIsMessage(maskSecretsInText(recreateError instanceof Error ? recreateError.message : String(recreateError), shownSecrets))}`, { cause: recreateError instanceof Error ? maskSecretsInError(recreateError, secrets) : void 0 });
36828
37223
  }
36829
37224
  }
36830
37225
  function typeChangeNameQuestion(resourceType, input) {
@@ -36916,7 +37311,7 @@ async function createFirstThenDeleteOld(input) {
36916
37311
  await this.deleteReplacedAfterCreate(logicalId, input.oldResourceType, currentResource, input.deleteProvider, input.deleteProperties, finalSnapshotIdentifier, input.deletePolicy, secrets, input.deleteProvisionedBy, input.noEchoDeleteValues);
36917
37312
  return createResult;
36918
37313
  }
36919
- async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, deleteProvider, deleteProperties, finalSnapshotIdentifier, updateReplacePolicy, secrets, deleteProvisionedBy, noEchoDeleteValues) {
37314
+ async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, deleteProvider, deleteProperties, finalSnapshotIdentifier, updateReplacePolicy, secrets, deleteProvisionedBy, noEchoDeleteValues, isRetry = false) {
36920
37315
  let deleteResult = void 0;
36921
37316
  let deleteFailed = false;
36922
37317
  const inlinePolicyClaimed = isStandaloneInlinePolicyType(oldResourceType) ? this.inlinePolicyClaimedFor(oldResourceType, logicalId, this.deployStateResources) : void 0;
@@ -36935,6 +37330,18 @@ async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentReso
36935
37330
  } catch (deleteError) {
36936
37331
  const deleteMsg = maskSecretsInText(deleteError instanceof Error ? deleteError.message : String(deleteError), secrets);
36937
37332
  deleteFailed = true;
37333
+ const deferred = this.deferredReplacedDeletes;
37334
+ if (!isRetry && deferred !== void 0) {
37335
+ this.logger.info(safeMsg` Could not delete old ${logicalId} (${currentResource.physicalId}) yet: ${deleteMsg}. Retrying after the rest of the deploy.`);
37336
+ deferred.set(logicalId, {
37337
+ physicalId: currentResource.physicalId,
37338
+ resourceType: oldResourceType,
37339
+ provisionedBy: deleteProvisionedBy,
37340
+ failureMessage: deleteMsg,
37341
+ retry: () => this.deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, deleteProvider, deleteProperties, finalSnapshotIdentifier, updateReplacePolicy, secrets, deleteProvisionedBy, noEchoDeleteValues, true)
37342
+ });
37343
+ return;
37344
+ }
36938
37345
  this.logger.warn(safeMsg` ⚠ Failed to delete old resource ${logicalId} (${currentResource.physicalId}): ${deleteMsg}`);
36939
37346
  }
36940
37347
  reportDeleteGuards(deleteResult, {
@@ -36945,8 +37352,67 @@ async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentReso
36945
37352
  const skipReason = deleteSkipReason(deleteResult);
36946
37353
  if (skipReason !== void 0) {
36947
37354
  this.replacedDeleteSkips.set(logicalId, `the replaced ${oldResourceType} (${currentResource.physicalId}) was not deleted (${skipReason}) and is no longer tracked by cdkd`);
36948
- 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.`);
36949
- } else if (!deleteFailed) this.logger.info(` ${green("✓")} Old resource deleted`);
37355
+ this.logger.warn(safeMsg` ⚠ ${deleteSkippedMessage(logicalId, currentResource.physicalId, skipReason, "while cleaning up the replaced resource", { commandFreeLine: true })}. Delete it manually — it is no longer tracked in state.`);
37356
+ } else if (!deleteFailed) this.logger.info(isRetry ? safeMsg` ${green("✓")} Old ${logicalId} (${currentResource.physicalId}) deleted` : safeMsg` ${green("✓")} Old resource deleted`);
37357
+ }
37358
+ async function retryDeferredReplacedDeletes(stackName, counts) {
37359
+ const deferred = this.deferredReplacedDeletes;
37360
+ this.deferredReplacedDeletes = void 0;
37361
+ if (deferred === void 0 || deferred.size === 0) return;
37362
+ this.logger.info(safeMsg`Retrying the delete of ${deferred.size} replaced resource(s)`);
37363
+ const retryOne = async (logicalId, entry) => {
37364
+ const guards = [];
37365
+ try {
37366
+ await withPrintingSecrets(this.secretNameBagFor(logicalId), () => withStackRecords(this.stackRecordsView, () => collectDeleteGuards(guards, async () => {
37367
+ this.logger.info(safeMsg` Deleting old ${logicalId} (${entry.physicalId})...`);
37368
+ try {
37369
+ await entry.retry();
37370
+ } catch {
37371
+ this.logger.warn(safeMsg` ⚠ Failed to delete old resource ${logicalId} (${entry.physicalId}): the retry failed unexpectedly`);
37372
+ }
37373
+ })));
37374
+ } finally {
37375
+ for (const guard of guards) this.recordEvent({
37376
+ eventType: "RESOURCE_GUARD_INDETERMINATE",
37377
+ stackName,
37378
+ operation: "DELETE",
37379
+ logicalId,
37380
+ resourceType: guard.resourceType,
37381
+ ...guard.provisionedBy && { provisionedBy: guard.provisionedBy },
37382
+ ...guard.physicalId && { physicalId: maskSecretsInText(guard.physicalId, this.perResourceSecrets.get(logicalId) ?? EMPTY_SECRETS) },
37383
+ guard: guard.guard,
37384
+ reason: guard.reason
37385
+ });
37386
+ }
37387
+ const skip = this.replacedDeleteSkips.get(logicalId);
37388
+ if (skip === void 0) return;
37389
+ this.replacedDeleteSkips.delete(logicalId);
37390
+ if (entry.rowPartial !== true) {
37391
+ counts.updated = Math.max(0, counts.updated - 1);
37392
+ counts.updatePartial++;
37393
+ }
37394
+ this.recordEvent({
37395
+ eventType: "RESOURCE_SKIPPED",
37396
+ stackName,
37397
+ operation: "UPDATE",
37398
+ logicalId,
37399
+ resourceType: entry.resourceType,
37400
+ ...entry.provisionedBy && { provisionedBy: entry.provisionedBy },
37401
+ physicalId: entry.physicalId,
37402
+ reason: skip
37403
+ });
37404
+ };
37405
+ const queue = [...deferred];
37406
+ const workers = Math.max(1, Math.min(this.options.concurrency ?? 1, queue.length));
37407
+ await Promise.all(Array.from({ length: workers }, async () => {
37408
+ for (let next = queue.shift(); next !== void 0; next = queue.shift()) await retryOne(...next);
37409
+ }));
37410
+ }
37411
+ function warnUnretriedReplacedDeletes(why) {
37412
+ const deferred = this.deferredReplacedDeletes;
37413
+ this.deferredReplacedDeletes = void 0;
37414
+ const note = why === "failed" ? "not retried: the deploy failed first" : "not retried: the deploy was interrupted";
37415
+ for (const [logicalId, entry] of deferred ?? []) withPrintingSecrets(this.secretNameBagFor(logicalId), () => this.logger.warn(safeMsg` ⚠ Failed to delete old resource ${logicalId} (${entry.physicalId}): ${entry.failureMessage} (${note})`));
36950
37416
  }
36951
37417
 
36952
37418
  //#endregion
@@ -37050,7 +37516,7 @@ async function readStaleAttributes(logicalId, resource, stackName) {
37050
37516
  resourceType: resource.resourceType,
37051
37517
  attributes
37052
37518
  });
37053
- this.logger.debug(`Re-read the attributes of ${displaySafe(logicalId)} (${displaySafe(resource.resourceType)}) from AWS — its state record lacked one a Fn::GetAtt asked for: ${Object.keys(attributes).length} attribute(s) read`);
37519
+ this.logger.debug(safeMsg`Re-read the attributes of ${displaySafe(logicalId)} (${displaySafe(resource.resourceType)}) from AWS — its state record lacked one a Fn::GetAtt asked for: ${Object.keys(attributes).length} attribute(s) read`);
37054
37520
  return outcome;
37055
37521
  }
37056
37522
  function withHealedAttributes(logicalId, record) {
@@ -37077,8 +37543,8 @@ function auditResolvedAssetReferences(logicalId, resourceType, resolvedProps) {
37077
37543
  if (!redirect) return;
37078
37544
  const findings = findUnrewrittenAssetReferences(resolvedProps, redirect);
37079
37545
  if (findings.length === 0) return;
37080
- const detail = findings.map((f) => ` - ${f.path}: still references '${f.source}'`).join("\n");
37081
- throw new ProvisioningError(`Unrewritten asset reference on '${logicalId}' (${resourceType}): this region uses cdkd-owned asset storage, but the following resolved properties still point at the CDK bootstrap storage that 'cdk gc' may garbage-collect:\n${detail}\nThis is a template shape cdkd's asset-reference rewrite did not cover — deploying it would split-brain the stack (assets in cdkd storage, properties reading the CDK bucket). Please report this at https://github.com/go-to-k/cdkd/issues with the property shape. Workaround: deploy with --use-cdk-bootstrap-assets to pin the legacy destinations for this app.`, resourceType, logicalId);
37546
+ const detail = findings.map((f) => safeMsg` - ${f.path}: still references '${f.source}'`).join("\n");
37547
+ throw new ProvisioningError(safeMsg`Unrewritten asset reference on '${logicalId}' (${resourceType}): this region uses ` + `cdkd-owned asset storage, but the following resolved properties still point at the CDK bootstrap storage that 'cdk gc' may garbage-collect:\n${detail}\nThis is a template shape cdkd's asset-reference rewrite did not cover — deploying it would split-brain the stack (assets in cdkd storage, properties reading the CDK bucket). Please report this at https://github.com/go-to-k/cdkd/issues with the property shape. Workaround: deploy with --use-cdk-bootstrap-assets to pin the legacy destinations for this app.`, resourceType, logicalId);
37082
37548
  }
37083
37549
  function extractAllDependencies(template, logicalId) {
37084
37550
  const resource = template?.Resources?.[logicalId];
@@ -37368,7 +37834,7 @@ async function provisionCreate(logicalId, change, stateResources, stackName, tem
37368
37834
  if (progress) progress.current++;
37369
37835
  const createPrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
37370
37836
  renderer.removeTask(logicalId);
37371
- this.logger.info(`${createPrefix}${formatResourceLine("created", logicalId, resourceType)}`);
37837
+ this.logger.info(safeMsg`${createPrefix}${formatResourceLine("created", logicalId, resourceType)}`);
37372
37838
  }
37373
37839
  async function refuseUnlicensedGeneratedName(input) {
37374
37840
  const { logicalId, resourceType } = input;
@@ -40235,6 +40701,118 @@ function recordedProtectionNote(evidence, flags) {
40235
40701
  return `${evidence}. AWS refuses to delete the resource while that protection is on, and cdkd deploy has no --remove-protection flag to clear it (only cdkd destroy and cdkd state destroy act on one), so ${flags} alone does not remove the old resource: depending on the replacement order, the deploy either fails at that delete or completes leaving the old resource, and its data, in AWS and no longer tracked by cdkd. Read ${DELETION_PROTECTION_DOC_POINTER} before you disable anything, then turn the protection off out of band (the console, or the service's own API) and re-run with ${flags}.`;
40236
40702
  }
40237
40703
 
40704
+ //#endregion
40705
+ //#region src/deployment/deploy-engine/read-provenance-moved.ts
40706
+ function occurrences(value, token) {
40707
+ if (typeof value === "string") return value.includes(token) ? value.split(token).length - 1 : 0;
40708
+ if (Array.isArray(value)) {
40709
+ let n = 0;
40710
+ for (const item of value) n += occurrences(item, token);
40711
+ return n;
40712
+ }
40713
+ if (value !== null && typeof value === "object") {
40714
+ let n = 0;
40715
+ for (const item of Object.values(value)) n += occurrences(item, token);
40716
+ return n;
40717
+ }
40718
+ return 0;
40719
+ }
40720
+ function readProvenanceMovedPaths(args) {
40721
+ const paths = /* @__PURE__ */ new Set();
40722
+ const tokens = [];
40723
+ const field = referenceProvenanceOf(args.record);
40724
+ if (field === void 0) return {
40725
+ paths,
40726
+ tokens
40727
+ };
40728
+ for (const [token, entry] of Object.entries(field)) {
40729
+ const recorded = entry.readVersions;
40730
+ if (recorded === void 0 || recorded.length === 0) continue;
40731
+ const served = passReadVersionsFor(args.secrets, token);
40732
+ if (served === void 0) continue;
40733
+ if ([...served].every((version) => recorded.includes(version))) continue;
40734
+ const held = /* @__PURE__ */ new Set();
40735
+ for (const key of Object.keys(args.desiredRedacted)) {
40736
+ const count = occurrences(args.desiredRedacted[key], token);
40737
+ if (count === 0) continue;
40738
+ if (count > (Object.hasOwn(args.templateProperties, key) ? occurrences(args.templateProperties[key], token) : 0)) held.add(key);
40739
+ }
40740
+ if (held.size === 0) continue;
40741
+ for (const key of held) paths.add(key);
40742
+ tokens.push({
40743
+ token,
40744
+ paths: held,
40745
+ recorded,
40746
+ served,
40747
+ region: entry.region
40748
+ });
40749
+ }
40750
+ return {
40751
+ paths,
40752
+ tokens
40753
+ };
40754
+ }
40755
+ async function confirmValueMoves(moved, sameValue) {
40756
+ const kept = [];
40757
+ const unchanged = [];
40758
+ for (const entry of moved.tokens) {
40759
+ let equal = entry.recorded.length === 1 ? true : void 0;
40760
+ for (const served of entry.served) {
40761
+ if (equal !== true) break;
40762
+ equal = await sameValue(entry, entry.recorded[0], served);
40763
+ }
40764
+ if (equal === true) unchanged.push(entry);
40765
+ else kept.push(entry);
40766
+ }
40767
+ const paths = /* @__PURE__ */ new Set();
40768
+ for (const entry of kept) for (const key of entry.paths) paths.add(key);
40769
+ return {
40770
+ moved: {
40771
+ paths,
40772
+ tokens: kept
40773
+ },
40774
+ unchanged
40775
+ };
40776
+ }
40777
+ async function sameValueAtVersions(resolver, entry, recorded, served, base) {
40778
+ const context = (pin) => ({
40779
+ template: base.template,
40780
+ resources: base.resources,
40781
+ recordedSecretValues: /* @__PURE__ */ new Map(),
40782
+ provenanceSuppressed: true,
40783
+ referencePins: /* @__PURE__ */ new Map([[entry.token, pin]])
40784
+ });
40785
+ if (entry.region === void 0) return void 0;
40786
+ const reader = resolver.resolverForRecordedRegion(entry.region);
40787
+ try {
40788
+ const now = await reader.resolveDynamicReferences(entry.token, context(served));
40789
+ const then = await reader.resolveDynamicReferences(entry.token, context(recorded));
40790
+ if (now.includes("{{resolve:") || then.includes("{{resolve:")) return void 0;
40791
+ return now === then;
40792
+ } catch (err) {
40793
+ if (isDeliberateResolutionRefusal(err)) throw err;
40794
+ return;
40795
+ }
40796
+ }
40797
+ function withRefreshedReadVersions(record, unchanged) {
40798
+ const field = referenceProvenanceOf(record);
40799
+ if (field === void 0) return record;
40800
+ const out = { ...field };
40801
+ for (const { token, served } of unchanged) {
40802
+ const before = Object.hasOwn(field, token) ? field[token] : void 0;
40803
+ const previousRead = new Set(before?.readVersions ?? []);
40804
+ const versions = [.../* @__PURE__ */ new Set([...(before?.versions ?? []).filter((version) => !previousRead.has(version)), ...served])].sort();
40805
+ if (versions.length > 8) continue;
40806
+ const next = validateReferenceProvenance(token, {
40807
+ ...before?.region !== void 0 && { region: before.region },
40808
+ versions,
40809
+ readVersions: [...served].sort()
40810
+ });
40811
+ if (next !== void 0) out[token] = next;
40812
+ }
40813
+ return withReferenceProvenance(record, out);
40814
+ }
40815
+
40238
40816
  //#endregion
40239
40817
  //#region src/deployment/deploy-engine/noecho.ts
40240
40818
  function noEchoExactEchoLeavesOf(record) {
@@ -42191,12 +42769,23 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
42191
42769
  };
42192
42770
  const suppliesFreshMaskOnlyValue = pendingParameterLeaves.size > 0 || Object.keys(resolvedProps).some((key) => otherFreshAt(key).length > 0);
42193
42771
  const rewrittenPaths = readsProducerReplacedThisRun.call(this, template, logicalId, stateResources) ? redactionRewrittenPaths(resolvedProps, desiredForSkipCheck, comparisonCoordinates) : /* @__PURE__ */ new Set();
42772
+ const { moved: provenanceMoved, unchanged: provenanceUnchanged } = await confirmValueMoves(readProvenanceMovedPaths({
42773
+ record: currentResource,
42774
+ templateProperties: desiredProps,
42775
+ desiredRedacted: desiredForSkipCheck,
42776
+ secrets: updateSecrets
42777
+ }), (entry, recordedVersion, servedVersion) => sameValueAtVersions(this.resolver, entry, recordedVersion, servedVersion, {
42778
+ template,
42779
+ resources: stateResources
42780
+ }));
42781
+ for (const path of provenanceMoved.paths) rewrittenPaths.add(path);
42782
+ if (provenanceMoved.paths.size > 0) this.logger.info(safeMsg`${logicalId} is sent: ${[...provenanceMoved.paths].sort().join(", ")} read a secret-derived value at a newer version than ${logicalId} was deployed with (its upstream changed since then)`);
42194
42783
  const recordMatchesDesired = movedMasked.size === 0 && rewrittenPaths.size === 0 && keyOrderFreeJson(desiredForSkipCheckAsWritten) === keyOrderFreeJson(currentPropsAsWritten);
42195
42784
  const applyAttributeOnlyUpdate = (attributeChanges) => {
42196
42785
  const attrSummary = attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
42197
42786
  this.logger.info(safeMsg` ↻ ${logicalId} (${resourceType}) attribute update: ${attrSummary}`);
42198
42787
  stateResources[logicalId] = {
42199
- ...currentResource,
42788
+ ...stateResources[logicalId] ?? currentResource,
42200
42789
  ...this.extractTemplateAttributes(template, logicalId)
42201
42790
  };
42202
42791
  if (counts) counts.updated++;
@@ -42266,6 +42855,7 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
42266
42855
  const differsWhy = (key) => !lateReplacementDeclined.has(key) ? "differs; the provider is not known to report this property exactly, so the difference may be its normalization" : lateCrossPrefixRefused ? "differs; the replacement was refused: see the state-prefix warning above" : `differs; the replacement was not approved (--require-approval=${this.options.requireApproval ?? "never"})`;
42267
42856
  if (witnessMigrates && !typeChanged && echoCandidates.length > 0 && hasAddressablePhysicalId(currentResource)) await readOnce();
42268
42857
  if (!typeChanged && !suppliesFreshMaskOnlyValue && lostChild === void 0 && this.recreateDirectionFor(stackName, logicalId) === void 0 && recordMatchesDesired) {
42858
+ if (provenanceUnchanged.length > 0) stateResources[logicalId] = withRefreshedReadVersions(stateResources[logicalId] ?? currentResource, provenanceUnchanged);
42269
42859
  if (change.attributeChanges && change.attributeChanges.length > 0) {
42270
42860
  applyAttributeOnlyUpdate(change.attributeChanges);
42271
42861
  return;
@@ -42411,6 +43001,7 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
42411
43001
  ...remaining.length > 0 && { noEchoLeaves: remaining.map((c) => [...c]) }
42412
43002
  };
42413
43003
  }
43004
+ if (provenanceUnchanged.length > 0) stateResources[logicalId] = withRefreshedReadVersions(stateResources[logicalId] ?? currentResource, provenanceUnchanged);
42414
43005
  this.attemptedResolvedProps.delete(logicalId);
42415
43006
  if (change.attributeChanges && change.attributeChanges.length > 0) {
42416
43007
  applyAttributeOnlyUpdate(change.attributeChanges);
@@ -42590,20 +43181,20 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42590
43181
  if (statefulReason && this.options.forceStatefulRecreation !== true) {
42591
43182
  const immutableProps = change.propertyChanges?.filter((pc) => pc.requiresReplacement).map((pc) => pc.path).join(", ") || "Type";
42592
43183
  const protection = recordedProtectionEvidence(oldResourceType, currentProps, currentResource.observedProperties, this.stackRegion);
42593
- throw markNonRetryable(new CdkdError(`${logicalId} (${oldResourceType}) requires replacement (immutable property changed: ${immutableProps}${typeChanged ? `, to ${resourceType}` : ""}) but it is a stateful resource — ${renderStatefulReason(statefulReason)}. ` + (protection ? `${recordedProtectionNote(protection, "--force-stateful-recreation")} Or change the resource's definition to avoid the immutable-property change.` : "Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change."), "STATEFUL_REPLACE_BLOCKED"));
43184
+ throw markNonRetryable(new CdkdError(safeMsg`${logicalId} (${oldResourceType}) requires replacement (immutable property changed: ${immutableProps}${typeChanged ? `, to ${resourceType}` : ""}) but it is a stateful resource — ` + safeMsg`${renderStatefulReason(statefulReason)}. ` + (protection ? safeMsg`${recordedProtectionNote(protection, "--force-stateful-recreation")} Or change ` + `the resource's definition to avoid the immutable-property change.` : "Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change."), "STATEFUL_REPLACE_BLOCKED"));
42594
43185
  }
42595
43186
  }
42596
43187
  if (recreateViaCcApi) {
42597
43188
  const noCcRoute = this.providerRegistry.ccRouteUnavailableReason(resourceType);
42598
- if (noCcRoute !== void 0) throw markNonRetryable(new CdkdError(`--recreate-via-cc-api cannot recreate ${logicalId} (${resourceType}): Cloud Control API cannot create this type (${noCcRoute}). Nothing was deleted. Drop ${logicalId} from --recreate-via-cc-api.`, "RECREATE_TARGETS_INVALID"));
43189
+ if (noCcRoute !== void 0) throw markNonRetryable(new CdkdError(safeMsg`--recreate-via-cc-api cannot recreate ${logicalId} (${resourceType}): Cloud ` + safeMsg`Control API cannot create this type (${noCcRoute}). Nothing was deleted. ` + safeMsg`Drop ${logicalId} from --recreate-via-cc-api.`, "RECREATE_TARGETS_INVALID"));
42599
43190
  const ccBroken = ccBrokenReason(resourceType);
42600
- if (ccBroken !== void 0) throw markNonRetryable(new CdkdError(`--recreate-via-cc-api cannot move ${logicalId} (${resourceType}) to Cloud Control: ${ccBroken}, so cdkd keeps it on its SDK provider. Nothing was deleted. Drop ${logicalId} from --recreate-via-cc-api.`, "RECREATE_TARGETS_INVALID"));
43191
+ if (ccBroken !== void 0) throw markNonRetryable(new CdkdError(safeMsg`--recreate-via-cc-api cannot move ${logicalId} (${resourceType}) to Cloud ` + safeMsg`Control: ${ccBroken}, so cdkd keeps it on its SDK provider. Nothing was ` + safeMsg`deleted. Drop ${logicalId} from --recreate-via-cc-api.`, "RECREATE_TARGETS_INVALID"));
42601
43192
  }
42602
43193
  let replacementReason;
42603
43194
  if (recreateViaCcApi) replacementReason = "--recreate-via-cc-api flag (mid-life SDK→CC migration)";
42604
43195
  else if (recreateViaSdkProvider) replacementReason = "--recreate-via-sdk-provider flag (mid-life CC→SDK migration)";
42605
43196
  else replacementReason = `immutable properties changed: ${change.propertyChanges?.filter((pc) => pc.requiresReplacement).map((pc) => pc.path).join(", ")}`;
42606
- this.logger.info(`Replacing ${logicalId} (${typeChanged ? `${oldResourceType} -> ${resourceType}` : resourceType}) - ${replacementReason}`);
43197
+ this.logger.info(safeMsg`Replacing ${logicalId} (${typeChanged ? `${oldResourceType} -> ${resourceType}` : resourceType}) - ${replacementReason}`);
42607
43198
  const recreateDirectionHint = recreateViaCcApi ? "cc-api" : recreateViaSdkProvider ? "sdk" : void 0;
42608
43199
  const replaceDecision = this.providerRegistry.getProviderFor({
42609
43200
  resourceType,
@@ -42672,9 +43263,9 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42672
43263
  if (updateReplacePolicy === "Retain") {
42673
43264
  this.retainedOldOnReplacement.add(logicalId);
42674
43265
  await noteRetainedResource(oldResourceType, logicalId);
42675
- this.logger.warn(` ⚠ ${logicalId} has UpdateReplacePolicy: Retain — ${recreateFlagName} will leak the old physical resource (${currentResource.physicalId}). The new resource shares the same name where applicable; if the type has user-supplied names (e.g. functionName, bucketName), the create will deterministically collide with the retained orphan.`);
43266
+ this.logger.warn(safeMsg` ⚠ ${logicalId} has UpdateReplacePolicy: Retain — ${recreateFlagName} will ` + safeMsg`leak the old physical resource (${currentResource.physicalId}). The new ` + "resource shares the same name where applicable; if the type has user-supplied names (e.g. functionName, bucketName), the create will deterministically collide with the retained orphan.");
42676
43267
  } else {
42677
- this.logger.info(` Destroying old ${logicalId} (${currentResource.physicalId}) before recreate...`);
43268
+ this.logger.info(safeMsg` Destroying old ${logicalId} (${currentResource.physicalId}) before recreate...`);
42678
43269
  const recreateFinalSnapshotId = await this.prepareFinalSnapshotForDelete(logicalId, oldResourceType, currentResource, updateReplacePolicy);
42679
43270
  let recreateDeleteResult;
42680
43271
  try {
@@ -42689,7 +43280,8 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42689
43280
  maskSecrets: createUnionSecretMasker([updateSecrets, this.secretNameBagFor(logicalId)])
42690
43281
  }));
42691
43282
  } catch (deleteError) {
42692
- throw new Error(maskSecretsInText(`Failed to destroy old resource ${logicalId} (${currentResource.physicalId}) during ${recreateFlagName}: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`, updateSecrets), { cause: deleteError instanceof Error ? maskSecretsInError(deleteError, updateSecrets) : void 0 });
43283
+ const shownSecrets = unionOfSecretBags([updateSecrets, this.printingSecretsFor(logicalId)]);
43284
+ throw new Error(safeMsg`Failed to destroy old resource ${maskSecretsInText(logicalId, shownSecrets)} ` + safeMsg`(${maskSecretsInText(currentResource.physicalId, shownSecrets)}) during ${recreateFlagName}: ` + safeMsg`${asIsMessage(maskSecretsInText(deleteError instanceof Error ? deleteError.message : String(deleteError), shownSecrets))}`, { cause: deleteError instanceof Error ? maskSecretsInError(deleteError, updateSecrets) : void 0 });
42693
43285
  }
42694
43286
  reportDeleteGuards(recreateDeleteResult, {
42695
43287
  physicalId: currentResource.physicalId,
@@ -42698,10 +43290,10 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42698
43290
  });
42699
43291
  const recreateSkipReason = deleteSkipReason(recreateDeleteResult);
42700
43292
  if (recreateSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, recreateSkipReason, `during ${recreateFlagName}`));
42701
- this.logger.info(` ${green("✓")} Old resource deleted`);
43293
+ this.logger.info(safeMsg` ${green("✓")} Old resource deleted`);
42702
43294
  this.oldDeletedBeforeCreate.add(logicalId);
42703
43295
  }
42704
- this.logger.info(` Creating new ${logicalId}...`);
43296
+ this.logger.info(safeMsg` Creating new ${logicalId}...`);
42705
43297
  createResult = await withRetry(() => this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replaceProvider.create(logicalId, resourceType, replaceProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replaceProvider), logicalId, {
42706
43298
  maxRetries: 8,
42707
43299
  initialDelayMs: 2e3,
@@ -42711,9 +43303,9 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42711
43303
  onInterrupted: () => new InterruptedError(this.interruptCause ?? "user"),
42712
43304
  isRetryable: isRecreateRetryableError
42713
43305
  });
42714
- if (equalIdIsSameResource && updateReplacePolicy === "Retain" && createResult.physicalId === currentResource.physicalId) throw new CdkdError(`${logicalId} (${resourceType}) recreate returned the existing resource (${currentResource.physicalId}) instead of creating a new one — its Create API is name-idempotent — and UpdateReplacePolicy: Retain means the old resource was never destroyed, so the new properties were not applied. Rename the resource in your CDK code (or remove the explicit physical name) so the recreate can produce a genuinely new resource.`, "NAMED_REPLACEMENT_IDEMPOTENT_CREATE");
43306
+ if (equalIdIsSameResource && updateReplacePolicy === "Retain" && createResult.physicalId === currentResource.physicalId) throw new CdkdError(safeMsg`${logicalId} (${resourceType}) recreate returned the existing resource ` + safeMsg`(${currentResource.physicalId}) instead of creating a new one — its Create ` + "API is name-idempotent — and UpdateReplacePolicy: Retain means the old resource was never destroyed, so the new properties were not applied. Rename the resource in your CDK code (or remove the explicit physical name) so the recreate can produce a genuinely new resource.", "NAMED_REPLACEMENT_IDEMPOTENT_CREATE");
42715
43307
  } else {
42716
- this.logger.info(` Creating new ${logicalId}...`);
43308
+ this.logger.info(safeMsg` Creating new ${logicalId}...`);
42717
43309
  let deletedOldFirst = lostWithParent !== void 0;
42718
43310
  if (lostWithParent !== void 0) {
42719
43311
  this.oldDeletedBeforeCreate.add(logicalId);
@@ -42733,7 +43325,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42733
43325
  observed: currentResource.observedProperties,
42734
43326
  physicalId: currentResource.physicalId
42735
43327
  });
42736
- if (nameHeldElsewhere !== void 0) throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement, but the create-first attempt collided: ${createMsg}. ${renderNameHeldElsewhere(nameHeldElsewhere)}` + (this.options.replace === true ? ` — so --replace was NOT applied and nothing was deleted.` : updateReplacePolicy === "Retain" ? " — so removing UpdateReplacePolicy: Retain and re-running with `cdkd deploy --replace` would delete this resource and still collide." : " — so `cdkd deploy --replace` would delete this resource and still collide.") + " Choose a name no other resource holds, or delete the resource holding it if it is yours.", "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
43328
+ if (nameHeldElsewhere !== void 0) throw markNonRetryable(new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement, but the create-first ` + safeMsg`attempt collided: ${createMsg}. ${renderNameHeldElsewhere(nameHeldElsewhere)}` + (this.options.replace === true ? ` — so --replace was NOT applied and nothing was deleted.` : updateReplacePolicy === "Retain" ? " — so removing UpdateReplacePolicy: Retain and re-running with `cdkd deploy --replace` would delete this resource and still collide." : " — so `cdkd deploy --replace` would delete this resource and still collide.") + " Choose a name no other resource holds, or delete the resource holding it if it is yours.", "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
42737
43329
  const holder = replacementOldHoldsSentName({
42738
43330
  createType: resourceType,
42739
43331
  holderType: oldResourceType,
@@ -42751,26 +43343,26 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42751
43343
  const flagClause = this.options.replace === true ? ` --replace was NOT applied and nothing was deleted.` : updateReplacePolicy === "Retain" ? " Nothing was deleted. UpdateReplacePolicy: Retain keeps the resource being replaced in place; removing it and re-running with `cdkd deploy --replace` would refuse the same way rather than delete it." : " Nothing was deleted, and `cdkd deploy --replace` would refuse the same way rather than delete it.";
42752
43344
  throw markNonRetryable(new CdkdError(maskSecretsInText(`${displaySafe(logicalId)} (${displaySafe(resourceType)}) requires replacement, but the create-first attempt collided: ${holder.diagnosis} — ` + (holder.known ? "so another resource holds the colliding name (an orphan of an earlier attempt, or one made outside this stack), and deleting the resource being replaced would destroy it and collide again." + flagClause + " Remove or rename the resource holding that name if it is yours, then re-run the deploy." : "so if another resource holds it (an orphan of an earlier attempt, or one made outside this stack), deleting the resource being replaced would destroy it and collide again." + flagClause + " Remove or rename whatever holds that name if it is yours — if that is the resource being replaced itself, delete it by hand — then re-run the deploy.") + ` Underlying collision: ${createMsg}`, updateSecrets), "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
42753
43345
  }
42754
- if (updateReplacePolicy === "Retain") throw new CdkdError(`${logicalId} (${resourceType}) requires replacement, but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. ${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed.`, "NAMED_REPLACEMENT_COLLISION");
42755
- 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");
42756
- this.logger.info(` Create-first collided with the existing resource's name and --replace is set — deleting old ${logicalId} (${currentResource.physicalId}) first...`);
43346
+ if (updateReplacePolicy === "Retain") throw new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement, but its physical name ` + `is still held by the existing resource AND UpdateReplacePolicy: Retain ` + safeMsg`pins that resource in place. ${nameOrigin.descriptor}. ` + safeMsg`${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a ` + `same-name replacement can never proceed.`, "NAMED_REPLACEMENT_COLLISION");
43347
+ if (this.options.replace !== true) throw new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement, but the create-first ` + safeMsg`attempt collided with the existing resource: ${createMsg}. ` + safeMsg`${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\". " + safeMsg`${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");
43348
+ this.logger.info(` Create-first collided with the existing resource's name and --replace is ` + safeMsg`set — deleting old ${logicalId} (${currentResource.physicalId}) first...`);
42757
43349
  deletedOldFirst = true;
42758
43350
  createResult = await this.replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, updateSecrets, updateReplacePolicy, oldDeleteRoute.provisionedBy, noEchoDeleteValues);
42759
43351
  }
42760
43352
  if (equalIdIsSameResource && !deletedOldFirst && createResult.physicalId === currentResource.physicalId) {
42761
43353
  const idempotentNameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
42762
- if (updateReplacePolicy === "Retain") 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, and UpdateReplacePolicy: Retain pins that resource in place. ${idempotentNameOrigin.descriptor}. ${idempotentNameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed.`, "NAMED_REPLACEMENT_IDEMPOTENT_CREATE");
42763
- 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");
42764
- this.logger.info(` Create-first returned the existing resource (name-idempotent Create API) and --replace is set — deleting old ${logicalId} (${currentResource.physicalId}) first...`);
43354
+ if (updateReplacePolicy === "Retain") throw new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement, but its Create API is ` + `name-idempotent: the create-first attempt returned the existing resource ` + safeMsg`(${currentResource.physicalId}) instead of creating a new one, and ` + `UpdateReplacePolicy: Retain pins that resource in place. ` + safeMsg`${idempotentNameOrigin.descriptor}. ${idempotentNameOrigin.remedy} — with ` + "Retain, the old resource keeps the name, so a same-name replacement can never proceed.", "NAMED_REPLACEMENT_IDEMPOTENT_CREATE");
43355
+ if (this.options.replace !== true) throw new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement, but its Create API is ` + `name-idempotent: the create-first attempt returned the EXISTING resource ` + safeMsg`(${currentResource.physicalId}) instead of creating a new one, so deleting ` + `the "old" resource would silently destroy the resource the deploy just ` + safeMsg`reported as created. ${idempotentNameOrigin.descriptor}; ` + safeMsg`${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");
43356
+ this.logger.info(` Create-first returned the existing resource (name-idempotent Create API) ` + safeMsg`and --replace is set — deleting old ${logicalId} ` + safeMsg`(${currentResource.physicalId}) first...`);
42765
43357
  deletedOldFirst = true;
42766
43358
  createResult = await this.replaceDeleteFirstAndRecreate(logicalId, resourceType, oldResourceType, currentResource, oldDeleteProvider, replaceProvider, replaceProps, updateSecrets, updateReplacePolicy, oldDeleteRoute.provisionedBy, noEchoDeleteValues);
42767
43359
  }
42768
43360
  if (deletedOldFirst) {} else if (updateReplacePolicy === "Retain") {
42769
43361
  this.retainedOldOnReplacement.add(logicalId);
42770
43362
  await noteRetainedResource(oldResourceType, logicalId);
42771
- this.logger.info(` Retaining old ${logicalId} (${currentResource.physicalId}) - UpdateReplacePolicy: Retain`);
43363
+ this.logger.info(safeMsg` Retaining old ${logicalId} (${currentResource.physicalId}) - UpdateReplacePolicy: Retain`);
42772
43364
  } else {
42773
- this.logger.info(` Deleting old ${logicalId} (${currentResource.physicalId})...`);
43365
+ this.logger.info(safeMsg` Deleting old ${logicalId} (${currentResource.physicalId})...`);
42774
43366
  let cleanupFinalSnapshotId;
42775
43367
  let snapshotBlockedDelete = false;
42776
43368
  try {
@@ -42778,7 +43370,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42778
43370
  } catch (snapshotError) {
42779
43371
  if (snapshotError instanceof CdkdError && snapshotError.code === "FINAL_SNAPSHOT_UNSUPPORTED") throw snapshotError;
42780
43372
  snapshotBlockedDelete = true;
42781
- 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.`);
43373
+ this.logger.warn(safeMsg` ⚠ Final snapshot for old ${logicalId} (${currentResource.physicalId}) ` + safeMsg`failed: ${asIsMessage(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.");
42782
43374
  }
42783
43375
  if (!snapshotBlockedDelete) await this.deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, oldDeleteProvider, currentResource.properties, cleanupFinalSnapshotId, updateReplacePolicy, updateSecrets, oldDeleteRoute.provisionedBy, noEchoDeleteValues);
42784
43376
  }
@@ -42804,9 +43396,9 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42804
43396
  const replacePrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
42805
43397
  renderer.removeTask(logicalId);
42806
43398
  const replacedSkip = this.replacedDeleteSkips.get(logicalId);
42807
- const replacedLine = `${replacePrefix}${yellow("↻")} ${bold(logicalId)} ${gray(`(${resourceType})`)} ${yellow("replaced")}`;
43399
+ const replacedLine = safeMsg`${replacePrefix}${yellow("↻")} ${bold(logicalId)} ${gray(`(${resourceType})`)} ${yellow("replaced")}`;
42808
43400
  if (replacedSkip !== void 0) {
42809
- this.logger.warn(replacedLine + " " + updatePartialMessage(replacedSkip));
43401
+ this.logger.warn(safeMsg`${replacedLine} ${updatePartialMessage(replacedSkip)}`);
42810
43402
  return;
42811
43403
  }
42812
43404
  this.logger.info(replacedLine);
@@ -42815,7 +43407,7 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
42815
43407
  //#endregion
42816
43408
  //#region src/deployment/deploy-engine/update-in-place.ts
42817
43409
  async function updateInPlace({ conditions, counts, currentProps, currentPropsAsWritten, currentResource, dependencies, desiredForSkipCheckAsWritten, logicalId, noEchoHeldPaths, parameterValues, progress, renderer, resolvedProps, resourceType, stackName, stateResources, template, updateReplacePolicy, updateSecrets, reattach }) {
42818
- this.logger.debug(`Updating ${logicalId} (${resourceType})`);
43410
+ this.logger.debug(safeMsg`Updating ${logicalId} (${resourceType})`);
42819
43411
  const updateDecision = this.providerRegistry.getProviderFor({
42820
43412
  resourceType,
42821
43413
  properties: resolvedProps,
@@ -42829,12 +43421,12 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
42829
43421
  let message;
42830
43422
  switch (exemptMode) {
42831
43423
  case "cc-broken":
42832
- message = `${logicalId} (${resourceType}): moving to the SDK provider — Cloud Control cannot manage this type correctly. ${preserved}, and this routing is not optional.`;
43424
+ message = safeMsg`${logicalId} (${resourceType}): moving to the SDK provider — Cloud ` + `Control cannot manage this type correctly. ${preserved}, and this routing is not optional.`;
42833
43425
  break;
42834
43426
  case "sdk-coverage":
42835
- message = `${logicalId} (${resourceType}): returning to the SDK provider — cdkd now covers every property this resource uses. ${preserved}; pass --pin-cc-api ${logicalId} to decline this for a deploy.`;
43427
+ message = safeMsg`${logicalId} (${resourceType}): returning to the SDK provider — cdkd now ` + `covers every property this resource uses. ${preserved}; pass ` + safeMsg`--pin-cc-api ${logicalId} to decline this for a deploy.`;
42836
43428
  break;
42837
- default: message = `${logicalId} (${resourceType}): moving to the SDK provider. ${preserved}.`;
43429
+ default: message = safeMsg`${logicalId} (${resourceType}): moving to the SDK provider. ${preserved}.`;
42838
43430
  }
42839
43431
  this.logger.info(message);
42840
43432
  }
@@ -42882,7 +43474,7 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
42882
43474
  const statefulReason = retainOldOnReplace ? null : isStatefulRecreateTargetForReplace(resourceType, currentProps, currentResource.observedProperties);
42883
43475
  if (statefulReason && this.options.forceStatefulRecreation !== true) {
42884
43476
  const protection = recordedProtectionEvidence(resourceType, currentProps, currentResource.observedProperties, this.stackRegion);
42885
- throw markNonRetryable(new CdkdError(replaceOptIn ? `--replace would DELETE + CREATE the stateful resource ${logicalId} (${resourceType}) — ${renderStatefulReason(statefulReason)}. ` + (protection ? `${recordedProtectionNote(protection, "--replace --force-stateful-recreation")} Or change the resource's definition to avoid the immutable-property change.` : "Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.") : `${logicalId} (${resourceType}) cannot be updated in place by the provisioning layer it routes through, so applying this change would DELETE + CREATE it — but it is a stateful resource: ${renderStatefulReason(statefulReason)}. ` + (protection ? `${recordedProtectionNote(protection, "--force-stateful-recreation")} Or change the resource's definition to avoid the update.` : "Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the update."), "STATEFUL_REPLACE_BLOCKED", updateError instanceof Error ? updateError : void 0));
43477
+ throw markNonRetryable(new CdkdError(replaceOptIn ? safeMsg`--replace would DELETE + CREATE the stateful resource ${logicalId} ` + safeMsg`(${resourceType}) — ${renderStatefulReason(statefulReason)}. ` + (protection ? safeMsg`${recordedProtectionNote(protection, "--replace --force-stateful-recreation")} ` + `Or change the resource's definition to avoid the immutable-property change.` : "Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.") : safeMsg`${logicalId} (${resourceType}) cannot be updated in place by the ` + "provisioning layer it routes through, so applying this change would DELETE + CREATE it — but it is a stateful resource: " + safeMsg`${renderStatefulReason(statefulReason)}. ` + (protection ? safeMsg`${recordedProtectionNote(protection, "--force-stateful-recreation")} ` + `Or change the resource's definition to avoid the update.` : "Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the update."), "STATEFUL_REPLACE_BLOCKED", updateError instanceof Error ? updateError : void 0));
42886
43478
  }
42887
43479
  const replDecision = this.providerRegistry.getProviderFor({
42888
43480
  resourceType,
@@ -42913,7 +43505,7 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
42913
43505
  secrets: updateSecrets,
42914
43506
  inputSources: template && this.maskedInputSources(template, stateResources, this.noEchoConditions, stackName)
42915
43507
  });
42916
- this.logger.info(retainOldOnReplace ? `UPDATE not supported for ${logicalId} (${resourceType}), replacing (CREATE only — UpdateReplacePolicy: Retain keeps the old resource)` : createFirst ? safeMsg`UPDATE not supported for ${logicalId} (${resourceType}), replacing (CREATE → DELETE — the new name differs from the old resource's)` : `UPDATE not supported for ${logicalId} (${resourceType}), replacing (DELETE → CREATE)`);
43508
+ this.logger.info(retainOldOnReplace ? safeMsg`UPDATE not supported for ${logicalId} (${resourceType}), replacing ` + `(CREATE only — UpdateReplacePolicy: Retain keeps the old resource)` : createFirst ? safeMsg`UPDATE not supported for ${logicalId} (${resourceType}), replacing (CREATE → DELETE — the new name differs from the old resource's)` : safeMsg`UPDATE not supported for ${logicalId} (${resourceType}), replacing (DELETE → CREATE)`);
42917
43509
  if (retainOldOnReplace) await noteRetainedResource(resourceType, logicalId);
42918
43510
  if (!retainOldOnReplace && !createFirst) {
42919
43511
  const fallbackUpdateReplacePolicy = template?.Resources?.[logicalId]?.UpdateReplacePolicy ?? currentResource.updateReplacePolicy;
@@ -42932,7 +43524,7 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
42932
43524
  }));
42933
43525
  } catch (deleteError) {
42934
43526
  const deleteMsg = deleteError instanceof Error ? deleteError.message : String(deleteError);
42935
- 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`);
43527
+ if (!isWaitAbandonedError(deleteError) && !isInterruptedWaitError(deleteError) && !isMarkedNonRetryable(deleteError) && (deleteMsg.includes("does not exist") || deleteMsg.includes("not found") || deleteMsg.includes("NotFound"))) this.logger.debug(safeMsg`Old resource ${logicalId} already gone, proceeding with CREATE`);
42936
43528
  else throw deleteError;
42937
43529
  }
42938
43530
  reportDeleteGuards(fallbackDeleteResult, {
@@ -42972,7 +43564,10 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
42972
43564
  }) : await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replProvider);
42973
43565
  } catch (createError) {
42974
43566
  if (createFirst) throw createError;
42975
- if (!retainOldOnReplace) throw new Error(maskSecretsInText(`Failed to create ${logicalId} after the UPDATE-not-supported replacement: the old resource (${currentResource.physicalId}) is now gone. Cause: ${createError instanceof Error ? createError.message : String(createError)}. Re-run the deploy to create it fresh.`, updateSecrets), { cause: createError instanceof Error ? createError : void 0 });
43567
+ if (!retainOldOnReplace) {
43568
+ const shownSecrets = unionOfSecretBags([updateSecrets, this.printingSecretsFor(logicalId)]);
43569
+ throw new Error(safeMsg`Failed to create ${maskSecretsInText(logicalId, shownSecrets)} after the ` + safeMsg`UPDATE-not-supported replacement: the old resource (${maskSecretsInText(currentResource.physicalId, shownSecrets)}) ` + safeMsg`is now gone. Re-run the deploy to create it fresh. Cause: ${asIsMessage(maskSecretsInText(createError instanceof Error ? createError.message : String(createError), shownSecrets))}`, { cause: createError instanceof Error ? createError : void 0 });
43570
+ }
42976
43571
  if (!isNameCollisionErrorFrom(createError, logicalId)) throw createError;
42977
43572
  const nameHeldElsewhere = replacementRequestsDifferentName({
42978
43573
  oldResourceType: resourceType,
@@ -42982,9 +43577,9 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
42982
43577
  observed: currentResource.observedProperties,
42983
43578
  physicalId: currentResource.physicalId
42984
43579
  });
42985
- if (nameHeldElsewhere !== void 0) throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement because the provisioning layer cannot update it in place, but the create collided. ${renderNameHeldElsewhere(nameHeldElsewhere)} — so removing UpdateReplacePolicy: Retain would delete this resource and still collide. Choose a name no other resource holds, or delete the resource holding it if it is yours.`, "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
43580
+ if (nameHeldElsewhere !== void 0) throw markNonRetryable(new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement because the ` + `provisioning layer cannot update it in place, but the create collided. ` + safeMsg`${renderNameHeldElsewhere(nameHeldElsewhere)} — so removing ` + "UpdateReplacePolicy: Retain would delete this resource and still collide. Choose a name no other resource holds, or delete the resource holding it if it is yours.", "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
42986
43581
  const nameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
42987
- throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement because the provisioning layer cannot update it in place — but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. ${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed. Removing UpdateReplacePolicy: Retain lets cdkd delete the old resource first, which destroys it and any data it holds.`, "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
43582
+ throw markNonRetryable(new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement because the ` + "provisioning layer cannot update it in place — but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. " + safeMsg`${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old ` + "resource keeps the name, so a same-name replacement can never proceed. Removing UpdateReplacePolicy: Retain lets cdkd delete the old resource first, which destroys it and any data it holds.", "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
42988
43583
  }
42989
43584
  if (!retainOldOnReplace && !createFirst && createResult.physicalId === currentResource.physicalId && !equalIdNamesDifferentResources({
42990
43585
  resourceType,
@@ -43000,10 +43595,10 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
43000
43595
  newProperties: resolvedProps
43001
43596
  })) {
43002
43597
  const idempotentNameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
43003
- throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement, but its Create API is name-idempotent: the create returned the existing resource (${currentResource.physicalId}) instead of creating a new one, and UpdateReplacePolicy: Retain pins that resource in place, so the new properties were not applied. ${idempotentNameOrigin.descriptor}. ${idempotentNameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed.`, "NAMED_REPLACEMENT_IDEMPOTENT_CREATE"));
43598
+ throw markNonRetryable(new CdkdError(safeMsg`${logicalId} (${resourceType}) requires replacement, but its Create ` + `API is name-idempotent: the create returned the existing resource ` + safeMsg`(${currentResource.physicalId}) instead of creating a new one, and ` + `UpdateReplacePolicy: Retain pins that resource in place, so the new ` + safeMsg`properties were not applied. ${idempotentNameOrigin.descriptor}. ` + safeMsg`${idempotentNameOrigin.remedy} — with Retain, the old resource keeps ` + `the name, so a same-name replacement can never proceed.`, "NAMED_REPLACEMENT_IDEMPOTENT_CREATE"));
43004
43599
  }
43005
43600
  this.retainedOldOnReplacement.add(logicalId);
43006
- this.logger.warn(` ⚠ ${logicalId} has UpdateReplacePolicy: Retain — the old physical resource (${currentResource.physicalId}) is RETAINED and is no longer tracked by cdkd: it keeps running and incurring cost, and \`cdkd destroy\` will not remove it. Delete it yourself once you no longer need its data.`);
43601
+ this.logger.warn(safeMsg` ⚠ ${logicalId} has UpdateReplacePolicy: Retain — the old physical ` + safeMsg`resource (${currentResource.physicalId}) is RETAINED and is no longer ` + "tracked by cdkd: it keeps running and incurring cost, and `cdkd destroy` will not remove it. Delete it yourself once you no longer need its data.");
43007
43602
  retainedSurvivorReason = `UpdateReplacePolicy: Retain kept the old ${resourceType} (${currentResource.physicalId}), now untracked by cdkd`;
43008
43603
  }
43009
43604
  const replacementResult = {
@@ -43034,7 +43629,7 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
43034
43629
  physicalId: result.physicalId,
43035
43630
  properties: resolvedProps
43036
43631
  });
43037
- this.logger.info(`Resource ${logicalId} was replaced: ${currentResource.physicalId} -> ${result.physicalId}`);
43632
+ this.logger.info(safeMsg`Resource ${logicalId} was replaced: ${currentResource.physicalId} -> ${result.physicalId}`);
43038
43633
  }
43039
43634
  const dischargedByReplacement = result.wasReplaced === true && result.physicalId !== currentResource.physicalId;
43040
43635
  const keepsParameterRefusal = !dischargedByReplacement && hasUnverifiableParameterRefusal(currentResource);
@@ -43063,7 +43658,7 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
43063
43658
  }
43064
43659
  };
43065
43660
  if (updatePartialReason(result) === void 0) this.recordInlinePolicyWrite(logicalId, "update");
43066
- if (keepsParameterRefusal) this.logger.debug(`observedProperties capture SKIPPED for updated ${logicalId} (${resourceType}): 'cdkd import' refused its baseline because a template parameter was not provably deployed at its 'Default', and this deploy bound the same 'Default' — an in-place update cannot show that AWS no longer holds the deployed value. The refusal stands until the resource is replaced or re-imported against a CloudFormation stack that proves the parameter.`);
43661
+ if (keepsParameterRefusal) this.logger.debug(safeMsg`observedProperties capture SKIPPED for updated ${logicalId} (${resourceType}): 'cdkd import' refused its baseline because a template parameter was not provably deployed at its 'Default', and this deploy bound the same 'Default' — an in-place update cannot show that AWS no longer holds the deployed value. The refusal stands until the resource is replaced or re-imported against a CloudFormation stack that proves the parameter.`);
43067
43662
  const updateCaptureSiblings = keepsParameterRefusal ? void 0 : await this.buildObservedCaptureSiblings(resourceType, logicalId, result.physicalId, template, stateResources, stackName, parameterValues, conditions);
43068
43663
  if (!keepsParameterRefusal) this.kickOffObservedCapture(captureProvider, logicalId, result.physicalId, resourceType, resolvedProps, {
43069
43664
  ...updateCaptureSiblings,
@@ -43080,11 +43675,11 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
43080
43675
  const replacedSkip = this.replacedDeleteSkips.get(logicalId);
43081
43676
  const shownPartial = updatePartial !== void 0 && replacedSkip !== void 0 ? `${updatePartial}; ${replacedSkip}` : updatePartial ?? replacedSkip;
43082
43677
  if (shownPartial !== void 0) {
43083
- this.logger.warn(`${updatePrefix}${formatResourceLine("updated", logicalId, resourceType)} ` + updatePartialMessage(shownPartial));
43678
+ this.logger.warn(safeMsg`${updatePrefix}${formatResourceLine("updated", logicalId, resourceType)} ` + safeMsg`${updatePartialMessage(shownPartial)}`);
43084
43679
  if (updatePartial !== void 0) return { updatePartial };
43085
43680
  return;
43086
43681
  }
43087
- this.logger.info(`${updatePrefix}${formatResourceLine("updated", logicalId, resourceType)}`);
43682
+ this.logger.info(safeMsg`${updatePrefix}${formatResourceLine("updated", logicalId, resourceType)}`);
43088
43683
  }
43089
43684
 
43090
43685
  //#endregion
@@ -43169,10 +43764,10 @@ async function provisionDelete(logicalId, change, stateResources, stackName, tem
43169
43764
  const existingState = stateResources[logicalId];
43170
43765
  const renderer = getLiveRenderer();
43171
43766
  const currentResource = existingState;
43172
- if (!currentResource) throw new Error(`Cannot delete ${logicalId}: resource not found in state`);
43767
+ if (!currentResource) throw new Error(safeMsg`Cannot delete ${logicalId}: resource not found in state`);
43173
43768
  const deletionPolicy = currentResource.deletionPolicy ?? template?.Resources?.[logicalId]?.DeletionPolicy;
43174
43769
  if (shouldRetainResource(deletionPolicy)) {
43175
- this.logger.info(`Retaining ${logicalId} (${resourceType}) - DeletionPolicy: ${deletionPolicy}`);
43770
+ this.logger.info(safeMsg`Retaining ${logicalId} (${resourceType}) - DeletionPolicy: ${deletionPolicy}`);
43176
43771
  delete stateResources[logicalId];
43177
43772
  await noteRetainedResource(resourceType, logicalId);
43178
43773
  if (keptForReadoption(currentResource)) {
@@ -43244,7 +43839,7 @@ Drop the record with: ${dropCommand}`);
43244
43839
  provisionedBy: currentResource.provisionedBy
43245
43840
  });
43246
43841
  const deleteProvider = deleteRoute.provider;
43247
- this.logger.debug(`Deleting ${logicalId} (${resourceType})`);
43842
+ this.logger.debug(safeMsg`Deleting ${logicalId} (${resourceType})`);
43248
43843
  let deleteResult = void 0;
43249
43844
  const inlinePolicyClaimed = this.inlinePolicyClaimedFor(resourceType, logicalId, stateResources);
43250
43845
  try {
@@ -43260,7 +43855,7 @@ Drop the record with: ${dropCommand}`);
43260
43855
  }), logicalId, 3, 5e3, deleteProvider);
43261
43856
  } catch (deleteError) {
43262
43857
  const msg = deleteError instanceof Error ? deleteError.message : String(deleteError);
43263
- 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`);
43858
+ 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(safeMsg`Resource ${logicalId} already deleted (${asIsMessage(msg)}), removing from state`);
43264
43859
  else throw deleteError;
43265
43860
  }
43266
43861
  reportDeleteGuards(deleteResult, {
@@ -43273,7 +43868,7 @@ Drop the record with: ${dropCommand}`);
43273
43868
  if (progress) progress.current++;
43274
43869
  const skipPrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
43275
43870
  renderer.removeTask(logicalId);
43276
- this.logger.info(`${skipPrefix}${formatResourceLine("skipped", logicalId, resourceType, `skipped (${deleteSkipped})`)}`);
43871
+ this.logger.info(safeMsg`${skipPrefix}${formatResourceLine("skipped", logicalId, resourceType, `skipped (${deleteSkipped})`)}`);
43277
43872
  const nested = resourceType === "AWS::CloudFormation::Stack";
43278
43873
  const recordStack = nested ? nestedChildStackName(stackName, logicalId) : stackName;
43279
43874
  const interrupted = nested && deleteSkipped.endsWith(" was interrupted");
@@ -43285,7 +43880,7 @@ Drop the record with: ${dropCommand}`);
43285
43880
  hole: nested ? "child-stack" : "stack",
43286
43881
  opts: { plainIdent: true }
43287
43882
  };
43288
- 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.") + (accountClause === "" ? "" : ` ${accountClause}`) + `\nInspect it with: ${pasteableCommand("cdkd state show", [
43883
+ this.logger.warn(safeMsg`${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.") + (accountClause === "" ? "" : safeMsg` ${accountClause}`) + safeMsg`\nInspect it with: ${pasteableCommand("cdkd state show", [
43289
43884
  stackArg,
43290
43885
  {
43291
43886
  flag: "--stack-region",
@@ -43293,7 +43888,7 @@ Drop the record with: ${dropCommand}`);
43293
43888
  hole: "region"
43294
43889
  },
43295
43890
  ...account
43296
- ]).command}\nDrop the record with: ${pasteableCommand("cdkd state orphan", [
43891
+ ]).command}` + safeMsg`\nDrop the record with: ${pasteableCommand("cdkd state orphan", [
43297
43892
  stackArg,
43298
43893
  {
43299
43894
  flag: "--stack-region",
@@ -43316,7 +43911,7 @@ Drop the record with: ${dropCommand}`);
43316
43911
  if (progress) progress.current++;
43317
43912
  const deletePrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
43318
43913
  renderer.removeTask(logicalId);
43319
- this.logger.info(`${deletePrefix}${formatResourceLine("deleted", logicalId, resourceType)}`);
43914
+ this.logger.info(safeMsg`${deletePrefix}${formatResourceLine("deleted", logicalId, resourceType)}`);
43320
43915
  }
43321
43916
 
43322
43917
  //#endregion
@@ -43384,6 +43979,8 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
43384
43979
  }
43385
43980
  } else updatePartial = `${updatePartial}; ${replacedSkip}`;
43386
43981
  }
43982
+ const deferred = this.deferredReplacedDeletes?.get(logicalId);
43983
+ if (deferred !== void 0 && updatePartial !== void 0) deferred.rowPartial = true;
43387
43984
  nestedChildUnaddressed = unaddressed;
43388
43985
  } finally {
43389
43986
  for (const guard of deleteGuards.splice(0)) this.recordEvent({
@@ -43408,7 +44005,7 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
43408
44005
  if (current !== void 0) current.warnSuffix = warnSuffix;
43409
44006
  renderer.updateTaskLabel(logicalId, `${current?.label ?? baseLabel}${warnSuffix}`);
43410
44007
  renderer.printAbove(() => {
43411
- this.logger.warn(`${logicalId} (${resourceType}) has been ${operationKind === "CREATE" ? "creating" : operationKind === "DELETE" ? "deleting" : "updating"} for ${minutes}m — still waiting`);
44008
+ this.logger.warn(safeMsg`${logicalId} (${resourceType}) has been ${operationKind === "CREATE" ? "creating" : operationKind === "DELETE" ? "deleting" : "updating"} for ${minutes}m — still waiting`);
43412
44009
  });
43413
44010
  },
43414
44011
  onTimeout: (elapsedMs) => new ResourceTimeoutError(logicalId, resourceType, this.stackRegion, elapsedMs, operationKind, timeoutMs)
@@ -43456,7 +44053,9 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
43456
44053
  } catch (error) {
43457
44054
  renderer.removeTask(logicalId);
43458
44055
  const message = error instanceof Error ? error.message : String(error);
43459
- this.logger.error(this.maskForResource(logicalId, `Failed to ${change.changeType.toLowerCase()} ${logicalId}: ${message}`));
44056
+ const shownMessage = this.maskForResource(logicalId, message);
44057
+ const shownId = safeMsg`${logicalId}`;
44058
+ this.logger.error(this.maskForResource(logicalId, `Failed to ${change.changeType.toLowerCase()} ${shownId}: ${shownMessage}`));
43460
44059
  const orphanAdvice = this.orphanedNameCollisionAdvice(change.changeType, logicalId, error);
43461
44060
  if (orphanAdvice) this.logger.error(this.maskForResource(logicalId, orphanAdvice));
43462
44061
  this.recordEvent({
@@ -43469,7 +44068,7 @@ async function provisionResource(logicalId, change, stateResources, stackName, t
43469
44068
  durationMs: Date.now() - resourceStartedAt,
43470
44069
  error: extractDeploymentEventError(error)
43471
44070
  });
43472
- 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);
44071
+ throw new ProvisioningError(safeMsg`Failed to ${change.changeType.toLowerCase()} resource ${logicalId}`, resourceType, logicalId, stateResources[logicalId]?.physicalId, error instanceof Error ? maskSecretsInError(error, this.printingSecretsFor(logicalId) ?? EMPTY_SECRETS) : void 0);
43473
44072
  } finally {
43474
44073
  renderer.removeTask(logicalId);
43475
44074
  }
@@ -43649,9 +44248,9 @@ async function executeDeployment(template, currentState, changes, dag, execution
43649
44248
  migrateLegacy: migrate
43650
44249
  });
43651
44250
  if (migrate) pendingMigration = false;
43652
- this.logger.debug(`State saved after ${logicalId}`);
44251
+ this.logger.debug(safeMsg`State saved after ${logicalId}`);
43653
44252
  } catch (error) {
43654
- this.logger.warn(`Failed to save state after ${logicalId}: ${error instanceof Error ? error.message : String(error)}`);
44253
+ this.logger.warn(safeMsg`Failed to save state after ${logicalId}: ${asIsMessage(error instanceof Error ? error.message : String(error))}`);
43655
44254
  }
43656
44255
  });
43657
44256
  };
@@ -43660,6 +44259,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
43660
44259
  const settledUpdates = /* @__PURE__ */ new Set();
43661
44260
  const inFlightWrites = /* @__PURE__ */ new Map();
43662
44261
  this.stackRecordsView = deployStackRecordsView(newResources, currentState.resources, deleteChanges, (logicalId) => startedUpdates.has(logicalId) && !settledUpdates.has(logicalId), () => [...inFlightWrites.values()].map(({ write }) => write));
44262
+ this.deferredReplacedDeletes = /* @__PURE__ */ new Map();
43663
44263
  try {
43664
44264
  const createUpdateIds = [];
43665
44265
  for (const [id, change] of changes.entries()) {
@@ -43668,7 +44268,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
43668
44268
  createUpdateIds.push(id);
43669
44269
  }
43670
44270
  if (createUpdateIds.length > 0) {
43671
- this.logger.info(`${cyan("Deploying")} ${cyan(createUpdateIds.length)} resource(s) (DAG: ${executionLevels.length} levels, max parallel: ${concurrency})`);
44271
+ this.logger.info(safeMsg`${cyan("Deploying")} ${cyan(createUpdateIds.length)} resource(s) (DAG: ${executionLevels.length} levels, max parallel: ${concurrency})`);
43672
44272
  const createUpdateExecutor = new DagExecutor();
43673
44273
  const provisionable = new Set(createUpdateIds);
43674
44274
  const createUpdateDeps = /* @__PURE__ */ new Map();
@@ -43837,7 +44437,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
43837
44437
  if (this.interrupted && this.hasPending(createUpdateExecutor)) throw new InterruptedError(this.interruptCause ?? "user");
43838
44438
  }
43839
44439
  if (deleteChanges.size > 0) {
43840
- this.logger.info(`${red("Deleting")} ${red(deleteChanges.size)} resource(s)`);
44440
+ this.logger.info(safeMsg`${red("Deleting")} ${red(deleteChanges.size)} resource(s)`);
43841
44441
  const deleteDeps = this.buildDeletionDependencies(deleteChanges, currentState);
43842
44442
  const deleteExecutor = new DagExecutor();
43843
44443
  for (const id of deleteChanges) deleteExecutor.add({
@@ -43882,7 +44482,10 @@ async function executeDeployment(template, currentState, changes, dag, execution
43882
44482
  }
43883
44483
  if (this.interrupted && this.hasPending(deleteExecutor)) throw new InterruptedError(this.interruptCause ?? "user");
43884
44484
  }
44485
+ if (this.interrupted) this.warnUnretriedReplacedDeletes("interrupted");
44486
+ else await this.retryDeferredReplacedDeletes(stackName, actualCounts);
43885
44487
  } catch (error) {
44488
+ this.warnUnretriedReplacedDeletes(this.interruptCause === "user" ? "interrupted" : "failed");
43886
44489
  const initialDeploy = currentEtag === void 0;
43887
44490
  const written = /* @__PURE__ */ new Set([...this.restoredLostChildren, ...completedOperations.map((op) => op.logicalId)]);
43888
44491
  for (const logicalId of this.updatesThatSentNothing) written.delete(logicalId);
@@ -43958,7 +44561,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
43958
44561
  if (migrate) pendingMigration = false;
43959
44562
  this.logger.debug("Partial state saved before rollback (orphaned resource tracking)");
43960
44563
  } catch (saveError) {
43961
- this.logger.warn(`Failed to save partial state before rollback: ${saveError instanceof Error ? saveError.message : String(saveError)}`);
44564
+ this.logger.warn(safeMsg`Failed to save partial state before rollback: ${asIsMessage(saveError instanceof Error ? saveError.message : String(saveError))}`);
43962
44565
  }
43963
44566
  let autoRollbackClean = false;
43964
44567
  let autoRollbackJournaled = false;
@@ -43967,7 +44570,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
43967
44570
  let rollbackRemainingFailedOps = failedOperations;
43968
44571
  if (error instanceof InterruptedError || isInterruptedWaitError(error) || this.interruptCause === "user") {
43969
44572
  await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "interrupted", initialDeploy);
43970
- 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.`);
44573
+ this.logger.info(safeMsg`Partial state saved (${Object.keys(newResources).length} resources). ` + "Run deploy again to resume, 'cdkd rollback' to revert, or destroy to clean up.");
43971
44574
  throw error;
43972
44575
  }
43973
44576
  if (this.options.noRollback) {
@@ -44006,7 +44609,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
44006
44609
  this.logger.debug("State saved after deployment failure");
44007
44610
  if (autoRollbackClean) await this.settleNestedChildrenAfterCleanRollback(stackName, rollbackSettledNested, await this.settleJournalAfterCleanRollback(stackName, rollbackRemainingFailedOps, initialDeploy));
44008
44611
  } catch (saveError) {
44009
- this.logger.debug(`Retrying state save after rollback (ETag mismatch): ${saveError instanceof Error ? saveError.message : String(saveError)}`);
44612
+ this.logger.debug(safeMsg`Retrying state save after rollback (ETag mismatch): ${asIsMessage(saveError instanceof Error ? saveError.message : String(saveError))}`);
44010
44613
  try {
44011
44614
  const freshEtag = (await this.stateBackend.getState(stackName, this.stackRegion))?.etag;
44012
44615
  const postRollbackState = {
@@ -44025,7 +44628,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
44025
44628
  this.logger.debug("State saved after deployment failure (retry succeeded)");
44026
44629
  if (autoRollbackClean) await this.settleNestedChildrenAfterCleanRollback(stackName, rollbackSettledNested, await this.settleJournalAfterCleanRollback(stackName, rollbackRemainingFailedOps, initialDeploy));
44027
44630
  } catch (retryError) {
44028
- this.logger.warn(`Failed to save state after rollback: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
44631
+ this.logger.warn(safeMsg`Failed to save state after rollback: ${asIsMessage(retryError instanceof Error ? retryError.message : String(retryError))}`);
44029
44632
  }
44030
44633
  }
44031
44634
  throw error;
@@ -44080,13 +44683,13 @@ async function persistStateAfterOutputFailure(stackName, currentState, newResour
44080
44683
  });
44081
44684
  this.logger.debug("State saved after output resolution failure");
44082
44685
  } catch (saveError) {
44083
- this.logger.debug(`Retrying state save after output resolution failure (ETag mismatch): ${saveError instanceof Error ? saveError.message : String(saveError)}`);
44686
+ this.logger.debug(safeMsg`Retrying state save after output resolution failure (ETag mismatch): ${asIsMessage(saveError instanceof Error ? saveError.message : String(saveError))}`);
44084
44687
  try {
44085
44688
  const freshEtag = (await this.stateBackend.getState(stackName, this.stackRegion))?.etag;
44086
44689
  await this.stateBackend.saveState(stackName, this.stackRegion, this.withParentInfo(buildState()), { ...freshEtag !== void 0 && { expectedEtag: freshEtag } });
44087
44690
  this.logger.debug("State saved after output resolution failure (retry succeeded)");
44088
44691
  } catch (retryError) {
44089
- this.logger.warn(`Failed to save state after output resolution failure: ${retryError instanceof Error ? retryError.message : String(retryError)} — resources were provisioned but not recorded; run deploy again to reconcile.`);
44692
+ this.logger.warn(safeMsg`Failed to save state after output resolution failure: ${asIsMessage(retryError instanceof Error ? retryError.message : String(retryError))} — resources were provisioned but not recorded; run deploy again to reconcile.`);
44090
44693
  }
44091
44694
  }
44092
44695
  }
@@ -44924,18 +45527,18 @@ function conditionInputsFrom(args) {
44924
45527
  };
44925
45528
  }
44926
45529
  const FINGERPRINT_LAYOUT = 1;
44927
- function isPlainObject(value) {
45530
+ function isPlainObject$1(value) {
44928
45531
  return value !== null && typeof value === "object" && !Array.isArray(value);
44929
45532
  }
44930
45533
  function canonicalJson(value) {
44931
45534
  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
44932
- if (isPlainObject(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
45535
+ if (isPlainObject$1(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
44933
45536
  const encoded = JSON.stringify(value);
44934
45537
  return encoded === void 0 ? "undefined" : encoded;
44935
45538
  }
44936
45539
  function walkModelledDefinition(value, declaredParameters, parameters, conditions) {
44937
45540
  if (typeof value === "string") return !carriesDynamicReference(value);
44938
- if (!isPlainObject(value)) return false;
45541
+ if (!isPlainObject$1(value)) return false;
44939
45542
  const keys = Object.keys(value);
44940
45543
  if (keys.length !== 1) return false;
44941
45544
  const [key] = keys;
@@ -44958,8 +45561,8 @@ function walkModelledDefinition(value, declaredParameters, parameters, condition
44958
45561
  }
44959
45562
  function conditionFingerprint(template, name, inputOf) {
44960
45563
  const definitions = template.Conditions;
44961
- if (!isPlainObject(definitions)) return void 0;
44962
- const declared = isPlainObject(template.Parameters) ? template.Parameters : {};
45564
+ if (!isPlainObject$1(definitions)) return void 0;
45565
+ const declared = isPlainObject$1(template.Parameters) ? template.Parameters : {};
44963
45566
  const declaredNames = new Set(Object.keys(declared));
44964
45567
  const closure = nullPrototypeRecord();
44965
45568
  const parameters = /* @__PURE__ */ new Set();
@@ -44981,7 +45584,7 @@ function conditionFingerprint(template, name, inputOf) {
44981
45584
  let hasToken = false;
44982
45585
  for (const parameter of parameters) {
44983
45586
  const definition = declared[parameter];
44984
- const type = isPlainObject(definition) ? definition["Type"] : void 0;
45587
+ const type = isPlainObject$1(definition) ? definition["Type"] : void 0;
44985
45588
  if (typeof type !== "string") return void 0;
44986
45589
  const input = inputOf(parameter);
44987
45590
  if (input === void 0) return void 0;
@@ -45012,7 +45615,7 @@ function collectIfConditionNames(value, names, conditions) {
45012
45615
  for (const element of value) collectIfConditionNames(element, names, conditions);
45013
45616
  return;
45014
45617
  }
45015
- if (!isPlainObject(value)) return;
45618
+ if (!isPlainObject$1(value)) return;
45016
45619
  const ifArgs = value["Fn::If"];
45017
45620
  if (Array.isArray(ifArgs) && typeof ifArgs[0] === "string") {
45018
45621
  names.add(ifArgs[0]);
@@ -45026,9 +45629,9 @@ function collectIfConditionNames(value, names, conditions) {
45026
45629
  function conditionsReadByDiff(template, conditions) {
45027
45630
  const names = /* @__PURE__ */ new Set();
45028
45631
  for (const section of [template.Resources, template.Outputs]) {
45029
- if (!isPlainObject(section)) continue;
45632
+ if (!isPlainObject$1(section)) continue;
45030
45633
  for (const entry of Object.values(section)) {
45031
- if (!isPlainObject(entry)) continue;
45634
+ if (!isPlainObject$1(entry)) continue;
45032
45635
  const gate = entry["Condition"];
45033
45636
  if (typeof gate === "string") {
45034
45637
  names.add(gate);
@@ -45060,10 +45663,10 @@ function buildConditionVerdictRecord(template, conditions, inputOf) {
45060
45663
  function readRecordedConditionVerdicts(state) {
45061
45664
  const read = nullPrototypeRecord();
45062
45665
  const field = state?.conditionVerdicts;
45063
- if (!isPlainObject(field)) return read;
45666
+ if (!isPlainObject$1(field)) return read;
45064
45667
  for (const name of Object.keys(field)) {
45065
45668
  const entry = field[name];
45066
- if (isPlainObject(entry) && typeof entry["verdict"] === "boolean" && typeof entry["fingerprint"] === "string") read[name] = {
45669
+ if (isPlainObject$1(entry) && typeof entry["verdict"] === "boolean" && typeof entry["fingerprint"] === "string") read[name] = {
45067
45670
  verdict: entry["verdict"],
45068
45671
  fingerprint: entry["fingerprint"]
45069
45672
  };
@@ -45106,11 +45709,11 @@ function deployConditionInputs(parameterValues, inheritedSecrets, shadowedBy = /
45106
45709
  function parentSuppliedValues(template, supplied, tokens) {
45107
45710
  const names = /* @__PURE__ */ new Set();
45108
45711
  if (supplied === void 0) return names;
45109
- const declared = isPlainObject(template.Parameters) ? template.Parameters : {};
45712
+ const declared = isPlainObject$1(template.Parameters) ? template.Parameters : {};
45110
45713
  for (const [name, value] of Object.entries(supplied)) {
45111
45714
  if (tokens.has(name)) continue;
45112
45715
  const definition = declared[name];
45113
- const fallback = isPlainObject(definition) ? definition["Default"] : void 0;
45716
+ const fallback = isPlainObject$1(definition) ? definition["Default"] : void 0;
45114
45717
  if (fallback === void 0 || String(fallback) !== String(value)) names.add(name);
45115
45718
  }
45116
45719
  return names;
@@ -45334,12 +45937,73 @@ function promoteRecreateTargets(changes, recreateTargets, stackName) {
45334
45937
  };
45335
45938
  }
45336
45939
 
45940
+ //#endregion
45941
+ //#region src/deployment/read-provenance-sources.ts
45942
+ function isPlainObject(value) {
45943
+ return value !== null && typeof value === "object" && !Array.isArray(value);
45944
+ }
45945
+ function crossStackNodes(value, into = []) {
45946
+ if (Array.isArray(value)) {
45947
+ for (const item of value) crossStackNodes(item, into);
45948
+ return into;
45949
+ }
45950
+ if (!isPlainObject(value)) return into;
45951
+ const keys = Object.keys(value);
45952
+ if (keys.length === 1 && (keys[0] === "Fn::ImportValue" || keys[0] === "Fn::GetStackOutput")) into.push(value);
45953
+ for (const item of Object.values(value)) crossStackNodes(item, into);
45954
+ return into;
45955
+ }
45956
+ function crossStackOutputProvenanceSource(reads, scope, stateBackend) {
45957
+ return async (value) => {
45958
+ const out = [];
45959
+ for (const node of crossStackNodes(value)) {
45960
+ const key = crossStackSourceKey(node);
45961
+ if (key === void 0) continue;
45962
+ const read = reads.get(key);
45963
+ if (read === void 0 || !read.carriesToken) continue;
45964
+ const state = await readProducerStateOnce(scope, stateBackend, read.stackName, read.region, () => void 0, read.state);
45965
+ const bag = outputReferenceProvenanceOf(state, read.outputKey);
45966
+ if (bag !== void 0) out.push(bag);
45967
+ }
45968
+ return out;
45969
+ };
45970
+ }
45971
+ function inheritedProvenanceForChildDiff(args) {
45972
+ const { row, rowRecord, parentRecords, parentTemplate } = args;
45973
+ if (!args.rowProvisioned || rowRecord === void 0) return void 0;
45974
+ const recordedParameters = isPlainObject(rowRecord.properties) ? rowRecord.properties["Parameters"] : void 0;
45975
+ const tokens = referenceTokensIn(recordedParameters);
45976
+ if (tokens.size === 0) return void 0;
45977
+ const own = referenceProvenanceOf(rowRecord);
45978
+ const upstreams = [...new TemplateParser().extractReferences(isPlainObject(row.Properties) ? row.Properties["Parameters"] : void 0)].filter((id) => Object.hasOwn(parentTemplate.Resources, id) && Object.hasOwn(parentRecords, id));
45979
+ const out = /* @__PURE__ */ new Map();
45980
+ for (const token of tokens) {
45981
+ const versions = /* @__PURE__ */ new Set();
45982
+ let region;
45983
+ for (const id of upstreams) {
45984
+ const entry = recordedProvenanceOf(parentRecords[id], token);
45985
+ for (const version of entry?.versions ?? []) versions.add(version);
45986
+ region ??= entry?.region;
45987
+ }
45988
+ if (versions.size > 0) {
45989
+ out.set(token, {
45990
+ ...region !== void 0 && { region },
45991
+ versions: [...versions].sort()
45992
+ });
45993
+ continue;
45994
+ }
45995
+ const recorded = own !== void 0 && Object.hasOwn(own, token) ? own[token] : void 0;
45996
+ if (recorded !== void 0) out.set(token, recorded);
45997
+ }
45998
+ return out.size === 0 ? void 0 : out;
45999
+ }
46000
+
45337
46001
  //#endregion
45338
46002
  //#region src/deployment/deploy-engine/deploy-flow.ts
45339
46003
  const TAIL_WARM_CONNECTIONS = 3;
45340
46004
  async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45341
46005
  const startTime = Date.now();
45342
- this.logger.debug(`Starting deployment for stack: ${stackName}`);
46006
+ this.logger.debug(safeMsg`Starting deployment for stack: ${displayStackName(stackName)}`);
45343
46007
  const renderer = getLiveRenderer();
45344
46008
  this.interrupted = false;
45345
46009
  this.interruptCause = null;
@@ -45385,7 +46049,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45385
46049
  refuseMalformedOrphanRecords(currentState, stackName, this.stackRegion, this.options.refusalRecovery);
45386
46050
  this.provenanceBaseline = provenanceBaselineOf(currentState, isKnownTokenFreeState(currentStateData?.state));
45387
46051
  const migrationPending = currentStateData?.migrationPending ?? false;
45388
- this.logger.debug(`Loaded current state: ${Object.keys(currentState.resources).length} resources`);
46052
+ this.logger.debug(safeMsg`Loaded current state: ${Object.keys(currentState.resources).length} resources`);
45389
46053
  if (this.options.onCurrentStateLoaded) {
45390
46054
  const gate = this.options.onCurrentStateLoaded(stackName, currentStateData?.state);
45391
46055
  if (currentStateData === null || currentStateData === void 0) {
@@ -45411,10 +46075,10 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45411
46075
  };
45412
46076
  if (journal && journal.segments.length > 0) {
45413
46077
  const failedOnly = journal.segments.every((s) => s.operations.length === 0) && journal.segments.some((s) => (s.failedOperations?.length ?? 0) > 0);
45414
- this.logger.info(failedOnly ? `A previous deploy of ${displayStackName(stackName)} failed and was automatically rolled back. The failed resource may be partially applied — revert it, or continue deploying to fix forward (${this.options.parentStackInfo ? "a successful deploy of the top-level stack clears this note" : "a successful deploy clears this note"}).\nRevert it with: ${pasteableCommand("cdkd rollback", [{
46078
+ this.logger.info(failedOnly ? safeMsg`A previous deploy of ${displayStackName(stackName)} failed and was automatically rolled back. ` + `The failed resource may be partially applied — revert it, or continue ` + safeMsg`deploying to fix forward (${this.options.parentStackInfo ? "a successful deploy of the top-level stack clears this note" : "a successful deploy clears this note"}).` + safeMsg`\nRevert it with: ${pasteableCommand("cdkd rollback", [{
45415
46079
  value: stackName,
45416
46080
  hole: "stack"
45417
- }, { literal: "--revert-failed" }]).command}` : `A previous deploy of ${displayStackName(stackName)} failed or was interrupted. Revert it, or continue deploying to fix forward.\nRevert it with: ${pasteableCommand("cdkd rollback", [{
46081
+ }, { literal: "--revert-failed" }]).command}` : safeMsg`A previous deploy of ${displayStackName(stackName)} failed or was interrupted. Revert it, ` + `or continue deploying to fix forward.` + safeMsg`\nRevert it with: ${pasteableCommand("cdkd rollback", [{
45418
46082
  value: stackName,
45419
46083
  hole: "stack"
45420
46084
  }]).command}`);
@@ -45422,13 +46086,13 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45422
46086
  } catch {}
45423
46087
  this.stampReasonlessParameterRefusals(currentState.resources, template);
45424
46088
  this.kickOffAutoRefreshObservedProperties(currentState.resources, currentState);
45425
- this.logger.debug(`Template has ${Object.keys(template.Resources || {}).length} resources`);
46089
+ this.logger.debug(safeMsg`Template has ${Object.keys(template.Resources || {}).length} resources`);
45426
46090
  const outputsDigestSource = structuredClone({
45427
46091
  ...template,
45428
46092
  Resources: {}
45429
46093
  });
45430
46094
  const parameterValues = await this.resolver.resolveParameters(template, this.options.parameters, { ...this.options.inheritedSecrets && hasMaskableValues(this.options.inheritedSecrets) && { inheritedSecrets: this.options.inheritedSecrets } });
45431
- this.logger.debug(`Resolved ${Object.keys(parameterValues).length} parameters: ${Object.keys(parameterValues).join(", ")}`);
46095
+ this.logger.debug(safeMsg`Resolved ${Object.keys(parameterValues).length} parameters: ${Object.keys(parameterValues).join(", ")}`);
45432
46096
  poisonRenderedSpellingsCollidingIn(template, parameterValues, this.options.inheritedSecrets);
45433
46097
  this.inheritedNoEchoParameters = /* @__PURE__ */ new Set([...this.freshNoEchoParameters(parameterValues) ?? [], ...this.options.passedNoEchoParameters ?? []]);
45434
46098
  const backfillNoEchoValues = noEchoParameterValueSeed(template.Parameters, parameterValues, this.options.inheritedSecrets, this.options.parameters);
@@ -45448,7 +46112,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45448
46112
  parameters: parameterValues
45449
46113
  }, stackName);
45450
46114
  const conditions = await this.resolver.evaluateConditions(context);
45451
- this.logger.debug(`Evaluated ${Object.keys(conditions).length} conditions: ${Object.keys(conditions).join(", ")}`);
46115
+ this.logger.debug(safeMsg`Evaluated ${Object.keys(conditions).length} conditions: ${Object.keys(conditions).join(", ")}`);
45452
46116
  refuseNoValueOutputs(template.Outputs, conditions);
45453
46117
  let conditionVerdicts;
45454
46118
  if (conditionsReadByDiff(template, conditions).size > 0) {
@@ -45486,7 +46150,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45486
46150
  this.logger.debug(`All resource properties validated`);
45487
46151
  const dag = this.dagBuilder.buildGraph(effectiveTemplate);
45488
46152
  const executionLevels = this.dagBuilder.getExecutionLevels(dag);
45489
- this.logger.debug(`Dependency graph: ${executionLevels.length} execution levels`);
46153
+ this.logger.debug(safeMsg`Dependency graph: ${executionLevels.length} execution levels`);
45490
46154
  const diffResolverContext = this.buildResolverContext({
45491
46155
  template: effectiveTemplate,
45492
46156
  resources: currentState.resources,
@@ -45495,13 +46159,18 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45495
46159
  }, stackName);
45496
46160
  diffResolverContext.bestEffort = true;
45497
46161
  diffResolverContext.skipDynamicReferences = true;
46162
+ const crossStackReads = /* @__PURE__ */ new Map();
46163
+ diffResolverContext.crossStackReads = crossStackReads;
45498
46164
  const diffResolveFn = (value) => this.resolver.resolve(value, diffResolverContext);
45499
46165
  const maskedInputSourcesForDiff = this.maskedInputSources(effectiveTemplate, currentState.resources, conditions, stackName);
45500
46166
  const maskedInputs = maskedInputSourcesForDiff && {
45501
46167
  sources: maskedInputSourcesForDiff,
45502
46168
  rebaselined: /* @__PURE__ */ new Map()
45503
46169
  };
45504
- const changes = await this.diffCalculator.calculateDiff(currentState, effectiveTemplate, diffResolveFn, makeCanonicalizePropertiesFn(this.providerRegistry), this.providerRegistry.getAllowedUnsupportedProperties?.(), freshNoEchoParametersWithDeclared(this.inheritedNoEchoParameters, effectiveTemplate), this.diffLogMasker(diffResolverContext.recordedSecretValues, effectiveTemplate, parameterValues, currentState.resources), recreateTargetIdsFor(this.options.recreateTargets, stackName), maskedInputs, this.options.refusalRecovery, this.noEchoDiffComparison(currentState.resources, effectiveTemplate, conditions, parameterValues, stackName));
46170
+ const changes = await this.diffCalculator.calculateDiff(currentState, effectiveTemplate, diffResolveFn, makeCanonicalizePropertiesFn(this.providerRegistry), this.providerRegistry.getAllowedUnsupportedProperties?.(), freshNoEchoParametersWithDeclared(this.inheritedNoEchoParameters, effectiveTemplate), this.diffLogMasker(diffResolverContext.recordedSecretValues, effectiveTemplate, parameterValues, currentState.resources), recreateTargetIdsFor(this.options.recreateTargets, stackName), maskedInputs, this.options.refusalRecovery, this.noEchoDiffComparison(currentState.resources, effectiveTemplate, conditions, parameterValues, stackName), {
46171
+ ...this.options.inheritedReferenceProvenance && { inherited: this.options.inheritedReferenceProvenance },
46172
+ crossStackOutputs: crossStackOutputProvenanceSource(crossStackReads, this.recordedImports, this.stateBackend)
46173
+ });
45505
46174
  createOnlyPrefetch.cancel();
45506
46175
  for (const [logicalId, fingerprints] of maskedInputs?.rebaselined ?? []) {
45507
46176
  const record = currentState.resources[logicalId];
@@ -45581,8 +46250,8 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45581
46250
  const outputsChanged = !outputMapsEqual(persistedOutputs, outputsToPersist);
45582
46251
  const persistExportSet = new Set(exportNamesToPersist ?? []);
45583
46252
  const exportSetChanged = exportNamesToPersist !== void 0 && (currentEffectiveExports.size !== persistExportSet.size || [...persistExportSet].some((k) => !currentEffectiveExports.has(k)));
45584
- if (merge?.kind === "kept" && !outputMapsEqual(persistedOutputs, resolvedOutputs)) this.logger.warn(`Outputs changed but one or more could not be resolved; keeping the previously persisted outputs. ${keptWholeReasonText(merge.reason)} A downstream Fn::ImportValue may fail until the next deploy.`);
45585
- else if (merge?.kind === "merged" && merge.carriedKeys.length > 0) this.logger.debug(`Kept the previously persisted value of ${merge.carriedKeys.length} output key(s), carried export aliases included, that could not be resolved (no-change path)`);
46253
+ if (merge?.kind === "kept" && !outputMapsEqual(persistedOutputs, resolvedOutputs)) this.logger.warn(safeMsg`Outputs changed but one or more could not be resolved; keeping the previously persisted outputs. ${keptWholeReasonText(merge.reason)} ` + "A downstream Fn::ImportValue may fail until the next deploy.");
46254
+ else if (merge?.kind === "merged" && merge.carriedKeys.length > 0) this.logger.debug(safeMsg`Kept the previously persisted value of ${merge.carriedKeys.length} output key(s), ` + "carried export aliases included, that could not be resolved (no-change path)");
45586
46255
  const skippedOutputsChanged = !skippedOutputsEqual(currentState.skippedOutputs, this.skippedOutputs);
45587
46256
  const healedAttributesPending = this.hasUnpersistedHeals(currentState.resources);
45588
46257
  const conditionVerdictsChanged = !conditionVerdictRecordsEqual(readRecordedConditionVerdicts(currentState), conditionVerdicts);
@@ -45621,7 +46290,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45621
46290
  else if (healedAttributesPending) this.logger.debug("Persisted attributes re-read from AWS for a stale record (no-change path)");
45622
46291
  else this.logger.debug("Persisted skipped-outputs record (no outputs-value diff, no-change path)");
45623
46292
  } catch (saveError) {
45624
- 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.`);
46293
+ this.logger.warn(safeMsg`Failed to persist no-change state update: ${asIsMessage(saveError instanceof Error ? saveError.message : String(saveError))} — drift baseline / outputs will be re-resolved on next deploy.`);
45625
46294
  }
45626
46295
  }
45627
46296
  return {
@@ -45640,7 +46309,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45640
46309
  const createChanges = this.diffCalculator.filterByType(changes, "CREATE");
45641
46310
  const updateChanges = this.diffCalculator.filterByType(changes, "UPDATE");
45642
46311
  const deleteChanges = this.diffCalculator.filterByType(changes, "DELETE");
45643
- this.logger.info(`Changes: ${green(createChanges.length)} to create, ${yellow(updateChanges.length)} to update, ${red(deleteChanges.length)} to delete`);
46312
+ this.logger.info(safeMsg`Changes: ${green(createChanges.length)} to create, ${yellow(updateChanges.length)} to update, ${red(deleteChanges.length)} to delete`);
45644
46313
  if (this.options.dryRun) {
45645
46314
  this.logger.info("Dry run mode - skipping actual deployment");
45646
46315
  return {
@@ -45719,7 +46388,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45719
46388
  ...newState,
45720
46389
  conditionVerdicts
45721
46390
  } : newState)), flushKeptForReadoption(this)]);
45722
- this.logger.debug(`State saved (ETag: ${newEtag})`);
46391
+ this.logger.debug(safeMsg`State saved (ETag: ${newEtag})`);
45723
46392
  const ledgerAndKeptCleanup = (async () => {
45724
46393
  await forgetRecordedCreateTokens(Object.keys(newState.resources));
45725
46394
  const readopted = await this.generatedNameGuard?.readoptedFromRetained() ?? [];
@@ -45780,7 +46449,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
45780
46449
  await this.lockManager.releaseLock(stackName, this.stackRegion);
45781
46450
  this.logger.debug("Lock released");
45782
46451
  } catch (lockError) {
45783
- this.logger.warn(`Failed to release lock: ${lockError instanceof Error ? lockError.message : String(lockError)}`);
46452
+ this.logger.warn(safeMsg`Failed to release lock: ${asIsMessage(lockError instanceof Error ? lockError.message : String(lockError))}`);
45784
46453
  }
45785
46454
  }
45786
46455
  }
@@ -45935,7 +46604,7 @@ function addImplicitDeleteDependencies(deleteIds, state, dependedBy) {
45935
46604
  if (!dependedBy.has(id)) dependedBy.set(id, /* @__PURE__ */ new Set());
45936
46605
  if (!dependedBy.get(id).has(depId)) {
45937
46606
  dependedBy.get(id).add(depId);
45938
- this.logger.debug(`Implicit delete dependency: ${depId} (${depType}) must be deleted before ${id} (${resource.resourceType})`);
46607
+ this.logger.debug(safeMsg`Implicit delete dependency: ${depId} (${depType}) must be deleted before ${id} (${resource.resourceType})`);
45939
46608
  }
45940
46609
  }
45941
46610
  }
@@ -45949,7 +46618,7 @@ function addImplicitDeleteDependencies(deleteIds, state, dependedBy) {
45949
46618
  if (!dependedBy.has(after)) dependedBy.set(after, /* @__PURE__ */ new Set());
45950
46619
  if (!dependedBy.get(after).has(before)) {
45951
46620
  dependedBy.get(after).add(before);
45952
- this.logger.debug(`Implicit delete dependency: ${before} (${scoped[before]?.resourceType}) must be deleted before ${after} (${scoped[after]?.resourceType})`);
46621
+ this.logger.debug(safeMsg`Implicit delete dependency: ${before} (${scoped[before]?.resourceType}) must be deleted before ${after} (${scoped[after]?.resourceType})`);
45953
46622
  }
45954
46623
  }
45955
46624
  }
@@ -46014,6 +46683,7 @@ var DeployEngine = class {
46014
46683
  noEchoExactEchoes = /* @__PURE__ */ new Map();
46015
46684
  noEchoAttributeReads = /* @__PURE__ */ new Map();
46016
46685
  replacedDeleteSkips = /* @__PURE__ */ new Map();
46686
+ deferredReplacedDeletes = void 0;
46017
46687
  secretNameNeedles = /* @__PURE__ */ new Map();
46018
46688
  perResourceTemplateProps = /* @__PURE__ */ new Map();
46019
46689
  perResourceResolvedType = /* @__PURE__ */ new Map();
@@ -46091,6 +46761,7 @@ var DeployEngine = class {
46091
46761
  this.noEchoExactEchoes = /* @__PURE__ */ new Map();
46092
46762
  this.noEchoAttributeReads = /* @__PURE__ */ new Map();
46093
46763
  this.replacedDeleteSkips = /* @__PURE__ */ new Map();
46764
+ this.deferredReplacedDeletes = void 0;
46094
46765
  this.secretNameNeedles = /* @__PURE__ */ new Map();
46095
46766
  this.perResourceTemplateProps = /* @__PURE__ */ new Map();
46096
46767
  this.constructPathTemplate = void 0;
@@ -46327,6 +46998,8 @@ DeployEngine.prototype.typeChangeNameQuestion = typeChangeNameQuestion;
46327
46998
  DeployEngine.prototype.checkedReplacementNameChange = checkedReplacementNameChange;
46328
46999
  DeployEngine.prototype.createFirstThenDeleteOld = createFirstThenDeleteOld;
46329
47000
  DeployEngine.prototype.deleteReplacedAfterCreate = deleteReplacedAfterCreate;
47001
+ DeployEngine.prototype.retryDeferredReplacedDeletes = retryDeferredReplacedDeletes;
47002
+ DeployEngine.prototype.warnUnretriedReplacedDeletes = warnUnretriedReplacedDeletes;
46330
47003
  DeployEngine.prototype.diffLogMasker = diffLogMasker;
46331
47004
  DeployEngine.prototype.freshNoEchoParameters = freshNoEchoParameters;
46332
47005
  DeployEngine.prototype.redactParametersForDiff = redactParametersForDiff;
@@ -46380,5 +47053,5 @@ DeployEngine.prototype.replacementNameOrigin = replacementNameOrigin;
46380
47053
  DeployEngine.prototype.orphanedNameCollisionAdvice = orphanedNameCollisionAdvice;
46381
47054
 
46382
47055
  //#endregion
46383
- export { isTruthyCfnBoolean as $, NO_CC_HANDLERS_REASON as $a, resolveApp as $c, malformedLocalResourceEntriesWarning as $i, ledgerForStack as $n, shareLogOnlyValues as $o, sendableAssumeRoleCommand as $r, hasUnverifiableParameterRefusal as $s, seedsDeleteFirstGuard as $t, noEchoComparisonForTemplate as A, refuseMalformedResourceEntriesForOrphan as Aa, dockerSpawnEnvWithSensitive as Ac, refStateLookupFromResource as Ai, displayAssemblyPath as Al, journaledOrphanPrintingBag as An, TemplateParser as Ao, deleteIndeterminateGuards as Ar, wholeStringLeavesOf as As, dropFailedHint as At, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as B, repairMalformedOrphansForReadOnly as Ba, runDockerForeground as Bc, UNREADABLE_RESOURCES_MAP_ROW as Bi, PRE_DELETE_SNAPSHOT_TYPES as Bn, passedNoEchoParametersOf as Bo, reDisableInstanceApiTermination as Br, rebuildClientForBucketRegion as Bs, getStackRecords as Bt, recordRetainedForReadoption as C, refuseMalformedOutputsForDestroy as Ca, validateContainerRepoName as Cc, carriesDynamicReference as Ci, defineOwnKey as Cl, collectDeclaredOutputNames as Cn, templateResourceTypes as Co, applyCustomResourceResponseExpiration as Cr, carriesSecretMask as Cs, revertNestedChildFromJournal as Ct, withResourceDeadline as D, refuseMalformedResourceEntriesForDestroy as Da, describeDockerCapturedOutput as Dc, AWS_NO_VALUE as Di, ownValue as Dl, DEFAULT_RESOURCE_TIMEOUT_MS as Dn, lambdaFunctionNameForMask as Do, unchangedBehindSecretReference as Dr, recordNoEchoAttributeValues as Ds, getCurrentNestedStackContext as Dt, serviceTokenBlockingReason as E, refuseMalformedResourceEntriesForDeploy as Ea, resolveDockerContextDirectory as Ec, keepsSecretReferenceToken as Ei, nullPrototypeRecord as El, bindingSkippedOutputs as En, canonicalLambdaFunctionName as Eo, slowCcOperationTimeoutMs as Er, recordMaskOnlyValuesIn as Es, collectNestedChildUnaddressed as Et, PROTECTION_PROPERTY_BY_TYPE as F, refuseMalformedResourcesForDeploy as Fa, isMalformedEnvKey as Fc, declaresNoEcho as Fi, clearBucketRegionCache as Fl, secretNamedRecordNeedles as Fn, maskWholeValue as Fo, markWaitAbandoned as Fr, WHOLE_DYNAMIC_REFERENCE_PATTERN as Fs, sameJournaledOrphans as Ft, resolveDynamoDbDeleteBudgetMs as G, unpreviewableOrphanRecords as Ga, stripForDisplay as Gc, hasReadableOutputs as Gi, isFinalSnapshotError as Gn, carryLogOnlyValues as Go, poisonRenderedSpellingsCollidingIn as Gr, isAccessDenied$1 as Gs, isJournaledOrphan as Gt, compensateRemovedDeletionProtection as H, repairMalformedResourceEntriesForReadOnly as Ha, warnFinchArgvExposure as Hc, deployRefusesOrphanRowsReason as Hi, ccRoutedFinalSnapshotError as Hn, readsNoEchoSource as Ho, DiffCalculator as Hr, CrossPrefixScanCache as Hs, removeProtectionTypeList as Ht, isProtectionValueActive as I, refuseMalformedResourcesForDestroy as Ia, partitionSensitiveEnv as Ic, JSON_LISTING_HOLE_VALUE as Ii, resolveBucketRegion as Il, stateSecretNameNeedles as In, maskedLeafCoordinatesOf as Io, disableInstanceApiTermination as Ir, isSingleDynamicReferenceToken as Is, replayFailedOperations as It, deleteTableWithIndexBusyRetry as J, withheldAccountClause as Ja, Synthesizer as Jc, isReadableResourceEntry as Ji, maskingRetryLogger as Jn, literalSplitDelimitersOf as Jo, applyRoleArnIfSet as Jr, acceptedCreateOnlyDropsOf as Js, planRollback as Jt, DELETE_INDEX_WAIT_PROCEED_NOTE as K, unreadableOrphanRecords as Ka, AssetManifestLoader as Kc, hasReadableResources as Ki, refusesFinalSnapshot as Kn, createUnionSecretMasker as Ko, producerLookupOver as Kr, isNotImplemented as Ks, isReplacementOrphan as Kt, perType as L, refuseMalformedResourcesForExport as La, redactDockerArgvValues as Lc, STATE_REGION_DIVERGED as Li, storedSecretNameNeedles as Ln, noEchoCoordinatesOf as Lo, ec2InstanceProtectionSite as Lr, LockManager as Ls, replayRollback as Lt, noEchoParameterNamesOf as M, refuseMalformedResourcePropertiesForDrift as Ma, formatDockerLoginError as Mc, withSharedDrainBudget as Mi, resolveAssemblyPath as Ml, orphanRecordsPrintingBag as Mn, isMarkedCoordinate as Mo, deleteSkipReason as Mr, STATE_SOURCED_CROSS_GENERATION_RULES as Ms, journaledOrphanLines as Mt, recordedProtectionEvidence as N, refuseMalformedResourcePropertiesForExport as Na, getDockerCmd as Nc, parameterInputsFor as Ni, injectAwsRegion as Nl, secretNamePrintingBag as Nn, maskAtCoordinates as No, withIndeterminateGuard as Nr, STATE_SOURCED_READBACK_RULES as Ns, loadJournaledOrphans as Nt, diffSecurity as O, refuseMalformedResourceEntriesForImport as Oa, describeDockerExecFailure as Oc, cfnRefValueFromPhysicalId as Oi, absoluteAssemblyPathEscape as Ol, DEFAULT_RESOURCE_WARN_AFTER_MS as On, sameLambdaFunctionAddress as Oo, RollbackInlinePolicyWriters as Or, recordNoEchoParameterFreshValue as Os, withNestedStackContext as Ot, recordedProtectionNote as P, refuseMalformedResourcePropertiesForOrphan as Pa, isDockerClientEnvKey as Pc, passedParameterClassesOf as Pi, injectedAwsRegionValue as Pl, secretNamePrintingBags as Pn, maskReadbackAtCoordinates as Po, isWaitAbandonedError as Pr, TEMPLATE_SOURCED_RULES as Ps, makeForeignHolderScan as Pt, hasCdkAutoDeleteTag as Q, withoutSilentDropProperties as Qa, loadCdkJson as Qc, malformedLocalOutputsWarning as Qi, earliestDefined as Qn, recordLogOnlyValue as Qo, isIamRoleArn as Qr, hasReasonlessBaselineRefusal as Qs, resolveReplacementOldType as Qt, readProtection as R, refuseMalformedState as Ra, redactedCause as Rc, STATE_RESOURCES_MALFORMED as Ri, extractDeploymentEventError as Rn, noEchoLeavesOf as Ro, isTerminationProtectionPropagationError as Rr, isLockInfoExpired as Rs, awaitInFlightSibling as Rt, keptForReadoption as S, refuseMalformedOutputs as Sa, validateAssetBucketName as Sc, isImpossibleEmptyStoredAttribute as Si, processStackMessages as Sl, noEchoParameterValueSeed as Sn, prefetchCreateOnlyPropertyPaths as So, CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID as Sr, splitGetAttStringForm as Ss, recordDisplacedSkips as St, findServiceTokenRefusals as T, refuseMalformedResourceEntries as Ta, buildDockerImage as Tc, isNamelessDynamicReferenceError as Ti, hasPlainPrototype$1 as Tl, isExportAliasCollision as Tn, withRetry as To, CloudControlProvider as Tr, recordMaskOnlyValue as Ts, withNestedRevertRun as Tt, deleteBudgetKey as U, repairMalformedResourcePropertiesForReadOnly as Ua, escapeRegExp$3 as Uc, displayLogicalId as Ui, createPreDeleteFinalSnapshot as Un, valueAtCoordinate as Uo, INTRINSIC_KEYS as Ur, applyCrossPrefixScan as Us, recordAfterRollbackUpdate as Ut, beginDeleteWait as V, repairMalformedOutputsForReadOnly as Va, runDockerStreaming as Vc, accountArgs as Vi, buildFinalSnapshotIdentifier as Vn, readbackPathFor as Vo, reEnableInstanceApiTermination as Vr, CrossPrefixReadError as Vs, withStackRecords as Vt, resolveDynamoDbDeleteBudgetClock as W, repairMalformedResourcesForReadOnly as Wa, stripControlChars as Wc, hasReadableOrphans as Wi, effectiveDeletionPolicy as Wn, liveMatchesUnresolvedTokenFrame as Wo, IntrinsicFunctionResolver as Wr, crossPrefixDeniedWarning as Ws, demoteSupersededOrphans as Wt, ECR_AUTO_DELETE_IMAGES_TAG as X, findSilentDropProperties as Xa, getDefaultStateBucketName as Xc, malformedExportNamesWarning as Xi, findDestructiveChanges as Xn, printingCorpusOf as Xo, assertSendableRoleArn as Xr, exportNamesCarriedFrom as Xs, recordUnderIdIsNotOwn as Xt, waitForIndexesSettled as Y, findActionableSilentDrops as Ya, synthesisStatusMessage as Yc, malformedDriftResourcePropertiesWarning as Yi, constructPathOf as Yn, logOnlyValueCount as Yo, assertFlagRoleArn as Yr, describeRegionValueKind as Ys, recheckFailedPlan as Yt, S3_AUTO_DELETE_OBJECTS_TAG as Z, unwrittenCreateOnlyReplacement as Za, getLegacyStateBucketName as Zc, malformedExportSourceWarning as Zi, formatDestructiveChange as Zn, recordLogOnlyParameterValue as Zo, explicitRoleArnOrThrow as Zr, hasReadableExportSet as Zs, replacementNeverSwapped as Zt, makeCanonicalizePropertiesFn as _, refuseMalformedOrphanRecords as _a, ensureAssetStorage as _c, regionLessSecretName as _i, PARTITION_TABLE as _l, secretSafeKeyDisplay as _n, readConfigString as _o, TemplateNoEchoReresolver as _r, recordNestedStackParameterExpressions as _s, displacedOpClause as _t, findNestedTemplateTreeDefect as a, malformedOrphansWarning as aa, shouldRetainResource as ac, keepHeldTokenProvenance as ai, resolveUseCdkBootstrapAssets as al, isRedactedRecordedValue as an, isStatefulRecreateTargetSync as ao, planTagDiff as ar, recordReferenceProvenanceEntry as as, cyan as at, lookupEachName as b, refuseMalformedOrphansForDestroy as ba, parseBootstrapMarker as bc, parameterTypeMayLoseSecretIdentity as bi, AssemblyReader as bl, exportNameSecretExposure as bn, requireConfigObject as bo, getCurrentResourceSecrets as br, recordAttributeIdCopy as bs, getNestedRevertRun as bt, renderNestedTemplateTreeDefect as c, malformedRenderedContainersWarning as ca, stringifyValue as cc, recordedReferenceRegions as ci, ssmResolvedValueType as cl, updatePartialMessage as cn, coerceWarmThroughput as co, tagMapAsList as cr, scrubResourceRecord as cs, red as ct, conditionInputsFrom as d, malformedResourcesWarning as da, createAssetRedirectResolver as dc, s3BucketDualStackDomainName as di, MIGRATE_TMP_PREFIX as dl, DeploymentEventsStore as dn, toFiniteNumber as do, stringifyIfAssigned as dr, DYNAMIC_REFERENCE_TOKEN_SCAN as ds, namesAnyDeclaredParameter as dt, malformedLocalResourcesWarning as ea, importableOutputKeys as ec, AWS_CREDENTIAL_ENV_KEYS as ei, resolveAutoAssetStorage as el, orphanDeleteNeedsIdentity as en, hasNoCloudControlHandlers as eo, reserveStackCreateToken as er, createSecretMasker as es, getPriorAttempts as et, parentSuppliedValues as f, malformedScrubResourceEntriesRefusalMessage as fa, loadPublishableAssetManifest as fc, s3BucketRegionalDomainName as fi, findLargeInlineResources as fl, WITHHELD_NAME_DISPLAY as fn, coerceCfnBoolean as fo, CC_BROKEN_REASON as fr, dynamicReferenceTokens as fs, reachableDivergentParameters as ft, mergeNoChangeOutputs as g, refuseMalformedNestedChildOutputs as ga, assertAssetBucketRegion as gc, producerRegionsFromState as gi, expectedOwnerParam as gl, secretBearingStateKeyWarning as gn, configStringRefusal as go, wouldReturnToSdkProvider as gr, inheritNestedStackParameterAssociations as gs, NESTED_PENDING_PARENT_REASON as gt, keptWholeReasonText as h, refuseDivergentRecordRegionForDestroy as ha, BOOTSTRAP_MARKER_PREFIX as hc, classifyReplaySecretRegion as hi, decodeListingKey as hl, secretBearing as hn, configIntegerRefusal as ho, isCustomResource as hr, identityKeyFor as hs, planOrphanAdoption as ht, childTemplateLoader as i, malformedOrphansRefusalMessage as ia, orphansCarriedFrom as ic, isSettledInstanceState as ii, resolveStateBucketWithDefaultAndSource as il, REDACTED_DELETE_ADDRESS_SKIP_REASON as in, isStatefulRecreateTargetForReplace as io, DBPROXY_TAG_OPTIONS as ir, markSameGenerationBag as is, bold as it, noEchoExactEchoLeavesOf as j, refuseMalformedResourcePropertiesForDestroy as ja, finchSecretArgvRefusal as jc, parseWebACLArn as ji, renderAssemblyPathEscape as jl, maskEventTextWithBoundBags as jn, canonicalCoordinates as jo, deleteLeftInPlace as jr, STATE_SOURCED_BASELINE_RULES as js, isHandledOrphan as jt, noEchoAttributeNamesOf as k, refuseMalformedResourceEntriesForImportSave as ka, describeDockerFailure as kc, isStalePlaceholderArnAttribute as ki, describeFileReadFailure as kl, completedReplayEntries as kn, DagBuilder as ko, UNSPECIFIED_SKIP_REASON as kr, recordProvenPublicExpression as ks, deleteJournaledOrphans as kt, templateIdentity as l, malformedResourceEntriesWarning as la, WorkGraph as lc, s3BucketArn as li, CFN_TEMPLATE_BODY_LIMIT as ll, updatePartialReason as ln, isWarmThroughputDecrease as lo, tagPlanWarning as lr, withPhysicalNameCopies as ls, yellow as lt, isSecretBearingReferenceString as m, previewableOrphanRecords as ma, AssetModeResolver as mc, classifyRecordedSecretRegion as mi, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as ml, exportAliasCollisionScrubWarning as mn, configBooleanRefusal as mo, ccBrokenReason as mr, pathCrossesDottedKey as ms, makeSiblingClaimReader as mt, IMPLICIT_DELETE_DEPENDENCIES as n, malformedOrphanRecordsWarning as na, isReadableBag as nc, callerEnvCredentials as ni, resolveSkipPrefix as nl, getCurrentProducerRegions as nn, shownType as no, acquireIdempotencyToken as nr, maskSecretsInError as ns, formatResourceLine as nt, isAbsoluteAssetPath as o, malformedOutputsRefusalMessage as oa, AssetPublisher as oc, outputReferenceProvenanceOf as oi, stateBucketExistenceConfirmed as ol, redactedDeleteAddressFields as on, renderStatefulReason as oo, readTagList as or, snapshotPassProvenance as os, gray as ot, readRecordedConditionVerdicts as p, malformedStateRefusalMessage as pa, rewriteTemplateAssetReferences as pc, s3BucketWebsiteUrl as pi, uploadCfnTemplate as pl, displayTextOrWithheld as pn, coerceCfnInteger as po, ProviderRegistry as pr, isUncertifiedBaselineMaskPosition as ps, resourcesNamingDeclaredParameter as pt, INDEX_SETTLE_POLL_INTERVAL_MS as q, unreadableResourceEntries as qa, getDockerImageBySourceHash as qc, isReadableOrphanRecord as qi, unsupportedFinalSnapshotError as qn, hasMaskableValues as qo, refuseUnreadableCdkCrossAccountRefs as qr, splitImportedOps as qs, planFailedOps as qt, computeImplicitDeleteEdges as r, malformedOrphanRowsKeptWarning as ra, orphansAfterRollback as rc, envCredentialsAreAssumedRole as ri, resolveStateBucketWithDefault as rl, inheritProducerRegions as rn, MULTI_REGION_RECREATE_BLOCKED_TYPES as ro, DBPROXY_TAGS_WHAT as rr, maskSecretsInText as rs, createReadOnlyAttributeHealerFactory as rt, listNestedTemplateRows as s, malformedOutputsWarning as sa, isSensitiveAttributeName as sc, recordedOutputReferenceRegions as si, warnDeprecatedNoPrefixCliFlag as sl, redactedDeleteAddressSkip as sn, WARM_THROUGHPUT_MEMBERS as so, refuseMalformedDesiredTags as sr, redactSecretsForState as ss, green as st, DeployEngine as t, malformedOrphanRecordsRefusalMessage as ta, importableOutputs as tc, applyCallerIdentityCredentials as ti, resolveCaptureObservedState as tl, findNestedStackTypeChanges as tn, findReplacedReadersOfRecreateTargets as to, withCreateTokenLedger as tr, errorCauseChain as ts, markRefusedBeforeApplying as tt, conditionFingerprint as u, malformedResourcePropertiesWarning as ua, buildAssetRedirectMap as uc, s3BucketDomainName as ui, CFN_TEMPLATE_URL_LIMIT as ul, DeploymentEventsReader as un, toCfnInteger as uo, definedAttributes as ur, withoutPhysicalNameCopies as us, computeParameterTaint as ut, chunks as v, refuseMalformedOrphanRecordsForDestroy as va, getBootstrapMarkerKey as vc, coerceParameterTypedValue as vi, canonicalizeRegion as vl, carriedExportAliasExposure as vn, replayWarn as vo, readsNoEchoDeleteValues as vr, recoverMaskedOutput as vs, displacedPhysicalIdShown as vt, deferredServiceTokenWarning as w, refuseMalformedResourceAttributesForOrphan as wa, buildDenyExternalAccessPolicy as wc, carriesFetchableDynamicReference as wi, hasOwnKey as wl, collectPublishedOutputNames as wn, describeTypeWithThrottleRetry as wo, customResourceResponseExpirationWarning as wr, provenPublicValue as ws, revertedNestedRowIds as wt, withApiLimit as x, refuseMalformedOrphansForOrphan as xa, readBootstrapMarkerBody as xc, getAccountInfo as xi, StageLoadError as xl, isWholeDynamicReferenceValue as xn, requireConfigString as xo, withPrintingSecrets as xr, recordPhysicalNameCopy as xs, nestedChildStackName as xt, isAccessDeniedError as y, refuseMalformedOrphans as ya, isCrossRegionRedirect as yc, isUnboundTemplateParameter as yi, derivePartitionAndUrlSuffix as yl, exportNameNoEchoParameters as yn, requireConfigArray as yo, isCustomResourceType as yr, physicalNameCopiesOf as ys, dropSettledNestedJournals as yt, DynamoDBGlobalTableProvider as z, repairMalformedOrphanRecordsForReadOnly as za, redactedDockerCause as zc, UNREADABLE_ORPHANS_CONTAINER_ROW as zi, ATOMIC_FINAL_SNAPSHOT_TYPES as zn, noEchoOutputsComparison as zo, observeThenDisableInstanceApiTermination as zr, S3StateBackend as zs, destroyStackRecordsView as zt };
46384
- //# sourceMappingURL=deploy-engine-DEBgHf6Z.js.map
47056
+ export { S3_AUTO_DELETE_OBJECTS_TAG as $, unwrittenCreateOnlyReplacement as $a, getLegacyStateBucketName as $c, malformedExportSourceWarning as $i, formatDestructiveChange as $n, recordLogOnlyParameterValue as $o, explicitRoleArnOrThrow as $r, hasReadableExportSet as $s, replacementNeverSwapped as $t, diffSecurity as A, refuseMalformedResourceEntriesForImport as Aa, describeDockerExecFailure as Ac, cfnRefValueFromPhysicalId as Ai, absoluteAssemblyPathEscape as Al, DEFAULT_RESOURCE_WARN_AFTER_MS as An, sameLambdaFunctionAddress as Ao, RollbackInlinePolicyWriters as Ar, recordNoEchoParameterFreshValue as As, withNestedStackContext as At, readProtection as B, refuseMalformedState as Ba, redactedCause as Bc, STATE_RESOURCES_MALFORMED as Bi, extractDeploymentEventError as Bn, noEchoLeavesOf as Bo, isTerminationProtectionPropagationError as Br, isLockInfoExpired as Bs, awaitInFlightSibling as Bt, withApiLimit as C, refuseMalformedOrphansForOrphan as Ca, readBootstrapMarkerBody as Cc, getAccountInfo as Ci, StageLoadError as Cl, isWholeDynamicReferenceValue as Cn, requireConfigString as Co, withPrintingSecrets as Cr, recordPhysicalNameCopy as Cs, nestedChildStackName as Ct, findServiceTokenRefusals as D, refuseMalformedResourceEntries as Da, buildDockerImage as Dc, isNamelessDynamicReferenceError as Di, hasPlainPrototype$1 as Dl, isExportAliasCollision as Dn, withRetry as Do, CloudControlProvider as Dr, recordMaskOnlyValue as Ds, withNestedRevertRun as Dt, deferredServiceTokenWarning as E, refuseMalformedResourceAttributesForOrphan as Ea, buildDenyExternalAccessPolicy as Ec, carriesFetchableDynamicReference as Ei, hasOwnKey as El, collectPublishedOutputNames as En, describeTypeWithThrottleRetry as Eo, customResourceResponseExpirationWarning as Er, provenPublicValue as Es, revertedNestedRowIds as Et, recordedProtectionEvidence as F, refuseMalformedResourcePropertiesForExport as Fa, getDockerCmd as Fc, parameterInputsFor as Fi, injectAwsRegion as Fl, secretNamePrintingBag as Fn, maskAtCoordinates as Fo, withIndeterminateGuard as Fr, STATE_SOURCED_READBACK_RULES as Fs, loadJournaledOrphans as Ft, deleteBudgetKey as G, repairMalformedResourcePropertiesForReadOnly as Ga, escapeRegExp$3 as Gc, displayLogicalId as Gi, createPreDeleteFinalSnapshot as Gn, valueAtCoordinate as Go, INTRINSIC_KEYS as Gr, applyCrossPrefixScan as Gs, recordAfterRollbackUpdate as Gt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as H, repairMalformedOrphansForReadOnly as Ha, runDockerForeground as Hc, UNREADABLE_RESOURCES_MAP_ROW as Hi, PRE_DELETE_SNAPSHOT_TYPES as Hn, passedNoEchoParametersOf as Ho, reDisableInstanceApiTermination as Hr, rebuildClientForBucketRegion as Hs, getStackRecords as Ht, recordedProtectionNote as I, refuseMalformedResourcePropertiesForOrphan as Ia, isDockerClientEnvKey as Ic, passedParameterClassesOf as Ii, injectedAwsRegionValue as Il, secretNamePrintingBags as In, maskReadbackAtCoordinates as Io, isWaitAbandonedError as Ir, TEMPLATE_SOURCED_RULES as Is, makeForeignHolderScan as It, DELETE_INDEX_WAIT_PROCEED_NOTE as J, unreadableOrphanRecords as Ja, AssetManifestLoader as Jc, hasReadableResources as Ji, refusesFinalSnapshot as Jn, createUnionSecretMasker as Jo, producerLookupOver as Jr, isNotImplemented as Js, isReplacementOrphan as Jt, resolveDynamoDbDeleteBudgetClock as K, repairMalformedResourcesForReadOnly as Ka, stripControlChars as Kc, hasReadableOrphans as Ki, effectiveDeletionPolicy as Kn, liveMatchesUnresolvedTokenFrame as Ko, IntrinsicFunctionResolver as Kr, crossPrefixDeniedWarning as Ks, demoteSupersededOrphans as Kt, PROTECTION_PROPERTY_BY_TYPE as L, refuseMalformedResourcesForDeploy as La, isMalformedEnvKey as Lc, declaresNoEcho as Li, clearBucketRegionCache as Ll, secretNamedRecordNeedles as Ln, maskWholeValue as Lo, markWaitAbandoned as Lr, WHOLE_DYNAMIC_REFERENCE_PATTERN as Ls, sameJournaledOrphans as Lt, noEchoComparisonForTemplate as M, refuseMalformedResourceEntriesForOrphan as Ma, dockerSpawnEnvWithSensitive as Mc, refStateLookupFromResource as Mi, displayAssemblyPath as Ml, journaledOrphanPrintingBag as Mn, TemplateParser as Mo, deleteIndeterminateGuards as Mr, wholeStringLeavesOf as Ms, dropFailedHint as Mt, noEchoExactEchoLeavesOf as N, refuseMalformedResourcePropertiesForDestroy as Na, finchSecretArgvRefusal as Nc, parseWebACLArn as Ni, renderAssemblyPathEscape as Nl, maskEventTextWithBoundBags as Nn, canonicalCoordinates as No, deleteLeftInPlace as Nr, STATE_SOURCED_BASELINE_RULES as Ns, isHandledOrphan as Nt, serviceTokenBlockingReason as O, refuseMalformedResourceEntriesForDeploy as Oa, resolveDockerContextDirectory as Oc, keepsSecretReferenceToken as Oi, nullPrototypeRecord as Ol, bindingSkippedOutputs as On, canonicalLambdaFunctionName as Oo, slowCcOperationTimeoutMs as Or, recordMaskOnlyValuesIn as Os, collectNestedChildUnaddressed as Ot, noEchoParameterNamesOf as P, refuseMalformedResourcePropertiesForDrift as Pa, formatDockerLoginError as Pc, withSharedDrainBudget as Pi, resolveAssemblyPath as Pl, orphanRecordsPrintingBag as Pn, isMarkedCoordinate as Po, deleteSkipReason as Pr, STATE_SOURCED_CROSS_GENERATION_RULES as Ps, journaledOrphanLines as Pt, ECR_AUTO_DELETE_IMAGES_TAG as Q, findSilentDropProperties as Qa, getDefaultStateBucketName as Qc, malformedExportNamesWarning as Qi, findDestructiveChanges as Qn, printingCorpusOf as Qo, assertSendableRoleArn as Qr, exportNamesCarriedFrom as Qs, recordUnderIdIsNotOwn as Qt, isProtectionValueActive as R, refuseMalformedResourcesForDestroy as Ra, partitionSensitiveEnv as Rc, JSON_LISTING_HOLE_VALUE as Ri, resolveBucketRegion as Rl, stateSecretNameNeedles as Rn, maskedLeafCoordinatesOf as Ro, disableInstanceApiTermination as Rr, isSingleDynamicReferenceToken as Rs, replayFailedOperations as Rt, lookupEachName as S, refuseMalformedOrphansForDestroy as Sa, parseBootstrapMarker as Sc, parameterTypeMayLoseSecretIdentity as Si, AssemblyReader as Sl, exportNameSecretExposure as Sn, requireConfigObject as So, getCurrentResourceSecrets as Sr, recordAttributeIdCopy as Ss, getNestedRevertRun as St, recordRetainedForReadoption as T, refuseMalformedOutputsForDestroy as Ta, validateContainerRepoName as Tc, carriesDynamicReference as Ti, defineOwnKey as Tl, collectDeclaredOutputNames as Tn, templateResourceTypes as To, applyCustomResourceResponseExpiration as Tr, carriesSecretMask as Ts, revertNestedChildFromJournal as Tt, beginDeleteWait as U, repairMalformedOutputsForReadOnly as Ua, runDockerStreaming as Uc, accountArgs as Ui, buildFinalSnapshotIdentifier as Un, readbackPathFor as Uo, reEnableInstanceApiTermination as Ur, CrossPrefixReadError as Us, withStackRecords as Ut, DynamoDBGlobalTableProvider as V, repairMalformedOrphanRecordsForReadOnly as Va, redactedDockerCause as Vc, UNREADABLE_ORPHANS_CONTAINER_ROW as Vi, ATOMIC_FINAL_SNAPSHOT_TYPES as Vn, noEchoOutputsComparison as Vo, observeThenDisableInstanceApiTermination as Vr, S3StateBackend as Vs, destroyStackRecordsView as Vt, compensateRemovedDeletionProtection as W, repairMalformedResourceEntriesForReadOnly as Wa, warnFinchArgvExposure as Wc, deployRefusesOrphanRowsReason as Wi, ccRoutedFinalSnapshotError as Wn, readsNoEchoSource as Wo, DiffCalculator as Wr, CrossPrefixScanCache as Ws, removeProtectionTypeList as Wt, deleteTableWithIndexBusyRetry as X, withheldAccountClause as Xa, Synthesizer as Xc, isReadableResourceEntry as Xi, maskingRetryLogger as Xn, literalSplitDelimitersOf as Xo, applyRoleArnIfSet as Xr, acceptedCreateOnlyDropsOf as Xs, planRollback as Xt, INDEX_SETTLE_POLL_INTERVAL_MS as Y, unreadableResourceEntries as Ya, getDockerImageBySourceHash as Yc, isReadableOrphanRecord as Yi, unsupportedFinalSnapshotError as Yn, hasMaskableValues as Yo, refuseUnreadableCdkCrossAccountRefs as Yr, splitImportedOps as Ys, planFailedOps as Yt, waitForIndexesSettled as Z, findActionableSilentDrops as Za, synthesisStatusMessage as Zc, malformedDriftResourcePropertiesWarning as Zi, constructPathOf as Zn, logOnlyValueCount as Zo, assertFlagRoleArn as Zr, describeRegionValueKind as Zs, recheckFailedPlan as Zt, keptWholeReasonText as _, refuseDivergentRecordRegionForDestroy as _a, BOOTSTRAP_MARKER_PREFIX as _c, classifyReplaySecretRegion as _i, decodeListingKey as _l, secretBearing as _n, configIntegerRefusal as _o, isCustomResource as _r, identityKeyFor as _s, planOrphanAdoption as _t, inheritedProvenanceForChildDiff as a, malformedOrphanRowsKeptWarning as aa, orphansAfterRollback as ac, envCredentialsAreAssumedRole as ai, resolveStateBucketWithDefault as al, inheritProducerRegions as an, MULTI_REGION_RECREATE_BLOCKED_TYPES as ao, DBPROXY_TAGS_WHAT as ar, maskSecretsInText as as, createReadOnlyAttributeHealerFactory as at, chunks as b, refuseMalformedOrphanRecordsForDestroy as ba, getBootstrapMarkerKey as bc, coerceParameterTypedValue as bi, canonicalizeRegion as bl, carriedExportAliasExposure as bn, replayWarn as bo, readsNoEchoDeleteValues as br, recoverMaskedOutput as bs, displacedPhysicalIdShown as bt, isAbsoluteAssetPath as c, malformedOutputsRefusalMessage as ca, AssetPublisher as cc, outputReferenceProvenanceOf as ci, stateBucketExistenceConfirmed as cl, redactedDeleteAddressFields as cn, renderStatefulReason as co, readTagList as cr, snapshotPassProvenance as cs, gray as ct, templateIdentity as d, malformedResourceEntriesWarning as da, WorkGraph as dc, s3BucketArn as di, CFN_TEMPLATE_BODY_LIMIT as dl, updatePartialReason as dn, isWarmThroughputDecrease as do, tagPlanWarning as dr, withPhysicalNameCopies as ds, yellow as dt, malformedLocalOutputsWarning as ea, hasReasonlessBaselineRefusal as ec, isIamRoleArn as ei, loadCdkJson as el, resolveReplacementOldType as en, withoutSilentDropProperties as eo, earliestDefined as er, recordLogOnlyValue as es, hasCdkAutoDeleteTag as et, conditionFingerprint as f, malformedResourcePropertiesWarning as fa, buildAssetRedirectMap as fc, s3BucketDomainName as fi, CFN_TEMPLATE_URL_LIMIT as fl, DeploymentEventsReader as fn, toCfnInteger as fo, definedAttributes as fr, withoutPhysicalNameCopies as fs, computeParameterTaint as ft, isSecretBearingReferenceString as g, previewableOrphanRecords as ga, AssetModeResolver as gc, classifyRecordedSecretRegion as gi, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as gl, exportAliasCollisionScrubWarning as gn, configBooleanRefusal as go, ccBrokenReason as gr, pathCrossesDottedKey as gs, makeSiblingClaimReader as gt, readRecordedConditionVerdicts as h, malformedStateRefusalMessage as ha, rewriteTemplateAssetReferences as hc, s3BucketWebsiteUrl as hi, uploadCfnTemplate as hl, displayTextOrWithheld as hn, coerceCfnInteger as ho, ProviderRegistry as hr, isUncertifiedBaselineMaskPosition as hs, resourcesNamingDeclaredParameter as ht, crossStackOutputProvenanceSource as i, malformedOrphanRecordsWarning as ia, isReadableBag as ic, callerEnvCredentials as ii, resolveSkipPrefix as il, getCurrentProducerRegions as in, shownType as io, acquireIdempotencyToken as ir, maskSecretsInError as is, formatResourceLine as it, noEchoAttributeNamesOf as j, refuseMalformedResourceEntriesForImportSave as ja, describeDockerFailure as jc, isStalePlaceholderArnAttribute as ji, describeFileReadFailure as jl, completedReplayEntries as jn, DagBuilder as jo, UNSPECIFIED_SKIP_REASON as jr, recordProvenPublicExpression as js, deleteJournaledOrphans as jt, withResourceDeadline as k, refuseMalformedResourceEntriesForDestroy as ka, describeDockerCapturedOutput as kc, AWS_NO_VALUE as ki, ownValue as kl, DEFAULT_RESOURCE_TIMEOUT_MS as kn, lambdaFunctionNameForMask as ko, unchangedBehindSecretReference as kr, recordNoEchoAttributeValues as ks, getCurrentNestedStackContext as kt, listNestedTemplateRows as l, malformedOutputsWarning as la, isSensitiveAttributeName as lc, recordedOutputReferenceRegions as li, warnDeprecatedNoPrefixCliFlag as ll, redactedDeleteAddressSkip as ln, WARM_THROUGHPUT_MEMBERS as lo, refuseMalformedDesiredTags as lr, redactSecretsForState as ls, green as lt, parentSuppliedValues as m, malformedScrubResourceEntriesRefusalMessage as ma, loadPublishableAssetManifest as mc, s3BucketRegionalDomainName as mi, findLargeInlineResources as ml, WITHHELD_NAME_DISPLAY as mn, coerceCfnBoolean as mo, CC_BROKEN_REASON as mr, dynamicReferenceTokens as ms, reachableDivergentParameters as mt, IMPLICIT_DELETE_DEPENDENCIES as n, malformedLocalResourcesWarning as na, importableOutputKeys as nc, AWS_CREDENTIAL_ENV_KEYS as ni, resolveAutoAssetStorage as nl, orphanDeleteNeedsIdentity as nn, hasNoCloudControlHandlers as no, reserveStackCreateToken as nr, createSecretMasker as ns, getPriorAttempts as nt, childTemplateLoader as o, malformedOrphansRefusalMessage as oa, orphansCarriedFrom as oc, isSettledInstanceState as oi, resolveStateBucketWithDefaultAndSource as ol, REDACTED_DELETE_ADDRESS_SKIP_REASON as on, isStatefulRecreateTargetForReplace as oo, DBPROXY_TAG_OPTIONS as or, markSameGenerationBag as os, bold as ot, conditionInputsFrom as p, malformedResourcesWarning as pa, createAssetRedirectResolver as pc, s3BucketDualStackDomainName as pi, MIGRATE_TMP_PREFIX as pl, DeploymentEventsStore as pn, toFiniteNumber as po, stringifyIfAssigned as pr, DYNAMIC_REFERENCE_TOKEN_SCAN as ps, namesAnyDeclaredParameter as pt, resolveDynamoDbDeleteBudgetMs as q, unpreviewableOrphanRecords as qa, stripForDisplay as qc, hasReadableOutputs as qi, isFinalSnapshotError as qn, carryLogOnlyValues as qo, poisonRenderedSpellingsCollidingIn as qr, isAccessDenied$1 as qs, isJournaledOrphan as qt, computeImplicitDeleteEdges as r, malformedOrphanRecordsRefusalMessage as ra, importableOutputs as rc, applyCallerIdentityCredentials as ri, resolveCaptureObservedState as rl, findNestedStackTypeChanges as rn, findReplacedReadersOfRecreateTargets as ro, withCreateTokenLedger as rr, errorCauseChain as rs, markRefusedBeforeApplying as rt, findNestedTemplateTreeDefect as s, malformedOrphansWarning as sa, shouldRetainResource as sc, keepHeldTokenProvenance as si, resolveUseCdkBootstrapAssets as sl, isRedactedRecordedValue as sn, isStatefulRecreateTargetSync as so, planTagDiff as sr, recordReferenceProvenanceEntry as ss, cyan as st, DeployEngine as t, malformedLocalResourceEntriesWarning as ta, hasUnverifiableParameterRefusal as tc, sendableAssumeRoleCommand as ti, resolveApp as tl, seedsDeleteFirstGuard as tn, NO_CC_HANDLERS_REASON as to, ledgerForStack as tr, shareLogOnlyValues as ts, isTruthyCfnBoolean as tt, renderNestedTemplateTreeDefect as u, malformedRenderedContainersWarning as ua, stringifyValue as uc, recordedReferenceRegions as ui, ssmResolvedValueType as ul, updatePartialMessage as un, coerceWarmThroughput as uo, tagMapAsList as ur, scrubResourceRecord as us, red as ut, mergeNoChangeOutputs as v, refuseMalformedNestedChildOutputs as va, assertAssetBucketRegion as vc, producerRegionsFromState as vi, expectedOwnerParam as vl, secretBearingStateKeyWarning as vn, configStringRefusal as vo, wouldReturnToSdkProvider as vr, inheritNestedStackParameterAssociations as vs, NESTED_PENDING_PARENT_REASON as vt, keptForReadoption as w, refuseMalformedOutputs as wa, validateAssetBucketName as wc, isImpossibleEmptyStoredAttribute as wi, processStackMessages as wl, noEchoParameterValueSeed as wn, prefetchCreateOnlyPropertyPaths as wo, CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID as wr, splitGetAttStringForm as ws, recordDisplacedSkips as wt, isAccessDeniedError as x, refuseMalformedOrphans as xa, isCrossRegionRedirect as xc, isUnboundTemplateParameter as xi, derivePartitionAndUrlSuffix as xl, exportNameNoEchoParameters as xn, requireConfigArray as xo, isCustomResourceType as xr, physicalNameCopiesOf as xs, dropSettledNestedJournals as xt, makeCanonicalizePropertiesFn as y, refuseMalformedOrphanRecords as ya, ensureAssetStorage as yc, regionLessSecretName as yi, PARTITION_TABLE as yl, secretSafeKeyDisplay as yn, readConfigString as yo, TemplateNoEchoReresolver as yr, recordNestedStackParameterExpressions as ys, displacedOpClause as yt, perType as z, refuseMalformedResourcesForExport as za, redactDockerArgvValues as zc, STATE_REGION_DIVERGED as zi, storedSecretNameNeedles as zn, noEchoCoordinatesOf as zo, ec2InstanceProtectionSite as zr, LockManager as zs, replayRollback as zt };
47057
+ //# sourceMappingURL=deploy-engine-D6CSo8Gj.js.map