@go-to-k/cdkd 0.284.76 → 0.284.78

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 { d as generateResourceName, f as generateResourceNameWithFallback, g as withStackName, m as looksLikeCdkdGeneratedName, n as getLogger, o as getLiveRenderer, p as getCurrentStackName, u as applyDefaultNameForFallback } from "./logger-C9-E73FI.js";
2
- import { t as getCdkdVersion } from "./version-BMCefk9p.js";
2
+ import { t as getCdkdVersion } from "./version-GEIr41xq.js";
3
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -288,6 +288,83 @@ const THROTTLING_ERROR_NAMES = /* @__PURE__ */ new Set([
288
288
  */
289
289
  const NON_RETRYABLE_MARKER = Symbol.for("cdkd.nonRetryable");
290
290
  /**
291
+ * How far every `.cause` walk in this module reads.
292
+ *
293
+ * ONE constant rather than five literals, because the walks are only sound
294
+ * together: {@link isMarkedNonRetryable} is what stops a deliberate refusal
295
+ * being read as transient, so any walk that reads text FURTHER than the marker
296
+ * walk creates a band where a refusal is legible but its marker is not.
297
+ * {@link retryClassificationText} shipped at 10 against the marker's 5 for
298
+ * exactly that reason, and the chain shape that makes the band reachable is
299
+ * the one the code already cites -- a nested-stack failure grows one
300
+ * `ProvisioningError` per level.
301
+ */
302
+ const MAX_CAUSE_CHAIN_DEPTH = 5;
303
+ /**
304
+ * Stamped on an error whose own message deliberately WITHHOLDS text its
305
+ * `cause` carries (issue [#2302](https://github.com/go-to-k/cdkd/issues/2302)).
306
+ *
307
+ * Distinct from {@link NON_RETRYABLE_MARKER} and orthogonal to it: this one
308
+ * says nothing about whether the error should be retried, only that the
309
+ * message a classifier would normally read is INCOMPLETE.
310
+ */
311
+ const REDACTED_CAUSE_MARKER = Symbol.for("cdkd.redactedCause");
312
+ /**
313
+ * Declare that this error's message withholds text its `cause` carries, so the
314
+ * message-based retry classifiers must read the CHAIN instead
315
+ * (issue [#2302](https://github.com/go-to-k/cdkd/issues/2302)).
316
+ *
317
+ * cdkd's retry classifiers match by SUBSTRING over a message. That is sound
318
+ * only while a wrapper copies its cause's text, which every wrapper did until
319
+ * #2302 started reducing an AWS failure to its error CLASS -- S3 words its
320
+ * `AccessDenied` as `User: arn:aws:sts::<account>:assumed-role/<role>/<session>
321
+ * is not authorized to perform: ...`, and a THROWN message is captured into the
322
+ * persisted `deployments/{runId}.jsonl` store. Redacting it also removed the
323
+ * substrings the pattern table matches on: measured on `S3BucketProvider`,
324
+ * `not authorized to perform` (retryable, on the DENSE IAM-propagation cadence)
325
+ * and S3's `conflicting conditional operation` both went NON-retryable.
326
+ *
327
+ * Call it at every site that redacts, and only there. It is deliberately an
328
+ * opt-in stamp rather than an unconditional chain read -- see
329
+ * {@link retryClassificationText} for the measurement that forced that choice.
330
+ *
331
+ * Same non-extensible tolerance as {@link markNonRetryable}, for the same
332
+ * reason: callers use it inline around the error they are about to throw, so a
333
+ * `TypeError` here would replace the refusal with an unrelated crash. Losing
334
+ * the stamp degrades to reading the top-level message, i.e. the pre-#2302
335
+ * classification of a message that is now shorter -- worse, but not a crash.
336
+ */
337
+ function markRedactedCause(error) {
338
+ if (!Object.isExtensible(error)) return error;
339
+ Object.defineProperty(error, REDACTED_CAUSE_MARKER, {
340
+ value: true,
341
+ enumerable: false,
342
+ configurable: true,
343
+ writable: false
344
+ });
345
+ return error;
346
+ }
347
+ /**
348
+ * True when the error, or anything in its bounded `.cause` chain, was stamped
349
+ * by {@link markRedactedCause}.
350
+ *
351
+ * Walked rather than read off the top link, because the redacting error is
352
+ * itself wrapped further out: `deploy-engine.ts` re-wraps every provider
353
+ * failure, so by the time a classifier sees it the stamp is one or more links
354
+ * deep. Same {@link MAX_CAUSE_CHAIN_DEPTH} as the marker walk, which is what
355
+ * lets {@link retryClassificationText} claim the two agree.
356
+ */
357
+ function hasRedactedCause(error) {
358
+ let current = error;
359
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
360
+ if (typeof current === "object" || typeof current === "function") {
361
+ if (current[REDACTED_CAUSE_MARKER] === true) return true;
362
+ }
363
+ current = current.cause;
364
+ }
365
+ return false;
366
+ }
367
+ /**
291
368
  * Mark a cdkd-authored refusal as terminal and return it, for
292
369
  * `throw markNonRetryable(new ProvisioningError(...))`.
293
370
  *
@@ -354,7 +431,7 @@ function markNonRetryable(error) {
354
431
  */
355
432
  function isMarkedNonRetryable(error) {
356
433
  let current = error;
357
- for (let depth = 0; depth < 5 && current != null; depth++) {
434
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
358
435
  if (typeof current === "object" || typeof current === "function") {
359
436
  if (current[NON_RETRYABLE_MARKER] === true) return true;
360
437
  }
@@ -378,7 +455,7 @@ function isMarkedNonRetryable(error) {
378
455
  */
379
456
  function isThrottlingError(error) {
380
457
  let current = error;
381
- for (let depth = 0; depth < 5 && current != null; depth++) {
458
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
382
459
  const name = current.name;
383
460
  if (typeof name === "string" && THROTTLING_ERROR_NAMES.has(name)) return true;
384
461
  const status = current.$metadata?.httpStatusCode;
@@ -480,7 +557,7 @@ const TRANSIENT_SERVER_ERROR_STATUS_CODES = /* @__PURE__ */ new Set([
480
557
  */
481
558
  function isTransientServerError(error) {
482
559
  let current = error;
483
- for (let depth = 0; depth < 5 && current != null; depth++) {
560
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
484
561
  const status = current.$metadata?.httpStatusCode;
485
562
  if (status !== void 0 && TRANSIENT_SERVER_ERROR_STATUS_CODES.has(status)) return true;
486
563
  current = current.cause;
@@ -531,7 +608,7 @@ function describeRetryClassificationSignals(error) {
531
608
  let sawMetadata = false;
532
609
  let metadataName;
533
610
  let metadataRequestId;
534
- for (let depth = 0; depth < 5 && current != null; depth++) {
611
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
535
612
  const name = current.name;
536
613
  if (depth > 0 && typeof name === "string" && name !== "") deepestName = name;
537
614
  const metadata = current.$metadata;
@@ -599,6 +676,62 @@ function isRetryableTransientError(error, message) {
599
676
  return RETRYABLE_ERROR_MESSAGE_PATTERNS.some((p) => message.includes(p));
600
677
  }
601
678
  /**
679
+ * The text every MESSAGE-based retry classifier should read: this error's own
680
+ * message plus every message down its `cause` chain.
681
+ *
682
+ * Every classifier in this module that reads a message reads the TOP-LEVEL one,
683
+ * and that was sound only while cdkd's wrappers copied their cause's text
684
+ * verbatim -- which they did, everywhere, until issue
685
+ * [#2302](https://github.com/go-to-k/cdkd/issues/2302). A wrapper on a THROWN
686
+ * path may now deliberately WITHHOLD AWS's wording, because a thrown message is
687
+ * captured into the persisted `deployments/{runId}.jsonl` store and S3's
688
+ * `AccessDenied` names the caller's account, role and session. Measured on
689
+ * `S3BucketProvider.create` before this function existed: the wrap turned
690
+ * `not authorized to perform` (retryable, and on the DENSE IAM-propagation
691
+ * cadence) and `conflicting conditional operation` (retryable) into
692
+ * NON-retryable, i.e. the redaction silently removed a retry the deploy
693
+ * depended on.
694
+ *
695
+ * This is the missing THIRD walk rather than a new idea: {@link
696
+ * isMarkedNonRetryable} and {@link isThrottlingError} already walk the same
697
+ * chain, for the same stated reason (cdkd wraps SDK errors routinely).
698
+ *
699
+ * It cannot resurrect a cdkd refusal: every consumer checks
700
+ * {@link isMarkedNonRetryable} FIRST, that marker is itself chain-walked, and
701
+ * both walks are bounded by the SAME {@link MAX_CAUSE_CHAIN_DEPTH}.
702
+ *
703
+ * It is a NO-OP for every error that has not opted in via
704
+ * {@link markRedactedCause} -- which is every wrapper on `main` outside
705
+ * #2302's redacting sites. An earlier revision justified itself with a wider
706
+ * claim, that every wrapper on `main` COPIES its cause's message; that claim is
707
+ * false (`custom-resource-provider.ts`'s `describeWaiterFailure` already
708
+ * withholds the raw waiter payload, and it is not the only wrapper that does),
709
+ * and it does not need to be true. The opt-in stamp makes the no-op a property
710
+ * of the mechanism rather than of a survey.
711
+ *
712
+ * NEVER use the result as a LOG line or a thrown message: it is the union of
713
+ * exactly the text the redaction exists to withhold. `retry.ts` keeps the
714
+ * top-level message for its `warn` / `debug` output and uses this only to
715
+ * classify.
716
+ */
717
+ function retryClassificationText(error) {
718
+ const top = error instanceof Error ? error.message : String(error);
719
+ if (!hasRedactedCause(error)) return top;
720
+ const parts = [];
721
+ const seen = /* @__PURE__ */ new Set();
722
+ let current = error;
723
+ for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null && !seen.has(current); depth++) {
724
+ seen.add(current);
725
+ if (current instanceof Error) {
726
+ if (current.message) parts.push(current.message);
727
+ } else try {
728
+ parts.push(String(current));
729
+ } catch {}
730
+ current = current?.cause;
731
+ }
732
+ return parts.join("\n");
733
+ }
734
+ /**
602
735
  * True when the message is a just-created-IAM-entity propagation rejection
603
736
  * ({@link IAM_PROPAGATION_ERROR_MESSAGE_PATTERNS}).
604
737
  *
@@ -5756,6 +5889,50 @@ var DockerAssetPublisher = class {
5756
5889
  }
5757
5890
  };
5758
5891
 
5892
+ //#endregion
5893
+ //#region src/utils/aws-failure-text.ts
5894
+ /** Appended to a redacted summary so the withheld half is still reachable. */
5895
+ const VERBOSE_POINTER = "Re-run with --verbose for AWS's own message.";
5896
+ /**
5897
+ * Whether AWS wrote this failure's message.
5898
+ *
5899
+ * Keyed on the marker fields `@aws-sdk/*` errors carry through
5900
+ * `@smithy/smithy-client`'s `ServiceException` — `$metadata` on every
5901
+ * deserialized error, `$fault` on every modeled one, `$response` where a
5902
+ * middleware attached the raw response. Nothing under `src/` sets any of them,
5903
+ * so a match cannot be a cdkd-authored error.
5904
+ *
5905
+ * A transport-level failure (a socket timeout, a DNS error) can reach a caller
5906
+ * without `$metadata`, and that is the correct answer rather than a gap: those
5907
+ * messages are written by the HTTP layer and name a host, never a caller.
5908
+ */
5909
+ function isAwsAuthoredFailure(error) {
5910
+ const candidate = error;
5911
+ return candidate.$metadata !== void 0 || candidate.$fault !== void 0 || candidate.$response !== void 0;
5912
+ }
5913
+ /**
5914
+ * Describe a caught failure for a thrown message. See {@link AwsFailureText}.
5915
+ */
5916
+ function describeAwsFailure(error) {
5917
+ if (error instanceof Error) {
5918
+ if (!isAwsAuthoredFailure(error)) return {
5919
+ summary: error.message,
5920
+ detail: error.message,
5921
+ redacted: false
5922
+ };
5923
+ return {
5924
+ summary: `${error.name || "Error"}. ${VERBOSE_POINTER}`,
5925
+ detail: error.message,
5926
+ redacted: true
5927
+ };
5928
+ }
5929
+ return {
5930
+ summary: `a non-Error value of type ${typeof error}. ${VERBOSE_POINTER}`,
5931
+ detail: String(error),
5932
+ redacted: true
5933
+ };
5934
+ }
5935
+
5759
5936
  //#endregion
5760
5937
  //#region src/utils/deny-external-access-policy.ts
5761
5938
  /**
@@ -5945,7 +6122,11 @@ async function assertAssetBucketRegion(s3Client, bucketName, expectedRegion, acc
5945
6122
  } catch (probeError) {
5946
6123
  const fromProbe = readBucketRegionHeader(probeError);
5947
6124
  if (fromProbe) actual = canonicalizeRegion(fromProbe);
5948
- else throw new CdkdError(`Asset bucket '${bucketName}' is claimed by an existing bucket, but cdkd could not determine which region that bucket is in, so it cannot confirm it belongs to ${want}. Refusing to adopt it. (region probe failed: ${probeError instanceof Error ? probeError.message : String(probeError)}) ${remedy}`, "ASSET_STORAGE_FOREIGN_REGION_BUCKET", cause);
6125
+ else {
6126
+ const failure = describeAwsFailure(probeError);
6127
+ if (failure.redacted) getLogger().debug(`GetBucketLocation failed for asset bucket '${bucketName}' while confirming it belongs to ${want}: ${failure.detail}`);
6128
+ throw new CdkdError(`Asset bucket '${bucketName}' is claimed by an existing bucket, but cdkd could not determine which region that bucket is in, so it cannot confirm it belongs to ${want}. Refusing to adopt it. (region probe failed: ${failure.summary}) ${remedy}`, "ASSET_STORAGE_FOREIGN_REGION_BUCKET", cause);
6129
+ }
5949
6130
  }
5950
6131
  if (actual === want) return;
5951
6132
  throw new CdkdError(`Asset bucket name '${bucketName}' resolves to a bucket in ${actual}, while this operation targets ${want}. S3 bucket names are globally unique, and both 'BucketAlreadyOwnedByYou' and a cross-region redirect report ACCOUNT ownership rather than the bucket's region, so cdkd cannot treat it as ${want}'s asset bucket. cdkd asset storage is per-region by design: adopting it would publish ${want}'s assets into ${actual} and apply ${want}'s bucket configuration there. ${remedy}`, "ASSET_STORAGE_FOREIGN_REGION_BUCKET", cause);
@@ -8977,9 +9158,13 @@ function splitGetAttStringForm(getAtt) {
8977
9158
  * (`(producer X / Y)`), so it is neither derivable from the source leaf nor
8978
9159
  * stable.
8979
9160
  *
8980
- * THREE arms answer: `Fn::ImportValue`, `Fn::GetStackOutput`, and the
8981
- * `Fn::GetAtt` on a nested-stack OUTPUT that issue #2055's read site
8982
- * re-resolves. Every other leaf refuses.
9161
+ * FIVE arms answer, and the enumeration is kept current because a stale one
9162
+ * reads as exhaustive: `Fn::ImportValue`, `Fn::GetStackOutput`, the `Fn::GetAtt`
9163
+ * on a nested-stack OUTPUT that issue #2055's read site re-resolves, the
9164
+ * single-placeholder `Fn::Sub` that normalizes ONTO that `Fn::GetAtt` key
9165
+ * (issue #2270 round 3 -- this list said THREE until issue #2291 noticed it had
9166
+ * been four since then), and the `Ref` to a nested-stack CHILD's own PARAMETER
9167
+ * (issue #2291). Every other leaf refuses.
8983
9168
  *
8984
9169
  * `Region` and `RoleArn` are OPTIONAL slots, and an ABSENT one keys as empty
8985
9170
  * while a PRESENT-but-non-literal one refuses. Absent has to be its own key
@@ -9082,6 +9267,11 @@ function crossStackSourceKey(source) {
9082
9267
  split.attributeName
9083
9268
  ].join(CROSS_STACK_KEY_SEPARATOR);
9084
9269
  }
9270
+ if (key === "Ref") {
9271
+ const parameterName = literalStringOrUndefined(source[key]);
9272
+ if (parameterName === void 0) return void 0;
9273
+ return ["Ref", parameterName].join(CROSS_STACK_KEY_SEPARATOR);
9274
+ }
9085
9275
  }
9086
9276
  /**
9087
9277
  * Remember, FOR THE PASS THAT OWNS `secrets`, that the cross-stack source leaf
@@ -9101,6 +9291,34 @@ function recordCrossStackExpression(secrets, key, expression, plaintext) {
9101
9291
  associations = /* @__PURE__ */ new Map();
9102
9292
  crossStackAssociations.set(secrets, associations);
9103
9293
  }
9294
+ storeAssociation(associations, key, expression, plaintext);
9295
+ }
9296
+ /**
9297
+ * The store's WRITE rule, shared by {@link recordCrossStackExpression} and
9298
+ * {@link recordNestedStackParameterExpressions} so the two tables cannot drift
9299
+ * apart on what a second sighting means.
9300
+ *
9301
+ * A key recorded against a DIFFERENT (expression, plaintext) pair is POISONED
9302
+ * to {@link CONFLICTING_CROSS_STACK} rather than overwritten; an already
9303
+ * poisoned key stays poisoned, because a third sighting cannot un-contradict
9304
+ * the first two. Every reader refuses a poisoned key, which degrades to the
9305
+ * value scan — today's behaviour — rather than guessing between the two.
9306
+ *
9307
+ * WHAT IS AND IS NOT FENCED, stated because a reader would otherwise assume the
9308
+ * whole thing is (review of issue #2291). The POISON-vs-OVERWRITE decision IS
9309
+ * fenced: a second sighting under a THIRD expression makes the two outcomes
9310
+ * differ (poison refuses and falls back; overwriting would certify the third),
9311
+ * and a case asserts it. Nothing fences the branch from
9312
+ * {@link recordNestedStackParameterExpressions}'s side in PRODUCTION, because
9313
+ * that writer runs once per resource bag and `Object.entries` cannot yield one
9314
+ * name twice — the poison is reachable only through this module's API. It is
9315
+ * kept as an INVARIANT, not claimed as covered behaviour.
9316
+ *
9317
+ * The `isSingleDynamicReferenceToken` shape invariant is deliberately NOT here:
9318
+ * it belongs to each writer, which is where the parameters are named and where
9319
+ * a swap could be introduced.
9320
+ */
9321
+ function storeAssociation(associations, key, expression, plaintext) {
9104
9322
  const seen = associations.get(key);
9105
9323
  if (seen === void 0) {
9106
9324
  associations.set(key, {
@@ -9113,6 +9331,218 @@ function recordCrossStackExpression(secrets, key, expression, plaintext) {
9113
9331
  if (seen.expression !== expression || seen.plaintext !== plaintext) associations.set(key, CONFLICTING_CROSS_STACK);
9114
9332
  }
9115
9333
  /**
9334
+ * The `AWS::CloudFormation::Stack` type string, named once because the recorder
9335
+ * below gates on it and the tests assert against the same population.
9336
+ *
9337
+ * DUPLICATED, deliberately: `intrinsic-function-resolver.ts` declares the same
9338
+ * literal under the same name (for the `Outputs.<Name>` re-resolution of issue
9339
+ * #2055). This module is a LEAF by design -- see the file header, it imports
9340
+ * nothing, because both the resolver and the deploy engine consume it -- so
9341
+ * importing that spelling would close a cycle, and exporting this one for the
9342
+ * resolver to import would make the leaf a source of values rather than of
9343
+ * pure functions. The two cannot drift into DISAGREEMENT in any way that
9344
+ * matters: an AWS resource type string is fixed by AWS, and a typo in either
9345
+ * copy makes that copy's gate simply never fire (no-op), never fire wrongly.
9346
+ */
9347
+ const NESTED_STACK_RESOURCE_TYPE$1 = "AWS::CloudFormation::Stack";
9348
+ /**
9349
+ * What a PARENT stack's resolution proved about each `Parameters` entry of an
9350
+ * `AWS::CloudFormation::Stack` row it is about to provision, keyed by the
9351
+ * child's PARAMETER NAME (issue
9352
+ * [#2291](https://github.com/go-to-k/cdkd/issues/2291)).
9353
+ *
9354
+ * WHY A THIRD STORE, when {@link crossStackAssociations} already holds
9355
+ * per-leaf associations. This one is OUTBOUND: it is written against the
9356
+ * PARENT's bag and describes leaves of the CHILD's template, so it has to be
9357
+ * transported across the engine boundary before any reader can use it. The
9358
+ * child's per-resource bag then receives those entries as ORDINARY
9359
+ * {@link crossStackAssociations} rows (see
9360
+ * {@link inheritNestedStackParameterAssociations}), which is what lets the
9361
+ * existing three-condition reader answer for them with no new arm.
9362
+ *
9363
+ * KEEPING THE TWO TABLES SEPARATE IS LOAD-BEARING, not tidiness. A child engine
9364
+ * that itself owns a grandchild `AWS::CloudFormation::Stack` row records the
9365
+ * GRANDCHILD's parameter names against the CHILD's bag — the same bag that
9366
+ * already carries the child's own INBOUND `Ref` associations. Writing both into
9367
+ * one table means a grandchild parameter sharing a NAME with a child parameter
9368
+ * poisons the child's entry (two expressions under one key), so a leaf that was
9369
+ * being certified correctly falls back to the value scan the moment a
9370
+ * same-named parameter appears one level down. Two tables make the collision
9371
+ * impossible rather than unlikely.
9372
+ *
9373
+ * A `WeakMap` keyed by the parent pass's own bag, for the reason
9374
+ * {@link crossStackAssociations} gives: the entries hold PLAINTEXT, and they
9375
+ * must not outlive the pass that fetched them.
9376
+ */
9377
+ const nestedStackParameterExpressions = /* @__PURE__ */ new WeakMap();
9378
+ /**
9379
+ * Record, for the pass that owns `secrets`, which `{{resolve:...}}` expression
9380
+ * each `Parameters` entry of a nested-stack row was resolved FROM (issue
9381
+ * #2291). No-op for every other resource type.
9382
+ *
9383
+ * THE EXPRESSIONS COME FROM THE POSITION PASS, not from `secrets`, and that is
9384
+ * the whole reason this works at all. `RecordedSecretValues` is keyed by
9385
+ * PLAINTEXT, so two parameters resolving to one value have already collapsed to
9386
+ * a single entry there by the time this runs — asking the map which expression
9387
+ * a given parameter came from returns the SURVIVOR for both. What has not
9388
+ * collapsed is the parent's own template: `Properties.Parameters.<Name>` still
9389
+ * holds each entry's own source leaf. So this walks the parent's resolved
9390
+ * parameter bag against that source with {@link redactSecretsForState}, which
9391
+ * is exactly the machinery the parent's persist path already uses and which
9392
+ * certifies PER LEAF (measured on this issue: the parent's own two properties
9393
+ * come out correct while the child's collapse onto one). Deriving the answer
9394
+ * from the positioner rather than restating its rules is what keeps this from
9395
+ * drifting away from the persist path.
9396
+ *
9397
+ * THE `rules` PARAMETER IS THE CALLER'S GENERATION CLAIM, not a knob. The
9398
+ * DEPLOY path passes {@link TEMPLATE_DERIVED_RULES} (the default): its source is
9399
+ * the parent's TEMPLATE, which can carry a PUBLIC `ssm:` reference that must
9400
+ * stay resolved (issue #1901) and which cannot certify the generation of
9401
+ * anything. The rollback REPLAY passes {@link STATE_DERIVED_RULES}, because its
9402
+ * source is the JOURNAL record — a persisted bag holding no public expressions,
9403
+ * and the same generation the bag was resolved from one statement earlier. That
9404
+ * is the identical pairing `redactRollbackRecord` already makes for the record
9405
+ * it positions, so the two replay walks now agree about what their source is.
9406
+ *
9407
+ * "No public expressions" carries the carve-out {@link PathSourceRules} states
9408
+ * and this note must not restate without it: `cdkd import` warns and persists
9409
+ * the RAW template intrinsic, so a public `ssm:` token CAN sit in a record. The
9410
+ * replay then CERTIFIES one the deploy default would refuse, at a cost bounded
9411
+ * to the issue #1901 class — a spurious UPDATE over a value state should hold
9412
+ * resolved, never a disclosure, since an expression is what gets persisted
9413
+ * either way. See the replay call sites for why gating on
9414
+ * {@link isKnownSecretExpression} is the wrong way to close it.
9415
+ *
9416
+ * FOUR REFUSALS, each degrading to today's behaviour (the child leaf falls to
9417
+ * the plaintext-keyed value scan):
9418
+ *
9419
+ * 1. REFUSAL — the resolved parameter value is not a WHOLE recorded plaintext.
9420
+ * A parameter the parent built with an `Fn::Sub` merely EMBEDS the secret,
9421
+ * so there is no single expression the child's leaf could be persisted as.
9422
+ * It also bounds what this store HOLDS: an entry carries a plaintext, and
9423
+ * remembering one this pass never resolved has no purpose.
9424
+ * 2. REFUSAL — the expression is not a single complete `{{resolve:...}}` token.
9425
+ * The same test {@link recordCrossStackExpression} applies at its own
9426
+ * boundary, spelled here because this writer populates a DIFFERENT table.
9427
+ * This is what rejects an embedded case that survived refusal 1 (a value
9428
+ * scan produced `postgres://u:{{resolve:...}}@host`, which is not a token).
9429
+ * 3. REFUSAL — the expression may never EQUAL the plaintext it is recorded
9430
+ * against. The reader returns the expression to be PERSISTED, so an entry
9431
+ * whose two halves coincide hands a SECRET back as though it were a
9432
+ * reference.
9433
+ *
9434
+ * THIS IS REACHABLE, and an earlier revision of this note called it an
9435
+ * unreachable invariant and told the next reader not to try to fence it.
9436
+ * That was wrong twice over: wrong on the fact, and wrong to assert it,
9437
+ * because {@link plaintextIndexOf}'s own note records the rule that
9438
+ * "asserting something cannot be fenced suppresses the attempt, so it needs
9439
+ * the same evidence a fence does" -- and no such evidence existed. The
9440
+ * reaching shape is the issue
9441
+ * [#1917](https://github.com/go-to-k/cdkd/issues/1917) family: a
9442
+ * SELF-REFERENTIAL secret, whose stored VALUE is byte-identical to its own
9443
+ * `{{resolve:...}}` text, so the pass records `SELF -> SELF`. The route is
9444
+ * NOT the value scan the old note named. It is {@link redactByPath}'s
9445
+ * `!sourceIsSameGeneration && isSingleDynamicReferenceToken(bag)` arm, which
9446
+ * returns `secrets.get(bag) ?? bag` -- and for a self-referential secret
9447
+ * that IS the bag. Under {@link STATE_DERIVED_RULES} the same input arrives
9448
+ * by the other door (`sourceIsSameGeneration` is true, so the arm takes
9449
+ * `return source`, which is the same string again), so both callers reach it.
9450
+ * Fenced by the self-referential case in
9451
+ * `secret-redaction-nested-parameter-source.test.ts`.
9452
+ */
9453
+ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedProperties, sourceProperties, rules = TEMPLATE_DERIVED_RULES) {
9454
+ if (resourceType !== NESTED_STACK_RESOURCE_TYPE$1) return;
9455
+ if (secrets.size === 0) return;
9456
+ if (!isPlainObject$2(resolvedProperties) || !isPlainObject$2(sourceProperties)) return;
9457
+ if (!Object.hasOwn(resolvedProperties, "Parameters")) return;
9458
+ if (!Object.hasOwn(sourceProperties, "Parameters")) return;
9459
+ const resolvedParameters = resolvedProperties["Parameters"];
9460
+ const sourceParameters = sourceProperties["Parameters"];
9461
+ if (!isPlainObject$2(resolvedParameters) || !isPlainObject$2(sourceParameters)) return;
9462
+ const positioned = redactSecretsForState(resolvedParameters, secrets, sourceParameters, rules);
9463
+ let table = nestedStackParameterExpressions.get(secrets);
9464
+ for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
9465
+ if (typeof resolvedValue !== "string" || !secrets.has(resolvedValue)) continue;
9466
+ const expression = positioned[name];
9467
+ if (typeof expression !== "string") continue;
9468
+ if (!isSingleDynamicReferenceToken(expression)) continue;
9469
+ const sourceLeaf = sourceParameters[name];
9470
+ if (typeof sourceLeaf === "string" && expression !== sourceLeaf) continue;
9471
+ if (expression === resolvedValue) continue;
9472
+ if (table === void 0) {
9473
+ table = /* @__PURE__ */ new Map();
9474
+ nestedStackParameterExpressions.set(secrets, table);
9475
+ }
9476
+ storeAssociation(table, name, expression, resolvedValue);
9477
+ }
9478
+ }
9479
+ /**
9480
+ * Copy a parent pass's per-PARAMETER associations onto a nested-stack CHILD
9481
+ * resource's own bag, as ordinary {@link crossStackAssociations} rows keyed by
9482
+ * `{Ref: <ParamName>}` (issue #2291).
9483
+ *
9484
+ * Called by the child {@link DeployEngine} once per resolver context, so each
9485
+ * child resource's fresh bag carries them. Pre-seeding every resource this way
9486
+ * does NOT reintroduce issue #2087's over-redaction: an association can only
9487
+ * change an answer through {@link positionByCrossStackSource}'s condition 1,
9488
+ * which requires the bag leaf to be a plaintext THIS resource's bag holds — and
9489
+ * since #2087 that is true only of resources whose own resolution consumed the
9490
+ * parameter. The scoping still comes from the plaintext bag; this table only
9491
+ * decides WHICH expression such a leaf takes.
9492
+ *
9493
+ * Nothing is copied when the parent recorded nothing, which is every non-nested
9494
+ * caller and every nested one whose parameters carry no secret.
9495
+ */
9496
+ function inheritNestedStackParameterAssociations(childSecrets, parentSecrets) {
9497
+ const table = nestedStackParameterExpressions.get(parentSecrets);
9498
+ if (table === void 0 || table.size === 0) return;
9499
+ let associations = crossStackAssociations.get(childSecrets);
9500
+ for (const [name, association] of table) {
9501
+ const key = crossStackSourceKey({ Ref: name });
9502
+ if (key === void 0) continue;
9503
+ if (associations === void 0) {
9504
+ associations = /* @__PURE__ */ new Map();
9505
+ crossStackAssociations.set(childSecrets, associations);
9506
+ }
9507
+ if (typeof association === "symbol") {
9508
+ associations.set(key, association);
9509
+ continue;
9510
+ }
9511
+ storeAssociation(associations, key, association.expression, association.plaintext);
9512
+ }
9513
+ }
9514
+ /**
9515
+ * The expression a nested-stack child's PARAMETER was resolved from, or
9516
+ * `undefined` when this pass cannot certify one (issue #2291).
9517
+ *
9518
+ * The DIFF-side twin of {@link positionByCrossStackSource}, and it must exist
9519
+ * or the fix trades one bug for another. The child's persisted state now holds
9520
+ * each parameter-fed leaf's OWN expression, so the desired side of the next
9521
+ * diff has to hold it too; the engine's `redactParametersForDiff` rewrites the
9522
+ * parameter bag through the plaintext-keyed map alone, which hands BOTH members
9523
+ * of a coinciding pair the survivor's expression. The two sides would then
9524
+ * never match for the losing parameter: a perpetual UPDATE on every deploy of
9525
+ * such a child, which is issue #2087's user-visible symptom arriving through a
9526
+ * different door.
9527
+ *
9528
+ * `parentSecrets` is the INHERITED bag — the parent's own per-resource map, the
9529
+ * object this table is keyed by — not the child resource's bag.
9530
+ *
9531
+ * The same THREE conditions {@link positionByCrossStackSource} applies, for the
9532
+ * same reasons; see that function's own notes for why condition 3 is not
9533
+ * subsumed by condition 2.
9534
+ */
9535
+ function inheritedParameterExpression(parentSecrets, parameterName, resolvedValue) {
9536
+ if (typeof resolvedValue !== "string" || resolvedValue === "") return void 0;
9537
+ if (!parentSecrets.has(resolvedValue)) return void 0;
9538
+ const association = nestedStackParameterExpressions.get(parentSecrets)?.get(parameterName);
9539
+ if (association === void 0 || typeof association === "symbol") return void 0;
9540
+ if (association.plaintext !== resolvedValue) return void 0;
9541
+ const recordedPlaintext = plaintextIndexOf(parentSecrets).get(association.expression);
9542
+ if (recordedPlaintext !== void 0 && recordedPlaintext !== resolvedValue) return void 0;
9543
+ return association.expression;
9544
+ }
9545
+ /**
9116
9546
  * A resolved secret value shorter than this is NOT used as a redaction needle:
9117
9547
  * a 1-2 character plaintext (e.g. a secret whose JSON key holds `"0"`) would
9118
9548
  * match incidental characters everywhere and mangle unrelated state. Such a
@@ -12235,11 +12665,12 @@ async function withRetry(operation, logicalId, opts = {}) {
12235
12665
  } catch (error) {
12236
12666
  lastError = error;
12237
12667
  const message = error instanceof Error ? error.message : String(error);
12668
+ const classifyText = retryClassificationText(error);
12238
12669
  if (isMarkedNonRetryable(error)) throw error;
12239
- const retryable = opts.isRetryable ? opts.isRetryable(message, error) : isRetryableTransientError(error, message);
12240
- const propagation = defaultSchedule && isIamPropagationError(message);
12670
+ const retryable = opts.isRetryable ? opts.isRetryable(classifyText, error) : isRetryableTransientError(error, classifyText);
12671
+ const propagation = defaultSchedule && isIamPropagationError(classifyText);
12241
12672
  if (propagation) sawPropagation = true;
12242
- const nameCooldown = defaultSchedule && !propagation && isNameCooldownError(message);
12673
+ const nameCooldown = defaultSchedule && !propagation && isNameCooldownError(classifyText);
12243
12674
  const attemptLimit = sawPropagation ? 26 : maxRetries;
12244
12675
  if (!retryable || attempt >= attemptLimit) {
12245
12676
  if (propagationRetries > 0 || serverErrorRetries > 0 || nameCooldownRetries > 0) {
@@ -16420,15 +16851,79 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
16420
16851
  * `Fn::Select` / `Fn::FindInMap` all re-enter `resolveValue` and reach the
16421
16852
  * parameter through this same `Ref` branch.
16422
16853
  *
16854
+ * WHICH EXPRESSION the pair is recorded against is the issue
16855
+ * [#2291](https://github.com/go-to-k/cdkd/issues/2291) round-2 fix, and
16856
+ * skipping it made the persist and diff halves DISAGREE.
16857
+ *
16858
+ * `inherited` is keyed by PLAINTEXT, so two parent parameters resolving to
16859
+ * ONE value collapse to a single entry there and this method used to copy
16860
+ * whichever expression SURVIVED. That is invisible for a leaf spelled exactly
16861
+ * `{Ref: P}` — the persist path positions such a leaf through the parent's
16862
+ * per-parameter association and never consults this bag's value — but every
16863
+ * EMBEDDING shape (`Fn::Sub`, `Fn::Join`, and `{'Fn::Sub': '${P}'}`, which
16864
+ * `crossStackSourceKey` refuses because its `Fn::Sub` arm requires a dotted
16865
+ * attribute) falls to the plaintext-keyed VALUE SCAN, which reads exactly this
16866
+ * bag. Meanwhile `DeployEngine.redactParametersForDiff` answers PER PARAMETER.
16867
+ * So `Fn::Sub "postgres://u:${LoserParam}@host"` — the dominant CDK
16868
+ * connection-string shape — persisted the SURVIVOR's expression while the
16869
+ * desired side computed the LOSER's, and the two never matched again: a
16870
+ * perpetual UPDATE, or a perpetual REPLACEMENT on a create-only property.
16871
+ * That is issue [#2087](https://github.com/go-to-k/cdkd/issues/2087)'s symptom
16872
+ * arriving through a different door, prevented for the bare-`Ref` leaf and
16873
+ * created for the embedded one.
16874
+ *
16875
+ * Recording THIS parameter's own expression makes the value scan agree with
16876
+ * the diff side, so both halves move together.
16877
+ *
16878
+ * THE RESIDUAL, and the earlier version of this note UNDERSTATED IT. It said
16879
+ * the leftover case was "no worse than the behaviour before this fix". That
16880
+ * is true only of the shape it was measured on. MEASURED 2026-08-27 against
16881
+ * `main` (f56c2cf9) and against this branch, one child resource, parameters
16882
+ * `A` and `B` resolving to one plaintext:
16883
+ *
16884
+ * | shape | main | here |
16885
+ * | ---------------------------------------- | ------- | ------- |
16886
+ * | `{Ref: A}` and `{Ref: B}` | agree | agree |
16887
+ * | `Fn::Sub '${A}'` only | agree | agree |
16888
+ * | `Fn::Sub 'x${A}'` **and** `{Ref: B}` | agree | DISAGREE|
16889
+ *
16890
+ * The third row is a NEW disagreement this PR introduces, not a pre-existing
16891
+ * one it fails to fix: `main` had both halves take the collapsed survivor, so
16892
+ * they matched (on the WRONG expression, which is issue #2291, but they
16893
+ * matched). Here the DIFF side is per-parameter while an EMBEDDED leaf can
16894
+ * only be redacted by the plaintext-keyed value scan, and this bag holds ONE
16895
+ * entry — whichever `Ref` resolved LAST. So the embedded leaf takes `B`'s
16896
+ * expression while the desired side computes `A`'s, and the resource reports
16897
+ * an UPDATE on every deploy (a REPLACEMENT, on a create-only property).
16898
+ *
16899
+ * It is ORDER-DEPENDENT, which is why it is narrow: reversing the two
16900
+ * properties makes the embedded parameter the last one resolved and the two
16901
+ * halves agree again (measured). It also needs BOTH leaves in ONE resource —
16902
+ * `perResourceSecrets` is keyed by logical id, so two resources get two bags
16903
+ * and each is right. A resource that consumes and embeds BOTH parameters is
16904
+ * unfixable here for the same reason and is genuinely inherent.
16905
+ *
16906
+ * CLOSING IT NEEDS A PLACEHOLDER-SPAN POSITION ARM — aligning an `Fn::Sub` /
16907
+ * `Fn::Join` source against the resolved string to locate each placeholder's
16908
+ * span and rewrite it from the association. That is a new positioning
16909
+ * CONCEPT rather than an arm beside the existing ones: the persist path would
16910
+ * have to reproduce the resolver's substitution semantics from a module that
16911
+ * holds neither a resolver nor a parameter bag, and any divergence between
16912
+ * the two reproductions is this same perpetual-UPDATE bug. Deferred to issue
16913
+ * [#2320](https://github.com/go-to-k/cdkd/issues/2320) with the measurement.
16914
+ * It shares only the word "span" with issue #2102, which registers live
16915
+ * values for `{{resolve:...}}` TOKEN spans on the drift paths.
16916
+ *
16423
16917
  * Substituting is deliberately NOT done here — the resolved value is what
16424
16918
  * reaches AWS, and an `Fn::Equals` over a parameter must compare the real
16425
16919
  * value or the condition flips.
16426
16920
  */
16427
- recordInheritedParameterSecrets(value, context) {
16921
+ recordInheritedParameterSecrets(parameterName, value, context) {
16428
16922
  const inherited = context.inheritedSecrets;
16429
16923
  const recorded = context.recordedSecretValues;
16430
16924
  if (!inherited || inherited.size === 0 || !recorded) return;
16431
- for (const [plaintext, expression] of inheritedSecretsCarriedBy(value, inherited)) recorded.set(plaintext, expression);
16925
+ const own = inheritedParameterExpression(inherited, parameterName, value);
16926
+ for (const [plaintext, expression] of inheritedSecretsCarriedBy(value, inherited)) recorded.set(plaintext, own !== void 0 && plaintext === value ? own : expression);
16432
16927
  }
16433
16928
  /**
16434
16929
  * Refuse a child parameter whose declared `Type` would COERCE an inherited
@@ -16493,7 +16988,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
16493
16988
  const value = context.parameters[logicalId];
16494
16989
  const paramDef = context.template.Parameters?.[logicalId];
16495
16990
  this.logger.debug(`Resolved Ref to parameter: ${logicalId} -> ${this.maskSecretsForLog(stringifyParameterForLog(paramDef, value), context)}`);
16496
- this.recordInheritedParameterSecrets(value, context);
16991
+ this.recordInheritedParameterSecrets(logicalId, value, context);
16497
16992
  return value;
16498
16993
  }
16499
16994
  const pseudoValue = await this.resolvePseudoParameter(logicalId, context);
@@ -19514,7 +20009,7 @@ var CloudControlProvider = class {
19514
20009
  await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
19515
20010
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
19516
20011
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
19517
- const { ASGProvider } = await import("./asg-provider-BjebXXKD.js").then((n) => n.n);
20012
+ const { ASGProvider } = await import("./asg-provider-R60Irey3.js").then((n) => n.n);
19518
20013
  return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
19519
20014
  }
19520
20015
  const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
@@ -28346,6 +28841,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
28346
28841
  const current = stateResources[op.logicalId];
28347
28842
  const prev = op.previousState;
28348
28843
  const resolvedPrevProps = await resolveReplayProps(prev.properties, resolver, secrets, ctx, op.logicalId) ?? {};
28844
+ recordNestedStackParameterExpressions(secrets, op.resourceType, resolvedPrevProps, prev.properties, STATE_DERIVED_RULES);
28349
28845
  logger.info(` Rollback: Reversing replacement of ${op.logicalId} (${op.resourceType}) — re-creating the old resource and deleting the new one`);
28350
28846
  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.`);
28351
28847
  const { provider: createProvider } = ctx.providerRegistry.getProviderFor({
@@ -28439,6 +28935,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
28439
28935
  });
28440
28936
  const desiredProps = await resolveReplayProps(previousState.properties, resolver, secrets, ctx, op.logicalId);
28441
28937
  const currentProps = await resolveReplayProps(current.properties, resolver, secrets, ctx, op.logicalId);
28938
+ recordNestedStackParameterExpressions(secrets, op.resourceType, desiredProps, previousState.properties, STATE_DERIVED_RULES);
28442
28939
  const revertResult = await updateWithRollbackRetry(provider, [
28443
28940
  op.logicalId,
28444
28941
  current.physicalId,
@@ -28591,6 +29088,7 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
28591
29088
  });
28592
29089
  const desiredProps = await resolveReplayProps(prev.properties, resolver, secrets, ctx, op.logicalId);
28593
29090
  const attemptedProps = await resolveReplayProps(op.attemptedProperties ?? current.properties, resolver, secrets, ctx, op.logicalId);
29091
+ recordNestedStackParameterExpressions(secrets, op.resourceType, desiredProps, prev.properties, STATE_DERIVED_RULES);
28594
29092
  const revertFailedResult = await updateWithRollbackRetry(provider, [
28595
29093
  op.logicalId,
28596
29094
  current.physicalId,
@@ -29533,6 +30031,8 @@ var DeployEngine = class {
29533
30031
  * `this.buildResolverContext({...}, stackName)`.
29534
30032
  */
29535
30033
  buildResolverContext(base, stackName) {
30034
+ const recordedSecretValues = /* @__PURE__ */ new Map();
30035
+ if (this.options.inheritedSecrets && this.options.inheritedSecrets.size > 0) inheritNestedStackParameterAssociations(recordedSecretValues, this.options.inheritedSecrets);
29536
30036
  return {
29537
30037
  template: base.template,
29538
30038
  resources: base.resources,
@@ -29544,7 +30044,7 @@ var DeployEngine = class {
29544
30044
  recordedImports: this.recordedImports,
29545
30045
  recordedOutputReads: this.recordedOutputReads,
29546
30046
  ...this.options.inheritedSecrets && this.options.inheritedSecrets.size > 0 && { inheritedSecrets: this.options.inheritedSecrets },
29547
- recordedSecretValues: /* @__PURE__ */ new Map()
30047
+ recordedSecretValues
29548
30048
  };
29549
30049
  }
29550
30050
  /**
@@ -29571,7 +30071,9 @@ var DeployEngine = class {
29571
30071
  redactParametersForDiff(parameterValues) {
29572
30072
  const inherited = this.options.inheritedSecrets;
29573
30073
  if (!inherited || inherited.size === 0) return parameterValues;
29574
- return redactSecretsForState(parameterValues, inherited);
30074
+ const out = {};
30075
+ for (const [name, value] of Object.entries(parameterValues)) out[name] = inheritedParameterExpression(inherited, name, value) ?? redactSecretsForState(value, inherited);
30076
+ return out;
29575
30077
  }
29576
30078
  /**
29577
30079
  * Redact resolved secret plaintext out of a bag about to be PERSISTED to
@@ -30687,6 +31189,7 @@ var DeployEngine = class {
30687
31189
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
30688
31190
  this.perResourceTemplateProps.set(logicalId, desiredProps);
30689
31191
  const createSecrets = context.recordedSecretValues ?? /* @__PURE__ */ new Map();
31192
+ recordNestedStackParameterExpressions(createSecrets, resourceType, resolvedProps, desiredProps);
30690
31193
  this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
30691
31194
  this.attemptedResolvedProps.set(logicalId, resolvedProps);
30692
31195
  const createDecision = this.providerRegistry.getProviderFor({
@@ -30731,6 +31234,7 @@ var DeployEngine = class {
30731
31234
  this.perResourceSecrets.set(logicalId, updateSecrets);
30732
31235
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
30733
31236
  this.perResourceTemplateProps.set(logicalId, desiredProps);
31237
+ recordNestedStackParameterExpressions(updateSecrets, resourceType, resolvedProps, desiredProps);
30734
31238
  this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
30735
31239
  this.attemptedResolvedProps.set(logicalId, resolvedProps);
30736
31240
  if (JSON.stringify(redactSecretsForState(resolvedProps, updateSecrets, desiredProps)) === JSON.stringify(currentProps)) {
@@ -31398,5 +31902,5 @@ var DeployEngine = class {
31398
31902
  };
31399
31903
 
31400
31904
  //#endregion
31401
- export { maskerOrIdentity as $, MIGRATE_TMP_PREFIX as $n, redactSecretsForState as $t, renderStatefulReason as A, dockerSpawnEnvWithSensitive as An, ResourceUpdateNotSupportedError as Ar, classifyReplaySecretRegion as At, exportAliasCollisionScrubWarning as B, getDefaultStateBucketName as Bn, isRetryableTransientError as Br, describeTypeWithThrottleRetry as Bt, isFinalSnapshotError as C, isCrossRegionRedirect as Cn, LocalStartServiceError as Cr, configBooleanRefusal as Ct, extractDeploymentEventError as D, validateContainerRepoName as Dn, PartialFailureError as Dr, requireConfigArray as Dt, makeCanonicalizePropertiesFn as E, validateAssetBucketName as En, NestedStackChildDirectDestroyError as Er, replayWarn as Et, green as F, runDockerStreaming as Fn, formatError as Fr, s3BucketRegionalDomainName as Ft, IAMRoleProvider as G, resolveSkipPrefix as Gn, STATE_SOURCED_READBACK_RULES as Gt, secretBearingStateKeyWarning as H, resolveApp as Hn, markNonRetryable as Hr, DagBuilder as Ht, red as I, AssetManifestLoader as In, isCdkdError as Ir, s3BucketWebsiteUrl as It, ProviderRegistry as J, resolveUseCdkBootstrapAssets as Jn, dynamicReferenceTokens as Jt, collectInlinePolicyNamesManagedBySiblings as K, resolveStateBucketWithDefault as Kn, TEMPLATE_SOURCED_RULES as Kt, yellow as L, getDockerImageBySourceHash as Ln, normalizeAwsError as Lr, applyRoleArnIfSet as Lt, bold as M, getDockerCmd as Mn, StackTerminationProtectionError as Mr, s3BucketArn as Mt, cyan as N, partitionSensitiveEnv as Nn, StateError as Nr, s3BucketDomainName as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, buildDenyExternalAccessPolicy as On, ProvisioningError as Or, requireConfigObject as Ot, gray as P, runDockerForeground as Pn, SynthesisError as Pr, s3BucketDualStackDomainName as Pt, maskDeep as Q, CFN_TEMPLATE_URL_LIMIT as Qn, maskSecretsInText as Qt, collectDeclaredOutputNames as R, Synthesizer as Rn, withErrorHandling as Rr, DiffCalculator as Rt, createPreDeleteFinalSnapshot as S, getBootstrapMarkerKey as Sn, LocalMigrateError as Sr, coerceCfnBoolean as St, unsupportedFinalSnapshotError as T, readBootstrapMarkerBody as Tn, MissingCdkCliError as Tr, readConfigString as Tt, stateKeySecretExposure as U, resolveAutoAssetStorage as Un, __exportAll as Ur, TemplateParser as Ut, isExportAliasCollision as V, getLegacyStateBucketName as Vn, isThrottlingError as Vr, withRetry as Vt, getCurrentResourceSecrets as W, resolveCaptureObservedState as Wn, STATE_SOURCED_CROSS_GENERATION_RULES as Wt, findSilentDropProperties as X, warnDeprecatedNoPrefixCliFlag as Xn, isSingleDynamicReferenceToken as Xt, findActionableSilentDrops as Y, stateBucketExistenceConfirmed as Yn, errorCauseChain as Yt, createMaskedRetryLogger as Z, CFN_TEMPLATE_BODY_LIMIT as Zn, maskSecretsInError as Zt, computeImplicitDeleteEdges as _, stripControlChars as _n, CrossAccountSecretRefusalError as _r, refStateLookupFromResource as _t, DeploymentEventsStore as a, exportNamesCarriedFrom as an, derivePartitionAndUrlSuffix as ar, isInterruptedWaitError as at, buildFinalSnapshotIdentifier as b, assertAssetBucketRegion as bn, DynamicReferenceRegionAmbiguousError as br, resolveExplicitPhysicalId as bt, replayFailedOperations as c, shouldRetainResource as cn, clearBucketRegionCache as cr, slowCcOperationTimeoutMs as ct, updatePartialReason as d, WorkGraph as dn, getAwsClients as dr, IntrinsicFunctionResolver as dt, scrubResourceRecord as en, findLargeInlineResources as er, CUSTOM_RESOURCE_RESPONSE_PREFIX as et, UNSPECIFIED_SKIP_REASON as f, buildAssetRedirectMap as fn, resetAwsClients as fr, carriesDynamicReference as ft, IMPLICIT_DELETE_DEPENDENCIES as g, escapeRegExp$1 as gn, ConfigError as gr, parameterTypeMayLoseSecretIdentity as gt, maskingRetryLogger as h, rewriteTemplateAssetReferences as hn, CdkdError as hr, isUnboundTemplateParameter as ht, DeploymentEventsReader as i, rebuildClientForBucketRegion as in, canonicalizeRegion as ir, interruptWatchListenerCount as it, formatResourceLine as j, formatDockerLoginError as jn, StackHasActiveImportsError as jr, producerRegionsFromState as jt, isStatefulRecreateTargetSync as k, buildDockerImage as kn, ResourceTimeoutError as kr, requireConfigString as kt, replayRollback as l, AssetPublisher as ln, resolveBucketRegion as lr, disableInstanceApiTermination as lt, withResourceDeadline as m, loadPublishableAssetManifest as mn, AssetError as mr, getAccountInfo as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, displaySafe as nn, expectedOwnerParam as nr, beginCommandInterruptScope as nt, planFailedOps as o, importableOutputKeys as on, AssemblyReader as or, startInterruptWatch as ot, deleteSkipReason as p, createAssetRedirectResolver as pn, setAwsClients as pr, cfnRefValueFromPhysicalId as pt, clearOnUpdateRemoval as q, resolveStateBucketWithDefaultAndSource as qn, createSecretMasker as qt, DeployEngine as r, S3StateBackend as rn, PARTITION_TABLE as rr, endCommandInterruptScope as rt, planRollback as s, importableOutputs as sn, processStackMessages as sr, CloudControlProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, LockManager as tn, uploadCfnTemplate as tr, DEFAULT_STATE_PREFIX as tt, updatePartialMessage as u, stringifyValue as un, AwsClients as ur, isTerminationProtectionPropagationError as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, AssetModeResolver as vn, DependencyError as vr, WAFv2WebACLProvider as vt, refusesFinalSnapshot as w, parseBootstrapMarker as wn, LockError as wr, configStringRefusal as wt, ccRoutedFinalSnapshotError as x, ensureAssetStorage as xn, LocalInvokeBuildError as xr, assertRegionMatch as xt, PRE_DELETE_SNAPSHOT_TYPES as y, BOOTSTRAP_MARKER_PREFIX as yn, DeployCancelledError as yr, normalizeAwsTagsToCfn as yt, collectPublishedOutputNames as z, synthesisStatusMessage as zn, isMarkedNonRetryable as zr, INTRINSIC_KEYS as zt };
31402
- //# sourceMappingURL=deploy-engine-Dm-MdFR-.js.map
31905
+ export { maskerOrIdentity as $, CFN_TEMPLATE_URL_LIMIT as $n, redactSecretsForState as $t, renderStatefulReason as A, buildDockerImage as An, ResourceTimeoutError as Ar, classifyReplaySecretRegion as At, exportAliasCollisionScrubWarning as B, synthesisStatusMessage as Bn, isMarkedNonRetryable as Br, describeTypeWithThrottleRetry as Bt, isFinalSnapshotError as C, isCrossRegionRedirect as Cn, LocalMigrateError as Cr, configBooleanRefusal as Ct, extractDeploymentEventError as D, validateContainerRepoName as Dn, NestedStackChildDirectDestroyError as Dr, requireConfigArray as Dt, makeCanonicalizePropertiesFn as E, validateAssetBucketName as En, MissingCdkCliError as Er, replayWarn as Et, green as F, runDockerForeground as Fn, SynthesisError as Fr, s3BucketRegionalDomainName as Ft, IAMRoleProvider as G, resolveCaptureObservedState as Gn, retryClassificationText as Gr, STATE_SOURCED_READBACK_RULES as Gt, secretBearingStateKeyWarning as H, getLegacyStateBucketName as Hn, isThrottlingError as Hr, DagBuilder as Ht, red as I, runDockerStreaming as In, formatError as Ir, s3BucketWebsiteUrl as It, ProviderRegistry as J, resolveStateBucketWithDefaultAndSource as Jn, dynamicReferenceTokens as Jt, collectInlinePolicyNamesManagedBySiblings as K, resolveSkipPrefix as Kn, __exportAll as Kr, TEMPLATE_SOURCED_RULES as Kt, yellow as L, AssetManifestLoader as Ln, isCdkdError as Lr, applyRoleArnIfSet as Lt, bold as M, formatDockerLoginError as Mn, StackHasActiveImportsError as Mr, s3BucketArn as Mt, cyan as N, getDockerCmd as Nn, StackTerminationProtectionError as Nr, s3BucketDomainName as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, buildDenyExternalAccessPolicy as On, PartialFailureError as Or, requireConfigObject as Ot, gray as P, partitionSensitiveEnv as Pn, StateError as Pr, s3BucketDualStackDomainName as Pt, maskDeep as Q, CFN_TEMPLATE_BODY_LIMIT as Qn, maskSecretsInText as Qt, collectDeclaredOutputNames as R, getDockerImageBySourceHash as Rn, normalizeAwsError as Rr, DiffCalculator as Rt, createPreDeleteFinalSnapshot as S, getBootstrapMarkerKey as Sn, LocalInvokeBuildError as Sr, coerceCfnBoolean as St, unsupportedFinalSnapshotError as T, readBootstrapMarkerBody as Tn, LockError as Tr, readConfigString as Tt, stateKeySecretExposure as U, resolveApp as Un, markNonRetryable as Ur, TemplateParser as Ut, isExportAliasCollision as V, getDefaultStateBucketName as Vn, isRetryableTransientError as Vr, withRetry as Vt, getCurrentResourceSecrets as W, resolveAutoAssetStorage as Wn, markRedactedCause as Wr, STATE_SOURCED_CROSS_GENERATION_RULES as Wt, findSilentDropProperties as X, stateBucketExistenceConfirmed as Xn, isSingleDynamicReferenceToken as Xt, findActionableSilentDrops as Y, resolveUseCdkBootstrapAssets as Yn, errorCauseChain as Yt, createMaskedRetryLogger as Z, warnDeprecatedNoPrefixCliFlag as Zn, maskSecretsInError as Zt, computeImplicitDeleteEdges as _, stripControlChars as _n, ConfigError as _r, refStateLookupFromResource as _t, DeploymentEventsStore as a, exportNamesCarriedFrom as an, canonicalizeRegion as ar, isInterruptedWaitError as at, buildFinalSnapshotIdentifier as b, assertAssetBucketRegion as bn, DeployCancelledError as br, resolveExplicitPhysicalId as bt, replayFailedOperations as c, shouldRetainResource as cn, processStackMessages as cr, slowCcOperationTimeoutMs as ct, updatePartialReason as d, WorkGraph as dn, AwsClients as dr, IntrinsicFunctionResolver as dt, scrubResourceRecord as en, MIGRATE_TMP_PREFIX as er, CUSTOM_RESOURCE_RESPONSE_PREFIX as et, UNSPECIFIED_SKIP_REASON as f, buildAssetRedirectMap as fn, getAwsClients as fr, carriesDynamicReference as ft, IMPLICIT_DELETE_DEPENDENCIES as g, escapeRegExp$1 as gn, CdkdError as gr, parameterTypeMayLoseSecretIdentity as gt, maskingRetryLogger as h, rewriteTemplateAssetReferences as hn, AssetError as hr, isUnboundTemplateParameter as ht, DeploymentEventsReader as i, rebuildClientForBucketRegion as in, PARTITION_TABLE as ir, interruptWatchListenerCount as it, formatResourceLine as j, dockerSpawnEnvWithSensitive as jn, ResourceUpdateNotSupportedError as jr, producerRegionsFromState as jt, isStatefulRecreateTargetSync as k, describeAwsFailure as kn, ProvisioningError as kr, requireConfigString as kt, replayRollback as l, AssetPublisher as ln, clearBucketRegionCache as lr, disableInstanceApiTermination as lt, withResourceDeadline as m, loadPublishableAssetManifest as mn, setAwsClients as mr, getAccountInfo as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, displaySafe as nn, uploadCfnTemplate as nr, beginCommandInterruptScope as nt, planFailedOps as o, importableOutputKeys as on, derivePartitionAndUrlSuffix as or, startInterruptWatch as ot, deleteSkipReason as p, createAssetRedirectResolver as pn, resetAwsClients as pr, cfnRefValueFromPhysicalId as pt, clearOnUpdateRemoval as q, resolveStateBucketWithDefault as qn, createSecretMasker as qt, DeployEngine as r, S3StateBackend as rn, expectedOwnerParam as rr, endCommandInterruptScope as rt, planRollback as s, importableOutputs as sn, AssemblyReader as sr, CloudControlProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, LockManager as tn, findLargeInlineResources as tr, DEFAULT_STATE_PREFIX as tt, updatePartialMessage as u, stringifyValue as un, resolveBucketRegion as ur, isTerminationProtectionPropagationError as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, AssetModeResolver as vn, CrossAccountSecretRefusalError as vr, WAFv2WebACLProvider as vt, refusesFinalSnapshot as w, parseBootstrapMarker as wn, LocalStartServiceError as wr, configStringRefusal as wt, ccRoutedFinalSnapshotError as x, ensureAssetStorage as xn, DynamicReferenceRegionAmbiguousError as xr, assertRegionMatch as xt, PRE_DELETE_SNAPSHOT_TYPES as y, BOOTSTRAP_MARKER_PREFIX as yn, DependencyError as yr, normalizeAwsTagsToCfn as yt, collectPublishedOutputNames as z, Synthesizer as zn, withErrorHandling as zr, INTRINSIC_KEYS as zt };
31906
+ //# sourceMappingURL=deploy-engine-Cvkqa30x.js.map