@go-to-k/cdkd 0.300.2 → 0.301.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/{asg-provider-DJdNNqDe.js → asg-provider-BHhRkEYv.js} +2 -2
  2. package/dist/{asg-provider-DJdNNqDe.js.map → asg-provider-BHhRkEYv.js.map} +1 -1
  3. package/dist/aws-failure-text-BEQfs6za.js.map +1 -1
  4. package/dist/cli.js +2 -2
  5. package/dist/{deploy-engine-DOBzE5TD.js → deploy-engine-BYgrFxwH.js} +1304 -766
  6. package/dist/deploy-engine-BYgrFxwH.js.map +1 -0
  7. package/dist/{iam-role-provider-C8gNXG1G.js → iam-role-provider-B3i7FMiT.js} +3 -9
  8. package/dist/iam-role-provider-B3i7FMiT.js.map +1 -0
  9. package/dist/index.d.ts +25 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -2
  12. package/dist/{neptune-provider-UDy6HC5O.js → neptune-provider-iRg5Dagt.js} +2 -2
  13. package/dist/{neptune-provider-UDy6HC5O.js.map → neptune-provider-iRg5Dagt.js.map} +1 -1
  14. package/dist/{program-BDm58Wc8.js → program-Djx1RrEU.js} +107 -82
  15. package/dist/program-Djx1RrEU.js.map +1 -0
  16. package/dist/{provider-classes-DzoIZFZK.js → provider-classes-gt8C7wFO.js} +154 -95
  17. package/dist/provider-classes-gt8C7wFO.js.map +1 -0
  18. package/dist/{rds-provider-C-lGTdAb.js → rds-provider-N3EBsqc6.js} +2 -2
  19. package/dist/{rds-provider-C-lGTdAb.js.map → rds-provider-N3EBsqc6.js.map} +1 -1
  20. package/dist/{version-CZbKGFSS.js → version-Q15RJPDm.js} +2 -2
  21. package/dist/{version-CZbKGFSS.js.map → version-Q15RJPDm.js.map} +1 -1
  22. package/package.json +2 -2
  23. package/dist/deploy-engine-DOBzE5TD.js.map +0 -1
  24. package/dist/iam-role-provider-C8gNXG1G.js.map +0 -1
  25. package/dist/program-BDm58Wc8.js.map +0 -1
  26. package/dist/provider-classes-DzoIZFZK.js.map +0 -1
@@ -2,7 +2,7 @@ import { r as getAwsClients, s as __exportAll } from "./aws-clients-B_CEQGE1.js"
2
2
  import { A as UNRENDERABLE, B as safeMsg, C as looksLikeCdkdGeneratedName, D as SAFE_MSG_ALTERED_CHAR, E as withoutGeneratedFallbackName, F as displaySafe, H as terminalSafe, I as displayStackName, L as isPasteableIdent, N as displayAwsMessage, O as SECRET_REF_MAX_CODE_POINTS, P as displayIdent, S as getCurrentStackName, T as withStackName, U as truncateCodePoints, a as getLogger, b as generateResourceNameWithFallback, d as installLogLineMaskerSource, f as getLiveRenderer, g as applyDefaultNameForFallback, j as asIsMessage, k as STACK_REF_MAX_CODE_POINTS, o as isStdoutReservedForPayload, r as safeStringify$1, t as describeAwsFailure, u as currentLogLineMasker, v as explicitNamePropertyFor, w as withSkipPrefix, x as getCurrentSkipPrefix, y as generateResourceName, z as plainIdentOr } from "./aws-failure-text-BEQfs6za.js";
3
3
  import { $ as protectedReplacementAdvice, $t as ambientCredentialConfig, A as isQuotableImportValue, An as SHELL_ACTIVE, At as isAuxiliaryMarkOf, B as isTerminalDeleteFailure, Bn as shellBoundedDisplay, Bt as formatLockOperation, Cn as StateError, Ct as RETRY_AUXILIARY_OWNER, Dn as normalizeAwsError, Dt as createdResourceIdentityBeforeFailure, E as assertRegionMatch, Et as createdBeforeFailure, F as resolveExplicitPhysicalId, Fn as isInertUnquoted, Ft as UNREPRODUCIBLE_LOCK_CLAUSE, G as runDeleteAttempt, Gn as isUpdateUnsupportedError, Gt as DEFAULT_STATE_PREFIX, H as observeThenDisableProtection, Hn as withheldTargetClause, Ht as recoveryCommandFlags, In as pasteableCommand, It as buildForceUnlockCommand, J as DELETION_PROTECTION_DOC_POINTER, Jn as isNameCooldownError, Kn as hasReplayMayCollide, Kt as injectiveKey, L as ProtectionFlipRegistry, Ln as physicalIdShownBesideCommand, M as quotedRemedyLogicalId, Mn as UNSHOWABLE_VALUE, Mt as markCreatedBeforeFailure, N as refusalTypeShown, Nn as commandHole, Ot as hasCreatedBeforeFailure, Pt as replayMadeAnotherResource, Q as pasteableAwsCommand, Qn as markReplayMayCollide, Qt as ambientClientDefaults, R as compensateProtectionFlip, Rn as plainOrDescribed, St as withDerivedNameMasks, T as RESOURCE_NOT_FOUND, U as protectionFlipKey, Ut as sanitizeRecoveryValue, Vn as shellQuote, Vt as formatLockOwner, Wt as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xn as isReplayedNameCollisionFrom, Yn as isRecreateRetryableError, Yt as producerRecordKey, Zt as withPasteableAwsProfile, _t as createMaskedLogSinks, ar as isRetryableTransientError, at as startInterruptWatch, bn as ResourceUpdateNotSupportedError, bt as maskDeep, ct as canonicalizeRoute53QueryName, d as prepareRemovalForUpdate, dr as markNonRetryable, en as clientDefaultsFor, er as formatRetryClassificationSignals, f as removalWarning, fr as markRedactedCause, ft as logicalIdShown, gt as stateOrphanRecordRemedy, hn as MalformedProducerRecordRefusalError, ht as segmentAfterAnchor, i as holdsSecretDerivedEntry, in as CdkdError, ir as isIamPropagationError, it as isInterruptedWaitError, j as normalizeAwsTagsToCfn, jn as SHELL_ACTIVE_WHY, jt as markAuxiliaryFailure, kt as isAuxiliaryFailure, l as withUnchangedSecretPrincipalLists, ln as DynamicReferenceRegionAmbiguousError, lr as isMarkedNonRetryable, m as withoutInjectedRemovals, mn as MacroExpansionError, mt as resourceTypeShown, nn as AccountIdUnavailableError, nr as isAmbiguousOutcomeError, on as CrossAccountSecretRefusalError, or as isTransientServerError, ot as ElapsedBudgetRegistry, pn as LockError, pr as wrapMaskedAwsError, qn as isNameCollisionErrorFrom, rn as AssetError, sn as DependencyError, sr as retryClassificationText, st as monotonicNowMs, tn as credentialFingerprint, tr as isAmbiguousCcHandlerErrorCode, un as IntrinsicResolutionRefusalError, ur as isThrottlingError, ut as compositeIdSeparatorRefusal, vn as ProvisioningError, vt as createMaskedRetryLogger, w as withoutServerErrorRetries, wn as SynthesisError, wt as carryCreatedBeforeFailure, xt as maskerOrIdentity, yn as ResourceTimeoutError, yt as isSecretDerivedValue, z as deleteWithProtectionCompensation, zn as quotedOrDescribed, zt as formatLockExpiry } from "./iam-policy-targets-DFk7zr0Q.js";
4
4
  import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, s as ambientRegion, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-DBXBcg0J.js";
5
- import { t as getCdkdVersion } from "./version-CZbKGFSS.js";
5
+ import { t as getCdkdVersion } from "./version-Q15RJPDm.js";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
8
8
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketLifecycleConfigurationCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -4958,11 +4958,22 @@ function refuseMalformedOperation(shownStack, where, op) {
4958
4958
  if (o["oldResourceMaySurvive"] !== void 0 && !["kept", "unconfirmed"].includes(o["oldResourceMaySurvive"])) fail("oldResourceMaySurvive", o["oldResourceMaySurvive"], "kept or unconfirmed when present");
4959
4959
  if (o["physicalIdRecoveredFromError"] !== void 0 && typeof o["physicalIdRecoveredFromError"] !== "boolean") fail("physicalIdRecoveredFromError", o["physicalIdRecoveredFromError"], "a boolean when present");
4960
4960
  if (o["physicalIdRecoveredFromError"] !== void 0 && o["changeType"] !== "CREATE") refuseMalformed(shownStack, `${where}.physicalIdRecoveredFromError is only valid on a CREATE (got changeType ${kind(o["changeType"])}).`);
4961
+ const pending = o["pendingCloudControlRequest"];
4962
+ if (pending !== void 0) {
4963
+ const p = pending;
4964
+ if (typeof pending !== "object" || pending === null || Array.isArray(pending) || typeof p["requestToken"] !== "string" || !/^[-A-Za-z0-9+/=]{1,128}$/.test(p["requestToken"]) || typeof p["abandonedAt"] !== "number" || !Number.isFinite(p["abandonedAt"])) fail("pendingCloudControlRequest", pending, "an object with a Cloud Control requestToken and a numeric abandonedAt when present");
4965
+ if (o["changeType"] !== "CREATE" || o["physicalId"] !== void 0 || o["physicalIdRecoveredFromError"] !== void 0) refuseMalformed(shownStack, `${where}.pendingCloudControlRequest is only valid on a CREATE with no physicalId.`);
4966
+ }
4961
4967
  const identity = o["createdResourceIdentity"];
4962
4968
  if (identity !== void 0) {
4963
4969
  if (typeof identity !== "string" || identity === "") fail("createdResourceIdentity", identity, "a non-empty string when present");
4964
4970
  if (typeof o["physicalIdRecoveredFromError"] !== "boolean") refuseMalformed(shownStack, `${where}.createdResourceIdentity is only valid on a CREATE carrying physicalIdRecoveredFromError.`);
4965
4971
  }
4972
+ const unique = o["createdIdentifierUnique"];
4973
+ if (unique !== void 0) {
4974
+ if (typeof unique !== "boolean") fail("createdIdentifierUnique", unique, "a boolean when present");
4975
+ if (typeof o["physicalIdRecoveredFromError"] !== "boolean" || o["provisionedBy"] !== "cc-api") refuseMalformed(shownStack, `${where}.createdIdentifierUnique is only valid on a Cloud Control CREATE carrying physicalIdRecoveredFromError.`);
4976
+ }
4966
4977
  if (o["deletionPolicy"] !== void 0 && ![
4967
4978
  "Delete",
4968
4979
  "Retain",
@@ -6458,6 +6469,25 @@ var S3StateBackend = class S3StateBackend {
6458
6469
  await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
6459
6470
  return removed;
6460
6471
  }
6472
+ async rewriteRollbackJournalFailedOperations(stackName, region, rewrite) {
6473
+ const journal = await this.loadRollbackJournal(stackName, region);
6474
+ if (!journal) return 0;
6475
+ let changed = 0;
6476
+ for (const segment of journal.segments) {
6477
+ if (!segment.failedOperations) continue;
6478
+ const next = [];
6479
+ for (const op of segment.failedOperations) {
6480
+ const out = rewrite(op, segment);
6481
+ if (out !== op) changed++;
6482
+ if (out !== null) next.push(out);
6483
+ }
6484
+ if (next.length === 0) delete segment.failedOperations;
6485
+ else segment.failedOperations = next;
6486
+ }
6487
+ if (changed === 0) return 0;
6488
+ await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
6489
+ return changed;
6490
+ }
6461
6491
  async reduceRollbackJournalToFailedOperations(stackName, region, keep, supersededLogicalIds = [], demote = () => false) {
6462
6492
  const journal = await this.loadRollbackJournal(stackName, region);
6463
6493
  if (!journal) return 0;
@@ -8183,6 +8213,73 @@ function positionByInheritedParameter(bag, source, secrets) {
8183
8213
  if (!deepEqualJsonValue(redactSecretsForState(answer, secrets), answer)) return void 0;
8184
8214
  return answer;
8185
8215
  }
8216
+ const REREAD_PSEUDO_PARAMETERS = /* @__PURE__ */ new Set([
8217
+ "AWS::Region",
8218
+ "AWS::Partition",
8219
+ "AWS::URLSuffix",
8220
+ "AWS::AccountId"
8221
+ ]);
8222
+ function templateRereadsAccountId(template) {
8223
+ if (template === void 0) return false;
8224
+ const resources = template.Resources !== null && typeof template.Resources === "object" ? template.Resources : void 0;
8225
+ const cached = resources && accountRereadVerdicts.get(resources);
8226
+ if (cached !== void 0 && cached.outputs === template.Outputs) return cached.verdict;
8227
+ const parts = resources ? Object.values(resources) : [];
8228
+ if (template.Outputs !== void 0) parts.push(template.Outputs);
8229
+ const verdict = parts.some(partRereadsAccountId);
8230
+ if (resources) accountRereadVerdicts.set(resources, {
8231
+ outputs: template.Outputs,
8232
+ verdict
8233
+ });
8234
+ return verdict;
8235
+ }
8236
+ const accountRereadVerdicts = /* @__PURE__ */ new WeakMap();
8237
+ function partRereadsAccountId(part) {
8238
+ let trigger = false;
8239
+ let account = false;
8240
+ const pending = [part];
8241
+ while (pending.length > 0 && !(trigger && account)) {
8242
+ const node = pending.pop();
8243
+ if (Array.isArray(node)) {
8244
+ pending.push(...node);
8245
+ continue;
8246
+ }
8247
+ if (node === null || typeof node !== "object") continue;
8248
+ for (const [key, value] of Object.entries(node)) {
8249
+ if (REREAD_TRIGGERS.has(key)) trigger = true;
8250
+ if (key === "Ref" && value === "AWS::AccountId") account = true;
8251
+ if (key === "Fn::Sub") {
8252
+ const text = Array.isArray(value) ? value[0] : value;
8253
+ if (typeof text === "string" && text.includes("${AWS::AccountId}")) account = true;
8254
+ }
8255
+ pending.push(value);
8256
+ }
8257
+ }
8258
+ return trigger && account;
8259
+ }
8260
+ const inheritedPseudoParameters = /* @__PURE__ */ new WeakMap();
8261
+ const POISONED_PSEUDO_PARAMETERS = Symbol("cdkd.inherited-pseudo-parameters.poisoned");
8262
+ function recordInheritedPseudoParameters(inheritedSecrets, values) {
8263
+ let table = inheritedPseudoParameters.get(inheritedSecrets);
8264
+ if (table === POISONED_PSEUDO_PARAMETERS) return;
8265
+ if (table === void 0) {
8266
+ table = /* @__PURE__ */ new Map();
8267
+ inheritedPseudoParameters.set(inheritedSecrets, table);
8268
+ }
8269
+ for (const [name, value] of values) {
8270
+ if (!REREAD_PSEUDO_PARAMETERS.has(name) || typeof value !== "string") continue;
8271
+ const known = table.get(name);
8272
+ if (known !== void 0 && known !== value) {
8273
+ inheritedPseudoParameters.set(inheritedSecrets, POISONED_PSEUDO_PARAMETERS);
8274
+ return;
8275
+ }
8276
+ table.set(name, value);
8277
+ }
8278
+ }
8279
+ function pseudoBindingOf(parentSecrets) {
8280
+ const table = inheritedPseudoParameters.get(parentSecrets);
8281
+ return (name) => table instanceof Map && table.has(name) ? { value: table.get(name) } : void 0;
8282
+ }
8186
8283
  const REREAD_TRIGGERS = /* @__PURE__ */ new Set([
8187
8284
  "Fn::Select",
8188
8285
  "Fn::Split",
@@ -8221,9 +8318,9 @@ function standsForInheritedSecret(parentSecrets, token) {
8221
8318
  return parentSecrets !== void 0 && resolvedPlaintextOf(parentSecrets, token) !== void 0;
8222
8319
  }
8223
8320
  const plainSplit = (text, delimiter) => text.split(delimiter);
8224
- function evaluatePureRead(node, bind, split, choose, depth = 0) {
8321
+ function evaluatePureRead(node, bind, pseudo, split, choose, depth = 0) {
8225
8322
  if (depth > MAX_REREAD_DEPTH) return void 0;
8226
- const evaluate = (child) => evaluatePureRead(child, bind, split, choose, depth + 1);
8323
+ const evaluate = (child) => evaluatePureRead(child, bind, pseudo, split, choose, depth + 1);
8227
8324
  if (typeof node === "string") return node.includes("{{resolve:") ? void 0 : { value: node };
8228
8325
  if (Array.isArray(node)) {
8229
8326
  const out = [];
@@ -8241,7 +8338,7 @@ function evaluatePureRead(node, bind, split, choose, depth = 0) {
8241
8338
  const args = node[key];
8242
8339
  if (key === "Ref") {
8243
8340
  if (args === "AWS::NoValue") return { value: REREAD_NO_VALUE };
8244
- return typeof args === "string" ? bind(args) : void 0;
8341
+ return typeof args === "string" ? bindReadName(args, bind, pseudo) : void 0;
8245
8342
  }
8246
8343
  if (key === "Fn::If") {
8247
8344
  if (!Array.isArray(args) || args.length !== 3 || typeof args[0] !== "string") return void 0;
@@ -8249,7 +8346,7 @@ function evaluatePureRead(node, bind, split, choose, depth = 0) {
8249
8346
  if (tookTrue === void 0) return void 0;
8250
8347
  return evaluate(tookTrue ? args[1] : args[2]);
8251
8348
  }
8252
- if (key === "Fn::Sub") return evaluatePureSub(args, bind, evaluate);
8349
+ if (key === "Fn::Sub") return evaluatePureSub(args, bind, pseudo, evaluate);
8253
8350
  if (!Array.isArray(args) || args.length !== 2) return void 0;
8254
8351
  if (key === "Fn::Select") {
8255
8352
  const index = args[0];
@@ -8273,7 +8370,7 @@ function evaluatePureRead(node, bind, split, choose, depth = 0) {
8273
8370
  return { value: parts.value.join(delimiter) };
8274
8371
  }
8275
8372
  }
8276
- function evaluatePureSub(args, bind, evaluate) {
8373
+ function evaluatePureSub(args, bind, pseudo, evaluate) {
8277
8374
  const [text, variables] = typeof args === "string" ? [args, {}] : Array.isArray(args) && args.length === 2 ? [args[0], args[1]] : [void 0, void 0];
8278
8375
  if (typeof text !== "string" || text.includes("{{resolve:") || !isPlainObject$7(variables)) return;
8279
8376
  const bound = /* @__PURE__ */ new Map();
@@ -8291,8 +8388,8 @@ function evaluatePureSub(args, bind, evaluate) {
8291
8388
  else if (name === "") replacement = match[0];
8292
8389
  else if (bound.has(name)) replacement = bound.get(name);
8293
8390
  else {
8294
- if (name.startsWith("AWS::") || name.includes(".")) return void 0;
8295
- const value = bind(name);
8391
+ if (name.includes(".")) return void 0;
8392
+ const value = bindReadName(name, bind, pseudo);
8296
8393
  if (value === void 0 || typeof value.value !== "string") return void 0;
8297
8394
  replacement = value.value;
8298
8395
  }
@@ -8301,6 +8398,10 @@ function evaluatePureSub(args, bind, evaluate) {
8301
8398
  }
8302
8399
  return { value: out + text.slice(cursor) };
8303
8400
  }
8401
+ function bindReadName(name, bind, pseudo) {
8402
+ if (!name.startsWith("AWS::")) return bind(name);
8403
+ return bind(name) === void 0 ? pseudo(name) : void 0;
8404
+ }
8304
8405
  function collectRereadConditions(node, names, depth = 0) {
8305
8406
  if (depth > MAX_REREAD_DEPTH) return false;
8306
8407
  if (Array.isArray(node)) return node.every((element) => collectRereadConditions(element, names, depth + 1));
@@ -8338,10 +8439,11 @@ function diffSideReading(bind, parentSecrets) {
8338
8439
  };
8339
8440
  }
8340
8441
  function rereadUnder(source, bind, parentSecrets, choose) {
8341
- const resolved = evaluatePureRead(source, bind, plainSplit, choose);
8442
+ const pseudo = pseudoBindingOf(parentSecrets);
8443
+ const resolved = evaluatePureRead(source, bind, pseudo, plainSplit, choose);
8342
8444
  if (resolved === void 0) return void 0;
8343
8445
  const diffSide = diffSideReading(bind, parentSecrets);
8344
- const redacted = evaluatePureRead(source, diffSide.bind, diffSide.split, choose);
8446
+ const redacted = evaluatePureRead(source, diffSide.bind, pseudo, diffSide.split, choose);
8345
8447
  if (redacted === void 0) return void 0;
8346
8448
  if (resolved.value === REREAD_NO_VALUE || redacted.value === REREAD_NO_VALUE) return resolved.value === redacted.value ? REREAD_NO_VALUE : void 0;
8347
8449
  if (!rendersReadTo(redacted.value, parentSecrets, resolved.value)) return void 0;
@@ -19907,6 +20009,25 @@ async function getAccountInfo(overrideRegion) {
19907
20009
  if (accountInfoInFlight.get(identityKey) === inFlight) accountInfoInFlight.delete(identityKey);
19908
20010
  }
19909
20011
  }
20012
+ const rereadAccountLookupRefused = /* @__PURE__ */ new Set();
20013
+ async function accountIdForReread(overrideRegion) {
20014
+ let identityKey;
20015
+ try {
20016
+ identityKey = credentialFingerprint(ambientCredentialConfig());
20017
+ } catch {
20018
+ return;
20019
+ }
20020
+ const cached = cachedAccountIdentities.get(identityKey);
20021
+ if (cached) return cached.accountId;
20022
+ if (rereadAccountLookupRefused.has(identityKey)) return void 0;
20023
+ try {
20024
+ return (await getAccountInfo(overrideRegion)).accountId;
20025
+ } catch (error) {
20026
+ rereadAccountLookupRefused.add(identityKey);
20027
+ getLogger().child("IntrinsicFunctionResolver").debug(`AWS::AccountId stays unbound in the nested-stack parameter re-read: the account lookup failed (${error instanceof Error ? error.name : "unknown"})`);
20028
+ return;
20029
+ }
20030
+ }
19910
20031
  async function ownRefusal(lookup) {
19911
20032
  try {
19912
20033
  return await lookup;
@@ -23097,6 +23218,20 @@ function recordInheritedParameterSecrets(parameterName, value, context) {
23097
23218
  carryFreshNoEchoMark(inherited, recorded, plaintext);
23098
23219
  }
23099
23220
  }
23221
+ async function recordInheritedPseudoParameterValues(resolver, inherited, template) {
23222
+ if (inherited.size === 0) return;
23223
+ const values = /* @__PURE__ */ new Map();
23224
+ for (const name of [
23225
+ "AWS::Region",
23226
+ "AWS::Partition",
23227
+ "AWS::URLSuffix"
23228
+ ]) values.set(name, await resolver.resolvePseudoParameter(name));
23229
+ if (templateRereadsAccountId(template)) {
23230
+ const accountId = await accountIdForReread(resolver.resolverRegion);
23231
+ if (accountId !== void 0) values.set("AWS::AccountId", accountId);
23232
+ }
23233
+ recordInheritedPseudoParameters(inherited, values);
23234
+ }
23100
23235
  function declaredParameterNames(context) {
23101
23236
  const declared = context.template?.Parameters;
23102
23237
  if (declared === null || typeof declared !== "object") return void 0;
@@ -23814,6 +23949,7 @@ function displayLeaf(value, context) {
23814
23949
  //#region src/deployment/intrinsic-resolver/params-conditions.ts
23815
23950
  async function resolveParameters(template, userParameters, options) {
23816
23951
  const inheritedSecrets = options?.inheritedSecrets;
23952
+ if (inheritedSecrets && options?.recordPseudoParameters !== false) await recordInheritedPseudoParameterValues(this, inheritedSecrets, template);
23817
23953
  const maskInherited = (text) => {
23818
23954
  const mask = (value) => inheritedSecrets && hasMaskableValues(inheritedSecrets) ? maskSecretsInText(value, inheritedSecrets) : value;
23819
23955
  return displaySafe(mask(stripControlChars(mask(text))));
@@ -25096,8 +25232,9 @@ function ec2InstanceProtectionSite(instanceId, region) {
25096
25232
  //#endregion
25097
25233
  //#region src/provisioning/wait-abandoned.ts
25098
25234
  const WAIT_ABANDONED_MARKER = Symbol.for("cdkd.waitAbandoned");
25235
+ const ABANDONED_REQUEST = Symbol.for("cdkd.waitAbandoned.request");
25099
25236
  const MAX_CAUSE_CHAIN_DEPTH = 5;
25100
- function markWaitAbandoned(error) {
25237
+ function markWaitAbandoned(error, request) {
25101
25238
  if (!Object.isExtensible(error)) return error;
25102
25239
  Object.defineProperty(error, WAIT_ABANDONED_MARKER, {
25103
25240
  value: true,
@@ -25105,6 +25242,12 @@ function markWaitAbandoned(error) {
25105
25242
  configurable: true,
25106
25243
  writable: false
25107
25244
  });
25245
+ if (request !== void 0) Object.defineProperty(error, ABANDONED_REQUEST, {
25246
+ value: Object.freeze({ ...request }),
25247
+ enumerable: false,
25248
+ configurable: true,
25249
+ writable: false
25250
+ });
25108
25251
  return error;
25109
25252
  }
25110
25253
  function isWaitAbandonedError(error) {
@@ -25115,6 +25258,14 @@ function isWaitAbandonedError(error) {
25115
25258
  }
25116
25259
  return false;
25117
25260
  }
25261
+ function abandonedRequestOf(error) {
25262
+ let current = error;
25263
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
25264
+ const request = current[ABANDONED_REQUEST];
25265
+ if (request !== void 0) return request;
25266
+ current = current.cause;
25267
+ }
25268
+ }
25118
25269
 
25119
25270
  //#endregion
25120
25271
  //#region src/provisioning/ec2-volume-delete.ts
@@ -26372,9 +26523,18 @@ var CloudControlWaitAbandonedError = class CloudControlWaitAbandonedError extend
26372
26523
  this.lastSeenIdentifier = lastSeenIdentifier;
26373
26524
  this.name = "CloudControlWaitAbandonedError";
26374
26525
  Object.setPrototypeOf(this, CloudControlWaitAbandonedError.prototype);
26375
- markWaitAbandoned(this);
26526
+ markWaitAbandoned(this, {
26527
+ requestToken,
26528
+ operation: ccOperation
26529
+ });
26376
26530
  }
26377
26531
  };
26532
+ function failedOutcome$1(errorCode, identifier) {
26533
+ return identifier && errorCode !== "AlreadyExists" && errorCode !== "ResourceConflict" ? {
26534
+ status: "failed",
26535
+ remnant: identifier
26536
+ } : { status: "failed" };
26537
+ }
26378
26538
  const POLL_TRANSPORT_ERROR_CODES = /* @__PURE__ */ new Set([
26379
26539
  "ECONNRESET",
26380
26540
  "ECONNREFUSED",
@@ -26702,7 +26862,7 @@ var CloudControlProvider = class {
26702
26862
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
26703
26863
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
26704
26864
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
26705
- const { ASGProvider } = await import("./asg-provider-DJdNNqDe.js");
26865
+ const { ASGProvider } = await import("./asg-provider-BHhRkEYv.js");
26706
26866
  const delegateRegion = ambientRegion();
26707
26867
  let asgProvider = this.asgDeleteDelegates.get(delegateRegion);
26708
26868
  if (asgProvider === void 0) {
@@ -26808,7 +26968,7 @@ var CloudControlProvider = class {
26808
26968
  const family = SDK_DELETE_FAMILIES.get(resourceType);
26809
26969
  const cached = this.sdkDeleteDelegates.get(family);
26810
26970
  if (cached !== void 0 && cached.region === ccRegion) return cached.provider;
26811
- const provider = family === "rds" ? new (await (import("./rds-provider-C-lGTdAb.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-UDy6HC5O.js"))).NeptuneProvider({ region: ccRegion });
26971
+ const provider = family === "rds" ? new (await (import("./rds-provider-N3EBsqc6.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-iRg5Dagt.js"))).NeptuneProvider({ region: ccRegion });
26812
26972
  this.sdkDeleteDelegates.set(family, {
26813
26973
  region: ccRegion,
26814
26974
  provider
@@ -27016,9 +27176,10 @@ var CloudControlProvider = class {
27016
27176
  const failureMessage = progressEvent.StatusMessage || "Unknown error";
27017
27177
  throw new CloudControlOperationFailedError(`${operation} failed for ${logicalId}: ${failureMessage}${handlerAuthFailureHint(failureMessage)}`, progressEvent.TypeName || "Unknown", logicalId, progressEvent.Identifier, progressEvent.ErrorCode, operation);
27018
27178
  }
27019
- case "CANCEL_COMPLETE": throw new ProvisioningError(`${operation} cancelled for ${logicalId}`, progressEvent.TypeName || "Unknown", logicalId, progressEvent.Identifier);
27179
+ case "CANCEL_COMPLETE": throw Object.assign(new ProvisioningError(`${operation} cancelled for ${logicalId}`, progressEvent.TypeName || "Unknown", logicalId, progressEvent.Identifier), { ccOperationCancelled: true });
27020
27180
  case "IN_PROGRESS":
27021
27181
  case "PENDING":
27182
+ case "CANCEL_IN_PROGRESS":
27022
27183
  await this.sleep(pollInterval);
27023
27184
  pollInterval = Math.min(Math.ceil(pollInterval * 1.5), this.MAX_POLL_INTERVAL_MS);
27024
27185
  break;
@@ -27030,13 +27191,90 @@ var CloudControlProvider = class {
27030
27191
  }
27031
27192
  throw await this.abandonWait(requestToken, logicalId, operation, resourceType, lastSeenIdentifier, `${operation} timeout for ${logicalId} after ${maxWaitMs / 1e3}s`, lastTransientError);
27032
27193
  }
27194
+ async resumeCreatedResource(logicalId, resourceType, identifier, properties, context) {
27195
+ const mask = maskerOrIdentity(context?.maskSecrets);
27196
+ const attributeNamesLookup = getTopLevelDeployAttributeNames(resourceType);
27197
+ let raw;
27198
+ try {
27199
+ raw = (await this.cloudControlClient.send(new GetResourceCommand({
27200
+ TypeName: resourceType,
27201
+ Identifier: identifier
27202
+ }))).ResourceDescription?.Properties;
27203
+ } catch (error) {
27204
+ if (error.name === "ResourceNotFoundException") throw Object.assign(new ProvisioningError(`${logicalId}'s resource that an earlier CREATE made no longer exists`, resourceType, logicalId, identifier, error instanceof Error ? error : void 0), { resumedResourceGone: true });
27205
+ throw error;
27206
+ }
27207
+ const model = typeof raw === "string" && raw !== "" ? this.parseResourceModel(raw) : {};
27208
+ const modelKeys = Object.keys(model);
27209
+ const enriched = await this.enrichResourceAttributes(resourceType, identifier, model);
27210
+ return {
27211
+ physicalId: identifier,
27212
+ attributes: await this.maskDeployedNonAttributeKeys(enriched, modelKeys, resourceType, identifier, attributeNamesLookup, properties, mask)
27213
+ };
27214
+ }
27215
+ async resumeAbandonedRequest(requestToken, logicalId, resourceType) {
27216
+ let first;
27217
+ try {
27218
+ first = await this.cloudControlClient.send(new GetResourceRequestStatusCommand({ RequestToken: requestToken }));
27219
+ } catch (error) {
27220
+ if (error.name === "RequestTokenNotFoundException") return { status: "not-found" };
27221
+ return {
27222
+ status: "unresolved",
27223
+ error
27224
+ };
27225
+ }
27226
+ let event = first.ProgressEvent;
27227
+ if (event?.TypeName !== void 0 && event.TypeName !== resourceType || event?.Operation !== void 0 && event.Operation !== "CREATE") return {
27228
+ status: "unresolved",
27229
+ error: /* @__PURE__ */ new Error("the request is not a CREATE of the type the journal records")
27230
+ };
27231
+ if (event !== void 0 && ![
27232
+ "SUCCESS",
27233
+ "FAILED",
27234
+ "CANCEL_COMPLETE"
27235
+ ].includes(String(event.OperationStatus))) try {
27236
+ event = await this.waitForOperation(requestToken, logicalId, "CREATE", resourceType);
27237
+ } catch (error) {
27238
+ if (error instanceof CloudControlOperationFailedError) return failedOutcome$1(error.ccErrorCode, error.physicalId);
27239
+ if (error.ccOperationCancelled === true) {
27240
+ const made = error.physicalId;
27241
+ return made ? {
27242
+ status: "cancelled",
27243
+ remnant: made
27244
+ } : { status: "cancelled" };
27245
+ }
27246
+ if (isInterruptedWaitError(error)) throw error;
27247
+ return {
27248
+ status: "unresolved",
27249
+ error
27250
+ };
27251
+ }
27252
+ switch (event?.OperationStatus) {
27253
+ case "SUCCESS": return event.Identifier ? {
27254
+ status: "succeeded",
27255
+ identifier: event.Identifier
27256
+ } : {
27257
+ status: "unresolved",
27258
+ error: /* @__PURE__ */ new Error("the SUCCESS event named no Identifier")
27259
+ };
27260
+ case "FAILED": return failedOutcome$1(event.ErrorCode, event.Identifier);
27261
+ case "CANCEL_COMPLETE": return event.Identifier ? {
27262
+ status: "cancelled",
27263
+ remnant: event.Identifier
27264
+ } : { status: "cancelled" };
27265
+ default: return {
27266
+ status: "unresolved",
27267
+ error: /* @__PURE__ */ new Error(`unexpected operation status ${String(event?.OperationStatus)}`)
27268
+ };
27269
+ }
27270
+ }
27033
27271
  async abandonWait(requestToken, logicalId, operation, resourceType, lastSeenIdentifier, reason, cause) {
27034
27272
  const described = describePollFailure(cause);
27035
27273
  const safeDisplay = displaySafe(described.display);
27036
27274
  const causeText = safeDisplay === "" ? "" : `: ${safeDisplay}`;
27037
27275
  if (described.detail !== "") this.logger.debug(`${operation} ${logicalId}: the abandoned operation's underlying failure was: ${displaySafe(described.detail)}`);
27038
27276
  const identifierClause = lastSeenIdentifier === void 0 ? "" : ` The last status cdkd read named the resource ${displaySafe(lastSeenIdentifier, { asciiOnly: true })}.`;
27039
- const consequence = operation === "CREATE" ? "cdkd has NO state record for it, so any resource it creates is untracked by rollback and by cdkd destroy" : operation === "DELETE" ? "the resource may or may not have been removed; its state record is kept so a re-run can finish the delete" : "its state record still holds the PREVIOUS properties, so the record may no longer describe the live resource";
27277
+ const consequence = operation === "CREATE" ? "cdkd has NO state record for it: when the failed deploy records the request in the stack's rollback journal, the next cdkd deploy, destroy or rollback checks how it ended, and otherwise any resource it creates is untracked" : operation === "DELETE" ? "the resource may or may not have been removed; its state record is kept so a re-run can finish the delete" : "its state record still holds the PREVIOUS properties, so the record may no longer describe the live resource";
27040
27278
  const error = new CloudControlWaitAbandonedError(safeMsg`${operation} of ${logicalId} was accepted by Cloud Control API, but cdkd stopped waiting for it ` + safeMsg`(${reason}${causeText}). The operation may still be running in AWS, and ${consequence}.` + `${identifierClause} Check what it did with:\n ${await this.buildResumeCommand(requestToken)}`, resourceType, logicalId, requestToken, operation, lastSeenIdentifier, cause instanceof Error ? cause : void 0);
27041
27279
  if (described.marker) markRedactedCause(error);
27042
27280
  return operation === "CREATE" ? markNonRetryable(error) : error;
@@ -28015,7 +28253,10 @@ var TemplateNoEchoReresolver = class TemplateNoEchoReresolver {
28015
28253
  return bag;
28016
28254
  }
28017
28255
  boundParameters() {
28018
- this.parametersPromise ??= this.resolver.resolveParameters(this.options.template, this.options.parameters, { inheritedSecrets: this.newBag() }).catch(() => {
28256
+ this.parametersPromise ??= this.resolver.resolveParameters(this.options.template, this.options.parameters, {
28257
+ inheritedSecrets: this.newBag(),
28258
+ recordPseudoParameters: false
28259
+ }).catch(() => {
28019
28260
  this.logger.debug(safeMsg`Could not bind the parameters of ${this.options.stackName}'s template; NoEcho ` + `coordinates are not re-resolved for its custom resources' deletes.`);
28020
28261
  });
28021
28262
  return this.parametersPromise;
@@ -33443,343 +33684,95 @@ function seedOnlyAliasRefusal(seed) {
33443
33684
  }
33444
33685
 
33445
33686
  //#endregion
33446
- //#region src/state/deployment-events-store.ts
33447
- const DEPLOYMENT_EVENTS_MAX_INDEX_RUNS = 20;
33448
- const FLUSH_INTERVAL_MS = 2e3;
33449
- const FLUSH_EVENT_THRESHOLD = 50;
33450
- function newDeploymentRunId(now = /* @__PURE__ */ new Date()) {
33451
- return `${now.toISOString().replace(/[-:.]/g, "")}-${randomUUID().slice(0, 8)}`;
33452
- }
33453
- function deploymentEventsKey(prefix, stackName, region, runId) {
33454
- return `${prefix}/${stackName}/${region}/deployments/${runId}.jsonl`;
33455
- }
33456
- function deploymentEventsIndexKey(prefix, stackName, region) {
33457
- return `${prefix}/${stackName}/${region}/deployments/index.json`;
33687
+ //#region src/deployment/rollback-executor/orphan-identity.ts
33688
+ const UNIQUE_PHYSICAL_ID_TYPES = /* @__PURE__ */ new Set([
33689
+ "AWS::EC2::VPC",
33690
+ "AWS::EC2::Subnet",
33691
+ "AWS::EC2::EIP",
33692
+ "AWS::EC2::NatGateway",
33693
+ "AWS::EC2::SecurityGroup",
33694
+ "AWS::EC2::Instance",
33695
+ "AWS::EFS::FileSystem",
33696
+ "AWS::EFS::MountTarget",
33697
+ "AWS::FSx::FileSystem",
33698
+ "AWS::KMS::Key",
33699
+ "AWS::CertificateManager::Certificate",
33700
+ "AWS::ElasticLoadBalancingV2::LoadBalancer",
33701
+ "AWS::ElasticLoadBalancingV2::TargetGroup",
33702
+ "AWS::ElasticLoadBalancingV2::Listener",
33703
+ "AWS::EMR::Cluster",
33704
+ "AWS::EMR::InstanceGroupConfig",
33705
+ "AWS::EMR::InstanceFleetConfig",
33706
+ "AWS::Cognito::UserPool",
33707
+ "AWS::Route53::HostedZone",
33708
+ "AWS::ServiceDiscovery::PrivateDnsNamespace",
33709
+ "AWS::ServiceDiscovery::PublicDnsNamespace",
33710
+ "AWS::ServiceDiscovery::HttpNamespace",
33711
+ "AWS::ServiceDiscovery::Service",
33712
+ "AWS::AppSync::GraphQLApi",
33713
+ "AWS::IAM::AccessKey",
33714
+ "AWS::Kinesis::StreamConsumer"
33715
+ ]);
33716
+ const CONTENT_COMPARED_DELETE_TYPES = /* @__PURE__ */ new Set(["AWS::SQS::QueuePolicy", "AWS::SNS::TopicPolicy"]);
33717
+ const CDKD_NAMESPACE_ID_TYPES = /* @__PURE__ */ new Set(["AWS::CloudFormation::Stack"]);
33718
+ function orphanDeleteNeedsIdentity(resourceType) {
33719
+ return !UNIQUE_PHYSICAL_ID_TYPES.has(resourceType) && !CONTENT_COMPARED_DELETE_TYPES.has(resourceType) && !CDKD_NAMESPACE_ID_TYPES.has(resourceType);
33458
33720
  }
33459
- function deploymentsDirPrefix(prefix, stackName, region) {
33460
- return `${prefix}/${stackName}/${region}/deployments/`;
33721
+ function orphanNeedsIdentity(op) {
33722
+ if (op.provisionedBy === "cc-api") return op.createdIdentifierUnique !== true;
33723
+ return orphanDeleteNeedsIdentity(op.resourceType);
33461
33724
  }
33462
- const DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION = "deployment-event streams and their index, whose recorded error messages can quote values the secret mask does not catch";
33463
- async function deleteAndPurgeEventObjects(backend, keys, dirPrefix, scope = "deleted-keys") {
33464
- if (keys.length === 0) return void 0;
33465
- let swept;
33725
+ const RESOURCE_IDENTITY_TIMEOUT_MS = 1e4;
33726
+ async function readResourceIdentity(providerRegistry, target, region, timeoutMs = RESOURCE_IDENTITY_TIMEOUT_MS) {
33727
+ let timer;
33728
+ const timedOut = new Promise((resolve) => {
33729
+ timer = setTimeout(() => resolve(void 0), timeoutMs);
33730
+ });
33466
33731
  try {
33467
- await backend.deleteRawObjects(keys);
33732
+ return await Promise.race([askResourceIdentity(providerRegistry, target, region), timedOut]);
33468
33733
  } finally {
33469
- if (scope === "whole-dir") swept = await backend.purgeNoncurrentVersionsUnderPrefix(dirPrefix, { objectDescription: DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION });
33470
- else await backend.purgeNoncurrentVersions(keys, {
33471
- ...keys.length > 1 && { listPrefix: dirPrefix },
33472
- objectDescription: DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION
33473
- });
33734
+ clearTimeout(timer);
33474
33735
  }
33475
- return swept;
33476
- }
33477
- function runIdTimestampMs(runId) {
33478
- const m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})Z/.exec(runId);
33479
- if (!m) return null;
33480
- const iso = `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}.${m[7]}Z`;
33481
- const ms = Date.parse(iso);
33482
- return Number.isNaN(ms) ? null : ms;
33483
- }
33484
- function runIdFromJsonlKey(key, dirPrefix) {
33485
- if (!key.startsWith(dirPrefix) || !key.endsWith(".jsonl")) return null;
33486
- return key.slice(dirPrefix.length, -6);
33487
33736
  }
33488
- var DeploymentEventsStore = class {
33489
- logger = getLogger().child("DeploymentEvents");
33490
- backend;
33491
- stackName;
33492
- region;
33493
- command;
33494
- runId;
33495
- cdkdVersion;
33496
- startedAt;
33497
- events = [];
33498
- persistedCount = 0;
33499
- flushTimer;
33500
- writeChain = Promise.resolve();
33501
- warnedOnce = false;
33502
- finalized = false;
33503
- constructor(backend, options) {
33504
- this.backend = backend;
33505
- this.stackName = options.stackName;
33506
- this.region = options.region;
33507
- this.command = options.command;
33508
- this.runId = options.runId ?? newDeploymentRunId();
33509
- this.cdkdVersion = options.cdkdVersion ?? getCdkdVersion();
33510
- this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
33511
- }
33512
- record(event) {
33513
- try {
33514
- if (this.finalized) return;
33515
- this.events.push({
33516
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
33517
- ...event
33518
- });
33519
- if (this.events.length - this.persistedCount >= FLUSH_EVENT_THRESHOLD) this.scheduleFlush(0);
33520
- else this.scheduleFlush(FLUSH_INTERVAL_MS);
33521
- } catch {}
33522
- }
33523
- async finalize(result) {
33524
- if (this.finalized) return;
33525
- this.finalized = true;
33526
- if (this.flushTimer) {
33527
- clearTimeout(this.flushTimer);
33528
- this.flushTimer = void 0;
33529
- }
33530
- if (this.events.length === 0) return;
33531
- await this.enqueueWrite(async () => {
33532
- const indexRead = this.readIndexRuns();
33533
- indexRead.catch(() => {});
33534
- await this.doFlush();
33535
- await this.writeIndexAndPrune(result, await indexRead);
33536
- });
33537
- }
33538
- async writeIndexAndPrune(result, existingRuns) {
33539
- const { key, file, runs } = this.buildIndexUpdate(result, existingRuns);
33540
- const keptRunIds = runs.map((r) => r.runId);
33541
- const willPrune = keptRunIds.length >= 20;
33542
- const dirPrefix = deploymentsDirPrefix(this.backend.prefix, this.stackName, this.region);
33543
- const staleKeysRead = willPrune ? this.backend.listRawKeys(dirPrefix) : void 0;
33544
- staleKeysRead?.catch(() => {});
33545
- await this.backend.putRawObject(key, JSON.stringify(file, null, 2));
33546
- if (!staleKeysRead) return;
33547
- await this.pruneSupersededRunFiles(keptRunIds, dirPrefix, await staleKeysRead);
33548
- }
33549
- async drain() {
33550
- await this.writeChain;
33551
- }
33552
- scheduleFlush(delayMs) {
33553
- if (this.flushTimer) {
33554
- if (delayMs > 0) return;
33555
- clearTimeout(this.flushTimer);
33556
- }
33557
- this.flushTimer = setTimeout(() => {
33558
- this.flushTimer = void 0;
33559
- this.enqueueWrite(() => this.doFlush());
33560
- }, delayMs);
33561
- this.flushTimer.unref?.();
33562
- }
33563
- enqueueWrite(op) {
33564
- const next = this.writeChain.then(op).catch((err) => {
33565
- this.warnOnce(`Failed to persist deployment events for run ${this.runId}: ${describeAwsFailure(err).detail}`);
33566
- });
33567
- this.writeChain = next;
33568
- return next;
33569
- }
33570
- async doFlush() {
33571
- if (this.events.length === 0 || this.events.length === this.persistedCount) return;
33572
- const snapshotCount = this.events.length;
33573
- const body = this.events.slice(0, snapshotCount).map((e) => JSON.stringify(e)).join("\n");
33574
- await this.backend.putRawObject(deploymentEventsKey(this.backend.prefix, this.stackName, this.region, this.runId), body + "\n", "application/x-ndjson");
33575
- this.persistedCount = snapshotCount;
33576
- }
33577
- async readIndexRuns() {
33578
- const key = deploymentEventsIndexKey(this.backend.prefix, this.stackName, this.region);
33579
- try {
33580
- const raw = await this.backend.getRawObject(key);
33581
- if (raw !== null) {
33582
- const parsed = JSON.parse(raw);
33583
- if (Array.isArray(parsed.runs)) return parsed.runs;
33584
- }
33585
- } catch (err) {
33586
- this.logger.debug(`Deployment-events index unreadable, rewriting: ${describeAwsFailure(err).detail}`);
33587
- }
33588
- return [];
33589
- }
33590
- buildIndexUpdate(result, existingRuns) {
33591
- const key = deploymentEventsIndexKey(this.backend.prefix, this.stackName, this.region);
33592
- const runs = [{
33593
- runId: this.runId,
33594
- command: this.command,
33595
- cdkdVersion: this.cdkdVersion,
33596
- startedAt: this.startedAt,
33597
- finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
33598
- result,
33599
- eventCount: this.persistedCount
33600
- }, ...existingRuns.filter((r) => r.runId !== this.runId)].slice(0, 20);
33601
- return {
33602
- key,
33603
- file: {
33604
- indexVersion: 1,
33605
- stackName: this.stackName,
33606
- region: this.region,
33607
- runs,
33608
- lastModified: Date.now()
33609
- },
33610
- runs
33611
- };
33612
- }
33613
- async pruneSupersededRunFiles(keptRunIds, dirPrefix, keys) {
33614
- if (keptRunIds.length < 20) return;
33615
- const cutoff = keptRunIds.reduce((min, id) => id < min ? id : min, keptRunIds[0]);
33616
- const stale = keys.filter((k) => {
33617
- const runId = runIdFromJsonlKey(k, dirPrefix);
33618
- return runId !== null && runId < cutoff;
33737
+ async function askResourceIdentity(providerRegistry, target, region) {
33738
+ try {
33739
+ const { provider } = providerRegistry.getProviderFor({
33740
+ resourceType: target.resourceType,
33741
+ provisionedBy: target.provisionedBy
33619
33742
  });
33620
- if (stale.length === 0) return;
33621
- await deleteAndPurgeEventObjects(this.backend, stale, dirPrefix);
33622
- this.logger.debug(`Pruned ${stale.length} superseded deployment-event stream(s) for ${this.stackName} (${this.region})`);
33623
- }
33624
- warnOnce(message) {
33625
- if (this.warnedOnce) {
33626
- this.logger.debug(message);
33627
- return;
33628
- }
33629
- this.warnedOnce = true;
33630
- this.logger.warn(`${message} — continuing; deployment events are best-effort and never block the run.`);
33631
- }
33632
- };
33633
- var DeploymentEventsReader = class {
33634
- backend;
33635
- constructor(backend) {
33636
- this.backend = backend;
33637
- }
33638
- async listRegions(stackName) {
33639
- const prefix = `${this.backend.prefix}/${stackName}/`;
33640
- const keys = await this.backend.listRawKeys(prefix);
33641
- const regions = /* @__PURE__ */ new Set();
33642
- for (const key of keys) {
33643
- const segments = key.slice(prefix.length).split("/");
33644
- if (segments.length === 3 && segments[1] === "deployments" && segments[0]) regions.add(segments[0]);
33645
- }
33646
- return [...regions].sort();
33647
- }
33648
- async listRuns(stackName, region) {
33649
- const key = deploymentEventsIndexKey(this.backend.prefix, stackName, region);
33650
- try {
33651
- const raw = await this.backend.getRawObject(key);
33652
- if (raw !== null) {
33653
- const parsed = JSON.parse(raw);
33654
- if (Array.isArray(parsed.runs)) return parsed.runs;
33655
- }
33656
- } catch {}
33657
- const dirPrefix = `${this.backend.prefix}/${stackName}/${region}/deployments/`;
33658
- const runIds = (await this.backend.listRawKeys(dirPrefix)).filter((k) => k.endsWith(".jsonl")).map((k) => k.slice(dirPrefix.length, -6)).sort().reverse();
33659
- return Promise.all(runIds.map((runId) => this.summarizeRunFromJsonl(stackName, region, runId)));
33660
- }
33661
- async summarizeRunFromJsonl(stackName, region, runId) {
33662
- const fallback = {
33663
- runId,
33664
- command: "deploy",
33665
- cdkdVersion: "unknown",
33666
- startedAt: "",
33667
- finishedAt: "",
33668
- result: "UNKNOWN",
33669
- eventCount: 0
33670
- };
33671
- let events = null;
33672
- try {
33673
- events = await this.readRunEvents(stackName, region, runId);
33674
- } catch {
33675
- return fallback;
33676
- }
33677
- if (events === null || events.length === 0) return fallback;
33678
- const started = events.find((e) => e.eventType === "RUN_STARTED");
33679
- let finished;
33680
- for (const e of events) if (e.eventType === "RUN_FINISHED") finished = e;
33681
- return {
33682
- runId,
33683
- command: started?.command ?? fallback.command,
33684
- cdkdVersion: started?.cdkdVersion ?? fallback.cdkdVersion,
33685
- startedAt: started?.timestamp ?? fallback.startedAt,
33686
- finishedAt: finished?.timestamp ?? fallback.finishedAt,
33687
- result: finished?.result ?? "UNKNOWN",
33688
- eventCount: events.length
33689
- };
33690
- }
33691
- async readRunEvents(stackName, region, runId) {
33692
- const key = deploymentEventsKey(this.backend.prefix, stackName, region, runId);
33693
- const raw = await this.backend.getRawObject(key);
33694
- if (raw === null) return null;
33695
- const events = [];
33696
- for (const line of raw.split("\n")) {
33697
- const trimmed = line.trim();
33698
- if (!trimmed) continue;
33699
- try {
33700
- events.push(JSON.parse(trimmed));
33701
- } catch {}
33702
- }
33703
- return events;
33743
+ if (typeof provider.resourceIdentity !== "function") return void 0;
33744
+ const identity = await provider.resourceIdentity(target.physicalId, target.resourceType, { expectedRegion: region });
33745
+ if (identity === RESOURCE_NOT_FOUND) return RESOURCE_NOT_FOUND;
33746
+ return typeof identity === "string" && identity !== "" ? identity : void 0;
33747
+ } catch {
33748
+ return;
33704
33749
  }
33705
- async pruneRuns(stackName, region, opts = {}) {
33706
- const dirPrefix = deploymentsDirPrefix(this.backend.prefix, stackName, region);
33707
- const keys = await this.backend.listRawKeys(dirPrefix);
33708
- const runIdsDesc = keys.map((k) => runIdFromJsonlKey(k, dirPrefix)).filter((id) => id !== null).sort().reverse();
33709
- const indexKey = deploymentEventsIndexKey(this.backend.prefix, stackName, region);
33710
- const indexExisted = keys.includes(indexKey);
33711
- if (opts.all === true) {
33712
- const toDelete = runIdsDesc.map((id) => deploymentEventsKey(this.backend.prefix, stackName, region, id));
33713
- const earlierVersions = await deleteAndPurgeEventObjects(this.backend, [...toDelete, indexKey], dirPrefix, "whole-dir");
33714
- return {
33715
- deletedRunIds: runIdsDesc,
33716
- remainingRunIds: [],
33717
- indexDeleted: indexExisted,
33718
- ...earlierVersions !== void 0 && { earlierVersions }
33719
- };
33720
- }
33721
- const noGuards = opts.keep === void 0 && opts.olderThanMs === void 0;
33722
- const keep = opts.keep ?? (noGuards ? 20 : void 0);
33723
- const protectedByCount = keep === void 0 ? /* @__PURE__ */ new Set() : new Set(runIdsDesc.slice(0, keep));
33724
- let candidates = runIdsDesc.filter((id) => !protectedByCount.has(id));
33725
- if (opts.olderThanMs !== void 0) {
33726
- const cutoff = (opts.now ?? /* @__PURE__ */ new Date()).getTime() - opts.olderThanMs;
33727
- candidates = candidates.filter((id) => {
33728
- const t = runIdTimestampMs(id);
33729
- return t !== null && t < cutoff;
33730
- });
33731
- }
33732
- if (candidates.length === 0) return {
33733
- deletedRunIds: [],
33734
- remainingRunIds: runIdsDesc,
33735
- indexDeleted: false
33736
- };
33737
- const deletedSet = new Set(candidates);
33738
- const deleteKeys = candidates.map((id) => deploymentEventsKey(this.backend.prefix, stackName, region, id));
33739
- const remainingRunIds = runIdsDesc.filter((id) => !deletedSet.has(id));
33740
- if (remainingRunIds.length === 0) {
33741
- await deleteAndPurgeEventObjects(this.backend, [...deleteKeys, indexKey], dirPrefix);
33742
- return {
33743
- deletedRunIds: candidates,
33744
- remainingRunIds,
33745
- indexDeleted: indexExisted
33746
- };
33747
- }
33748
- await this.rewriteIndexAfterPrune(indexKey, stackName, region, deletedSet);
33749
- await deleteAndPurgeEventObjects(this.backend, deleteKeys, dirPrefix);
33750
+ }
33751
+ async function createdResourceStillThere(op, ctx) {
33752
+ if (op.deletionPolicy === "Retain") return "proven";
33753
+ if (!orphanNeedsIdentity(op)) return "proven";
33754
+ const physicalId = op.physicalId;
33755
+ if (!physicalId) return "unproven";
33756
+ const live = await readResourceIdentity(ctx.providerRegistry, {
33757
+ resourceType: op.resourceType,
33758
+ physicalId,
33759
+ provisionedBy: op.provisionedBy
33760
+ }, ctx.region);
33761
+ if (live === RESOURCE_NOT_FOUND) return "gone";
33762
+ const journaled = op.createdResourceIdentity;
33763
+ if (typeof journaled !== "string" || journaled === "" || typeof live !== "string") return "unproven";
33764
+ return live === journaled ? "proven" : "mismatch";
33765
+ }
33766
+ async function askForeignHolder(foreignHolder, op) {
33767
+ try {
33768
+ return await foreignHolder(op.resourceType, op.physicalId);
33769
+ } catch {
33750
33770
  return {
33751
- deletedRunIds: candidates,
33752
- remainingRunIds,
33753
- indexDeleted: false
33754
- };
33755
- }
33756
- async rewriteIndexAfterPrune(indexKey, stackName, region, deletedRunIds) {
33757
- let raw;
33758
- try {
33759
- raw = await this.backend.getRawObject(indexKey);
33760
- } catch {
33761
- return;
33762
- }
33763
- if (raw === null) return;
33764
- let parsed;
33765
- try {
33766
- parsed = JSON.parse(raw);
33767
- } catch {
33768
- return;
33769
- }
33770
- if (!Array.isArray(parsed.runs)) return;
33771
- const remaining = parsed.runs.filter((r) => !deletedRunIds.has(r.runId));
33772
- if (remaining.length === parsed.runs.length) return;
33773
- const file = {
33774
- indexVersion: 1,
33775
- stackName,
33776
- region,
33777
- runs: remaining,
33778
- lastModified: Date.now()
33771
+ kind: "unreadable",
33772
+ what: "the other stacks' state records (the scan failed)"
33779
33773
  };
33780
- await this.backend.putRawObject(indexKey, JSON.stringify(file, null, 2));
33781
33774
  }
33782
- };
33775
+ }
33783
33776
 
33784
33777
  //#endregion
33785
33778
  //#region src/deployment/rollback-executor/replay-scope.ts
@@ -34089,93 +34082,6 @@ function renderNestedStackTypeChangeRefusal(typeChanges, stackName) {
34089
34082
  return `Refusing to deploy ${stackName}: ` + (typeChanges.length === 1 ? `a resource changes its Type ` : `${typeChanges.length} resources change their Type `) + `into or out of ${NESTED_STACK_RESOURCE_TYPE}, which cdkd does not replace in place.\n${rows.join("\n")}\n Deploy this as two changes instead: give the new resource a DIFFERENT logical id (in CDK, rename the construct) so the existing row is deleted through its own type's provider and the new one is created under its own — or remove the resource in one deploy and add its replacement in the next. There is no flag that overrides this refusal.`;
34090
34083
  }
34091
34084
 
34092
- //#endregion
34093
- //#region src/deployment/rollback-executor/orphan-identity.ts
34094
- const UNIQUE_PHYSICAL_ID_TYPES = /* @__PURE__ */ new Set([
34095
- "AWS::EC2::VPC",
34096
- "AWS::EC2::Subnet",
34097
- "AWS::EC2::EIP",
34098
- "AWS::EC2::NatGateway",
34099
- "AWS::EC2::SecurityGroup",
34100
- "AWS::EC2::Instance",
34101
- "AWS::EFS::FileSystem",
34102
- "AWS::EFS::MountTarget",
34103
- "AWS::FSx::FileSystem",
34104
- "AWS::KMS::Key",
34105
- "AWS::CertificateManager::Certificate",
34106
- "AWS::ElasticLoadBalancingV2::LoadBalancer",
34107
- "AWS::ElasticLoadBalancingV2::TargetGroup",
34108
- "AWS::ElasticLoadBalancingV2::Listener",
34109
- "AWS::EMR::Cluster",
34110
- "AWS::EMR::InstanceGroupConfig",
34111
- "AWS::EMR::InstanceFleetConfig",
34112
- "AWS::Cognito::UserPool",
34113
- "AWS::Route53::HostedZone",
34114
- "AWS::ServiceDiscovery::PrivateDnsNamespace",
34115
- "AWS::ServiceDiscovery::PublicDnsNamespace",
34116
- "AWS::ServiceDiscovery::HttpNamespace",
34117
- "AWS::ServiceDiscovery::Service",
34118
- "AWS::AppSync::GraphQLApi",
34119
- "AWS::IAM::AccessKey",
34120
- "AWS::Kinesis::StreamConsumer"
34121
- ]);
34122
- const CONTENT_COMPARED_DELETE_TYPES = /* @__PURE__ */ new Set(["AWS::SQS::QueuePolicy", "AWS::SNS::TopicPolicy"]);
34123
- const CDKD_NAMESPACE_ID_TYPES = /* @__PURE__ */ new Set(["AWS::CloudFormation::Stack"]);
34124
- function orphanDeleteNeedsIdentity(resourceType) {
34125
- return !UNIQUE_PHYSICAL_ID_TYPES.has(resourceType) && !CONTENT_COMPARED_DELETE_TYPES.has(resourceType) && !CDKD_NAMESPACE_ID_TYPES.has(resourceType);
34126
- }
34127
- const RESOURCE_IDENTITY_TIMEOUT_MS = 1e4;
34128
- async function readResourceIdentity(providerRegistry, target, region, timeoutMs = RESOURCE_IDENTITY_TIMEOUT_MS) {
34129
- let timer;
34130
- const timedOut = new Promise((resolve) => {
34131
- timer = setTimeout(() => resolve(void 0), timeoutMs);
34132
- });
34133
- try {
34134
- return await Promise.race([askResourceIdentity(providerRegistry, target, region), timedOut]);
34135
- } finally {
34136
- clearTimeout(timer);
34137
- }
34138
- }
34139
- async function askResourceIdentity(providerRegistry, target, region) {
34140
- try {
34141
- const { provider } = providerRegistry.getProviderFor({
34142
- resourceType: target.resourceType,
34143
- provisionedBy: target.provisionedBy
34144
- });
34145
- if (typeof provider.resourceIdentity !== "function") return void 0;
34146
- const identity = await provider.resourceIdentity(target.physicalId, target.resourceType, { expectedRegion: region });
34147
- if (identity === RESOURCE_NOT_FOUND) return RESOURCE_NOT_FOUND;
34148
- return typeof identity === "string" && identity !== "" ? identity : void 0;
34149
- } catch {
34150
- return;
34151
- }
34152
- }
34153
- async function createdResourceStillThere(op, ctx) {
34154
- if (op.deletionPolicy === "Retain") return "proven";
34155
- if (!orphanDeleteNeedsIdentity(op.resourceType)) return "proven";
34156
- const physicalId = op.physicalId;
34157
- if (!physicalId) return "unproven";
34158
- const live = await readResourceIdentity(ctx.providerRegistry, {
34159
- resourceType: op.resourceType,
34160
- physicalId,
34161
- provisionedBy: op.provisionedBy
34162
- }, ctx.region);
34163
- if (live === RESOURCE_NOT_FOUND) return "gone";
34164
- const journaled = op.createdResourceIdentity;
34165
- if (typeof journaled !== "string" || journaled === "" || typeof live !== "string") return "unproven";
34166
- return live === journaled ? "proven" : "mismatch";
34167
- }
34168
- async function askForeignHolder(foreignHolder, op) {
34169
- try {
34170
- return await foreignHolder(op.resourceType, op.physicalId);
34171
- } catch {
34172
- return {
34173
- kind: "unreadable",
34174
- what: "the other stacks' state records (the scan failed)"
34175
- };
34176
- }
34177
- }
34178
-
34179
34085
  //#endregion
34180
34086
  //#region src/deployment/rollback-executor/plan.ts
34181
34087
  function journaledOldTypes(op) {
@@ -35632,7 +35538,7 @@ async function replayRollbackUnbound(operations, stateResources, stackName, ctx,
35632
35538
  }
35633
35539
  function protectionRemovalProven(op, deleteProven) {
35634
35540
  if (op.physicalIdRecoveredFromError !== true) return true;
35635
- return deleteProven && (!orphanDeleteNeedsIdentity(op.resourceType) || removeProtectionTypes().includes(op.resourceType));
35541
+ return deleteProven && (!orphanNeedsIdentity(op) || removeProtectionTypes().includes(op.resourceType));
35636
35542
  }
35637
35543
  async function journaledOrphanKeepReason(op, foreignHolder, ctx) {
35638
35544
  const holding = await askForeignHolder(foreignHolder, op);
@@ -36050,6 +35956,344 @@ async function replayFailedOperations(...args) {
36050
35956
  return await withProducerRegions(() => replayProducerRegionEvidence(args[3]), () => withStackRecords(replayStackRecordsView(args[1]), () => replayFailedOperationsUnbound(...args)));
36051
35957
  }
36052
35958
 
35959
+ //#endregion
35960
+ //#region src/provisioning/nested-stack-context.ts
35961
+ const storage$1 = new AsyncLocalStorage();
35962
+ function withNestedStackContext(ctx, fn) {
35963
+ return storage$1.run(ctx, fn);
35964
+ }
35965
+ function getCurrentNestedStackContext() {
35966
+ return storage$1.getStore();
35967
+ }
35968
+ async function collectNestedChildUnaddressed(fn) {
35969
+ const ctx = storage$1.getStore();
35970
+ if (!ctx) return {
35971
+ value: await fn(),
35972
+ unaddressed: void 0
35973
+ };
35974
+ const slot = {};
35975
+ return {
35976
+ value: await storage$1.run({
35977
+ ...ctx,
35978
+ childUnaddressed: slot
35979
+ }, fn),
35980
+ unaddressed: slot.last
35981
+ };
35982
+ }
35983
+
35984
+ //#endregion
35985
+ //#region src/deployment/nested-child-journal.ts
35986
+ const NESTED_PENDING_PARENT_REASON = "nested-pending-parent";
35987
+ const NESTED_STACK_TYPE$2 = "AWS::CloudFormation::Stack";
35988
+ const MAX_NESTED_WALK_DEPTH = 32;
35989
+ function nestedChildStackName(parentStackName, logicalId) {
35990
+ return `${parentStackName}~${logicalId}`;
35991
+ }
35992
+ function nestedPendingSnapshot(state, refusesExportName) {
35993
+ const outputs = { ...isPlainRecord(state.outputs) ? state.outputs : {} };
35994
+ let exportNames = Array.isArray(state.exportNames) ? [...state.exportNames] : void 0;
35995
+ const refused = new Set(importableOutputKeys(state).filter((name) => refusesExportName(name)));
35996
+ if (refused.size > 0) {
35997
+ for (const name of refused) Reflect.deleteProperty(outputs, name);
35998
+ if (exportNames !== void 0) exportNames = exportNames.filter((name) => !refused.has(name));
35999
+ }
36000
+ return {
36001
+ previousOutputs: {
36002
+ outputs,
36003
+ ...exportNames !== void 0 && { exportNames }
36004
+ },
36005
+ previousCrossStackReads: {
36006
+ ...Array.isArray(state.imports) && { imports: [...state.imports] },
36007
+ ...Array.isArray(state.outputReads) && { outputReads: [...state.outputReads] }
36008
+ }
36009
+ };
36010
+ }
36011
+ function displacedPhysicalIdShown(op, logger, physicalId = journalOpPhysicalId(op)) {
36012
+ if (physicalId === void 0) return void 0;
36013
+ const masker = createOpMasker(logger, /* @__PURE__ */ new Map());
36014
+ for (const properties of [
36015
+ op.properties,
36016
+ op.attemptedProperties,
36017
+ op.previousState?.properties
36018
+ ]) {
36019
+ if (properties === void 0) continue;
36020
+ masker.addNamed({
36021
+ resourceType: op.resourceType,
36022
+ properties,
36023
+ logicalId: op.logicalId,
36024
+ physicalIds: [physicalId]
36025
+ });
36026
+ }
36027
+ return displaySafe(String(masker.mask(physicalId)));
36028
+ }
36029
+ function displacedOpClause(op, marks, logger) {
36030
+ const retainedOld = retainedOldPhysicalId(op);
36031
+ if (retainedOld !== void 0 && marks.some((m) => isMarkFor(m, op))) {
36032
+ const shownOld = displacedPhysicalIdShown(op, logger, retainedOld);
36033
+ return `replaced ${shownOld} ${op.oldResourceRetained === true ? "but kept it (UpdateReplacePolicy: Retain)" : op.oldResourceMaySurvive !== void 0 ? "and may have kept it (its delete was not confirmed)" : "and may have kept it (the journal records no verdict)"}; cdkd import adopted the replacement, so ${shownOld} is left untracked`;
36034
+ }
36035
+ const shownId = displacedPhysicalIdShown(op, logger);
36036
+ return shownId !== void 0 ? `recorded ${shownId}, which cdkd import has since replaced under this id` : "recorded no physical id, and cdkd import has since put another resource under this id";
36037
+ }
36038
+ function recordDisplacedSkips(recordEvent, stackName, ops) {
36039
+ for (const op of ops) recordEvent?.({
36040
+ eventType: "ROLLBACK_RESOURCE_SKIPPED",
36041
+ stackName,
36042
+ operation: op.changeType,
36043
+ logicalId: op.logicalId,
36044
+ resourceType: op.resourceType,
36045
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy },
36046
+ reason: "cdkd import has since put another resource under this logical id, so the op was not reverted; check the resource it recorded by hand"
36047
+ });
36048
+ }
36049
+ function revertedNestedRowIds(ops) {
36050
+ return ops.filter((op) => op.resourceType === NESTED_STACK_TYPE$2 && op.changeType === "UPDATE").map((op) => op.logicalId);
36051
+ }
36052
+ const revertRunStorage = new AsyncLocalStorage();
36053
+ function withNestedRevertRun(runId, fn) {
36054
+ const run = {
36055
+ runId,
36056
+ settled: /* @__PURE__ */ new Map(),
36057
+ warnings: 0
36058
+ };
36059
+ return revertRunStorage.run(run, () => fn(run));
36060
+ }
36061
+ function getNestedRevertRun() {
36062
+ return revertRunStorage.getStore();
36063
+ }
36064
+ function errorText(error) {
36065
+ return displaySafe(describeAwsFailure(error).detail);
36066
+ }
36067
+ function isPlainRecord(value) {
36068
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36069
+ }
36070
+ async function dropNestedChildJournals(args) {
36071
+ const { stateBackend, parentStackName, region, resources, logger } = args;
36072
+ const depth = args.depth ?? 0;
36073
+ if (!isPlainRecord(resources)) return;
36074
+ if (depthExceeded(depth, parentStackName, logger)) return;
36075
+ for (const [logicalId, record] of Object.entries(resources)) {
36076
+ if (!isPlainRecord(record) || record["resourceType"] !== NESTED_STACK_TYPE$2) continue;
36077
+ const child = nestedChildStackName(parentStackName, logicalId);
36078
+ try {
36079
+ const data = await stateBackend.getState(child, region);
36080
+ if (data && isPlainRecord(data.state) && isPlainRecord(data.state.resources) && (data.state.stackName === void 0 || data.state.stackName === child)) await dropNestedChildJournals({
36081
+ ...args,
36082
+ parentStackName: child,
36083
+ resources: data.state.resources,
36084
+ depth: depth + 1
36085
+ });
36086
+ } catch (error) {
36087
+ warnUncleared(logger, child, error);
36088
+ }
36089
+ try {
36090
+ if (await withChildLock(args.lockManager, child, region, logger, async () => {
36091
+ if (args.beforeDelete) {
36092
+ if (!await args.beforeDelete(child, await readOwnRecord(stateBackend, child, region))) return false;
36093
+ }
36094
+ let gone;
36095
+ try {
36096
+ gone = await stateBackend.deleteRollbackJournal(child, region);
36097
+ } catch (error) {
36098
+ await args.onDeleteFailed?.(child);
36099
+ throw error;
36100
+ }
36101
+ if (gone === false) {
36102
+ await args.onDeleteFailed?.(child);
36103
+ return false;
36104
+ }
36105
+ return true;
36106
+ })) logger.debug(safeMsg`Deleted the rollback journal of nested stack ${displaySafe(child)}`);
36107
+ } catch (error) {
36108
+ warnUncleared(logger, child, error);
36109
+ }
36110
+ }
36111
+ }
36112
+ async function readOwnRecord(stateBackend, child, region) {
36113
+ try {
36114
+ const data = await stateBackend.getState(child, region);
36115
+ if (data && isPlainRecord(data.state) && isPlainRecord(data.state.resources) && (data.state.stackName === void 0 || data.state.stackName === child)) return data.state;
36116
+ } catch {}
36117
+ }
36118
+ async function dropSettledNestedJournals(args) {
36119
+ const { stateBackend, parentStackName, region, runId, logger } = args;
36120
+ const depth = args.depth ?? 0;
36121
+ if (runId === void 0) return;
36122
+ if (depthExceeded(depth, parentStackName, logger)) return;
36123
+ const isSettled = (segment) => segment.runId === runId && segment.reason === "nested-pending-parent";
36124
+ for (const [logicalId, grandchildren] of args.settled) {
36125
+ const child = nestedChildStackName(parentStackName, logicalId);
36126
+ if (grandchildren.size > 0) await dropSettledNestedJournals({
36127
+ ...args,
36128
+ parentStackName: child,
36129
+ settled: grandchildren,
36130
+ depth: depth + 1
36131
+ });
36132
+ try {
36133
+ const removed = await withChildLock(args.lockManager, child, region, logger, () => stateBackend.dropRollbackJournalSegments(child, region, isSettled));
36134
+ if (removed > 0) logger.debug(safeMsg`Dropped ${removed} settled rollback journal segment(s) of ${displaySafe(child)}`);
36135
+ } catch (error) {
36136
+ warnUncleared(logger, child, error);
36137
+ }
36138
+ }
36139
+ }
36140
+ async function withChildLock(lockManager, child, region, logger, fn) {
36141
+ await lockManager.acquireLockWithRetry(child, region, void 0, "rollback");
36142
+ try {
36143
+ return await fn();
36144
+ } finally {
36145
+ await lockManager.releaseLock(child, region).catch((error) => {
36146
+ logger.warn(safeMsg`Failed to release the lock of nested stack ${displayIdent(child)}: ${errorText(error)}`);
36147
+ });
36148
+ }
36149
+ }
36150
+ function depthExceeded(depth, parentStackName, logger) {
36151
+ if (depth < MAX_NESTED_WALK_DEPTH) return false;
36152
+ logger.warn(safeMsg`Stopped clearing nested rollback journals below ${displayIdent(parentStackName)}: ` + safeMsg`the nesting is deeper than ${MAX_NESTED_WALK_DEPTH} levels.`);
36153
+ return true;
36154
+ }
36155
+ function warnUncleared(logger, child, error) {
36156
+ logger.warn(safeMsg`Could not clear the rollback journal of nested stack ${displayIdent(child)}: ${errorText(error)}. ` + "It is inert to every parent revert (they select segments by run) and the next successful deploy of the top-level stack removes it.");
36157
+ }
36158
+ async function revertNestedChildFromJournal(args) {
36159
+ const { ctx, logicalId, childStackName, region, run, logger } = args;
36160
+ const runId = run.runId;
36161
+ const shownChild = displayIdent(childStackName);
36162
+ const refuse = (detail) => {
36163
+ throw markNonRetryable(/* @__PURE__ */ new Error(`Cannot revert nested stack ${shownChild} (row ${displayIdent(logicalId)}): ${detail} The child was NOT (fully) reverted and may still hold the failed deploy's configuration. Inspect it with 'cdkd state show'; re-run the rollback once the cause is fixed (its journal is kept), or re-deploy the parent to converge.`));
36164
+ };
36165
+ if (runId === void 0) refuse("the rollback carries no deploy run id to select its journal segments by.");
36166
+ await ctx.lockManager.acquireLockWithRetry(childStackName, region, void 0, "rollback");
36167
+ try {
36168
+ const stateData = await ctx.stateBackend.getState(childStackName, region);
36169
+ if (!stateData) refuse("its state.json is missing.");
36170
+ if (stateData.divergentBodyRegion !== void 0) refuse("its state record's region field disagrees with the key it is stored under.");
36171
+ const base = stateData.state;
36172
+ const refusalRecovery = {
36173
+ profile: ctx.destroyOptions?.profile,
36174
+ stateBucket: ctx.stateBucket,
36175
+ statePrefix: ctx.destroyOptions?.statePrefix
36176
+ };
36177
+ refuseMalformedState(base, childStackName, region, refusalRecovery);
36178
+ refuseMalformedOrphans(base, childStackName, region, refusalRecovery);
36179
+ refuseMalformedOrphanRecords(base, childStackName, region, refusalRecovery);
36180
+ const segments = ((await ctx.stateBackend.loadRollbackJournal(childStackName, region))?.segments ?? []).filter((segment) => segment.runId === runId);
36181
+ if (segments.length === 0) refuse("its rollback journal holds no segment for this deploy run, so there is no record of what it held before.");
36182
+ const stateResources = { ...base.resources };
36183
+ const mintedOrphans = [];
36184
+ const restoredOutputs = segments.find((s) => s.previousOutputs)?.previousOutputs;
36185
+ const restoredReads = segments.find((s) => s.previousCrossStackReads)?.previousCrossStackReads;
36186
+ let currentEtag = stateData.etag;
36187
+ let persisted = false;
36188
+ let restoring = false;
36189
+ const { skippedOutputs: _dropped, ...carried } = base;
36190
+ const next = () => ({
36191
+ ...carried,
36192
+ version: 12,
36193
+ region,
36194
+ resources: { ...stateResources },
36195
+ ...orphansAfterRollback(base, mintedOrphans),
36196
+ ...restoring && restoredOutputs && { outputs: { ...restoredOutputs.outputs } },
36197
+ ...restoring && restoredReads && {
36198
+ ...restoredReads.imports && { imports: [...restoredReads.imports] },
36199
+ ...restoredReads.outputReads && { outputReads: [...restoredReads.outputReads] }
36200
+ },
36201
+ ...restoring && restoredOutputs?.exportNames && { exportNames: [...restoredOutputs.exportNames] },
36202
+ lastModified: Date.now()
36203
+ });
36204
+ const nextState = () => {
36205
+ const state = next();
36206
+ if (!restoring) return state;
36207
+ if (restoredOutputs && !restoredOutputs.exportNames) delete state.exportNames;
36208
+ if (restoredOutputs) delete state.outputReferenceProvenance;
36209
+ if (restoredReads && !restoredReads.imports) delete state.imports;
36210
+ if (restoredReads && !restoredReads.outputReads) delete state.outputReads;
36211
+ return state;
36212
+ };
36213
+ const save = async () => {
36214
+ persisted = false;
36215
+ try {
36216
+ currentEtag = await ctx.stateBackend.saveState(childStackName, region, nextState(), { ...currentEtag !== void 0 && { expectedEtag: currentEtag } });
36217
+ persisted = true;
36218
+ } catch {
36219
+ try {
36220
+ const fresh = await ctx.stateBackend.getState(childStackName, region);
36221
+ currentEtag = await ctx.stateBackend.saveState(childStackName, region, nextState(), { ...fresh?.etag !== void 0 && { expectedEtag: fresh.etag } });
36222
+ persisted = true;
36223
+ } catch (retryError) {
36224
+ logger.warn(safeMsg`Failed to persist the state of nested stack ${shownChild} after reverting it: ` + safeMsg`${errorText(retryError)}. The resources were reverted in AWS.`);
36225
+ }
36226
+ }
36227
+ };
36228
+ const producerRegions = inheritProducerRegions(producerRegionsFromState({
36229
+ imports: [...base.imports ?? [], ...restoredReads?.imports ?? []],
36230
+ outputReads: [...base.outputReads ?? [], ...restoredReads?.outputReads ?? []]
36231
+ }), args.inheritedProducerRegions);
36232
+ const execCtx = {
36233
+ providerRegistry: ctx.providerRegistry,
36234
+ region,
36235
+ logger,
36236
+ ...ctx.options?.eventRecorder && { recordEvent: (event) => ctx.options.eventRecorder.record(maskEventTextWithBoundBags(event)) },
36237
+ finalSnapshotClients: ctx.options?.finalSnapshotClients,
36238
+ skipFinalSnapshot: ctx.options?.skipFinalSnapshot === true || ctx.destroyOptions?.skipFinalSnapshot === true,
36239
+ ...ctx.destroyOptions?.removeProtection === true && {
36240
+ removeProtection: true,
36241
+ foreignHolder: makeForeignHolderScan(ctx.stateBackend)({
36242
+ stackName: childStackName,
36243
+ region
36244
+ })
36245
+ },
36246
+ importedProducerRegions: producerRegions.regions,
36247
+ producerRegionsIncomplete: !producerRegions.complete,
36248
+ nestedChildRevert: true
36249
+ };
36250
+ const childCtx = {
36251
+ ...ctx,
36252
+ parentStackName: childStackName,
36253
+ parentRegion: region,
36254
+ nestedTemplates: void 0
36255
+ };
36256
+ let failures = 0;
36257
+ let warnings = 0;
36258
+ const inlinePolicyWriters = new RollbackInlinePolicyWriters();
36259
+ const settledBelow = /* @__PURE__ */ new Map();
36260
+ for (let s = segments.length - 1; s >= 0; s--) {
36261
+ const segment = segments[s];
36262
+ const skipPrefix = segment.skipPrefix ?? getCurrentSkipPrefix();
36263
+ const split = splitImportedOps(segment.operations, segment);
36264
+ const result = await withNestedStackContext(childCtx, () => withSkipPrefix(skipPrefix, () => withStackName(childStackName, () => withCreateTokenLedger(ledgerForStack(ctx.stateBackend, childStackName, region), () => withNestedRevertRun(runId, async (inner) => {
36265
+ const replayed = await withPrintingSecrets(journaledOrphanPrintingBag(completedReplayEntries(split.replay), stateResources), () => replayRollback(split.replay, stateResources, childStackName, execCtx, {
36266
+ afterOp: save,
36267
+ onOrphan: (record) => mintedOrphans.push(record),
36268
+ inlinePolicyWriters,
36269
+ failedOperations: segment.failedOperations
36270
+ }));
36271
+ for (const [id, below] of inner.settled) settledBelow.set(id, below);
36272
+ return {
36273
+ ...replayed,
36274
+ warnings: replayed.warnings + inner.warnings
36275
+ };
36276
+ })))));
36277
+ failures += result.failures;
36278
+ warnings += result.warnings + split.displaced.length;
36279
+ recordDisplacedSkips(execCtx.recordEvent, childStackName, split.displaced);
36280
+ for (const op of split.displaced) logger.warn(safeMsg`Nested stack ${childStackName}: ${op.logicalId} ` + safeMsg`${displacedOpClause(op, segment.importedResources ?? [], logger)}; ` + "not reverted, check that resource by hand");
36281
+ }
36282
+ restoring = failures === 0;
36283
+ await save();
36284
+ if (restoring && persisted && restoredOutputs && ctx.exportIndexStore) await ctx.exportIndexStore.updateForStack(childStackName, region, importableOutputs(nextState()));
36285
+ if (warnings > 0) logger.warn(safeMsg`Nested stack ${shownChild}: ${warnings} operation(s) were skipped with a warning during ` + `its revert (see above); they may need attention by hand.`);
36286
+ if (failures > 0) refuse(`${failures} of its operation(s) failed to revert (see the warnings above).`);
36287
+ if (warnings > 0) run.warnings += warnings;
36288
+ else run.settled.set(logicalId, settledBelow);
36289
+ return { warnings };
36290
+ } finally {
36291
+ await ctx.lockManager.releaseLock(childStackName, region).catch((error) => {
36292
+ logger.warn(safeMsg`Failed to release the lock of nested stack ${shownChild}: ${errorText(error)}`);
36293
+ });
36294
+ }
36295
+ }
36296
+
36053
36297
  //#endregion
36054
36298
  //#region src/deployment/rollback-executor/journaled-orphans.ts
36055
36299
  const NONE = {
@@ -36082,6 +36326,7 @@ async function loadJournaledOrphans(stateBackend, stackName, region, rollbackOrp
36082
36326
  for (const segment of segments) if (options.deployRunId !== void 0 && segment.reason === "nested-pending-parent" && segment.runId === options.deployRunId) for (const op of segment.operations) deployLogicalIds.add(op.logicalId);
36083
36327
  const out = [];
36084
36328
  let count = 0;
36329
+ const pendingRequests = segments.flatMap((segment) => segment.failedOperations ?? []).filter((op) => op.pendingCloudControlRequest !== void 0).length;
36085
36330
  for (let s = segments.length - 1; s >= 0; s--) {
36086
36331
  const segment = segments[s];
36087
36332
  if (segment.reason === "nested-pending-parent") continue;
@@ -36099,7 +36344,8 @@ async function loadJournaledOrphans(stateBackend, stackName, region, rollbackOrp
36099
36344
  return {
36100
36345
  segments: out,
36101
36346
  count,
36102
- deployLogicalIds
36347
+ deployLogicalIds,
36348
+ ...pendingRequests > 0 && { pendingRequests }
36103
36349
  };
36104
36350
  }
36105
36351
  function journaledOrphanLines(orphans, logger) {
@@ -36215,10 +36461,24 @@ async function settleJournaledOrphansOnSuccess(args) {
36215
36461
  keepJournal: true
36216
36462
  };
36217
36463
  }
36218
- if (orphans.count === 0) return {
36219
- unaddressed: 0,
36220
- keepJournal: false
36464
+ const pendingKept = (orphans.pendingRequests ?? 0) > 0;
36465
+ const keepPendingOnly = async () => {
36466
+ try {
36467
+ await stateBackend.reduceRollbackJournalToFailedOperations(stackName, region, (op) => op.pendingCloudControlRequest !== void 0, newerIds, () => false);
36468
+ return true;
36469
+ } catch (err) {
36470
+ logger.warn(safeMsg`Failed to reduce the rollback journal of stack ${stack} to its unsettled Cloud ` + safeMsg`Control requests: ${errorDetail(err)}. The whole journal is kept.`);
36471
+ await markSuperseded(stateBackend, stackName, region, newerIds);
36472
+ return false;
36473
+ }
36221
36474
  };
36475
+ if (orphans.count === 0) {
36476
+ if (pendingKept) await keepPendingOnly();
36477
+ return {
36478
+ unaddressed: 0,
36479
+ keepJournal: pendingKept
36480
+ };
36481
+ }
36222
36482
  const all = orphans.segments.flatMap(({ segment, ops }) => ops.map((op) => ({
36223
36483
  segment,
36224
36484
  op
@@ -36270,15 +36530,18 @@ async function settleJournaledOrphansOnSuccess(args) {
36270
36530
  logger.warn(safeMsg`Failed to remove the settled entries from the rollback journal of stack ${stack}: ` + safeMsg`${errorDetail(err)}. A cdkd rollback or cdkd destroy could act on them again; run a ` + "successful cdkd deploy of the stack first, which settles them again.");
36271
36531
  }
36272
36532
  };
36273
- if (kept.length === 0) return {
36274
- unaddressed: skipped + leftInPlace,
36275
- keepJournal: false,
36276
- ...stripCleared && { stripCleared }
36277
- };
36533
+ if (kept.length === 0) {
36534
+ if (pendingKept && !await keepPendingOnly()) await stripCleared?.();
36535
+ return {
36536
+ unaddressed: skipped + leftInPlace,
36537
+ keepJournal: pendingKept,
36538
+ ...stripCleared && { stripCleared }
36539
+ };
36540
+ }
36278
36541
  const keptIds = new Set(kept.map(({ op }) => op.logicalId));
36279
36542
  const supersededIds = newerIds.filter((id) => !keptIds.has(id));
36280
36543
  const demoted = kept.filter(({ op }) => op.physicalIdRecoveredFromError === false);
36281
- const reduce = () => stateBackend.reduceRollbackJournalToFailedOperations(stackName, region, (op, segment) => isHandledOrphan(kept, segment, op), supersededIds, (op, segment) => isHandledOrphan(demoted, segment, op));
36544
+ const reduce = () => stateBackend.reduceRollbackJournalToFailedOperations(stackName, region, (op, segment) => isHandledOrphan(kept, segment, op) || op.pendingCloudControlRequest !== void 0, supersededIds, (op, segment) => isHandledOrphan(demoted, segment, op));
36282
36545
  let reduced = false;
36283
36546
  for (let attempt = 0; attempt < 2 && !reduced; attempt++) try {
36284
36547
  await reduce();
@@ -36479,342 +36742,496 @@ function sameJournaledOrphans(a, b) {
36479
36742
  }
36480
36743
 
36481
36744
  //#endregion
36482
- //#region src/provisioning/nested-stack-context.ts
36483
- const storage$1 = new AsyncLocalStorage();
36484
- function withNestedStackContext(ctx, fn) {
36485
- return storage$1.run(ctx, fn);
36745
+ //#region src/deployment/cc-pending-requests.ts
36746
+ function hasPendingCloudControlRequest(op) {
36747
+ return op.pendingCloudControlRequest !== void 0;
36486
36748
  }
36487
- function getCurrentNestedStackContext() {
36488
- return storage$1.getStore();
36749
+ function pendingRequestCount(journal) {
36750
+ return pendingRequests(journal ?? null).size;
36489
36751
  }
36490
- async function collectNestedChildUnaddressed(fn) {
36491
- const ctx = storage$1.getStore();
36492
- if (!ctx) return {
36493
- value: await fn(),
36494
- unaddressed: void 0
36495
- };
36496
- const slot = {};
36497
- return {
36498
- value: await storage$1.run({
36499
- ...ctx,
36500
- childUnaddressed: slot
36501
- }, fn),
36502
- unaddressed: slot.last
36752
+ async function resolvePendingCloudControlRequests(params) {
36753
+ const { journal, stackName, region } = params;
36754
+ if (pendingRequests(params.loaded).size === 0) return false;
36755
+ const settle = async () => {
36756
+ await params.beforeSettle?.();
36757
+ let current = params.loaded;
36758
+ if (params.underLock) try {
36759
+ current = await journal.loadRollbackJournal(stackName, region);
36760
+ } catch (error) {
36761
+ throw new CdkdError(safeMsg`cdkd ${params.command} of ${displayStackName(stackName)} refused: its rollback ` + "journal recorded an unsettled Cloud Control CREATE when this run started and cannot " + safeMsg`be read now (${displaySafe(describeAwsFailure(error).summary)}). Nothing was ` + "changed; re-run once it can be read.", "CC_PENDING_REQUEST_UNREADABLE");
36762
+ }
36763
+ const pending = pendingRequests(current);
36764
+ if (pending.size > 0) await settlePending(params, pending);
36765
+ return params.underLock !== void 0 || pending.size > 0;
36503
36766
  };
36767
+ return params.underLock ? params.underLock(settle) : settle();
36504
36768
  }
36505
-
36506
- //#endregion
36507
- //#region src/deployment/nested-child-journal.ts
36508
- const NESTED_PENDING_PARENT_REASON = "nested-pending-parent";
36509
- const NESTED_STACK_TYPE$2 = "AWS::CloudFormation::Stack";
36510
- const MAX_NESTED_WALK_DEPTH = 32;
36511
- function nestedChildStackName(parentStackName, logicalId) {
36512
- return `${parentStackName}~${logicalId}`;
36769
+ function pendingRequests(loaded) {
36770
+ const pending = /* @__PURE__ */ new Map();
36771
+ for (const segment of loaded?.segments ?? []) for (const op of segment.failedOperations ?? []) if (hasPendingCloudControlRequest(op)) pending.set(op.pendingCloudControlRequest.requestToken, op);
36772
+ return pending;
36513
36773
  }
36514
- function nestedPendingSnapshot(state, refusesExportName) {
36515
- const outputs = { ...isPlainRecord(state.outputs) ? state.outputs : {} };
36516
- let exportNames = Array.isArray(state.exportNames) ? [...state.exportNames] : void 0;
36517
- const refused = new Set(importableOutputKeys(state).filter((name) => refusesExportName(name)));
36518
- if (refused.size > 0) {
36519
- for (const name of refused) Reflect.deleteProperty(outputs, name);
36520
- if (exportNames !== void 0) exportNames = exportNames.filter((name) => !refused.has(name));
36521
- }
36522
- return {
36523
- previousOutputs: {
36524
- outputs,
36525
- ...exportNames !== void 0 && { exportNames }
36526
- },
36527
- previousCrossStackReads: {
36528
- ...Array.isArray(state.imports) && { imports: [...state.imports] },
36529
- ...Array.isArray(state.outputReads) && { outputReads: [...state.outputReads] }
36774
+ async function settlePending(params, pending) {
36775
+ const { journal, stackName, region, command, logger } = params;
36776
+ const reader = params.reader();
36777
+ const isUnique = params.identifierUnique ?? ccIdentifierIsUnique;
36778
+ const stackShown = displayStackName(stackName);
36779
+ const settlements = /* @__PURE__ */ new Map();
36780
+ const unresolved = [];
36781
+ for (const [token, op] of pending) {
36782
+ const named = `${logicalIdShown(op.logicalId)} (${resourceTypeShown(op.resourceType)})`;
36783
+ logger.info(safeMsg`A previous run of ${stackShown} stopped waiting for the Cloud Control CREATE of ${named}; ` + "checking how it ended...");
36784
+ const outcome = await reader.resumeAbandonedRequest(token, op.logicalId, op.resourceType);
36785
+ switch (outcome.status) {
36786
+ case "succeeded":
36787
+ case "failed":
36788
+ case "cancelled": {
36789
+ const made = outcome.status === "succeeded" ? outcome.identifier : outcome.remnant;
36790
+ if (made === void 0) {
36791
+ logger.info(safeMsg`The CREATE of ${named} ${outcome.status === "cancelled" ? "was cancelled" : "failed"} ` + "in AWS and made nothing.");
36792
+ settlements.set(token, { kind: "drop" });
36793
+ break;
36794
+ }
36795
+ const madeShown = displacedPhysicalIdShown({
36796
+ ...op,
36797
+ physicalId: made
36798
+ }, logger, made) ?? "a resource";
36799
+ const held = params.stateResources?.[op.logicalId];
36800
+ if (held !== void 0 && held.physicalId === made) {
36801
+ logger.info(safeMsg`The CREATE of ${named} made ${madeShown}, which state already records.`);
36802
+ settlements.set(token, { kind: "drop" });
36803
+ break;
36804
+ }
36805
+ const unique = await isUnique({
36806
+ resourceType: op.resourceType,
36807
+ identifier: made,
36808
+ attemptedProperties: op.attemptedProperties,
36809
+ logicalId: op.logicalId,
36810
+ stackName
36811
+ });
36812
+ const ended = outcome.status === "succeeded" ? "completed" : outcome.status === "cancelled" ? "was cancelled" : "failed";
36813
+ if (outcome.status === "succeeded" && unique && held === void 0 && params.resume?.(op, made)) {
36814
+ logger.info(safeMsg`The CREATE of ${named} completed in AWS after cdkd stopped waiting, and made ` + safeMsg`${madeShown}; this deploy's CREATE of it takes that resource over when it sends ` + "the same properties.");
36815
+ settlements.set(token, { kind: "resume" });
36816
+ break;
36817
+ }
36818
+ if (params.resume !== void 0 && !unique) logger.warn(safeMsg`The CREATE of ${named} ${ended} in AWS after cdkd stopped waiting, and made ` + safeMsg`${madeShown}. cdkd cannot prove its id is unique (it may be a name, which can ` + safeMsg`since belong to another resource), so this deploy does not take it over, and creating ${logicalIdShown(op.logicalId)} ` + "again will ask for the name it holds. Adopt it with cdkd import (--resource " + safeMsg`${logicalIdShown(op.logicalId)}=<its id>), or delete it, then re-run. It is kept in the ` + "rollback journal as a resource the failed deploy created.");
36819
+ else logger.warn(safeMsg`The CREATE of ${named} ${ended} in AWS after cdkd stopped waiting, and made ` + safeMsg`${madeShown}. It is now recorded in the rollback journal as a resource the failed ` + "deploy created: cdkd destroy, cdkd rollback --revert-failed and the next successful deploy delete it as its DeletionPolicy directs when cdkd can prove it is still the resource that create made, and otherwise name it in a warning for you to delete by hand.");
36820
+ settlements.set(token, {
36821
+ kind: "orphan",
36822
+ physicalId: made,
36823
+ unique
36824
+ });
36825
+ break;
36826
+ }
36827
+ case "not-found":
36828
+ logger.warn(safeMsg`Cloud Control no longer has the CREATE request of ${named}: requests expire after ` + "seven days, and a request is not visible from another account or region. cdkd cannot tell whether it created the resource and stops tracking the request. If it exists, adopt it with cdkd import or delete it by hand.");
36829
+ settlements.set(token, { kind: "drop" });
36830
+ break;
36831
+ case "unresolved": {
36832
+ settlements.set(token, { kind: "keep" });
36833
+ const reason = holdsSecretReference(op.attemptedProperties) ? "details withheld: its properties carry a secret" : displaySafe(describeAwsFailure(outcome.error).summary);
36834
+ unresolved.push(safeMsg` - ${named}${reason === "" ? "" : ` (${reason})`}\n` + ` Check it with: ${await reader.buildResumeCommand(token)}`);
36835
+ break;
36836
+ }
36530
36837
  }
36531
- };
36532
- }
36533
- function displacedPhysicalIdShown(op, logger, physicalId = journalOpPhysicalId(op)) {
36534
- if (physicalId === void 0) return void 0;
36535
- const masker = createOpMasker(logger, /* @__PURE__ */ new Map());
36536
- for (const properties of [
36537
- op.properties,
36538
- op.attemptedProperties,
36539
- op.previousState?.properties
36540
- ]) {
36541
- if (properties === void 0) continue;
36542
- masker.addNamed({
36543
- resourceType: op.resourceType,
36544
- properties,
36545
- logicalId: op.logicalId,
36546
- physicalIds: [physicalId]
36547
- });
36548
36838
  }
36549
- return displaySafe(String(masker.mask(physicalId)));
36839
+ if ([...settlements.values()].some((s) => s.kind === "orphan" || s.kind === "drop")) await journal.rewriteRollbackJournalFailedOperations(stackName, region, (op) => {
36840
+ if (!hasPendingCloudControlRequest(op)) return op;
36841
+ const settlement = settlements.get(op.pendingCloudControlRequest.requestToken);
36842
+ if (settlement?.kind === "drop") return withoutPendingRequest(op);
36843
+ if (settlement?.kind !== "orphan") return op;
36844
+ return {
36845
+ ...withoutPendingRequest(op),
36846
+ provisionedBy: "cc-api",
36847
+ physicalId: settlement.physicalId,
36848
+ physicalIdRecoveredFromError: true,
36849
+ ...settlement.unique && { createdIdentifierUnique: true }
36850
+ };
36851
+ });
36852
+ if (unresolved.length > 0) {
36853
+ const kept = [...pending.values()].filter((op) => settlements.get(op.pendingCloudControlRequest.requestToken)?.kind === "keep");
36854
+ const drop = dropFailedCommands(stackName, region, kept.map((op) => op.logicalId));
36855
+ const withheld = drop?.commands.some((c) => c.includes("<")) === true;
36856
+ throw new CdkdError(safeMsg`cdkd ${command} of ${stackShown} refused: a previous run stopped waiting for a Cloud ` + `Control CREATE, and cdkd still cannot tell whether it made its resource. Proceeding could leave that resource untracked. Nothing was changed.
36857
+ ${unresolved.join("\n")}\nRe-run once the request has finished and can be read. If you have reconciled it by hand (cdkd import, or deleted the resource), drop its journal entry with:` + (drop === void 0 ? "" : drop.commands.map((c) => `\n ${c}`).join("")) + (withheld ? "\nA value that is not a plain identifier is shown as a <hole>; read it from the stack's state record and rollback-journal.json." : ""), "CC_PENDING_REQUEST_UNRESOLVED");
36858
+ }
36859
+ }
36860
+ function holdsSecretReference(properties) {
36861
+ if (properties === void 0) return false;
36862
+ return carriesSecretMask(properties) || JSON.stringify(properties).includes("{{resolve:");
36863
+ }
36864
+ const ccIdentifierIsUnique = async ({ resourceType, identifier, attemptedProperties, logicalId, stackName }) => {
36865
+ if (attemptedProperties === void 0 || holdsSecretReference(attemptedProperties)) return false;
36866
+ const [fields, readOnly] = await Promise.all([getPrimaryIdentifierFields(resourceType), getTopLevelReadOnlyProperties(resourceType)]);
36867
+ if (fields === void 0 || readOnly === void 0) return false;
36868
+ const parts = identifier.split("|");
36869
+ if (parts.length !== fields.length) return false;
36870
+ const sent = /* @__PURE__ */ new Set();
36871
+ const collect = (value) => {
36872
+ if (typeof value === "string" || typeof value === "number") for (const piece of nameSegments(String(value))) sent.add(piece);
36873
+ else if (Array.isArray(value)) value.forEach(collect);
36874
+ else if (value !== null && typeof value === "object") Object.values(value).forEach(collect);
36875
+ };
36876
+ collect(attemptedProperties);
36877
+ return parts.some((part, i) => {
36878
+ if (part === "" || !readOnly.has(fields[i])) return false;
36879
+ return !nameSegments(part).some((segment) => sent.has(segment) || looksLikeCdkdGeneratedName(segment, logicalId, stackName));
36880
+ });
36881
+ };
36882
+ function nameSegments(value) {
36883
+ const text = value.toLowerCase();
36884
+ const arn = /^arn:[^:]*:[^:]*:[^:]*:[^:]*:(.*)$/.exec(text);
36885
+ const body = arn ? arn[1] : text;
36886
+ return [
36887
+ text,
36888
+ body,
36889
+ ...body.split(/[:/]/)
36890
+ ].filter((piece) => piece !== "");
36550
36891
  }
36551
- function displacedOpClause(op, marks, logger) {
36552
- const retainedOld = retainedOldPhysicalId(op);
36553
- if (retainedOld !== void 0 && marks.some((m) => isMarkFor(m, op))) {
36554
- const shownOld = displacedPhysicalIdShown(op, logger, retainedOld);
36555
- return `replaced ${shownOld} ${op.oldResourceRetained === true ? "but kept it (UpdateReplacePolicy: Retain)" : op.oldResourceMaySurvive !== void 0 ? "and may have kept it (its delete was not confirmed)" : "and may have kept it (the journal records no verdict)"}; cdkd import adopted the replacement, so ${shownOld} is left untracked`;
36556
- }
36557
- const shownId = displacedPhysicalIdShown(op, logger);
36558
- return shownId !== void 0 ? `recorded ${shownId}, which cdkd import has since replaced under this id` : "recorded no physical id, and cdkd import has since put another resource under this id";
36892
+ function withoutPendingRequest(op) {
36893
+ const { pendingCloudControlRequest: _settled, ...rest } = op;
36894
+ return rest;
36559
36895
  }
36560
- function recordDisplacedSkips(recordEvent, stackName, ops) {
36561
- for (const op of ops) recordEvent?.({
36562
- eventType: "ROLLBACK_RESOURCE_SKIPPED",
36563
- stackName,
36564
- operation: op.changeType,
36565
- logicalId: op.logicalId,
36566
- resourceType: op.resourceType,
36567
- ...op.provisionedBy && { provisionedBy: op.provisionedBy },
36568
- reason: "cdkd import has since put another resource under this logical id, so the op was not reverted; check the resource it recorded by hand"
36569
- });
36896
+
36897
+ //#endregion
36898
+ //#region src/state/deployment-events-store.ts
36899
+ const DEPLOYMENT_EVENTS_MAX_INDEX_RUNS = 20;
36900
+ const FLUSH_INTERVAL_MS = 2e3;
36901
+ const FLUSH_EVENT_THRESHOLD = 50;
36902
+ function newDeploymentRunId(now = /* @__PURE__ */ new Date()) {
36903
+ return `${now.toISOString().replace(/[-:.]/g, "")}-${randomUUID().slice(0, 8)}`;
36570
36904
  }
36571
- function revertedNestedRowIds(ops) {
36572
- return ops.filter((op) => op.resourceType === NESTED_STACK_TYPE$2 && op.changeType === "UPDATE").map((op) => op.logicalId);
36905
+ function deploymentEventsKey(prefix, stackName, region, runId) {
36906
+ return `${prefix}/${stackName}/${region}/deployments/${runId}.jsonl`;
36573
36907
  }
36574
- const revertRunStorage = new AsyncLocalStorage();
36575
- function withNestedRevertRun(runId, fn) {
36576
- const run = {
36577
- runId,
36578
- settled: /* @__PURE__ */ new Map(),
36579
- warnings: 0
36580
- };
36581
- return revertRunStorage.run(run, () => fn(run));
36908
+ function deploymentEventsIndexKey(prefix, stackName, region) {
36909
+ return `${prefix}/${stackName}/${region}/deployments/index.json`;
36582
36910
  }
36583
- function getNestedRevertRun() {
36584
- return revertRunStorage.getStore();
36911
+ function deploymentsDirPrefix(prefix, stackName, region) {
36912
+ return `${prefix}/${stackName}/${region}/deployments/`;
36585
36913
  }
36586
- function errorText(error) {
36587
- return displaySafe(describeAwsFailure(error).detail);
36914
+ const DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION = "deployment-event streams and their index, whose recorded error messages can quote values the secret mask does not catch";
36915
+ async function deleteAndPurgeEventObjects(backend, keys, dirPrefix, scope = "deleted-keys") {
36916
+ if (keys.length === 0) return void 0;
36917
+ let swept;
36918
+ try {
36919
+ await backend.deleteRawObjects(keys);
36920
+ } finally {
36921
+ if (scope === "whole-dir") swept = await backend.purgeNoncurrentVersionsUnderPrefix(dirPrefix, { objectDescription: DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION });
36922
+ else await backend.purgeNoncurrentVersions(keys, {
36923
+ ...keys.length > 1 && { listPrefix: dirPrefix },
36924
+ objectDescription: DEPLOYMENT_EVENTS_OBJECT_DESCRIPTION
36925
+ });
36926
+ }
36927
+ return swept;
36588
36928
  }
36589
- function isPlainRecord(value) {
36590
- return typeof value === "object" && value !== null && !Array.isArray(value);
36929
+ function runIdTimestampMs(runId) {
36930
+ const m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})Z/.exec(runId);
36931
+ if (!m) return null;
36932
+ const iso = `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}.${m[7]}Z`;
36933
+ const ms = Date.parse(iso);
36934
+ return Number.isNaN(ms) ? null : ms;
36591
36935
  }
36592
- async function dropNestedChildJournals(args) {
36593
- const { stateBackend, parentStackName, region, resources, logger } = args;
36594
- const depth = args.depth ?? 0;
36595
- if (!isPlainRecord(resources)) return;
36596
- if (depthExceeded(depth, parentStackName, logger)) return;
36597
- for (const [logicalId, record] of Object.entries(resources)) {
36598
- if (!isPlainRecord(record) || record["resourceType"] !== NESTED_STACK_TYPE$2) continue;
36599
- const child = nestedChildStackName(parentStackName, logicalId);
36936
+ function runIdFromJsonlKey(key, dirPrefix) {
36937
+ if (!key.startsWith(dirPrefix) || !key.endsWith(".jsonl")) return null;
36938
+ return key.slice(dirPrefix.length, -6);
36939
+ }
36940
+ var DeploymentEventsStore = class {
36941
+ logger = getLogger().child("DeploymentEvents");
36942
+ backend;
36943
+ stackName;
36944
+ region;
36945
+ command;
36946
+ runId;
36947
+ cdkdVersion;
36948
+ startedAt;
36949
+ events = [];
36950
+ persistedCount = 0;
36951
+ flushTimer;
36952
+ writeChain = Promise.resolve();
36953
+ warnedOnce = false;
36954
+ finalized = false;
36955
+ constructor(backend, options) {
36956
+ this.backend = backend;
36957
+ this.stackName = options.stackName;
36958
+ this.region = options.region;
36959
+ this.command = options.command;
36960
+ this.runId = options.runId ?? newDeploymentRunId();
36961
+ this.cdkdVersion = options.cdkdVersion ?? getCdkdVersion();
36962
+ this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
36963
+ }
36964
+ record(event) {
36600
36965
  try {
36601
- const data = await stateBackend.getState(child, region);
36602
- if (data && isPlainRecord(data.state) && isPlainRecord(data.state.resources) && (data.state.stackName === void 0 || data.state.stackName === child)) await dropNestedChildJournals({
36603
- ...args,
36604
- parentStackName: child,
36605
- resources: data.state.resources,
36606
- depth: depth + 1
36966
+ if (this.finalized) return;
36967
+ this.events.push({
36968
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
36969
+ ...event
36607
36970
  });
36608
- } catch (error) {
36609
- warnUncleared(logger, child, error);
36971
+ if (this.events.length - this.persistedCount >= FLUSH_EVENT_THRESHOLD) this.scheduleFlush(0);
36972
+ else this.scheduleFlush(FLUSH_INTERVAL_MS);
36973
+ } catch {}
36974
+ }
36975
+ async finalize(result) {
36976
+ if (this.finalized) return;
36977
+ this.finalized = true;
36978
+ if (this.flushTimer) {
36979
+ clearTimeout(this.flushTimer);
36980
+ this.flushTimer = void 0;
36610
36981
  }
36611
- try {
36612
- if (await withChildLock(args.lockManager, child, region, logger, async () => {
36613
- if (args.beforeDelete) {
36614
- if (!await args.beforeDelete(child, await readOwnRecord(stateBackend, child, region))) return false;
36615
- }
36616
- let gone;
36617
- try {
36618
- gone = await stateBackend.deleteRollbackJournal(child, region);
36619
- } catch (error) {
36620
- await args.onDeleteFailed?.(child);
36621
- throw error;
36622
- }
36623
- if (gone === false) {
36624
- await args.onDeleteFailed?.(child);
36625
- return false;
36626
- }
36627
- return true;
36628
- })) logger.debug(safeMsg`Deleted the rollback journal of nested stack ${displaySafe(child)}`);
36629
- } catch (error) {
36630
- warnUncleared(logger, child, error);
36982
+ if (this.events.length === 0) return;
36983
+ await this.enqueueWrite(async () => {
36984
+ const indexRead = this.readIndexRuns();
36985
+ indexRead.catch(() => {});
36986
+ await this.doFlush();
36987
+ await this.writeIndexAndPrune(result, await indexRead);
36988
+ });
36989
+ }
36990
+ async writeIndexAndPrune(result, existingRuns) {
36991
+ const { key, file, runs } = this.buildIndexUpdate(result, existingRuns);
36992
+ const keptRunIds = runs.map((r) => r.runId);
36993
+ const willPrune = keptRunIds.length >= 20;
36994
+ const dirPrefix = deploymentsDirPrefix(this.backend.prefix, this.stackName, this.region);
36995
+ const staleKeysRead = willPrune ? this.backend.listRawKeys(dirPrefix) : void 0;
36996
+ staleKeysRead?.catch(() => {});
36997
+ await this.backend.putRawObject(key, JSON.stringify(file, null, 2));
36998
+ if (!staleKeysRead) return;
36999
+ await this.pruneSupersededRunFiles(keptRunIds, dirPrefix, await staleKeysRead);
37000
+ }
37001
+ async drain() {
37002
+ await this.writeChain;
37003
+ }
37004
+ scheduleFlush(delayMs) {
37005
+ if (this.flushTimer) {
37006
+ if (delayMs > 0) return;
37007
+ clearTimeout(this.flushTimer);
36631
37008
  }
37009
+ this.flushTimer = setTimeout(() => {
37010
+ this.flushTimer = void 0;
37011
+ this.enqueueWrite(() => this.doFlush());
37012
+ }, delayMs);
37013
+ this.flushTimer.unref?.();
36632
37014
  }
36633
- }
36634
- async function readOwnRecord(stateBackend, child, region) {
36635
- try {
36636
- const data = await stateBackend.getState(child, region);
36637
- if (data && isPlainRecord(data.state) && isPlainRecord(data.state.resources) && (data.state.stackName === void 0 || data.state.stackName === child)) return data.state;
36638
- } catch {}
36639
- }
36640
- async function dropSettledNestedJournals(args) {
36641
- const { stateBackend, parentStackName, region, runId, logger } = args;
36642
- const depth = args.depth ?? 0;
36643
- if (runId === void 0) return;
36644
- if (depthExceeded(depth, parentStackName, logger)) return;
36645
- const isSettled = (segment) => segment.runId === runId && segment.reason === "nested-pending-parent";
36646
- for (const [logicalId, grandchildren] of args.settled) {
36647
- const child = nestedChildStackName(parentStackName, logicalId);
36648
- if (grandchildren.size > 0) await dropSettledNestedJournals({
36649
- ...args,
36650
- parentStackName: child,
36651
- settled: grandchildren,
36652
- depth: depth + 1
37015
+ enqueueWrite(op) {
37016
+ const next = this.writeChain.then(op).catch((err) => {
37017
+ this.warnOnce(`Failed to persist deployment events for run ${this.runId}: ${describeAwsFailure(err).detail}`);
36653
37018
  });
37019
+ this.writeChain = next;
37020
+ return next;
37021
+ }
37022
+ async doFlush() {
37023
+ if (this.events.length === 0 || this.events.length === this.persistedCount) return;
37024
+ const snapshotCount = this.events.length;
37025
+ const body = this.events.slice(0, snapshotCount).map((e) => JSON.stringify(e)).join("\n");
37026
+ await this.backend.putRawObject(deploymentEventsKey(this.backend.prefix, this.stackName, this.region, this.runId), body + "\n", "application/x-ndjson");
37027
+ this.persistedCount = snapshotCount;
37028
+ }
37029
+ async readIndexRuns() {
37030
+ const key = deploymentEventsIndexKey(this.backend.prefix, this.stackName, this.region);
36654
37031
  try {
36655
- const removed = await withChildLock(args.lockManager, child, region, logger, () => stateBackend.dropRollbackJournalSegments(child, region, isSettled));
36656
- if (removed > 0) logger.debug(safeMsg`Dropped ${removed} settled rollback journal segment(s) of ${displaySafe(child)}`);
36657
- } catch (error) {
36658
- warnUncleared(logger, child, error);
37032
+ const raw = await this.backend.getRawObject(key);
37033
+ if (raw !== null) {
37034
+ const parsed = JSON.parse(raw);
37035
+ if (Array.isArray(parsed.runs)) return parsed.runs;
37036
+ }
37037
+ } catch (err) {
37038
+ this.logger.debug(`Deployment-events index unreadable, rewriting: ${describeAwsFailure(err).detail}`);
36659
37039
  }
37040
+ return [];
36660
37041
  }
36661
- }
36662
- async function withChildLock(lockManager, child, region, logger, fn) {
36663
- await lockManager.acquireLockWithRetry(child, region, void 0, "rollback");
36664
- try {
36665
- return await fn();
36666
- } finally {
36667
- await lockManager.releaseLock(child, region).catch((error) => {
36668
- logger.warn(safeMsg`Failed to release the lock of nested stack ${displayIdent(child)}: ${errorText(error)}`);
37042
+ buildIndexUpdate(result, existingRuns) {
37043
+ const key = deploymentEventsIndexKey(this.backend.prefix, this.stackName, this.region);
37044
+ const runs = [{
37045
+ runId: this.runId,
37046
+ command: this.command,
37047
+ cdkdVersion: this.cdkdVersion,
37048
+ startedAt: this.startedAt,
37049
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
37050
+ result,
37051
+ eventCount: this.persistedCount
37052
+ }, ...existingRuns.filter((r) => r.runId !== this.runId)].slice(0, 20);
37053
+ return {
37054
+ key,
37055
+ file: {
37056
+ indexVersion: 1,
37057
+ stackName: this.stackName,
37058
+ region: this.region,
37059
+ runs,
37060
+ lastModified: Date.now()
37061
+ },
37062
+ runs
37063
+ };
37064
+ }
37065
+ async pruneSupersededRunFiles(keptRunIds, dirPrefix, keys) {
37066
+ if (keptRunIds.length < 20) return;
37067
+ const cutoff = keptRunIds.reduce((min, id) => id < min ? id : min, keptRunIds[0]);
37068
+ const stale = keys.filter((k) => {
37069
+ const runId = runIdFromJsonlKey(k, dirPrefix);
37070
+ return runId !== null && runId < cutoff;
36669
37071
  });
37072
+ if (stale.length === 0) return;
37073
+ await deleteAndPurgeEventObjects(this.backend, stale, dirPrefix);
37074
+ this.logger.debug(`Pruned ${stale.length} superseded deployment-event stream(s) for ${this.stackName} (${this.region})`);
36670
37075
  }
36671
- }
36672
- function depthExceeded(depth, parentStackName, logger) {
36673
- if (depth < MAX_NESTED_WALK_DEPTH) return false;
36674
- logger.warn(safeMsg`Stopped clearing nested rollback journals below ${displayIdent(parentStackName)}: ` + safeMsg`the nesting is deeper than ${MAX_NESTED_WALK_DEPTH} levels.`);
36675
- return true;
36676
- }
36677
- function warnUncleared(logger, child, error) {
36678
- logger.warn(safeMsg`Could not clear the rollback journal of nested stack ${displayIdent(child)}: ${errorText(error)}. ` + "It is inert to every parent revert (they select segments by run) and the next successful deploy of the top-level stack removes it.");
36679
- }
36680
- async function revertNestedChildFromJournal(args) {
36681
- const { ctx, logicalId, childStackName, region, run, logger } = args;
36682
- const runId = run.runId;
36683
- const shownChild = displayIdent(childStackName);
36684
- const refuse = (detail) => {
36685
- throw markNonRetryable(/* @__PURE__ */ new Error(`Cannot revert nested stack ${shownChild} (row ${displayIdent(logicalId)}): ${detail} The child was NOT (fully) reverted and may still hold the failed deploy's configuration. Inspect it with 'cdkd state show'; re-run the rollback once the cause is fixed (its journal is kept), or re-deploy the parent to converge.`));
36686
- };
36687
- if (runId === void 0) refuse("the rollback carries no deploy run id to select its journal segments by.");
36688
- await ctx.lockManager.acquireLockWithRetry(childStackName, region, void 0, "rollback");
36689
- try {
36690
- const stateData = await ctx.stateBackend.getState(childStackName, region);
36691
- if (!stateData) refuse("its state.json is missing.");
36692
- if (stateData.divergentBodyRegion !== void 0) refuse("its state record's region field disagrees with the key it is stored under.");
36693
- const base = stateData.state;
36694
- const refusalRecovery = {
36695
- profile: ctx.destroyOptions?.profile,
36696
- stateBucket: ctx.stateBucket,
36697
- statePrefix: ctx.destroyOptions?.statePrefix
37076
+ warnOnce(message) {
37077
+ if (this.warnedOnce) {
37078
+ this.logger.debug(message);
37079
+ return;
37080
+ }
37081
+ this.warnedOnce = true;
37082
+ this.logger.warn(`${message} — continuing; deployment events are best-effort and never block the run.`);
37083
+ }
37084
+ };
37085
+ var DeploymentEventsReader = class {
37086
+ backend;
37087
+ constructor(backend) {
37088
+ this.backend = backend;
37089
+ }
37090
+ async listRegions(stackName) {
37091
+ const prefix = `${this.backend.prefix}/${stackName}/`;
37092
+ const keys = await this.backend.listRawKeys(prefix);
37093
+ const regions = /* @__PURE__ */ new Set();
37094
+ for (const key of keys) {
37095
+ const segments = key.slice(prefix.length).split("/");
37096
+ if (segments.length === 3 && segments[1] === "deployments" && segments[0]) regions.add(segments[0]);
37097
+ }
37098
+ return [...regions].sort();
37099
+ }
37100
+ async listRuns(stackName, region) {
37101
+ const key = deploymentEventsIndexKey(this.backend.prefix, stackName, region);
37102
+ try {
37103
+ const raw = await this.backend.getRawObject(key);
37104
+ if (raw !== null) {
37105
+ const parsed = JSON.parse(raw);
37106
+ if (Array.isArray(parsed.runs)) return parsed.runs;
37107
+ }
37108
+ } catch {}
37109
+ const dirPrefix = `${this.backend.prefix}/${stackName}/${region}/deployments/`;
37110
+ const runIds = (await this.backend.listRawKeys(dirPrefix)).filter((k) => k.endsWith(".jsonl")).map((k) => k.slice(dirPrefix.length, -6)).sort().reverse();
37111
+ return Promise.all(runIds.map((runId) => this.summarizeRunFromJsonl(stackName, region, runId)));
37112
+ }
37113
+ async summarizeRunFromJsonl(stackName, region, runId) {
37114
+ const fallback = {
37115
+ runId,
37116
+ command: "deploy",
37117
+ cdkdVersion: "unknown",
37118
+ startedAt: "",
37119
+ finishedAt: "",
37120
+ result: "UNKNOWN",
37121
+ eventCount: 0
36698
37122
  };
36699
- refuseMalformedState(base, childStackName, region, refusalRecovery);
36700
- refuseMalformedOrphans(base, childStackName, region, refusalRecovery);
36701
- refuseMalformedOrphanRecords(base, childStackName, region, refusalRecovery);
36702
- const segments = ((await ctx.stateBackend.loadRollbackJournal(childStackName, region))?.segments ?? []).filter((segment) => segment.runId === runId);
36703
- if (segments.length === 0) refuse("its rollback journal holds no segment for this deploy run, so there is no record of what it held before.");
36704
- const stateResources = { ...base.resources };
36705
- const mintedOrphans = [];
36706
- const restoredOutputs = segments.find((s) => s.previousOutputs)?.previousOutputs;
36707
- const restoredReads = segments.find((s) => s.previousCrossStackReads)?.previousCrossStackReads;
36708
- let currentEtag = stateData.etag;
36709
- let persisted = false;
36710
- let restoring = false;
36711
- const { skippedOutputs: _dropped, ...carried } = base;
36712
- const next = () => ({
36713
- ...carried,
36714
- version: 12,
36715
- region,
36716
- resources: { ...stateResources },
36717
- ...orphansAfterRollback(base, mintedOrphans),
36718
- ...restoring && restoredOutputs && { outputs: { ...restoredOutputs.outputs } },
36719
- ...restoring && restoredReads && {
36720
- ...restoredReads.imports && { imports: [...restoredReads.imports] },
36721
- ...restoredReads.outputReads && { outputReads: [...restoredReads.outputReads] }
36722
- },
36723
- ...restoring && restoredOutputs?.exportNames && { exportNames: [...restoredOutputs.exportNames] },
36724
- lastModified: Date.now()
36725
- });
36726
- const nextState = () => {
36727
- const state = next();
36728
- if (!restoring) return state;
36729
- if (restoredOutputs && !restoredOutputs.exportNames) delete state.exportNames;
36730
- if (restoredOutputs) delete state.outputReferenceProvenance;
36731
- if (restoredReads && !restoredReads.imports) delete state.imports;
36732
- if (restoredReads && !restoredReads.outputReads) delete state.outputReads;
36733
- return state;
37123
+ let events = null;
37124
+ try {
37125
+ events = await this.readRunEvents(stackName, region, runId);
37126
+ } catch {
37127
+ return fallback;
37128
+ }
37129
+ if (events === null || events.length === 0) return fallback;
37130
+ const started = events.find((e) => e.eventType === "RUN_STARTED");
37131
+ let finished;
37132
+ for (const e of events) if (e.eventType === "RUN_FINISHED") finished = e;
37133
+ return {
37134
+ runId,
37135
+ command: started?.command ?? fallback.command,
37136
+ cdkdVersion: started?.cdkdVersion ?? fallback.cdkdVersion,
37137
+ startedAt: started?.timestamp ?? fallback.startedAt,
37138
+ finishedAt: finished?.timestamp ?? fallback.finishedAt,
37139
+ result: finished?.result ?? "UNKNOWN",
37140
+ eventCount: events.length
36734
37141
  };
36735
- const save = async () => {
36736
- persisted = false;
37142
+ }
37143
+ async readRunEvents(stackName, region, runId) {
37144
+ const key = deploymentEventsKey(this.backend.prefix, stackName, region, runId);
37145
+ const raw = await this.backend.getRawObject(key);
37146
+ if (raw === null) return null;
37147
+ const events = [];
37148
+ for (const line of raw.split("\n")) {
37149
+ const trimmed = line.trim();
37150
+ if (!trimmed) continue;
36737
37151
  try {
36738
- currentEtag = await ctx.stateBackend.saveState(childStackName, region, nextState(), { ...currentEtag !== void 0 && { expectedEtag: currentEtag } });
36739
- persisted = true;
36740
- } catch {
36741
- try {
36742
- const fresh = await ctx.stateBackend.getState(childStackName, region);
36743
- currentEtag = await ctx.stateBackend.saveState(childStackName, region, nextState(), { ...fresh?.etag !== void 0 && { expectedEtag: fresh.etag } });
36744
- persisted = true;
36745
- } catch (retryError) {
36746
- logger.warn(safeMsg`Failed to persist the state of nested stack ${shownChild} after reverting it: ` + safeMsg`${errorText(retryError)}. The resources were reverted in AWS.`);
36747
- }
36748
- }
36749
- };
36750
- const producerRegions = inheritProducerRegions(producerRegionsFromState({
36751
- imports: [...base.imports ?? [], ...restoredReads?.imports ?? []],
36752
- outputReads: [...base.outputReads ?? [], ...restoredReads?.outputReads ?? []]
36753
- }), args.inheritedProducerRegions);
36754
- const execCtx = {
36755
- providerRegistry: ctx.providerRegistry,
36756
- region,
36757
- logger,
36758
- ...ctx.options?.eventRecorder && { recordEvent: (event) => ctx.options.eventRecorder.record(maskEventTextWithBoundBags(event)) },
36759
- finalSnapshotClients: ctx.options?.finalSnapshotClients,
36760
- skipFinalSnapshot: ctx.options?.skipFinalSnapshot === true || ctx.destroyOptions?.skipFinalSnapshot === true,
36761
- ...ctx.destroyOptions?.removeProtection === true && {
36762
- removeProtection: true,
36763
- foreignHolder: makeForeignHolderScan(ctx.stateBackend)({
36764
- stackName: childStackName,
36765
- region
36766
- })
36767
- },
36768
- importedProducerRegions: producerRegions.regions,
36769
- producerRegionsIncomplete: !producerRegions.complete,
36770
- nestedChildRevert: true
37152
+ events.push(JSON.parse(trimmed));
37153
+ } catch {}
37154
+ }
37155
+ return events;
37156
+ }
37157
+ async pruneRuns(stackName, region, opts = {}) {
37158
+ const dirPrefix = deploymentsDirPrefix(this.backend.prefix, stackName, region);
37159
+ const keys = await this.backend.listRawKeys(dirPrefix);
37160
+ const runIdsDesc = keys.map((k) => runIdFromJsonlKey(k, dirPrefix)).filter((id) => id !== null).sort().reverse();
37161
+ const indexKey = deploymentEventsIndexKey(this.backend.prefix, stackName, region);
37162
+ const indexExisted = keys.includes(indexKey);
37163
+ if (opts.all === true) {
37164
+ const toDelete = runIdsDesc.map((id) => deploymentEventsKey(this.backend.prefix, stackName, region, id));
37165
+ const earlierVersions = await deleteAndPurgeEventObjects(this.backend, [...toDelete, indexKey], dirPrefix, "whole-dir");
37166
+ return {
37167
+ deletedRunIds: runIdsDesc,
37168
+ remainingRunIds: [],
37169
+ indexDeleted: indexExisted,
37170
+ ...earlierVersions !== void 0 && { earlierVersions }
37171
+ };
37172
+ }
37173
+ const noGuards = opts.keep === void 0 && opts.olderThanMs === void 0;
37174
+ const keep = opts.keep ?? (noGuards ? 20 : void 0);
37175
+ const protectedByCount = keep === void 0 ? /* @__PURE__ */ new Set() : new Set(runIdsDesc.slice(0, keep));
37176
+ let candidates = runIdsDesc.filter((id) => !protectedByCount.has(id));
37177
+ if (opts.olderThanMs !== void 0) {
37178
+ const cutoff = (opts.now ?? /* @__PURE__ */ new Date()).getTime() - opts.olderThanMs;
37179
+ candidates = candidates.filter((id) => {
37180
+ const t = runIdTimestampMs(id);
37181
+ return t !== null && t < cutoff;
37182
+ });
37183
+ }
37184
+ if (candidates.length === 0) return {
37185
+ deletedRunIds: [],
37186
+ remainingRunIds: runIdsDesc,
37187
+ indexDeleted: false
36771
37188
  };
36772
- const childCtx = {
36773
- ...ctx,
36774
- parentStackName: childStackName,
36775
- parentRegion: region,
36776
- nestedTemplates: void 0
37189
+ const deletedSet = new Set(candidates);
37190
+ const deleteKeys = candidates.map((id) => deploymentEventsKey(this.backend.prefix, stackName, region, id));
37191
+ const remainingRunIds = runIdsDesc.filter((id) => !deletedSet.has(id));
37192
+ if (remainingRunIds.length === 0) {
37193
+ await deleteAndPurgeEventObjects(this.backend, [...deleteKeys, indexKey], dirPrefix);
37194
+ return {
37195
+ deletedRunIds: candidates,
37196
+ remainingRunIds,
37197
+ indexDeleted: indexExisted
37198
+ };
37199
+ }
37200
+ await this.rewriteIndexAfterPrune(indexKey, stackName, region, deletedSet);
37201
+ await deleteAndPurgeEventObjects(this.backend, deleteKeys, dirPrefix);
37202
+ return {
37203
+ deletedRunIds: candidates,
37204
+ remainingRunIds,
37205
+ indexDeleted: false
36777
37206
  };
36778
- let failures = 0;
36779
- let warnings = 0;
36780
- const inlinePolicyWriters = new RollbackInlinePolicyWriters();
36781
- const settledBelow = /* @__PURE__ */ new Map();
36782
- for (let s = segments.length - 1; s >= 0; s--) {
36783
- const segment = segments[s];
36784
- const skipPrefix = segment.skipPrefix ?? getCurrentSkipPrefix();
36785
- const split = splitImportedOps(segment.operations, segment);
36786
- const result = await withNestedStackContext(childCtx, () => withSkipPrefix(skipPrefix, () => withStackName(childStackName, () => withCreateTokenLedger(ledgerForStack(ctx.stateBackend, childStackName, region), () => withNestedRevertRun(runId, async (inner) => {
36787
- const replayed = await withPrintingSecrets(journaledOrphanPrintingBag(completedReplayEntries(split.replay), stateResources), () => replayRollback(split.replay, stateResources, childStackName, execCtx, {
36788
- afterOp: save,
36789
- onOrphan: (record) => mintedOrphans.push(record),
36790
- inlinePolicyWriters,
36791
- failedOperations: segment.failedOperations
36792
- }));
36793
- for (const [id, below] of inner.settled) settledBelow.set(id, below);
36794
- return {
36795
- ...replayed,
36796
- warnings: replayed.warnings + inner.warnings
36797
- };
36798
- })))));
36799
- failures += result.failures;
36800
- warnings += result.warnings + split.displaced.length;
36801
- recordDisplacedSkips(execCtx.recordEvent, childStackName, split.displaced);
36802
- for (const op of split.displaced) logger.warn(safeMsg`Nested stack ${childStackName}: ${op.logicalId} ` + safeMsg`${displacedOpClause(op, segment.importedResources ?? [], logger)}; ` + "not reverted, check that resource by hand");
37207
+ }
37208
+ async rewriteIndexAfterPrune(indexKey, stackName, region, deletedRunIds) {
37209
+ let raw;
37210
+ try {
37211
+ raw = await this.backend.getRawObject(indexKey);
37212
+ } catch {
37213
+ return;
36803
37214
  }
36804
- restoring = failures === 0;
36805
- await save();
36806
- if (restoring && persisted && restoredOutputs && ctx.exportIndexStore) await ctx.exportIndexStore.updateForStack(childStackName, region, importableOutputs(nextState()));
36807
- if (warnings > 0) logger.warn(safeMsg`Nested stack ${shownChild}: ${warnings} operation(s) were skipped with a warning during ` + `its revert (see above); they may need attention by hand.`);
36808
- if (failures > 0) refuse(`${failures} of its operation(s) failed to revert (see the warnings above).`);
36809
- if (warnings > 0) run.warnings += warnings;
36810
- else run.settled.set(logicalId, settledBelow);
36811
- return { warnings };
36812
- } finally {
36813
- await ctx.lockManager.releaseLock(childStackName, region).catch((error) => {
36814
- logger.warn(safeMsg`Failed to release the lock of nested stack ${shownChild}: ${errorText(error)}`);
36815
- });
37215
+ if (raw === null) return;
37216
+ let parsed;
37217
+ try {
37218
+ parsed = JSON.parse(raw);
37219
+ } catch {
37220
+ return;
37221
+ }
37222
+ if (!Array.isArray(parsed.runs)) return;
37223
+ const remaining = parsed.runs.filter((r) => !deletedRunIds.has(r.runId));
37224
+ if (remaining.length === parsed.runs.length) return;
37225
+ const file = {
37226
+ indexVersion: 1,
37227
+ stackName,
37228
+ region,
37229
+ runs: remaining,
37230
+ lastModified: Date.now()
37231
+ };
37232
+ await this.backend.putRawObject(indexKey, JSON.stringify(file, null, 2));
36816
37233
  }
36817
- }
37234
+ };
36818
37235
 
36819
37236
  //#endregion
36820
37237
  //#region src/deployment/orphan-adoption.ts
@@ -37120,6 +37537,7 @@ async function settleJournalAfterSuccess(stackName, completedOperations, previou
37120
37537
  const deployRunId = this.options.eventRecorder?.runId;
37121
37538
  const stripOnFailure = /* @__PURE__ */ new Map();
37122
37539
  const [ownLeft] = await Promise.all([(async () => {
37540
+ await orphanUntakenResumes.call(this, stackName, finalResources);
37123
37541
  if (this.absentJournalVersionPurge !== void 0 && this.stateBackend.rollbackJournalReadAbsent(stackName, this.stackRegion)) {
37124
37542
  await this.absentJournalVersionPurge;
37125
37543
  return 0;
@@ -37291,6 +37709,27 @@ async function writeRollbackJournalSegment(stackName, completedOperations, faile
37291
37709
  return false;
37292
37710
  }
37293
37711
  }
37712
+ async function orphanUntakenResumes(stackName, finalResources) {
37713
+ if (this.resumedCreates.size === 0) return;
37714
+ const untaken = new Map([...this.resumedCreates.values()].map((r) => [r.requestToken, r]));
37715
+ this.resumedCreates = /* @__PURE__ */ new Map();
37716
+ try {
37717
+ await this.stateBackend.rewriteRollbackJournalFailedOperations(stackName, this.stackRegion, (op) => {
37718
+ const resumed = op.pendingCloudControlRequest === void 0 ? void 0 : untaken.get(op.pendingCloudControlRequest.requestToken);
37719
+ if (resumed === void 0) return op;
37720
+ if (resumed.gone || finalResources[op.logicalId]?.physicalId === resumed.identifier) return withoutPendingRequest(op);
37721
+ return {
37722
+ ...withoutPendingRequest(op),
37723
+ provisionedBy: "cc-api",
37724
+ physicalId: resumed.identifier,
37725
+ physicalIdRecoveredFromError: true,
37726
+ createdIdentifierUnique: true
37727
+ };
37728
+ });
37729
+ } catch (error) {
37730
+ this.logger.warn(safeMsg`Could not settle the resumed Cloud Control requests in the rollback journal of ` + safeMsg`${displayStackName(stackName)} (${displaySafe(describeAwsFailure(error).summary)}); ` + "the next run settles them.");
37731
+ }
37732
+ }
37294
37733
 
37295
37734
  //#endregion
37296
37735
  //#region src/analyzer/parameter-dependence.ts
@@ -38717,30 +39156,45 @@ async function provisionCreate(logicalId, change, stateResources, stackName, tem
38717
39156
  });
38718
39157
  const createProvider = createDecision.provider;
38719
39158
  const createProps = createDecision.provisionedBy === "cc-api" ? this.preparePropertiesForCcApi(resourceType, resolvedProps, logicalId) : resolvedProps;
38720
- await refuseUnlicensedGeneratedName.call(this, {
38721
- logicalId,
38722
- resourceType,
38723
- stackName,
38724
- createdVia: createDecision.provisionedBy,
38725
- resolvedProps
38726
- });
38727
- await refuseTakenCreateName.call(this, {
39159
+ const resumed = await resumeAbandonedCreate.call(this, {
38728
39160
  logicalId,
38729
39161
  resourceType,
38730
39162
  stackName,
39163
+ resolvedProps,
39164
+ createProps,
38731
39165
  createProvider,
38732
39166
  createdVia: createDecision.provisionedBy,
38733
- createProps,
38734
- secrets: createSecrets,
38735
- stateResources
39167
+ maskSecrets: createSecretMasker(createSecrets)
38736
39168
  });
38737
- this.generatedNameGuard?.noteSent(logicalId);
38738
39169
  let result;
38739
- try {
38740
- result = await this.withRetry(() => withCurrentResourceSecrets(createSecrets, () => createProvider.create(logicalId, resourceType, createProps, { maskSecrets: createSecretMasker(createSecrets) })), logicalId, void 0, void 0, createProvider);
38741
- } catch (error) {
38742
- this.generatedNameGuard?.noteFailed(logicalId, error);
38743
- throw error;
39170
+ if (resumed !== void 0) {
39171
+ this.generatedNameGuard?.noteSent(logicalId);
39172
+ result = resumed;
39173
+ } else {
39174
+ await refuseUnlicensedGeneratedName.call(this, {
39175
+ logicalId,
39176
+ resourceType,
39177
+ stackName,
39178
+ createdVia: createDecision.provisionedBy,
39179
+ resolvedProps
39180
+ });
39181
+ await refuseTakenCreateName.call(this, {
39182
+ logicalId,
39183
+ resourceType,
39184
+ stackName,
39185
+ createProvider,
39186
+ createdVia: createDecision.provisionedBy,
39187
+ createProps,
39188
+ secrets: createSecrets,
39189
+ stateResources
39190
+ });
39191
+ this.generatedNameGuard?.noteSent(logicalId);
39192
+ try {
39193
+ result = await this.withRetry(() => withCurrentResourceSecrets(createSecrets, () => createProvider.create(logicalId, resourceType, createProps, { maskSecrets: createSecretMasker(createSecrets) })), logicalId, void 0, void 0, createProvider);
39194
+ } catch (error) {
39195
+ this.generatedNameGuard?.noteFailed(logicalId, error);
39196
+ throw error;
39197
+ }
38744
39198
  }
38745
39199
  this.generatedNameGuard?.noteReturned(logicalId);
38746
39200
  this.registerNoEchoAttributes(logicalId, result, createSecrets, resolvedProps);
@@ -38870,6 +39324,45 @@ async function refuseTakenCreateName(input) {
38870
39324
  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 + holeNote + (adopt === void 0 ? "" : `
38871
39325
  CONFIRM IT IS YOURS FIRST: another stack or app may own a resource of that name, and adopting it hands that resource to this stack's \`cdkd destroy\`.\nAdopt with: ${adopt.command}`));
38872
39326
  }
39327
+ async function resumeAbandonedCreate(args) {
39328
+ const { logicalId, resourceType } = args;
39329
+ const resumed = this.resumedCreates.get(logicalId);
39330
+ if (resumed === void 0 || resumed.taken || resumed.resourceType !== resourceType) return;
39331
+ const reader = args.createProvider;
39332
+ if (args.createdVia !== "cc-api" || typeof reader.resumeCreatedResource !== "function") return;
39333
+ const probe = {
39334
+ logicalId,
39335
+ changeType: "CREATE",
39336
+ resourceType,
39337
+ attemptedProperties: args.resolvedProps
39338
+ };
39339
+ const [redacted] = this.redactOperationsForJournal([probe]);
39340
+ const sentNow = redacted?.attemptedProperties;
39341
+ const asJson = (value) => value === void 0 ? void 0 : JSON.parse(JSON.stringify(value));
39342
+ if (!isDeepStrictEqual(asJson(sentNow), asJson(resumed.attemptedProperties))) {
39343
+ this.logger.warn(safeMsg`${logicalId}: the template changed since the CREATE cdkd stopped waiting for, so ` + "this deploy creates the resource again; the one that CREATE made is kept in the rollback journal as a resource the failed deploy created.");
39344
+ return;
39345
+ }
39346
+ let result;
39347
+ try {
39348
+ result = await this.withRetry(() => reader.resumeCreatedResource(logicalId, resourceType, resumed.identifier, args.createProps, { maskSecrets: args.maskSecrets }), logicalId, void 0, void 0, args.createProvider);
39349
+ } catch (error) {
39350
+ if (error.resumedResourceGone !== true) throw error;
39351
+ resumed.gone = true;
39352
+ this.logger.warn(safeMsg`${logicalId}: the resource the earlier CREATE made no longer exists; creating it as usual.`);
39353
+ return;
39354
+ }
39355
+ resumed.taken = true;
39356
+ const shown = displacedPhysicalIdShown({
39357
+ logicalId,
39358
+ changeType: "CREATE",
39359
+ resourceType,
39360
+ physicalId: resumed.identifier,
39361
+ attemptedProperties: resumed.attemptedProperties
39362
+ }, this.logger, resumed.identifier) ?? "the resource";
39363
+ this.logger.info(safeMsg`${logicalId}: took over ${shown}, the resource the earlier CREATE made, instead of ` + "creating another.");
39364
+ return result;
39365
+ }
38873
39366
 
38874
39367
  //#endregion
38875
39368
  //#region src/provisioning/data-delete-intent.ts
@@ -45325,11 +45818,20 @@ async function executeDeployment(template, currentState, changes, dag, execution
45325
45818
  record: replaced,
45326
45819
  createdId: replacementCreatedId
45327
45820
  } : void 0;
45821
+ const abandoned = change.changeType === "CREATE" && statePhysicalId === void 0 && createdId === void 0 ? abandonedRequestOf(provisionError) : void 0;
45822
+ const pendingRequest = abandoned?.operation === "CREATE" && /^[-A-Za-z0-9+/=]{1,128}$/.test(abandoned.requestToken) ? {
45823
+ requestToken: abandoned.requestToken,
45824
+ abandonedAt: Date.now()
45825
+ } : void 0;
45328
45826
  const failedOp = {
45329
45827
  logicalId,
45330
45828
  changeType: change.changeType,
45331
45829
  resourceType: change.resourceType,
45332
- provisionedBy: createdId !== void 0 ? "sdk" : newResources[logicalId]?.provisionedBy ?? previousState?.provisionedBy,
45830
+ provisionedBy: createdId !== void 0 ? "sdk" : pendingRequest !== void 0 ? "cc-api" : newResources[logicalId]?.provisionedBy ?? previousState?.provisionedBy,
45831
+ ...pendingRequest !== void 0 && {
45832
+ pendingCloudControlRequest: pendingRequest,
45833
+ deletionPolicy: journaledOrphanPolicy(this.extractTemplateAttributes(template, logicalId).deletionPolicy)
45834
+ },
45333
45835
  ...previousState && { previousState },
45334
45836
  physicalId: createdId ?? statePhysicalId,
45335
45837
  ...createdId !== void 0 && {
@@ -45359,7 +45861,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
45359
45861
  failedOperations.push(replacementOrphanOp);
45360
45862
  }
45361
45863
  const orphanOp = createdId !== void 0 ? failedOp : replacementOrphanOp;
45362
- if (orphanOp?.physicalId !== void 0 && orphanOp.deletionPolicy !== "Retain" && orphanDeleteNeedsIdentity(orphanOp.resourceType)) {
45864
+ if (orphanOp?.physicalId !== void 0 && orphanOp.deletionPolicy !== "Retain" && orphanNeedsIdentity(orphanOp)) {
45363
45865
  const markedIdentity = createdResourceIdentityBeforeFailure(provisionError, logicalId, change.resourceType);
45364
45866
  if (markedIdentity !== void 0) orphanOp.createdResourceIdentity = markedIdentity;
45365
45867
  else if (this.interruptCause !== "user") {
@@ -47038,8 +47540,42 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
47038
47540
  if (exportIndexStore && importableOutputKeys(currentState).length === 0) exportsPrefetch = afterGate(() => exportIndexStore.prefetch());
47039
47541
  }
47040
47542
  this.absentJournalVersionPurge = void 0;
47543
+ let journalAtStart = null;
47544
+ let journalReadError;
47545
+ try {
47546
+ journalAtStart = await this.stateBackend.loadRollbackJournal(stackName, this.stackRegion);
47547
+ } catch (error) {
47548
+ journalReadError = error ?? /* @__PURE__ */ new Error("unreadable rollback journal");
47549
+ }
47550
+ if (!this.options.dryRun && await resolvePendingCloudControlRequests({
47551
+ journal: this.stateBackend,
47552
+ loaded: journalAtStart,
47553
+ reader: () => this.providerRegistry.getCloudControlProvider(),
47554
+ stackName,
47555
+ region: this.stackRegion,
47556
+ command: "deploy",
47557
+ logger: this.logger,
47558
+ stateResources: currentState.resources,
47559
+ resume: (op, identifier) => {
47560
+ const attempted = op.attemptedProperties;
47561
+ if (template.Resources?.[op.logicalId]?.Type !== op.resourceType || attempted === void 0 || carriesSecretMask(attempted) || op.pendingCloudControlRequest === void 0 || Object.values(currentState.resources).some((r) => r.physicalId === identifier && r.resourceType === op.resourceType)) return false;
47562
+ this.resumedCreates.set(op.logicalId, {
47563
+ requestToken: op.pendingCloudControlRequest.requestToken,
47564
+ identifier,
47565
+ resourceType: op.resourceType,
47566
+ attemptedProperties: attempted
47567
+ });
47568
+ return true;
47569
+ },
47570
+ ...gate !== void 0 && { beforeSettle: () => gate }
47571
+ })) try {
47572
+ journalAtStart = await this.stateBackend.loadRollbackJournal(stackName, this.stackRegion);
47573
+ } catch (error) {
47574
+ journalReadError = error ?? /* @__PURE__ */ new Error("unreadable rollback journal");
47575
+ }
47041
47576
  try {
47042
- const loaded = await this.stateBackend.loadRollbackJournal(stackName, this.stackRegion);
47577
+ if (journalReadError !== void 0) throw journalReadError;
47578
+ const loaded = journalAtStart;
47043
47579
  if (loaded === null && !this.options.parentStackInfo && !this.options.dryRun) this.absentJournalVersionPurge = afterGate(() => this.stateBackend.purgeRollbackJournalVersions(stackName, this.stackRegion));
47044
47580
  const journal = loaded && {
47045
47581
  ...loaded,
@@ -47674,6 +48210,7 @@ var DeployEngine = class {
47674
48210
  constructPathTemplate;
47675
48211
  outputsSourceUsable = true;
47676
48212
  attemptedResolvedProps = /* @__PURE__ */ new Map();
48213
+ resumedCreates = /* @__PURE__ */ new Map();
47677
48214
  generatedNameGuard;
47678
48215
  liveTaskLabels = /* @__PURE__ */ new Map();
47679
48216
  retainedOldOnReplacement = /* @__PURE__ */ new Set();
@@ -47746,6 +48283,7 @@ var DeployEngine = class {
47746
48283
  this.fingerprintChildTemplates = void 0;
47747
48284
  this.perResourceInputFingerprints = /* @__PURE__ */ new Map();
47748
48285
  this.attemptedResolvedProps = /* @__PURE__ */ new Map();
48286
+ this.resumedCreates = /* @__PURE__ */ new Map();
47749
48287
  this.generatedNameGuard = void 0;
47750
48288
  this.liveTaskLabels = /* @__PURE__ */ new Map();
47751
48289
  this.outputSecrets = /* @__PURE__ */ new Map();
@@ -48027,5 +48565,5 @@ DeployEngine.prototype.replacementNameOrigin = replacementNameOrigin;
48027
48565
  DeployEngine.prototype.orphanedNameCollisionAdvice = orphanedNameCollisionAdvice;
48028
48566
 
48029
48567
  //#endregion
48030
- export { S3_AUTO_DELETE_OBJECTS_TAG as $, withheldAccountClause as $a, getDockerImageBySourceHash as $c, isReadableResourceEntry as $i, findDestructiveChanges as $n, literalSplitDelimitersOf as $o, applyRoleArnIfSet as $r, splitImportedOps as $s, recordUnderIdIsNotOwn as $t, diffSecurity as A, refuseMalformedResourceEntries as Aa, buildDenyExternalAccessPolicy as Ac, isNamelessDynamicReferenceError as Ai, hasOwnKey as Al, DEFAULT_RESOURCE_TIMEOUT_MS as An, withRetry as Ao, CloudControlProvider as Ar, provenPublicValue as As, withNestedStackContext as At, readProtection as B, refuseMalformedResourcesForDeploy as Ba, isDockerClientEnvKey as Bc, declaresNoEcho as Bi, injectedAwsRegionValue as Bl, storedSecretNameNeedles as Bn, maskWholeValue as Bo, markWaitAbandoned as Br, TEMPLATE_SOURCED_RULES as Bs, awaitInFlightSibling as Bt, withApiLimit as C, refuseMalformedOrphanRecordsForDestroy as Ca, ensureAssetStorage as Cc, coerceParameterTypedValue as Ci, PARTITION_TABLE as Cl, exportNameSecretExposure as Cn, replayWarn as Co, readsNoEchoDeleteValues as Cr, recordNestedStackParameterExpressions as Cs, nestedChildStackName as Ct, findServiceTokenRefusals as D, refuseMalformedOutputs as Da, readBootstrapMarkerBody as Dc, isImpossibleEmptyStoredAttribute as Di, StageLoadError as Dl, collectPublishedOutputNames as Dn, prefetchCreateOnlyPropertyPaths as Do, CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID as Dr, recordPhysicalNameCopy as Ds, withNestedRevertRun as Dt, deferredServiceTokenWarning as E, refuseMalformedOrphansForOrphan as Ea, parseBootstrapMarker as Ec, getAccountInfo as Ei, AssemblyReader as El, collectDeclaredOutputNames as En, requireConfigString as Eo, withPrintingSecrets as Er, recordAttributeIdCopy as Es, revertedNestedRowIds as Et, recordedProtectionEvidence as F, refuseMalformedResourceEntriesForOrphan as Fa, describeDockerFailure as Fc, refStateLookupFromResource as Fi, describeFileReadFailure as Fl, orphanRecordsPrintingBag as Fn, TemplateParser as Fo, deleteIndeterminateGuards as Fr, recordProvenPublicExpression as Fs, loadJournaledOrphans as Ft, deleteBudgetKey as G, repairMalformedOrphansForReadOnly as Ga, redactedDockerCause as Gc, UNREADABLE_RESOURCES_MAP_ROW as Gi, ccRoutedFinalSnapshotError as Gn, passedNoEchoParametersOf as Go, reDisableInstanceApiTermination as Gr, S3StateBackend as Gs, replacedDeleteFailureVerdict as Gt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as H, refuseMalformedResourcesForExport as Ha, partitionSensitiveEnv as Hc, STATE_REGION_DIVERGED as Hi, resolveBucketRegion as Hl, ATOMIC_FINAL_SNAPSHOT_TYPES as Hn, noEchoCoordinatesOf as Ho, ec2InstanceProtectionSite as Hr, isSingleDynamicReferenceToken as Hs, getStackRecords as Ht, recordedProtectionNote as I, refuseMalformedResourcePropertiesForDestroy as Ia, dockerSpawnEnvWithSensitive as Ic, parseWebACLArn as Ii, displayAssemblyPath as Il, secretNamePrintingBag as In, canonicalCoordinates as Io, deleteLeftInPlace as Ir, wholeStringLeavesOf as Is, makeForeignHolderScan as It, DELETE_INDEX_WAIT_PROCEED_NOTE as J, repairMalformedResourcePropertiesForReadOnly as Ja, warnFinchArgvExposure as Jc, displayLogicalId as Ji, isFinalSnapshotError as Jn, valueAtCoordinate as Jo, INTRINSIC_KEYS as Jr, CrossPrefixScanCache as Js, isJournaledOrphan as Jt, resolveDynamoDbDeleteBudgetClock as K, repairMalformedOutputsForReadOnly as Ka, runDockerForeground as Kc, accountArgs as Ki, createPreDeleteFinalSnapshot as Kn, readbackPathFor as Ko, reEnableInstanceApiTermination as Kr, rebuildClientForBucketRegion as Ks, recordAfterRollbackUpdate as Kt, PROTECTION_PROPERTY_BY_TYPE as L, refuseMalformedResourcePropertiesForDrift as La, finchSecretArgvRefusal as Lc, withSharedDrainBudget as Li, renderAssemblyPathEscape as Ll, secretNamePrintingBags as Ln, isMarkedCoordinate as Lo, deleteSkipReason as Lr, STATE_SOURCED_BASELINE_RULES as Ls, sameJournaledOrphans as Lt, noEchoComparisonForTemplate as M, refuseMalformedResourceEntriesForDestroy as Ma, resolveDockerContextDirectory as Mc, AWS_NO_VALUE as Mi, nullPrototypeRecord as Ml, completedReplayEntries as Mn, lambdaFunctionNameForMask as Mo, unchangedBehindSecretReference as Mr, recordMaskOnlyValuesIn as Ms, dropFailedHint as Mt, noEchoExactEchoLeavesOf as N, refuseMalformedResourceEntriesForImport as Na, describeDockerCapturedOutput as Nc, cfnRefValueFromPhysicalId as Ni, ownValue as Nl, journaledOrphanPrintingBag as Nn, sameLambdaFunctionAddress as No, RollbackInlinePolicyWriters as Nr, recordNoEchoAttributeValues as Ns, isHandledOrphan as Nt, serviceTokenBlockingReason as O, refuseMalformedOutputsForDestroy as Oa, validateAssetBucketName as Oc, carriesDynamicReference as Oi, processStackMessages as Ol, isExportAliasCollision as On, templateResourceTypes as Oo, applyCustomResourceResponseExpiration as Or, splitGetAttStringForm as Os, collectNestedChildUnaddressed as Ot, noEchoParameterNamesOf as P, refuseMalformedResourceEntriesForImportSave as Pa, describeDockerExecFailure as Pc, isStalePlaceholderArnAttribute as Pi, absoluteAssemblyPathEscape as Pl, maskEventTextWithBoundBags as Pn, DagBuilder as Po, UNSPECIFIED_SKIP_REASON as Pr, recordNoEchoParameterFreshValue as Ps, journaledOrphanLines as Pt, ECR_AUTO_DELETE_IMAGES_TAG as Q, unreadableResourceEntries as Qa, AssetManifestLoader as Qc, isReadableOrphanRecord as Qi, constructPathOf as Qn, hasMaskableValues as Qo, refuseUnreadableCdkCrossAccountRefs as Qr, isNotImplemented as Qs, recheckFailedPlan as Qt, isProtectionValueActive as R, refuseMalformedResourcePropertiesForExport as Ra, formatDockerLoginError as Rc, parameterInputsFor as Ri, resolveAssemblyPath as Rl, secretNamedRecordNeedles as Rn, maskAtCoordinates as Ro, withIndeterminateGuard as Rr, STATE_SOURCED_CROSS_GENERATION_RULES as Rs, replayFailedOperations as Rt, lookupEachName as S, refuseMalformedOrphanRecords as Sa, assertAssetBucketRegion as Sc, regionLessSecretName as Si, expectedOwnerParam as Sl, exportNameNoEchoParameters as Sn, readConfigString as So, TemplateNoEchoReresolver as Sr, inheritNestedStackParameterAssociations as Ss, getNestedRevertRun as St, recordRetainedForReadoption as T, refuseMalformedOrphansForDestroy as Ta, isCrossRegionRedirect as Tc, parameterTypeMayLoseSecretIdentity as Ti, derivePartitionAndUrlSuffix as Tl, noEchoParameterValueSeed as Tn, requireConfigObject as To, getCurrentResourceSecrets as Tr, physicalNameCopiesOf as Ts, revertNestedChildFromJournal as Tt, beginDeleteWait as U, refuseMalformedState as Ua, redactDockerArgvValues as Uc, STATE_RESOURCES_MALFORMED as Ui, PRE_DELETE_SNAPSHOT_TYPES as Un, noEchoLeavesOf as Uo, isTerminationProtectionPropagationError as Ur, LockManager as Us, withStackRecords as Ut, DynamoDBGlobalTableProvider as V, refuseMalformedResourcesForDestroy as Va, isMalformedEnvKey as Vc, JSON_LISTING_HOLE_VALUE as Vi, clearBucketRegionCache as Vl, extractDeploymentEventError as Vn, maskedLeafCoordinatesOf as Vo, disableInstanceApiTermination as Vr, WHOLE_DYNAMIC_REFERENCE_PATTERN as Vs, destroyStackRecordsView as Vt, compensateRemovedDeletionProtection as W, repairMalformedOrphanRecordsForReadOnly as Wa, redactedCause as Wc, UNREADABLE_ORPHANS_CONTAINER_ROW as Wi, buildFinalSnapshotIdentifier as Wn, noEchoOutputsComparison as Wo, observeThenDisableInstanceApiTermination as Wr, isLockInfoExpired as Ws, removeProtectionTypeList as Wt, deleteTableWithIndexBusyRetry as X, unpreviewableOrphanRecords as Xa, stripControlChars as Xc, hasReadableOutputs as Xi, unsupportedFinalSnapshotError as Xn, carryLogOnlyValues as Xo, poisonRenderedSpellingsCollidingIn as Xr, crossPrefixDeniedWarning as Xs, planFailedOps as Xt, INDEX_SETTLE_POLL_INTERVAL_MS as Y, repairMalformedResourcesForReadOnly as Ya, escapeRegExp$3 as Yc, hasReadableOrphans as Yi, refusesFinalSnapshot as Yn, liveMatchesUnresolvedTokenFrame as Yo, IntrinsicFunctionResolver as Yr, applyCrossPrefixScan as Ys, isReplacementOrphan as Yt, waitForIndexesSettled as Z, unreadableOrphanRecords as Za, stripForDisplay as Zc, hasReadableResources as Zi, maskingRetryLogger as Zn, createUnionSecretMasker as Zo, producerLookupOver as Zr, isAccessDenied$1 as Zs, planRollback as Zt, keptWholeReasonText as _, malformedScrubResourceEntriesRefusalMessage as _a, createAssetRedirectResolver as _c, s3BucketRegionalDomainName as _i, MIGRATE_TMP_PREFIX as _l, exportAliasCollisionScrubWarning as _n, coerceCfnBoolean as _o, CC_BROKEN_REASON as _r, DYNAMIC_REFERENCE_TOKEN_SCAN as _s, planOrphanAdoption as _t, inheritedProvenanceForChildDiff as a, malformedLocalResourcesWarning as aa, hasUnverifiableParameterRefusal as ac, AWS_CREDENTIAL_ENV_KEYS as ai, resolveApp as al, getCurrentProducerRegions as an, hasNoCloudControlHandlers as ao, acquireIdempotencyToken as ar, unionOfSecretBags as as, createReadOnlyAttributeHealerFactory as at, chunks as b, refuseDivergentRecordRegionForDestroy as ba, AssetModeResolver as bc, classifyReplaySecretRegion as bi, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as bl, secretSafeKeyDisplay as bn, configIntegerRefusal as bo, isCustomResource as br, pathCrossesDottedKey as bs, displacedPhysicalIdShown as bt, isAbsoluteAssetPath as c, malformedOrphanRowsKeptWarning as ca, isReadableBag as cc, envCredentialsAreAssumedRole as ci, resolveSkipPrefix as cl, isRedactedRecordedValue as cn, MULTI_REGION_RECREATE_BLOCKED_TYPES as co, DBPROXY_TAGS_WHAT as cr, maskSecretsInError as cs, gray as ct, templateIdentity as d, malformedOutputsRefusalMessage as da, shouldRetainResource as dc, outputReferenceProvenanceOf as di, resolveUseCdkBootstrapAssets as dl, updatePartialMessage as dn, renderStatefulReason as do, readTagList as dr, recordReferenceProvenanceEntry as ds, yellow as dt, malformedDriftResourcePropertiesWarning as ea, acceptedCreateOnlyDropsOf as ec, assertFlagRoleArn as ei, Synthesizer as el, replacementNeverSwapped as en, findActionableSilentDrops as eo, formatDestructiveChange as er, logOnlyValueCount as es, hasCdkAutoDeleteTag as et, conditionFingerprint as f, malformedOutputsWarning as fa, AssetPublisher as fc, recordedOutputReferenceRegions as fi, stateBucketExistenceConfirmed as fl, updatePartialReason as fn, WARM_THROUGHPUT_MEMBERS as fo, refuseMalformedDesiredTags as fr, snapshotPassProvenance as fs, computeParameterTaint as ft, isSecretBearingReferenceString as g, malformedResourcesWarning as ga, buildAssetRedirectMap as gc, s3BucketDualStackDomainName as gi, CFN_TEMPLATE_URL_LIMIT as gl, displayTextOrWithheld as gn, toFiniteNumber as go, stringifyIfAssigned as gr, withoutPhysicalNameCopies as gs, makeSiblingClaimReader as gt, readRecordedConditionVerdicts as h, malformedResourcePropertiesWarning as ha, WorkGraph as hc, s3BucketDomainName as hi, CFN_TEMPLATE_BODY_LIMIT as hl, WITHHELD_NAME_DISPLAY as hn, toCfnInteger as ho, definedAttributes as hr, withPhysicalNameCopies as hs, resourcesNamingDeclaredParameter as ht, crossStackOutputProvenanceSource as i, malformedLocalResourceEntriesWarning as ia, hasReasonlessBaselineRefusal as ic, sendableAssumeRoleCommand as ii, loadCdkJson as il, findNestedStackTypeChanges as in, NO_CC_HANDLERS_REASON as io, withCreateTokenLedger as ir, shareLogOnlyValues as is, formatResourceLine as it, noEchoAttributeNamesOf as j, refuseMalformedResourceEntriesForDeploy as ja, buildDockerImage as jc, keepsSecretReferenceToken as ji, hasPlainPrototype$1 as jl, DEFAULT_RESOURCE_WARN_AFTER_MS as jn, canonicalLambdaFunctionName as jo, slowCcOperationTimeoutMs as jr, recordMaskOnlyValue as js, deleteJournaledOrphans as jt, withResourceDeadline as k, refuseMalformedResourceAttributesForOrphan as ka, validateContainerRepoName as kc, carriesFetchableDynamicReference as ki, defineOwnKey as kl, bindingSkippedOutputs as kn, describeTypeWithThrottleRetry as ko, customResourceResponseExpirationWarning as kr, carriesSecretMask as ks, getCurrentNestedStackContext as kt, listNestedTemplateRows as l, malformedOrphansRefusalMessage as la, orphansAfterRollback as lc, isSettledInstanceState as li, resolveStateBucketWithDefault as ll, redactedDeleteAddressFields as ln, isStatefulRecreateTargetForReplace as lo, DBPROXY_TAG_OPTIONS as lr, maskSecretsInText as ls, green as lt, parentSuppliedValues as m, malformedResourceEntriesWarning as ma, stringifyValue as mc, s3BucketArn as mi, ssmResolvedValueType as ml, DeploymentEventsStore as mn, isWarmThroughputDecrease as mo, tagPlanWarning as mr, scrubResourceRecord as ms, reachableDivergentParameters as mt, IMPLICIT_DELETE_DEPENDENCIES as n, malformedExportSourceWarning as na, exportNamesCarriedFrom as nc, explicitRoleArnOrThrow as ni, getDefaultStateBucketName as nl, seedsDeleteFirstGuard as nn, unwrittenCreateOnlyReplacement as no, ledgerForStack as nr, recordLogOnlyParameterValue as ns, getPriorAttempts as nt, childTemplateLoader as o, malformedOrphanRecordsRefusalMessage as oa, importableOutputKeys as oc, applyCallerIdentityCredentials as oi, resolveAutoAssetStorage as ol, inheritProducerRegions as on, findReplacedReadersOfRecreateTargets as oo, isRefusedByName as or, createSecretMasker as os, bold as ot, conditionInputsFrom as p, malformedRenderedContainersWarning as pa, isSensitiveAttributeName as pc, recordedReferenceRegions as pi, warnDeprecatedNoPrefixCliFlag as pl, DeploymentEventsReader as pn, coerceWarmThroughput as po, tagMapAsList as pr, redactSecretsForState as ps, namesAnyDeclaredParameter as pt, resolveDynamoDbDeleteBudgetMs as q, repairMalformedResourceEntriesForReadOnly as qa, runDockerStreaming as qc, deployRefusesOrphanRowsReason as qi, effectiveDeletionPolicy as qn, readsNoEchoSource as qo, DiffCalculator as qr, CrossPrefixReadError as qs, demoteSupersededOrphans as qt, computeImplicitDeleteEdges as r, malformedLocalOutputsWarning as ra, hasReadableExportSet as rc, isIamRoleArn as ri, getLegacyStateBucketName as rl, orphanDeleteNeedsIdentity as rn, withoutSilentDropProperties as ro, reserveStackCreateToken as rr, recordLogOnlyValue as rs, markRefusedBeforeApplying as rt, findNestedTemplateTreeDefect as s, malformedOrphanRecordsWarning as sa, importableOutputs as sc, callerEnvCredentials as si, resolveCaptureObservedState as sl, REDACTED_DELETE_ADDRESS_SKIP_REASON as sn, shownType as so, markDeleteStarted as sr, errorCauseChain as ss, cyan as st, DeployEngine as t, malformedExportNamesWarning as ta, describeRegionValueKind as tc, assertSendableRoleArn as ti, synthesisStatusMessage as tl, resolveReplacementOldType as tn, findSilentDropProperties as to, earliestDefined as tr, printingCorpusOf as ts, isTruthyCfnBoolean as tt, renderNestedTemplateTreeDefect as u, malformedOrphansWarning as ua, orphansCarriedFrom as uc, keepHeldTokenProvenance as ui, resolveStateBucketWithDefaultAndSource as ul, redactedDeleteAddressSkip as un, isStatefulRecreateTargetSync as uo, planTagDiff as ur, markSameGenerationBag as us, red as ut, mergeNoChangeOutputs as v, malformedStateRefusalMessage as va, loadPublishableAssetManifest as vc, s3BucketWebsiteUrl as vi, findLargeInlineResources as vl, secretBearing as vn, coerceCfnInteger as vo, ProviderRegistry as vr, dynamicReferenceTokens as vs, NESTED_PENDING_PARENT_REASON as vt, keptForReadoption as w, refuseMalformedOrphans as wa, getBootstrapMarkerKey as wc, isUnboundTemplateParameter as wi, canonicalizeRegion as wl, isWholeDynamicReferenceValue as wn, requireConfigArray as wo, isCustomResourceType as wr, recoverMaskedOutput as ws, recordDisplacedSkips as wt, isAccessDeniedError as x, refuseMalformedNestedChildOutputs as xa, BOOTSTRAP_MARKER_PREFIX as xc, producerRegionsFromState as xi, decodeListingKey as xl, carriedExportAliasExposure as xn, configStringRefusal as xo, wouldReturnToSdkProvider as xr, identityKeyFor as xs, dropSettledNestedJournals as xt, makeCanonicalizePropertiesFn as y, previewableOrphanRecords as ya, rewriteTemplateAssetReferences as yc, classifyRecordedSecretRegion as yi, uploadCfnTemplate as yl, secretBearingStateKeyWarning as yn, configBooleanRefusal as yo, ccBrokenReason as yr, isUncertifiedBaselineMaskPosition as ys, displacedOpClause as yt, perType as z, refuseMalformedResourcePropertiesForOrphan as za, getDockerCmd as zc, passedParameterClassesOf as zi, injectAwsRegion as zl, stateSecretNameNeedles as zn, maskReadbackAtCoordinates as zo, isWaitAbandonedError as zr, STATE_SOURCED_READBACK_RULES as zs, replayRollback as zt };
48031
- //# sourceMappingURL=deploy-engine-DOBzE5TD.js.map
48568
+ export { S3_AUTO_DELETE_OBJECTS_TAG as $, unpreviewableOrphanRecords as $a, stripControlChars as $c, hasReadableOutputs as $i, unsupportedFinalSnapshotError as $n, carryLogOnlyValues as $o, poisonRenderedSpellingsCollidingIn as $r, crossPrefixDeniedWarning as $s, isJournaledOrphan as $t, diffSecurity as A, refuseMalformedOutputs as Aa, readBootstrapMarkerBody as Ac, isImpossibleEmptyStoredAttribute as Ai, StageLoadError as Al, collectPublishedOutputNames as An, prefetchCreateOnlyPropertyPaths as Ao, CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID as Ar, recordPhysicalNameCopy as As, NESTED_PENDING_PARENT_REASON as At, readProtection as B, refuseMalformedResourcePropertiesForDrift as Ba, finchSecretArgvRefusal as Bc, withSharedDrainBudget as Bi, renderAssemblyPathEscape as Bl, secretNamePrintingBags as Bn, isMarkedCoordinate as Bo, deleteSkipReason as Br, STATE_SOURCED_BASELINE_RULES as Bs, collectNestedChildUnaddressed as Bt, withApiLimit as C, refuseDivergentRecordRegionForDestroy as Ca, AssetModeResolver as Cc, classifyReplaySecretRegion as Ci, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Cl, secretSafeKeyDisplay as Cn, configIntegerRefusal as Co, isCustomResource as Cr, pathCrossesDottedKey as Cs, dropFailedCommands as Ct, findServiceTokenRefusals as D, refuseMalformedOrphans as Da, getBootstrapMarkerKey as Dc, isUnboundTemplateParameter as Di, canonicalizeRegion as Dl, isWholeDynamicReferenceValue as Dn, requireConfigArray as Do, isCustomResourceType as Dr, recoverMaskedOutput as Ds, loadJournaledOrphans as Dt, deferredServiceTokenWarning as E, refuseMalformedOrphanRecordsForDestroy as Ea, ensureAssetStorage as Ec, coerceParameterTypedValue as Ei, PARTITION_TABLE as El, exportNameSecretExposure as En, replayWarn as Eo, readsNoEchoDeleteValues as Er, recordNestedStackParameterExpressions as Es, journaledOrphanLines as Et, recordedProtectionEvidence as F, refuseMalformedResourceEntriesForDestroy as Fa, resolveDockerContextDirectory as Fc, AWS_NO_VALUE as Fi, nullPrototypeRecord as Fl, completedReplayEntries as Fn, lambdaFunctionNameForMask as Fo, unchangedBehindSecretReference as Fr, recordMaskOnlyValuesIn as Fs, nestedChildStackName as Ft, deleteBudgetKey as G, refuseMalformedResourcesForExport as Ga, partitionSensitiveEnv as Gc, STATE_REGION_DIVERGED as Gi, resolveBucketRegion as Gl, ATOMIC_FINAL_SNAPSHOT_TYPES as Gn, noEchoCoordinatesOf as Go, ec2InstanceProtectionSite as Gr, isSingleDynamicReferenceToken as Gs, awaitInFlightSibling as Gt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as H, refuseMalformedResourcePropertiesForOrphan as Ha, getDockerCmd as Hc, passedParameterClassesOf as Hi, injectAwsRegion as Hl, stateSecretNameNeedles as Hn, maskReadbackAtCoordinates as Ho, isWaitAbandonedError as Hr, STATE_SOURCED_READBACK_RULES as Hs, withNestedStackContext as Ht, recordedProtectionNote as I, refuseMalformedResourceEntriesForImport as Ia, describeDockerCapturedOutput as Ic, cfnRefValueFromPhysicalId as Ii, ownValue as Il, journaledOrphanPrintingBag as In, sameLambdaFunctionAddress as Io, RollbackInlinePolicyWriters as Ir, recordNoEchoAttributeValues as Is, recordDisplacedSkips as It, DELETE_INDEX_WAIT_PROCEED_NOTE as J, repairMalformedOrphansForReadOnly as Ja, redactedDockerCause as Jc, UNREADABLE_RESOURCES_MAP_ROW as Ji, ccRoutedFinalSnapshotError as Jn, passedNoEchoParametersOf as Jo, reDisableInstanceApiTermination as Jr, S3StateBackend as Js, withStackRecords as Jt, resolveDynamoDbDeleteBudgetClock as K, refuseMalformedState as Ka, redactDockerArgvValues as Kc, STATE_RESOURCES_MALFORMED as Ki, PRE_DELETE_SNAPSHOT_TYPES as Kn, noEchoLeavesOf as Ko, isTerminationProtectionPropagationError as Kr, LockManager as Ks, destroyStackRecordsView as Kt, PROTECTION_PROPERTY_BY_TYPE as L, refuseMalformedResourceEntriesForImportSave as La, describeDockerExecFailure as Lc, isStalePlaceholderArnAttribute as Li, absoluteAssemblyPathEscape as Ll, maskEventTextWithBoundBags as Ln, DagBuilder as Lo, UNSPECIFIED_SKIP_REASON as Lr, recordNoEchoParameterFreshValue as Ls, revertNestedChildFromJournal as Lt, noEchoComparisonForTemplate as M, refuseMalformedResourceAttributesForOrphan as Ma, validateContainerRepoName as Mc, carriesFetchableDynamicReference as Mi, defineOwnKey as Ml, bindingSkippedOutputs as Mn, describeTypeWithThrottleRetry as Mo, customResourceResponseExpirationWarning as Mr, carriesSecretMask as Ms, displacedPhysicalIdShown as Mt, noEchoExactEchoLeavesOf as N, refuseMalformedResourceEntries as Na, buildDenyExternalAccessPolicy as Nc, isNamelessDynamicReferenceError as Ni, hasOwnKey as Nl, DEFAULT_RESOURCE_TIMEOUT_MS as Nn, withRetry as No, CloudControlProvider as Nr, provenPublicValue as Ns, dropSettledNestedJournals as Nt, serviceTokenBlockingReason as O, refuseMalformedOrphansForDestroy as Oa, isCrossRegionRedirect as Oc, parameterTypeMayLoseSecretIdentity as Oi, derivePartitionAndUrlSuffix as Ol, noEchoParameterValueSeed as On, requireConfigObject as Oo, getCurrentResourceSecrets as Or, physicalNameCopiesOf as Os, makeForeignHolderScan as Ot, noEchoParameterNamesOf as P, refuseMalformedResourceEntriesForDeploy as Pa, buildDockerImage as Pc, keepsSecretReferenceToken as Pi, hasPlainPrototype$1 as Pl, DEFAULT_RESOURCE_WARN_AFTER_MS as Pn, canonicalLambdaFunctionName as Po, slowCcOperationTimeoutMs as Pr, recordMaskOnlyValue as Ps, getNestedRevertRun as Pt, ECR_AUTO_DELETE_IMAGES_TAG as Q, repairMalformedResourcesForReadOnly as Qa, escapeRegExp$3 as Qc, hasReadableOrphans as Qi, refusesFinalSnapshot as Qn, liveMatchesUnresolvedTokenFrame as Qo, IntrinsicFunctionResolver as Qr, applyCrossPrefixScan as Qs, demoteSupersededOrphans as Qt, isProtectionValueActive as R, refuseMalformedResourceEntriesForOrphan as Ra, describeDockerFailure as Rc, refStateLookupFromResource as Ri, describeFileReadFailure as Rl, orphanRecordsPrintingBag as Rn, TemplateParser as Ro, deleteIndeterminateGuards as Rr, recordProvenPublicExpression as Rs, revertedNestedRowIds as Rt, lookupEachName as S, previewableOrphanRecords as Sa, rewriteTemplateAssetReferences as Sc, classifyRecordedSecretRegion as Si, uploadCfnTemplate as Sl, secretBearingStateKeyWarning as Sn, configBooleanRefusal as So, ccBrokenReason as Sr, isUncertifiedBaselineMaskPosition as Ss, deleteJournaledOrphans as St, recordRetainedForReadoption as T, refuseMalformedOrphanRecords as Ta, assertAssetBucketRegion as Tc, regionLessSecretName as Ti, expectedOwnerParam as Tl, exportNameNoEchoParameters as Tn, readConfigString as To, TemplateNoEchoReresolver as Tr, inheritNestedStackParameterAssociations as Ts, isHandledOrphan as Tt, beginDeleteWait as U, refuseMalformedResourcesForDeploy as Ua, isDockerClientEnvKey as Uc, declaresNoEcho as Ui, injectedAwsRegionValue as Ul, storedSecretNameNeedles as Un, maskWholeValue as Uo, markWaitAbandoned as Ur, TEMPLATE_SOURCED_RULES as Us, replayFailedOperations as Ut, DynamoDBGlobalTableProvider as V, refuseMalformedResourcePropertiesForExport as Va, formatDockerLoginError as Vc, parameterInputsFor as Vi, resolveAssemblyPath as Vl, secretNamedRecordNeedles as Vn, maskAtCoordinates as Vo, withIndeterminateGuard as Vr, STATE_SOURCED_CROSS_GENERATION_RULES as Vs, getCurrentNestedStackContext as Vt, compensateRemovedDeletionProtection as W, refuseMalformedResourcesForDestroy as Wa, isMalformedEnvKey as Wc, JSON_LISTING_HOLE_VALUE as Wi, clearBucketRegionCache as Wl, extractDeploymentEventError as Wn, maskedLeafCoordinatesOf as Wo, disableInstanceApiTermination as Wr, WHOLE_DYNAMIC_REFERENCE_PATTERN as Ws, replayRollback as Wt, deleteTableWithIndexBusyRetry as X, repairMalformedResourceEntriesForReadOnly as Xa, runDockerStreaming as Xc, deployRefusesOrphanRowsReason as Xi, effectiveDeletionPolicy as Xn, readsNoEchoSource as Xo, DiffCalculator as Xr, CrossPrefixReadError as Xs, replacedDeleteFailureVerdict as Xt, INDEX_SETTLE_POLL_INTERVAL_MS as Y, repairMalformedOutputsForReadOnly as Ya, runDockerForeground as Yc, accountArgs as Yi, createPreDeleteFinalSnapshot as Yn, readbackPathFor as Yo, reEnableInstanceApiTermination as Yr, rebuildClientForBucketRegion as Ys, removeProtectionTypeList as Yt, waitForIndexesSettled as Z, repairMalformedResourcePropertiesForReadOnly as Za, warnFinchArgvExposure as Zc, displayLogicalId as Zi, isFinalSnapshotError as Zn, valueAtCoordinate as Zo, INTRINSIC_KEYS as Zr, CrossPrefixScanCache as Zs, recordAfterRollbackUpdate as Zt, keptWholeReasonText as _, malformedResourceEntriesWarning as _a, stringifyValue as _c, s3BucketArn as _i, ssmResolvedValueType as _l, orphanNeedsIdentity as _n, isWarmThroughputDecrease as _o, tagPlanWarning as _r, scrubResourceRecord as _s, planOrphanAdoption as _t, inheritedProvenanceForChildDiff as a, malformedExportSourceWarning as aa, exportNamesCarriedFrom as ac, explicitRoleArnOrThrow as ai, getDefaultStateBucketName as al, replacementNeverSwapped as an, unwrittenCreateOnlyReplacement as ao, ledgerForStack as ar, recordLogOnlyParameterValue as as, createReadOnlyAttributeHealerFactory as at, chunks as b, malformedScrubResourceEntriesRefusalMessage as ba, createAssetRedirectResolver as bc, s3BucketRegionalDomainName as bi, MIGRATE_TMP_PREFIX as bl, exportAliasCollisionScrubWarning as bn, coerceCfnBoolean as bo, CC_BROKEN_REASON as br, DYNAMIC_REFERENCE_TOKEN_SCAN as bs, pendingRequestCount as bt, isAbsoluteAssetPath as c, malformedLocalResourcesWarning as ca, hasUnverifiableParameterRefusal as cc, AWS_CREDENTIAL_ENV_KEYS as ci, resolveApp as cl, findNestedStackTypeChanges as cn, hasNoCloudControlHandlers as co, acquireIdempotencyToken as cr, unionOfSecretBags as cs, gray as ct, templateIdentity as d, malformedOrphanRowsKeptWarning as da, isReadableBag as dc, envCredentialsAreAssumedRole as di, resolveSkipPrefix as dl, REDACTED_DELETE_ADDRESS_SKIP_REASON as dn, MULTI_REGION_RECREATE_BLOCKED_TYPES as do, DBPROXY_TAGS_WHAT as dr, maskSecretsInError as ds, yellow as dt, hasReadableResources as ea, isAccessDenied$1 as ec, producerLookupOver as ei, stripForDisplay as el, isReplacementOrphan as en, unreadableOrphanRecords as eo, maskingRetryLogger as er, createUnionSecretMasker as es, hasCdkAutoDeleteTag as et, conditionFingerprint as f, malformedOrphansRefusalMessage as fa, orphansAfterRollback as fc, isSettledInstanceState as fi, resolveStateBucketWithDefault as fl, isRedactedRecordedValue as fn, isStatefulRecreateTargetForReplace as fo, DBPROXY_TAG_OPTIONS as fr, maskSecretsInText as fs, computeParameterTaint as ft, isSecretBearingReferenceString as g, malformedRenderedContainersWarning as ga, isSensitiveAttributeName as gc, recordedReferenceRegions as gi, warnDeprecatedNoPrefixCliFlag as gl, updatePartialReason as gn, coerceWarmThroughput as go, tagMapAsList as gr, redactSecretsForState as gs, makeSiblingClaimReader as gt, readRecordedConditionVerdicts as h, malformedOutputsWarning as ha, AssetPublisher as hc, recordedOutputReferenceRegions as hi, stateBucketExistenceConfirmed as hl, updatePartialMessage as hn, WARM_THROUGHPUT_MEMBERS as ho, refuseMalformedDesiredTags as hr, snapshotPassProvenance as hs, resourcesNamingDeclaredParameter as ht, crossStackOutputProvenanceSource as i, malformedExportNamesWarning as ia, describeRegionValueKind as ic, assertSendableRoleArn as ii, synthesisStatusMessage as il, recordUnderIdIsNotOwn as in, findSilentDropProperties as io, earliestDefined as ir, printingCorpusOf as is, formatResourceLine as it, noEchoAttributeNamesOf as j, refuseMalformedOutputsForDestroy as ja, validateAssetBucketName as jc, carriesDynamicReference as ji, processStackMessages as jl, isExportAliasCollision as jn, templateResourceTypes as jo, applyCustomResourceResponseExpiration as jr, splitGetAttStringForm as js, displacedOpClause as jt, withResourceDeadline as k, refuseMalformedOrphansForOrphan as ka, parseBootstrapMarker as kc, getAccountInfo as ki, AssemblyReader as kl, collectDeclaredOutputNames as kn, requireConfigString as ko, withPrintingSecrets as kr, recordAttributeIdCopy as ks, sameJournaledOrphans as kt, listNestedTemplateRows as l, malformedOrphanRecordsRefusalMessage as la, importableOutputKeys as lc, applyCallerIdentityCredentials as li, resolveAutoAssetStorage as ll, getCurrentProducerRegions as ln, findReplacedReadersOfRecreateTargets as lo, isRefusedByName as lr, createSecretMasker as ls, green as lt, parentSuppliedValues as m, malformedOutputsRefusalMessage as ma, shouldRetainResource as mc, outputReferenceProvenanceOf as mi, resolveUseCdkBootstrapAssets as ml, redactedDeleteAddressSkip as mn, renderStatefulReason as mo, readTagList as mr, recordReferenceProvenanceEntry as ms, reachableDivergentParameters as mt, IMPLICIT_DELETE_DEPENDENCIES as n, isReadableResourceEntry as na, splitImportedOps as nc, applyRoleArnIfSet as ni, getDockerImageBySourceHash as nl, planRollback as nn, withheldAccountClause as no, findDestructiveChanges as nr, literalSplitDelimitersOf as ns, getPriorAttempts as nt, childTemplateLoader as o, malformedLocalOutputsWarning as oa, hasReadableExportSet as oc, isIamRoleArn as oi, getLegacyStateBucketName as ol, resolveReplacementOldType as on, withoutSilentDropProperties as oo, reserveStackCreateToken as or, recordLogOnlyValue as os, bold as ot, conditionInputsFrom as p, malformedOrphansWarning as pa, orphansCarriedFrom as pc, keepHeldTokenProvenance as pi, resolveStateBucketWithDefaultAndSource as pl, redactedDeleteAddressFields as pn, isStatefulRecreateTargetSync as po, planTagDiff as pr, markSameGenerationBag as ps, namesAnyDeclaredParameter as pt, resolveDynamoDbDeleteBudgetMs as q, repairMalformedOrphanRecordsForReadOnly as qa, redactedCause as qc, UNREADABLE_ORPHANS_CONTAINER_ROW as qi, buildFinalSnapshotIdentifier as qn, noEchoOutputsComparison as qo, observeThenDisableInstanceApiTermination as qr, isLockInfoExpired as qs, getStackRecords as qt, computeImplicitDeleteEdges as r, malformedDriftResourcePropertiesWarning as ra, acceptedCreateOnlyDropsOf as rc, assertFlagRoleArn as ri, Synthesizer as rl, recheckFailedPlan as rn, findActionableSilentDrops as ro, formatDestructiveChange as rr, logOnlyValueCount as rs, markRefusedBeforeApplying as rt, findNestedTemplateTreeDefect as s, malformedLocalResourceEntriesWarning as sa, hasReasonlessBaselineRefusal as sc, sendableAssumeRoleCommand as si, loadCdkJson as sl, seedsDeleteFirstGuard as sn, NO_CC_HANDLERS_REASON as so, withCreateTokenLedger as sr, shareLogOnlyValues as ss, cyan as st, DeployEngine as t, isReadableOrphanRecord as ta, isNotImplemented as tc, refuseUnreadableCdkCrossAccountRefs as ti, AssetManifestLoader as tl, planFailedOps as tn, unreadableResourceEntries as to, constructPathOf as tr, hasMaskableValues as ts, isTruthyCfnBoolean as tt, renderNestedTemplateTreeDefect as u, malformedOrphanRecordsWarning as ua, importableOutputs as uc, callerEnvCredentials as ui, resolveCaptureObservedState as ul, inheritProducerRegions as un, shownType as uo, markDeleteStarted as ur, errorCauseChain as us, red as ut, mergeNoChangeOutputs as v, malformedResourcePropertiesWarning as va, WorkGraph as vc, s3BucketDomainName as vi, CFN_TEMPLATE_BODY_LIMIT as vl, WITHHELD_NAME_DISPLAY as vn, toCfnInteger as vo, definedAttributes as vr, withPhysicalNameCopies as vs, DeploymentEventsReader as vt, keptForReadoption as w, refuseMalformedNestedChildOutputs as wa, BOOTSTRAP_MARKER_PREFIX as wc, producerRegionsFromState as wi, decodeListingKey as wl, carriedExportAliasExposure as wn, configStringRefusal as wo, wouldReturnToSdkProvider as wr, identityKeyFor as ws, dropFailedHint as wt, isAccessDeniedError as x, malformedStateRefusalMessage as xa, loadPublishableAssetManifest as xc, s3BucketWebsiteUrl as xi, findLargeInlineResources as xl, secretBearing as xn, coerceCfnInteger as xo, ProviderRegistry as xr, dynamicReferenceTokens as xs, resolvePendingCloudControlRequests as xt, makeCanonicalizePropertiesFn as y, malformedResourcesWarning as ya, buildAssetRedirectMap as yc, s3BucketDualStackDomainName as yi, CFN_TEMPLATE_URL_LIMIT as yl, displayTextOrWithheld as yn, toFiniteNumber as yo, stringifyIfAssigned as yr, withoutPhysicalNameCopies as ys, DeploymentEventsStore as yt, perType as z, refuseMalformedResourcePropertiesForDestroy as za, dockerSpawnEnvWithSensitive as zc, parseWebACLArn as zi, displayAssemblyPath as zl, secretNamePrintingBag as zn, canonicalCoordinates as zo, deleteLeftInPlace as zr, wholeStringLeavesOf as zs, withNestedRevertRun as zt };
48569
+ //# sourceMappingURL=deploy-engine-BYgrFxwH.js.map