@go-to-k/cdkd 0.284.52 → 0.284.53

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,5 +1,5 @@
1
1
  import { a as getLiveRenderer, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, l as applyDefaultNameForFallback, n as getLogger, p as looksLikeCdkdGeneratedName, u as generateResourceName } from "./logger-zRrlbaQt.js";
2
- import { t as getCdkdVersion } from "./version-BXmUXkY2.js";
2
+ import { t as getCdkdVersion } from "./version-CaIqvSUG.js";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
5
5
  import { CloudControlClient, CreateResourceCommand, DeleteResourceCommand, GetResourceCommand, GetResourceRequestStatusCommand, ListResourcesCommand, UpdateResourceCommand } from "@aws-sdk/client-cloudcontrol";
@@ -110,11 +110,17 @@ const IAM_PROPAGATION_ERROR_MESSAGE_PATTERNS = [
110
110
  "is not a valid role to allow SNS"
111
111
  ];
112
112
  /**
113
- * The NON-IAM-propagation half of {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}:
114
- * transient failures whose recovery window is either long (SQS's 60s same-name
115
- * cooldown, a resource still leaving a Pending/Creating state) or genuinely
116
- * load-related (throttling), where hammering AWS with dense retries is harmful
117
- * and exponential backoff is the correct shape.
113
+ * The NON-IAM-propagation, NON-name-cooldown third of
114
+ * {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}: transient failures whose recovery
115
+ * window is either long (a resource still leaving a Pending/Creating state) or
116
+ * genuinely load-related (throttling), where hammering AWS with dense retries
117
+ * is harmful and exponential backoff is the correct shape.
118
+ *
119
+ * The name-cooldown spellings used to live here too (`wait 60 seconds`, S3's
120
+ * `conflicting conditional operation`); they moved to
121
+ * {@link NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS} so the ordinary-create path and
122
+ * the delete-then-re-create sites read ONE list instead of two that drifted
123
+ * apart (issue [#2116](https://github.com/go-to-k/cdkd/issues/2116)).
118
124
  */
119
125
  const OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS = [
120
126
  "currently in the following state: Pending",
@@ -123,10 +129,8 @@ const OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS = [
123
129
  "DependencyViolation",
124
130
  "does not exist",
125
131
  "Schema is currently being altered",
126
- "conflicting conditional operation",
127
132
  "scheduled for deletion",
128
133
  "Could not deliver test message",
129
- "wait 60 seconds",
130
134
  "concurrent update operation",
131
135
  "because it is in use",
132
136
  "Rate exceeded",
@@ -135,15 +139,101 @@ const OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS = [
135
139
  "Unable to complete operation due to concurrent modification"
136
140
  ];
137
141
  /**
142
+ * The **name-cooldown** third of {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}:
143
+ * an AWS service that holds a resource's NAME (or other unique identifier)
144
+ * while an ASYNCHRONOUS delete of the previous holder is still in flight, so a
145
+ * create of the same name inside that window is refused with a
146
+ * service-specific message. The window always clears on its own — the delete
147
+ * that opened it is already running — which is what makes every entry here
148
+ * retryable rather than terminal, whichever call site hits it.
149
+ *
150
+ * Read by BOTH consumers, which is the whole point of the list existing
151
+ * (issue [#2116](https://github.com/go-to-k/cdkd/issues/2116)):
152
+ *
153
+ * - {@link isNameCooldownError}, and through it
154
+ * {@link isRecreateRetryableError}, the retry filter at the
155
+ * delete-then-re-create sites (the deploy engine's `--replace` delete-first
156
+ * fallback, the recreate-via-* path, the rollback executor's
157
+ * delete-new-first) — the sites where cdkd itself just deleted the name
158
+ * holder;
159
+ * - {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}, i.e. the ORDINARY create path,
160
+ * where a fresh `cdkd deploy` process has no idea a prior `cdkd destroy`
161
+ * deleted anything.
162
+ *
163
+ * The second consumer is the reachable one and was the measured failure in
164
+ * #2116: destroy-then-redeploy is a routine dev loop, CloudFormation absorbs
165
+ * the window and converges, and cdkd claims template compatibility with
166
+ * CloudFormation — so failing the whole deploy (26 resources created and
167
+ * rolled back, on the run that filed the issue) over a condition that clears
168
+ * in seconds is a parity defect. Before this list, the two consumers held
169
+ * DIFFERENT spellings of the same SQS error: the wire message
170
+ * (`wait 60 seconds`) was in the generic table so an ordinary create retried
171
+ * it, while the error CODE (`QueueDeletedRecently`) was not — so whether the
172
+ * identical AWS condition was survivable depended on which spelling the SDK
173
+ * happened to surface.
174
+ *
175
+ * Bounded, not unbounded: since #2116 the ordinary-create path rides
176
+ * `withRetry`'s NAME-COOLDOWN grid (8 retries, 2s/4s/8s then capped at 10s ≈
177
+ * 64s of sleep — `NAME_COOLDOWN_INITIAL_DELAY_MS` in `./retry.ts`), which is
178
+ * the same budget the re-create sites already carried. It is deliberately NOT
179
+ * the generic 47s schedule this path used to inherit: SQS's own sentence names
180
+ * a 60-second window, so 47s would not converge, it would merely fail 47s
181
+ * later. A name that is NOT in fact being
182
+ * released — a genuine, permanent collision — is a different signature
183
+ * ({@link isNameCollisionError}) and is deliberately NOT here, so it still
184
+ * fails fast into the actionable `--replace` refusal instead of burning a
185
+ * budget it cannot survive.
186
+ *
187
+ * **What must NOT go in this list.** Every entry below is specific to a delete
188
+ * that is ALREADY in flight and clears within a budget. Three candidates the
189
+ * sibling sweep turned up are recorded here as deliberate EXCLUSIONS rather
190
+ * than left unmentioned, because "absent" and "considered and rejected" are
191
+ * indistinguishable to the next person doing this sweep:
192
+ *
193
+ * - **ELBv2 `DuplicateLoadBalancerName`** and **DynamoDB's create-side
194
+ * `Table already exists: <name>`** — AWS raises both for a resource that
195
+ * merely EXISTS, just as readily as for a deleting one, so neither is
196
+ * distinguishable from a terminal collision. Promoting either would convert
197
+ * a fast, actionable `--replace` refusal into a full retry budget ending in
198
+ * the same failure. (DynamoDB's `Table is being deleted` IS distinguishable,
199
+ * but promoting THAT one re-multiplies the destroy-runner budget arithmetic
200
+ * `src/provisioning/dynamodb-index-busy-delete.ts` derives against the
201
+ * per-resource deadline — a different reason, so it is stated separately
202
+ * rather than folded in with the two above.)
203
+ * - **Secrets Manager `scheduled for deletion`** — the same one-sided shape as
204
+ * S3's entry (generic table only, invisible to
205
+ * {@link isRecreateRetryableError}), and the provider does delete with
206
+ * `ForceDeleteWithoutRecovery: true`, so it LOOKS like it belongs. It is
207
+ * excluded because that single message covers TWO conditions with wildly
208
+ * different windows: a force-deleted secret's name releasing in
209
+ * seconds-to-minutes, and a secret scheduled for deletion with a
210
+ * `RecoveryWindowInDays` of 7-30 DAYS, which no bounded budget can ride out
211
+ * and which a user reaches by deleting a secret outside cdkd. A budget that
212
+ * cannot converge on half its population is worse than failing fast, so the
213
+ * entry stays where it already was — in the generic table, retryable on an
214
+ * ordinary create and terminal at the re-create sites, unchanged by #2116.
215
+ */
216
+ const NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS = [
217
+ "QueueDeletedRecently",
218
+ "wait 60 seconds",
219
+ "StateMachineDeleting",
220
+ "State Machine is being deleted",
221
+ "conflicting conditional operation"
222
+ ];
223
+ /**
138
224
  * Patterns that mark an AWS error as a transient/retryable failure.
139
225
  * Each entry is a substring match against the error message; all of these
140
226
  * are situations where the same call typically succeeds after a short delay
141
227
  * because of eventual consistency or just-created-dependency propagation.
142
228
  *
143
- * Composed from the two halves above so retryability has ONE source of truth
229
+ * Composed from the three halves above so retryability has ONE source of truth
144
230
  * while `withRetry` can still pick a per-class backoff cadence.
145
231
  */
146
- const RETRYABLE_ERROR_MESSAGE_PATTERNS = [...IAM_PROPAGATION_ERROR_MESSAGE_PATTERNS, ...OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS];
232
+ const RETRYABLE_ERROR_MESSAGE_PATTERNS = [
233
+ ...IAM_PROPAGATION_ERROR_MESSAGE_PATTERNS,
234
+ ...OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS,
235
+ ...NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS
236
+ ];
147
237
  /**
148
238
  * HTTP status codes that always indicate a transient failure worth retrying.
149
239
  * 429 = Too Many Requests (throttle), 503 = Service Unavailable.
@@ -575,26 +665,31 @@ function isNameCollisionError(message) {
575
665
  return /(?<!\b(?:must|not|should|may|cannot)\s)already exists?\b/i.test(message) || message.includes("AlreadyExists");
576
666
  }
577
667
  /**
578
- * Match the SQS same-name re-creation cooldown: after `DeleteQueue`, creating
579
- * a queue with the SAME name inside ~60s fails with
580
- * `AWS.SimpleQueueService.QueueDeletedRecently` ("You must wait 60 seconds
581
- * after deleting a queue before you can create another with the same name").
582
- *
583
- * The generic transient table above already carries 'wait 60 seconds' for
584
- * plain CREATEs (rapid destroy → redeploy loops), but the delete-then-re-create
585
- * sites (the deploy engine's --replace delete-first fallback and the rollback
586
- * executor's reverse-replacement) override the retry filter with
587
- * {@link isNameCollisionError}, which this signature does NOT match — so a
588
- * replacement revert used to fail fast mid-flight with the resource absent
589
- * from both AWS and state (issue #1206). Those sites now OR this matcher into
590
- * their retry filter, with a schedule long enough to cover the 60s window.
668
+ * Match a same-name re-creation cooldown an AWS service still holding a
669
+ * resource's name while its asynchronous delete finishes. Every recognised
670
+ * spelling lives in {@link NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS}; add new ones
671
+ * THERE rather than here, so the ordinary-create path
672
+ * ({@link RETRYABLE_ERROR_MESSAGE_PATTERNS}, which composes that list) cannot
673
+ * drift out of step with the delete-then-re-create sites again. That drift is
674
+ * exactly what issue [#2116](https://github.com/go-to-k/cdkd/issues/2116)
675
+ * found: SQS's wire message was retryable on an ordinary create while its
676
+ * error code was not, and the Step Functions spelling was recognised by
677
+ * neither.
678
+ *
679
+ * The delete-then-re-create sites (the deploy engine's `--replace`
680
+ * delete-first fallback and the rollback executor's reverse-replacement)
681
+ * override the retry filter with {@link isNameCollisionError}, which these
682
+ * signatures do NOT match — so a replacement revert used to fail fast
683
+ * mid-flight with the resource absent from both AWS and state (issue #1206).
684
+ * Those sites OR this matcher into their retry filter, with a schedule long
685
+ * enough to cover the 60s SQS window.
591
686
  *
592
687
  * Kept separate from {@link isNameCollisionError} on purpose: a cooldown at a
593
688
  * create-first site must NOT be treated as a collision (deleting the new
594
689
  * resource would not release the cooldown on the old name).
595
690
  */
596
691
  function isNameCooldownError(message) {
597
- return message.includes("QueueDeletedRecently") || message.includes("wait 60 seconds");
692
+ return NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS.some((p) => message.includes(p));
598
693
  }
599
694
  /**
600
695
  * Retry filter for the delete-then-re-create sites: the old name holder was
@@ -989,8 +1084,10 @@ var PartialFailureError = class PartialFailureError extends CdkdError {
989
1084
  * is the whole point: the message interpolates the resource's LOGICAL ID,
990
1085
  * and the retry classifiers match by SUBSTRING, so a perfectly ordinary
991
1086
  * composite CDK id like `MyDependencyViolationSub` made
992
- * `isRetryableTransientError` return true (`DependencyViolation` is the only
993
- * whitespace-free entry in `RETRYABLE_ERROR_MESSAGE_PATTERNS`) and burned the
1087
+ * `isRetryableTransientError` return true (`DependencyViolation` was then the
1088
+ * only whitespace-free entry in `RETRYABLE_ERROR_MESSAGE_PATTERNS`; the
1089
+ * name-cooldown error CODES `QueueDeletedRecently` / `StateMachineDeleting`
1090
+ * joined it under issue #2116, so the hazard is wider, not narrower) and burned the
994
1091
  * full generic schedule — 8 retries, ~47s of pure sleep — on a path that was
995
1092
  * never going to succeed, before the fallback the error exists to trigger was
996
1093
  * even reached.
@@ -9760,6 +9857,68 @@ const IAM_PROPAGATION_MAX_DELAY_MS = 2e3;
9760
9857
  * generic one by more than 0.75s in the early band.
9761
9858
  */
9762
9859
  const IAM_PROPAGATION_MAX_RETRIES = 26;
9860
+ /**
9861
+ * Backoff for the NAME-COOLDOWN class on the DEFAULT schedule — an AWS service
9862
+ * still holding a resource's name while an asynchronous delete of the previous
9863
+ * holder finishes (`NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS` in
9864
+ * ./retryable-errors.ts). Issue
9865
+ * [#2116](https://github.com/go-to-k/cdkd/issues/2116).
9866
+ *
9867
+ * **Why this class does not inherit the generic schedule.** The generic one
9868
+ * sleeps 1+2+4+8+8+8+8+8 = 47s, and the longest window in this class NAMES its
9869
+ * own duration: SQS's own sentence is "You must wait 60 seconds after deleting
9870
+ * a queue before you can create another with the same name." A 47s budget
9871
+ * against a 60s window does not converge — it just fails 47s later, which is
9872
+ * strictly worse than failing at once. That mismatch was live for as long as
9873
+ * `wait 60 seconds` has been in the generic table.
9874
+ *
9875
+ * **Where the numbers come from — precedent, not a fresh guess.** They are the
9876
+ * delete-then-re-create sites' existing budget, chosen for this exact window
9877
+ * (`deploy-engine.ts`'s `--replace` fallback and `rollback-executor.ts`'s
9878
+ * reverse-replacement both pass `maxRetries: 8, initialDelayMs: 2_000,
9879
+ * maxDelayMs: 10_000`). Adopting it here makes the ordinary create path and
9880
+ * the re-create sites ride the SAME window with the SAME budget, which is the
9881
+ * property #2116 is about: whether a cooldown is survivable must not depend on
9882
+ * which call site met it.
9883
+ *
9884
+ * 2 + 4 + 8 + 10 x 5 = 64s over 8 retries
9885
+ *
9886
+ * Probe grid (seconds after the first failure): 2, 6, 14, 24, 34, 44, 54, 64 —
9887
+ * covering SQS's 60s and, with room to spare, the ~23s of `status: DELETING`
9888
+ * measured on an idle Step Functions state machine
9889
+ * (`tests/integration/custom-resource-provider`).
9890
+ *
9891
+ * **What it does NOT claim.** A window LONGER than 64s still fails, with the
9892
+ * same AWS message as before. This class converts "always fails" into "fails
9893
+ * only past a budget derived from the longest window AWS itself documents" —
9894
+ * and, unlike the generic schedule, a run that exhausts it now says so (see
9895
+ * the give-up summary in {@link withRetry}), so a too-short budget is
9896
+ * reportable rather than indistinguishable from having no retry at all.
9897
+ *
9898
+ * The retry COUNT is deliberately the generic 8 rather than a new ceiling, so
9899
+ * nothing about the loop's own exit condition moves. Same reason the dense IAM
9900
+ * grid needed its own count and this does not.
9901
+ *
9902
+ * **But "only the delay grid changes" understates the effect at the NESTED
9903
+ * sites, so state the compounding rather than implying there is none.** Three
9904
+ * call sites wrap a DEFAULT-schedule `withRetry` inside their own outer loop
9905
+ * (`deploy-engine.ts`'s two `--replace` / recreate sites and
9906
+ * `rollback-executor.ts`'s reverse-replacement). The inner loop is the one
9907
+ * this grid changes, and the outer one re-enters it per attempt, so the
9908
+ * product grows with it: total sleep on a cooldown at those sites measures
9909
+ * **487s -> 640s (8.1 -> 10.7 min)**. That is accepted, not overlooked -- it
9910
+ * stays inside the 30-minute per-resource `withResourceDeadline`, and the
9911
+ * alternative is an inner loop that cannot ride out the window it is nested
9912
+ * for. A reader auditing those budgets needs the number, which is why it is
9913
+ * here and not left to be re-derived.
9914
+ *
9915
+ * `dynamodb-index-busy-delete.ts` is unaffected and that was checked rather
9916
+ * than assumed: it passes all four knobs, so `defaultSchedule` is false and
9917
+ * this grid never applies to it -- its own deadline arithmetic stands.
9918
+ */
9919
+ const NAME_COOLDOWN_INITIAL_DELAY_MS = 2e3;
9920
+ /** Cap for the name-cooldown backoff. See {@link NAME_COOLDOWN_INITIAL_DELAY_MS}. */
9921
+ const NAME_COOLDOWN_MAX_DELAY_MS = 1e4;
9763
9922
  const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
9764
9923
  /**
9765
9924
  * Run `operation`, retrying transient failures with exponential backoff
@@ -9779,6 +9938,13 @@ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
9779
9938
  * re-create sites' ~64s budget covering SQS's 60s name cooldown) and gets it
9780
9939
  * verbatim.
9781
9940
  *
9941
+ * A THIRD class rides its own grid on the default schedule since issue
9942
+ * [#2116](https://github.com/go-to-k/cdkd/issues/2116): a NAME COOLDOWN (a
9943
+ * service still holding a name while an async delete finishes) gets
9944
+ * 2s/4s/8s then 10s to a 64s total, because the longest window in that class
9945
+ * NAMES its duration -- SQS says "wait 60 seconds" -- and the generic 47s
9946
+ * cannot ride out a 60s wait. See {@link NAME_COOLDOWN_INITIAL_DELAY_MS}.
9947
+ *
9782
9948
  * The class is re-evaluated per attempt, so a propagation retry that runs into
9783
9949
  * a throttle backs OFF exponentially for that attempt instead of hammering.
9784
9950
  *
@@ -9809,6 +9975,8 @@ async function withRetry(operation, logicalId, opts = {}) {
9809
9975
  let sawPropagation = false;
9810
9976
  let propagationRetries = 0;
9811
9977
  let propagationSleptMs = 0;
9978
+ let nameCooldownRetries = 0;
9979
+ let nameCooldownSleptMs = 0;
9812
9980
  let serverErrorRetries = 0;
9813
9981
  for (let attempt = 0; attempt <= attemptCeiling; attempt++) try {
9814
9982
  return await operation();
@@ -9819,12 +9987,15 @@ async function withRetry(operation, logicalId, opts = {}) {
9819
9987
  const retryable = opts.isRetryable ? opts.isRetryable(message, error) : isRetryableTransientError(error, message);
9820
9988
  const propagation = defaultSchedule && isIamPropagationError(message);
9821
9989
  if (propagation) sawPropagation = true;
9990
+ const nameCooldown = defaultSchedule && !propagation && isNameCooldownError(message);
9822
9991
  const attemptLimit = sawPropagation ? 26 : maxRetries;
9823
9992
  if (!retryable || attempt >= attemptLimit) {
9824
- if (propagationRetries > 0 || serverErrorRetries > 0) {
9993
+ if (propagationRetries > 0 || serverErrorRetries > 0 || nameCooldownRetries > 0) {
9825
9994
  const budgetExhausted = sawPropagation && attempt >= attemptLimit;
9995
+ const nameCooldownBudgetExhausted = nameCooldownRetries >= maxRetries && attempt >= attemptLimit;
9826
9996
  const spent = [];
9827
9997
  if (propagationRetries > 0) spent.push(`${propagationRetries} IAM-propagation ${propagationRetries === 1 ? "retry" : "retries"} over ${(propagationSleptMs / 1e3).toFixed(2)}s of propagation backoff${budgetExhausted ? " (the full propagation budget)" : ""}`);
9998
+ if (nameCooldownRetries > 0) spent.push(`${nameCooldownRetries} name-cooldown ${nameCooldownRetries === 1 ? "retry" : "retries"} over ${(nameCooldownSleptMs / 1e3).toFixed(2)}s waiting for the name to be released${nameCooldownBudgetExhausted ? " (the full name-cooldown budget)" : ""}`);
9828
9999
  if (serverErrorRetries > 0) spent.push(`${serverErrorRetries} transient server-error ${serverErrorRetries === 1 ? "retry" : "retries"} (HTTP 5xx)`);
9829
10000
  const summary = () => `${logicalId}: gave up after ${spent.join(" and ")} - ${message}` + formatRetryClassificationSignals(error);
9830
10001
  try {
@@ -9833,7 +10004,7 @@ async function withRetry(operation, logicalId, opts = {}) {
9833
10004
  }
9834
10005
  throw error;
9835
10006
  }
9836
- const delay = propagation ? Math.min(250 * Math.pow(2, attempt), IAM_PROPAGATION_MAX_DELAY_MS) : Math.min(initialDelayMs * Math.pow(2, attempt), maxDelayMs);
10007
+ const delay = propagation ? Math.min(250 * Math.pow(2, attempt), IAM_PROPAGATION_MAX_DELAY_MS) : nameCooldown ? Math.min(NAME_COOLDOWN_INITIAL_DELAY_MS * Math.pow(2, attempt), NAME_COOLDOWN_MAX_DELAY_MS) : Math.min(initialDelayMs * Math.pow(2, attempt), maxDelayMs);
9837
10008
  const backoffThroughThisAttemptMs = propagation ? propagationSleptMs + delay : propagationSleptMs;
9838
10009
  opts.logger?.debug(` ⏳ Retrying ${logicalId} in ${delay / 1e3}s (attempt ${attempt + 1}/${attemptLimit}${propagation ? `, ${(backoffThroughThisAttemptMs / 1e3).toFixed(2)}s backoff through this attempt` : ""}) - ${message}`);
9839
10010
  for (let waited = 0; waited < delay; waited += 1e3) {
@@ -9843,6 +10014,9 @@ async function withRetry(operation, logicalId, opts = {}) {
9843
10014
  if (propagation) {
9844
10015
  propagationRetries++;
9845
10016
  propagationSleptMs = backoffThroughThisAttemptMs;
10017
+ } else if (nameCooldown) {
10018
+ nameCooldownRetries++;
10019
+ nameCooldownSleptMs += delay;
9846
10020
  } else if (opts.isRetryable === void 0 && isTransientServerError(error)) serverErrorRetries++;
9847
10021
  }
9848
10022
  throw lastError;
@@ -16261,7 +16435,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
16261
16435
  * criterion `retryable-errors.ts` documents as insufficient: the classifiers
16262
16436
  * match by SUBSTRING, and `sourceClause` interpolates template-controlled
16263
16437
  * text, so a logical id like `MyDependencyViolationHandler` puts
16264
- * `DependencyViolation` (the table's only whitespace-free entry) into the
16438
+ * `DependencyViolation` (a whitespace-free entry in the table — the only
16439
+ * one until issue #2116 added the name-cooldown error codes) into the
16265
16440
  * message. Reachability is real even though resolution runs outside
16266
16441
  * `withRetry` on the flat path: `NestedStackProvider.create` runs a child
16267
16442
  * `DeployEngine.deploy()` and re-throws, and the parent wraps `create()` in
@@ -18276,7 +18451,7 @@ var CloudControlProvider = class {
18276
18451
  if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
18277
18452
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
18278
18453
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
18279
- const { ASGProvider } = await import("./asg-provider-DYnIz-Gy.js").then((n) => n.n);
18454
+ const { ASGProvider } = await import("./asg-provider-Ciurx_UV.js").then((n) => n.n);
18280
18455
  return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
18281
18456
  }
18282
18457
  const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
@@ -26075,7 +26250,8 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
26075
26250
  * hang the flag exists to prevent. Those providers retry internally.
26076
26251
  * - **Interrupt.** `replayRollback` polls interrupts only BETWEEN ops, so an
26077
26252
  * un-threaded `isInterrupted` leaves Ctrl-C dead for the length of the
26078
- * backoff schedule (~47s) per op.
26253
+ * backoff schedule per op — ~47s on the generic grid, or ~64s if the op
26254
+ * hits a name cooldown, which rides its own longer grid since issue #2116.
26079
26255
  *
26080
26256
  * Returns the provider's result so the caller can honour
26081
26257
  * `effectiveProperties` (issue #1644) — both revert arms used to write the
@@ -26381,8 +26557,13 @@ async function updateWithRollbackRetry(provider, args, logicalId, logger, isInte
26381
26557
  * on attempt 0 and it reaches the caller's catch on the FIRST outer attempt,
26382
26558
  * exactly as before. The SQS cooldown IS matched by the inner classifier (the
26383
26559
  * generic table carries `wait 60 seconds`), which is the same division of
26384
- * labour the deploy engine's named-replacement site documents: the inner retry
26385
- * absorbs most of the 60s window and the outer ~64s budget covers the tail.
26560
+ * labour the deploy engine's named-replacement site documents. Since issue
26561
+ * #2116 the inner retry rides the name-cooldown grid (≈64s) rather than the
26562
+ * generic ~47s one, so it covers the whole 60s window on its own instead of
26563
+ * absorbing most of it and leaving a tail for the outer loop; the outer loop
26564
+ * now earns its place by ALSO covering the late name release that the inner
26565
+ * default classifier rejects. The two compound — measured at 640s of total
26566
+ * sleep on a cooldown, inside the 30-minute per-resource deadline.
26386
26567
  */
26387
26568
  async function createWithRollbackRetry(provider, create, logicalId, logger, isInterrupted, secrets, outer) {
26388
26569
  if (provider.disableOuterRetry) return await create();
@@ -29616,4 +29797,4 @@ var DeployEngine = class {
29616
29797
 
29617
29798
  //#endregion
29618
29799
  export { startInterruptWatch as $, AwsClients as $n, shouldRetainResource as $t, renderStatefulReason as A, getLegacyStateBucketName as An, isThrottlingError as Ar, redactSecretsForState as At, exportAliasCollisionScrubWarning as B, CFN_TEMPLATE_BODY_LIMIT as Bn, DiffCalculator as Bt, isFinalSnapshotError as C, runDockerForeground as Cn, SynthesisError as Cr, TEMPLATE_SOURCED_RULES as Ct, extractDeploymentEventError as D, Synthesizer as Dn, withErrorHandling as Dr, isSingleDynamicReferenceToken as Dt, makeCanonicalizePropertiesFn as E, getDockerImageBySourceHash as En, normalizeAwsError as Er, errorCauseChain as Et, green as F, resolveStateBucketWithDefault as Fn, s3BucketDomainName as Ft, collectInlinePolicyNamesManagedBySiblings as G, expectedOwnerParam as Gn, TemplateParser as Gt, secretBearingStateKeyWarning as H, MIGRATE_TMP_PREFIX as Hn, describeTypeWithThrottleRetry as Ht, red as I, resolveStateBucketWithDefaultAndSource as In, s3BucketDualStackDomainName as It, findActionableSilentDrops as J, derivePartitionAndUrlSuffix as Jn, S3StateBackend as Jt, clearOnUpdateRemoval as K, PARTITION_TABLE as Kn, LockManager as Kt, yellow as L, resolveUseCdkBootstrapAssets as Ln, s3BucketRegionalDomainName as Lt, bold as M, resolveAutoAssetStorage as Mn, __exportAll as Mr, classifyReplaySecretRegion as Mt, cyan as N, resolveCaptureObservedState as Nn, producerRegionsFromState as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, synthesisStatusMessage as On, isMarkedNonRetryable as Or, maskSecretsInError as Ot, gray as P, resolveSkipPrefix as Pn, s3BucketArn as Pt, isInterruptedWaitError as Q, resolveBucketRegion as Qn, importableOutputs as Qt, collectDeclaredOutputNames as R, stateBucketExistenceConfirmed as Rn, s3BucketWebsiteUrl as Rt, createPreDeleteFinalSnapshot as S, partitionSensitiveEnv as Sn, StateError as Sr, STATE_SOURCED_READBACK_RULES as St, unsupportedFinalSnapshotError as T, AssetManifestLoader as Tn, isCdkdError as Tr, dynamicReferenceTokens as Tt, stateKeySecretExposure as U, findLargeInlineResources as Un, withRetry as Ut, isExportAliasCollision as V, CFN_TEMPLATE_URL_LIMIT as Vn, INTRINSIC_KEYS as Vt, IAMRoleProvider as W, uploadCfnTemplate as Wn, DagBuilder as Wt, beginCommandInterruptScope as X, processStackMessages as Xn, exportNamesCarriedFrom as Xt, findSilentDropProperties as Y, AssemblyReader as Yn, rebuildClientForBucketRegion as Yt, endCommandInterruptScope as Z, clearBucketRegionCache as Zn, importableOutputKeys as Zt, computeImplicitDeleteEdges as _, buildDenyExternalAccessPolicy as _n, ProvisioningError as _r, replayWarn as _t, DeploymentEventsStore as a, loadPublishableAssetManifest as an, ConfigError as ar, carriesDynamicReference as at, buildFinalSnapshotIdentifier as b, formatDockerLoginError as bn, StackHasActiveImportsError as br, requireConfigString as bt, replayFailedOperations as c, stripControlChars as cn, DeployCancelledError as cr, refStateLookupFromResource as ct, updatePartialReason as d, ensureAssetStorage as dn, LocalMigrateError as dr, resolveExplicitPhysicalId as dt, AssetPublisher as en, getAwsClients as er, CloudControlProvider as et, UNSPECIFIED_SKIP_REASON as f, getBootstrapMarkerKey as fn, LocalStartServiceError as fr, assertRegionMatch as ft, IMPLICIT_DELETE_DEPENDENCIES as g, validateContainerRepoName as gn, PartialFailureError as gr, readConfigString as gt, maskingRetryLogger as h, validateAssetBucketName as hn, NestedStackChildDirectDestroyError as hr, configStringRefusal as ht, DeploymentEventsReader as i, createAssetRedirectResolver as in, CdkdError as ir, IntrinsicFunctionResolver as it, formatResourceLine as j, resolveApp as jn, markNonRetryable as jr, scrubResourceRecord as jt, isStatefulRecreateTargetSync as k, getDefaultStateBucketName as kn, isRetryableTransientError as kr, maskSecretsInText as kt, replayRollback as l, AssetModeResolver as ln, DynamicReferenceRegionAmbiguousError as lr, WAFv2WebACLProvider as lt, withResourceDeadline as m, readBootstrapMarkerBody as mn, MissingCdkCliError as mr, configBooleanRefusal as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, WorkGraph as nn, setAwsClients as nr, disableInstanceApiTermination as nt, planFailedOps as o, rewriteTemplateAssetReferences as on, CrossAccountSecretRefusalError as or, cfnRefValueFromPhysicalId as ot, deleteSkipReason as p, parseBootstrapMarker as pn, LockError as pr, coerceCfnBoolean as pt, ProviderRegistry as q, canonicalizeRegion as qn, displaySafe as qt, DeployEngine as r, buildAssetRedirectMap as rn, AssetError as rr, isTerminationProtectionPropagationError as rt, planRollback as s, escapeRegExp$1 as sn, DependencyError as sr, getAccountInfo as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, stringifyValue as tn, resetAwsClients as tr, slowCcOperationTimeoutMs as tt, updatePartialMessage as u, BOOTSTRAP_MARKER_PREFIX as un, LocalInvokeBuildError as ur, normalizeAwsTagsToCfn as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, buildDockerImage as vn, ResourceTimeoutError as vr, requireConfigArray as vt, refusesFinalSnapshot as w, runDockerStreaming as wn, formatError as wr, createSecretMasker as wt, ccRoutedFinalSnapshotError as x, getDockerCmd as xn, StackTerminationProtectionError as xr, STATE_SOURCED_CROSS_GENERATION_RULES as xt, PRE_DELETE_SNAPSHOT_TYPES as y, dockerSpawnEnvWithSensitive as yn, ResourceUpdateNotSupportedError as yr, requireConfigObject as yt, collectPublishedOutputNames as z, warnDeprecatedNoPrefixCliFlag as zn, applyRoleArnIfSet as zt };
29619
- //# sourceMappingURL=deploy-engine-DxboGDr4.js.map
29800
+ //# sourceMappingURL=deploy-engine-DOP4V6eK.js.map