@go-to-k/cdkd 0.285.14 → 0.285.16

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.
@@ -1,6 +1,6 @@
1
1
  import { _ as withStackName, d as applyDefaultNameForFallback, f as generateResourceName, h as looksLikeCdkdGeneratedName, m as getCurrentStackName, n as getLogger, p as generateResourceNameWithFallback, r as isStdoutReservedForPayload, s as getLiveRenderer } from "./logger-Dw-3y48G.js";
2
2
  import { t as awsClientDefaults } from "./aws-client-defaults-D-iYiIJ6.js";
3
- import { t as getCdkdVersion } from "./version-DP5kGlzj.js";
3
+ import { t as getCdkdVersion } from "./version-C_ZRHikq.js";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { randomUUID } from "node:crypto";
6
6
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -7927,6 +7927,140 @@ function parseRollbackJournal(bodyString, stackName) {
7927
7927
  };
7928
7928
  }
7929
7929
 
7930
+ //#endregion
7931
+ //#region src/state/state-prefix.ts
7932
+ /**
7933
+ * The default S3 key prefix for cdkd state.
7934
+ *
7935
+ * Homed in the STATE layer rather than in `src/cli/commands/state-file-keys.ts`
7936
+ * (which re-exports it, so its four existing importers are unchanged) because
7937
+ * `src/state/lock-contention-message.ts` needs it to decide whether a recovery
7938
+ * hint should spell `--state-prefix` at all, and a `src/state/**` module
7939
+ * importing from `src/cli/commands/**` inverts the layering — the CLI sits
7940
+ * ABOVE the state layer in the 7-layer architecture, not below it.
7941
+ *
7942
+ * Note this is only the DEFAULT. Other commands accept `--state-prefix`, so
7943
+ * whole-bucket listings deliberately do not scope to it.
7944
+ */
7945
+ const DEFAULT_STATE_PREFIX = "cdkd";
7946
+ /**
7947
+ * The state-bucket prefix `CustomResourceProvider` PUTs its response
7948
+ * placeholders under, one object per invocation
7949
+ * (`custom-resource-responses/{requestId}.json`).
7950
+ *
7951
+ * Homed here for the same layering reason as {@link DEFAULT_STATE_PREFIX}: the
7952
+ * PRODUCER is `src/provisioning/providers/custom-resource-provider.ts` and the
7953
+ * COLLECTOR is `src/cli/commands/gc.ts`, so a copy in either would be a copy
7954
+ * the other could drift from — and the two spellings would then disagree about
7955
+ * which objects exist, which is the only way a sweeper can miss the family it
7956
+ * was written for (issue #2052). `src/cli/commands/state-file-keys.ts`
7957
+ * re-exports it so gc reads it alongside the other state-key constants.
7958
+ *
7959
+ * Note this is only the DEFAULT: `ProviderRegistry` can be configured with a
7960
+ * different `responsePrefix`, so a sweep scoped to this value is a sweep of the
7961
+ * default layout. gc has no access to a non-default one — nothing persists it —
7962
+ * which is stated at the sweep's own call site rather than implied here.
7963
+ */
7964
+ const CUSTOM_RESOURCE_RESPONSE_PREFIX = "custom-resource-responses";
7965
+
7966
+ //#endregion
7967
+ //#region src/state/lock-contention-message.ts
7968
+ /**
7969
+ * The message every fail-fast lock-contention site raises.
7970
+ *
7971
+ * Issue #2161 made six commands throw on `acquireLock` returning `false`
7972
+ * instead of running under a foreign lock. Issue #2170 is the follow-up: the
7973
+ * message those sites raise asked the user to decide "is another process
7974
+ * active?" while printing none of the evidence that would answer it, and the
7975
+ * recovery command it suggested could resolve against the wrong AWS account.
7976
+ *
7977
+ * Both matter more than they look, because of WHICH locks reach this message.
7978
+ * `LockManager.acquireLock` reaps an EXPIRED foreign lock and retries, so a
7979
+ * `false` return means the lock is LIVE — in practice a running `cdkd deploy`.
7980
+ * The user who follows a bare `cdkd force-unlock <stack>` suggestion therefore
7981
+ * deletes a live owner's lock and reproduces issue #2161's harm by hand, which
7982
+ * is the outcome #2161 exists to prevent.
7983
+ *
7984
+ * Centralising the text here also settles the third finding: the nine sites
7985
+ * had drifted to three spellings (`for stack` / `for nested stack` /
7986
+ * `for nested-stack child`), so a user grepping CI logs for one of them found
7987
+ * two of three. `subject` now varies only the noun.
7988
+ */
7989
+ /**
7990
+ * Stand-in for a value with nothing renderable left after sanitization. Named
7991
+ * rather than inlined so the message and the command-suppression branch cannot
7992
+ * disagree about what "unrenderable" looks like.
7993
+ */
7994
+ const UNRENDERABLE = "<unrenderable>";
7995
+ /** Render `expiresIn` without implying more precision than a clock skew allows. */
7996
+ function formatRemaining(ms) {
7997
+ if (!Number.isFinite(ms)) return "at an unknown time";
7998
+ if (ms <= 0) return "already expired";
7999
+ const minutes = Math.round(ms / 6e4);
8000
+ if (minutes < 1) return "in under a minute";
8001
+ return `in ~${minutes}m`;
8002
+ }
8003
+ function shellQuote(value) {
8004
+ return /^[A-Za-z0-9._/@:+-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
8005
+ }
8006
+ /**
8007
+ * The `cdkd force-unlock ...` line, carrying every flag that decides which
8008
+ * lock object it resolves to.
8009
+ */
8010
+ function buildForceUnlockCommand(stackName, region, recovery) {
8011
+ const safeStack = displaySafe(stackName, { asciiOnly: true });
8012
+ const stackIsExact = safeStack === stackName;
8013
+ const safeRegion = region === void 0 ? void 0 : displaySafe(region, { asciiOnly: true });
8014
+ if (!safeStack || safeRegion === "" || !stackIsExact || !(region === void 0 || safeRegion === region)) return "";
8015
+ const parts = [safeRegion === void 0 ? `cdkd force-unlock ${shellQuote(safeStack)}` : `cdkd force-unlock ${shellQuote(safeStack)} --stack-region ${shellQuote(safeRegion)}`];
8016
+ if (recovery?.profile) parts.push(`--profile ${shellQuote(recovery.profile)}`);
8017
+ if (recovery?.stateBucket) parts.push(`--state-bucket ${shellQuote(recovery.stateBucket)}`);
8018
+ if (recovery?.statePrefix && recovery.statePrefix !== "cdkd") parts.push(`--state-prefix ${shellQuote(recovery.statePrefix)}`);
8019
+ return parts.join(" ");
8020
+ }
8021
+ /**
8022
+ * The force-quit banner's recovery sentence.
8023
+ *
8024
+ * Exported so the two `destroy-runner.ts` banners do not each decide what to
8025
+ * say when {@link buildForceUnlockCommand} suppresses — a banner ending in a
8026
+ * bare `run: ` is the shape the review found, and two copies of the branch is
8027
+ * how the next one drifts. Returns a leading-space clause so the caller can
8028
+ * concatenate it unconditionally.
8029
+ */
8030
+ function forceQuitRecoveryClause(stackName, region, recovery) {
8031
+ const command = buildForceUnlockCommand(stackName, region, recovery);
8032
+ return command ? ` If the next run reports a lock, run: ${command}` : " Inspect the lock object directly: the name or region recorded for this stack cannot be reproduced safely on a command line, so any command shown here would address a different lock.";
8033
+ }
8034
+ /**
8035
+ * Build the contention message, reading the holder's identity best-effort.
8036
+ *
8037
+ * The `getLockInfo` read is one GetObject and is deliberately NOT allowed to
8038
+ * fail the command: the caller is already on its way to throwing, and turning
8039
+ * a contention refusal into an S3 error would lose the reason. A failed or
8040
+ * absent read degrades to the evidence-free wording rather than to a crash.
8041
+ */
8042
+ async function buildLockContentionMessage(args) {
8043
+ const { lockManager, stackName, region, subject = "stack", recovery, heldClause, suffix } = args;
8044
+ let held = heldClause ?? "another cdkd process holds it";
8045
+ let sawHolder = false;
8046
+ try {
8047
+ const info = await lockManager.getLockInfo(stackName, region);
8048
+ if (info) {
8049
+ const operation = info.operation ? `, operation: ${displaySafe(info.operation)}` : "";
8050
+ const expires = formatRemaining(info.expiresAt - Date.now());
8051
+ const owner = displaySafe(info.owner);
8052
+ const holder = owner ? `held by ${owner}${operation}` : `held by an unnamed holder`;
8053
+ held = `${heldClause ? `${heldClause} — ` : ""}${holder}, expires ${expires}`;
8054
+ if (owner) sawHolder = true;
8055
+ }
8056
+ } catch {}
8057
+ const advice = sawHolder ? `That process is still running — wait for it to finish. Only if you are certain it is gone` : `Wait for it to finish, or if you are certain no other process is active`;
8058
+ const recoveryCommand = buildForceUnlockCommand(stackName, region, recovery);
8059
+ const head = `Could not acquire lock for ${subject} '${displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>"}' (${displaySafe(region, { asciiOnly: true }) || "<unrenderable>"}) — ${held}.` + (suffix ? ` ${suffix}` : "");
8060
+ if (!recoveryCommand) return `${head} ${advice}. No recovery command can be shown: the name or region recorded for this lock contains characters that cannot be reproduced safely on a command line, so any command shown here would address a different lock — inspect the lock object directly.`;
8061
+ return `${head} ${advice}, run: ${recoveryCommand}`;
8062
+ }
8063
+
7930
8064
  //#endregion
7931
8065
  //#region src/utils/bucket-region-client.ts
7932
8066
  /**
@@ -8013,6 +8147,23 @@ const LEGACY_KEY_DEPTH = 2;
8013
8147
  /** The `version: 2` region-prefixed key. */
8014
8148
  const NEW_KEY_DEPTH = 3;
8015
8149
  /**
8150
+ * Does a legacy record classified by {@link LegacyStateProbe} belong to an
8151
+ * operation targeting `region`?
8152
+ *
8153
+ * Free function, and shared by both consumers on purpose: the delete sweep
8154
+ * needs the probe's KIND as well as this verdict (to warn when a record may
8155
+ * have been left behind), and duplicating the mapping at that call site is
8156
+ * how the two would drift apart again.
8157
+ */
8158
+ function legacyProbeBelongsTo(probe, region) {
8159
+ switch (probe.kind) {
8160
+ case "region": return probe.region === region;
8161
+ case "no-region": return true;
8162
+ case "absent":
8163
+ case "unreadable": return false;
8164
+ }
8165
+ }
8166
+ /**
8016
8167
  * S3-based state backend using conditional writes for optimistic locking.
8017
8168
  *
8018
8169
  * State keys are region-scoped (`{prefix}/{stackName}/{region}/state.json`)
@@ -8178,7 +8329,7 @@ var S3StateBackend = class {
8178
8329
  await this.ensureClientForBucket();
8179
8330
  const newKey = this.getStateKey(stackName, region);
8180
8331
  if (await this.headObject(newKey)) return true;
8181
- return this.legacyMatchesRegion(stackName, region);
8332
+ return this.legacyBelongsToRegion(stackName, region);
8182
8333
  }
8183
8334
  /**
8184
8335
  * Get state for a stack, transparently falling back to the legacy key.
@@ -8310,7 +8461,12 @@ var S3StateBackend = class {
8310
8461
  ...await this.ownerParam(),
8311
8462
  Key: this.getStateKey(stackName, region)
8312
8463
  }));
8313
- if (await this.legacyMatchesRegion(stackName, region)) {
8464
+ const legacyProbe = await this.probeLegacyState(stackName);
8465
+ if (legacyProbe.kind === "unreadable") {
8466
+ const safeName = this.displayName(stackName);
8467
+ this.logger.warn(`Could not read the legacy state record for '${safeName}' while cleaning up (${legacyProbe.reason}). If one exists it was left in place. Re-run with --verbose for the details.`);
8468
+ }
8469
+ if (legacyProbeBelongsTo(legacyProbe, region)) {
8314
8470
  await this.s3Client.send(new DeleteObjectCommand({
8315
8471
  Bucket: this.config.bucket,
8316
8472
  ...await this.ownerParam(),
@@ -8330,6 +8486,48 @@ var S3StateBackend = class {
8330
8486
  }
8331
8487
  }
8332
8488
  /**
8489
+ * Delete a legacy state file that names no region (issue #2537).
8490
+ *
8491
+ * `deleteState` cannot serve this case: it takes a region, keys the primary
8492
+ * delete off it, and sweeps the legacy key only when that key's own `region`
8493
+ * field matches. A `version: 1` blob whose body carries no `region` at all
8494
+ * has nothing to match, so it falls through every branch there — which is
8495
+ * how `cdkd state orphan` came to report a removal it never performed.
8496
+ *
8497
+ * Unconditional, and deliberately so — but NOT because the caller's ref
8498
+ * proves the body names no region. `listStacks` derives that ref from
8499
+ * `readLegacyRegion`, which also returns undefined on a swallowed 403 / 503
8500
+ * / unparseable body, so a record that DOES name a region can surface
8501
+ * region-less. The delete is still right there: the caller
8502
+ * (`cdkd state orphan` with no `--stack-region`) means "every record for
8503
+ * this name", and this key is one of them. A caller that means something
8504
+ * narrower must not use this method.
8505
+ *
8506
+ * No rollback-journal sweep: journal keys exist only in the region-scoped
8507
+ * layout (see `getRollbackJournalKey`), so a region-less record can have
8508
+ * none.
8509
+ */
8510
+ async deleteLegacyState(stackName) {
8511
+ await this.ensureClientForBucket();
8512
+ const key = this.getLegacyStateKey(stackName);
8513
+ try {
8514
+ const safeStack = displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>";
8515
+ this.logger.debug(`Deleting legacy state: ${safeStack} (${displaySafe(key, { asciiOnly: true }) || "<unrenderable>"})`);
8516
+ await this.s3Client.send(new DeleteObjectCommand({
8517
+ Bucket: this.config.bucket,
8518
+ ...await this.ownerParam(),
8519
+ Key: key
8520
+ }));
8521
+ this.logger.debug(`Legacy state deleted: ${safeStack}`);
8522
+ } catch (error) {
8523
+ const normalized = normalizeAwsError(error, {
8524
+ bucket: this.config.bucket,
8525
+ operation: "DeleteObject"
8526
+ });
8527
+ throw new StateError(`Failed to delete legacy state for stack '${displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>"}': ${normalized.message}`, normalized);
8528
+ }
8529
+ }
8530
+ /**
8333
8531
  * List all stacks with state in the bucket.
8334
8532
  *
8335
8533
  * Returns one `{stackName, region}` pair per state file. Both layouts
@@ -8708,29 +8906,85 @@ var S3StateBackend = class {
8708
8906
  }
8709
8907
  }
8710
8908
  /**
8711
- * Read the legacy state's `region` field. Used for region matching during
8712
- * `stateExists` / `deleteState` and for assigning a region to legacy
8713
- * entries during `listStacks`.
8909
+ * Read the legacy key and classify what is there {@link LegacyStateProbe}
8910
+ * says what each answer means and which consumer acts on it.
8714
8911
  */
8715
- async readLegacyRegion(stackName) {
8912
+ /**
8913
+ * A stack name safe to put in a log line. Names reach this class from S3
8914
+ * key segments, which anyone able to write the bucket controls, so every
8915
+ * message that renders one goes through here (issue #2170's class).
8916
+ */
8917
+ displayName(stackName) {
8918
+ return displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>";
8919
+ }
8920
+ async probeLegacyState(stackName) {
8716
8921
  try {
8717
8922
  const response = await this.s3Client.send(new GetObjectCommand({
8718
8923
  Bucket: this.config.bucket,
8719
8924
  ...await this.ownerParam(),
8720
8925
  Key: this.getLegacyStateKey(stackName)
8721
8926
  }));
8722
- if (!response.Body) return void 0;
8927
+ if (!response.Body) {
8928
+ this.logger.debug(`Legacy state probe for '${this.displayName(stackName)}': response carried no body`);
8929
+ return {
8930
+ kind: "unreadable",
8931
+ reason: "the response carried no body"
8932
+ };
8933
+ }
8723
8934
  const bodyString = await response.Body.transformToString();
8724
- const state = JSON.parse(bodyString);
8725
- return typeof state.region === "string" ? state.region : void 0;
8935
+ const raw = JSON.parse(bodyString).region;
8936
+ if (!raw) return { kind: "no-region" };
8937
+ if (typeof raw !== "string") {
8938
+ this.logger.debug(`Legacy state probe for '${this.displayName(stackName)}': 'region' is ${typeof raw}, not a string`);
8939
+ return {
8940
+ kind: "unreadable",
8941
+ reason: `its 'region' field is ${typeof raw}, not a string`
8942
+ };
8943
+ }
8944
+ return {
8945
+ kind: "region",
8946
+ region: raw
8947
+ };
8726
8948
  } catch (error) {
8727
- if (isNoSuchKey(error)) return void 0;
8728
- this.logger.debug(`Could not read legacy state region for '${stackName}': ${error instanceof Error ? error.message : String(error)}`);
8729
- return;
8949
+ if (isNoSuchKey(error)) return { kind: "absent" };
8950
+ const { detail } = describeAwsFailure(error);
8951
+ this.logger.debug(`Could not read legacy state region for '${this.displayName(stackName)}': ${displaySafe(detail, { asciiOnly: true }) || "<unrenderable>"}`);
8952
+ return {
8953
+ kind: "unreadable",
8954
+ reason: displaySafe(error instanceof Error && error.name ? error.name : "an unknown error", { asciiOnly: true }) || "<unrenderable>"
8955
+ };
8730
8956
  }
8731
8957
  }
8732
- async legacyMatchesRegion(stackName, region) {
8733
- return await this.readLegacyRegion(stackName) === region;
8958
+ /**
8959
+ * The region a legacy record should be listed under, or `undefined` when it
8960
+ * names none / could not be read. Preserves `listStacks`'s behaviour across
8961
+ * the {@link probeLegacyState} split.
8962
+ */
8963
+ async readLegacyRegion(stackName) {
8964
+ const probe = await this.probeLegacyState(stackName);
8965
+ return probe.kind === "region" ? probe.region : void 0;
8966
+ }
8967
+ /**
8968
+ * Whether an operation targeting `region` owns the legacy record — the
8969
+ * DELETE-side counterpart of `tryGetLegacy`'s read gate, and issue #2550.
8970
+ *
8971
+ * The two must agree. `tryGetLegacy` accepts a body that names NO region
8972
+ * from any region (`if (state.region && state.region !== region)` is false
8973
+ * when the field is absent), so `cdkd destroy` reads such a record, deletes
8974
+ * the AWS resources, and finishes. The old equality test here answered
8975
+ * `undefined === 'us-east-1'` — false — so the record survived a successful
8976
+ * destroy, kept appearing in `cdkd state list`, and the next deploy of that
8977
+ * name planned updates against resources that were gone.
8978
+ *
8979
+ * `unreadable` is deliberately NOT treated as `no-region`: a 403, a 503 or a
8980
+ * malformed body says nothing about who owns the record, and a read that
8981
+ * failed must never authorise a delete. It collapsed into the same
8982
+ * `undefined` as the other two before, which is why the one-line fix — make
8983
+ * `undefined` match — was wrong: it would also have made `stateExists`
8984
+ * report state for a stack that has none, since `absent` reads the same way.
8985
+ */
8986
+ async legacyBelongsToRegion(stackName, region) {
8987
+ return legacyProbeBelongsTo(await this.probeLegacyState(stackName), region);
8734
8988
  }
8735
8989
  /**
8736
8990
  * Try to read the legacy `version: 1` state. Returns null when the legacy
@@ -16367,7 +16621,7 @@ function normalizeAwsTagsToCfn(tags) {
16367
16621
  * through `update()` and surface as a hard AWS rejection, so we sanitize
16368
16622
  * the wire-layer payload while keeping the read-side placeholder
16369
16623
  * intact. This is the Class 2 pattern from
16370
- * `docs/provider-development.md § 3b`.
16624
+ * `docs/provider-rules.md#readcurrentstate-for-drift-detection`.
16371
16625
  */
16372
16626
  function sanitizeDescription(value) {
16373
16627
  if (value === void 0 || value === null) return void 0;
@@ -22124,7 +22378,7 @@ var CloudControlProvider = class {
22124
22378
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
22125
22379
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
22126
22380
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
22127
- const { ASGProvider } = await import("./asg-provider-BvIH9Ivw.js").then((n) => n.n);
22381
+ const { ASGProvider } = await import("./asg-provider-DoP-32eU.js").then((n) => n.n);
22128
22382
  return withIndeterminateGuard(await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
22129
22383
  }
22130
22384
  const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
@@ -23309,42 +23563,6 @@ function interruptWatchListenerCount() {
23309
23563
  return sharedSigintHandler === void 0 ? 0 : 1;
23310
23564
  }
23311
23565
 
23312
- //#endregion
23313
- //#region src/state/state-prefix.ts
23314
- /**
23315
- * The default S3 key prefix for cdkd state.
23316
- *
23317
- * Homed in the STATE layer rather than in `src/cli/commands/state-file-keys.ts`
23318
- * (which re-exports it, so its four existing importers are unchanged) because
23319
- * `src/state/lock-contention-message.ts` needs it to decide whether a recovery
23320
- * hint should spell `--state-prefix` at all, and a `src/state/**` module
23321
- * importing from `src/cli/commands/**` inverts the layering — the CLI sits
23322
- * ABOVE the state layer in the 7-layer architecture, not below it.
23323
- *
23324
- * Note this is only the DEFAULT. Other commands accept `--state-prefix`, so
23325
- * whole-bucket listings deliberately do not scope to it.
23326
- */
23327
- const DEFAULT_STATE_PREFIX = "cdkd";
23328
- /**
23329
- * The state-bucket prefix `CustomResourceProvider` PUTs its response
23330
- * placeholders under, one object per invocation
23331
- * (`custom-resource-responses/{requestId}.json`).
23332
- *
23333
- * Homed here for the same layering reason as {@link DEFAULT_STATE_PREFIX}: the
23334
- * PRODUCER is `src/provisioning/providers/custom-resource-provider.ts` and the
23335
- * COLLECTOR is `src/cli/commands/gc.ts`, so a copy in either would be a copy
23336
- * the other could drift from — and the two spellings would then disagree about
23337
- * which objects exist, which is the only way a sweeper can miss the family it
23338
- * was written for (issue #2052). `src/cli/commands/state-file-keys.ts`
23339
- * re-exports it so gc reads it alongside the other state-key constants.
23340
- *
23341
- * Note this is only the DEFAULT: `ProviderRegistry` can be configured with a
23342
- * different `responsePrefix`, so a sweep scoped to this value is a sweep of the
23343
- * default layout. gc has no access to a non-default one — nothing persists it —
23344
- * which is stated at the sweep's own call site rather than implied here.
23345
- */
23346
- const CUSTOM_RESOURCE_RESPONSE_PREFIX = "custom-resource-responses";
23347
-
23348
23566
  //#endregion
23349
23567
  //#region src/provisioning/masked-retry-logger.ts
23350
23568
  /**
@@ -27945,7 +28163,7 @@ function isCustomResource(resourceType) {
27945
28163
  * live value on removal. Route every optional mutable field of a
27946
28164
  * merge-semantics API through this helper, with `clearValue` set to the
27947
28165
  * property's CFn default or the SDK-documented clear sentinel — see
27948
- * docs/provider-development.md §2a for the per-field checklist.
28166
+ * docs/provider-rules.md#update-removal-semantics-clear-on-removal for the per-field checklist.
27949
28167
  *
27950
28168
  * Returns `newValue` when present, the `clearValue` when the field was
27951
28169
  * present before and is now absent (removal), and `undefined` when it was
@@ -28962,9 +29180,16 @@ function formatResourceLine(op, logicalId, resourceType, verbOverride) {
28962
29180
  *
28963
29181
  * To avoid an accidental data-loss footgun, cdkd refuses to recreate
28964
29182
  * any resource whose type is in {@link STATEFUL_TYPES} unless the user
28965
- * ALSO passes `--force-stateful-recreation`. The two-flag protection
28966
- * mirrors `--remove-protection`'s pattern (see
28967
- * `src/cli/commands/destroy-runner.ts`).
29183
+ * ALSO passes `--force-stateful-recreation`. On the `--recreate-via-*`
29184
+ * and `--replace` opt-ins that is a two-flag protection, mirroring
29185
+ * `--remove-protection`'s pattern (see
29186
+ * `src/cli/commands/destroy-runner.ts`). It is NOT only that shape any
29187
+ * more: the guard also runs on replacement paths a plain `cdkd deploy`
29188
+ * reaches with no flag at all (a property-driven replacement, and the
29189
+ * update-failure fallback's Cloud Control trigger — issue [#2514]),
29190
+ * where `--force-stateful-recreation` is the ONLY flag involved. See
29191
+ * {@link isStatefulRecreateTargetForReplace} for the mid-deploy variant
29192
+ * those paths use.
28968
29193
  *
28969
29194
  * The list is hand-curated and intentionally **conservative**: every
28970
29195
  * type here carries user data that the AWS service does NOT
@@ -28972,18 +29197,78 @@ function formatResourceLine(op, logicalId, resourceType, verbOverride) {
28972
29197
  * AWS service treats as ephemeral (e.g. Lambda Function, IAM Role)
28973
29198
  * are NOT in this list — recreate is cheap.
28974
29199
  *
28975
- * Two entries are **conditionally stateful** they only count when
28976
- * the resource actually contains data:
29200
+ * Two entries carry a CONDITION instead of counting unconditionally.
29201
+ * The condition is what the guard evaluates; failing it is not a
29202
+ * finding that the resource holds no data (see the LogGroup note):
28977
29203
  *
28978
29204
  * - `AWS::S3::Bucket`: empty buckets are safe to recreate. The
28979
- * deploy engine probes `s3:ListObjectsV2` at plan time and only
29205
+ * deploy engine probes `s3:ListObjectVersions` at plan time and only
28980
29206
  * refuses when the bucket has at least one object.
28981
- * - `AWS::Logs::LogGroup`: a log group with `RetentionInDays`
28982
- * undefined or zero is functionally ephemeral. The deploy engine
28983
- * refuses only when `RetentionInDays > 0`.
29207
+ * - `AWS::Logs::LogGroup`: the deploy engine refuses only when
29208
+ * `RetentionInDays > 0`. NOTE this is a KNOWN GAP, not a statement
29209
+ * that the rest are empty: an unset or zero retention is CloudWatch
29210
+ * Logs' "never expire", the most data-bearing setting there is, and
29211
+ * `LogsLogGroupProvider` writes `0` for precisely that. Issue
29212
+ * [#2558] tracks it; the predicate is left as-is here.
28984
29213
  *
28985
29214
  * Both conditional checks live in {@link isStatefulRecreateTarget};
28986
29215
  * the bare {@link STATEFUL_TYPES} set is the type-only first-cut.
29216
+ *
29217
+ * **Lower bound, enforced by a test** (issue [#2514]'s review round):
29218
+ * every type in `final-snapshot.ts`'s `ATOMIC_FINAL_SNAPSHOT_TYPES` ∪
29219
+ * `PRE_DELETE_SNAPSHOT_TYPES` must appear here. That union is the
29220
+ * CloudFormation-documented `DeletionPolicy: Snapshot`-capable list, and
29221
+ * CloudFormation permits the attribute exactly where deleting the resource
29222
+ * destroys data worth capturing first — so membership there is an
29223
+ * AWS-authored statement that the type is data-bearing. The types that were
29224
+ * in that union and NOT here (`AWS::Redshift::Cluster`,
29225
+ * `AWS::ElastiCache::ReplicationGroup`, `AWS::ElastiCache::CacheCluster`)
29226
+ * meant cdkd took a final snapshot before a `cdkd destroy` of them
29227
+ * while replacing them mid-deploy with no consent flag at all.
29228
+ * `tests/unit/provisioning/stateful-types.test.ts` pins the subset
29229
+ * relation so a future addition to either snapshot set cannot land without
29230
+ * the guard entry.
29231
+ *
29232
+ * The relation is deliberately ONE-directional: most data-bearing types
29233
+ * (S3, DynamoDB, LogGroup, ECR, …) have no snapshot API at all and
29234
+ * CloudFormation rejects `DeletionPolicy: Snapshot` on them, so this set is
29235
+ * a strict superset and the reverse containment would be wrong.
29236
+ *
29237
+ * **Second lower bound, also enforced by a test**: every resource type
29238
+ * registered to a provider whose `delete()` consults
29239
+ * `DeleteContext.forceDataDelete` must appear here. That field is set ONLY
29240
+ * by the replacement / recreate delete sites under
29241
+ * `--force-stateful-recreation`, so a provider reading it has already
29242
+ * declared its delete destroys user data — which makes the guard list's
29243
+ * agreement checkable rather than hand-curated.
29244
+ * `AWS::S3Express::DirectoryBucket` was the one type on the wrong side.
29245
+ *
29246
+ * **Third bound, and the first that reads the population the other two are
29247
+ * blind to** (issue [#2553]): both bounds above are derived from
29248
+ * `src/provisioning/providers/**` and `register-providers.ts`, so both can
29249
+ * only see types cdkd has an SDK PROVIDER for — 134 of them, against the
29250
+ * 1371 tier-2 types that have none and whose replacement routes through
29251
+ * Cloud Control's DELETE. That is the population issue [#2514] was filed
29252
+ * about, and until now it had never been swept.
29253
+ * `scripts/audit-stateful-candidates.ts` reads every tier-2 type's
29254
+ * CloudFormation registry schema and PROPOSES the ones that declare a
29255
+ * createOnly property (so a rename is a replacement a plain `cdkd deploy`
29256
+ * reaches with no flag) AND fire a data-bearing signal. Each proposal must
29257
+ * end up either on this list or in that script's `NOT_GUARDED` map with a
29258
+ * reason; `tests/unit/scripts/stateful-candidates.test.ts` fails on any that
29259
+ * is in neither, and on a `NOT_GUARDED` entry the derivation has stopped
29260
+ * proposing. Unlike the two bounds above the signals are HEURISTIC — no AWS
29261
+ * artifact states "deleting this destroys user data" — so this bound makes
29262
+ * the widening CHECKABLE rather than proven, which is the property a hand
29263
+ * pass over 1371 types could not have.
29264
+ *
29265
+ * Neither fence can see a provider whose delete destroys data with NO opt-in
29266
+ * at all — an unconditional empty (`S3TablesProvider.deleteTableBucket`,
29267
+ * `S3VectorsProvider.deleteVectorBucket`) or a plainly destructive API call
29268
+ * (`KMSProvider`'s `ScheduleKeyDeletion`,
29269
+ * `CodeCommitRepositoryProvider`'s `DeleteRepository`). Those types are
29270
+ * hand-added with the reason at the entry, and a provider added that way
29271
+ * should be reviewed for whether it wants a `forceDataDelete` gate too.
28987
29272
  */
28988
29273
  const STATEFUL_TYPES = /* @__PURE__ */ new Set([
28989
29274
  "AWS::RDS::DBInstance",
@@ -28994,21 +29279,96 @@ const STATEFUL_TYPES = /* @__PURE__ */ new Set([
28994
29279
  "AWS::Neptune::DBCluster",
28995
29280
  "AWS::DynamoDB::Table",
28996
29281
  "AWS::DynamoDB::GlobalTable",
29282
+ "AWS::Redshift::Cluster",
29283
+ "AWS::ElastiCache::CacheCluster",
29284
+ "AWS::ElastiCache::ReplicationGroup",
28997
29285
  "AWS::EFS::FileSystem",
28998
29286
  "AWS::FSx::FileSystem",
28999
29287
  "AWS::S3::Bucket",
29288
+ "AWS::S3Express::DirectoryBucket",
29289
+ "AWS::S3Tables::TableBucket",
29290
+ "AWS::S3Tables::Table",
29291
+ "AWS::S3Tables::Namespace",
29292
+ "AWS::S3Vectors::VectorBucket",
29000
29293
  "AWS::ECR::Repository",
29001
29294
  "AWS::EC2::Volume",
29295
+ "AWS::EMR::Cluster",
29002
29296
  "AWS::Kinesis::Stream",
29003
29297
  "AWS::Elasticsearch::Domain",
29004
29298
  "AWS::OpenSearchService::Domain",
29005
29299
  "AWS::Cognito::UserPool",
29006
29300
  "AWS::SecretsManager::Secret",
29007
29301
  "AWS::SSM::Parameter",
29302
+ "AWS::KMS::Key",
29303
+ "AWS::KMS::ReplicaKey",
29304
+ "AWS::CodeCommit::Repository",
29008
29305
  "AWS::Glue::Database",
29009
29306
  "AWS::Glue::Table",
29010
29307
  "AWS::Logs::LogGroup",
29011
- "AWS::CloudFront::Distribution"
29308
+ "AWS::CloudFront::Distribution",
29309
+ "AWS::Cassandra::Table",
29310
+ "AWS::DocDBElastic::Cluster",
29311
+ "AWS::Lightsail::Database",
29312
+ "AWS::Timestream::Database",
29313
+ "AWS::Timestream::Table",
29314
+ "AWS::Timestream::InfluxDBCluster",
29315
+ "AWS::Timestream::InfluxDBInstance",
29316
+ "AWS::ODB::CloudAutonomousVmCluster",
29317
+ "AWS::ODB::CloudVmCluster",
29318
+ "AWS::RedshiftServerless::Namespace",
29319
+ "AWS::RedshiftServerless::Snapshot",
29320
+ "AWS::NeptuneGraph::Graph",
29321
+ "AWS::NeptuneGraph::GraphSnapshot",
29322
+ "AWS::MemoryDB::Cluster",
29323
+ "AWS::MemoryDB::MultiRegionCluster",
29324
+ "AWS::ElastiCache::ServerlessCache",
29325
+ "AWS::MSK::Cluster",
29326
+ "AWS::MSK::ServerlessCluster",
29327
+ "AWS::MSK::Channel",
29328
+ "AWS::AmazonMQ::Broker",
29329
+ "AWS::OSIS::Pipeline",
29330
+ "AWS::KinesisVideo::Stream",
29331
+ "AWS::Events::Archive",
29332
+ "AWS::OpenSearchServerless::Collection",
29333
+ "AWS::OpenSearchServerless::Index",
29334
+ "AWS::OpenSearchServerless::CollectionIndex",
29335
+ "AWS::Kendra::Index",
29336
+ "AWS::QBusiness::Index",
29337
+ "AWS::QBusiness::Application",
29338
+ "AWS::Rekognition::Collection",
29339
+ "AWS::Location::GeofenceCollection",
29340
+ "AWS::S3Vectors::Index",
29341
+ "AWS::Bedrock::KnowledgeBase",
29342
+ "AWS::Bedrock::DataAutomationLibrary",
29343
+ "AWS::Lightsail::Bucket",
29344
+ "AWS::S3Outposts::Bucket",
29345
+ "AWS::HealthImaging::Datastore",
29346
+ "AWS::HealthLake::FHIRDatastore",
29347
+ "AWS::SES::MailManagerArchive",
29348
+ "AWS::WorkspacesInstances::Volume",
29349
+ "AWS::IoTAnalytics::Channel",
29350
+ "AWS::IoTAnalytics::Datastore",
29351
+ "AWS::IoTAnalytics::Dataset",
29352
+ "AWS::CodeArtifact::Domain",
29353
+ "AWS::CodeArtifact::Repository",
29354
+ "AWS::ECR::PublicRepository",
29355
+ "AWS::Backup::BackupVault",
29356
+ "AWS::Backup::LogicallyAirGappedBackupVault",
29357
+ "AWS::EKS::Cluster",
29358
+ "AWS::SageMaker::Cluster",
29359
+ "AWS::SageMaker::Domain",
29360
+ "AWS::Cases::Domain",
29361
+ "AWS::CustomerProfiles::Domain",
29362
+ "AWS::DataZone::Domain",
29363
+ "AWS::CleanRooms::IdMappingTable",
29364
+ "AWS::CleanRooms::IntermediateTable",
29365
+ "AWS::CloudFront::KeyValueStore",
29366
+ "AWS::Connect::DataTable",
29367
+ "AWS::AppConfig::ConfigurationProfile",
29368
+ "AWS::AIOps::InvestigationGroup",
29369
+ "AWS::Rbin::Rule",
29370
+ "AWS::SMSVOICE::PhoneNumber",
29371
+ "AWS::SMSVOICE::SenderId"
29012
29372
  ]);
29013
29373
  /**
29014
29374
  * Multi-region resource types — `--recreate-via-cc-api` refuses these
@@ -29025,7 +29385,7 @@ const STATEFUL_TYPES = /* @__PURE__ */ new Set([
29025
29385
  const MULTI_REGION_RECREATE_BLOCKED_TYPES = /* @__PURE__ */ new Set(["AWS::DynamoDB::GlobalTable"]);
29026
29386
  /**
29027
29387
  * Cheap, synchronous read of the resource's recorded properties only.
29028
- * For `AWS::S3::Bucket` this returns `null` — the live `ListObjectsV2`
29388
+ * For `AWS::S3::Bucket` this returns `null` — the live `ListObjectVersions`
29029
29389
  * probe to distinguish empty buckets (safe to recreate) from
29030
29390
  * non-empty (data loss) lives in
29031
29391
  * `src/deployment/recreate-targets.ts#probeStatefulRecreateTargetsAsync`
@@ -29048,17 +29408,26 @@ function isStatefulRecreateTargetSync(resourceType, recordedProperties) {
29048
29408
  return "always";
29049
29409
  }
29050
29410
  /**
29051
- * Conservative variant for the `cdkd deploy --replace` mid-deploy guard.
29411
+ * Conservative variant for the deploy engine's mid-deploy guard sites, which
29412
+ * between them serve the paths below — only one of which is reached by a flag:
29413
+ *
29414
+ * - property-driven replacement (an immutable / createOnly property changed
29415
+ * in the template) — fires on a plain `cdkd deploy`, no flag;
29416
+ * - the update-failure fallback's Cloud Control trigger (an
29417
+ * `UnsupportedActionException` / "does not support UPDATE" rejection) —
29418
+ * also no flag (issue [#2514]);
29419
+ * - the same fallback's `--replace` trigger (an SDK provider's typed
29420
+ * `ResourceUpdateNotSupportedError`).
29052
29421
  *
29053
- * `--replace` catches a provider's immutable-update rejection while the deploy
29054
- * is already in flight, so — unlike the `--recreate-via-*` pre-flight, which
29422
+ * All of them catch the rejection or classify the diff while the deploy is
29423
+ * already in flight, so — unlike the `--recreate-via-*` pre-flight, which
29055
29424
  * runs {@link probeStatefulRecreateTargetsAsync} (`s3:ListObjectVersions`) —
29056
29425
  * there is no opportunity to probe an `AWS::S3::Bucket`'s object count. The
29057
29426
  * sync check returns `null` for S3 (it defers to that async probe), which would
29058
29427
  * let a NON-EMPTY bucket be DELETE + CREATEd (data loss) without
29059
29428
  * `--force-stateful-recreation`. To stay fail-safe, treat a deferred S3 bucket
29060
29429
  * as stateful here: the user must pass `--force-stateful-recreation` to replace
29061
- * ANY S3 bucket via `--replace`, empty or not. Every other type matches
29430
+ * ANY S3 bucket on any of those paths, empty or not. Every other type matches
29062
29431
  * {@link isStatefulRecreateTargetSync} exactly (the LogGroup retention check is
29063
29432
  * fully resolvable from recorded properties, so no conservatism is needed there).
29064
29433
  */
@@ -31039,7 +31408,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
31039
31408
  refuseMaskedReplayBaseline(resolvedPrevProps, op.logicalId);
31040
31409
  recordNestedStackParameterExpressions(secrets, op.resourceType, resolvedPrevProps, prev.properties, STATE_DERIVED_RULES);
31041
31410
  logger.info(` Rollback: Reversing replacement of ${op.logicalId} (${op.resourceType}) — re-creating the old resource and deleting the new one`);
31042
- if (STATEFUL_TYPES.has(op.resourceType)) logger.warn(` ⚠ ${op.logicalId} (${op.resourceType}) is a stateful type — the old physical resource's data was destroyed by the replacement and CANNOT be recovered; the re-created resource starts empty.`);
31411
+ if (STATEFUL_TYPES.has(op.resourceType)) logger.warn(` ⚠ ${op.logicalId} (${op.resourceType}) is a stateful type — the old physical resource's data was destroyed by the replacement and is NOT recovered by this rollback; the re-created resource starts empty.`);
31043
31412
  const { provider: createProvider } = ctx.providerRegistry.getProviderFor({
31044
31413
  resourceType: op.resourceType,
31045
31414
  provisionedBy: prev.provisionedBy
@@ -33606,7 +33975,7 @@ var DeployEngine = class {
33606
33975
  const statefulReason = isStatefulRecreateTargetForReplace(resourceType, currentProps);
33607
33976
  if (statefulReason && this.options.forceStatefulRecreation !== true) {
33608
33977
  const immutableProps = change.propertyChanges?.filter((pc) => pc.requiresReplacement).map((pc) => pc.path).join(", ");
33609
- throw new CdkdError(`${logicalId} (${resourceType}) requires replacement (immutable property changed: ${immutableProps}) but it is a stateful resource — ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.`, "STATEFUL_REPLACE_BLOCKED");
33978
+ throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement (immutable property changed: ${immutableProps}) but it is a stateful resource — ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.`, "STATEFUL_REPLACE_BLOCKED"));
33610
33979
  }
33611
33980
  }
33612
33981
  let replacementReason;
@@ -33749,9 +34118,10 @@ var DeployEngine = class {
33749
34118
  const ccUnsupported = msg.includes("UnsupportedActionException") || msg.includes("does not support UPDATE");
33750
34119
  const replaceOptIn = updateError instanceof ResourceUpdateNotSupportedError && this.options.replace === true;
33751
34120
  if (ccUnsupported || replaceOptIn) {
33752
- if (replaceOptIn) {
33753
- const statefulReason = isStatefulRecreateTargetForReplace(resourceType, currentProps);
33754
- if (statefulReason && this.options.forceStatefulRecreation !== true) throw new CdkdError(`--replace would DELETE + CREATE the stateful resource ${logicalId} (${resourceType}) ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.`, "STATEFUL_REPLACE_BLOCKED");
34121
+ const statefulReason = isStatefulRecreateTargetForReplace(resourceType, currentProps);
34122
+ if (statefulReason && this.options.forceStatefulRecreation !== true) {
34123
+ const retainNote = updateReplacePolicy === "Retain" ? " Note: UpdateReplacePolicy: Retain does NOT protect this paththe replacement deletes the old resource regardless." : "";
34124
+ throw markNonRetryable(new CdkdError((replaceOptIn ? `--replace would DELETE + CREATE the stateful resource ${logicalId} (${resourceType}) — ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.` : `${logicalId} (${resourceType}) cannot be updated in place by the provisioning layer it routes through, so applying this change would DELETE + CREATE it — but it is a stateful resource: ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the update.`) + retainNote, "STATEFUL_REPLACE_BLOCKED", updateError instanceof Error ? updateError : void 0));
33755
34125
  }
33756
34126
  this.logger.info(`UPDATE not supported for ${logicalId} (${resourceType}), replacing (DELETE → CREATE)`);
33757
34127
  const fallbackFinalSnapshotId = await this.prepareFinalSnapshotForDelete(logicalId, resourceType, currentResource, template?.Resources?.[logicalId]?.UpdateReplacePolicy ?? currentResource.updateReplacePolicy);
@@ -34252,5 +34622,5 @@ var DeployEngine = class {
34252
34622
  };
34253
34623
 
34254
34624
  //#endregion
34255
- export { DEFAULT_STATE_PREFIX as $, resolveUseCdkBootstrapAssets as $n, retryClassificationText as $r, isSingleDynamicReferenceToken as $t, bold as A, validateAssetBucketName as An, LocalMigrateError as Ar, requireConfigObject as At, secretBearingStateKeyWarning as B, runDockerStreaming as Bn, StackTerminationProtectionError as Br, DiffCalculator as Bt, unsupportedFinalSnapshotError as C, BOOTSTRAP_MARKER_PREFIX as Cn, ConfigError as Cr, assertRegionMatch as Ct, isStatefulRecreateTargetSync as D, isCrossRegionRedirect as Dn, DynamicReferenceRegionAmbiguousError as Dr, readConfigString as Dt, MULTI_REGION_RECREATE_BLOCKED_TYPES as E, getBootstrapMarkerKey as En, DeployCancelledError as Er, configStringRefusal as Et, yellow as F, dockerSpawnEnvWithSensitive as Fn, PartialFailureError as Fr, s3BucketDomainName as Ft, clearOnUpdateRemoval as G, getDefaultStateBucketName as Gn, normalizeAwsError as Gr, TemplateParser as Gt, getCurrentResourceSecrets as H, getDockerImageBySourceHash as Hn, SynthesisError as Hr, describeTypeWithThrottleRetry as Ht, collectDeclaredOutputNames as I, formatDockerLoginError as In, ProvisioningError as Ir, s3BucketDualStackDomainName as It, findSilentDropProperties as J, resolveAutoAssetStorage as Jn, isRetryableTransientError as Jr, TEMPLATE_SOURCED_RULES as Jt, ProviderRegistry as K, getLegacyStateBucketName as Kn, withErrorHandling as Kr, STATE_SOURCED_CROSS_GENERATION_RULES as Kt, collectPublishedOutputNames as L, getDockerCmd as Ln, ResourceTimeoutError as Lr, s3BucketRegionalDomainName as Lt, gray as M, buildDenyExternalAccessPolicy as Mn, LockError as Mr, classifyReplaySecretRegion as Mt, green as N, describeAwsFailure as Nn, MissingCdkCliError as Nr, producerRegionsFromState as Nt, renderStatefulReason as O, parseBootstrapMarker as On, IntrinsicResolutionRefusalError as Or, replayWarn as Ot, red as P, buildDockerImage as Pn, NestedStackChildDirectDestroyError as Pr, s3BucketArn as Pt, CUSTOM_RESOURCE_RESPONSE_PREFIX as Q, resolveStateBucketWithDefaultAndSource as Qn, markRedactedCause as Qr, errorCauseChain as Qt, exportAliasCollisionScrubWarning as R, partitionSensitiveEnv as Rn, ResourceUpdateNotSupportedError as Rr, s3BucketWebsiteUrl as Rt, refusesFinalSnapshot as S, AssetModeResolver as Sn, CdkdError as Sr, resolveExplicitPhysicalId as St, extractDeploymentEventError as T, ensureAssetStorage as Tn, DependencyError as Tr, configBooleanRefusal as Tt, IAMRoleProvider as U, Synthesizer as Un, formatError as Ur, withRetry as Ut, stateKeySecretExposure as V, AssetManifestLoader as Vn, StateError as Vr, INTRINSIC_KEYS as Vt, collectInlinePolicyNamesManagedBySiblings as W, synthesisStatusMessage as Wn, isCdkdError as Wr, DagBuilder as Wt, maskDeep as X, resolveSkipPrefix as Xn, isTransientServerError as Xr, createSecretMasker as Xt, createMaskedRetryLogger as Y, resolveCaptureObservedState as Yn, isThrottlingError as Yr, carriesSecretMask as Yt, maskerOrIdentity as Z, resolveStateBucketWithDefault as Zn, markNonRetryable as Zr, dynamicReferenceTokens as Zt, PRE_DELETE_SNAPSHOT_TYPES as _, createAssetRedirectResolver as _n, AwsClients as _r, isUnboundTemplateParameter as _t, DeploymentEventsStore as a, scrubResourceRecord as an, findLargeInlineResources as ar, CloudControlProvider as at, createPreDeleteFinalSnapshot as b, escapeRegExp$1 as bn, setAwsClients as br, WAFv2WebACLProvider as bt, replayFailedOperations as c, rebuildClientForBucketRegion as cn, displaySafe as cr, deleteIndeterminateGuards as ct, updatePartialReason as d, importableOutputs as dn, canonicalizeRegion as dr, isTerminationProtectionPropagationError as dt, __exportAll as ei, maskSecretsInError as en, stateBucketExistenceConfirmed as er, beginCommandInterruptScope as et, withResourceDeadline as f, shouldRetainResource as fn, derivePartitionAndUrlSuffix as fr, IntrinsicFunctionResolver as ft, ATOMIC_FINAL_SNAPSHOT_TYPES as g, buildAssetRedirectMap as gn, resolveBucketRegion as gr, getAccountInfo as gt, computeImplicitDeleteEdges as h, WorkGraph as hn, clearBucketRegionCache as hr, coerceParameterTypedValue as ht, DeploymentEventsReader as i, redactSecretsForState as in, MIGRATE_TMP_PREFIX as ir, startInterruptWatch as it, cyan as j, validateContainerRepoName as jn, LocalStartServiceError as jr, requireConfigString as jt, formatResourceLine as k, readBootstrapMarkerBody as kn, LocalInvokeBuildError as kr, requireConfigArray as kt, replayRollback as l, exportNamesCarriedFrom as ln, expectedOwnerParam as lr, deleteSkipReason as lt, IMPLICIT_DELETE_DEPENDENCIES as m, stringifyValue as mn, processStackMessages as mr, cfnRefValueFromPhysicalId as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, recordMaskOnlyValue as nn, CFN_TEMPLATE_BODY_LIMIT as nr, interruptWatchListenerCount as nt, planFailedOps as o, LockManager as on, uploadCfnTemplate as or, slowCcOperationTimeoutMs as ot, maskingRetryLogger as p, AssetPublisher as pn, AssemblyReader as pr, carriesDynamicReference as pt, findActionableSilentDrops as q, resolveApp as qn, isMarkedNonRetryable as qr, STATE_SOURCED_READBACK_RULES as qt, DeployEngine as r, recoverMaskedOutput as rn, CFN_TEMPLATE_URL_LIMIT as rr, isInterruptedWaitError as rt, planRollback as s, S3StateBackend as sn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as sr, UNSPECIFIED_SKIP_REASON as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, maskSecretsInText as tn, warnDeprecatedNoPrefixCliFlag as tr, endCommandInterruptScope as tt, updatePartialMessage as u, importableOutputKeys as un, PARTITION_TABLE as ur, disableInstanceApiTermination as ut, buildFinalSnapshotIdentifier as v, loadPublishableAssetManifest as vn, getAwsClients as vr, parameterTypeMayLoseSecretIdentity as vt, makeCanonicalizePropertiesFn as w, assertAssetBucketRegion as wn, CrossAccountSecretRefusalError as wr, coerceCfnBoolean as wt, isFinalSnapshotError as x, stripControlChars as xn, AssetError as xr, normalizeAwsTagsToCfn as xt, ccRoutedFinalSnapshotError as y, rewriteTemplateAssetReferences as yn, resetAwsClients as yr, refStateLookupFromResource as yt, isExportAliasCollision as z, runDockerForeground as zn, StackHasActiveImportsError as zr, applyRoleArnIfSet as zt };
34256
- //# sourceMappingURL=deploy-engine-CA50haPO.js.map
34625
+ export { endCommandInterruptScope as $, resolveCaptureObservedState as $n, isThrottlingError as $r, maskSecretsInText as $t, bold as A, getBootstrapMarkerKey as An, DeployCancelledError as Ar, classifyReplaySecretRegion as At, secretBearingStateKeyWarning as B, formatDockerLoginError as Bn, ProvisioningError as Br, describeTypeWithThrottleRetry as Bt, unsupportedFinalSnapshotError as C, rewriteTemplateAssetReferences as Cn, resetAwsClients as Cr, configBooleanRefusal as Ct, isStatefulRecreateTargetSync as D, BOOTSTRAP_MARKER_PREFIX as Dn, ConfigError as Dr, requireConfigArray as Dt, MULTI_REGION_RECREATE_BLOCKED_TYPES as E, AssetModeResolver as En, CdkdError as Er, replayWarn as Et, yellow as F, validateContainerRepoName as Fn, LocalStartServiceError as Fr, s3BucketRegionalDomainName as Ft, clearOnUpdateRemoval as G, AssetManifestLoader as Gn, StateError as Gr, STATE_SOURCED_READBACK_RULES as Gt, getCurrentResourceSecrets as H, partitionSensitiveEnv as Hn, ResourceUpdateNotSupportedError as Hr, DagBuilder as Ht, collectDeclaredOutputNames as I, buildDenyExternalAccessPolicy as In, LockError as Ir, s3BucketWebsiteUrl as It, findSilentDropProperties as J, synthesisStatusMessage as Jn, isCdkdError as Jr, createSecretMasker as Jt, ProviderRegistry as K, getDockerImageBySourceHash as Kn, SynthesisError as Kr, TEMPLATE_SOURCED_RULES as Kt, collectPublishedOutputNames as L, describeAwsFailure as Ln, MissingCdkCliError as Lr, applyRoleArnIfSet as Lt, gray as M, parseBootstrapMarker as Mn, IntrinsicResolutionRefusalError as Mr, s3BucketArn as Mt, green as N, readBootstrapMarkerBody as Nn, LocalInvokeBuildError as Nr, s3BucketDomainName as Nt, renderStatefulReason as O, assertAssetBucketRegion as On, CrossAccountSecretRefusalError as Or, requireConfigObject as Ot, red as P, validateAssetBucketName as Pn, LocalMigrateError as Pr, s3BucketDualStackDomainName as Pt, beginCommandInterruptScope as Q, resolveAutoAssetStorage as Qn, isRetryableTransientError as Qr, maskSecretsInError as Qt, exportAliasCollisionScrubWarning as R, buildDockerImage as Rn, NestedStackChildDirectDestroyError as Rr, DiffCalculator as Rt, refusesFinalSnapshot as S, loadPublishableAssetManifest as Sn, getAwsClients as Sr, coerceCfnBoolean as St, extractDeploymentEventError as T, stripControlChars as Tn, AssetError as Tr, readConfigString as Tt, IAMRoleProvider as U, runDockerForeground as Un, StackHasActiveImportsError as Ur, TemplateParser as Ut, stateKeySecretExposure as V, getDockerCmd as Vn, ResourceTimeoutError as Vr, withRetry as Vt, collectInlinePolicyNamesManagedBySiblings as W, runDockerStreaming as Wn, StackTerminationProtectionError as Wr, STATE_SOURCED_CROSS_GENERATION_RULES as Wt, maskDeep as X, getLegacyStateBucketName as Xn, withErrorHandling as Xr, errorCauseChain as Xt, createMaskedRetryLogger as Y, getDefaultStateBucketName as Yn, normalizeAwsError as Yr, dynamicReferenceTokens as Yt, maskerOrIdentity as Z, resolveApp as Zn, isMarkedNonRetryable as Zr, isSingleDynamicReferenceToken as Zt, PRE_DELETE_SNAPSHOT_TYPES as _, AssetPublisher as _n, AssemblyReader as _r, refStateLookupFromResource as _t, DeploymentEventsStore as a, S3StateBackend as an, warnDeprecatedNoPrefixCliFlag as ar, UNSPECIFIED_SKIP_REASON as at, createPreDeleteFinalSnapshot as b, buildAssetRedirectMap as bn, resolveBucketRegion as br, resolveExplicitPhysicalId as bt, replayFailedOperations as c, buildForceUnlockCommand as cn, MIGRATE_TMP_PREFIX as cr, disableInstanceApiTermination as ct, updatePartialReason as d, CUSTOM_RESOURCE_RESPONSE_PREFIX as dn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as dr, carriesDynamicReference as dt, isTransientServerError as ei, recordMaskOnlyValue as en, resolveSkipPrefix as er, interruptWatchListenerCount as et, withResourceDeadline as f, DEFAULT_STATE_PREFIX as fn, displaySafe as fr, cfnRefValueFromPhysicalId as ft, ATOMIC_FINAL_SNAPSHOT_TYPES as g, shouldRetainResource as gn, derivePartitionAndUrlSuffix as gr, parameterTypeMayLoseSecretIdentity as gt, computeImplicitDeleteEdges as h, importableOutputs as hn, canonicalizeRegion as hr, isUnboundTemplateParameter as ht, DeploymentEventsReader as i, __exportAll as ii, LockManager as in, stateBucketExistenceConfirmed as ir, slowCcOperationTimeoutMs as it, cyan as j, isCrossRegionRedirect as jn, DynamicReferenceRegionAmbiguousError as jr, producerRegionsFromState as jt, formatResourceLine as k, ensureAssetStorage as kn, DependencyError as kr, requireConfigString as kt, replayRollback as l, buildLockContentionMessage as ln, findLargeInlineResources as lr, isTerminationProtectionPropagationError as lt, IMPLICIT_DELETE_DEPENDENCIES as m, importableOutputKeys as mn, PARTITION_TABLE as mr, getAccountInfo as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, markRedactedCause as ni, redactSecretsForState as nn, resolveStateBucketWithDefaultAndSource as nr, startInterruptWatch as nt, planFailedOps as o, rebuildClientForBucketRegion as on, CFN_TEMPLATE_BODY_LIMIT as or, deleteIndeterminateGuards as ot, maskingRetryLogger as p, exportNamesCarriedFrom as pn, expectedOwnerParam as pr, coerceParameterTypedValue as pt, findActionableSilentDrops as q, Synthesizer as qn, formatError as qr, carriesSecretMask as qt, DeployEngine as r, retryClassificationText as ri, scrubResourceRecord as rn, resolveUseCdkBootstrapAssets as rr, CloudControlProvider as rt, planRollback as s, UNRENDERABLE as sn, CFN_TEMPLATE_URL_LIMIT as sr, deleteSkipReason as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, markNonRetryable as ti, recoverMaskedOutput as tn, resolveStateBucketWithDefault as tr, isInterruptedWaitError as tt, updatePartialMessage as u, forceQuitRecoveryClause as un, uploadCfnTemplate as ur, IntrinsicFunctionResolver as ut, buildFinalSnapshotIdentifier as v, stringifyValue as vn, processStackMessages as vr, WAFv2WebACLProvider as vt, makeCanonicalizePropertiesFn as w, escapeRegExp$1 as wn, setAwsClients as wr, configStringRefusal as wt, isFinalSnapshotError as x, createAssetRedirectResolver as xn, AwsClients as xr, assertRegionMatch as xt, ccRoutedFinalSnapshotError as y, WorkGraph as yn, clearBucketRegionCache as yr, normalizeAwsTagsToCfn as yt, isExportAliasCollision as z, dockerSpawnEnvWithSensitive as zn, PartialFailureError as zr, INTRINSIC_KEYS as zt };
34626
+ //# sourceMappingURL=deploy-engine-DuFUy9D0.js.map