@go-to-k/cdkd 0.294.8 → 0.294.10

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 (26) hide show
  1. package/dist/{asg-provider-CsajFK4_.js → asg-provider-BFlmarbF.js} +2 -2
  2. package/dist/{asg-provider-CsajFK4_.js.map → asg-provider-BFlmarbF.js.map} +1 -1
  3. package/dist/cli.js +35 -4
  4. package/dist/cli.js.map +1 -1
  5. package/dist/{deploy-engine-C5kAhscq.js → deploy-engine-RCOtmm4V.js} +1214 -702
  6. package/dist/deploy-engine-RCOtmm4V.js.map +1 -0
  7. package/dist/iam-policy-targets-CMSQGQnm.js.map +1 -1
  8. package/dist/{iam-role-provider-CPn7nqoS.js → iam-role-provider-2w-Hr9_h.js} +2 -2
  9. package/dist/{iam-role-provider-CPn7nqoS.js.map → iam-role-provider-2w-Hr9_h.js.map} +1 -1
  10. package/dist/index.d.ts +6 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -2
  13. package/dist/{neptune-provider-DlFQdgwe.js → neptune-provider-CHnIs1hG.js} +2 -2
  14. package/dist/{neptune-provider-DlFQdgwe.js.map → neptune-provider-CHnIs1hG.js.map} +1 -1
  15. package/dist/{program-CVOLJJ2z.js → program-Eed63bId.js} +255 -17
  16. package/dist/program-Eed63bId.js.map +1 -0
  17. package/dist/{provider-classes-DlVxBF89.js → provider-classes-R7yvwymx.js} +287 -67
  18. package/dist/provider-classes-R7yvwymx.js.map +1 -0
  19. package/dist/{rds-provider-a-vZsR9L.js → rds-provider-DqHELwjV.js} +2 -2
  20. package/dist/{rds-provider-a-vZsR9L.js.map → rds-provider-DqHELwjV.js.map} +1 -1
  21. package/dist/{version-DGxZ-zFN.js → version-BNo3JdVW.js} +2 -2
  22. package/dist/{version-DGxZ-zFN.js.map → version-BNo3JdVW.js.map} +1 -1
  23. package/package.json +2 -2
  24. package/dist/deploy-engine-C5kAhscq.js.map +0 -1
  25. package/dist/program-CVOLJJ2z.js.map +0 -1
  26. package/dist/provider-classes-DlVxBF89.js.map +0 -1
@@ -2,7 +2,7 @@ import { r as getAwsClients, s as __exportAll } from "./aws-clients-CnmtbrxD.js"
2
2
  import { A as displaySafe, E as UNRENDERABLE, F as safeMsg, L as truncateCodePoints, M as isPasteableIdent, O as displayAwsMessage, P as plainIdentOr, S as withoutGeneratedFallbackName, T as STACK_REF_MAX_CODE_POINTS, _ as getCurrentSkipPrefix, b as withSkipPrefix, c as getLiveRenderer, f as applyDefaultNameForFallback, g as generateResourceNameWithFallback, h as generateResourceName, j as displayStackName, k as displayIdent, m as explicitNamePropertyFor, n as getLogger, r as isStdoutReservedForPayload, s as installLogLineMaskerSource, v as getCurrentStackName, w as SECRET_REF_MAX_CODE_POINTS, x as withStackName, y as looksLikeCdkdGeneratedName } from "./logger-B46YMG0h.js";
3
3
  import { $t as StateError, A as isTerminalDeleteFailure, An as isAmbiguousCcHandlerErrorCode, At as clientDefaultsFor, Bn as isMarkedNonRetryable, Bt as IntrinsicResolutionRefusalError, C as refusalTypeShown, Cn as isNameCollisionErrorFrom, D as ProtectionFlipRegistry, Dt as withPasteableAwsProfile, En as isReplayedNameCollisionFrom, Fn as retryClassificationText, Gt as MalformedProducerRecordRefusalError, H as pasteableAwsCommand, Hn as markNonRetryable, In as describeAwsFailure, It as CrossAccountSecretRefusalError, J as isInterruptedWaitError, Jt as ProvisioningError, Lt as DependencyError, M as observeThenDisableProtection, Mn as isIamPropagationError, Mt as AccountIdUnavailableError, N as protectionFlipKey, Nn as isRetryableTransientError, Nt as AssetError, O as compensateProtectionFlip, On as markReplayMayCollide, Ot as ambientClientDefaults, Pn as isTransientServerError, Pt as CdkdError, Q as canonicalizeRoute53QueryName, R as DELETION_PROTECTION_DOC_POINTER, Rn as safeStringify$1, S as quotedRemedyLogicalId, Sn as hasReplayMayCollide, St as injectiveKey, T as resolveExplicitPhysicalId, Tn as isRecreateRetryableError, Tt as producerRecordKey, U as protectedReplacementAdvice, Un as markRedactedCause, Ut as LockError, Vn as isThrottlingError, Wn as wrapMaskedAwsError, Wt as MacroExpansionError, X as ElapsedBudgetRegistry, Xt as ResourceUpdateNotSupportedError, Y as startInterruptWatch, Yt as ResourceTimeoutError, Z as monotonicNowMs, _n as shellQuote, _t as formatLockOperation, at as segmentAfterAnchor, b as isQuotableImportValue, bt as CUSTOM_RESOURCE_RESPONSE_PREFIX, cn as UNSHOWABLE_VALUE, ct as isSecretDerivedValue, d as prepareRemovalForUpdate, dn as isInertUnquoted, dt as withDerivedNameMasks, en as SynthesisError, et as compositeIdSeparatorRefusal, f as removalWarning, fn as pasteableCommand, ft as UNREPRODUCIBLE_LOCK_CLAUSE, g as assertRegionMatch, gn as shellBoundedDisplay, gt as formatLockExpiry, h as RESOURCE_NOT_FOUND, hn as quotedOrDescribed, i as holdsSecretDerivedEntry, it as resourceTypeShown, jn as isAmbiguousOutcomeError, jt as credentialFingerprint, k as deleteWithProtectionCompensation, kn as formatRetryClassificationSignals, kt as ambientCredentialConfig, l as withUnchangedSecretPrincipalLists, ln as commandHole, lt as maskDeep, m as withoutInjectedRemovals, mn as plainOrDescribed, nt as logicalIdShown, on as SHELL_ACTIVE, ot as createMaskedLogSinks, pn as physicalIdShownBesideCommand, pt as buildForceUnlockCommand, rn as normalizeAwsError, sn as SHELL_ACTIVE_WHY, st as createMaskedRetryLogger, ut as maskerOrIdentity, vn as withheldTargetClause, vt as formatLockOwner, wn as isNameCooldownError, x as normalizeAwsTagsToCfn, xn as isUpdateUnsupportedError, xt as DEFAULT_STATE_PREFIX, yt as sanitizeRecoveryValue, zt as DynamicReferenceRegionAmbiguousError } from "./iam-policy-targets-CMSQGQnm.js";
4
4
  import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, s as ambientRegion, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-D0q0z4dG.js";
5
- import { t as getCdkdVersion } from "./version-DGxZ-zFN.js";
5
+ import { t as getCdkdVersion } from "./version-BNo3JdVW.js";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
8
8
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -4645,6 +4645,12 @@ function importableOutputKeys(state) {
4645
4645
  if (state.exportNames === void 0) return Object.keys(outputs);
4646
4646
  return state.exportNames.filter((name) => typeof name === "string" && Object.hasOwn(outputs, name));
4647
4647
  }
4648
+ function acceptedCreateOnlyDropsOf(record) {
4649
+ if (record === null || typeof record !== "object") return /* @__PURE__ */ new Set();
4650
+ const value = record.acceptedCreateOnlyDrops;
4651
+ if (!Array.isArray(value)) return /* @__PURE__ */ new Set();
4652
+ return new Set(value.filter((entry) => typeof entry === "string"));
4653
+ }
4648
4654
  function hasReadableExportSet(state) {
4649
4655
  if (!isReadableBag(state.outputs)) return false;
4650
4656
  if (state.exportNames === void 0) return true;
@@ -6077,18 +6083,24 @@ function isPlainObject$3(value) {
6077
6083
 
6078
6084
  //#endregion
6079
6085
  //#region src/deployment/secret-redaction/mask-only.ts
6080
- const recordedSecretExpressions$1 = /* @__PURE__ */ new Set();
6081
- function recordSecretExpression(expression) {
6082
- recordedSecretExpressions$1.add(expression);
6086
+ const recordedSecretExpressions = /* @__PURE__ */ new Set();
6087
+ const secretVerdictScopes = /* @__PURE__ */ new Map();
6088
+ function pinScopedSecretVerdict(scope, expression, secret) {
6089
+ const scopes = secretVerdictScopes.get(expression);
6090
+ if (secret) {
6091
+ if (scopes) scopes.add(scope);
6092
+ else secretVerdictScopes.set(expression, /* @__PURE__ */ new Set([scope]));
6093
+ recordedSecretExpressions.add(expression);
6094
+ return;
6095
+ }
6096
+ if (scopes?.delete(scope) && scopes.size === 0) secretVerdictScopes.delete(expression);
6097
+ recordedSecretExpressions.delete(expression);
6083
6098
  }
6084
- function forgetSecretExpression(expression) {
6085
- recordedSecretExpressions$1.delete(expression);
6099
+ function isScopedSecretVerdict(scope, expression) {
6100
+ return secretVerdictScopes.get(expression)?.has(scope) === true;
6086
6101
  }
6087
6102
  function isRecordedSecretExpression(expression) {
6088
- return recordedSecretExpressions$1.has(expression);
6089
- }
6090
- function clearRecordedSecretExpressions() {
6091
- recordedSecretExpressions$1.clear();
6103
+ return recordedSecretExpressions.has(expression);
6092
6104
  }
6093
6105
  function recordMaskOnlyValue(secrets, plaintext) {
6094
6106
  if (plaintext.length < 4) return;
@@ -6542,12 +6554,11 @@ function positionByRecordedParameterSpans(bag, source, secrets, associations) {
6542
6554
  let persisted = "";
6543
6555
  const gaps = [];
6544
6556
  const certified = [];
6545
- for (const { start, length, parameter } of recorded) {
6557
+ for (const { start, length, key } of recorded) {
6546
6558
  if (!(start >= previousEnd && length > 0 && start + length <= bag.length)) return void 0;
6547
6559
  previousEnd = start + length;
6548
6560
  const text = bag.slice(start, start + length);
6549
- const key = crossStackSourceKey({ Ref: parameter });
6550
- const association = key === void 0 ? void 0 : associations.get(key);
6561
+ const association = associations.get(key);
6551
6562
  if (association === void 0 || typeof association === "symbol") continue;
6552
6563
  const expression = certifiedExpressionForLeaf(secrets, association, text);
6553
6564
  if (expression === void 0) continue;
@@ -7201,7 +7212,7 @@ function positionByIntrinsicSkeleton(bag, source, secrets, secretExpressions) {
7201
7212
  if (!pattern) return void 0;
7202
7213
  const plaintextOf = plaintextIndexOf(secrets);
7203
7214
  let matched;
7204
- for (const candidate of /* @__PURE__ */ new Set([...secretExpressions, ...recordedSecretExpressions$1])) {
7215
+ for (const candidate of /* @__PURE__ */ new Set([...secretExpressions, ...recordedSecretExpressions])) {
7205
7216
  if (candidate.length > MAX_SKELETON_CANDIDATE_LENGTH) return void 0;
7206
7217
  if (!pattern.test(candidate)) continue;
7207
7218
  const recordedPlaintext = plaintextOf.get(candidate);
@@ -7259,7 +7270,7 @@ function positionByIntrinsicFrame(bag, source, secrets, secretExpressions, bagIs
7259
7270
  let matched;
7260
7271
  for (const candidate of /* @__PURE__ */ new Set([
7261
7272
  ...secretExpressions,
7262
- ...recordedSecretExpressions$1,
7273
+ ...recordedSecretExpressions,
7263
7274
  ...resolvedExpressionsOf(secrets)
7264
7275
  ])) {
7265
7276
  if (candidate.length > MAX_SKELETON_CANDIDATE_LENGTH) return void 0;
@@ -7327,10 +7338,10 @@ function recordIntrinsicLeafResolution(secrets, source, resolution) {
7327
7338
  secret
7328
7339
  })),
7329
7340
  complete: resolution.complete,
7330
- ...resolution.parameterSpans === void 0 ? {} : { parameterSpans: resolution.parameterSpans.map(({ start, length, parameter }) => ({
7341
+ ...resolution.parameterSpans === void 0 ? {} : { parameterSpans: resolution.parameterSpans.map(({ start, length, key }) => ({
7331
7342
  start,
7332
7343
  length,
7333
- parameter
7344
+ key
7334
7345
  })) }
7335
7346
  };
7336
7347
  const previous = leaves.get(source);
@@ -7359,7 +7370,7 @@ function sameLeafResolution(a, b) {
7359
7370
  }
7360
7371
  function sameParameterSpans(a, b) {
7361
7372
  if (a === void 0 || b === void 0) return a === b;
7362
- return a.length === b.length && a.every((s, i) => s.start === b[i].start && s.length === b[i].length && s.parameter === b[i].parameter);
7373
+ return a.length === b.length && a.every((s, i) => s.start === b[i].start && s.length === b[i].length && s.key === b[i].key);
7363
7374
  }
7364
7375
  function substitutedSpellingOf(secrets, source, resolvedValue) {
7365
7376
  const resolution = intrinsicLeafResolutionsOf.get(secrets)?.get(source);
@@ -10063,8 +10074,8 @@ const REVERSE_REPLACEMENT_NAME_KEYS = {
10063
10074
  "AWS::Glue::Job": flat("Name"),
10064
10075
  "AWS::Glue::SecurityConfiguration": flat("Name"),
10065
10076
  "AWS::Glue::Table": {
10066
- name: [["TableInput", "Name"]],
10067
- scope: [["DatabaseName"]]
10077
+ name: [["TableInput", "Name"], ["Name"]],
10078
+ scope: [["DatabaseName"], ["CatalogId"]]
10068
10079
  },
10069
10080
  "AWS::Glue::Trigger": flat("Name"),
10070
10081
  "AWS::Glue::Workflow": flat("Name"),
@@ -10137,6 +10148,8 @@ const CASE_INSENSITIVE_NAME_TYPES = /* @__PURE__ */ new Set([
10137
10148
  "AWS::RDS::DBInstance",
10138
10149
  "AWS::RDS::DBSubnetGroup"
10139
10150
  ]);
10151
+ const ASCII_CASE_INSENSITIVE_NAME_TYPES = /* @__PURE__ */ new Set(["AWS::Glue::Table"]);
10152
+ const NO_PHYSICAL_ID_NAME_PROOF = /* @__PURE__ */ new Set(["AWS::Glue::Table"]);
10140
10153
  const GENERATED_NAME_VERBATIM = /* @__PURE__ */ new Set([
10141
10154
  "AWS::CloudWatch::Alarm",
10142
10155
  "AWS::DocDB::DBCluster",
@@ -10566,16 +10579,18 @@ function holderVerdict(input, v) {
10566
10579
  }
10567
10580
  if (namePath === void 0 || wantName === void 0) return unproven(`${v.create} named no ${labels} (its provider picks one), so cdkd cannot show that ${newResource} holds it`);
10568
10581
  const wanted = generatedName ? `${v.create} named no ${labels}, and the cdkd naming rule generates ${r.shown(namePath.join("."))} ${r.quoted(wantName)} for it` : `${v.create} asked for ${r.shown(namePath.join("."))} ${r.quoted(wantName)}`;
10569
- const same = CASE_INSENSITIVE_NAME_TYPES.has(oldResourceType) ? (a, b) => a.toLowerCase() === b.toLowerCase() : (a, b) => a === b;
10570
- const inCase = CASE_INSENSITIVE_NAME_TYPES.has(oldResourceType) ? (value) => value.toLowerCase() : (value) => value;
10571
- const drifted = newKey.name.find((path) => {
10572
- const recordedName = valueAt(recorded, path);
10573
- const observedName = valueAt(observed, path);
10574
- return recordedName !== void 0 && observedName !== void 0 && !same(recordedName, observedName);
10582
+ const asciiFold = ASCII_CASE_INSENSITIVE_NAME_TYPES.has(oldResourceType);
10583
+ const inCase = CASE_INSENSITIVE_NAME_TYPES.has(oldResourceType) ? (value) => value.toLowerCase() : asciiFold ? (value) => value.replace(/[A-Z]/g, (c) => c.toLowerCase()) : (value) => value;
10584
+ const same = (a, b) => inCase(a) === inCase(b);
10585
+ const namePathHeld = newKey.name.find((path) => {
10586
+ const h = heldAt(recorded, observed, path);
10587
+ return h.value !== void 0 || h.unreadable;
10575
10588
  });
10576
- if (drifted !== void 0) return unproven(`${wanted}, and the records of ${newResource} disagree on its ${r.shown(drifted.join("."))} (recorded ${r.quoted(valueAt(recorded, drifted) ?? "")}, read back ${r.quoted(valueAt(observed, drifted) ?? "")}), so cdkd cannot show which name it holds`);
10577
- const haveName = newKey.name.map((path) => heldAt(recorded, observed, path)).find((h) => h.value !== void 0)?.value;
10578
- if (!(haveName !== void 0 && same(haveName, wantName) || physicalId !== "" && holderIdNames(inCase(physicalId), inCase(wantName)))) return haveName !== void 0 && !generatedName ? elsewhere(`${wanted}, while ${newResource} holds ${r.quoted(haveName)}`) : unproven(`${wanted}, and cdkd cannot show that ${newResource} holds that name`);
10589
+ const recordedName = namePathHeld && valueAt(recorded, namePathHeld);
10590
+ const observedName = namePathHeld && valueAt(observed, namePathHeld);
10591
+ if (namePathHeld !== void 0 && recordedName !== void 0 && observedName !== void 0 && !same(recordedName, observedName)) return unproven(`${wanted}, and the records of ${newResource} disagree on its ${r.shown(namePathHeld.join("."))} (recorded ${r.quoted(recordedName)}, read back ${r.quoted(observedName)}), so cdkd cannot show which name it holds`);
10592
+ const haveName = namePathHeld === void 0 ? void 0 : heldAt(recorded, observed, namePathHeld).value;
10593
+ if (!(haveName !== void 0 && same(haveName, wantName) || physicalId !== "" && !NO_PHYSICAL_ID_NAME_PROOF.has(newResourceType) && holderIdNames(inCase(physicalId), inCase(wantName)))) return haveName !== void 0 && !generatedName ? elsewhere(`${wanted}, while ${newResource} holds ${r.quoted(haveName)}`) : unproven(`${wanted}, and cdkd cannot show that ${newResource} holds that name`);
10579
10594
  for (const [i, path] of (oldKey.scope ?? []).entries()) {
10580
10595
  const label = r.shown(path.join("."));
10581
10596
  const wantRaw = valueAt(requested, path);
@@ -14841,6 +14856,29 @@ function excludeCreateOnly(resourceType, names) {
14841
14856
  if (createOnly === void 0 || createOnly.size === 0) return names;
14842
14857
  return names.filter((property) => !createOnly.has(property));
14843
14858
  }
14859
+ function withoutUnwrittenSilentDropProperties(resourceType, recordedProperties, desiredProperties, allowedKeys, evidence) {
14860
+ const drops = findSilentDropProperties(resourceType, recordedProperties);
14861
+ if (drops.length === 0) return recordedProperties;
14862
+ const createOnly = getPropertyCoverage(resourceType)?.createOnlyDrops;
14863
+ const accepted = new Set(findAcceptedSilentDrops(resourceType, desiredProperties, allowedKeys, recordedProperties));
14864
+ const removable = drops.map(({ property }) => property).filter((property) => createOnly?.has(property) !== true || evidence.has(property) && !accepted.has(property));
14865
+ if (removable.length === 0) return recordedProperties;
14866
+ const narrowed = { ...recordedProperties };
14867
+ for (const property of removable) delete narrowed[property];
14868
+ return narrowed;
14869
+ }
14870
+ function findUnwrittenCreateOnlyDrops(resourceType, recordedProperties, desiredProperties, allowedKeys, evidence) {
14871
+ const createOnly = getPropertyCoverage(resourceType)?.createOnlyDrops;
14872
+ if (createOnly === void 0 || createOnly.size === 0 || evidence.size === 0) return [];
14873
+ const accepted = new Set(findAcceptedSilentDrops(resourceType, desiredProperties, allowedKeys, recordedProperties));
14874
+ return findSilentDropProperties(resourceType, recordedProperties).map(({ property }) => property).filter((property) => createOnly.has(property) && evidence.has(property) && !accepted.has(property) && Object.hasOwn(desiredProperties, property) && sameJsonValue(recordedProperties[property], desiredProperties[property], "unchanged"));
14875
+ }
14876
+ function unwrittenCreateOnlyReplacement(resourceType, recordedProperties, desiredProperties, allowedKeys, evidence, replacingPaths) {
14877
+ if (replacingPaths.length === 0) return [];
14878
+ const unwritten = findUnwrittenCreateOnlyDrops(resourceType, recordedProperties, desiredProperties, allowedKeys, evidence);
14879
+ if (unwritten.length === 0) return [];
14880
+ return replacingPaths.every((path) => unwritten.includes(path)) ? unwritten : [];
14881
+ }
14844
14882
  function unsupportedPropertyIssueUrl(resourceType, property) {
14845
14883
  return `https://github.com/go-to-k/cdkd/issues/new?title=${encodeURIComponent(`Support property ${resourceType}.${property}`)}&labels=resource-support`;
14846
14884
  }
@@ -15645,6 +15683,120 @@ function malformedOrphansForOrphanRefusalMessage(rawStackName, rawRegion, logica
15645
15683
  return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read — ${namedOrphanRows(logicalIds)} — because the record has no string 'logicalId' or shares it with another row, or its 'state' is not an object, names no resource type, has no non-empty string 'physicalId', or holds a 'properties' or 'attributes' map that is not an object. The record is malformed or truncated. ${verbatim} Those records are not inert: they are what the next 'cdkd deploy' may re-adopt into 'resources' and what 'cdkd diff' previews for adoption, so continuing would report success over damage the next command meets.`, "'cdkd orphan' cannot remove such a record itself: it is not in 'resources', so it has no construct path. Repair the record by hand rather than deleting it — it is the only record that an earlier failed deploy left its resource live in AWS.", ORPHANS_DROP_CAVEAT);
15646
15684
  }
15647
15685
 
15686
+ //#endregion
15687
+ //#region src/deployment/masked-property-fingerprints.ts
15688
+ const FINGERPRINT_LAYOUT$1 = 1;
15689
+ function canonicalJson$2(value) {
15690
+ if (value === void 0) return "null";
15691
+ if (Array.isArray(value)) return `[${value.map(canonicalJson$2).join(",")}]`;
15692
+ if (value !== null && typeof value === "object") {
15693
+ const record = value;
15694
+ return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson$2(record[key])}`).join(",")}}`;
15695
+ }
15696
+ return JSON.stringify(value) ?? "null";
15697
+ }
15698
+ const REFUSED_FINGERPRINT = "refused:secret-in-template";
15699
+ const FINGERPRINT_PREFIX = "sha256:";
15700
+ function templateCarriesNeedle(templateValue, secrets) {
15701
+ const text = canonicalJson$2(templateValue);
15702
+ for (const needle of printingCorpusOf(secrets).keys()) {
15703
+ if (needle.length < 4) continue;
15704
+ if (text.includes(needle) || text.includes(JSON.stringify(needle).slice(1, -1))) return true;
15705
+ }
15706
+ return false;
15707
+ }
15708
+ function maskedPropertyFingerprint(templateValue) {
15709
+ const digest = createHash("sha256").update(canonicalJson$2({
15710
+ layout: FINGERPRINT_LAYOUT$1,
15711
+ value: templateValue
15712
+ })).digest("hex");
15713
+ return `${FINGERPRINT_PREFIX}${digest}`;
15714
+ }
15715
+ function maskedPropertyFingerprintsFor(recordedProperties, templateProps) {
15716
+ const entries = [];
15717
+ for (const key of Object.keys(recordedProperties)) {
15718
+ if (!Object.hasOwn(templateProps, key)) continue;
15719
+ if (!carriesSecretMask(recordedProperties[key])) continue;
15720
+ entries.push([key, maskedPropertyFingerprint(templateProps[key])]);
15721
+ }
15722
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
15723
+ }
15724
+ function maskedPropertyFingerprintsOf(record) {
15725
+ const read = /* @__PURE__ */ new Map();
15726
+ if (record === null || typeof record !== "object") return read;
15727
+ const field = record.maskedPropertyFingerprints;
15728
+ if (field === null || typeof field !== "object" || Array.isArray(field)) return read;
15729
+ for (const [key, value] of Object.entries(field)) if (typeof value === "string" && value.startsWith(FINGERPRINT_PREFIX)) read.set(key, value);
15730
+ return read;
15731
+ }
15732
+ function movedMaskedProperties(record, templateProps) {
15733
+ const recorded = maskedPropertyFingerprintsOf(record);
15734
+ if (recorded.size === 0) return [];
15735
+ const properties = record.properties;
15736
+ if (properties === null || typeof properties !== "object") return [];
15737
+ const moved = [];
15738
+ for (const [key, fingerprint] of recorded) {
15739
+ if (!Object.hasOwn(templateProps, key) || !Object.hasOwn(properties, key)) continue;
15740
+ if (!carriesSecretMask(properties[key])) continue;
15741
+ if (maskedPropertyFingerprint(templateProps[key]) !== fingerprint) moved.push(key);
15742
+ }
15743
+ return moved;
15744
+ }
15745
+ const writtenFromDeployedTemplate = /* @__PURE__ */ new WeakSet();
15746
+ function markWrittenFromDeployedTemplate(bag) {
15747
+ writtenFromDeployedTemplate.add(bag);
15748
+ return bag;
15749
+ }
15750
+ function withMaskedPropertyFingerprints(scrubbed, writtenBag, templateProps, secrets, noEchoParameterValues) {
15751
+ if (templateProps === void 0) return scrubbed;
15752
+ const corpora = [secrets, noEchoParameterValues].filter((corpus) => corpus !== void 0);
15753
+ const written = writtenBag !== null && typeof writtenBag === "object" && writtenFromDeployedTemplate.has(writtenBag);
15754
+ const { maskedPropertyFingerprints: previous, ...rest } = scrubbed;
15755
+ let fingerprints;
15756
+ if (written) fingerprints = maskedPropertyFingerprintsFor(scrubbed.properties, templateProps);
15757
+ else {
15758
+ if (previous === void 0 || previous === null || typeof previous !== "object") return scrubbed;
15759
+ if (corpora.length === 0) return scrubbed;
15760
+ fingerprints = { ...previous };
15761
+ }
15762
+ if (fingerprints !== void 0 && corpora.length > 0) {
15763
+ const refused = Object.keys(fingerprints).filter((key) => Object.hasOwn(templateProps, key) && corpora.some((corpus) => templateCarriesNeedle(templateProps[key], corpus)));
15764
+ if (refused.length > 0) fingerprints = Object.fromEntries(Object.entries(fingerprints).map(([key, value]) => [key, refused.includes(key) ? REFUSED_FINGERPRINT : value]));
15765
+ }
15766
+ if (!written && JSON.stringify(fingerprints) === JSON.stringify(previous)) return scrubbed;
15767
+ return fingerprints === void 0 ? rest : {
15768
+ ...rest,
15769
+ maskedPropertyFingerprints: fingerprints
15770
+ };
15771
+ }
15772
+ function backfillMaskedPropertyFingerprints(resources, template, noEchoParameterValues) {
15773
+ const declared = template?.Resources;
15774
+ if (declared === void 0 || declared === null) return 0;
15775
+ let stamped = 0;
15776
+ for (const [logicalId, record] of Object.entries(resources)) {
15777
+ if (record === null || typeof record !== "object") continue;
15778
+ const field = record.maskedPropertyFingerprints;
15779
+ if (field !== void 0 && (field === null || typeof field !== "object" || Array.isArray(field))) continue;
15780
+ const existing = field ?? {};
15781
+ if (!Object.hasOwn(declared, logicalId)) continue;
15782
+ const definition = declared[logicalId];
15783
+ if (definition === void 0 || definition.Type !== record.resourceType) continue;
15784
+ const properties = record.properties;
15785
+ if (properties === null || typeof properties !== "object" || Array.isArray(properties)) continue;
15786
+ const fingerprints = maskedPropertyFingerprintsFor(properties, definition.Properties ?? {});
15787
+ if (fingerprints === void 0) continue;
15788
+ const templateProps = definition.Properties ?? {};
15789
+ const added = Object.entries(fingerprints).filter(([key]) => !Object.hasOwn(existing, key)).map(([key, value]) => noEchoParameterValues !== void 0 && templateCarriesNeedle(templateProps[key], noEchoParameterValues) ? [key, REFUSED_FINGERPRINT] : [key, value]);
15790
+ if (added.length === 0) continue;
15791
+ resources[logicalId] = {
15792
+ ...record,
15793
+ maskedPropertyFingerprints: Object.fromEntries([...Object.entries(existing), ...added])
15794
+ };
15795
+ stamped++;
15796
+ }
15797
+ return stamped;
15798
+ }
15799
+
15648
15800
  //#endregion
15649
15801
  //#region src/deployment/drain-budget.ts
15650
15802
  const drainDeadlines = new AsyncLocalStorage();
@@ -15975,12 +16127,6 @@ function isDeliberateResolutionRefusal(err) {
15975
16127
  }
15976
16128
  const cachedAccountIdentities = /* @__PURE__ */ new Map();
15977
16129
  const cachedAvailabilityZones = /* @__PURE__ */ new Map();
15978
- const recordedSecretExpressions = {
15979
- has: (expression) => isRecordedSecretExpression(expression),
15980
- add: (expression) => recordSecretExpression(expression),
15981
- delete: (expression) => forgetSecretExpression(expression),
15982
- clear: () => clearRecordedSecretExpressions()
15983
- };
15984
16130
  const cachedEc2InstanceAttributes = Object.create(null);
15985
16131
  const cachedVpcDefaultSecurityGroups = Object.create(null);
15986
16132
  const cachedCloudFrontDomainNames = Object.create(null);
@@ -17109,10 +17255,9 @@ async function reresolveCrossStackValue(value, producerRegion, context, origin,
17109
17255
  if (sourceKey !== void 0 && typeof value === "string" && isSingleDynamicReferenceToken(value) && typeof reresolved === "string" && context.recordedSecretValues?.has(reresolved) === true && isSecretExpressionByVerdictOrSpelling(value)) recordCrossStackExpression(context.recordedSecretValues, sourceKey, value, reresolved);
17110
17256
  return reresolved;
17111
17257
  }
17112
- function pinSecretVerdict(expression, secret) {
17258
+ function pinSecretVerdict(expression, secret, scope) {
17113
17259
  if (this.producerRegionGuest) return;
17114
- if (secret) recordedSecretExpressions.add(expression);
17115
- else recordedSecretExpressions.delete(expression);
17260
+ pinScopedSecretVerdict(scope, expression, secret);
17116
17261
  }
17117
17262
  async function resolveImportValue(importValueArg, context) {
17118
17263
  const sourceKey = crossStackSourceKey({ "Fn::ImportValue": importValueArg });
@@ -17725,6 +17870,9 @@ function classifyReplaySecretRegion(expression, consumerRegion, importedProducer
17725
17870
 
17726
17871
  //#endregion
17727
17872
  //#region src/deployment/intrinsic-resolver/dynamic-refs.ts
17873
+ function secretVerdictScope(resolver) {
17874
+ return injectiveKey(credentialFingerprint(ambientCredentialConfig()), canonicalizeRegion(resolver.explicitRegion) ?? "");
17875
+ }
17728
17876
  async function resolveDynamicReferences(value, context) {
17729
17877
  return (await this.resolveDynamicReferencesWithLogTwin(value, value, context, void 0, true)).result;
17730
17878
  }
@@ -17751,7 +17899,8 @@ async function resolveDynamicReferencesWithLogTwin(value, logTwin, context, inhe
17751
17899
  const tokenLogText = inherited?.tokenLogText ?? (pairedTwin === void 0 ? "***" : this.straddleSafeTwin(fullMatch, pairedTwin, context));
17752
17900
  const nameLogText = inherited?.nameLogText ?? (pairedTwin === void 0 ? () => "***" : this.dynamicReferenceNameLogText(inner, pairedTwin, context));
17753
17901
  try {
17754
- const isKnownSecret = service === "secretsmanager" || service === "ssm-secure" || recordedSecretExpressions.has(fullMatch);
17902
+ const verdictScope = secretVerdictScope(this);
17903
+ const isKnownSecret = service === "secretsmanager" || service === "ssm-secure" || isScopedSecretVerdict(verdictScope, fullMatch);
17755
17904
  if (isKnownSecret && context?.skipDynamicReferences) {
17756
17905
  complete = false;
17757
17906
  continue;
@@ -17804,8 +17953,8 @@ async function resolveDynamicReferencesWithLogTwin(value, logTwin, context, inhe
17804
17953
  const param = await this.resolveSSMReference(parts, decrypt, "ssm", context, nameLogText);
17805
17954
  if (param.type === "SecureString") {
17806
17955
  if (decrypt) pinSecureVerdict = true;
17807
- else if (persistedText || !this.tokenAssembledForRecording(fullMatch, tokenLogText, context)) this.pinSecretVerdict(fullMatch, true);
17808
- } else if (!param.secure) this.pinSecretVerdict(fullMatch, false);
17956
+ else if (persistedText || !this.tokenAssembledForRecording(fullMatch, tokenLogText, context)) this.pinSecretVerdict(fullMatch, true, verdictScope);
17957
+ } else if (!param.secure) this.pinSecretVerdict(fullMatch, false, verdictScope);
17809
17958
  else cacheable = false;
17810
17959
  isSecret = param.secure;
17811
17960
  if (param.secure) {
@@ -17827,7 +17976,7 @@ async function resolveDynamicReferencesWithLogTwin(value, logTwin, context, inhe
17827
17976
  continue;
17828
17977
  }
17829
17978
  if (isSecret && resolved && !persistedText) this.refuseSecretAssembledReference(fullMatch, tokenLogText, context);
17830
- if (pinSecureVerdict) this.pinSecretVerdict(fullMatch, true);
17979
+ if (pinSecureVerdict) this.pinSecretVerdict(fullMatch, true, verdictScope);
17831
17980
  if (cacheable) this.cachedDynamicReferences.set(dynamicReferenceCacheKey, {
17832
17981
  value: resolved,
17833
17982
  secret: isSecret
@@ -17838,7 +17987,7 @@ async function resolveDynamicReferencesWithLogTwin(value, logTwin, context, inhe
17838
17987
  recorded.set(resolved, fullMatch);
17839
17988
  recordResolvedPair(recorded, fullMatch, resolved);
17840
17989
  }
17841
- if (service === "secretsmanager" || service === "ssm-secure") this.pinSecretVerdict(fullMatch, true);
17990
+ if (service === "secretsmanager" || service === "ssm-secure") this.pinSecretVerdict(fullMatch, true, verdictScope);
17842
17991
  }
17843
17992
  result = result.replace(fullMatch, () => resolved);
17844
17993
  twin = twin.replace(fullMatch, () => isSecret && resolved ? "***" : resolved);
@@ -17977,11 +18126,20 @@ function partParameterSpans(context, part, resolved) {
17977
18126
  if (own === void 0 || own.output !== resolved) return [];
17978
18127
  return own.parameterSpans ?? [];
17979
18128
  }
18129
+ function wholeReferenceSpans(source, value) {
18130
+ if (typeof value !== "string" || value === "") return [];
18131
+ const key = crossStackSourceKey(source);
18132
+ return key === void 0 ? [] : [{
18133
+ start: 0,
18134
+ length: value.length,
18135
+ key
18136
+ }];
18137
+ }
17980
18138
  function appendShiftedSpans(out, spans, by) {
17981
18139
  for (const span of spans) out.push({
17982
18140
  start: span.start + by,
17983
18141
  length: span.length,
17984
- parameter: span.parameter
18142
+ key: span.key
17985
18143
  });
17986
18144
  }
17987
18145
  async function resolveJoin(joinArgs, context, source) {
@@ -18276,11 +18434,7 @@ async function resolveSub(subArgs, context, source) {
18276
18434
  listRefusal ??= refusal;
18277
18435
  replacement = refusal ? match[0] : String(value);
18278
18436
  if (!refusal) twinReplacement = this.productLogTwin(value, context);
18279
- if (!refusal && fromParameter && typeof value === "string" && value !== "") parameterSpans = [{
18280
- start: 0,
18281
- length: value.length,
18282
- parameter: varNameStr
18283
- }];
18437
+ if (!refusal && fromParameter) parameterSpans = wholeReferenceSpans({ Ref: varNameStr }, value);
18284
18438
  } catch (refError) {
18285
18439
  if (refError instanceof IntrinsicResolutionRefusalError) throw refError;
18286
18440
  if (varNameStr.includes(".")) try {
@@ -18288,7 +18442,10 @@ async function resolveSub(subArgs, context, source) {
18288
18442
  const refusal = this.subListRefusal(`the variable \${${varNameStr}}`, value, context);
18289
18443
  listRefusal ??= refusal;
18290
18444
  replacement = refusal ? match[0] : String(value);
18291
- if (!refusal) twinReplacement = this.productLogTwin(value, context);
18445
+ if (!refusal) {
18446
+ twinReplacement = this.productLogTwin(value, context);
18447
+ parameterSpans = wholeReferenceSpans({ "Fn::GetAtt": varNameStr }, value);
18448
+ }
18292
18449
  } catch (getAttError) {
18293
18450
  if (getAttError instanceof IntrinsicResolutionRefusalError) throw getAttError;
18294
18451
  this.rethrowStructuralSubFailure(varNameStr, getAttError, context);
@@ -19118,6 +19275,16 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
19118
19275
  const parts = pending === 1 ? "1 concurrent part was" : `${pending} concurrent parts were`;
19119
19276
  this.logger.warn(`A resolution failed while ${parts} still running, and cdkd stopped waiting because the wait after a failure (capped at ${capSeconds}s) was used up. A secret such a part resolves from now on is still recorded, but only what runs after it arrives can mask it: output already printed or saved is not revisited.`);
19120
19277
  }
19278
+ recordCrossStackReadSpan(context, source, value) {
19279
+ if (typeof value === "string") this.recordLeafResolution(context, source, {
19280
+ input: value,
19281
+ output: value,
19282
+ substitutions: [],
19283
+ complete: true,
19284
+ parameterSpans: wholeReferenceSpans(source, value)
19285
+ });
19286
+ return value;
19287
+ }
19121
19288
  async resolveValue(value, context) {
19122
19289
  if (typeof value !== "object" || value === null) {
19123
19290
  if (typeof value === "string" && value.includes("{{resolve:")) return await this.resolveTemplateLeafReferences(value, context);
@@ -19136,15 +19303,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
19136
19303
  output: value,
19137
19304
  substitutions: [],
19138
19305
  complete: true,
19139
- parameterSpans: value === "" ? [] : [{
19140
- start: 0,
19141
- length: value.length,
19142
- parameter: logicalId
19143
- }]
19306
+ parameterSpans: wholeReferenceSpans({ Ref: logicalId }, value)
19144
19307
  });
19145
19308
  return value;
19146
19309
  }
19147
- if ("Fn::GetAtt" in obj) return await this.resolveGetAtt(obj["Fn::GetAtt"], context);
19310
+ if ("Fn::GetAtt" in obj) return this.recordCrossStackReadSpan(context, obj, await this.resolveGetAtt(obj["Fn::GetAtt"], context));
19148
19311
  if ("Fn::Join" in obj) return await this.resolveJoin(obj["Fn::Join"], context, obj);
19149
19312
  if ("Fn::Sub" in obj) return await this.resolveSub(obj["Fn::Sub"], context, obj);
19150
19313
  if ("Fn::Select" in obj) return await this.resolveSelect(obj["Fn::Select"], context);
@@ -19155,8 +19318,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
19155
19318
  if ("Fn::And" in obj) return await this.resolveAnd(obj["Fn::And"], context);
19156
19319
  if ("Fn::Or" in obj) return await this.resolveOr(obj["Fn::Or"], context);
19157
19320
  if ("Fn::Not" in obj) return await this.resolveNot(obj["Fn::Not"], context);
19158
- if ("Fn::ImportValue" in obj) return await this.resolveImportValue(obj["Fn::ImportValue"], context);
19159
- if ("Fn::GetStackOutput" in obj) return await this.resolveGetStackOutput(obj["Fn::GetStackOutput"], context);
19321
+ if ("Fn::ImportValue" in obj) return this.recordCrossStackReadSpan(context, obj, await this.resolveImportValue(obj["Fn::ImportValue"], context));
19322
+ if ("Fn::GetStackOutput" in obj) return this.recordCrossStackReadSpan(context, obj, await this.resolveGetStackOutput(obj["Fn::GetStackOutput"], context));
19160
19323
  if ("Fn::FindInMap" in obj) return await this.resolveFindInMap(obj["Fn::FindInMap"], context);
19161
19324
  if ("Fn::Base64" in obj) return await this.resolveBase64(obj["Fn::Base64"], context);
19162
19325
  if ("Fn::GetAZs" in obj) return await this.resolveGetAZs(obj["Fn::GetAZs"], context);
@@ -19417,13 +19580,29 @@ var DiffCalculator = class DiffCalculator {
19417
19580
  const resolvedDesiredProps = resolveFn ? await this.resolveBestEffort(rawDesiredProps, resolveFn) : rawDesiredProps;
19418
19581
  const sdkRouted = currentResource.provisionedBy !== "cc-api";
19419
19582
  const desiredAfterDrops = sdkRouted && allowedUnsupportedProperties ? withoutAcceptedSilentDropProperties(desiredResource.Type, resolvedDesiredProps, allowedUnsupportedProperties, currentResource.properties) : resolvedDesiredProps;
19420
- const currentAfterDrops = sdkRouted ? withoutSilentDropProperties(desiredResource.Type, currentResource.properties) : currentResource.properties;
19583
+ const currentAfterDrops = sdkRouted ? withoutUnwrittenSilentDropProperties(desiredResource.Type, currentResource.properties, resolvedDesiredProps, allowedUnsupportedProperties ?? /* @__PURE__ */ new Set(), acceptedCreateOnlyDropsOf(currentResource)) : currentResource.properties;
19421
19584
  const desiredPropsForCompare = canonicalizeProperties ? canonicalizeProperties(desiredResource.Type, desiredAfterDrops) : desiredAfterDrops;
19422
19585
  const currentPropsForCompare = canonicalizeProperties && sdkRouted ? canonicalizeProperties(desiredResource.Type, currentAfterDrops) : currentAfterDrops;
19423
19586
  const droppedKeys = canonicalizeProperties ? Object.keys(desiredAfterDrops).filter((key) => !Object.hasOwn(desiredPropsForCompare, key)) : [];
19424
19587
  if (droppedKeys.length > 0) this.logger.warn(`${logicalId} (${desiredResource.Type}): part of the declared properties cannot be sent as declared and is ignored when comparing against deployed state — the provider narrows them (${droppedKeys.join(", ")}). Fix the template to declare only what the resource supports; until then changes to the ignored keys have no effect.`);
19425
19588
  else if (canonicalizeProperties && !this.valuesEqual(desiredPropsForCompare, desiredAfterDrops)) this.logger.debug(`${logicalId} (${desiredResource.Type}): the provider normalizes part of the declared properties before sending them; the comparison uses the normalized form. Nothing is dropped.`);
19426
19589
  const propertyChanges = await this.compareProperties(desiredResource.Type, currentPropsForCompare, desiredPropsForCompare, maskForLog);
19590
+ const reported = new Set(propertyChanges.map((pc) => pc.path));
19591
+ for (const key of movedMaskedProperties(currentResource, rawDesiredProps)) {
19592
+ if (reported.has(key)) continue;
19593
+ if (!Object.hasOwn(currentPropsForCompare, key)) continue;
19594
+ if (!Object.hasOwn(desiredPropsForCompare, key)) continue;
19595
+ const oldValue = currentPropsForCompare[key];
19596
+ const newValue = desiredPropsForCompare[key];
19597
+ propertyChanges.push({
19598
+ path: key,
19599
+ oldValue,
19600
+ newValue,
19601
+ requiresReplacement: await this.maskedEditRequiresReplacement(desiredResource.Type, key, oldValue, newValue),
19602
+ maskedExpressionChanged: true
19603
+ });
19604
+ this.logger.debug(safeMsg`${logicalId}: ${key} is recorded masked and its template expression changed (go-to-k/cdkd#4451)`);
19605
+ }
19427
19606
  const attributeChanges = this.compareAttributes(currentResource, desiredResource);
19428
19607
  if (propertyChanges.length > 0 || attributeChanges.length > 0) {
19429
19608
  changes.set(logicalId, {
@@ -19790,6 +19969,11 @@ var DiffCalculator = class DiffCalculator {
19790
19969
  }
19791
19970
  return changes;
19792
19971
  }
19972
+ async maskedEditRequiresReplacement(resourceType, key, oldValue, newValue) {
19973
+ if (this.replacementRules.requiresReplacement(resourceType, key, oldValue, newValue)) return true;
19974
+ if (this.replacementRules.isClassified(resourceType, key)) return false;
19975
+ return (await getCreateOnlyPropertyPaths(resourceType)).some((path) => path.length === 1 && path[0] === key);
19976
+ }
19793
19977
  static INTRINSIC_KEYS = INTRINSIC_KEYS;
19794
19978
  static isIntrinsic(value) {
19795
19979
  if (value === null || value === void 0 || typeof value !== "object" || Array.isArray(value)) return false;
@@ -20649,7 +20833,8 @@ var CloudControlProvider = class {
20649
20833
  }
20650
20834
  }
20651
20835
  async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
20652
- this.logger.debug(`Updating resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
20836
+ const idLog = updateIdLogSink(this.logger, physicalId, properties, previousProperties, context?.maskSecrets);
20837
+ idLog.debug(`Updating resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
20653
20838
  await this.assertRecordedRegionAgainstClient("pre-update", context?.expectedRegion, resourceType, logicalId, physicalId);
20654
20839
  try {
20655
20840
  const cleanPreviousProperties = stringifyJsonProperties(resourceType, stripNullValues(previousProperties));
@@ -20714,9 +20899,9 @@ var CloudControlProvider = class {
20714
20899
  physicalId,
20715
20900
  wasReplaced: false
20716
20901
  };
20717
- if (progressEvent.ResourceModel) result.attributes = this.parseResourceModel(progressEvent.ResourceModel);
20718
- result.attributes = await this.mergeSparseModelReadback(resourceType, physicalId, result.attributes || {});
20719
- result.attributes = await this.enrichResourceAttributes(resourceType, physicalId, result.attributes);
20902
+ if (progressEvent.ResourceModel) result.attributes = this.parseResourceModel(progressEvent.ResourceModel, idLog);
20903
+ result.attributes = await this.mergeSparseModelReadback(resourceType, physicalId, result.attributes || {}, idLog);
20904
+ result.attributes = await this.enrichResourceAttributes(resourceType, physicalId, result.attributes, idLog);
20720
20905
  return result;
20721
20906
  } catch (error) {
20722
20907
  this.handleError(error, "UPDATE", resourceType, logicalId, physicalId);
@@ -20729,7 +20914,7 @@ var CloudControlProvider = class {
20729
20914
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
20730
20915
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
20731
20916
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
20732
- const { ASGProvider } = await import("./asg-provider-CsajFK4_.js");
20917
+ const { ASGProvider } = await import("./asg-provider-BFlmarbF.js");
20733
20918
  const delegateRegion = ambientRegion();
20734
20919
  let asgProvider = this.asgDeleteDelegates.get(delegateRegion);
20735
20920
  if (asgProvider === void 0) {
@@ -20835,7 +21020,7 @@ var CloudControlProvider = class {
20835
21020
  const family = SDK_DELETE_FAMILIES.get(resourceType);
20836
21021
  const cached = this.sdkDeleteDelegates.get(family);
20837
21022
  if (cached !== void 0 && cached.region === ccRegion) return cached.provider;
20838
- const provider = family === "rds" ? new (await (import("./rds-provider-a-vZsR9L.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-DlFQdgwe.js"))).NeptuneProvider({ region: ccRegion });
21023
+ const provider = family === "rds" ? new (await (import("./rds-provider-DqHELwjV.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-CHnIs1hG.js"))).NeptuneProvider({ region: ccRegion });
20839
21024
  this.sdkDeleteDelegates.set(family, {
20840
21025
  region: ccRegion,
20841
21026
  provider
@@ -21080,34 +21265,34 @@ var CloudControlProvider = class {
21080
21265
  const regionFlag = safeRegion === void 0 ? "" : ` --region ${shellQuote(safeRegion)}`;
21081
21266
  return `${withPasteableAwsProfile("aws cloudcontrol get-resource-request-status")} --request-token ${shellQuote(safeToken)}${regionFlag}`;
21082
21267
  }
21083
- parseResourceModel(resourceModel) {
21268
+ parseResourceModel(resourceModel, log = this.logger) {
21084
21269
  try {
21085
21270
  return JSON.parse(resourceModel);
21086
21271
  } catch (error) {
21087
21272
  const described = describeAwsFailure(error);
21088
- this.logger.warn(`Failed to parse resource model: ${described.redacted ? described.summary : error instanceof Error ? error.name : "Error"}\nModel shape: ${resourceModel.length} chars, ${describeJsonKeys(resourceModel)}`);
21089
- this.logger.debug(`Resource model parse failure detail: ${displaySafe(described.detail)}`);
21273
+ log.warn(`Failed to parse resource model: ${described.redacted ? described.summary : error instanceof Error ? error.name : "Error"}\nModel shape: ${resourceModel.length} chars, ${describeJsonKeys(resourceModel)}`);
21274
+ if (log.withheld !== true) log.debug(`Resource model parse failure detail: ${displaySafe(described.detail)}`);
21090
21275
  return {};
21091
21276
  }
21092
21277
  }
21093
- async accountInfoForSynthesizedArn(resourceType, attributeName, physicalId) {
21278
+ async accountInfoForSynthesizedArn(resourceType, attributeName, physicalId, log = this.logger) {
21094
21279
  const region = await this.cloudControlClient.config.region();
21095
21280
  try {
21096
21281
  return await getAccountInfo(region);
21097
21282
  } catch (error) {
21098
21283
  if (!(error instanceof AccountIdUnavailableError)) throw error;
21099
- this.logger.warn(`Not enriching ${resourceType} ${attributeName} for ${physicalId}: ${error.message} The resource itself is unaffected; the record heals on its next update.`);
21284
+ log.warn(`Not enriching ${resourceType} ${attributeName} for ${physicalId}: ${error.message} The resource itself is unaffected; the record heals on its next update.`);
21100
21285
  return;
21101
21286
  }
21102
21287
  }
21103
- async enrichResourceAttributes(resourceType, physicalId, attributes) {
21288
+ async enrichResourceAttributes(resourceType, physicalId, attributes, log = this.logger) {
21104
21289
  const enriched = { ...attributes };
21105
21290
  switch (resourceType) {
21106
21291
  case "AWS::S3::Bucket":
21107
21292
  if (!enriched["Arn"]) try {
21108
21293
  enriched["Arn"] = s3BucketArn(physicalId, await this.cloudControlClient.config.region());
21109
21294
  } catch (error) {
21110
- this.logger.debug(`Failed to construct S3 Bucket Arn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21295
+ log.debug(`Failed to construct S3 Bucket Arn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21111
21296
  }
21112
21297
  break;
21113
21298
  case "AWS::RDS::DBCluster":
@@ -21119,10 +21304,10 @@ var CloudControlProvider = class {
21119
21304
  if (cluster.ReaderEndpoint) enriched["ReadEndpoint.Address"] = cluster.ReaderEndpoint;
21120
21305
  if (cluster.DBClusterArn) enriched["Arn"] = cluster.DBClusterArn;
21121
21306
  if (cluster.DbClusterResourceId) enriched["DBClusterResourceId"] = cluster.DbClusterResourceId;
21122
- this.logger.debug(`Enriched RDS DBCluster ${physicalId} with Endpoint/Port/Arn from DescribeDBClusters`);
21307
+ log.debug(`Enriched RDS DBCluster ${physicalId} with Endpoint/Port/Arn from DescribeDBClusters`);
21123
21308
  }
21124
21309
  } catch (error) {
21125
- this.logger.debug(`Failed to enrich RDS DBCluster ${physicalId}: ${describeAwsFailure(error).detail}`);
21310
+ log.debug(`Failed to enrich RDS DBCluster ${physicalId}: ${describeAwsFailure(error).detail}`);
21126
21311
  }
21127
21312
  break;
21128
21313
  case "AWS::RDS::DBInstance":
@@ -21133,10 +21318,10 @@ var CloudControlProvider = class {
21133
21318
  if (inst.Endpoint?.Port !== void 0) enriched["Endpoint.Port"] = String(inst.Endpoint.Port);
21134
21319
  if (inst.Endpoint?.HostedZoneId) enriched["Endpoint.HostedZoneId"] = inst.Endpoint.HostedZoneId;
21135
21320
  if (inst.DBInstanceArn) enriched["Arn"] = inst.DBInstanceArn;
21136
- this.logger.debug(`Enriched RDS DBInstance ${physicalId} with Endpoint/Port/Arn from DescribeDBInstances`);
21321
+ log.debug(`Enriched RDS DBInstance ${physicalId} with Endpoint/Port/Arn from DescribeDBInstances`);
21137
21322
  }
21138
21323
  } catch (error) {
21139
- this.logger.debug(`Failed to enrich RDS DBInstance ${physicalId}: ${describeAwsFailure(error).detail}`);
21324
+ log.debug(`Failed to enrich RDS DBInstance ${physicalId}: ${describeAwsFailure(error).detail}`);
21140
21325
  }
21141
21326
  break;
21142
21327
  case "AWS::DynamoDB::Table":
@@ -21144,10 +21329,10 @@ var CloudControlProvider = class {
21144
21329
  const latestStreamArn = (await getAwsClients().dynamoDB.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.LatestStreamArn;
21145
21330
  if (latestStreamArn) {
21146
21331
  enriched["StreamArn"] = latestStreamArn;
21147
- this.logger.debug(`Enriched DynamoDB StreamArn for ${physicalId}: ${latestStreamArn}`);
21332
+ log.debug(`Enriched DynamoDB StreamArn for ${physicalId}: ${latestStreamArn}`);
21148
21333
  }
21149
21334
  } catch (error) {
21150
- this.logger.debug(`Failed to get DynamoDB StreamArn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21335
+ log.debug(`Failed to get DynamoDB StreamArn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21151
21336
  }
21152
21337
  break;
21153
21338
  case "AWS::ApiGateway::RestApi":
@@ -21155,10 +21340,10 @@ var CloudControlProvider = class {
21155
21340
  const getRestApiResponse = await getAwsClients().apiGateway.send(new GetRestApiCommand({ restApiId: physicalId }));
21156
21341
  if (getRestApiResponse.rootResourceId) {
21157
21342
  enriched["RootResourceId"] = getRestApiResponse.rootResourceId;
21158
- this.logger.debug(`Enriched RestApi RootResourceId for ${physicalId}: ${getRestApiResponse.rootResourceId}`);
21343
+ log.debug(`Enriched RestApi RootResourceId for ${physicalId}: ${getRestApiResponse.rootResourceId}`);
21159
21344
  }
21160
21345
  } catch (error) {
21161
- this.logger.debug(`Failed to get RestApi RootResourceId for ${physicalId}: ${describeAwsFailure(error).detail}`);
21346
+ log.debug(`Failed to get RestApi RootResourceId for ${physicalId}: ${describeAwsFailure(error).detail}`);
21162
21347
  }
21163
21348
  if (!enriched["RestApiId"]) enriched["RestApiId"] = physicalId;
21164
21349
  break;
@@ -21167,21 +21352,21 @@ var CloudControlProvider = class {
21167
21352
  const s3CanonicalUserId = (await getAwsClients().cloudFront.send(new GetCloudFrontOriginAccessIdentityCommand({ Id: physicalId }))).CloudFrontOriginAccessIdentity?.S3CanonicalUserId;
21168
21353
  if (s3CanonicalUserId) {
21169
21354
  enriched["S3CanonicalUserId"] = s3CanonicalUserId;
21170
- this.logger.debug(`Enriched CloudFront OAI S3CanonicalUserId for ${physicalId}: ${s3CanonicalUserId}`);
21355
+ log.debug(`Enriched CloudFront OAI S3CanonicalUserId for ${physicalId}: ${s3CanonicalUserId}`);
21171
21356
  }
21172
21357
  } catch (error) {
21173
- this.logger.debug(`Failed to get CloudFront OAI S3CanonicalUserId for ${physicalId}: ${describeAwsFailure(error).detail}`);
21358
+ log.debug(`Failed to get CloudFront OAI S3CanonicalUserId for ${physicalId}: ${describeAwsFailure(error).detail}`);
21174
21359
  }
21175
21360
  break;
21176
21361
  case "AWS::KMS::Key":
21177
21362
  if (!enriched["Arn"]) try {
21178
- const kmsAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "Arn", physicalId);
21363
+ const kmsAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "Arn", physicalId, log);
21179
21364
  if (kmsAccountInfo) {
21180
21365
  enriched["Arn"] = `arn:${kmsAccountInfo.partition}:kms:${canonicalizeRegion(kmsAccountInfo.region)}:${kmsAccountInfo.accountId}:key/${physicalId}`;
21181
- this.logger.debug(`Enriched KMS Key Arn for ${physicalId}: ${String(enriched["Arn"])}`);
21366
+ log.debug(`Enriched KMS Key Arn for ${physicalId}: ${String(enriched["Arn"])}`);
21182
21367
  }
21183
21368
  } catch (error) {
21184
- this.logger.debug(`Failed to construct KMS Key Arn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21369
+ log.debug(`Failed to construct KMS Key Arn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21185
21370
  }
21186
21371
  if (!enriched["KeyId"]) enriched["KeyId"] = physicalId;
21187
21372
  break;
@@ -21193,16 +21378,16 @@ var CloudControlProvider = class {
21193
21378
  break;
21194
21379
  case "AWS::ECR::Repository":
21195
21380
  if (!enriched["Arn"]) try {
21196
- const ecrAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "Arn", physicalId);
21381
+ const ecrAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "Arn", physicalId, log);
21197
21382
  if (ecrAccountInfo) {
21198
21383
  enriched["Arn"] = `arn:${ecrAccountInfo.partition}:ecr:${canonicalizeRegion(ecrAccountInfo.region)}:${ecrAccountInfo.accountId}:repository/${physicalId}`;
21199
- this.logger.debug(`Enriched ECR Repository Arn for ${physicalId}: ${String(enriched["Arn"])}`);
21384
+ log.debug(`Enriched ECR Repository Arn for ${physicalId}: ${String(enriched["Arn"])}`);
21200
21385
  }
21201
21386
  } catch (error) {
21202
- this.logger.debug(`Failed to construct ECR Repository Arn: ${describeAwsFailure(error).detail}`);
21387
+ log.debug(`Failed to construct ECR Repository Arn: ${describeAwsFailure(error).detail}`);
21203
21388
  }
21204
21389
  if (!enriched["RepositoryUri"]) try {
21205
- const ecrAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "RepositoryUri", physicalId);
21390
+ const ecrAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "RepositoryUri", physicalId, log);
21206
21391
  if (ecrAccountInfo) {
21207
21392
  const { urlSuffix } = derivePartitionAndUrlSuffix(ecrAccountInfo.region);
21208
21393
  enriched["RepositoryUri"] = `${ecrAccountInfo.accountId}.dkr.ecr.${canonicalizeRegion(ecrAccountInfo.region)}.${urlSuffix}/${physicalId}`;
@@ -21214,7 +21399,7 @@ var CloudControlProvider = class {
21214
21399
  const [publicIp, allocationId] = physicalId.split("|");
21215
21400
  if (!enriched["AllocationId"]) enriched["AllocationId"] = allocationId;
21216
21401
  if (!enriched["PublicIp"]) enriched["PublicIp"] = publicIp;
21217
- this.logger.debug(`Enriched EIP attributes: AllocationId=${allocationId}, PublicIp=${publicIp}`);
21402
+ log.debug(`Enriched EIP attributes: AllocationId=${allocationId}, PublicIp=${publicIp}`);
21218
21403
  }
21219
21404
  break;
21220
21405
  case "AWS::Lambda::Version":
@@ -21222,18 +21407,18 @@ var CloudControlProvider = class {
21222
21407
  const versionSegments = physicalId.split(":");
21223
21408
  const versionNumber = versionSegments[versionSegments.length - 1];
21224
21409
  enriched["Version"] = versionNumber;
21225
- this.logger.debug(`Enriched Lambda Version for ${physicalId}: ${versionNumber}`);
21410
+ log.debug(`Enriched Lambda Version for ${physicalId}: ${versionNumber}`);
21226
21411
  }
21227
21412
  break;
21228
21413
  case "AWS::Kinesis::Stream":
21229
21414
  if (!enriched["Arn"]) try {
21230
- const kinesisAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "Arn", physicalId);
21415
+ const kinesisAccountInfo = await this.accountInfoForSynthesizedArn(resourceType, "Arn", physicalId, log);
21231
21416
  if (kinesisAccountInfo) {
21232
21417
  enriched["Arn"] = `arn:${kinesisAccountInfo.partition}:kinesis:${canonicalizeRegion(kinesisAccountInfo.region)}:${kinesisAccountInfo.accountId}:stream/${physicalId}`;
21233
- this.logger.debug(`Enriched Kinesis Stream Arn for ${physicalId}: ${String(enriched["Arn"])}`);
21418
+ log.debug(`Enriched Kinesis Stream Arn for ${physicalId}: ${String(enriched["Arn"])}`);
21234
21419
  }
21235
21420
  } catch (error) {
21236
- this.logger.debug(`Failed to construct Kinesis Stream Arn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21421
+ log.debug(`Failed to construct Kinesis Stream Arn for ${physicalId}: ${describeAwsFailure(error).detail}`);
21237
21422
  }
21238
21423
  break;
21239
21424
  case "AWS::Lambda::Url":
@@ -21241,11 +21426,11 @@ var CloudControlProvider = class {
21241
21426
  const urlConfig = await getAwsClients().lambda.send(new GetFunctionUrlConfigCommand({ FunctionName: physicalId }));
21242
21427
  if (urlConfig.FunctionUrl) {
21243
21428
  enriched["FunctionUrl"] = urlConfig.FunctionUrl;
21244
- this.logger.debug(`Enriched Lambda URL FunctionUrl for ${physicalId}: ${urlConfig.FunctionUrl}`);
21429
+ log.debug(`Enriched Lambda URL FunctionUrl for ${physicalId}: ${urlConfig.FunctionUrl}`);
21245
21430
  }
21246
21431
  if (urlConfig.FunctionArn) enriched["FunctionArn"] = urlConfig.FunctionArn;
21247
21432
  } catch (error) {
21248
- this.logger.debug(`Failed to get Lambda URL config for ${physicalId}: ${describeAwsFailure(error).detail}`);
21433
+ log.debug(`Failed to get Lambda URL config for ${physicalId}: ${describeAwsFailure(error).detail}`);
21249
21434
  }
21250
21435
  break;
21251
21436
  case "AWS::Events::Connection":
@@ -21259,9 +21444,9 @@ var CloudControlProvider = class {
21259
21444
  }
21260
21445
  }
21261
21446
  if (conn.SecretArn && !enriched["SecretArn"]) enriched["SecretArn"] = conn.SecretArn;
21262
- this.logger.debug(`Enriched Events Connection ${physicalId} with Arn/SecretArn/ArnForPolicy from DescribeConnection`);
21447
+ log.debug(`Enriched Events Connection ${physicalId} with Arn/SecretArn/ArnForPolicy from DescribeConnection`);
21263
21448
  } catch (error) {
21264
- this.logger.debug(`Failed to enrich Events Connection ${physicalId}: ${describeAwsFailure(error).detail}`);
21449
+ log.debug(`Failed to enrich Events Connection ${physicalId}: ${describeAwsFailure(error).detail}`);
21265
21450
  }
21266
21451
  break;
21267
21452
  case "AWS::Events::ApiDestination":
@@ -21274,9 +21459,9 @@ var CloudControlProvider = class {
21274
21459
  if (lastSlash > 0) enriched["ArnForPolicy"] = dest.ApiDestinationArn.slice(0, lastSlash);
21275
21460
  }
21276
21461
  }
21277
- this.logger.debug(`Enriched Events ApiDestination ${physicalId} with Arn/ArnForPolicy from DescribeApiDestination`);
21462
+ log.debug(`Enriched Events ApiDestination ${physicalId} with Arn/ArnForPolicy from DescribeApiDestination`);
21278
21463
  } catch (error) {
21279
- this.logger.debug(`Failed to enrich Events ApiDestination ${physicalId}: ${describeAwsFailure(error).detail}`);
21464
+ log.debug(`Failed to enrich Events ApiDestination ${physicalId}: ${describeAwsFailure(error).detail}`);
21280
21465
  }
21281
21466
  break;
21282
21467
  case "AWS::ElastiCache::ReplicationGroup":
@@ -21295,10 +21480,10 @@ var CloudControlProvider = class {
21295
21480
  const readPorts = readEndpoints.map((ep) => ep?.Port).filter((p) => p !== void 0);
21296
21481
  if (readAddrs.length > 0) enriched["ReadEndPoint.Addresses"] = readAddrs.join(",");
21297
21482
  if (readPorts.length > 0) enriched["ReadEndPoint.Ports"] = readPorts.map(String).join(",");
21298
- this.logger.debug(`Enriched ElastiCache ReplicationGroup ${physicalId} with endpoint attributes from DescribeReplicationGroups`);
21483
+ log.debug(`Enriched ElastiCache ReplicationGroup ${physicalId} with endpoint attributes from DescribeReplicationGroups`);
21299
21484
  }
21300
21485
  } catch (error) {
21301
- this.logger.debug(`Failed to enrich ElastiCache ReplicationGroup ${physicalId}: ${describeAwsFailure(error).detail}`);
21486
+ log.debug(`Failed to enrich ElastiCache ReplicationGroup ${physicalId}: ${describeAwsFailure(error).detail}`);
21302
21487
  }
21303
21488
  break;
21304
21489
  case "AWS::Redshift::Cluster":
@@ -21307,10 +21492,10 @@ var CloudControlProvider = class {
21307
21492
  if (cluster?.Endpoint) {
21308
21493
  if (cluster.Endpoint.Address) enriched["Endpoint.Address"] = cluster.Endpoint.Address;
21309
21494
  if (cluster.Endpoint.Port !== void 0) enriched["Endpoint.Port"] = String(cluster.Endpoint.Port);
21310
- this.logger.debug(`Enriched Redshift Cluster ${physicalId} with Endpoint.Address/Port from DescribeClusters`);
21495
+ log.debug(`Enriched Redshift Cluster ${physicalId} with Endpoint.Address/Port from DescribeClusters`);
21311
21496
  }
21312
21497
  } catch (error) {
21313
- this.logger.debug(`Failed to enrich Redshift Cluster ${physicalId}: ${describeAwsFailure(error).detail}`);
21498
+ log.debug(`Failed to enrich Redshift Cluster ${physicalId}: ${describeAwsFailure(error).detail}`);
21314
21499
  }
21315
21500
  break;
21316
21501
  case "AWS::OpenSearchService::Domain":
@@ -21324,31 +21509,31 @@ var CloudControlProvider = class {
21324
21509
  enriched["DomainArn"] = domain.ARN;
21325
21510
  }
21326
21511
  if (domain.DomainId) enriched["Id"] = domain.DomainId;
21327
- this.logger.debug(`Enriched OpenSearch Domain ${physicalId} with DomainEndpoint/Arn from DescribeDomain`);
21512
+ log.debug(`Enriched OpenSearch Domain ${physicalId} with DomainEndpoint/Arn from DescribeDomain`);
21328
21513
  }
21329
21514
  } catch (error) {
21330
- this.logger.debug(`Failed to enrich OpenSearch Domain ${physicalId}: ${describeAwsFailure(error).detail}`);
21515
+ log.debug(`Failed to enrich OpenSearch Domain ${physicalId}: ${describeAwsFailure(error).detail}`);
21331
21516
  }
21332
21517
  break;
21333
21518
  case "AWS::Backup::BackupVault":
21334
21519
  if (!enriched["BackupVaultArn"]) {
21335
- const model = await this.readCcResourceModel(resourceType, physicalId);
21520
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21336
21521
  if (model) {
21337
21522
  if (typeof model["BackupVaultArn"] === "string") enriched["BackupVaultArn"] = model["BackupVaultArn"];
21338
21523
  if (!enriched["BackupVaultName"] && typeof model["BackupVaultName"] === "string") enriched["BackupVaultName"] = model["BackupVaultName"];
21339
- this.logger.debug(`Enriched Backup BackupVault ${physicalId} with BackupVaultArn from CC GetResource`);
21524
+ log.debug(`Enriched Backup BackupVault ${physicalId} with BackupVaultArn from CC GetResource`);
21340
21525
  }
21341
21526
  }
21342
21527
  if (!enriched["BackupVaultName"]) enriched["BackupVaultName"] = physicalId;
21343
21528
  break;
21344
21529
  case "AWS::Backup::BackupPlan":
21345
21530
  if (!enriched["BackupPlanArn"] || !enriched["VersionId"]) {
21346
- const model = await this.readCcResourceModel(resourceType, physicalId);
21531
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21347
21532
  if (model) {
21348
21533
  if (!enriched["BackupPlanArn"] && typeof model["BackupPlanArn"] === "string") enriched["BackupPlanArn"] = model["BackupPlanArn"];
21349
21534
  if (!enriched["VersionId"] && typeof model["VersionId"] === "string") enriched["VersionId"] = model["VersionId"];
21350
21535
  if (!enriched["BackupPlanId"] && typeof model["BackupPlanId"] === "string") enriched["BackupPlanId"] = model["BackupPlanId"];
21351
- this.logger.debug(`Enriched Backup BackupPlan ${physicalId} with BackupPlanArn/VersionId from CC GetResource`);
21536
+ log.debug(`Enriched Backup BackupPlan ${physicalId} with BackupPlanArn/VersionId from CC GetResource`);
21352
21537
  }
21353
21538
  }
21354
21539
  if (!enriched["BackupPlanId"]) enriched["BackupPlanId"] = physicalId;
@@ -21360,53 +21545,53 @@ var CloudControlProvider = class {
21360
21545
  if (!enriched["SelectionId"]) enriched["SelectionId"] = physicalId.substring(0, firstUnderscore);
21361
21546
  if (!enriched["BackupPlanId"]) enriched["BackupPlanId"] = physicalId.substring(firstUnderscore + 1);
21362
21547
  }
21363
- const model = await this.readCcResourceModel(resourceType, physicalId);
21548
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21364
21549
  if (model) {
21365
21550
  if (typeof model["SelectionId"] === "string") enriched["SelectionId"] = model["SelectionId"];
21366
21551
  if (typeof model["BackupPlanId"] === "string") enriched["BackupPlanId"] = model["BackupPlanId"];
21367
- this.logger.debug(`Enriched Backup BackupSelection ${physicalId} with SelectionId from CC GetResource`);
21552
+ log.debug(`Enriched Backup BackupSelection ${physicalId} with SelectionId from CC GetResource`);
21368
21553
  }
21369
21554
  }
21370
21555
  break;
21371
21556
  case "AWS::Pipes::Pipe":
21372
21557
  if (!enriched["Arn"]) {
21373
- const model = await this.readCcResourceModel(resourceType, physicalId);
21558
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21374
21559
  if (model) {
21375
21560
  if (typeof model["Arn"] === "string") enriched["Arn"] = model["Arn"];
21376
21561
  if (!enriched["CurrentState"] && typeof model["CurrentState"] === "string") enriched["CurrentState"] = model["CurrentState"];
21377
21562
  if (!enriched["StateReason"] && typeof model["StateReason"] === "string") enriched["StateReason"] = model["StateReason"];
21378
21563
  if (!enriched["CreationTime"] && typeof model["CreationTime"] === "string") enriched["CreationTime"] = model["CreationTime"];
21379
21564
  if (!enriched["LastModifiedTime"] && typeof model["LastModifiedTime"] === "string") enriched["LastModifiedTime"] = model["LastModifiedTime"];
21380
- this.logger.debug(`Enriched Pipes Pipe ${physicalId} with Arn from CC GetResource`);
21565
+ log.debug(`Enriched Pipes Pipe ${physicalId} with Arn from CC GetResource`);
21381
21566
  }
21382
21567
  }
21383
21568
  break;
21384
21569
  case "AWS::S3::AccessPoint":
21385
21570
  if (!enriched["Arn"] || !enriched["Alias"]) {
21386
- const model = await this.readCcResourceModel(resourceType, physicalId);
21571
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21387
21572
  if (model) {
21388
21573
  if (!enriched["Arn"] && typeof model["Arn"] === "string") enriched["Arn"] = model["Arn"];
21389
21574
  if (!enriched["Alias"] && typeof model["Alias"] === "string") enriched["Alias"] = model["Alias"];
21390
21575
  if (!enriched["NetworkOrigin"] && typeof model["NetworkOrigin"] === "string") enriched["NetworkOrigin"] = model["NetworkOrigin"];
21391
- this.logger.debug(`Enriched S3 AccessPoint ${physicalId} with Arn/Alias from CC GetResource`);
21576
+ log.debug(`Enriched S3 AccessPoint ${physicalId} with Arn/Alias from CC GetResource`);
21392
21577
  }
21393
21578
  }
21394
21579
  break;
21395
21580
  case "AWS::ResourceGroups::Group": if (!enriched["Arn"]) {
21396
- const model = await this.readCcResourceModel(resourceType, physicalId);
21581
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21397
21582
  if (model) {
21398
21583
  if (typeof model["Arn"] === "string") enriched["Arn"] = model["Arn"];
21399
- this.logger.debug(`Enriched ResourceGroups Group ${physicalId} with Arn from CC GetResource`);
21584
+ log.debug(`Enriched ResourceGroups Group ${physicalId} with Arn from CC GetResource`);
21400
21585
  }
21401
21586
  }
21402
21587
  }
21403
21588
  return enriched;
21404
21589
  }
21405
- async mergeSparseModelReadback(resourceType, physicalId, attributes) {
21590
+ async mergeSparseModelReadback(resourceType, physicalId, attributes, log = this.logger) {
21406
21591
  if (!this.isSparseAttributeMap(attributes, physicalId)) return attributes;
21407
- const model = await this.readCcResourceModel(resourceType, physicalId);
21592
+ const model = await this.readCcResourceModel(resourceType, physicalId, log);
21408
21593
  if (!model) return attributes;
21409
- this.logger.debug(`Merged CC GetResource read-back over sparse ${resourceType} attributes for ${physicalId}`);
21594
+ log.debug(`Merged CC GetResource read-back over sparse ${resourceType} attributes for ${physicalId}`);
21410
21595
  return {
21411
21596
  ...attributes,
21412
21597
  ...model
@@ -21419,7 +21604,7 @@ var CloudControlProvider = class {
21419
21604
  identifierEchoes.add(physicalId);
21420
21605
  return values.every((value) => typeof value === "string" && identifierEchoes.has(value));
21421
21606
  }
21422
- async readCcResourceModel(resourceType, physicalId) {
21607
+ async readCcResourceModel(resourceType, physicalId, log = this.logger) {
21423
21608
  try {
21424
21609
  const raw = (await this.cloudControlClient.send(new GetResourceCommand({
21425
21610
  TypeName: resourceType,
@@ -21430,7 +21615,7 @@ var CloudControlProvider = class {
21430
21615
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
21431
21616
  return parsed;
21432
21617
  } catch (error) {
21433
- this.logger.debug(`Failed to read CC model for ${resourceType} ${physicalId}: ${describeAwsFailure(error).detail}`);
21618
+ log.debug(`Failed to read CC model for ${resourceType} ${physicalId}: ${describeAwsFailure(error).detail}`);
21434
21619
  return;
21435
21620
  }
21436
21621
  }
@@ -21538,6 +21723,28 @@ var CloudControlProvider = class {
21538
21723
  return masked;
21539
21724
  }
21540
21725
  };
21726
+ function updateIdLogSink(logger, physicalId, properties, previousProperties, maskSecrets) {
21727
+ const mask = maskerOrIdentity(maskSecrets);
21728
+ const raw = updateIdWithheld(properties, previousProperties, mask) ? [physicalId, ...physicalId.split("|")].filter((needle) => needle !== "") : [];
21729
+ const masked = raw.map((needle) => mask(needle));
21730
+ const needles = [.../* @__PURE__ */ new Set([...raw, ...masked.filter((m, i) => m !== "" && m !== raw[i] && m !== "***")])].sort((a, b) => b.length - a.length);
21731
+ const scrub = (message) => needles.reduce((text, needle) => text.split(needle).join("***"), mask(message));
21732
+ return {
21733
+ debug: (message) => logger.debug(scrub(message)),
21734
+ warn: (message) => logger.warn(scrub(message)),
21735
+ withheld: needles.length > 0
21736
+ };
21737
+ }
21738
+ function updateIdWithheld(properties, previousProperties, mask) {
21739
+ return holdsSecretDerivedLeaf(properties, mask) || holdsSecretDerivedLeaf(previousProperties, mask);
21740
+ }
21741
+ function holdsSecretDerivedLeaf(value, mask, depth = 0) {
21742
+ if (typeof value === "string") return isSecretDerivedValue(value, mask);
21743
+ if (value === null || typeof value !== "object") return false;
21744
+ if (depth > 64) return true;
21745
+ if (Array.isArray(value)) return value.some((entry) => holdsSecretDerivedLeaf(entry, mask, depth + 1));
21746
+ return Object.entries(value).some(([key, entry]) => isSecretDerivedValue(key, mask) || holdsSecretDerivedLeaf(entry, mask, depth + 1));
21747
+ }
21541
21748
  const IMPORT_YIELDED_NO_ATTRIBUTES_CONSEQUENCE = "Attributes the stack's state already records for this physical id are kept; without them, an Fn::GetAtt against this resource falls back to a value constructed from its physical id.";
21542
21749
  function maskLeavesDeep(value) {
21543
21750
  if (Array.isArray(value)) return value.map((element) => maskLeavesDeep(element));
@@ -24458,7 +24665,7 @@ var ProviderRegistry = class {
24458
24665
  if (reroutable.length > 0) remedies.push(`Remove the override for ${reroutable.join(", ")} to route this resource via Cloud Control API instead.`);
24459
24666
  if (needsRecreate.length > 0) {
24460
24667
  const one = needsRecreate.length === 1;
24461
- remedies.push(`${needsRecreate.join(", ")} ${one ? "is" : "are"} create-only, so removing the override does not apply ${one ? "it" : "them"} either -- a create-only property can only be applied by recreating the resource.`);
24668
+ remedies.push(`${needsRecreate.join(", ")} ${one ? "is" : "are"} create-only, so removing the override does not apply ${one ? "it" : "them"} in place -- a create-only property can only be applied by recreating the resource. Where cdkd created the resource without ${one ? "it" : "them"}, a deploy without the override refuses unless something else already forces a replacement or the recreate is opted into.`);
24462
24669
  }
24463
24670
  this.logger.warn(`${logicalId} (${resourceType}): ${overridden.join(", ")} will be silently dropped (--prefer-sdk-route override accepted). ${remedies.join(" ")}`);
24464
24671
  }
@@ -24866,30 +25073,47 @@ async function reserveStackCreateToken(options) {
24866
25073
  //#region src/deployment/inline-policy-claims.ts
24867
25074
  function isInlinePolicyClaimedByCompletedWriter(args, kind, principal, policyName) {
24868
25075
  const { selfLogicalId, writers, changes, stateResources } = args;
24869
- const same = (a, b) => typeof a === "string" && IAM_NAME.test(a) && a.toLowerCase() === b.toLowerCase();
24870
25076
  for (const [lid, write] of writers) {
24871
25077
  if (lid === selfLogicalId || !Object.hasOwn(stateResources, lid)) continue;
24872
25078
  const record = stateResources[lid];
24873
25079
  if (record.provisionedBy === "cc-api") continue;
24874
25080
  const props = record.properties ?? {};
24875
25081
  if (record.resourceType === "AWS::IAM::Policy") {
24876
- if (!same(record.physicalId, policyName)) continue;
25082
+ if (!sameIamName(record.physicalId, policyName)) continue;
24877
25083
  const listed = props[POLICY_LIST_FIELDS[kind]];
24878
- if (Array.isArray(listed) && listed.some((p) => same(p, principal))) return true;
25084
+ if (Array.isArray(listed) && listed.some((p) => sameIamName(p, principal))) return true;
24879
25085
  continue;
24880
25086
  }
24881
25087
  if (!Object.hasOwn(PRINCIPAL_KINDS, record.resourceType)) continue;
24882
25088
  if (PRINCIPAL_KINDS[record.resourceType] !== kind) continue;
24883
- if (!same(record.physicalId, principal)) continue;
25089
+ if (!sameIamName(record.physicalId, principal)) continue;
24884
25090
  if (write !== "create" && !ownPoliciesChange(changes.get(lid))) continue;
24885
25091
  const policies = props["Policies"];
24886
25092
  if (!Array.isArray(policies)) continue;
24887
- if (policies.some((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && same(entry["PolicyName"], policyName))) return true;
25093
+ if (policies.some((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && sameIamName(entry["PolicyName"], policyName))) return true;
24888
25094
  }
24889
25095
  return false;
24890
25096
  }
24891
25097
  var RollbackInlinePolicyWriters = class {
24892
25098
  entries = /* @__PURE__ */ new Map();
25099
+ removals = /* @__PURE__ */ new Map();
25100
+ unsettled = /* @__PURE__ */ new Map();
25101
+ notePending(ops) {
25102
+ for (const op of ops) if (!this.unsettled.has(op)) this.unsettled.set(op, {
25103
+ logicalId: op.logicalId,
25104
+ state: "pending"
25105
+ });
25106
+ }
25107
+ noteOutcome(op, completed) {
25108
+ if (!completed) {
25109
+ this.unsettled.set(op, {
25110
+ logicalId: op.logicalId,
25111
+ state: "failed"
25112
+ });
25113
+ return;
25114
+ }
25115
+ for (const [key, entry] of this.unsettled) if (key === op || entry.logicalId === op.logicalId) this.unsettled.delete(key);
25116
+ }
24893
25117
  record(logicalId, write, record, policiesChanged, via) {
24894
25118
  if (via === "cc-api") {
24895
25119
  this.entries.delete(logicalId);
@@ -24921,15 +25145,100 @@ var RollbackInlinePolicyWriters = class {
24921
25145
  }]
24922
25146
  });
24923
25147
  }
24924
- return isInlinePolicyClaimedByCompletedWriter({
25148
+ const claimed = isInlinePolicyClaimedByCompletedWriter({
24925
25149
  selfLogicalId: logicalId,
24926
25150
  writers,
24927
25151
  changes,
24928
25152
  stateResources
24929
25153
  }, kind, principal, policyName);
25154
+ if (!claimed) {
25155
+ const key = removalKey(kind, principal, policyName);
25156
+ const noted = this.removals.get(key) ?? {
25157
+ kind,
25158
+ principal,
25159
+ policyName,
25160
+ removers: /* @__PURE__ */ new Map()
25161
+ };
25162
+ noted.removers.set(logicalId, stateResources[logicalId]);
25163
+ this.removals.set(key, noted);
25164
+ }
25165
+ return claimed;
24930
25166
  };
24931
25167
  }
25168
+ takeHeldRemovals(stateResources) {
25169
+ const held = [];
25170
+ for (const [key, { kind, principal, policyName, removers }] of this.removals) {
25171
+ const { holders, unreadable } = inlinePolicyHolders(stateResources, kind, principal, policyName);
25172
+ const others = holders.filter((h) => !removers.has(h.logicalId) || stateResources[h.logicalId] !== removers.get(h.logicalId));
25173
+ if (others.length === 0) continue;
25174
+ this.removals.delete(key);
25175
+ const open = new Set([...this.unsettled.values()].map((u) => u.logicalId));
25176
+ const unsettled = [...new Set(others.map((h) => h.logicalId))].filter((id) => open.has(id));
25177
+ held.push({
25178
+ kind,
25179
+ holders: others,
25180
+ unreadable,
25181
+ unsettled
25182
+ });
25183
+ }
25184
+ return held;
25185
+ }
24932
25186
  };
25187
+ function inlinePolicyHolders(stateResources, kind, principal, policyName) {
25188
+ const holders = [];
25189
+ const unreadable = [];
25190
+ const unnamed = (v) => typeof v !== "string" || !IAM_NAME.test(v);
25191
+ for (const [logicalId, record] of Object.entries(stateResources)) {
25192
+ if (record === null || typeof record !== "object") continue;
25193
+ const props = record.properties ?? {};
25194
+ if (record.resourceType === "AWS::IAM::Policy") {
25195
+ const nameMatches = sameIamName(record.physicalId, policyName);
25196
+ if (!nameMatches && !unnamed(record.physicalId)) continue;
25197
+ const listed = props[POLICY_LIST_FIELDS[kind]];
25198
+ const entries = Array.isArray(listed) ? listed : [];
25199
+ const named = entries.find((p) => sameIamName(p, principal));
25200
+ if (nameMatches && typeof named === "string") holders.push({
25201
+ logicalId,
25202
+ principal: named,
25203
+ policyName: record.physicalId,
25204
+ document: props["PolicyDocument"]
25205
+ });
25206
+ else if (named !== void 0 || entries.some(unnamed)) unreadable.push(logicalId);
25207
+ continue;
25208
+ }
25209
+ if (!Object.hasOwn(PRINCIPAL_KINDS, record.resourceType)) continue;
25210
+ if (PRINCIPAL_KINDS[record.resourceType] !== kind) continue;
25211
+ const principalMatches = sameIamName(record.physicalId, principal);
25212
+ if (!principalMatches && !unnamed(record.physicalId)) continue;
25213
+ const policies = props["Policies"];
25214
+ if (!Array.isArray(policies)) continue;
25215
+ for (const entry of policies) {
25216
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
25217
+ const name = entry["PolicyName"];
25218
+ if (principalMatches && sameIamName(name, policyName)) holders.push({
25219
+ logicalId,
25220
+ principal: record.physicalId,
25221
+ policyName: name,
25222
+ document: entry["PolicyDocument"]
25223
+ });
25224
+ else if (unnamed(name) || sameIamName(name, policyName)) unreadable.push(logicalId);
25225
+ }
25226
+ }
25227
+ return {
25228
+ holders,
25229
+ unreadable: [...new Set(unreadable)]
25230
+ };
25231
+ }
25232
+ function sameIamName(a, b) {
25233
+ return typeof a === "string" && IAM_NAME.test(a) && a.toLowerCase() === b.toLowerCase();
25234
+ }
25235
+ function removalKey(kind, principal, policyName) {
25236
+ return JSON.stringify([
25237
+ kind,
25238
+ principal.toLowerCase(),
25239
+ policyName.toLowerCase()
25240
+ ]);
25241
+ }
24933
25242
  const IAM_NAME = /^[\w+=,.@-]+$/;
24934
25243
  const POLICY_LIST_FIELDS = {
24935
25244
  role: "Roles",
@@ -25805,6 +26114,31 @@ function updatePartialMessage(reason) {
25805
26114
  return `partial (${reason})`;
25806
26115
  }
25807
26116
 
26117
+ //#endregion
26118
+ //#region src/provisioning/redacted-delete-address.ts
26119
+ function isRedactedRecordedValue(value) {
26120
+ if (carriesSecretMask(value)) return true;
26121
+ let text;
26122
+ try {
26123
+ text = typeof value === "string" ? value : JSON.stringify(value);
26124
+ } catch {
26125
+ return false;
26126
+ }
26127
+ return text !== void 0 && dynamicReferenceTokens(text).length > 0;
26128
+ }
26129
+ const REDACTED_DELETE_ADDRESS_SKIP_REASON = "redacted address property in state — no delete issued";
26130
+ function redactedDeleteAddressFields(fields) {
26131
+ return Object.keys(fields).filter((key) => isRedactedRecordedValue(fields[key]));
26132
+ }
26133
+ function redactedDeleteAddressSkip(logger, logicalId, what, redactedFields) {
26134
+ if (redactedFields.length === 0) return void 0;
26135
+ logger.warn(safeMsg`${what} ${logicalId} is recorded in state with ${redactedFields.join(", ")} ` + "redacted (the '***' mask of a NoEcho value it read, or a secret '{{resolve:...}}' reference), which names nothing in AWS; skipping deletion — no AWS call is issued, so the resource is LEFT IN PLACE unless a parent resource this run also deletes removes it (then only the record is stale). Re-deploying records the same redaction again. The state record is KEPT and the run reports the skip: on 'cdkd destroy' / 'cdkd state destroy' (which exits non-zero) and, since issue 1762, on the plain DELETE of a resource removed from the template during cdkd deploy. Remove the resource by hand, then clear the stack's records with 'cdkd state orphan <stack>' — that command drops EVERY record for the stack, not just this one. NOTE a deploy-side REPLACEMENT or rollback delete instead FAILS the resource (https://github.com/go-to-k/cdkd/issues/1762) — the old resource is left untracked there, so remove it by hand.");
26136
+ return {
26137
+ outcome: "skipped",
26138
+ reason: REDACTED_DELETE_ADDRESS_SKIP_REASON
26139
+ };
26140
+ }
26141
+
25808
26142
  //#endregion
25809
26143
  //#region src/provisioning/final-snapshot.ts
25810
26144
  const ATOMIC_FINAL_SNAPSHOT_TYPES = /* @__PURE__ */ new Set([
@@ -26132,30 +26466,6 @@ async function createReplicationGroupFinalSnapshot(client, replicationGroupId, l
26132
26466
  const NESTED_STACK_RESOURCE_TYPE$1 = "AWS::CloudFormation::Stack";
26133
26467
  const nonEmptyString = (v) => typeof v === "string" && v.length > 0;
26134
26468
 
26135
- //#endregion
26136
- //#region src/deployment/producer-regions-scope.ts
26137
- const producerRegionsStore = new AsyncLocalStorage();
26138
- function withProducerRegions(evidence, fn) {
26139
- return producerRegionsStore.run(evidence, fn);
26140
- }
26141
- function getCurrentProducerRegions() {
26142
- return producerRegionsStore.getStore();
26143
- }
26144
- function inheritProducerRegions(own, inherited) {
26145
- const seen = /* @__PURE__ */ new Set();
26146
- const regions = [];
26147
- for (const region of [...own, ...inherited?.regions ?? []]) {
26148
- const canonical = canonicalizeRegion(region);
26149
- if (!canonical || seen.has(canonical)) continue;
26150
- seen.add(canonical);
26151
- regions.push(region);
26152
- }
26153
- return {
26154
- regions,
26155
- complete: inherited?.complete === true
26156
- };
26157
- }
26158
-
26159
26469
  //#endregion
26160
26470
  //#region src/deployment/rollback-executor/messages.ts
26161
26471
  function throwIfDeleteSkipped(result, logicalId, physicalId, duringClause) {
@@ -26183,6 +26493,19 @@ function maskedRollbackEventError(error, mask) {
26183
26493
  message
26184
26494
  };
26185
26495
  }
26496
+ function recordRollbackSkip(scope, op, reason) {
26497
+ scope.result.warnings++;
26498
+ scope.result.skipped++;
26499
+ scope.ctx.recordEvent?.({
26500
+ eventType: "ROLLBACK_RESOURCE_SKIPPED",
26501
+ stackName: scope.stackName,
26502
+ operation: op.changeType,
26503
+ logicalId: op.logicalId,
26504
+ resourceType: op.resourceType,
26505
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy },
26506
+ reason: scope.mask(reason)
26507
+ });
26508
+ }
26186
26509
  function effectiveProvisionedBy(record, fallbackProvisionedBy) {
26187
26510
  return record?.provisionedBy ?? fallbackProvisionedBy;
26188
26511
  }
@@ -26286,6 +26609,271 @@ function retainedSurvivorMessages(logicalId, resourceType, survivorPhysicalId, s
26286
26609
  };
26287
26610
  }
26288
26611
 
26612
+ //#endregion
26613
+ //#region src/deployment/rollback-executor/names.ts
26614
+ function replayPrefixScope(input, logger, mask, restoring) {
26615
+ const choice = replayPrefixChoice(input);
26616
+ if (choice.kind === "not-applicable") return (fn) => fn();
26617
+ const setting = (skip) => skip ? "SKIPPED" : "KEPT";
26618
+ const subject = `${safe(input.logicalId)} (${safe(input.resourceType)})`;
26619
+ const declared = choice.declared;
26620
+ const secretDerived = declared !== void 0 && mask(declared) !== declared;
26621
+ const withheld = secretDerived || choice.kind === "unreproduced" && declared === void 0;
26622
+ const shown = (value) => displayIdent(mask(String(value)));
26623
+ const quoted = (value) => {
26624
+ const masked = mask(value);
26625
+ const rendered = displayIdent(masked);
26626
+ return rendered === masked ? `"${masked}"` : rendered;
26627
+ };
26628
+ if (choice.kind === "reproduced" && choice.skipPrefix !== choice.recorded) logger.info(mask(` Rollback: ${restoring ? "re-creating" : "reverting"} ${subject} under the user-supplied-name prefix setting that created ` + (withheld ? `it (its physical id is withheld, as its name is secret-derived): ` : `${shown(input.physicalId)} (`) + `stack-name prefix ${setting(choice.skipPrefix)}; the failed deploy ran with it ${setting(choice.recorded)}${withheld ? "" : ")"}`));
26629
+ else if (choice.kind === "unreproduced" && restoring) {
26630
+ const idUnreadable = typeof input.physicalId !== "string" || input.physicalId === "";
26631
+ const prop = safe(choice.property);
26632
+ const unreadable = declared === void 0 ? idUnreadable ? `its ${prop} or its physical id` : `its ${prop}` : idUnreadable ? `its physical id` : void 0;
26633
+ logger.warn(mask(` ⚠ ${subject}: cdkd cannot tell which user-supplied-name prefix setting created the old resource (` + (withheld ? `its physical id is withheld, as its name is secret-derived or unreadable` : shown(input.physicalId)) + `) — ` + (choice.names === void 0 ? unreadable !== void 0 ? `cdkd cannot read ${unreadable} to compare` : `cdkd cannot derive the names its ${prop} takes to compare` : secretDerived ? `its ${prop} is secret-derived, and neither name it derives matches` : `its ${prop} derives to ${quoted(choice.names.skipped)} (prefix skipped) or ${quoted(choice.names.kept)} (prefix kept), and it is neither`) + `; re-creating it with the stack-name prefix ${setting(choice.skipPrefix)}, as the failed deploy ran, so it may come back under a different physical name.`));
26634
+ }
26635
+ const skip = choice.skipPrefix;
26636
+ return (fn) => withSkipPrefix(skip, fn);
26637
+ }
26638
+ function createOpMasker(logger, secrets) {
26639
+ const base = createMaskedLogSinks(logger, (text) => maskSecretsInText(text, secrets));
26640
+ const pairs = [];
26641
+ let sinks = base;
26642
+ return {
26643
+ mask: (text) => typeof text === "string" ? sinks.mask(text) : text,
26644
+ addNamed: (record) => {
26645
+ pairs.push(...secretDerivedNamePairs(record));
26646
+ sinks = withDerivedNameMasks(logger, base, pairs);
26647
+ }
26648
+ };
26649
+ }
26650
+ const OTHER_SPELLED_NAME_KEYS = {
26651
+ "AWS::Cognito::UserPoolDomain": ["Domain"],
26652
+ "AWS::Cognito::UserPoolUser": ["Username"],
26653
+ "AWS::ECS::TaskDefinition": ["Family"],
26654
+ "AWS::ElastiCache::ReplicationGroup": ["ReplicationGroupId"],
26655
+ "AWS::ElastiCache::User": ["UserId"],
26656
+ "AWS::ElastiCache::UserGroup": ["UserGroupId"],
26657
+ "AWS::SES::EmailIdentity": ["EmailIdentity"]
26658
+ };
26659
+ const COMPOSITE_SCOPE_LAST = /^(?:REGIONAL|CLOUDFRONT|GLOBAL)$/;
26660
+ const COMPOSITE_POOL_FIRST = /^[a-z]{2}(?:-gov)?-[a-z]+-\d+_[A-Za-z0-9]+$/;
26661
+ function idNameSegments(id) {
26662
+ const segments = /* @__PURE__ */ new Set();
26663
+ const arn = /^arn:[^:]*:([^:]*):[^:]*:[^:]*:(.+)$/.exec(id);
26664
+ if (arn !== null) {
26665
+ const service = arn[1];
26666
+ const resource = arn[2];
26667
+ const lambda = service === "lambda" ? /^(?:function|layer):([^:]+)(?::([^:]+))?/.exec(resource) : null;
26668
+ if (lambda !== null) {
26669
+ segments.add(lambda[1]);
26670
+ const qualifier = lambda[2];
26671
+ if (qualifier !== void 0 && !/^\d+$/.test(qualifier)) segments.add(qualifier);
26672
+ } else {
26673
+ const parts = resource.split(/[/:]/).filter((part) => part !== "");
26674
+ let body = parts.length > 1 ? parts.slice(1) : parts;
26675
+ if (body.length > 1 && /^\d+$/.test(body[body.length - 1])) body = body.slice(0, -1);
26676
+ for (const part of body) {
26677
+ segments.add(part);
26678
+ if (service === "secretsmanager") segments.add(part.replace(/-[A-Za-z0-9]{6}$/, ""));
26679
+ }
26680
+ }
26681
+ }
26682
+ if (id.includes("/")) {
26683
+ const afterSlash = id.slice(id.lastIndexOf("/") + 1);
26684
+ segments.add(afterSlash);
26685
+ segments.add(afterSlash.replace(/:\d+$/, ""));
26686
+ }
26687
+ if (id.includes("|")) {
26688
+ const parts = id.split("|");
26689
+ parts.forEach((part, index) => {
26690
+ if (part === "") return;
26691
+ if (index === parts.length - 1 && parts.length > 1 && COMPOSITE_SCOPE_LAST.test(part)) return;
26692
+ if (index === 0 && parts.length > 1 && COMPOSITE_POOL_FIRST.test(part)) return;
26693
+ segments.add(part);
26694
+ });
26695
+ }
26696
+ return [...segments].filter((segment) => segment.length >= 4 && segment !== id);
26697
+ }
26698
+ function ownEntry(table, key) {
26699
+ return Object.hasOwn(table, key) ? table[key] : void 0;
26700
+ }
26701
+ function secretDerivedNamePairs(record) {
26702
+ const { resourceType, properties, logicalId } = record;
26703
+ if (typeof resourceType !== "string" || !isRestorableBag(properties)) return [];
26704
+ const rewritten = reverseReplacementRewrittenNameTypes();
26705
+ const named = /* @__PURE__ */ new Set();
26706
+ const primary = Object.hasOwn(rewritten, resourceType) ? rewritten[resourceType].property : explicitNamePropertyFor(resourceType);
26707
+ if (typeof primary === "string") named.add(primary);
26708
+ for (const key of Object.keys(properties)) if (/(?:Name|Identifier)$/.test(key)) named.add(key);
26709
+ for (const key of ownEntry(OTHER_SPELLED_NAME_KEYS, resourceType) ?? []) named.add(key);
26710
+ const idSpellings = record.physicalIds.filter((id) => typeof id === "string" && id !== "").flatMap((id) => [
26711
+ id,
26712
+ ...id.toLowerCase() === id || id.length < 4 ? [] : [id.toLowerCase()],
26713
+ finalSnapshotNamePrefix(id, resourceType),
26714
+ ...idNameSegments(id)
26715
+ ]);
26716
+ const pairs = [];
26717
+ for (const key of named) {
26718
+ if (!Object.hasOwn(properties, key)) continue;
26719
+ const value = properties[key];
26720
+ if (typeof value !== "string" || value === "") continue;
26721
+ const derived = key === primary && !value.includes("{{resolve:") && value !== "***" ? rewrittenNameSpellings(resourceType, value, logicalId) : [];
26722
+ for (const spelling of [...idSpellings, ...derived]) pairs.push([value, spelling]);
26723
+ }
26724
+ return pairs;
26725
+ }
26726
+ function addRecordNames(opMasker, op, current) {
26727
+ const { logicalId } = op;
26728
+ for (const properties of [op.properties, op.attemptedProperties]) opMasker.addNamed({
26729
+ resourceType: op.resourceType,
26730
+ properties,
26731
+ logicalId,
26732
+ physicalIds: [op.physicalId]
26733
+ });
26734
+ for (const record of [op.previousState, current]) {
26735
+ if (record === null || typeof record !== "object") continue;
26736
+ opMasker.addNamed({
26737
+ resourceType: record.resourceType ?? op.resourceType,
26738
+ properties: record.properties,
26739
+ logicalId,
26740
+ physicalIds: [record.physicalId]
26741
+ });
26742
+ }
26743
+ }
26744
+ const ABSENT_BASELINE_SKIP_CAUSE = "Its recorded previous state has no `properties` bag, so there is nothing to restore it to; the rollback left the resource exactly as it is.";
26745
+ function requireRestorableBaseline(bag, logger, { logicalId, consequence, remedy, retry }) {
26746
+ if (isRestorableBag(bag)) return true;
26747
+ if (bag === void 0) {
26748
+ logger.warn(` Rollback: Cannot restore ${shownLogicalId(logicalId)} \u2014 its recorded previous state has no \`properties\` bag, so there is nothing to restore it to. An empty desired state would ${consequence}. The resource is therefore left exactly as it is. ${remedy}`);
26749
+ return false;
26750
+ }
26751
+ const shape = bag === null ? "null" : Array.isArray(bag) ? "an array" : `a ${typeof bag}`;
26752
+ throw new CdkdError(`Cannot roll ${shownLogicalId(logicalId)} back: its recorded previous state has a \`properties\` field that is not a property bag (${shape}), so cdkd cannot tell what to restore it to. Replaying it would do one of two things, and cdkd does neither: send the malformed value to the provider as-is, or send an empty desired state (which would ${consequence}). The rollback JOURNAL record is kept: once that record holds a property bag again, ${retry}. Otherwise fix forward with \`cdkd deploy\`, or remove the stack with \`cdkd destroy\`.`, "ROLLBACK_UNUSABLE_BASELINE");
26753
+ }
26754
+ function isRestorableBag(bag) {
26755
+ return typeof bag === "object" && bag !== null && !Array.isArray(bag);
26756
+ }
26757
+ async function prepareCreateRollbackFinalSnapshot(op, provisionedBy, ctx, mask) {
26758
+ const { logicalId, resourceType } = op;
26759
+ const physicalId = op.physicalId;
26760
+ switch (finalSnapshotMechanism(resourceType, provisionedBy)) {
26761
+ case "atomic-delete-parameter": return buildFinalSnapshotIdentifier(physicalId, resourceType);
26762
+ case "pre-delete-snapshot":
26763
+ await createPreDeleteFinalSnapshot(resourceType, physicalId, logicalId, ctx.finalSnapshotClients ?? getAwsClients(), {
26764
+ info: (message) => ctx.logger.info(mask(message)),
26765
+ debug: (message) => ctx.logger.debug(mask(message))
26766
+ });
26767
+ return;
26768
+ case "refuse-cc-routed": throw ccRoutedFinalSnapshotError(logicalId, resourceType, SKIP_FINAL_SNAPSHOT_FLAG);
26769
+ case "refuse-unsupported-type": throw unsupportedFinalSnapshotError(logicalId, resourceType, SKIP_FINAL_SNAPSHOT_FLAG);
26770
+ }
26771
+ }
26772
+
26773
+ //#endregion
26774
+ //#region src/deployment/rollback-executor/replay-inline-policy-restore.ts
26775
+ async function restoreHeldInlinePolicies(writers, stateResources, stackName, ctx, result, options = {}) {
26776
+ for (const removal of writers.takeHeldRemovals(stateResources)) await restoreOne(removal, stateResources, stackName, ctx, result, options.refuseAll === true);
26777
+ }
26778
+ async function restoreOne({ kind, holders, unreadable, unsettled }, stateResources, stackName, ctx, result, refuseAll) {
26779
+ const { logger } = ctx;
26780
+ const ids = [...new Set(holders.map((h) => h.logicalId))].map((id) => safe(id)).join(", ");
26781
+ const lost = safeMsg`the ${kind} it is on lacks that inline policy until the resource is next updated, or ` + `'cdkd drift <stack> --revert' restores it`;
26782
+ if (refuseAll || unsettled.length > 0) {
26783
+ const pending = refuseAll ? ids : unsettled.map((id) => safe(id)).join(", ");
26784
+ logger.warn(safeMsg` Rollback: an inline policy this rollback removed is recorded by ${ids}, but the ` + safeMsg`rollback of ${pending} has not completed, so that record may be the failed ` + safeMsg`deploy's and cdkd did not put it back; ${lost}.`);
26785
+ result.warnings++;
26786
+ return;
26787
+ }
26788
+ if (unreadable.length > 0) {
26789
+ logger.warn(safeMsg` Rollback: an inline policy this rollback removed is recorded by ${ids}, and ` + safeMsg`${unreadable.map((id) => safe(id)).join(", ")} may record it too under a redacted ` + safeMsg`name, so cdkd did not put it back; ${lost}.`);
26790
+ result.warnings++;
26791
+ return;
26792
+ }
26793
+ const documents = holders.map((h) => serializedDocument(h.document));
26794
+ if (documents.some((d) => d === void 0)) {
26795
+ logger.warn(safeMsg` Rollback: an inline policy this rollback removed is still recorded by ${ids}, but its ` + safeMsg`recorded document is absent or redacted, so cdkd did not put it back; ${lost}.`);
26796
+ result.warnings++;
26797
+ return;
26798
+ }
26799
+ if (new Set(documents).size > 1) {
26800
+ logger.warn(safeMsg` Rollback: an inline policy this rollback removed is recorded by ${ids} with different ` + safeMsg`documents under one name on one ${kind}, so cdkd put neither back; ${lost}.`);
26801
+ result.warnings++;
26802
+ return;
26803
+ }
26804
+ const holder = holders[0];
26805
+ const secrets = /* @__PURE__ */ new Map();
26806
+ for (const h of holders) {
26807
+ const bag = ctx.logOnlyNeedlesFor?.(h.logicalId);
26808
+ if (bag) carryLogOnlyValues(bag, secrets);
26809
+ }
26810
+ const masker = createOpMasker(logger, secrets);
26811
+ for (const h of holders) {
26812
+ const record = stateResources[h.logicalId];
26813
+ addRecordNames(masker, {
26814
+ logicalId: h.logicalId,
26815
+ resourceType: record?.resourceType,
26816
+ physicalId: record?.physicalId
26817
+ }, record);
26818
+ }
26819
+ try {
26820
+ const { provider, provisionedBy } = ctx.providerRegistry.getProviderFor({
26821
+ resourceType: "AWS::IAM::Policy",
26822
+ provisionedBy: "sdk"
26823
+ });
26824
+ if (provisionedBy !== "sdk") throw new Error("AWS::IAM::Policy is not routed to its SDK provider");
26825
+ await provider.create(holder.logicalId, "AWS::IAM::Policy", {
26826
+ PolicyName: holder.policyName,
26827
+ PolicyDocument: holder.document,
26828
+ [POLICY_LIST_FIELDS[kind]]: [holder.principal]
26829
+ }, { maskSecrets: masker.mask });
26830
+ } catch (error) {
26831
+ logger.warn(maskedFailureText(safeMsg` Rollback: could not put back the inline policy ${ids} records on its ${kind} ` + safeMsg`(${lost}): `, error, masker.mask));
26832
+ result.warnings++;
26833
+ return;
26834
+ }
26835
+ logger.info(safeMsg` Rollback: put back the inline policy ${ids} records on its ${kind}`);
26836
+ const holderType = stateResources[holder.logicalId]?.resourceType;
26837
+ ctx.recordEvent?.({
26838
+ eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
26839
+ stackName,
26840
+ operation: "UPDATE",
26841
+ logicalId: holder.logicalId,
26842
+ ...typeof holderType === "string" && { resourceType: holderType },
26843
+ provisionedBy: "sdk",
26844
+ reason: `Put back the inline policy this resource records on its ${kind}, which the rollback had removed from it.`
26845
+ });
26846
+ }
26847
+ function serializedDocument(document) {
26848
+ if (typeof document === "string") return document.length > 0 && !isRedactedRecordedValue(document) ? document : void 0;
26849
+ if (document === null || typeof document !== "object" || Array.isArray(document)) return;
26850
+ return isRedactedRecordedValue(document) ? void 0 : JSON.stringify(document);
26851
+ }
26852
+
26853
+ //#endregion
26854
+ //#region src/deployment/producer-regions-scope.ts
26855
+ const producerRegionsStore = new AsyncLocalStorage();
26856
+ function withProducerRegions(evidence, fn) {
26857
+ return producerRegionsStore.run(evidence, fn);
26858
+ }
26859
+ function getCurrentProducerRegions() {
26860
+ return producerRegionsStore.getStore();
26861
+ }
26862
+ function inheritProducerRegions(own, inherited) {
26863
+ const seen = /* @__PURE__ */ new Set();
26864
+ const regions = [];
26865
+ for (const region of [...own, ...inherited?.regions ?? []]) {
26866
+ const canonical = canonicalizeRegion(region);
26867
+ if (!canonical || seen.has(canonical)) continue;
26868
+ seen.add(canonical);
26869
+ regions.push(region);
26870
+ }
26871
+ return {
26872
+ regions,
26873
+ complete: inherited?.complete === true
26874
+ };
26875
+ }
26876
+
26289
26877
  //#endregion
26290
26878
  //#region src/deployment/rollback-executor/replay-secrets.ts
26291
26879
  function replayProducerRegionEvidence(ctx) {
@@ -26589,166 +27177,6 @@ function sortRollbackCreates(createOps, stateResources, logger) {
26589
27177
  return sorted;
26590
27178
  }
26591
27179
 
26592
- //#endregion
26593
- //#region src/deployment/rollback-executor/names.ts
26594
- function replayPrefixScope(input, logger, mask, restoring) {
26595
- const choice = replayPrefixChoice(input);
26596
- if (choice.kind === "not-applicable") return (fn) => fn();
26597
- const setting = (skip) => skip ? "SKIPPED" : "KEPT";
26598
- const subject = `${safe(input.logicalId)} (${safe(input.resourceType)})`;
26599
- const declared = choice.declared;
26600
- const secretDerived = declared !== void 0 && mask(declared) !== declared;
26601
- const withheld = secretDerived || choice.kind === "unreproduced" && declared === void 0;
26602
- const shown = (value) => displayIdent(mask(String(value)));
26603
- const quoted = (value) => {
26604
- const masked = mask(value);
26605
- const rendered = displayIdent(masked);
26606
- return rendered === masked ? `"${masked}"` : rendered;
26607
- };
26608
- if (choice.kind === "reproduced" && choice.skipPrefix !== choice.recorded) logger.info(mask(` Rollback: ${restoring ? "re-creating" : "reverting"} ${subject} under the user-supplied-name prefix setting that created ` + (withheld ? `it (its physical id is withheld, as its name is secret-derived): ` : `${shown(input.physicalId)} (`) + `stack-name prefix ${setting(choice.skipPrefix)}; the failed deploy ran with it ${setting(choice.recorded)}${withheld ? "" : ")"}`));
26609
- else if (choice.kind === "unreproduced" && restoring) {
26610
- const idUnreadable = typeof input.physicalId !== "string" || input.physicalId === "";
26611
- const prop = safe(choice.property);
26612
- const unreadable = declared === void 0 ? idUnreadable ? `its ${prop} or its physical id` : `its ${prop}` : idUnreadable ? `its physical id` : void 0;
26613
- logger.warn(mask(` ⚠ ${subject}: cdkd cannot tell which user-supplied-name prefix setting created the old resource (` + (withheld ? `its physical id is withheld, as its name is secret-derived or unreadable` : shown(input.physicalId)) + `) — ` + (choice.names === void 0 ? unreadable !== void 0 ? `cdkd cannot read ${unreadable} to compare` : `cdkd cannot derive the names its ${prop} takes to compare` : secretDerived ? `its ${prop} is secret-derived, and neither name it derives matches` : `its ${prop} derives to ${quoted(choice.names.skipped)} (prefix skipped) or ${quoted(choice.names.kept)} (prefix kept), and it is neither`) + `; re-creating it with the stack-name prefix ${setting(choice.skipPrefix)}, as the failed deploy ran, so it may come back under a different physical name.`));
26614
- }
26615
- const skip = choice.skipPrefix;
26616
- return (fn) => withSkipPrefix(skip, fn);
26617
- }
26618
- function createOpMasker(logger, secrets) {
26619
- const base = createMaskedLogSinks(logger, (text) => maskSecretsInText(text, secrets));
26620
- const pairs = [];
26621
- let sinks = base;
26622
- return {
26623
- mask: (text) => typeof text === "string" ? sinks.mask(text) : text,
26624
- addNamed: (record) => {
26625
- pairs.push(...secretDerivedNamePairs(record));
26626
- sinks = withDerivedNameMasks(logger, base, pairs);
26627
- }
26628
- };
26629
- }
26630
- const OTHER_SPELLED_NAME_KEYS = {
26631
- "AWS::Cognito::UserPoolDomain": ["Domain"],
26632
- "AWS::Cognito::UserPoolUser": ["Username"],
26633
- "AWS::ECS::TaskDefinition": ["Family"],
26634
- "AWS::ElastiCache::ReplicationGroup": ["ReplicationGroupId"],
26635
- "AWS::ElastiCache::User": ["UserId"],
26636
- "AWS::ElastiCache::UserGroup": ["UserGroupId"],
26637
- "AWS::SES::EmailIdentity": ["EmailIdentity"]
26638
- };
26639
- const COMPOSITE_SCOPE_LAST = /^(?:REGIONAL|CLOUDFRONT|GLOBAL)$/;
26640
- const COMPOSITE_POOL_FIRST = /^[a-z]{2}(?:-gov)?-[a-z]+-\d+_[A-Za-z0-9]+$/;
26641
- function idNameSegments(id) {
26642
- const segments = /* @__PURE__ */ new Set();
26643
- const arn = /^arn:[^:]*:([^:]*):[^:]*:[^:]*:(.+)$/.exec(id);
26644
- if (arn !== null) {
26645
- const service = arn[1];
26646
- const resource = arn[2];
26647
- const lambda = service === "lambda" ? /^(?:function|layer):([^:]+)(?::([^:]+))?/.exec(resource) : null;
26648
- if (lambda !== null) {
26649
- segments.add(lambda[1]);
26650
- const qualifier = lambda[2];
26651
- if (qualifier !== void 0 && !/^\d+$/.test(qualifier)) segments.add(qualifier);
26652
- } else {
26653
- const parts = resource.split(/[/:]/).filter((part) => part !== "");
26654
- let body = parts.length > 1 ? parts.slice(1) : parts;
26655
- if (body.length > 1 && /^\d+$/.test(body[body.length - 1])) body = body.slice(0, -1);
26656
- for (const part of body) {
26657
- segments.add(part);
26658
- if (service === "secretsmanager") segments.add(part.replace(/-[A-Za-z0-9]{6}$/, ""));
26659
- }
26660
- }
26661
- }
26662
- if (id.includes("/")) {
26663
- const afterSlash = id.slice(id.lastIndexOf("/") + 1);
26664
- segments.add(afterSlash);
26665
- segments.add(afterSlash.replace(/:\d+$/, ""));
26666
- }
26667
- if (id.includes("|")) {
26668
- const parts = id.split("|");
26669
- parts.forEach((part, index) => {
26670
- if (part === "") return;
26671
- if (index === parts.length - 1 && parts.length > 1 && COMPOSITE_SCOPE_LAST.test(part)) return;
26672
- if (index === 0 && parts.length > 1 && COMPOSITE_POOL_FIRST.test(part)) return;
26673
- segments.add(part);
26674
- });
26675
- }
26676
- return [...segments].filter((segment) => segment.length >= 4 && segment !== id);
26677
- }
26678
- function ownEntry(table, key) {
26679
- return Object.hasOwn(table, key) ? table[key] : void 0;
26680
- }
26681
- function secretDerivedNamePairs(record) {
26682
- const { resourceType, properties, logicalId } = record;
26683
- if (typeof resourceType !== "string" || !isRestorableBag(properties)) return [];
26684
- const rewritten = reverseReplacementRewrittenNameTypes();
26685
- const named = /* @__PURE__ */ new Set();
26686
- const primary = Object.hasOwn(rewritten, resourceType) ? rewritten[resourceType].property : explicitNamePropertyFor(resourceType);
26687
- if (typeof primary === "string") named.add(primary);
26688
- for (const key of Object.keys(properties)) if (/(?:Name|Identifier)$/.test(key)) named.add(key);
26689
- for (const key of ownEntry(OTHER_SPELLED_NAME_KEYS, resourceType) ?? []) named.add(key);
26690
- const idSpellings = record.physicalIds.filter((id) => typeof id === "string" && id !== "").flatMap((id) => [
26691
- id,
26692
- ...id.toLowerCase() === id || id.length < 4 ? [] : [id.toLowerCase()],
26693
- finalSnapshotNamePrefix(id, resourceType),
26694
- ...idNameSegments(id)
26695
- ]);
26696
- const pairs = [];
26697
- for (const key of named) {
26698
- if (!Object.hasOwn(properties, key)) continue;
26699
- const value = properties[key];
26700
- if (typeof value !== "string" || value === "") continue;
26701
- const derived = key === primary && !value.includes("{{resolve:") && value !== "***" ? rewrittenNameSpellings(resourceType, value, logicalId) : [];
26702
- for (const spelling of [...idSpellings, ...derived]) pairs.push([value, spelling]);
26703
- }
26704
- return pairs;
26705
- }
26706
- function addRecordNames(opMasker, op, current) {
26707
- const { logicalId } = op;
26708
- for (const properties of [op.properties, op.attemptedProperties]) opMasker.addNamed({
26709
- resourceType: op.resourceType,
26710
- properties,
26711
- logicalId,
26712
- physicalIds: [op.physicalId]
26713
- });
26714
- for (const record of [op.previousState, current]) {
26715
- if (record === null || typeof record !== "object") continue;
26716
- opMasker.addNamed({
26717
- resourceType: record.resourceType ?? op.resourceType,
26718
- properties: record.properties,
26719
- logicalId,
26720
- physicalIds: [record.physicalId]
26721
- });
26722
- }
26723
- }
26724
- function requireRestorableBaseline(bag, logger, { logicalId, consequence, remedy, retry }) {
26725
- if (isRestorableBag(bag)) return true;
26726
- if (bag === void 0) {
26727
- logger.warn(` Rollback: Cannot restore ${shownLogicalId(logicalId)} \u2014 its recorded previous state has no \`properties\` bag, so there is nothing to restore it to. An empty desired state would ${consequence}. The resource is therefore left exactly as it is. ${remedy}`);
26728
- return false;
26729
- }
26730
- const shape = bag === null ? "null" : Array.isArray(bag) ? "an array" : `a ${typeof bag}`;
26731
- throw new CdkdError(`Cannot roll ${shownLogicalId(logicalId)} back: its recorded previous state has a \`properties\` field that is not a property bag (${shape}), so cdkd cannot tell what to restore it to. Replaying it would do one of two things, and cdkd does neither: send the malformed value to the provider as-is, or send an empty desired state (which would ${consequence}). The rollback JOURNAL record is kept: once that record holds a property bag again, ${retry}. Otherwise fix forward with \`cdkd deploy\`, or remove the stack with \`cdkd destroy\`.`, "ROLLBACK_UNUSABLE_BASELINE");
26732
- }
26733
- function isRestorableBag(bag) {
26734
- return typeof bag === "object" && bag !== null && !Array.isArray(bag);
26735
- }
26736
- async function prepareCreateRollbackFinalSnapshot(op, provisionedBy, ctx, mask) {
26737
- const { logicalId, resourceType } = op;
26738
- const physicalId = op.physicalId;
26739
- switch (finalSnapshotMechanism(resourceType, provisionedBy)) {
26740
- case "atomic-delete-parameter": return buildFinalSnapshotIdentifier(physicalId, resourceType);
26741
- case "pre-delete-snapshot":
26742
- await createPreDeleteFinalSnapshot(resourceType, physicalId, logicalId, ctx.finalSnapshotClients ?? getAwsClients(), {
26743
- info: (message) => ctx.logger.info(mask(message)),
26744
- debug: (message) => ctx.logger.debug(mask(message))
26745
- });
26746
- return;
26747
- case "refuse-cc-routed": throw ccRoutedFinalSnapshotError(logicalId, resourceType, SKIP_FINAL_SNAPSHOT_FLAG);
26748
- case "refuse-unsupported-type": throw unsupportedFinalSnapshotError(logicalId, resourceType, SKIP_FINAL_SNAPSHOT_FLAG);
26749
- }
26750
- }
26751
-
26752
27180
  //#endregion
26753
27181
  //#region src/deployment/rollback-executor/replay-props.ts
26754
27182
  async function resolveReplayProps(props, resolvers, secrets, execCtx, logicalId) {
@@ -26916,10 +27344,10 @@ async function replayOrphanRetain(s) {
26916
27344
  });
26917
27345
  }
26918
27346
  async function replayDelete(s) {
26919
- const { op, stateResources, stackName, ctx, result, inlinePolicyWriters, afterOp, action, logger, mask } = s;
27347
+ const { op, stateResources, stackName, ctx, inlinePolicyWriters, afterOp, action, logger, mask } = s;
26920
27348
  if (!op.physicalId) {
26921
27349
  logger.warn(` Rollback: Cannot delete ${safe(op.logicalId)} — no physical ID recorded`);
26922
- result.warnings++;
27350
+ recordRollbackSkip(s, op, "No physical id is recorded for the rolled-back CREATE, so the rollback cannot address it to delete it.");
26923
27351
  return;
26924
27352
  }
26925
27353
  const deleteProvisionedBy = effectiveProvisionedBy(stateResources[op.logicalId], op.provisionedBy);
@@ -27004,17 +27432,17 @@ async function replayReadopt(s) {
27004
27432
  });
27005
27433
  }
27006
27434
  async function replayRevert(s) {
27007
- const { op, stateResources, stackName, ctx, resolver, result, inlinePolicyWriters, afterOp, isInterrupted, logger, secrets, opMasker, mask } = s;
27435
+ const { op, stateResources, stackName, ctx, resolver, inlinePolicyWriters, afterOp, isInterrupted, logger, secrets, opMasker, mask } = s;
27008
27436
  if (!op.previousState) {
27009
27437
  logger.warn(` Rollback: Cannot restore ${safe(op.logicalId)} — no previous state available`);
27010
- result.warnings++;
27438
+ recordRollbackSkip(s, op, "No previous state is recorded for it, so there is nothing to restore it to.");
27011
27439
  return;
27012
27440
  }
27013
27441
  const previousState = op.previousState;
27014
27442
  const current = stateResources[op.logicalId];
27015
27443
  if (!current) {
27016
27444
  logger.warn(` Rollback: Cannot restore ${safe(op.logicalId)} — resource not found in current state`);
27017
- result.warnings++;
27445
+ recordRollbackSkip(s, op, "The resource is not in the current state, so the rollback had nothing to restore.");
27018
27446
  return;
27019
27447
  }
27020
27448
  if (!requireRestorableBaseline(previousState.properties, logger, {
@@ -27023,7 +27451,7 @@ async function replayRevert(s) {
27023
27451
  remedy: "Re-run `cdkd deploy` to re-converge it.",
27024
27452
  retry: `re-running ${rerunRollbackPhrase(ctx, "`cdkd rollback`")} retries this op`
27025
27453
  })) {
27026
- result.warnings++;
27454
+ recordRollbackSkip(s, op, ABSENT_BASELINE_SKIP_CAUSE);
27027
27455
  return;
27028
27456
  }
27029
27457
  logger.info(` Rollback: Restoring ${safe(op.logicalId)} (${safe(op.resourceType)}) to previous state`);
@@ -27102,7 +27530,7 @@ async function replayReverseReplacement(s) {
27102
27530
  remedy: "Re-run `cdkd deploy` to re-converge it.",
27103
27531
  retry: `re-running ${rerunRollbackPhrase(ctx, "`cdkd rollback`")} retries this op`
27104
27532
  })) {
27105
- result.warnings++;
27533
+ recordRollbackSkip(s, op, ABSENT_BASELINE_SKIP_CAUSE);
27106
27534
  return;
27107
27535
  }
27108
27536
  const resolvedPrevProps = await resolveReplayProps(prev.properties, resolver, secrets, ctx, op.logicalId) ?? {};
@@ -27261,7 +27689,8 @@ async function replayReverseReplacement(s) {
27261
27689
  physicalId: current.physicalId,
27262
27690
  reason: mask(survivorReason),
27263
27691
  ...survivorProvisionedBy && { provisionedBy: survivorProvisionedBy }
27264
- }
27692
+ },
27693
+ ...adoptedLiveNewResource && { reason: mask("The re-create returned the live new resource instead of re-creating the old one (its Create API is name-idempotent), so the replacement was NOT fully reversed: the old resource's original properties may not have been re-applied. Inspect it with `cdkd drift` and run `cdkd deploy` to reconcile.") }
27265
27694
  });
27266
27695
  }
27267
27696
 
@@ -27317,11 +27746,13 @@ async function replayRollbackUnbound(operations, stateResources, stackName, ctx,
27317
27746
  const result = {
27318
27747
  failures: 0,
27319
27748
  warnings: 0,
27749
+ skipped: 0,
27320
27750
  interrupted: false,
27321
27751
  orphaned: []
27322
27752
  };
27323
27753
  if (operations.length === 0) {
27324
27754
  ctx.logger.info("No completed operations to roll back.");
27755
+ await restoreHeldInlinePolicies(inlinePolicyWriters, stateResources, stackName, ctx, result);
27325
27756
  return result;
27326
27757
  }
27327
27758
  ctx.logger.info(`Rolling back ${operations.length} completed operation(s)...`);
@@ -27330,6 +27761,7 @@ async function replayRollbackUnbound(operations, stateResources, stackName, ctx,
27330
27761
  stackName
27331
27762
  });
27332
27763
  const resolver = new ReplayResolvers(ctx.region);
27764
+ inlinePolicyWriters.notePending(operations);
27333
27765
  const { createOps, otherOps } = partitionOps(operations);
27334
27766
  for (let i = otherOps.length - 1; i >= 0; i--) {
27335
27767
  if (options.isInterrupted?.()) {
@@ -27348,6 +27780,7 @@ async function replayRollbackUnbound(operations, stateResources, stackName, ctx,
27348
27780
  await replaySingle(op, stateResources, stackName, ctx, resolver, orphanLogicalIds, result, options.onOrphan, inlinePolicyWriters, options.afterOp, options.isInterrupted);
27349
27781
  }
27350
27782
  }
27783
+ await restoreHeldInlinePolicies(inlinePolicyWriters, stateResources, stackName, ctx, result);
27351
27784
  ctx.logger.info("Rollback completed. Some resources may remain if deletion failed.");
27352
27785
  ctx.recordEvent?.({
27353
27786
  eventType: "ROLLBACK_FINISHED",
@@ -27382,23 +27815,24 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
27382
27815
  mask,
27383
27816
  createRollbackRoute: void 0
27384
27817
  };
27818
+ const recordBefore = ownRecord(stateResources, op.logicalId);
27385
27819
  try {
27386
27820
  addRecordNames(opMasker, op, stateResources[op.logicalId]);
27387
27821
  switch (action) {
27388
27822
  case "unrecoverable-delete":
27389
27823
  logger.warn(` Rollback: Cannot restore deleted resource ${safe(op.logicalId)} (${safe(op.resourceType)}) — resource has already been deleted`);
27390
- result.warnings++;
27824
+ recordRollbackSkip(scope, op, "The failed deploy deleted this resource, and a rollback cannot re-create a deleted resource.");
27391
27825
  return;
27392
27826
  case "skip-already-done":
27393
27827
  logger.debug(` Rollback: ${safe(op.logicalId)} already reverted, skipping`);
27394
27828
  return;
27395
27829
  case "skip-mismatch":
27396
27830
  logger.warn(` Rollback: Skipping ${safe(op.logicalId)} — its physical id changed since the failed deploy (replaced by a later attempt); manual attention may be required`);
27397
- result.warnings++;
27831
+ recordRollbackSkip(scope, op, "Its physical id changed since the failed deploy (replaced by a later attempt), so the rollback left it as it is; manual attention may be required.");
27398
27832
  return;
27399
27833
  case "skip-absent":
27400
27834
  logger.warn(` Rollback: Cannot restore ${safe(op.logicalId)} — resource no longer in state, skipping`);
27401
- result.warnings++;
27835
+ recordRollbackSkip(scope, op, "The resource is no longer in state, so the rollback had nothing to restore.");
27402
27836
  return;
27403
27837
  case "refuse-replacement-routing": {
27404
27838
  const routing = resolveReplacementOldType(op);
@@ -27426,13 +27860,19 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
27426
27860
  ...failedRoute && { provisionedBy: failedRoute },
27427
27861
  error: maskedRollbackEventError(rollbackError, mask)
27428
27862
  });
27863
+ } finally {
27864
+ inlinePolicyWriters.noteOutcome(op, action === "skip-already-done" || ownRecord(stateResources, op.logicalId) !== recordBefore);
27429
27865
  }
27430
27866
  }
27867
+ function ownRecord(stateResources, logicalId) {
27868
+ return Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
27869
+ }
27431
27870
  async function replayFailedOperationsUnbound(failedOps, stateResources, stackName, ctx, options = {}) {
27432
27871
  const inlinePolicyWriters = options.inlinePolicyWriters ?? new RollbackInlinePolicyWriters();
27433
27872
  const result = {
27434
27873
  failures: 0,
27435
27874
  warnings: 0,
27875
+ skipped: 0,
27436
27876
  interrupted: false,
27437
27877
  remainingFailedOps: [],
27438
27878
  orphaned: []
@@ -27456,7 +27896,14 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
27456
27896
  const secrets = /* @__PURE__ */ new Map();
27457
27897
  const opMasker = createOpMasker(logger, secrets);
27458
27898
  const mask = opMasker.mask;
27899
+ const skipScope = {
27900
+ ctx,
27901
+ stackName,
27902
+ result,
27903
+ mask
27904
+ };
27459
27905
  let createRollbackRoute;
27906
+ const recordBefore = ownRecord(stateResources, op.logicalId);
27460
27907
  try {
27461
27908
  addRecordNames(opMasker, op, stateResources[op.logicalId]);
27462
27909
  switch (action) {
@@ -27465,15 +27912,15 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
27465
27912
  break;
27466
27913
  case "skip-failed-unknown":
27467
27914
  logger.warn(` Rollback: failed CREATE of ${safe(op.logicalId)} (${safe(op.resourceType)}) recorded no physical id — if it was partially created in AWS, delete it manually`);
27468
- result.warnings++;
27915
+ recordRollbackSkip(skipScope, op, "The failed CREATE recorded no physical id, so the rollback cannot address it; if it was partially created in AWS, delete it manually.");
27469
27916
  break;
27470
27917
  case "skip-failed-absent":
27471
27918
  logger.warn(` Rollback: cannot revert failed UPDATE of ${safe(op.logicalId)} — no previous state available, skipping`);
27472
- result.warnings++;
27919
+ recordRollbackSkip(skipScope, op, "No previous state is available for the failed UPDATE, so there is nothing to revert it to.");
27473
27920
  break;
27474
27921
  case "skip-failed-type-change":
27475
27922
  logger.warn(` Rollback: cannot revert failed UPDATE of ${shownLogicalId(op.logicalId)} in place — it was a Type change (${refusalResourceType(op.previousState?.resourceType)} -> ${refusalResourceType(op.resourceType)}), which is a replacement, and its remote state is unknown. Inspect it with \`cdkd drift\` and re-converge with \`cdkd deploy\`. Skipping.`);
27476
- result.warnings++;
27923
+ recordRollbackSkip(skipScope, op, `The failed UPDATE was a Type change (${String(op.previousState?.resourceType)} -> ${String(op.resourceType)}), which is a replacement, and its remote state is unknown, so it cannot be reverted in place.`);
27477
27924
  break;
27478
27925
  case "orphan-failed-create-retain": {
27479
27926
  const failedCreateRecord = stateResources[op.logicalId];
@@ -27546,7 +27993,7 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
27546
27993
  remedy: "Inspect it with `cdkd drift` (this op died mid-flight, so its remote state is unknown) and re-converge with `cdkd drift --revert` or `cdkd deploy`.",
27547
27994
  retry: "re-running `cdkd rollback --revert-failed` retries this op (a plain `cdkd rollback` replays only the COMPLETED ops and then pops the whole segment, discarding this record)"
27548
27995
  })) {
27549
- result.warnings++;
27996
+ recordRollbackSkip(skipScope, op, ABSENT_BASELINE_SKIP_CAUSE);
27550
27997
  break;
27551
27998
  }
27552
27999
  logger.info(` Rollback: force-reverting failed UPDATE of ${safe(op.logicalId)} (${safe(op.resourceType)}) to its pre-deploy properties (--revert-failed; remote state is unknown)`);
@@ -27625,7 +28072,9 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
27625
28072
  error: maskedRollbackEventError(revertError, mask)
27626
28073
  });
27627
28074
  }
28075
+ inlinePolicyWriters.noteOutcome(op, action === "skip-failed-noop" || ownRecord(stateResources, op.logicalId) !== recordBefore);
27628
28076
  }
28077
+ if (result.interrupted) await restoreHeldInlinePolicies(inlinePolicyWriters, stateResources, stackName, ctx, result, { refuseAll: true });
27629
28078
  if (emitEnvelope) ctx.recordEvent?.({
27630
28079
  eventType: "ROLLBACK_FINISHED",
27631
28080
  stackName
@@ -28096,6 +28545,7 @@ async function performRollback(completedOperations, stateResources, stackName, p
28096
28545
  return {
28097
28546
  failures: result.failures,
28098
28547
  warnings: result.warnings + run.warnings,
28548
+ skipped: result.skipped,
28099
28549
  orphaned: result.orphaned,
28100
28550
  settledNested: run.settled
28101
28551
  };
@@ -28145,7 +28595,7 @@ async function settleJournalAfterCleanRollback(stackName, failedOperations, init
28145
28595
  this.logger.warn(safeMsg`Failed to settle the rollback journal after the clean rollback: ${err instanceof Error ? err.message : String(err)}. ` + `The journal keeps the full segment; a later rollback replay is idempotent.`);
28146
28596
  return false;
28147
28597
  }
28148
- await this.writeRollbackJournalSegment(stackName, [], failedOperations, "auto-rollback-clean", initialDeploy);
28598
+ if (!await this.writeRollbackJournalSegment(stackName, [], failedOperations, "auto-rollback-clean", initialDeploy)) return true;
28149
28599
  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", [{
28150
28600
  value: stackName,
28151
28601
  hole: "stack"
@@ -28193,7 +28643,7 @@ function producerRegionEvidence(previousState) {
28193
28643
  return inheritProducerRegions(own, this.options.inheritedProducerRegions?.());
28194
28644
  }
28195
28645
  async function writeRollbackJournalSegment(stackName, completedOperations, failedOperations, reason, initialDeploy, nestedPending) {
28196
- if (!nestedPending && completedOperations.length === 0 && failedOperations.length === 0) return;
28646
+ if (!nestedPending && completedOperations.length === 0 && failedOperations.length === 0) return false;
28197
28647
  const redactedCompleted = this.redactOperationsForJournal(completedOperations);
28198
28648
  const redactedFailed = this.redactOperationsForJournal(failedOperations);
28199
28649
  try {
@@ -28212,8 +28662,10 @@ async function writeRollbackJournalSegment(stackName, completedOperations, faile
28212
28662
  };
28213
28663
  await this.stateBackend.appendRollbackJournalSegment(stackName, this.stackRegion, segment);
28214
28664
  this.logger.debug(`Rollback journal segment written (${reason})`);
28665
+ return true;
28215
28666
  } catch (journalError) {
28216
28667
  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.`);
28668
+ return false;
28217
28669
  }
28218
28670
  }
28219
28671
 
@@ -29147,6 +29599,45 @@ function hasUnpersistedHeals(resources) {
29147
29599
  return false;
29148
29600
  }
29149
29601
 
29602
+ //#endregion
29603
+ //#region src/deployment/deploy-engine/record-shape.ts
29604
+ function auditResolvedAssetReferences(logicalId, resourceType, resolvedProps) {
29605
+ const redirect = this.options.assetRedirect;
29606
+ if (!redirect) return;
29607
+ const findings = findUnrewrittenAssetReferences(resolvedProps, redirect);
29608
+ if (findings.length === 0) return;
29609
+ const detail = findings.map((f) => ` - ${f.path}: still references '${f.source}'`).join("\n");
29610
+ 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);
29611
+ }
29612
+ function extractAllDependencies(template, logicalId) {
29613
+ const resource = template?.Resources?.[logicalId];
29614
+ if (!resource) return void 0;
29615
+ const parser = new TemplateParser();
29616
+ const parameterNames = new Set(Object.keys(template?.Parameters ?? {}));
29617
+ const deps = [...parser.extractDependencies(resource)].filter((dep) => !parameterNames.has(dep));
29618
+ return deps.length > 0 ? deps : void 0;
29619
+ }
29620
+ function propertiesToRecord(desiredProperties, result, resourceType, provisionedBy) {
29621
+ if (result.effectiveProperties) return markWrittenFromDeployedTemplate(provisionedBy === "sdk" ? withoutSilentDropProperties(resourceType, result.effectiveProperties) : result.effectiveProperties);
29622
+ const written = provisionedBy === "sdk" ? withoutSilentDropProperties(resourceType, desiredProperties) : desiredProperties;
29623
+ return markWrittenFromDeployedTemplate(markSameGenerationBag(written));
29624
+ }
29625
+ function extractTemplateAttributes(template, logicalId) {
29626
+ const resource = template?.Resources?.[logicalId];
29627
+ return {
29628
+ deletionPolicy: resource?.DeletionPolicy,
29629
+ updateReplacePolicy: resource?.UpdateReplacePolicy
29630
+ };
29631
+ }
29632
+ function acceptedCreateOnlyDropsField(recordedProperties, resourceType, provisionedBy, mode, previous) {
29633
+ if (provisionedBy !== "sdk") return { acceptedCreateOnlyDrops: void 0 };
29634
+ const createOnly = getPropertyCoverage(resourceType)?.createOnlyDrops;
29635
+ if (createOnly === void 0 || createOnly.size === 0) return { acceptedCreateOnlyDrops: void 0 };
29636
+ const carried = mode === "in-place" ? acceptedCreateOnlyDropsOf(previous) : void 0;
29637
+ const names = findSilentDropProperties(resourceType, recordedProperties).map(({ property }) => property).filter((property) => createOnly.has(property) && (carried === void 0 || carried.has(property)));
29638
+ return { acceptedCreateOnlyDrops: names.length > 0 ? names : void 0 };
29639
+ }
29640
+
29150
29641
  //#endregion
29151
29642
  //#region src/utils/resource-line.ts
29152
29643
  function formatResourceLine(op, logicalId, resourceType, verbOverride) {
@@ -29160,6 +29651,75 @@ function formatResourceLine(op, logicalId, resourceType, verbOverride) {
29160
29651
  }
29161
29652
  }
29162
29653
 
29654
+ //#endregion
29655
+ //#region src/deployment/prior-attempt-scope.ts
29656
+ const priorAttemptStore = new AsyncLocalStorage();
29657
+ function withPriorAttempts(lookup, fn) {
29658
+ return priorAttemptStore.run(lookup, fn);
29659
+ }
29660
+ function priorAttemptLookup(logicalId, attempts) {
29661
+ let landed = false;
29662
+ return {
29663
+ logicalId,
29664
+ attempts,
29665
+ notePossiblyLanded: () => {
29666
+ landed = true;
29667
+ },
29668
+ possiblyLanded: () => landed
29669
+ };
29670
+ }
29671
+ function getPriorAttempts(logicalId) {
29672
+ const bound = priorAttemptStore.getStore();
29673
+ return bound?.logicalId === logicalId ? bound : void 0;
29674
+ }
29675
+ function priorAttemptsInJournal(journal, logicalId, resourceType) {
29676
+ let bags = [];
29677
+ for (const segment of journal?.segments ?? []) {
29678
+ if (segment.operations.some((op) => op.logicalId === logicalId)) bags = [];
29679
+ for (const op of segment.failedOperations ?? []) {
29680
+ if (op.logicalId !== logicalId || op.resourceType !== resourceType) continue;
29681
+ if (op.changeType === "DELETE" || !isBag(op.attemptedProperties)) continue;
29682
+ if (recordedAsNewResource(op)) continue;
29683
+ bags.push(op.attemptedProperties);
29684
+ }
29685
+ if (segment.supersededLogicalIds?.includes(logicalId)) bags = [];
29686
+ }
29687
+ return bags;
29688
+ }
29689
+ function recordedAsNewResource(op) {
29690
+ if (typeof op.physicalId !== "string" || op.physicalId === "") return false;
29691
+ if (op.changeType === "CREATE") return true;
29692
+ const previous = op.previousState?.physicalId;
29693
+ return typeof previous === "string" && previous !== op.physicalId;
29694
+ }
29695
+ function isBag(value) {
29696
+ return typeof value === "object" && value !== null && !Array.isArray(value);
29697
+ }
29698
+ const REFUSED_BEFORE_APPLYING = Symbol.for("cdkd.refusedBeforeApplying");
29699
+ const MAX_CAUSE_DEPTH = 10;
29700
+ function markRefusedBeforeApplying(error) {
29701
+ if (!Object.isExtensible(error)) return error;
29702
+ Object.defineProperty(error, REFUSED_BEFORE_APPLYING, {
29703
+ value: true,
29704
+ enumerable: false,
29705
+ configurable: true,
29706
+ writable: false
29707
+ });
29708
+ return error;
29709
+ }
29710
+ function isRefusedBeforeApplying(error, logicalId) {
29711
+ let current = error;
29712
+ for (let depth = 0; depth < MAX_CAUSE_DEPTH && current != null; depth++) {
29713
+ if (typeof current === "object" || typeof current === "function") {
29714
+ const linkId = current.logicalId;
29715
+ if (typeof linkId === "string" && linkId !== logicalId) return false;
29716
+ if (current[REFUSED_BEFORE_APPLYING] === true) return true;
29717
+ }
29718
+ current = current.cause;
29719
+ }
29720
+ return false;
29721
+ }
29722
+
29163
29723
  //#endregion
29164
29724
  //#region src/deployment/deploy-engine/create.ts
29165
29725
  async function provisionCreate(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress) {
@@ -29202,10 +29762,12 @@ async function provisionCreate(logicalId, change, stateResources, stackName, tem
29202
29762
  this.registerNoEchoAttributes(logicalId, result, createSecrets, resolvedProps);
29203
29763
  const dependencies = this.extractAllDependencies(template, logicalId);
29204
29764
  const templateAttrs = this.extractTemplateAttributes(template, logicalId);
29765
+ const recordedProperties = this.propertiesToRecord(resolvedProps, result, resourceType, createDecision.provisionedBy);
29205
29766
  stateResources[logicalId] = {
29206
29767
  physicalId: result.physicalId,
29207
29768
  resourceType,
29208
- properties: this.propertiesToRecord(resolvedProps, result, resourceType, createDecision.provisionedBy),
29769
+ properties: recordedProperties,
29770
+ ...acceptedCreateOnlyDropsField(recordedProperties, resourceType, createDecision.provisionedBy, "new-resource"),
29209
29771
  ...result.attributes && { attributes: result.attributes },
29210
29772
  ...dependencies && dependencies.length > 0 && { dependencies },
29211
29773
  ...templateAttrs,
@@ -29239,7 +29801,7 @@ async function refuseTakenCreateName(input) {
29239
29801
  const named = `${question.property} ${shown(question.desiredName)}`;
29240
29802
  const adoptsText = "its create API hands back or overwrites an existing resource of that name instead of refusing it";
29241
29803
  const refuse = (message, cause) => {
29242
- throw markNonRetryable(new CdkdError(maskName(message), "NAMED_CREATE_COLLISION", cause instanceof Error ? cause : void 0));
29804
+ throw markNonRetryable(markRefusedBeforeApplying(new CdkdError(maskName(message), "NAMED_CREATE_COLLISION", cause instanceof Error ? cause : void 0)));
29243
29805
  };
29244
29806
  let knownPhysicalId;
29245
29807
  const byArn = ["AWS::SNS::Topic", "AWS::StepFunctions::StateMachine"].includes(resourceType) ? createLookupArn(resourceType, question.desiredName, await getAccountInfo(this.stackRegion)) : void 0;
@@ -29272,262 +29834,6 @@ async function refuseTakenCreateName(input) {
29272
29834
  return refuse(`${subject} is created with ${named}, and an existing resource (${shown(holderId)}) already holds that name. Since ${adoptsText}, creating it would take that resource over and record it as this stack's, for a later \`cdkd destroy\` to delete. Nothing was created. Choose a name no other resource holds; ` + ownRemedy);
29273
29835
  }
29274
29836
 
29275
- //#endregion
29276
- //#region src/deployment/deploy-value-equality.ts
29277
- function isReplacementCeiling(pc) {
29278
- return pc.requiresReplacement && (pc.inPlacePropagated === true || pc.replacementPropagated === true);
29279
- }
29280
- function keyOrderFreeJson(value) {
29281
- return JSON.stringify(value, (_key, node) => {
29282
- if (node === null || typeof node !== "object" || Array.isArray(node)) return node;
29283
- const sorted = Object.create(null);
29284
- for (const key of Object.keys(node).sort()) sorted[key] = node[key];
29285
- return sorted;
29286
- });
29287
- }
29288
- function liveHoldsFreshLeaves(live, leaves) {
29289
- for (const leaf of leaves) {
29290
- let node = live;
29291
- for (const segment of leaf.path) {
29292
- if (typeof segment === "number") {
29293
- if (!Array.isArray(node) || segment >= node.length) return false;
29294
- node = node[segment];
29295
- continue;
29296
- }
29297
- if (node === null || typeof node !== "object" || Array.isArray(node)) return false;
29298
- if (!Object.prototype.hasOwnProperty.call(node, segment)) return false;
29299
- node = node[segment];
29300
- }
29301
- if (typeof node !== "string" || node !== leaf.plaintext) return false;
29302
- }
29303
- return true;
29304
- }
29305
- function outputMapsEqual(a, b) {
29306
- return deepEqualValue(a, b);
29307
- }
29308
- function deepEqualValue(a, b) {
29309
- if (a === b) return true;
29310
- if (a == null || b == null) return a === b;
29311
- if (typeof a !== typeof b) return false;
29312
- if (typeof a !== "object") return false;
29313
- if (Array.isArray(a) || Array.isArray(b)) {
29314
- if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
29315
- return a.every((v, i) => deepEqualValue(v, b[i]));
29316
- }
29317
- const ao = a;
29318
- const bo = b;
29319
- const ak = Object.keys(ao);
29320
- if (ak.length !== Object.keys(bo).length) return false;
29321
- for (const k of ak) {
29322
- if (!Object.prototype.hasOwnProperty.call(bo, k)) return false;
29323
- if (!deepEqualValue(ao[k], bo[k])) return false;
29324
- }
29325
- return true;
29326
- }
29327
-
29328
- //#endregion
29329
- //#region src/deployment/deploy-engine/update.ts
29330
- async function provisionUpdate(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress) {
29331
- const resourceType = change.resourceType;
29332
- const existingState = stateResources[logicalId];
29333
- const renderer = getLiveRenderer();
29334
- const currentResource = existingState;
29335
- if (!currentResource) throw new Error(`Cannot update ${logicalId}: resource not found in state`);
29336
- const oldResourceType = currentResource.resourceType;
29337
- const typeChanged = oldResourceType !== resourceType;
29338
- const desiredProps = change.desiredProperties || {};
29339
- const currentProps = change.currentProperties || {};
29340
- const currentPropsAsWritten = currentResource.provisionedBy === "cc-api" ? currentProps : withoutSilentDropProperties(resourceType, currentProps);
29341
- const context = this.buildResolverContext({
29342
- template,
29343
- resources: stateResources,
29344
- ...parameterValues && { parameters: parameterValues },
29345
- ...conditions && { conditions },
29346
- redactedAttributeReads: []
29347
- }, stackName);
29348
- const updateSecrets = context.recordedSecretValues ?? /* @__PURE__ */ new Map();
29349
- this.perResourceSecrets.set(logicalId, updateSecrets);
29350
- const resolvedProps = await this.resolver.resolve(desiredProps, context);
29351
- this.perResourceTemplateProps.set(logicalId, desiredProps);
29352
- this.perResourceResolvedType.set(logicalId, resourceType);
29353
- recordNestedStackParameterExpressions(updateSecrets, resourceType, resolvedProps, desiredProps);
29354
- this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
29355
- const lostCandidate = childLostWithRecreatedParent({
29356
- resourceType,
29357
- templateProperties: desiredProps,
29358
- recreatedUnderSameId: this.recreatedUnderSameId,
29359
- recordedTypeOf: (id) => Object.hasOwn(stateResources, id) ? stateResources[id]?.resourceType : void 0,
29360
- conditions
29361
- });
29362
- const lostChild = lostCandidate?.mode === "reattach" || lostCandidate !== void 0 && Object.hasOwn(resolvedProps, lostCandidate.property) && Object.hasOwn(currentProps, lostCandidate.property) && keyOrderFreeJson(resolvedProps[lostCandidate.property]) === keyOrderFreeJson(currentProps[lostCandidate.property]) ? lostCandidate : void 0;
29363
- const lostWithParent = lostChild?.mode === "recreate" ? lostChild.parent : void 0;
29364
- const suppliesFreshMaskOnlyValue = carriesFreshNoEchoValue(resolvedProps, updateSecrets);
29365
- const desiredForSkipCheck = redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), updateSecrets, desiredProps);
29366
- const allowedSilentDrops = this.providerRegistry.getAllowedUnsupportedProperties?.();
29367
- const desiredForSkipCheckAsWritten = currentResource.provisionedBy !== "cc-api" && allowedSilentDrops ? withoutAcceptedSilentDropProperties(resourceType, desiredForSkipCheck, allowedSilentDrops, currentResource.properties) : desiredForSkipCheck;
29368
- const applyAttributeOnlyUpdate = (attributeChanges) => {
29369
- const attrSummary = attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
29370
- this.logger.info(safeMsg` ↻ ${logicalId} (${resourceType}) attribute update: ${attrSummary}`);
29371
- stateResources[logicalId] = {
29372
- ...currentResource,
29373
- ...this.extractTemplateAttributes(template, logicalId)
29374
- };
29375
- if (counts) counts.updated++;
29376
- if (progress) progress.current++;
29377
- const attrPrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
29378
- renderer.removeTask(logicalId);
29379
- this.logger.info(safeMsg`${attrPrefix}${formatResourceLine("updated", logicalId, resourceType, "updated (metadata)")}`);
29380
- };
29381
- if (!typeChanged && !suppliesFreshMaskOnlyValue && lostChild === void 0 && this.recreateDirectionFor(stackName, logicalId) === void 0 && keyOrderFreeJson(desiredForSkipCheckAsWritten) === keyOrderFreeJson(currentPropsAsWritten)) {
29382
- if (change.attributeChanges && change.attributeChanges.length > 0) {
29383
- applyAttributeOnlyUpdate(change.attributeChanges);
29384
- return;
29385
- }
29386
- this.logger.debug(`Skipping ${logicalId}: no actual changes after intrinsic function resolution`);
29387
- if (counts) counts.skipped++;
29388
- return;
29389
- }
29390
- this.refuseRedactedAttributeReads(logicalId, resourceType, context);
29391
- this.attemptedResolvedProps.set(logicalId, resolvedProps);
29392
- const noEchoHeldPaths = /* @__PURE__ */ new Set();
29393
- if (change.propertyChanges?.some((pc) => pc.requiresReplacement) === true) {
29394
- let readback;
29395
- const lowered = [];
29396
- for (const pc of change.propertyChanges) {
29397
- if (!pc.requiresReplacement) {
29398
- lowered.push(pc);
29399
- continue;
29400
- }
29401
- const freshLeaves = freshNoEchoLeafPositions(resolvedProps[pc.path], updateSecrets);
29402
- if (!isReplacementCeiling(pc) && freshLeaves.length === 0) {
29403
- lowered.push(pc);
29404
- continue;
29405
- }
29406
- const moved = keyOrderFreeJson(desiredForSkipCheckAsWritten[pc.path]) !== keyOrderFreeJson(currentPropsAsWritten[pc.path]);
29407
- const conditionalVerdict = moved && !typeChanged && isReplacementCeiling(pc) ? this.diffCalculator.conditionalReplacementVerdict?.(resourceType, pc.path, currentPropsAsWritten[pc.path], desiredForSkipCheckAsWritten[pc.path]) : void 0;
29408
- if (moved && conditionalVerdict !== false) {
29409
- lowered.push(pc);
29410
- continue;
29411
- }
29412
- if (freshLeaves.length > 0) {
29413
- if (typeChanged) {
29414
- lowered.push(pc);
29415
- continue;
29416
- }
29417
- readback ??= this.readReaderForFreshNoEchoCeiling(logicalId, currentResource, updateSecrets);
29418
- const read = await readback;
29419
- let verdict;
29420
- if ("failure" in read) verdict = read.failure;
29421
- else if (!Object.prototype.hasOwnProperty.call(read.live, pc.path)) verdict = "not-readable";
29422
- else verdict = liveHoldsFreshLeaves(read.live[pc.path], freshLeaves) ? "held" : "differs";
29423
- if (verdict !== "held") {
29424
- this.logger.warn(safeMsg`${logicalId}.${pc.path} carries a NoEcho value that AWS could not confirm unchanged (${verdict}): replacement kept.`);
29425
- lowered.push(pc);
29426
- continue;
29427
- }
29428
- this.logger.debug(safeMsg`${logicalId}.${pc.path} carries a NoEcho value AWS already holds: not replaced.`);
29429
- noEchoHeldPaths.add(pc.path);
29430
- }
29431
- lowered.push({
29432
- ...pc,
29433
- requiresReplacement: false
29434
- });
29435
- }
29436
- change.propertyChanges = lowered;
29437
- }
29438
- if (noEchoHeldPaths.size > 0 && !typeChanged && lostChild === void 0 && this.recreateDirectionFor(stackName, logicalId) === void 0 && keyOrderFreeJson(desiredForSkipCheckAsWritten) === keyOrderFreeJson(currentPropsAsWritten) && Object.entries(resolvedProps).every(([key, value]) => noEchoHeldPaths.has(key) || freshNoEchoLeafPositions(value, updateSecrets).length === 0)) {
29439
- this.logger.debug(safeMsg`Skipping ${logicalId}: AWS already holds every NoEcho value it carries, and nothing else changed`);
29440
- this.attemptedResolvedProps.delete(logicalId);
29441
- if (change.attributeChanges && change.attributeChanges.length > 0) {
29442
- applyAttributeOnlyUpdate(change.attributeChanges);
29443
- return;
29444
- }
29445
- if (counts) counts.skipped++;
29446
- return;
29447
- }
29448
- const propertyDrivenReplacement = typeChanged || change.propertyChanges?.some((pc) => pc.requiresReplacement);
29449
- const recreateTargets = this.options.recreateTargets?.stackName === stackName ? this.options.recreateTargets : void 0;
29450
- const recreateViaCcApi = recreateTargets?.viaCcApi.has(logicalId) ?? false;
29451
- const recreateViaSdkProvider = recreateTargets?.viaSdkProvider.has(logicalId) ?? false;
29452
- const recreateFlagged = recreateViaCcApi || recreateViaSdkProvider;
29453
- const needsReplacement = propertyDrivenReplacement || recreateFlagged || lostWithParent !== void 0;
29454
- const liveLabel = this.liveTaskLabels.get(logicalId);
29455
- if (needsReplacement && liveLabel !== void 0 && !liveLabel.replacing) {
29456
- const label = `Replacing ${logicalId} (${resourceType})${this.peekRoutingForLabel(change, currentResource, stackName, logicalId, true, this.recreateDirectionFor(stackName, logicalId)) === "cc-api" ? " [CC API]" : ""}`;
29457
- this.liveTaskLabels.set(logicalId, {
29458
- label,
29459
- replacing: true,
29460
- ...liveLabel.warnSuffix !== void 0 && { warnSuffix: liveLabel.warnSuffix }
29461
- });
29462
- renderer.updateTaskLabel(logicalId, `${label}${liveLabel.warnSuffix ?? ""}`);
29463
- } else if (!needsReplacement && liveLabel !== void 0 && liveLabel.replacing) {
29464
- const label = `Updating ${logicalId} (${resourceType})${this.peekRoutingForLabel(change, currentResource, stackName, logicalId, false, this.recreateDirectionFor(stackName, logicalId)) === "cc-api" ? " [CC API]" : ""}`;
29465
- this.liveTaskLabels.set(logicalId, {
29466
- label,
29467
- replacing: false,
29468
- ...liveLabel.warnSuffix !== void 0 && { warnSuffix: liveLabel.warnSuffix }
29469
- });
29470
- renderer.updateTaskLabel(logicalId, `${label}${liveLabel.warnSuffix ?? ""}`);
29471
- }
29472
- const dependencies = this.extractAllDependencies(template, logicalId);
29473
- const updateReplacePolicy = template?.Resources?.[logicalId]?.UpdateReplacePolicy;
29474
- const markRestored = (outcome) => {
29475
- if (lostChild === void 0) return outcome;
29476
- if (this.updatesThatSentNothing.has(logicalId)) {
29477
- this.logger.warn(survivesParent(resourceType) ? safeMsg` ⚠ ${logicalId} lost its attachment to ${lostChild.parent}, which was re-created, but its update sent no change (it is recorded on Cloud Control, which patches record against template); it may no longer be attached to ${lostChild.parent}. Attach it there by hand.` : safeMsg` ⚠ ${logicalId} went with ${lostChild.parent}, which was re-created, but its update sent no change (it is recorded on Cloud Control, which patches record against template); its policy may be missing from ${lostChild.parent}. Re-run with --recreate-via-sdk-provider ${logicalId} to write it again.`);
29478
- return outcome;
29479
- }
29480
- this.restoredLostChildren.add(logicalId);
29481
- return outcome;
29482
- };
29483
- if (needsReplacement) return markRestored(await this.updateByReplacement({
29484
- change,
29485
- counts,
29486
- currentProps,
29487
- currentResource,
29488
- dependencies,
29489
- logicalId,
29490
- oldResourceType,
29491
- progress,
29492
- propertyDrivenReplacement,
29493
- recreateFlagged,
29494
- recreateViaCcApi,
29495
- recreateViaSdkProvider,
29496
- renderer,
29497
- resolvedProps,
29498
- resourceType,
29499
- stackName,
29500
- stateResources,
29501
- template,
29502
- typeChanged,
29503
- updateReplacePolicy,
29504
- updateSecrets,
29505
- lostWithParent
29506
- }));
29507
- return markRestored(await this.updateInPlace({
29508
- conditions,
29509
- counts,
29510
- currentProps,
29511
- currentPropsAsWritten,
29512
- currentResource,
29513
- dependencies,
29514
- desiredForSkipCheckAsWritten,
29515
- logicalId,
29516
- noEchoHeldPaths,
29517
- parameterValues,
29518
- progress,
29519
- renderer,
29520
- resolvedProps,
29521
- resourceType,
29522
- stackName,
29523
- stateResources,
29524
- template,
29525
- updateReplacePolicy,
29526
- updateSecrets,
29527
- reattach: lostChild?.mode === "reattach"
29528
- }));
29529
- }
29530
-
29531
29837
  //#endregion
29532
29838
  //#region src/provisioning/data-delete-intent.ts
29533
29839
  const S3_AUTO_DELETE_OBJECTS_TAG = "aws-cdk:auto-delete-objects";
@@ -32235,6 +32541,286 @@ function recordedProtectionNote(evidence, flags) {
32235
32541
  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}.`;
32236
32542
  }
32237
32543
 
32544
+ //#endregion
32545
+ //#region src/deployment/deploy-value-equality.ts
32546
+ function isReplacementCeiling(pc) {
32547
+ return pc.requiresReplacement && (pc.inPlacePropagated === true || pc.replacementPropagated === true);
32548
+ }
32549
+ function keyOrderFreeJson(value) {
32550
+ return JSON.stringify(value, (_key, node) => {
32551
+ if (node === null || typeof node !== "object" || Array.isArray(node)) return node;
32552
+ const sorted = Object.create(null);
32553
+ for (const key of Object.keys(node).sort()) sorted[key] = node[key];
32554
+ return sorted;
32555
+ });
32556
+ }
32557
+ function liveHoldsFreshLeaves(live, leaves) {
32558
+ for (const leaf of leaves) {
32559
+ let node = live;
32560
+ for (const segment of leaf.path) {
32561
+ if (typeof segment === "number") {
32562
+ if (!Array.isArray(node) || segment >= node.length) return false;
32563
+ node = node[segment];
32564
+ continue;
32565
+ }
32566
+ if (node === null || typeof node !== "object" || Array.isArray(node)) return false;
32567
+ if (!Object.prototype.hasOwnProperty.call(node, segment)) return false;
32568
+ node = node[segment];
32569
+ }
32570
+ if (typeof node !== "string" || node !== leaf.plaintext) return false;
32571
+ }
32572
+ return true;
32573
+ }
32574
+ function outputMapsEqual(a, b) {
32575
+ return deepEqualValue(a, b);
32576
+ }
32577
+ function deepEqualValue(a, b) {
32578
+ if (a === b) return true;
32579
+ if (a == null || b == null) return a === b;
32580
+ if (typeof a !== typeof b) return false;
32581
+ if (typeof a !== "object") return false;
32582
+ if (Array.isArray(a) || Array.isArray(b)) {
32583
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
32584
+ return a.every((v, i) => deepEqualValue(v, b[i]));
32585
+ }
32586
+ const ao = a;
32587
+ const bo = b;
32588
+ const ak = Object.keys(ao);
32589
+ if (ak.length !== Object.keys(bo).length) return false;
32590
+ for (const k of ak) {
32591
+ if (!Object.prototype.hasOwnProperty.call(bo, k)) return false;
32592
+ if (!deepEqualValue(ao[k], bo[k])) return false;
32593
+ }
32594
+ return true;
32595
+ }
32596
+
32597
+ //#endregion
32598
+ //#region src/deployment/deploy-engine/update.ts
32599
+ async function provisionUpdate(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress) {
32600
+ const resourceType = change.resourceType;
32601
+ const existingState = stateResources[logicalId];
32602
+ const renderer = getLiveRenderer();
32603
+ const currentResource = existingState;
32604
+ if (!currentResource) throw new Error(`Cannot update ${logicalId}: resource not found in state`);
32605
+ const oldResourceType = currentResource.resourceType;
32606
+ const typeChanged = oldResourceType !== resourceType;
32607
+ const desiredProps = change.desiredProperties || {};
32608
+ const currentProps = change.currentProperties || {};
32609
+ const context = this.buildResolverContext({
32610
+ template,
32611
+ resources: stateResources,
32612
+ ...parameterValues && { parameters: parameterValues },
32613
+ ...conditions && { conditions },
32614
+ redactedAttributeReads: []
32615
+ }, stackName);
32616
+ const updateSecrets = context.recordedSecretValues ?? /* @__PURE__ */ new Map();
32617
+ this.perResourceSecrets.set(logicalId, updateSecrets);
32618
+ const resolvedProps = await this.resolver.resolve(desiredProps, context);
32619
+ this.perResourceTemplateProps.set(logicalId, desiredProps);
32620
+ this.perResourceResolvedType.set(logicalId, resourceType);
32621
+ recordNestedStackParameterExpressions(updateSecrets, resourceType, resolvedProps, desiredProps);
32622
+ this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
32623
+ const lostCandidate = childLostWithRecreatedParent({
32624
+ resourceType,
32625
+ templateProperties: desiredProps,
32626
+ recreatedUnderSameId: this.recreatedUnderSameId,
32627
+ recordedTypeOf: (id) => Object.hasOwn(stateResources, id) ? stateResources[id]?.resourceType : void 0,
32628
+ conditions
32629
+ });
32630
+ const lostChild = lostCandidate?.mode === "reattach" || lostCandidate !== void 0 && Object.hasOwn(resolvedProps, lostCandidate.property) && Object.hasOwn(currentProps, lostCandidate.property) && keyOrderFreeJson(resolvedProps[lostCandidate.property]) === keyOrderFreeJson(currentProps[lostCandidate.property]) ? lostCandidate : void 0;
32631
+ const lostWithParent = lostChild?.mode === "recreate" ? lostChild.parent : void 0;
32632
+ const suppliesFreshMaskOnlyValue = carriesFreshNoEchoValue(resolvedProps, updateSecrets);
32633
+ const movedMasked = new Set(movedMaskedProperties(currentResource, desiredProps));
32634
+ const desiredForSkipCheck = redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), updateSecrets, desiredProps);
32635
+ const allowedSilentDrops = this.providerRegistry.getAllowedUnsupportedProperties?.();
32636
+ const desiredForSkipCheckAsWritten = currentResource.provisionedBy !== "cc-api" && allowedSilentDrops ? withoutAcceptedSilentDropProperties(resourceType, desiredForSkipCheck, allowedSilentDrops, currentResource.properties) : desiredForSkipCheck;
32637
+ const allowedForRecord = allowedSilentDrops ?? /* @__PURE__ */ new Set();
32638
+ const createOnlyEvidence = acceptedCreateOnlyDropsOf(currentResource);
32639
+ const currentPropsAsWritten = currentResource.provisionedBy === "cc-api" ? currentProps : withoutUnwrittenSilentDropProperties(resourceType, currentProps, desiredForSkipCheck, allowedForRecord, createOnlyEvidence);
32640
+ const recordMatchesDesired = movedMasked.size === 0 && keyOrderFreeJson(desiredForSkipCheckAsWritten) === keyOrderFreeJson(currentPropsAsWritten);
32641
+ const applyAttributeOnlyUpdate = (attributeChanges) => {
32642
+ const attrSummary = attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
32643
+ this.logger.info(safeMsg` ↻ ${logicalId} (${resourceType}) attribute update: ${attrSummary}`);
32644
+ stateResources[logicalId] = {
32645
+ ...currentResource,
32646
+ ...this.extractTemplateAttributes(template, logicalId)
32647
+ };
32648
+ if (counts) counts.updated++;
32649
+ if (progress) progress.current++;
32650
+ const attrPrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
32651
+ renderer.removeTask(logicalId);
32652
+ this.logger.info(safeMsg`${attrPrefix}${formatResourceLine("updated", logicalId, resourceType, "updated (metadata)")}`);
32653
+ };
32654
+ if (!typeChanged && !suppliesFreshMaskOnlyValue && lostChild === void 0 && this.recreateDirectionFor(stackName, logicalId) === void 0 && recordMatchesDesired) {
32655
+ if (change.attributeChanges && change.attributeChanges.length > 0) {
32656
+ applyAttributeOnlyUpdate(change.attributeChanges);
32657
+ return;
32658
+ }
32659
+ this.logger.debug(`Skipping ${logicalId}: no actual changes after intrinsic function resolution`);
32660
+ if (counts) counts.skipped++;
32661
+ return;
32662
+ }
32663
+ this.refuseRedactedAttributeReads(logicalId, resourceType, context);
32664
+ this.attemptedResolvedProps.set(logicalId, resolvedProps);
32665
+ const noEchoHeldPaths = /* @__PURE__ */ new Set();
32666
+ if (change.propertyChanges?.some((pc) => pc.requiresReplacement) === true) {
32667
+ let readback;
32668
+ const lowered = [];
32669
+ for (const pc of change.propertyChanges) {
32670
+ if (!pc.requiresReplacement) {
32671
+ lowered.push(pc);
32672
+ continue;
32673
+ }
32674
+ const freshLeaves = freshNoEchoLeafPositions(resolvedProps[pc.path], updateSecrets);
32675
+ if (!isReplacementCeiling(pc) && freshLeaves.length === 0) {
32676
+ lowered.push(pc);
32677
+ continue;
32678
+ }
32679
+ const moved = movedMasked.has(pc.path) || keyOrderFreeJson(desiredForSkipCheckAsWritten[pc.path]) !== keyOrderFreeJson(currentPropsAsWritten[pc.path]);
32680
+ const conditionalVerdict = moved && !typeChanged && isReplacementCeiling(pc) ? this.diffCalculator.conditionalReplacementVerdict?.(resourceType, pc.path, currentPropsAsWritten[pc.path], desiredForSkipCheckAsWritten[pc.path]) : void 0;
32681
+ if (moved && conditionalVerdict !== false) {
32682
+ lowered.push(pc);
32683
+ continue;
32684
+ }
32685
+ if (freshLeaves.length > 0) {
32686
+ if (typeChanged) {
32687
+ lowered.push(pc);
32688
+ continue;
32689
+ }
32690
+ readback ??= this.readReaderForFreshNoEchoCeiling(logicalId, currentResource, updateSecrets);
32691
+ const read = await readback;
32692
+ let verdict;
32693
+ if ("failure" in read) verdict = read.failure;
32694
+ else if (!Object.prototype.hasOwnProperty.call(read.live, pc.path)) verdict = "not-readable";
32695
+ else verdict = liveHoldsFreshLeaves(read.live[pc.path], freshLeaves) ? "held" : "differs";
32696
+ if (verdict !== "held") {
32697
+ this.logger.warn(safeMsg`${logicalId}.${pc.path} carries a NoEcho value that AWS could not confirm unchanged (${verdict}): replacement kept.`);
32698
+ lowered.push(pc);
32699
+ continue;
32700
+ }
32701
+ this.logger.debug(safeMsg`${logicalId}.${pc.path} carries a NoEcho value AWS already holds: not replaced.`);
32702
+ noEchoHeldPaths.add(pc.path);
32703
+ }
32704
+ lowered.push({
32705
+ ...pc,
32706
+ requiresReplacement: false
32707
+ });
32708
+ }
32709
+ change.propertyChanges = lowered;
32710
+ }
32711
+ if (noEchoHeldPaths.size > 0 && !typeChanged && lostChild === void 0 && this.recreateDirectionFor(stackName, logicalId) === void 0 && recordMatchesDesired && Object.entries(resolvedProps).every(([key, value]) => noEchoHeldPaths.has(key) || freshNoEchoLeafPositions(value, updateSecrets).length === 0)) {
32712
+ this.logger.debug(safeMsg`Skipping ${logicalId}: AWS already holds every NoEcho value it carries, and nothing else changed`);
32713
+ this.attemptedResolvedProps.delete(logicalId);
32714
+ if (change.attributeChanges && change.attributeChanges.length > 0) {
32715
+ applyAttributeOnlyUpdate(change.attributeChanges);
32716
+ return;
32717
+ }
32718
+ if (counts) counts.skipped++;
32719
+ return;
32720
+ }
32721
+ const propertyDrivenReplacement = typeChanged || change.propertyChanges?.some((pc) => pc.requiresReplacement);
32722
+ const recreateTargets = this.options.recreateTargets?.stackName === stackName ? this.options.recreateTargets : void 0;
32723
+ const recreateViaCcApi = recreateTargets?.viaCcApi.has(logicalId) ?? false;
32724
+ const recreateViaSdkProvider = recreateTargets?.viaSdkProvider.has(logicalId) ?? false;
32725
+ const recreateFlagged = recreateViaCcApi || recreateViaSdkProvider;
32726
+ const needsReplacement = propertyDrivenReplacement || recreateFlagged || lostWithParent !== void 0;
32727
+ if (propertyDrivenReplacement && !typeChanged && !recreateFlagged && lostWithParent === void 0 && this.options.replace !== true && currentResource.provisionedBy !== "cc-api") {
32728
+ const unwritten = unwrittenCreateOnlyReplacement(resourceType, currentProps, desiredForSkipCheck, allowedForRecord, createOnlyEvidence, (change.propertyChanges ?? []).filter((pc) => pc.requiresReplacement).map((pc) => pc.path));
32729
+ if (unwritten.length > 0) throw markRefusedBeforeApplying(markNonRetryable(new CdkdError(unwrittenCreateOnlyRefusal({
32730
+ logicalId,
32731
+ resourceType,
32732
+ unwritten,
32733
+ routeDriving: findActionableSilentDrops(resourceType, desiredForSkipCheck, allowedForRecord, currentProps).map(({ property }) => property),
32734
+ nested: this.options.parentStackInfo !== void 0,
32735
+ protectionEvidence: recordedProtectionEvidence(resourceType, currentProps, currentResource.observedProperties, this.stackRegion)
32736
+ }), "CREATE_ONLY_DROP_NEEDS_REPLACEMENT")));
32737
+ }
32738
+ const liveLabel = this.liveTaskLabels.get(logicalId);
32739
+ if (needsReplacement && liveLabel !== void 0 && !liveLabel.replacing) {
32740
+ const label = `Replacing ${logicalId} (${resourceType})${this.peekRoutingForLabel(change, currentResource, stackName, logicalId, true, this.recreateDirectionFor(stackName, logicalId)) === "cc-api" ? " [CC API]" : ""}`;
32741
+ this.liveTaskLabels.set(logicalId, {
32742
+ label,
32743
+ replacing: true,
32744
+ ...liveLabel.warnSuffix !== void 0 && { warnSuffix: liveLabel.warnSuffix }
32745
+ });
32746
+ renderer.updateTaskLabel(logicalId, `${label}${liveLabel.warnSuffix ?? ""}`);
32747
+ } else if (!needsReplacement && liveLabel !== void 0 && liveLabel.replacing) {
32748
+ const label = `Updating ${logicalId} (${resourceType})${this.peekRoutingForLabel(change, currentResource, stackName, logicalId, false, this.recreateDirectionFor(stackName, logicalId)) === "cc-api" ? " [CC API]" : ""}`;
32749
+ this.liveTaskLabels.set(logicalId, {
32750
+ label,
32751
+ replacing: false,
32752
+ ...liveLabel.warnSuffix !== void 0 && { warnSuffix: liveLabel.warnSuffix }
32753
+ });
32754
+ renderer.updateTaskLabel(logicalId, `${label}${liveLabel.warnSuffix ?? ""}`);
32755
+ }
32756
+ const dependencies = this.extractAllDependencies(template, logicalId);
32757
+ const updateReplacePolicy = template?.Resources?.[logicalId]?.UpdateReplacePolicy;
32758
+ const markRestored = (outcome) => {
32759
+ if (lostChild === void 0) return outcome;
32760
+ if (this.updatesThatSentNothing.has(logicalId)) {
32761
+ this.logger.warn(survivesParent(resourceType) ? safeMsg` ⚠ ${logicalId} lost its attachment to ${lostChild.parent}, which was re-created, but its update sent no change (it is recorded on Cloud Control, which patches record against template); it may no longer be attached to ${lostChild.parent}. Attach it there by hand.` : safeMsg` ⚠ ${logicalId} went with ${lostChild.parent}, which was re-created, but its update sent no change (it is recorded on Cloud Control, which patches record against template); its policy may be missing from ${lostChild.parent}. Re-run with --recreate-via-sdk-provider ${logicalId} to write it again.`);
32762
+ return outcome;
32763
+ }
32764
+ this.restoredLostChildren.add(logicalId);
32765
+ return outcome;
32766
+ };
32767
+ if (needsReplacement) return markRestored(await this.updateByReplacement({
32768
+ change,
32769
+ counts,
32770
+ currentProps,
32771
+ currentResource,
32772
+ dependencies,
32773
+ logicalId,
32774
+ oldResourceType,
32775
+ progress,
32776
+ propertyDrivenReplacement,
32777
+ recreateFlagged,
32778
+ recreateViaCcApi,
32779
+ recreateViaSdkProvider,
32780
+ renderer,
32781
+ resolvedProps,
32782
+ resourceType,
32783
+ stackName,
32784
+ stateResources,
32785
+ template,
32786
+ typeChanged,
32787
+ updateReplacePolicy,
32788
+ updateSecrets,
32789
+ lostWithParent
32790
+ }));
32791
+ return markRestored(await this.updateInPlace({
32792
+ conditions,
32793
+ counts,
32794
+ currentProps,
32795
+ currentPropsAsWritten,
32796
+ currentResource,
32797
+ dependencies,
32798
+ desiredForSkipCheckAsWritten,
32799
+ logicalId,
32800
+ noEchoHeldPaths,
32801
+ parameterValues,
32802
+ progress,
32803
+ renderer,
32804
+ resolvedProps,
32805
+ resourceType,
32806
+ stackName,
32807
+ stateResources,
32808
+ template,
32809
+ updateReplacePolicy,
32810
+ updateSecrets,
32811
+ reattach: lostChild?.mode === "reattach"
32812
+ }));
32813
+ }
32814
+ function unwrittenCreateOnlyRefusal(input) {
32815
+ const { logicalId, resourceType, unwritten, routeDriving, nested, protectionEvidence } = input;
32816
+ const one = unwritten.length === 1;
32817
+ const list = unwritten.join(", ");
32818
+ const keep = [.../* @__PURE__ */ new Set([...unwritten, ...routeDriving])].sort((a, b) => a.localeCompare(b)).map((property) => `${resourceType}:${property}`).join(",");
32819
+ const replaceFlags = nested ? "--replace (which creates the new resource before deleting the old one, so a resource holding a unique value other than its name, such as a CIDR block, collides)" : `--recreate-via-cc-api ${logicalId}, which deletes the old resource first (--replace also works, but creates the new one first, so a resource holding a unique value other than its name, such as a CIDR block, collides)`;
32820
+ const routed = [...routeDriving].sort((a, b) => a.localeCompare(b)).join(", ");
32821
+ return `${logicalId} (${resourceType}): ${list} ${one ? "is" : "are"} create-only, and the state record holds ${one ? "it" : "them"} although this type's SDK provider never writes ${one ? "it" : "them"}, so AWS does not. This deploy routes the resource through Cloud Control (--prefer-sdk-route does not cover ${routed}), and applying a create-only property means replacing the resource, which cdkd does not do on its own. This resource was not changed. To replace it and apply ${list}, re-run with ${replaceFlags}; a stateful resource also needs --force-stateful-recreation.` + (protectionEvidence !== void 0 ? ` ${recordedProtectionNote(protectionEvidence, nested ? "--replace" : `--recreate-via-cc-api ${logicalId} or --replace`)}` : "") + ` To keep dropping ${one ? "it" : "them"}, re-run with --prefer-sdk-route ${keep}.`;
32822
+ }
32823
+
32238
32824
  //#endregion
32239
32825
  //#region src/deployment/deploy-engine/update-replace.ts
32240
32826
  async function updateByReplacement({ change, counts, currentProps, currentResource, dependencies, logicalId, oldResourceType, progress, propertyDrivenReplacement, recreateFlagged, recreateViaCcApi, recreateViaSdkProvider, renderer, resolvedProps, resourceType, stackName, stateResources, template, typeChanged, updateReplacePolicy, updateSecrets, lostWithParent }) {
@@ -32423,10 +33009,12 @@ async function updateByReplacement({ change, counts, currentProps, currentResour
32423
33009
  }
32424
33010
  this.registerNoEchoAttributes(logicalId, createResult, updateSecrets, resolvedProps);
32425
33011
  if (equalIdIsSameResource && createResult.physicalId === currentResource.physicalId) this.recreatedUnderSameId.add(logicalId);
33012
+ const recordedReplacementProperties = this.propertiesToRecord(resolvedProps, createResult, resourceType, replaceDecision.provisionedBy);
32426
33013
  stateResources[logicalId] = {
32427
33014
  physicalId: createResult.physicalId,
32428
33015
  resourceType,
32429
- properties: this.propertiesToRecord(resolvedProps, createResult, resourceType, replaceDecision.provisionedBy),
33016
+ properties: recordedReplacementProperties,
33017
+ ...acceptedCreateOnlyDropsField(recordedReplacementProperties, resourceType, replaceDecision.provisionedBy, "new-resource"),
32430
33018
  ...createResult.attributes && { attributes: createResult.attributes },
32431
33019
  ...dependencies && dependencies.length > 0 && { dependencies },
32432
33020
  ...this.extractTemplateAttributes(template, logicalId),
@@ -32633,17 +33221,20 @@ async function updateInPlace({ conditions, counts, currentProps, currentPropsAsW
32633
33221
  } else throw updateError;
32634
33222
  }
32635
33223
  if (result.wasReplaced) this.logger.info(`Resource ${logicalId} was replaced: ${currentResource.physicalId} -> ${result.physicalId}`);
32636
- const keepsParameterRefusal = !(result.wasReplaced === true && result.physicalId !== currentResource.physicalId) && hasUnverifiableParameterRefusal(currentResource);
33224
+ const dischargedByReplacement = result.wasReplaced === true && result.physicalId !== currentResource.physicalId;
33225
+ const keepsParameterRefusal = !dischargedByReplacement && hasUnverifiableParameterRefusal(currentResource);
32637
33226
  const carriedAttributes = result.attributes ?? (result.wasReplaced ? void 0 : currentResource.attributes);
32638
33227
  this.registerNoEchoAttributes(logicalId, {
32639
33228
  ...carriedAttributes && { attributes: carriedAttributes },
32640
33229
  ...result.noEchoAttributes === true && { noEchoAttributes: true },
32641
33230
  ...result.noEchoAttributeNames && { noEchoAttributeNames: result.noEchoAttributeNames }
32642
33231
  }, updateSecrets, resolvedProps);
33232
+ const recordedProperties = this.propertiesToRecord(resolvedProps, result, resourceType, resultProvisionedBy);
32643
33233
  stateResources[logicalId] = {
32644
33234
  physicalId: result.physicalId,
32645
33235
  resourceType,
32646
- properties: this.propertiesToRecord(resolvedProps, result, resourceType, resultProvisionedBy),
33236
+ properties: recordedProperties,
33237
+ ...acceptedCreateOnlyDropsField(recordedProperties, resourceType, resultProvisionedBy, dischargedByReplacement ? "new-resource" : "in-place", currentResource),
32647
33238
  ...carriedAttributes && { attributes: carriedAttributes },
32648
33239
  ...dependencies && dependencies.length > 0 && { dependencies },
32649
33240
  ...this.extractTemplateAttributes(template, logicalId),
@@ -32798,75 +33389,6 @@ async function withResourceDeadline(operation, opts) {
32798
33389
  });
32799
33390
  }
32800
33391
 
32801
- //#endregion
32802
- //#region src/deployment/prior-attempt-scope.ts
32803
- const priorAttemptStore = new AsyncLocalStorage();
32804
- function withPriorAttempts(lookup, fn) {
32805
- return priorAttemptStore.run(lookup, fn);
32806
- }
32807
- function priorAttemptLookup(logicalId, attempts) {
32808
- let landed = false;
32809
- return {
32810
- logicalId,
32811
- attempts,
32812
- notePossiblyLanded: () => {
32813
- landed = true;
32814
- },
32815
- possiblyLanded: () => landed
32816
- };
32817
- }
32818
- function getPriorAttempts(logicalId) {
32819
- const bound = priorAttemptStore.getStore();
32820
- return bound?.logicalId === logicalId ? bound : void 0;
32821
- }
32822
- function priorAttemptsInJournal(journal, logicalId, resourceType) {
32823
- let bags = [];
32824
- for (const segment of journal?.segments ?? []) {
32825
- if (segment.operations.some((op) => op.logicalId === logicalId)) bags = [];
32826
- for (const op of segment.failedOperations ?? []) {
32827
- if (op.logicalId !== logicalId || op.resourceType !== resourceType) continue;
32828
- if (op.changeType === "DELETE" || !isBag(op.attemptedProperties)) continue;
32829
- if (recordedAsNewResource(op)) continue;
32830
- bags.push(op.attemptedProperties);
32831
- }
32832
- if (segment.supersededLogicalIds?.includes(logicalId)) bags = [];
32833
- }
32834
- return bags;
32835
- }
32836
- function recordedAsNewResource(op) {
32837
- if (typeof op.physicalId !== "string" || op.physicalId === "") return false;
32838
- if (op.changeType === "CREATE") return true;
32839
- const previous = op.previousState?.physicalId;
32840
- return typeof previous === "string" && previous !== op.physicalId;
32841
- }
32842
- function isBag(value) {
32843
- return typeof value === "object" && value !== null && !Array.isArray(value);
32844
- }
32845
- const REFUSED_BEFORE_APPLYING = Symbol.for("cdkd.refusedBeforeApplying");
32846
- const MAX_CAUSE_DEPTH = 10;
32847
- function markRefusedBeforeApplying(error) {
32848
- if (!Object.isExtensible(error)) return error;
32849
- Object.defineProperty(error, REFUSED_BEFORE_APPLYING, {
32850
- value: true,
32851
- enumerable: false,
32852
- configurable: true,
32853
- writable: false
32854
- });
32855
- return error;
32856
- }
32857
- function isRefusedBeforeApplying(error, logicalId) {
32858
- let current = error;
32859
- for (let depth = 0; depth < MAX_CAUSE_DEPTH && current != null; depth++) {
32860
- if (typeof current === "object" || typeof current === "function") {
32861
- const linkId = current.logicalId;
32862
- if (typeof linkId === "string" && linkId !== logicalId) return false;
32863
- if (current[REFUSED_BEFORE_APPLYING] === true) return true;
32864
- }
32865
- current = current.cause;
32866
- }
32867
- return false;
32868
- }
32869
-
32870
33392
  //#endregion
32871
33393
  //#region src/deployment/deploy-engine/provision.ts
32872
33394
  async function provisionResource(logicalId, change, stateResources, stackName, template, parameterValues, conditions, counts, progress) {
@@ -33245,14 +33767,17 @@ async function executeDeployment(template, currentState, changes, dag, execution
33245
33767
  } catch (provisionError) {
33246
33768
  this.interrupted = true;
33247
33769
  this.interruptCause ??= "sibling-failure";
33770
+ const refused = isRefusedBeforeApplying(provisionError, logicalId);
33771
+ const physicalId = newResources[logicalId]?.physicalId ?? previousState?.physicalId;
33772
+ if (refused && change.changeType === "CREATE" && physicalId === void 0) throw provisionError;
33248
33773
  failedOperations.push({
33249
33774
  logicalId,
33250
33775
  changeType: change.changeType,
33251
33776
  resourceType: change.resourceType,
33252
33777
  provisionedBy: newResources[logicalId]?.provisionedBy ?? previousState?.provisionedBy,
33253
33778
  ...previousState && { previousState },
33254
- physicalId: newResources[logicalId]?.physicalId ?? previousState?.physicalId,
33255
- ...!isRefusedBeforeApplying(provisionError, logicalId) && { attemptedProperties: this.attemptedResolvedProps.get(logicalId) }
33779
+ physicalId,
33780
+ ...!refused && { attemptedProperties: this.attemptedResolvedProps.get(logicalId) }
33256
33781
  });
33257
33782
  throw provisionError;
33258
33783
  }
@@ -33402,6 +33927,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
33402
33927
  this.logger.warn(`Failed to save partial state before rollback: ${saveError instanceof Error ? saveError.message : String(saveError)}`);
33403
33928
  }
33404
33929
  let autoRollbackClean = false;
33930
+ let autoRollbackJournaled = false;
33405
33931
  let rollbackOrphans = [];
33406
33932
  let rollbackSettledNested = /* @__PURE__ */ new Map();
33407
33933
  if (error instanceof InterruptedError || isInterruptedWaitError(error) || this.interruptCause === "user") {
@@ -33414,9 +33940,16 @@ async function executeDeployment(template, currentState, changes, dag, execution
33414
33940
  this.logger.warn("Deployment failed. --no-rollback is set, skipping rollback.");
33415
33941
  this.logger.warn(safeMsg`Partial state has been saved. ${this.recoveryHint("Run 'cdkd deploy' to resume, 'cdkd rollback' to revert, or destroy to clean up.")}`);
33416
33942
  } else {
33417
- await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "auto-rollback-started", initialDeploy);
33943
+ autoRollbackJournaled = await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "auto-rollback-started", initialDeploy);
33418
33944
  const rollbackResult = await this.performRollback(completedOperations, newResources, stackName, currentState);
33419
- autoRollbackClean = rollbackResult.failures === 0;
33945
+ autoRollbackClean = autoRollbackJournaled && rollbackResult.failures === 0 && rollbackResult.skipped === 0;
33946
+ if (rollbackResult.failures === 0 && rollbackResult.skipped > 0) {
33947
+ this.logger.warn(safeMsg`The automatic rollback could not revert ${rollbackResult.skipped} operation(s) ` + `(see the warnings above; each is recorded as a ROLLBACK_RESOURCE_SKIPPED event).` + (autoRollbackJournaled ? ` The rollback journal keeps them.` : ""));
33948
+ if (autoRollbackJournaled && this.options.parentStackInfo === void 0 && failedOperations.some((op) => op.changeType !== "DELETE")) this.logger.warn(safeMsg`The record of the operation that failed is kept too. Revert it with: ${pasteableCommand("cdkd rollback", [{
33949
+ value: stackName,
33950
+ hole: "stack"
33951
+ }, { literal: "--revert-failed" }]).command}`);
33952
+ }
33420
33953
  rollbackOrphans = rollbackResult.orphaned;
33421
33954
  rollbackSettledNested = rollbackResult.settledNested;
33422
33955
  }
@@ -33941,6 +34474,9 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
33941
34474
  });
33942
34475
  const parameterValues = await this.resolver.resolveParameters(template, this.options.parameters, { ...this.options.inheritedSecrets && hasMaskableValues(this.options.inheritedSecrets) && { inheritedSecrets: this.options.inheritedSecrets } });
33943
34476
  this.logger.debug(`Resolved ${Object.keys(parameterValues).length} parameters: ${Object.keys(parameterValues).join(", ")}`);
34477
+ const backfillNoEchoValues = noEchoParameterValueSeed(template.Parameters, parameterValues, this.options.inheritedSecrets, this.options.parameters);
34478
+ this.fingerprintNoEchoValues = backfillNoEchoValues;
34479
+ let maskedFingerprintsBackfilled = backfillMaskedPropertyFingerprints(currentState.resources, template, backfillNoEchoValues) > 0;
33944
34480
  const context = this.buildResolverContext({
33945
34481
  template,
33946
34482
  resources: currentState.resources,
@@ -33962,7 +34498,10 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
33962
34498
  const effectiveTemplate = this.templateParser.filterResourcesByCondition(template, conditions);
33963
34499
  const orphanCountBeforeAdoption = (currentState.orphans ?? []).length;
33964
34500
  const orphanPlan = await this.adoptRollbackOrphans(currentState, effectiveTemplate);
33965
- if (Object.keys(orphanPlan.adopted).length > 0) this.stampReasonlessParameterRefusals(currentState.resources, template);
34501
+ if (Object.keys(orphanPlan.adopted).length > 0) {
34502
+ this.stampReasonlessParameterRefusals(currentState.resources, template);
34503
+ if (backfillMaskedPropertyFingerprints(currentState.resources, template, backfillNoEchoValues) > 0) maskedFingerprintsBackfilled = true;
34504
+ }
33966
34505
  const orphansChanged = Object.keys(orphanPlan.adopted).length > 0 || (currentState.orphans ?? []).length !== orphanCountBeforeAdoption;
33967
34506
  const resourceTypes = new Set(Object.values(effectiveTemplate.Resources || {}).map((r) => r.Type).filter((type) => type !== "AWS::CDK::Metadata"));
33968
34507
  this.providerRegistry.validateResourceTypes(resourceTypes);
@@ -34039,7 +34578,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
34039
34578
  const skippedOutputsChanged = !skippedOutputsEqual(currentState.skippedOutputs, this.skippedOutputs);
34040
34579
  const healedAttributesPending = this.hasUnpersistedHeals(currentState.resources);
34041
34580
  const conditionVerdictsChanged = !conditionVerdictRecordsEqual(readRecordedConditionVerdicts(currentState), conditionVerdicts);
34042
- if (observedRefresh || conditionVerdictsChanged || outputsChanged || exportSetChanged || skippedOutputsChanged || orphansChanged || healedAttributesPending) try {
34581
+ if (observedRefresh || maskedFingerprintsBackfilled || conditionVerdictsChanged || outputsChanged || exportSetChanged || skippedOutputsChanged || orphansChanged || healedAttributesPending) try {
34043
34582
  const refreshedState = {
34044
34583
  version: 10,
34045
34584
  region: this.stackRegion,
@@ -34218,37 +34757,6 @@ function preparePropertiesForCcApi(resourceType, resolvedProps, logicalId) {
34218
34757
  return applyDefaultNameForFallback(logicalId, resourceType, resolvedProps);
34219
34758
  }
34220
34759
 
34221
- //#endregion
34222
- //#region src/deployment/deploy-engine/record-shape.ts
34223
- function auditResolvedAssetReferences(logicalId, resourceType, resolvedProps) {
34224
- const redirect = this.options.assetRedirect;
34225
- if (!redirect) return;
34226
- const findings = findUnrewrittenAssetReferences(resolvedProps, redirect);
34227
- if (findings.length === 0) return;
34228
- const detail = findings.map((f) => ` - ${f.path}: still references '${f.source}'`).join("\n");
34229
- 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);
34230
- }
34231
- function extractAllDependencies(template, logicalId) {
34232
- const resource = template?.Resources?.[logicalId];
34233
- if (!resource) return void 0;
34234
- const parser = new TemplateParser();
34235
- const parameterNames = new Set(Object.keys(template?.Parameters ?? {}));
34236
- const deps = [...parser.extractDependencies(resource)].filter((dep) => !parameterNames.has(dep));
34237
- return deps.length > 0 ? deps : void 0;
34238
- }
34239
- function propertiesToRecord(desiredProperties, result, resourceType, provisionedBy) {
34240
- if (result.effectiveProperties) return provisionedBy === "sdk" ? withoutSilentDropProperties(resourceType, result.effectiveProperties) : result.effectiveProperties;
34241
- const written = provisionedBy === "sdk" ? withoutSilentDropProperties(resourceType, desiredProperties) : desiredProperties;
34242
- return markSameGenerationBag(written);
34243
- }
34244
- function extractTemplateAttributes(template, logicalId) {
34245
- const resource = template?.Resources?.[logicalId];
34246
- return {
34247
- deletionPolicy: resource?.DeletionPolicy,
34248
- updateReplacePolicy: resource?.UpdateReplacePolicy
34249
- };
34250
- }
34251
-
34252
34760
  //#endregion
34253
34761
  //#region src/analyzer/implicit-delete-deps.ts
34254
34762
  const IMPLICIT_DELETE_DEPENDENCIES = {
@@ -34427,6 +34935,7 @@ var DeployEngine = class {
34427
34935
  noEchoAttributeResources = /* @__PURE__ */ new Map();
34428
34936
  perResourceTemplateProps = /* @__PURE__ */ new Map();
34429
34937
  perResourceResolvedType = /* @__PURE__ */ new Map();
34938
+ fingerprintNoEchoValues = void 0;
34430
34939
  outputSecrets = /* @__PURE__ */ new Map();
34431
34940
  outputsPassSecretMaps = [];
34432
34941
  outputsTemplateSource = Object.create(null);
@@ -34474,6 +34983,7 @@ var DeployEngine = class {
34474
34983
  this.noEchoAttributeResources = /* @__PURE__ */ new Map();
34475
34984
  this.perResourceTemplateProps = /* @__PURE__ */ new Map();
34476
34985
  this.perResourceResolvedType = /* @__PURE__ */ new Map();
34986
+ this.fingerprintNoEchoValues = void 0;
34477
34987
  this.attemptedResolvedProps = /* @__PURE__ */ new Map();
34478
34988
  this.liveTaskLabels = /* @__PURE__ */ new Map();
34479
34989
  this.outputSecrets = /* @__PURE__ */ new Map();
@@ -34500,13 +35010,15 @@ var DeployEngine = class {
34500
35010
  for (const [logicalId, record] of Object.entries(state.resources)) {
34501
35011
  const secrets = this.perResourceSecrets.get(logicalId);
34502
35012
  const templateProps = this.perResourceTemplateProps.get(logicalId);
34503
- resources[logicalId] = scrubResourceRecord(this.withHealedAttributes(logicalId, record), secrets ?? /* @__PURE__ */ new Map(), templateProps);
35013
+ const scrubbed = scrubResourceRecord(this.withHealedAttributes(logicalId, record), secrets ?? /* @__PURE__ */ new Map(), templateProps);
35014
+ resources[logicalId] = withMaskedPropertyFingerprints(scrubbed, record.properties, templateProps, secrets, this.fingerprintNoEchoValues);
34504
35015
  }
34505
35016
  const orphans = state.orphans?.map((entry) => {
34506
35017
  const sameResource = this.perResourceResolvedType.get(entry.logicalId) === entry.state.resourceType;
35018
+ const orphanTemplateProps = sameResource ? this.perResourceTemplateProps.get(entry.logicalId) : void 0;
34507
35019
  return {
34508
35020
  ...entry,
34509
- state: scrubResourceRecord(entry.state, (sameResource ? this.perResourceSecrets.get(entry.logicalId) : void 0) ?? /* @__PURE__ */ new Map(), sameResource ? this.perResourceTemplateProps.get(entry.logicalId) : void 0)
35021
+ state: withMaskedPropertyFingerprints(scrubResourceRecord(entry.state, (sameResource ? this.perResourceSecrets.get(entry.logicalId) : void 0) ?? /* @__PURE__ */ new Map(), orphanTemplateProps), entry.state.properties, orphanTemplateProps, sameResource ? this.perResourceSecrets.get(entry.logicalId) : void 0, sameResource ? this.fingerprintNoEchoValues : void 0)
34510
35022
  };
34511
35023
  });
34512
35024
  const outputs = this.redactOutputs(state.outputs);
@@ -34679,5 +35191,5 @@ DeployEngine.prototype.replacementNameOrigin = replacementNameOrigin;
34679
35191
  DeployEngine.prototype.orphanedNameCollisionAdvice = orphanedNameCollisionAdvice;
34680
35192
 
34681
35193
  //#endregion
34682
- export { nestedChildStackName as $, shouldRetainResource as $a, markAuxiliaryFailure as $i, isUnboundTemplateParameter as $n, ssmResolvedValueType as $o, refuseMalformedOutputsForDestroy as $r, DBPROXY_TAGS_WHAT as $t, deleteTableWithIndexBusyRetry as A, carriesSecretMask as Aa, MULTI_REGION_RECREATE_BLOCKED_TYPES as Ai, DiffCalculator as An, partitionSensitiveEnv as Ao, malformedLocalResourcesWarning as Ar, extractDeploymentEventError as At, gray as B, isLockInfoExpired as Ba, coerceCfnInteger as Bi, isIamRoleArn as Bn, Synthesizer as Bo, malformedResourcePropertiesWarning as Br, collectDeclaredOutputNames as Bt, beginDeleteWait as C, scrubResourceRecord as Ca, findActionableSilentDrops as Ci, markWaitAbandoned as Cn, describeDockerFailure as Co, isReadableOrphanRecord as Cr, resolveAssemblyPath as Cs, isFinalSnapshotError as Ct, resolveDynamoDbDeleteBudgetMs as D, isUncertifiedBaselineMaskPosition as Da, hasNoCloudControlHandlers as Di, observeThenDisableInstanceApiTermination as Dn, getDockerCmd as Do, malformedExportSourceWarning as Dr, updatePartialReason as Dt, resolveDynamoDbDeleteBudgetClock as E, dynamicReferenceTokens as Ea, NO_CC_HANDLERS_REASON as Ei, isTerminationProtectionPropagationError as En, formatDockerLoginError as Eo, malformedExportNamesWarning as Er, updatePartialMessage as Et, isTruthyCfnBoolean as F, STATE_SOURCED_READBACK_RULES as Fa, coerceWarmThroughput as Fi, regionLessSecretName as Fn, warnFinchArgvExposure as Fo, malformedOrphansWarning as Fr, secretBearingStateKeyWarning as Ft, namesAnyDeclaredParameter as G, hasReadableExportSet as Ga, replayWarn as Gi, envCredentialsAreAssumedRole as Gn, resolveAutoAssetStorage as Go, refuseDivergentRecordRegionForDestroy as Gr, DEFAULT_RESOURCE_WARN_AFTER_MS as Gt, red as H, rebuildClientForBucketRegion as Ha, configIntegerRefusal as Hi, AWS_CREDENTIAL_ENV_KEYS as Hn, getDefaultStateBucketName as Ho, malformedScrubResourceEntriesRefusalMessage as Hr, isExportAliasCollision as Ht, formatResourceLine as I, TEMPLATE_SOURCED_RULES as Ia, isWarmThroughputDecrease as Ii, applyRoleArnIfSet as In, escapeRegExp$2 as Io, malformedOutputsRefusalMessage as Ir, secretSafeKeyDisplay as It, makeSiblingClaimReader as J, importableOutputKeys as Ja, requireConfigString as Ji, s3BucketDomainName as Jn, resolveStateBucketWithDefault as Jo, refuseMalformedOrphanRecordsForDestroy as Jr, earliestDefined as Jt, reachableDivergentParameters as K, hasReasonlessBaselineRefusal as Ka, requireConfigArray as Ki, isSettledInstanceState as Kn, resolveCaptureObservedState as Ko, refuseMalformedNestedChildOutputs as Kr, maskingRetryLogger as Kt, createReadOnlyAttributeHealerFactory as L, WHOLE_DYNAMIC_REFERENCE_PATTERN as La, toCfnInteger as Li, assertFlagRoleArn as Ln, stripControlChars as Lo, malformedOutputsWarning as Lr, exportNameSecretExposure as Lt, ECR_AUTO_DELETE_IMAGES_TAG as M, recordMaskOnlyValuesIn as Ma, isStatefulRecreateTargetSync as Mi, IntrinsicFunctionResolver as Mn, redactedDockerCause as Mo, malformedOrphanRecordsWarning as Mr, displayTextOrWithheld as Mt, S3_AUTO_DELETE_OBJECTS_TAG as N, STATE_SOURCED_BASELINE_RULES as Na, renderStatefulReason as Ni, classifyReplaySecretRegion as Nn, runDockerForeground as No, malformedOrphanRowsKeptWarning as Nr, exportAliasCollisionScrubWarning as Nt, DELETE_INDEX_WAIT_PROCEED_NOTE as O, pathCrossesDottedKey as Oa, findReplacedReadersOfRecreateTargets as Oi, reDisableInstanceApiTermination as On, isDockerClientEnvKey as Oo, malformedLocalOutputsWarning as Or, DeploymentEventsReader as Ot, hasCdkAutoDeleteTag as P, STATE_SOURCED_CROSS_GENERATION_RULES as Pa, WARM_THROUGHPUT_MEMBERS as Pi, producerRegionsFromState as Pn, runDockerStreaming as Po, malformedOrphansRefusalMessage as Pr, secretBearing as Pt, getNestedRevertRun as Q, orphansCarriedFrom as Qa, withRetry as Qi, coerceParameterTypedValue as Qn, warnDeprecatedNoPrefixCliFlag as Qo, refuseMalformedOutputs as Qr, acquireIdempotencyToken as Qt, bold as R, isSingleDynamicReferenceToken as Ra, toFiniteNumber as Ri, assertSendableRoleArn as Rn, AssetManifestLoader as Ro, malformedRenderedContainersWarning as Rr, isWholeDynamicReferenceValue as Rt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as S, redactSecretsForState as Sa, unreadableResourceEntries as Si, isWaitAbandonedError as Sn, describeDockerExecFailure as So, hasReadableResources as Sr, renderAssemblyPathEscape as Ss, effectiveDeletionPolicy as St, deleteBudgetKey as T, DYNAMIC_REFERENCE_TOKEN_SCAN as Ta, withoutSilentDropProperties as Ti, ec2InstanceProtectionSite as Tn, finchSecretArgvRefusal as To, malformedDriftResourcePropertiesWarning as Tr, resolveBucketRegion as Ts, unsupportedFinalSnapshotError as Tt, yellow as U, describeRegionValueKind as Ua, configStringRefusal as Ui, applyCallerIdentityCredentials as Un, getLegacyStateBucketName as Uo, malformedStateRefusalMessage as Ur, bindingSkippedOutputs as Ut, green as V, S3StateBackend as Va, configBooleanRefusal as Vi, sendableAssumeRoleCommand as Vn, synthesisStatusMessage as Vo, malformedResourcesWarning as Vr, collectPublishedOutputNames as Vt, computeParameterTaint as W, exportNamesCarriedFrom as Wa, readConfigString as Wi, callerEnvCredentials as Wn, resolveApp as Wo, previewableOrphanRecords as Wr, DEFAULT_RESOURCE_TIMEOUT_MS as Wt, NESTED_PENDING_PARENT_REASON as X, isReadableBag as Xa, templateResourceTypes as Xi, s3BucketRegionalDomainName as Xn, resolveUseCdkBootstrapAssets as Xo, refuseMalformedOrphansForDestroy as Xr, reserveStackCreateToken as Xt, planOrphanAdoption as Y, importableOutputs as Ya, prefetchCreateOnlyPropertyPaths as Yi, s3BucketDualStackDomainName as Yn, resolveStateBucketWithDefaultAndSource as Yo, refuseMalformedOrphans as Yr, ledgerForStack as Yt, dropSettledNestedJournals as Z, orphansAfterRollback as Za, describeTypeWithThrottleRetry as Zi, s3BucketWebsiteUrl as Zn, stateBucketExistenceConfirmed as Zo, refuseMalformedOrphansForOrphan as Zr, withCreateTokenLedger as Zt, PROTECTION_PROPERTY_BY_TYPE as _, createSecretMasker as _a, repairMalformedResourceEntriesForReadOnly as _i, unchangedBehindSecretReference as _n, validateContainerRepoName as _o, UNREADABLE_RESOURCES_MAP_ROW as _r, nullPrototypeRecord as _s, ATOMIC_FINAL_SNAPSHOT_TYPES as _t, conditionInputsFrom as a, liveMatchesUnresolvedTokenFrame as aa, refuseMalformedResourceEntriesForImportSave as ai, tagPlanWarning as an, createAssetRedirectResolver as ao, isNamelessDynamicReferenceError as ar, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as as, replayFailedOperations as at, readProtection as b, maskSecretsInText as ba, unpreviewableOrphanRecords as bi, deleteSkipReason as bn, resolveDockerContextDirectory as bo, hasReadableOrphans as br, describeFileReadFailure as bs, ccRoutedFinalSnapshotError as bt, isSecretBearingReferenceString as c, carryLogOnlyValues as ca, refuseMalformedResourcePropertiesForExport as ci, CC_BROKEN_REASON as cn, AssetModeResolver as co, cfnRefValueFromPhysicalId as cr, PARTITION_TABLE as cs, destroyStackRecordsView as ct, makeCanonicalizePropertiesFn as d, literalSplitDelimitersOf as da, refuseMalformedResourcesForDestroy as di, wouldReturnToSdkProvider as dn, ensureAssetStorage as do, parseWebACLArn as dr, AssemblyReader as ds, planFailedOps as dt, canonicalLambdaFunctionName as ea, refuseMalformedResourceAttributesForOrphan as ei, DBPROXY_TAG_OPTIONS as en, AssetPublisher as eo, parameterTypeMayLoseSecretIdentity as er, CFN_TEMPLATE_BODY_LIMIT as es, revertNestedChildFromJournal as et, getPriorAttempts as f, logOnlyValueCount as fa, refuseMalformedResourcesForExport as fi, isCustomResourceType as fn, getBootstrapMarkerKey as fo, withSharedDrainBudget as fr, StageLoadError as fs, planRollback as ft, recordedProtectionNote as g, shareLogOnlyValues as ga, repairMalformedOutputsForReadOnly as gi, ccProtectionRegistryTypes as gn, validateAssetBucketName as go, UNREADABLE_ORPHANS_CONTAINER_ROW as gr, hasPlainPrototype$1 as gs, inheritProducerRegions as gt, recordedProtectionEvidence as h, recordLogOnlyValue as ha, repairMalformedOrphansForReadOnly as hi, slowCcOperationTimeoutMs as hn, readBootstrapMarkerBody as ho, STATE_RESOURCES_MALFORMED as hr, hasOwnKey as hs, getCurrentProducerRegions as ht, conditionFingerprint as i, TemplateParser as ia, refuseMalformedResourceEntriesForImport as ii, tagMapAsList as in, buildAssetRedirectMap as io, carriesFetchableDynamicReference as ir, uploadCfnTemplate as is, withNestedStackContext as it, waitForIndexesSettled as j, recordMaskOnlyValue as ja, isStatefulRecreateTargetForReplace as ji, INTRINSIC_KEYS as jn, redactDockerArgvValues as jo, malformedOrphanRecordsRefusalMessage as jr, WITHHELD_NAME_DISPLAY as jt, INDEX_SETTLE_POLL_INTERVAL_MS as k, identityKeyFor as ka, shownType as ki, reEnableInstanceApiTermination as kn, isMalformedEnvKey as ko, malformedLocalResourceEntriesWarning as kr, DeploymentEventsStore as kt, keptWholeReasonText as l, createUnionSecretMasker as la, refuseMalformedResourcePropertiesForOrphan as li, ProviderRegistry as ln, BOOTSTRAP_MARKER_PREFIX as lo, isStalePlaceholderArnAttribute as lr, canonicalizeRegion as ls, getStackRecords as lt, withResourceDeadline as m, recordLogOnlyParameterValue as ma, repairMalformedOrphanRecordsForReadOnly as mi, CloudControlProvider as mn, parseBootstrapMarker as mo, STATE_REGION_DIVERGED as mr, defineOwnKey as ms, findNestedStackTypeChanges as mt, IMPLICIT_DELETE_DEPENDENCIES as n, sameLambdaFunctionAddress as na, refuseMalformedResourceEntriesForDeploy as ni, readTagList as nn, stringifyValue as no, isImpossibleEmptyStoredAttribute as nr, MIGRATE_TMP_PREFIX as ns, withNestedRevertRun as nt, parentSuppliedValues as o, inheritNestedStackParameterAssociations as oa, refuseMalformedResourceEntriesForOrphan as oi, definedAttributes as on, loadPublishableAssetManifest as oo, keepsSecretReferenceToken as or, decodeListingKey as os, replayRollback as ot, markRefusedBeforeApplying as p, printingCorpusOf as pa, refuseMalformedState as pi, getCurrentResourceSecrets as pn, isCrossRegionRedirect as po, JSON_LISTING_HOLE_VALUE as pr, processStackMessages as ps, resolveReplacementOldType as pt, resourcesNamingDeclaredParameter as q, hasUnverifiableParameterRefusal as qa, requireConfigObject as qi, s3BucketArn as qn, resolveSkipPrefix as qo, refuseMalformedOrphanRecords as qr, RollbackInlinePolicyWriters as qt, computeImplicitDeleteEdges as r, DagBuilder as ra, refuseMalformedResourceEntriesForDestroy as ri, refuseMalformedDesiredTags as rn, WorkGraph as ro, carriesDynamicReference as rr, findLargeInlineResources as rs, getCurrentNestedStackContext as rt, readRecordedConditionVerdicts as s, recordNestedStackParameterExpressions as sa, refuseMalformedResourcePropertiesForDrift as si, stringifyIfAssigned as sn, rewriteTemplateAssetReferences as so, AWS_NO_VALUE as sr, expectedOwnerParam as ss, awaitInFlightSibling as st, DeployEngine as t, lambdaFunctionNameForMask as ta, refuseMalformedResourceEntries as ti, planTagDiff as tn, isSensitiveAttributeName as to, getAccountInfo as tr, CFN_TEMPLATE_URL_LIMIT as ts, revertedNestedRowIds as tt, mergeNoChangeOutputs as u, hasMaskableValues as ua, refuseMalformedResourcesForDeploy as ui, ccBrokenReason as un, assertAssetBucketRegion as uo, refStateLookupFromResource as ur, derivePartitionAndUrlSuffix as us, withStackRecords as ut, isProtectionValueActive as v, errorCauseChain as va, repairMalformedResourcePropertiesForReadOnly as vi, UNSPECIFIED_SKIP_REASON as vn, buildDenyExternalAccessPolicy as vo, deployRefusesOrphanRowsReason as vr, ownValue as vs, PRE_DELETE_SNAPSHOT_TYPES as vt, compensateRemovedDeletionProtection as w, recoverMaskedOutput as wa, findSilentDropProperties as wi, disableInstanceApiTermination as wn, dockerSpawnEnvWithSensitive as wo, isReadableResourceEntry as wr, clearBucketRegionCache as ws, refusesFinalSnapshot as wt, DynamoDBGlobalTableProvider as x, markSameGenerationBag as xa, unreadableOrphanRecords as xi, withIndeterminateGuard as xn, describeDockerCapturedOutput as xo, hasReadableOutputs as xr, displayAssemblyPath as xs, createPreDeleteFinalSnapshot as xt, perType as y, maskSecretsInError as ya, repairMalformedResourcesForReadOnly as yi, deleteIndeterminateGuards as yn, buildDockerImage as yo, displayLogicalId as yr, absoluteAssemblyPathEscape as ys, buildFinalSnapshotIdentifier as yt, cyan as z, LockManager as za, coerceCfnBoolean as zi, explicitRoleArnOrThrow as zn, getDockerImageBySourceHash as zo, malformedResourceEntriesWarning as zr, noEchoParameterValueSeed as zt };
34683
- //# sourceMappingURL=deploy-engine-C5kAhscq.js.map
35194
+ export { nestedChildStackName as $, hasReadableExportSet as $a, requireConfigObject as $i, s3BucketDomainName as $n, resolveAutoAssetStorage as $o, refuseMalformedOrphanRecordsForDestroy as $r, earliestDefined as $t, ECR_AUTO_DELETE_IMAGES_TAG as A, recoverMaskedOutput as Aa, unwrittenCreateOnlyReplacement as Ai, ec2InstanceProtectionSite as An, describeDockerExecFailure as Ao, malformedDriftResourcePropertiesWarning as Ar, renderAssemblyPathEscape as As, redactedDeleteAddressSkip as At, gray as B, STATE_SOURCED_BASELINE_RULES as Ba, WARM_THROUGHPUT_MEMBERS as Bi, regionLessSecretName as Bn, redactedDockerCause as Bo, malformedOrphansWarning as Br, secretBearingStateKeyWarning as Bt, deleteBudgetKey as C, createSecretMasker as Ca, repairMalformedResourcePropertiesForReadOnly as Ci, UNSPECIFIED_SKIP_REASON as Cn, readBootstrapMarkerBody as Co, deployRefusesOrphanRowsReason as Cr, hasOwnKey as Cs, effectiveDeletionPolicy as Ct, INDEX_SETTLE_POLL_INTERVAL_MS as D, markSameGenerationBag as Da, unreadableResourceEntries as Di, isWaitAbandonedError as Dn, buildDockerImage as Do, hasReadableResources as Dr, absoluteAssemblyPathEscape as Ds, REDACTED_DELETE_ADDRESS_SKIP_REASON as Dt, DELETE_INDEX_WAIT_PROCEED_NOTE as E, maskSecretsInText as Ea, unreadableOrphanRecords as Ei, withIndeterminateGuard as En, buildDenyExternalAccessPolicy as Eo, hasReadableOutputs as Er, ownValue as Es, unsupportedFinalSnapshotError as Et, markRefusedBeforeApplying as F, identityKeyFor as Fa, shownType as Fi, DiffCalculator as Fn, getDockerCmd as Fo, malformedLocalResourcesWarning as Fr, extractDeploymentEventError as Ft, namesAnyDeclaredParameter as G, isSingleDynamicReferenceToken as Ga, coerceCfnBoolean as Gi, isIamRoleArn as Gn, stripControlChars as Go, malformedResourcePropertiesWarning as Gr, collectDeclaredOutputNames as Gt, red as H, STATE_SOURCED_READBACK_RULES as Ha, isWarmThroughputDecrease as Hi, assertFlagRoleArn as Hn, runDockerStreaming as Ho, malformedOutputsWarning as Hr, exportNameSecretExposure as Ht, formatResourceLine as I, carriesSecretMask as Ia, MULTI_REGION_RECREATE_BLOCKED_TYPES as Ii, INTRINSIC_KEYS as In, isDockerClientEnvKey as Io, malformedOrphanRecordsRefusalMessage as Ir, WITHHELD_NAME_DISPLAY as It, makeSiblingClaimReader as J, S3StateBackend as Ja, configIntegerRefusal as Ji, applyCallerIdentityCredentials as Jn, Synthesizer as Jo, malformedStateRefusalMessage as Jr, bindingSkippedOutputs as Jt, reachableDivergentParameters as K, LockManager as Ka, coerceCfnInteger as Ki, sendableAssumeRoleCommand as Kn, AssetManifestLoader as Ko, malformedResourcesWarning as Kr, collectPublishedOutputNames as Kt, createReadOnlyAttributeHealerFactory as L, recordMaskOnlyValue as La, isStatefulRecreateTargetForReplace as Li, IntrinsicFunctionResolver as Ln, isMalformedEnvKey as Lo, malformedOrphanRecordsWarning as Lr, displayTextOrWithheld as Lt, hasCdkAutoDeleteTag as M, dynamicReferenceTokens as Ma, NO_CC_HANDLERS_REASON as Mi, observeThenDisableInstanceApiTermination as Mn, dockerSpawnEnvWithSensitive as Mo, malformedExportSourceWarning as Mr, clearBucketRegionCache as Ms, updatePartialReason as Mt, isTruthyCfnBoolean as N, isUncertifiedBaselineMaskPosition as Na, hasNoCloudControlHandlers as Ni, reDisableInstanceApiTermination as Nn, finchSecretArgvRefusal as No, malformedLocalOutputsWarning as Nr, resolveBucketRegion as Ns, DeploymentEventsReader as Nt, deleteTableWithIndexBusyRetry as O, redactSecretsForState as Oa, findActionableSilentDrops as Oi, markWaitAbandoned as On, resolveDockerContextDirectory as Oo, isReadableOrphanRecord as Or, describeFileReadFailure as Os, isRedactedRecordedValue as Ot, getPriorAttempts as P, pathCrossesDottedKey as Pa, findReplacedReadersOfRecreateTargets as Pi, reEnableInstanceApiTermination as Pn, formatDockerLoginError as Po, malformedLocalResourceEntriesWarning as Pr, DeploymentEventsStore as Pt, getNestedRevertRun as Q, exportNamesCarriedFrom as Qa, requireConfigArray as Qi, s3BucketArn as Qn, resolveApp as Qo, refuseMalformedOrphanRecords as Qr, RollbackInlinePolicyWriters as Qt, bold as R, recordMaskOnlyValuesIn as Ra, isStatefulRecreateTargetSync as Ri, classifyReplaySecretRegion as Rn, partitionSensitiveEnv as Ro, malformedOrphanRowsKeptWarning as Rr, exportAliasCollisionScrubWarning as Rt, compensateRemovedDeletionProtection as S, shareLogOnlyValues as Sa, repairMalformedResourceEntriesForReadOnly as Si, unchangedBehindSecretReference as Sn, parseBootstrapMarker as So, UNREADABLE_RESOURCES_MAP_ROW as Sr, defineOwnKey as Ss, createPreDeleteFinalSnapshot as St, resolveDynamoDbDeleteBudgetMs as T, maskSecretsInError as Ta, unpreviewableOrphanRecords as Ti, deleteSkipReason as Tn, validateContainerRepoName as To, hasReadableOrphans as Tr, nullPrototypeRecord as Ts, refusesFinalSnapshot as Tt, yellow as U, TEMPLATE_SOURCED_RULES as Ua, toCfnInteger as Ui, assertSendableRoleArn as Un, warnFinchArgvExposure as Uo, malformedRenderedContainersWarning as Ur, isWholeDynamicReferenceValue as Ut, green as V, STATE_SOURCED_CROSS_GENERATION_RULES as Va, coerceWarmThroughput as Vi, applyRoleArnIfSet as Vn, runDockerForeground as Vo, malformedOutputsRefusalMessage as Vr, secretSafeKeyDisplay as Vt, computeParameterTaint as W, WHOLE_DYNAMIC_REFERENCE_PATTERN as Wa, toFiniteNumber as Wi, explicitRoleArnOrThrow as Wn, escapeRegExp$2 as Wo, malformedResourceEntriesWarning as Wr, noEchoParameterValueSeed as Wt, NESTED_PENDING_PARENT_REASON as X, acceptedCreateOnlyDropsOf as Xa, readConfigString as Xi, envCredentialsAreAssumedRole as Xn, getDefaultStateBucketName as Xo, refuseDivergentRecordRegionForDestroy as Xr, DEFAULT_RESOURCE_WARN_AFTER_MS as Xt, planOrphanAdoption as Y, rebuildClientForBucketRegion as Ya, configStringRefusal as Yi, callerEnvCredentials as Yn, synthesisStatusMessage as Yo, previewableOrphanRecords as Yr, DEFAULT_RESOURCE_TIMEOUT_MS as Yt, dropSettledNestedJournals as Z, describeRegionValueKind as Za, replayWarn as Zi, isSettledInstanceState as Zn, getLegacyStateBucketName as Zo, refuseMalformedNestedChildOutputs as Zr, maskingRetryLogger as Zt, perType as _, literalSplitDelimitersOf as _a, refuseMalformedResourcesForExport as _i, isCustomResourceType as _n, BOOTSTRAP_MARKER_PREFIX as _o, withSharedDrainBudget as _r, canonicalizeRegion as _s, inheritProducerRegions as _t, conditionInputsFrom as a, markAuxiliaryFailure as aa, refuseMalformedResourceAttributesForOrphan as ai, DBPROXY_TAG_OPTIONS as an, orphansAfterRollback as ao, parameterTypeMayLoseSecretIdentity as ar, stateBucketExistenceConfirmed as as, replayFailedOperations as at, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as b, recordLogOnlyParameterValue as ba, repairMalformedOrphansForReadOnly as bi, slowCcOperationTimeoutMs as bn, getBootstrapMarkerKey as bo, STATE_RESOURCES_MALFORMED as br, StageLoadError as bs, buildFinalSnapshotIdentifier as bt, isSecretBearingReferenceString as c, sameLambdaFunctionAddress as ca, refuseMalformedResourceEntriesForDestroy as ci, refuseMalformedDesiredTags as cn, AssetPublisher as co, carriesDynamicReference as cr, CFN_TEMPLATE_BODY_LIMIT as cs, destroyStackRecordsView as ct, makeCanonicalizePropertiesFn as d, liveMatchesUnresolvedTokenFrame as da, refuseMalformedResourceEntriesForOrphan as di, definedAttributes as dn, WorkGraph as do, keepsSecretReferenceToken as dr, findLargeInlineResources as ds, recordAfterRollbackUpdate as dt, requireConfigString as ea, refuseMalformedOrphans as ei, ledgerForStack as en, hasReasonlessBaselineRefusal as eo, s3BucketDualStackDomainName as er, resolveCaptureObservedState as es, revertNestedChildFromJournal as et, withResourceDeadline as f, inheritNestedStackParameterAssociations as fa, refuseMalformedResourcePropertiesForDrift as fi, stringifyIfAssigned as fn, buildAssetRedirectMap as fo, AWS_NO_VALUE as fr, uploadCfnTemplate as fs, planFailedOps as ft, isProtectionValueActive as g, hasMaskableValues as ga, refuseMalformedResourcesForDestroy as gi, wouldReturnToSdkProvider as gn, AssetModeResolver as go, parseWebACLArn as gr, PARTITION_TABLE as gs, getCurrentProducerRegions as gt, PROTECTION_PROPERTY_BY_TYPE as h, createUnionSecretMasker as ha, refuseMalformedResourcesForDeploy as hi, ccBrokenReason as hn, rewriteTemplateAssetReferences as ho, refStateLookupFromResource as hr, expectedOwnerParam as hs, findNestedStackTypeChanges as ht, conditionFingerprint as i, withRetry as ia, refuseMalformedOutputsForDestroy as ii, DBPROXY_TAGS_WHAT as in, isReadableBag as io, isUnboundTemplateParameter as ir, resolveUseCdkBootstrapAssets as is, withNestedStackContext as it, S3_AUTO_DELETE_OBJECTS_TAG as j, DYNAMIC_REFERENCE_TOKEN_SCAN as ja, withoutSilentDropProperties as ji, isTerminationProtectionPropagationError as jn, describeDockerFailure as jo, malformedExportNamesWarning as jr, resolveAssemblyPath as js, updatePartialMessage as jt, waitForIndexesSettled as k, scrubResourceRecord as ka, findSilentDropProperties as ki, disableInstanceApiTermination as kn, describeDockerCapturedOutput as ko, isReadableResourceEntry as kr, displayAssemblyPath as ks, redactedDeleteAddressFields as kt, keptWholeReasonText as l, DagBuilder as la, refuseMalformedResourceEntriesForImport as li, tagMapAsList as ln, isSensitiveAttributeName as lo, carriesFetchableDynamicReference as lr, CFN_TEMPLATE_URL_LIMIT as ls, getStackRecords as lt, recordedProtectionNote as m, carryLogOnlyValues as ma, refuseMalformedResourcePropertiesForOrphan as mi, ProviderRegistry as mn, loadPublishableAssetManifest as mo, isStalePlaceholderArnAttribute as mr, decodeListingKey as ms, resolveReplacementOldType as mt, IMPLICIT_DELETE_DEPENDENCIES as n, templateResourceTypes as na, refuseMalformedOrphansForOrphan as ni, withCreateTokenLedger as nn, importableOutputKeys as no, s3BucketWebsiteUrl as nr, resolveStateBucketWithDefault as ns, withNestedRevertRun as nt, parentSuppliedValues as o, canonicalLambdaFunctionName as oa, refuseMalformedResourceEntries as oi, planTagDiff as on, orphansCarriedFrom as oo, getAccountInfo as or, warnDeprecatedNoPrefixCliFlag as os, replayRollback as ot, recordedProtectionEvidence as p, recordNestedStackParameterExpressions as pa, refuseMalformedResourcePropertiesForExport as pi, CC_BROKEN_REASON as pn, createAssetRedirectResolver as po, cfnRefValueFromPhysicalId as pr, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as ps, planRollback as pt, resourcesNamingDeclaredParameter as q, isLockInfoExpired as qa, configBooleanRefusal as qi, AWS_CREDENTIAL_ENV_KEYS as qn, getDockerImageBySourceHash as qo, malformedScrubResourceEntriesRefusalMessage as qr, isExportAliasCollision as qt, computeImplicitDeleteEdges as r, describeTypeWithThrottleRetry as ra, refuseMalformedOutputs as ri, acquireIdempotencyToken as rn, importableOutputs as ro, coerceParameterTypedValue as rr, resolveStateBucketWithDefaultAndSource as rs, getCurrentNestedStackContext as rt, readRecordedConditionVerdicts as s, lambdaFunctionNameForMask as sa, refuseMalformedResourceEntriesForDeploy as si, readTagList as sn, shouldRetainResource as so, isImpossibleEmptyStoredAttribute as sr, ssmResolvedValueType as ss, awaitInFlightSibling as st, DeployEngine as t, prefetchCreateOnlyPropertyPaths as ta, refuseMalformedOrphansForDestroy as ti, reserveStackCreateToken as tn, hasUnverifiableParameterRefusal as to, s3BucketRegionalDomainName as tr, resolveSkipPrefix as ts, revertedNestedRowIds as tt, mergeNoChangeOutputs as u, TemplateParser as ua, refuseMalformedResourceEntriesForImportSave as ui, tagPlanWarning as un, stringifyValue as uo, isNamelessDynamicReferenceError as ur, MIGRATE_TMP_PREFIX as us, withStackRecords as ut, readProtection as v, logOnlyValueCount as va, refuseMalformedState as vi, getCurrentResourceSecrets as vn, assertAssetBucketRegion as vo, JSON_LISTING_HOLE_VALUE as vr, derivePartitionAndUrlSuffix as vs, ATOMIC_FINAL_SNAPSHOT_TYPES as vt, resolveDynamoDbDeleteBudgetClock as w, errorCauseChain as wa, repairMalformedResourcesForReadOnly as wi, deleteIndeterminateGuards as wn, validateAssetBucketName as wo, displayLogicalId as wr, hasPlainPrototype$1 as ws, isFinalSnapshotError as wt, beginDeleteWait as x, recordLogOnlyValue as xa, repairMalformedOutputsForReadOnly as xi, ccProtectionRegistryTypes as xn, isCrossRegionRedirect as xo, UNREADABLE_ORPHANS_CONTAINER_ROW as xr, processStackMessages as xs, ccRoutedFinalSnapshotError as xt, DynamoDBGlobalTableProvider as y, printingCorpusOf as ya, repairMalformedOrphanRecordsForReadOnly as yi, CloudControlProvider as yn, ensureAssetStorage as yo, STATE_REGION_DIVERGED as yr, AssemblyReader as ys, PRE_DELETE_SNAPSHOT_TYPES as yt, cyan as z, recordNoEchoAttributeValues as za, renderStatefulReason as zi, producerRegionsFromState as zn, redactDockerArgvValues as zo, malformedOrphansRefusalMessage as zr, secretBearing as zt };
35195
+ //# sourceMappingURL=deploy-engine-RCOtmm4V.js.map