@go-to-k/cdkd 0.290.21 → 0.290.23

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
- import { C as displaySafe, S as displayIdent, b as STACK_REF_MAX_CODE_POINTS, d as applyDefaultNameForFallback, f as explicitNamePropertyFor, g as looksLikeCdkdGeneratedName, h as getCurrentStackName, m as generateResourceNameWithFallback, n as getLogger, p as generateResourceName, r as isStdoutReservedForPayload, s as getLiveRenderer, v as withStackName, w as truncateCodePoints, x as UNRENDERABLE, y as withoutGeneratedFallbackName } from "./logger-C17H06QA.js";
1
+ import { C as displaySafe, S as displayIdent, b as STACK_REF_MAX_CODE_POINTS, d as applyDefaultNameForFallback, f as explicitNamePropertyFor, g as looksLikeCdkdGeneratedName, h as getCurrentStackName, m as generateResourceNameWithFallback, n as getLogger, p as generateResourceName, r as isStdoutReservedForPayload, s as getLiveRenderer, v as withStackName, w as truncateCodePoints, x as UNRENDERABLE, y as withoutGeneratedFallbackName } from "./logger-CkHVgzLx.js";
2
2
  import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-BoIxyCir.js";
3
- import { t as getCdkdVersion } from "./version-CGcB3KHZ.js";
3
+ import { t as getCdkdVersion } from "./version-DxUVmvM5.js";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { createHash, randomUUID } from "node:crypto";
6
6
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -7360,7 +7360,7 @@ function repairSpawnRefusal(text, args, maskedArgs) {
7360
7360
  * error would only say "Command failed with exit code N".
7361
7361
  */
7362
7362
  function describeDockerExecFailure(error, args) {
7363
- const message = thrownMessageText(error) || safeStringify(error);
7363
+ const message = thrownMessageText(error) || safeStringify$1(error);
7364
7364
  const stderrText = capturedStreamText(error, "stderr");
7365
7365
  return redactDockerArgvInText(stderrText ? `${message}\n${stderrText}` : message, args);
7366
7366
  }
@@ -7403,7 +7403,7 @@ function thrownMessageText(error) {
7403
7403
  * two of these call sites are in `cleanupEcsRun`, where an exception aborts
7404
7404
  * the remaining volume / network teardown and leaks real Docker resources.
7405
7405
  */
7406
- function safeStringify(error) {
7406
+ function safeStringify$1(error) {
7407
7407
  try {
7408
7408
  return String(error);
7409
7409
  } catch {
@@ -7429,7 +7429,7 @@ function safeStringify(error) {
7429
7429
  * wrapper text needs the status as well.
7430
7430
  */
7431
7431
  function describeDockerFailure(error, args) {
7432
- return redactDockerArgvInText(capturedStreamText(error, "stderr") || thrownMessageText(error) || safeStringify(error), args);
7432
+ return redactDockerArgvInText(capturedStreamText(error, "stderr") || thrownMessageText(error) || safeStringify$1(error), args);
7433
7433
  }
7434
7434
  /**
7435
7435
  * A `cause` that is safe to CHAIN onto a wrapper error, for a caller that
@@ -8019,6 +8019,40 @@ function isAwsAuthoredFailure(error) {
8019
8019
  return candidate.$fault !== void 0 || typeof candidate.$metadata?.httpStatusCode === "number" || error.name === "CredentialsProviderError";
8020
8020
  }
8021
8021
  /**
8022
+ * Exactly what `String(value)` produces, without the throw.
8023
+ *
8024
+ * `String(value)` is the only spelling that carries an `Error`'s NAME as well
8025
+ * as its message (`"AccessDenied: User ... is not authorized"`), and several
8026
+ * call sites depend on that: four build a persisted `outcome: 'partial'`
8027
+ * reason where the wire code is the discriminator an operator reads first.
8028
+ * {@link describeAwsFailure}'s `detail` is the MESSAGE only, so it is NOT a
8029
+ * drop-in for the bare form -- substituting it silently deletes the code.
8030
+ * Measured, after a sweep did exactly that at nine sites.
8031
+ *
8032
+ * So this is the 1:1 replacement: same output for every value `String` can
8033
+ * convert, and a stable sentence for the ones it cannot. A null-prototype
8034
+ * object throws `TypeError: Cannot convert object to primitive value`, and an
8035
+ * object with a hostile or `null` `toString` throws whatever it likes -- inside
8036
+ * a catch, that replaces the failure being reported.
8037
+ *
8038
+ * Use `describeAwsFailure(x).detail` where the site previously read
8039
+ * `x instanceof Error ? x.message : String(x)`; use THIS where it read a bare
8040
+ * `String(x)`.
8041
+ *
8042
+ * NOT a substitute for `displaySafe` in `display-safe.ts`, which guards the
8043
+ * same coercion and answers differently on purpose -- it falls back to
8044
+ * `Object.prototype.toString` and, more importantly, SANITISES the result for a
8045
+ * terminal. Anything about to be rendered or logged goes through that one; this
8046
+ * one is for the text a catch is about to record.
8047
+ */
8048
+ function safeStringify(value) {
8049
+ try {
8050
+ return String(value);
8051
+ } catch {
8052
+ return "a value that could not be converted to text";
8053
+ }
8054
+ }
8055
+ /**
8022
8056
  * Describe a caught failure for a thrown message. See {@link AwsFailureText}.
8023
8057
  */
8024
8058
  function describeAwsFailure(error) {
@@ -11935,6 +11969,84 @@ function resolvedPlaintextOf(secrets, expression) {
11935
11969
  function resolvedExpressionsOf(secrets) {
11936
11970
  return [...resolvedPairsOf.get(secrets)?.keys() ?? []];
11937
11971
  }
11972
+ /** Poison for an intrinsic object one pass resolved two different ways. */
11973
+ const CONFLICTING_LEAF_RESOLUTION = Symbol("conflicting leaf resolution");
11974
+ /**
11975
+ * {@link IntrinsicLeafResolution}s per pass bag, keyed by the template OBJECT
11976
+ * that was resolved (issue [#3156](https://github.com/go-to-k/cdkd/issues/3156)).
11977
+ * The carry in {@link recordNestedStackParameterExpressions} reads it for the
11978
+ * very object the deploy engine handed the resolver, so its evidence is THIS
11979
+ * leaf's own resolution: no other leaf's substitution, however equal its value,
11980
+ * can answer for it, and each substitution carries its own verdict, which the
11981
+ * secret-only pair table cannot (an unclassifiable `ssm` answer recorded as a
11982
+ * pair looks the same as a later public answer with the same plaintext).
11983
+ * Both keys are weak, so a record lives as long as its bag and its template.
11984
+ */
11985
+ const intrinsicLeafResolutionsOf = /* @__PURE__ */ new WeakMap();
11986
+ /**
11987
+ * Record how the pass that owns `secrets` resolved the intrinsic object
11988
+ * `source`. A second resolution of the same object that differs in any field
11989
+ * poisons it for the pass, and the poison is never lifted; an identical one
11990
+ * changes nothing.
11991
+ */
11992
+ function recordIntrinsicLeafResolution(secrets, source, resolution) {
11993
+ let leaves = intrinsicLeafResolutionsOf.get(secrets);
11994
+ if (leaves === void 0) {
11995
+ leaves = /* @__PURE__ */ new WeakMap();
11996
+ intrinsicLeafResolutionsOf.set(secrets, leaves);
11997
+ }
11998
+ const copy = {
11999
+ input: resolution.input,
12000
+ output: resolution.output,
12001
+ substitutions: resolution.substitutions.map(({ token, value, secret }) => ({
12002
+ token,
12003
+ value,
12004
+ secret
12005
+ })),
12006
+ complete: resolution.complete
12007
+ };
12008
+ const previous = leaves.get(source);
12009
+ if (previous === void 0) leaves.set(source, copy);
12010
+ else if (previous === CONFLICTING_LEAF_RESOLUTION || !sameLeafResolution(previous, copy)) leaves.set(source, CONFLICTING_LEAF_RESOLUTION);
12011
+ }
12012
+ function sameLeafResolution(a, b) {
12013
+ return a.input === b.input && a.output === b.output && a.complete === b.complete && a.substitutions.length === b.substitutions.length && a.substitutions.every((s, i) => s.token === b.substitutions[i].token && s.value === b.substitutions[i].value && s.secret === b.substitutions[i].secret);
12014
+ }
12015
+ /**
12016
+ * The spelling `source`'s own resolution in this pass proves for
12017
+ * `resolvedValue`, or `undefined` (issue
12018
+ * [#3156](https://github.com/go-to-k/cdkd/issues/3156)). Certified only when
12019
+ * the resolution replaced every token it met, replaced exactly ONE, took a
12020
+ * SECRET verdict for it, and produced `resolvedValue` from `input` by that one
12021
+ * replacement ({@link singleSpanFrame} over `input` with the token and value
12022
+ * equal). That is the observed equation `resolvedValue = input[token := value]`;
12023
+ * it says nothing about what a later lookup of the token returns.
12024
+ *
12025
+ * The `secret` test and the COUNT are independent. The count refuses a
12026
+ * replacement listed ahead of the one the frame names that left its plaintext,
12027
+ * not its token, in `input` -- a used Sub variable holding the SAME token as
12028
+ * the template (`port:T${V}` with `V` = `T`), whose first replacement passes
12029
+ * the token and value tests while `input` keeps the variable's plaintext.
12030
+ * `complete`, `output` and the token and value tests are implied, for every
12031
+ * shape the resolver records, by the count and `singleSpanFrame` over `input`:
12032
+ * a token left unreplaced in `input` is a second span, and a frame that fits
12033
+ * `input` around the one replacement fixes the output it produces. They are
12034
+ * kept so a recorder that is not faithful refuses rather than certifies, and
12035
+ * are pinned by hand-built records only.
12036
+ */
12037
+ function substitutedSpellingOf(secrets, source, resolvedValue) {
12038
+ const resolution = intrinsicLeafResolutionsOf.get(secrets)?.get(source);
12039
+ if (resolution === void 0 || resolution === CONFLICTING_LEAF_RESOLUTION) return void 0;
12040
+ if (!resolution.complete || resolution.output !== resolvedValue) return void 0;
12041
+ if (resolution.substitutions.length !== 1) return void 0;
12042
+ const [substitution] = resolution.substitutions;
12043
+ if (!substitution.secret) return void 0;
12044
+ const frame = singleSpanFrame(resolvedValue, resolution.input);
12045
+ if (frame === void 0) return void 0;
12046
+ if (frame.token !== substitution.token || frame.middle !== substitution.value) return void 0;
12047
+ for (const plaintext of secrets.keys()) if (plaintext !== "" && (frame.prefix.includes(plaintext) || frame.suffix.includes(plaintext))) return;
12048
+ return resolution.input;
12049
+ }
11938
12050
  /**
11939
12051
  * The bag OBJECTS a deploy pass produced ITSELF and installed on a success
11940
12052
  * path — the fact the resolved-pair evidence above cannot state (issue
@@ -12886,8 +12998,9 @@ const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
12886
12998
  * literal source; pinned by the "map NO RESOLVER populated" case,
12887
12999
  * where (ii) and (iii) both pass and only the missing pair refuses.
12888
13000
  * On an OBJECT source (`Fn::Join` / `Fn::Sub`, issue #3062) there is
12889
- * no source text to compare, so the spelling is what the pass WROTE,
12890
- * admitted only when `positioned[name] !== resolvedValue`. Sound
13001
+ * no source text to compare, so the spelling-based arm takes what
13002
+ * the pass WROTE, admitted only when `positioned[name] !==
13003
+ * resolvedValue`. Sound
12891
13004
  * together with (ii), not alone: on a value the scan is silent on,
12892
13005
  * the cross-stack and skeleton arms both refuse (each requires the
12893
13006
  * WHOLE leaf to be a key of the map, which would make the scan's
@@ -12895,16 +13008,23 @@ const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
12895
13008
  * scan leaves the leaf alone -- so the frame arm is the only writer
12896
13009
  * that can have rewritten it, on its pair and the engine's mark. A
12897
13010
  * frame that is not wholly literal makes that arm refuse, the leaf
12898
- * comes back unrewritten, and (i) refuses too. The object arm
12899
- * certifies only a source whose OWN rendered token starts with a
13011
+ * comes back unrewritten, and this arm refuses too. It certifies
13012
+ * only a source whose OWN rendered token starts with a
12900
13013
  * spelled-secret prefix (`secretsmanager:` / `ssm-secure:`), read from
12901
13014
  * the source and never from what the pass wrote: the frame arm
12902
13015
  * matches among RECORDED references and a public `ssm` parameter
12903
13016
  * records none, so a public leaf whose source spells `ssm:`, or leaves
12904
13017
  * the service to an intrinsic part, can match a recorded secret
12905
- * sibling and be written as the sibling's reference. A SecureString
12906
- * spelled either way is indistinguishable here, so both are refused
12907
- * (see (e)). The STATE-derived
13018
+ * sibling and be written as the sibling's reference. Where it refuses,
13019
+ * the PROVENANCE arm (issue #3156) certifies on the leaf's own
13020
+ * resolution instead: the resolver records, per `Fn::Join` /
13021
+ * `Fn::Sub` object and pass bag, every token it replaced with the
13022
+ * verdict that replacement took, and one SECRET replacement that turns
13023
+ * the record's input into the value certifies that input as the
13024
+ * spelling -- an `ssm:` or intrinsic-service token, and a frame whose
13025
+ * non-literal part sits OUTSIDE the token, which the frame arm never
13026
+ * writes. `frameSpellingOf` states what it proves and what it does
13027
+ * not. The STATE-derived
12908
13028
  * call sites reach this arm as well: `cdkd import` can leave raw
12909
13029
  * intrinsics in a record's `properties`, which a rollback replay
12910
13030
  * passes as its source, and the frame arm does not read `rules`.
@@ -12940,10 +13060,9 @@ const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
12940
13060
  * (i)-(iii) on its own), a leaf (iii) refused under a different
12941
13061
  * frame, an object spelling the frame arm refused and a plain
12942
13062
  * literal equal to the value all fail it and would take the entry's
12943
- * frame (an object spelling the arm POSITIONED whose own source
12944
- * spells a secret service is a frame like a literal one, issue
12945
- * #3062; one whose source does not counts as unframed) -- and so
12946
- * would a
13063
+ * frame (an object spelling (i) certified is a frame like a literal
13064
+ * one, issues #3062 and #3156; one it refused counts as unframed) --
13065
+ * and so would a
12947
13066
  * same-frame sibling whose token this pass never resolved to the
12948
13067
  * middle: a PUBLIC `ssm` reference in the same `port:` frame holding
12949
13068
  * the same two characters is kept RESOLVED on the record, and the
@@ -12952,7 +13071,13 @@ const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
12952
13071
  * the row are gathered BEFORE the conditions run, a spelling that is
12953
13072
  * not a single-span literal frame with this pass's pair for its token
12954
13073
  * (`resolvedPlaintextOf`) counting as its own, and a value is
12955
- * recorded only when its certified frame is the row's only one.
13074
+ * recorded only when its certified frame is the row's only one. A
13075
+ * value one of whose leaves the position pass did NOT write (the
13076
+ * provenance arm's outside-the-token frame) also counts as unframed
13077
+ * unless every framed spelling of it carries ONE token: the frame arm
13078
+ * refuses that leaf on the parent's record, so the entry is written
13079
+ * onto it by the value scan whatever its token, and (iii)'s rescue
13080
+ * for a same-frame sibling does not reach it.
12956
13081
  * (v) No OTHER string leaf of the ROW would be rewritten by the entry,
12957
13082
  * read over every leaf of the resolved row since the bag is per
12958
13083
  * resource, not per `Parameters`. Two arms of the persist walk read
@@ -13038,16 +13163,29 @@ const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
13038
13163
  * persists the plaintext -- the same class as the nonliteral-frame deferral.
13039
13164
  * (e) CLOSED for a wholly literal frame by (i)'s object arm (issue #3062;
13040
13165
  * was: an `Fn::Join` / `Fn::Sub` source in the parent's own `Parameters`
13041
- * block was never carried). What remains of it: an object source whose frame
13042
- * is NOT wholly literal -- a region `Ref` outside the token -- is refused by
13043
- * the frame arm, so (i) refuses it and the child leaf keeps the plaintext,
13044
- * the same nonliteral-frame deferral the parent's own record has; and an
13045
- * intrinsic frame whose token spells `ssm:`, or leaves its service to an
13046
- * intrinsic part, is refused by (i) whatever the parameter's type, so a 1-3
13047
- * character SecureString spelled that way keeps the plaintext in the child
13048
- * too. That refusal is what keeps the frame arm's own wrong-reference
13049
- * residual -- a public leaf matching a recorded sibling -- on the parent's
13050
- * record instead of carrying it into the child's. (f) A child record persisted BEFORE this carry
13166
+ * block was never carried), and for the two spellings that arm refused -- a
13167
+ * token spelling `ssm:` or leaving its service to an intrinsic part, and a
13168
+ * frame whose non-literal part sits outside the token -- by its provenance
13169
+ * arm (issue #3156), which on the second also rewrites the PARENT's record of
13170
+ * the leaf through the entry. What remains of it: a leaf whose own resolution
13171
+ * does not certify -- the token spelled inside a NESTED intrinsic part (the
13172
+ * outer object's own text spells none), the token held by a used `Fn::Sub`
13173
+ * variable (the template spells a placeholder there), a leaf resolved two
13174
+ * different ways in one pass, one whose replacement took a public verdict, one
13175
+ * that replaced more than one token, one whose affix holds a plaintext the bag
13176
+ * holds (another secret a non-literal part resolved), an `Fn::If` around the
13177
+ * object (which the skeleton cannot render, and whose record is under the
13178
+ * selected branch) -- keeps the plaintext in the child, and for the
13179
+ * outside-the-token frame in the parent's record; so does an outside-the-token
13180
+ * frame sharing its value with a leaf of another token, which (iv) refuses. A
13181
+ * rollback replay records nothing here (`resolveReplayProps` resolves strings,
13182
+ * not intrinsic objects): a journal a deploy wrote holds a carried frame's
13183
+ * persisted spelling as a STRING, which the literal arm reads, while a record
13184
+ * `cdkd import` left holding the raw intrinsic stays refused on this arm
13185
+ * (go-to-k/cdkd#3306 tracks the refused shapes). Any other resolved
13186
+ * text a non-literal part contributes is carried verbatim in the spelling, as
13187
+ * the value already carries it.
13188
+ * (f) A child record persisted BEFORE this carry
13051
13189
  * keeps `port:q7` until the child is next redeployed: the parent's own row
13052
13190
  * already held the frame (the literal or frame arm), so a parent deploy whose child
13053
13191
  * row is unchanged never re-runs the child, and `cdkd scrub` cannot repair
@@ -13083,12 +13221,19 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
13083
13221
  }
13084
13222
  const framesByValue = /* @__PURE__ */ new Map();
13085
13223
  const tokensOf = /* @__PURE__ */ new Map();
13086
- const frameSpellingOf = (name, resolvedValue) => {
13224
+ const frameSpellings = /* @__PURE__ */ new Map();
13225
+ const frameSpellingOf = (name) => {
13226
+ if (!frameSpellings.has(name)) frameSpellings.set(name, computeFrameSpelling(name));
13227
+ return frameSpellings.get(name);
13228
+ };
13229
+ const computeFrameSpelling = (name) => {
13230
+ const resolvedValue = resolvedParameters[name];
13231
+ if (typeof resolvedValue !== "string") return void 0;
13087
13232
  const sourceLeaf = sourceParameters[name];
13088
13233
  if (typeof sourceLeaf === "string") return sourceLeaf;
13089
13234
  if (!isPlainObject$2(sourceLeaf)) return void 0;
13090
13235
  const written = positioned[name];
13091
- if (typeof written !== "string" || written === resolvedValue) return void 0;
13236
+ if (typeof written !== "string") return void 0;
13092
13237
  const segments = intrinsicSkeletonSegments(sourceLeaf);
13093
13238
  if (segments === void 0) return void 0;
13094
13239
  const rendered = segments.map((s) => s === UNKNOWN_PART ? UNKNOWN_PART_PLACEHOLDER : s).join("");
@@ -13096,16 +13241,20 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
13096
13241
  if (spans.length !== 1) return void 0;
13097
13242
  const [span] = spans;
13098
13243
  const ownToken = rendered.slice(span.start, span.end);
13099
- return SPELLED_SECRET_REFERENCE_PREFIXES.some((prefix) => ownToken.startsWith(prefix)) ? written : void 0;
13244
+ if (written !== resolvedValue && SPELLED_SECRET_REFERENCE_PREFIXES.some((prefix) => ownToken.startsWith(prefix))) return written;
13245
+ const substituted = substitutedSpellingOf(secrets, sourceLeaf, resolvedValue);
13246
+ if (substituted === void 0) return void 0;
13247
+ return written === resolvedValue || written === substituted ? substituted : void 0;
13100
13248
  };
13101
- const certifiedSpellingOf = (name, resolvedValue) => {
13249
+ const certifiedSpellingOf = (name) => {
13102
13250
  const sourceLeaf = sourceParameters[name];
13103
13251
  if (typeof sourceLeaf === "string") return positioned[name] === sourceLeaf ? sourceLeaf : void 0;
13104
- return frameSpellingOf(name, resolvedValue);
13252
+ return frameSpellingOf(name);
13105
13253
  };
13254
+ const unwrittenValues = /* @__PURE__ */ new Set();
13106
13255
  for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
13107
13256
  if (typeof resolvedValue !== "string") continue;
13108
- const spelling = frameSpellingOf(name, resolvedValue);
13257
+ const spelling = frameSpellingOf(name);
13109
13258
  const frame = spelling === void 0 ? void 0 : singleSpanFrame(resolvedValue, spelling);
13110
13259
  const frames = framesByValue.get(resolvedValue) ?? /* @__PURE__ */ new Set();
13111
13260
  const unframed = frame === void 0 || resolvedPlaintextOf(secrets, frame.token) !== frame.middle;
@@ -13115,8 +13264,10 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
13115
13264
  const tokens = tokensOf.get(resolvedValue) ?? /* @__PURE__ */ new Set();
13116
13265
  tokens.add(frame.token);
13117
13266
  tokensOf.set(resolvedValue, tokens);
13267
+ if (typeof sourceParameters[name] !== "string" && positioned[name] !== spelling) unwrittenValues.add(resolvedValue);
13118
13268
  }
13119
13269
  }
13270
+ for (const value of unwrittenValues) if (tokensOf.get(value)?.size !== 1) framesByValue.get(value)?.add(UNFRAMED_SPELLING);
13120
13271
  const rowWithoutParameters = {};
13121
13272
  for (const [key, value] of Object.entries(resolvedProperties)) if (key !== "Parameters") rowWithoutParameters[key] = value;
13122
13273
  const outsideLeaves = wholeStringLeavesOf(rowWithoutParameters);
@@ -13124,7 +13275,7 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
13124
13275
  const framedByName = [];
13125
13276
  for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
13126
13277
  if (typeof resolvedValue !== "string") continue;
13127
- const spelling = certifiedSpellingOf(name, resolvedValue);
13278
+ const spelling = certifiedSpellingOf(name);
13128
13279
  if (spelling === void 0) continue;
13129
13280
  if (redactSecretsForState(resolvedValue, secrets) !== resolvedValue) continue;
13130
13281
  const frame = singleSpanFrame(resolvedValue, spelling);
@@ -17884,7 +18035,7 @@ function getCreateOnlyPropertyPaths(resourceType) {
17884
18035
  if (cached) return cached;
17885
18036
  const entry = fetchCreateOnlyPropertyPaths(resourceType).catch((error) => {
17886
18037
  createOnlyPropertiesCache.delete(resourceType);
17887
- const message = error instanceof Error ? error.message : String(error);
18038
+ const message = describeAwsFailure(error).detail;
17888
18039
  getLogger().child("CreateOnlyProperties").warn(`Failed to resolve create-only properties for ${resourceType} via cloudformation:DescribeType (${message}). Falling back to the registry-only replacement classification for this resource — an immutable-property change may be mis-classified as an in-place update. Grant cloudformation:DescribeType to enable schema-driven replacement detection.`);
17889
18040
  return [];
17890
18041
  });
@@ -21389,6 +21540,39 @@ function stackClause(stackName, region) {
21389
21540
  const where = region === void 0 ? "" : ` (${shellQuote(safeIdentifier(region))})`;
21390
21541
  return `State for ${shellQuote(safeIdentifier(stackName))}${where}`;
21391
21542
  }
21543
+ /**
21544
+ * The DESTRUCTIVE remedy, built the way {@link inspectCommand} builds the
21545
+ * read-only one, and the region clause follows the SAME rule for two reasons
21546
+ * that pull in opposite directions.
21547
+ *
21548
+ * With a region in hand the flag is not decoration: `cdkd state orphan <stack>`
21549
+ * without it drops the record for that stack name in EVERY region, so omitting
21550
+ * it hands a stuck operator something wider than the message describes.
21551
+ *
21552
+ * With NO region the flag is worse than useless, and a placeholder is the worst
21553
+ * of the three: an absent region means a v1 record, which predates the
21554
+ * region-prefixed key layout, so `--stack-region <region>` selects no record at
21555
+ * all whatever the operator fills in. The bare command is the correct one
21556
+ * there, because such a record is not region-partitioned.
21557
+ *
21558
+ * With no trusted STACK the whole thing degrades to a template, as the inspect
21559
+ * command does — there is nothing to substitute.
21560
+ *
21561
+ * **It diverges from {@link malformedDestroyResourcesRefusalMessage}, which
21562
+ * keeps `cdkd state orphan` a template on purpose, and the difference is where
21563
+ * the identity comes from.** That builder is reached with a record-derived
21564
+ * REGION (`state.region ?? ctx.baseRegion` in `destroy-runner.ts`) -- its stack
21565
+ * name is the caller's, so the region alone is what would aim a destructive
21566
+ * command using a value the record supplied. This one is reached only with the caller's
21567
+ * synthesized stack and `pickStackRegion`'s answer, so substituting is safe and
21568
+ * omitting the region is the wider action. Two opposite precedents in one
21569
+ * module; neither is the general rule.
21570
+ */
21571
+ function dropRecordCommand(stackName, region) {
21572
+ if (stackName === void 0 || stackName === "") return "cdkd state orphan <stack> --stack-region <region>";
21573
+ const flag = region === void 0 || region === "" ? "" : ` --stack-region ${shellQuote(safeIdentifier(region))}`;
21574
+ return `cdkd state orphan ${shellQuote(safeIdentifier(stackName))}${flag}`;
21575
+ }
21392
21576
  /** The remedy command {@link stackClause}'s message ends on. */
21393
21577
  function inspectCommand(stackName, region) {
21394
21578
  if (stackName === void 0) return "cdkd state show <stack> --stack-region <region> --json";
@@ -21463,12 +21647,19 @@ function unreadableResourcePropertyBags(state) {
21463
21647
  *
21464
21648
  * Deliberately NOT folded into {@link refuseMalformedState}, for the reason
21465
21649
  * {@link unreadableResourcePropertyBags} gives: that predicate answers a
21466
- * question about the record ROOT, and its four callers (`cdkd scrub`,
21467
- * `import`, `orphan`, `rollback`) have made no decision about this one. Three
21468
- * of them do not compare properties at all, and `cdkd rollback` replays a
21469
- * journal rather than diffing, so an unrelated broken bag would stop the
21470
- * command documented as the way to UNWIND a stack whose state is already
21471
- * suspect. This rule is OPT-IN, taken by the flow that COMPARES the bag.
21650
+ * question about the record ROOT, and its callers have each had to make their
21651
+ * own decision about this one. `cdkd rollback` replays a journal rather than
21652
+ * diffing, so an unrelated broken bag would stop the command documented as the
21653
+ * way to UNWIND a stack whose state is already suspect; `cdkd scrub` and
21654
+ * `cdkd import` do not compare properties at all.
21655
+ *
21656
+ * **The rule is OPT-IN PER CALLER, not "whoever COMPARES the bag"**, and an
21657
+ * earlier revision of this sentence said the latter — which go-to-k/cdkd#3318
21658
+ * falsified within two lanes. `cdkd orphan` compares nothing and still opts in
21659
+ * through {@link refuseMalformedResourcePropertiesForOrphan}, because it SAVES
21660
+ * the bag; what each caller owes is an answer to "what would I do with a map I
21661
+ * cannot read", and comparison is only one way to owe one. Do not read this
21662
+ * paragraph as licence to delete a call from a caller that does not diff.
21472
21663
  */
21473
21664
  function refuseMalformedResourceProperties(state, stackName, region) {
21474
21665
  const unreadable = unreadableResourcePropertyBags(state);
@@ -21575,7 +21766,7 @@ function namedPropertyBagsClause(stackName, region, logicalIds) {
21575
21766
  /**
21576
21767
  * The text {@link refuseMalformedResourceProperties} raises.
21577
21768
  *
21578
- * `stackName` / `region` are the CALLER's resolved identity or nothing at all;
21769
+ * `rawStackName` / `rawRegion` are the CALLER's resolved identity or nothing at all;
21579
21770
  * {@link stackClause} is the authority for why this one may be handed neither.
21580
21771
  *
21581
21772
  * **It must be true under `cdkd deploy --dry-run` as well**, and the first
@@ -21604,6 +21795,155 @@ function malformedResourcePropertiesRefusalMessage(stackName, region, logicalIds
21604
21795
  return `${namedPropertyBagsClause(stackName, region, logicalIds)} 'cdkd deploy' can WRITE state and AWS resources, so it refuses rather than continuing — under '--dry-run' too, because the plan a dry run would print is the wrong one: a DELETE and re-create of resources the template did not change, and reading the bag as empty produces that same verdict rather than avoiding it. Nothing was provisioned and no state was written FOR THIS STACK. Repair or remove the record first; 'cdkd diff' previews the rest of the stack with those maps read as EMPTY and warns that it did. Inspect the record with: ${inspectCommand(stackName, region)}`;
21605
21796
  }
21606
21797
  /**
21798
+ * The `cdkd orphan` refusal text for the per-entry `properties` container
21799
+ * (issue [#3318](https://github.com/go-to-k/cdkd/issues/3318)).
21800
+ *
21801
+ * A SECOND `properties` refusal beside
21802
+ * {@link malformedResourcePropertiesRefusalMessage}, for the reason every
21803
+ * split in this module is its own: that text describes the DIFF's verdict —
21804
+ * "a DELETE and re-create of resources the template did not change" — which
21805
+ * `cdkd orphan` never computes. It runs no diff at all.
21806
+ *
21807
+ * **And the harm here is NOT the laundering the module's other write-capable
21808
+ * refusals describe.** Measured 2026-09-17 through the real
21809
+ * `rewriteResourceReferences` over an `AWS::S3::Bucket` record: `rewriteValue`
21810
+ * returns a non-object verbatim, so a stored `"abcdef"` comes back as
21811
+ * `"abcdef"`, a `5` as `5`, a `null` as `null`, and an ABSENT bag stays absent
21812
+ * once `JSON.stringify` drops it. Nothing is fabricated and no evidence is
21813
+ * replaced — so {@link malformedOutputsRefusalMessage}'s "saved back as a
21814
+ * well-formed six-key map" sentence, true one container over, would be FALSE
21815
+ * here and must not be borrowed.
21816
+ *
21817
+ * What it DOES share is {@link namedPropertyBagsClause}, which carries a
21818
+ * diff-shaped sentence of its own ("a create-only property among them is a
21819
+ * REPLACEMENT of the live resource"). That is not a contradiction and is not
21820
+ * an oversight: the shared clause describes what the RECORD is, and the reason
21821
+ * an operator must care is precisely that a later `cdkd deploy` / `cdkd diff`
21822
+ * reaches that verdict. What this text must not do — and what its fence pins —
21823
+ * is claim that verdict as its OWN, since `cdkd orphan` computes no diff.
21824
+ *
21825
+ * What IS at stake is the command's own job. `cdkd orphan` exists to leave the
21826
+ * record deployable: it rewrites every surviving sibling's `Ref` /
21827
+ * `Fn::GetAtt` / `Fn::Sub` reference to an orphan so the next deploy neither
21828
+ * re-creates the orphan nor fails on a stale reference. Over a map it cannot
21829
+ * read it cannot do that and cannot say it did not. A scalar bag presents no
21830
+ * reference to find, so the `--force`-less hard fail on unresolvable
21831
+ * references can never fire for one; a LIST bag is the one unreadable shape
21832
+ * `rewriteValue` DOES walk (measured: a stored `[{"Ref":"<orphan>"}]` came
21833
+ * back as `["<physicalId>"]` with one row in the audit table), so its rewrites
21834
+ * are reported into a container that is still not a map. Either way the
21835
+ * command takes a lock, saves, and reports success over a record left in
21836
+ * exactly the state `cdkd deploy` REFUSES
21837
+ * ({@link malformedResourcePropertiesRefusalMessage}) and `cdkd diff` previews
21838
+ * as a replacement — one command after the evidence was last in cdkd's hands.
21839
+ *
21840
+ * **The refusal is SCOPED to the records the save would KEEP, so orphaning the
21841
+ * DAMAGED record itself still works** —
21842
+ * {@link refuseMalformedResourcePropertiesForOrphan} is handed the ids being
21843
+ * removed and never names one. Compare
21844
+ * `malformedDestroyResourcesRefusalMessage`, which has to point at a different
21845
+ * COMMAND for its way out because a destroy keeps every record it reads.
21846
+ *
21847
+ * **But that in-command way out is CONDITIONAL, and the text must say so.**
21848
+ * `cdkd orphan` addresses resources only through the `aws:cdk:path` index of
21849
+ * the SYNTHESIZED template (`resolveConstructPaths` →
21850
+ * `buildCdkPathIndex`), so an id the CDK app no longer declares — a record
21851
+ * left behind when the construct was deleted, or one a hand edit invented —
21852
+ * can never enter the orphan set for ANY invocation. The exemption therefore
21853
+ * cannot reach it, and an earlier revision of this text nonetheless told the
21854
+ * operator to "orphan the damaged record ITSELF" unconditionally: an
21855
+ * instruction that dies on `Construct path '...' not found in template`, which
21856
+ * is the misstating-the-remedy class this module's own notes record (security
21857
+ * review of go-to-k/cdkd#3318). The remedy is now stated with its condition and
21858
+ * the two unconditional ways out beside it — hand repair, and
21859
+ * `cdkd state orphan <stack>`, which needs no CDK app and drops the whole
21860
+ * record with the live resources left standing.
21861
+ *
21862
+ * So the recovery-path objection is answered for the common case by the
21863
+ * exemption and for the rest by naming commands that do not depend on the
21864
+ * template. What this does NOT claim is that `cdkd orphan` stays usable on a
21865
+ * stack holding a template-less torn record: it does not, exactly as
21866
+ * `cdkd deploy` does not (go-to-k/cdkd#3191). A state-keyed escape hatch
21867
+ * (`--orphan-logical-id`, addressing a record by its state key rather than by
21868
+ * a construct path) was considered in the same review and DECLINED: it is a new
21869
+ * mutating CLI surface whose only job is to route around a record the operator
21870
+ * must repair or drop anyway, and `cdkd state orphan <stack>` already removes
21871
+ * such a record with no CDK app and no new flag.
21872
+ *
21873
+ * It must be true under `--dry-run` as well, and it is: the guard sits at the
21874
+ * load, far above the `if (options.dryRun)` return. Refusing there is
21875
+ * {@link malformedResourcePropertiesRefusalMessage}'s call for the same
21876
+ * reason — a plausible rewrite audit table followed by a refusal the moment
21877
+ * the flag comes off is the worst arm of all.
21878
+ *
21879
+ * `rawStackName` / `rawRegion` are the CALLER's resolved identity — the synthesized
21880
+ * stack name and the region `pickStackRegion` settled on, never the record's
21881
+ * own unvalidated self-report. See {@link stackClause}.
21882
+ */
21883
+ function malformedOrphanResourcePropertiesRefusalMessage(rawStackName, rawRegion, logicalIds) {
21884
+ const stackName = rawStackName === "" ? void 0 : rawStackName;
21885
+ const region = rawRegion === "" ? void 0 : rawRegion;
21886
+ return `${namedPropertyBagsClause(stackName, region, logicalIds)} 'cdkd orphan' REWRITES and SAVES every record it keeps, so it refuses rather than continuing — under '--dry-run' too, because the rewrite audit table a dry run prints is the wrong one. It is not that the save would fabricate a map: an unreadable bag is carried through VERBATIM. It is that this command exists to leave the record deployable by rewriting every reference to an orphaned resource, and a map it cannot read hides whichever references it holds — a string or a number presents none to find, and a list is walked, so its rewrites are recorded into a container that is still not a map. Continuing would rewrite, save, and report success over a record 'cdkd deploy' then REFUSES. No state was written. Two ways out need no CDK app: repair the record by hand, or drop it whole with '${dropRecordCommand(stackName, region)}', which leaves the live AWS resources standing. A third works only while the CDK app STILL DECLARES the named resource — this refusal covers just the records that would SURVIVE the save, so 'cdkd orphan <its construct path>' removes it and repairs the rest; construct paths come from the synthesized template, so a resource the app no longer declares has none and must take one of the first two. Inspect the record with: ${inspectCommand(stackName, region)}`;
21887
+ }
21888
+ /**
21889
+ * For `cdkd orphan`: refuse a record whose SURVIVING resource entries carry a
21890
+ * `properties` bag that cannot be read (issue
21891
+ * [#3318](https://github.com/go-to-k/cdkd/issues/3318)).
21892
+ *
21893
+ * A separate call from {@link refuseMalformedResourceProperties} rather than a
21894
+ * flag on it, for the reason {@link refuseMalformedOutputsForDestroy} is
21895
+ * separate from {@link refuseMalformedOutputs}: the refusal a user sees must
21896
+ * describe what THIS command would have done with the bag, and
21897
+ * {@link malformedOrphanResourcePropertiesRefusalMessage} records how far the
21898
+ * two consequences diverge.
21899
+ *
21900
+ * `removedLogicalIds` is the orphan set — the ids this run is dropping from
21901
+ * `state.resources`. They are EXCLUDED from the verdict because the save
21902
+ * cannot persist a record it is deleting, and because refusing on one would
21903
+ * break the recovery path the refusal is otherwise meant to preserve.
21904
+ *
21905
+ * **It covers `state.resources` ONLY, and the save keeps more than that.**
21906
+ * `rewriteResourceReferences` spreads `carriedState`, so `state.orphans[]` —
21907
+ * rollback-orphaned records each holding a whole `ResourceState`
21908
+ * (go-to-k/cdkd#2934) — rides through untouched, and
21909
+ * {@link unreadableResourcePropertyBags} never walks it. A torn bag parked
21910
+ * there is therefore still saved, and `computeStackDiff` splices those records
21911
+ * into `state.resources` on the next preview. Stated rather than implied,
21912
+ * because "the records the save would KEEP" reads wider than what this scans:
21913
+ * the gap is go-to-k/cdkd#3344, filed rather than folded in because the remedy
21914
+ * differs — an entry in that container has no construct path, so the message's
21915
+ * third way out is meaningless for it.
21916
+ *
21917
+ * **A surviving ENTRY that is not a map is the other gap, and it DOES launder.**
21918
+ * This scan asks whether a resource's `properties` is readable; it never asks
21919
+ * whether the resource RECORD is. `isReadableBag('abcdef')` is false, so a
21920
+ * string entry is skipped here, and then `rewriteResourceReferences`'s
21921
+ * `{ ...resource }` spreads it into per-character keys — the record is SAVED as
21922
+ * `{"0":"a",…,"dependencies":[]}` and the run reports success. A number entry
21923
+ * saves as `{"dependencies":[]}`, a record with no `physicalId`. So the
21924
+ * refusal's own text, which says a torn `properties` map is persisted verbatim
21925
+ * rather than reshaped, is true of the container it scans and NOT of the one
21926
+ * above it.
21927
+ *
21928
+ * That gap is NOT go-to-k/cdkd#3202's as filed — that issue records only the
21929
+ * `null`-entry `TypeError` — and NOT open PR go-to-k/cdkd#3226's, whose file
21930
+ * list carries neither `orphan.ts` nor `orphan-rewriter.ts`. A lane closing
21931
+ * either one leaves this open, which is why it is named here rather than
21932
+ * deferred to them by reference. Filed as go-to-k/cdkd#3350.
21933
+ *
21934
+ * CALL IT AT THE LOAD, beside {@link refuseMalformedState} and
21935
+ * {@link refuseMalformedOutputs}, above `rewriteResourceReferences` — the
21936
+ * placement rule {@link repairMalformedResourcesForReadOnly}'s note records.
21937
+ * The orphan set is resolved from the synthesized template before the state is
21938
+ * loaded, so nothing forces this call any lower.
21939
+ */
21940
+ function refuseMalformedResourcePropertiesForOrphan(state, removedLogicalIds, stackName, region) {
21941
+ const removed = new Set(removedLogicalIds);
21942
+ const unreadable = unreadableResourcePropertyBags(state).filter((id) => !removed.has(id));
21943
+ if (unreadable.length === 0) return;
21944
+ throw new CdkdError(malformedOrphanResourcePropertiesRefusalMessage(stackName, region, unreadable), STATE_RESOURCES_MALFORMED);
21945
+ }
21946
+ /**
21607
21947
  * The warning a caller of {@link repairMalformedResourcePropertiesForReadOnly}
21608
21948
  * emits.
21609
21949
  */
@@ -24554,7 +24894,7 @@ var WAFv2WebACLProvider = class {
24554
24894
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$11({ ResourceARN: physicalId }));
24555
24895
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagInfoForResource?.TagList);
24556
24896
  } catch (err) {
24557
- this.logger.debug(`WAFv2 ListTagsForResource(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
24897
+ this.logger.debug(`WAFv2 ListTagsForResource(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
24558
24898
  }
24559
24899
  return result;
24560
24900
  }
@@ -26778,8 +27118,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
26778
27118
  const obj = value;
26779
27119
  if ("Ref" in obj) return await this.resolveRef(obj["Ref"], context);
26780
27120
  if ("Fn::GetAtt" in obj) return await this.resolveGetAtt(obj["Fn::GetAtt"], context);
26781
- if ("Fn::Join" in obj) return await this.resolveJoin(obj["Fn::Join"], context);
26782
- if ("Fn::Sub" in obj) return await this.resolveSub(obj["Fn::Sub"], context);
27121
+ if ("Fn::Join" in obj) return await this.resolveJoin(obj["Fn::Join"], context, obj);
27122
+ if ("Fn::Sub" in obj) return await this.resolveSub(obj["Fn::Sub"], context, obj);
26783
27123
  if ("Fn::Select" in obj) return await this.resolveSelect(obj["Fn::Select"], context);
26784
27124
  if ("Fn::Split" in obj) return await this.resolveSplit(obj["Fn::Split"], context);
26785
27125
  if ("Fn::If" in obj) return await this.resolveIf(obj["Fn::If"], context);
@@ -27875,32 +28215,45 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27875
28215
  *
27876
28216
  * Fn::Join: [delimiter, [value1, value2, ...]]
27877
28217
  */
27878
- async resolveJoin(joinArgs, context) {
28218
+ async resolveJoin(joinArgs, context, source) {
27879
28219
  const [delimiter, rawValues] = joinArgs;
27880
28220
  let values = rawValues;
27881
28221
  if (!Array.isArray(values)) values = await this.resolveValue(values, context);
27882
28222
  if (!Array.isArray(values)) throw new Error(`Fn::Join's second argument must be a list (an array literal or a list-returning intrinsic such as Fn::Cidr / Fn::GetAZs / Fn::Split / a Ref to a list-typed parameter — any List<...> type or CommaDelimitedList), but resolved to ${typeof values}`);
27883
28223
  const literalList = Array.isArray(rawValues);
27884
- const parts = (await allSettledKeepingFirstRejection(values.map(async (v) => {
27885
- if (typeof v === "string") return {
27886
- ...v.includes("{{resolve:") ? await this.resolveDynamicReferencesWithLogTwin(v, this.logTwinOfProduct({
28224
+ const resolvedParts = await allSettledKeepingFirstRejection(values.map(async (v) => {
28225
+ if (typeof v === "string") {
28226
+ const part = v.includes("{{resolve:") ? await this.resolveDynamicReferencesWithLogTwin(v, this.logTwinOfProduct({
27887
28227
  result: v,
27888
28228
  twin: v
27889
28229
  }, context).twin, context) : {
27890
28230
  result: v,
27891
- twin: v
27892
- },
27893
- product: !literalList
27894
- };
28231
+ twin: v,
28232
+ substitutions: [],
28233
+ complete: true
28234
+ };
28235
+ return {
28236
+ result: part.result,
28237
+ twin: part.twin,
28238
+ product: !literalList,
28239
+ input: v,
28240
+ substitutions: part.substitutions,
28241
+ complete: part.complete
28242
+ };
28243
+ }
27895
28244
  const raw = await this.resolveValue(v, context);
27896
28245
  const resolved = String(raw);
27897
28246
  return {
27898
28247
  result: resolved,
27899
28248
  twin: resolved,
27900
28249
  product: true,
27901
- raw: { value: raw }
28250
+ raw: { value: raw },
28251
+ input: resolved,
28252
+ substitutions: [],
28253
+ complete: true
27902
28254
  };
27903
- }), (pending) => this.warnAbandonedParts(pending))).map((part) => {
28255
+ }), (pending) => this.warnAbandonedParts(pending));
28256
+ const parts = resolvedParts.map((part) => {
27904
28257
  if (!part.product) return part;
27905
28258
  if (part.raw) return {
27906
28259
  result: part.result,
@@ -27910,7 +28263,20 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27910
28263
  });
27911
28264
  let result = parts.map((part) => part.result).join(delimiter);
27912
28265
  let twin = parts.map((part) => part.twin).join(delimiter);
27913
- if (result.includes("{{resolve:")) ({result, twin} = await this.resolveDynamicReferencesWithLogTwin(result, twin, context));
28266
+ const substitutions = resolvedParts.flatMap((part) => part.substitutions);
28267
+ let complete = resolvedParts.every((part) => part.complete);
28268
+ if (result.includes("{{resolve:")) {
28269
+ const joined = await this.resolveDynamicReferencesWithLogTwin(result, twin, context);
28270
+ ({result, twin} = joined);
28271
+ substitutions.push(...joined.substitutions);
28272
+ complete &&= joined.complete;
28273
+ }
28274
+ this.recordLeafResolution(context, source, {
28275
+ input: resolvedParts.map((part) => part.input).join(delimiter),
28276
+ output: result,
28277
+ substitutions,
28278
+ complete
28279
+ });
27914
28280
  this.rememberLogTwin(context, result, twin);
27915
28281
  this.logger.debug(`Resolved Fn::Join: ${this.maskSecretsForLog(this.logTwinText(result, twin, context), context)}`);
27916
28282
  return result;
@@ -28052,10 +28418,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28052
28418
  * inside replace(). For full async support, we'd need to collect all replacements
28053
28419
  * first, then do them synchronously.
28054
28420
  */
28055
- async resolveSub(subArgs, context) {
28421
+ async resolveSub(subArgs, context, source) {
28056
28422
  let template;
28057
28423
  const variables = Object.create(null);
28058
28424
  const variableTwins = Object.create(null);
28425
+ const variablePasses = Object.create(null);
28059
28426
  if (Array.isArray(subArgs)) {
28060
28427
  const [templateString, variableMap] = subArgs;
28061
28428
  template = templateString;
@@ -28063,10 +28430,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28063
28430
  for (const [key, val] of Object.entries(variableMap)) if (typeof val === "string") {
28064
28431
  const resolved = val.includes("{{resolve:") ? await this.resolveDynamicReferencesWithLogTwin(val, val, context) : {
28065
28432
  result: val,
28066
- twin: val
28433
+ twin: val,
28434
+ substitutions: [],
28435
+ complete: true
28067
28436
  };
28068
28437
  variables[key] = resolved.result;
28069
28438
  variableTwins[key] = resolved.twin;
28439
+ variablePasses[key] = resolved;
28070
28440
  } else variables[key] = context.abandonedResolutions === void 0 ? await this.resolveValue(val, context) : await this.resolveKeyUnit(key, val, context, context.abandonedResolutions);
28071
28441
  } else template = subArgs;
28072
28442
  const replacements = [];
@@ -28093,9 +28463,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28093
28463
  }
28094
28464
  let replacement;
28095
28465
  let twinReplacement;
28466
+ let pass;
28096
28467
  if (varNameStr in variables) {
28097
28468
  replacement = String(variables[varNameStr]);
28098
28469
  twinReplacement = varNameStr in variableTwins ? variableTwins[varNameStr] : this.productLogTwin(variables[varNameStr], context);
28470
+ if (varNameStr in variablePasses) pass = variablePasses[varNameStr];
28099
28471
  } else {
28100
28472
  const pseudoValue = await this.resolvePseudoParameter(varNameStr, context);
28101
28473
  if (pseudoValue !== void 0) replacement = String(pseudoValue);
@@ -28125,7 +28497,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28125
28497
  replacements.push({
28126
28498
  match: match[0],
28127
28499
  replacement,
28128
- twin: twinReplacement ?? replacement
28500
+ twin: twinReplacement ?? replacement,
28501
+ ...pass ? { pass } : {}
28129
28502
  });
28130
28503
  }
28131
28504
  let cursor = 0;
@@ -28138,7 +28511,21 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28138
28511
  const entry = replacements[twinCursor++];
28139
28512
  return entry ? entry.twin : whole;
28140
28513
  });
28141
- if (result.includes("{{resolve:")) ({result, twin} = await this.resolveDynamicReferencesWithLogTwin(result, twin, context));
28514
+ const input = result;
28515
+ const substitutions = replacements.flatMap((entry) => entry.pass?.substitutions ?? []);
28516
+ let complete = replacements.every((entry) => entry.pass?.complete ?? true);
28517
+ if (result.includes("{{resolve:")) {
28518
+ const substituted = await this.resolveDynamicReferencesWithLogTwin(result, twin, context);
28519
+ ({result, twin} = substituted);
28520
+ substitutions.push(...substituted.substitutions);
28521
+ complete &&= substituted.complete;
28522
+ }
28523
+ this.recordLeafResolution(context, source, {
28524
+ input,
28525
+ output: result,
28526
+ substitutions,
28527
+ complete
28528
+ });
28142
28529
  this.rememberLogTwin(context, result, twin);
28143
28530
  this.logger.debug(`Resolved Fn::Sub: ${this.maskSecretsForLog(this.logTwinText(result, twin, context), context)}`);
28144
28531
  return result;
@@ -29528,7 +29915,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29528
29915
  * not the bag holds pairs. Where the middle RE-WRAPS it (an `Fn::Join` around
29529
29916
  * the `Ref`) the middle registers its own twin, and the hand-off still drops
29530
29917
  * a bag holding no pairs (it passes `inheritedSecrets` only when `size` is
29531
- * nonzero). Both are issue #3156.
29918
+ * nonzero). What reaches a grandchild instead is the parent's WHOLE-VALUE
29919
+ * entry: the middle's `{ Ref }` copies it into the middle's bag, which is then
29920
+ * non-empty and handed down. Issue #3156 made the carry record that entry for
29921
+ * the intrinsic frames it used to refuse; a frame it still refuses (listed on
29922
+ * `recordNestedStackParameterExpressions`) keeps both gaps.
29532
29923
  *
29533
29924
  * The registry is keyed by VALUE, and `splitLogTwins`' unaligned arm
29534
29925
  * registers every piece, public ones included. So a child `Fn::Base64` over a
@@ -29578,6 +29969,17 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29578
29969
  };
29579
29970
  }
29580
29971
  /**
29972
+ * Record the `Fn::Join` / `Fn::Sub` object `source`'s own resolution under
29973
+ * the pass bag the nested-stack carry reads (issue
29974
+ * [#3156](https://github.com/go-to-k/cdkd/issues/3156)). The key is the
29975
+ * object `resolveValue` dispatched on, and a context with no bag has no pass
29976
+ * to scope it to.
29977
+ */
29978
+ recordLeafResolution(context, source, resolution) {
29979
+ if (context.recordedSecretValues === void 0) return;
29980
+ recordIntrinsicLeafResolution(context.recordedSecretValues, source, resolution);
29981
+ }
29982
+ /**
29581
29983
  * Register a MASKED `twin` as the log twin of `result` for this pass (issue
29582
29984
  * #3100). An unmasked twin is not registered, so a later literal that
29583
29985
  * resolves to the same string cannot replace an earlier write's mask, and
@@ -29715,6 +30117,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29715
30117
  const pattern = /\{\{resolve:([^}]+)\}\}/g;
29716
30118
  let result = value;
29717
30119
  let twin = logTwin;
30120
+ const substitutions = [];
30121
+ let complete = true;
29718
30122
  let match;
29719
30123
  const matches = [];
29720
30124
  while ((match = pattern.exec(value)) !== null) matches.push({
@@ -29730,7 +30134,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29730
30134
  const nameLogText = inherited?.nameLogText ?? (pairedTwin === void 0 ? () => "***" : this.dynamicReferenceNameLogText(inner, pairedTwin, context));
29731
30135
  try {
29732
30136
  const isKnownSecret = service === "secretsmanager" || service === "ssm-secure" || recordedSecretExpressions.has(fullMatch);
29733
- if (isKnownSecret && context?.skipDynamicReferences) continue;
30137
+ if (isKnownSecret && context?.skipDynamicReferences) {
30138
+ complete = false;
30139
+ continue;
30140
+ }
29734
30141
  const regionVerdict = classifyReplaySecretRegion(fullMatch, this.explicitRegion ?? this.resolverRegion, context?.producerRegions);
29735
30142
  if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${this.maskSecretsForLog(tokenLogText, context)}: it names '${this.maskSecretsForLog(nameLogText(regionVerdict.secretName), context)}' without a region, and this stack reads from ${this.maskSecretsForLog(regionVerdict.foreignProducerRegions.map((r) => this.maskSecretsForLog(r, context)).join(", "), context)} as well as its own region. cdkd cannot tell which one must answer, and resolving against the wrong one yields a different secret. Spell the reference as a full ARN to say which region owns it.`));
29736
30143
  if (regionVerdict.kind === "named-region") {
@@ -29740,6 +30147,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29740
30147
  });
29741
30148
  result = result.replace(fullMatch, () => foreign.result);
29742
30149
  twin = twin.replace(fullMatch, () => foreign.twin);
30150
+ const [delegated] = foreign.substitutions;
30151
+ substitutions.push({
30152
+ token: fullMatch,
30153
+ value: foreign.result,
30154
+ secret: foreign.substitutions.length === 1 && delegated.secret
30155
+ });
30156
+ if (!foreign.complete || foreign.substitutions.length !== 1) complete = false;
29743
30157
  continue;
29744
30158
  }
29745
30159
  const cached = this.cachedDynamicReferences.get(fullMatch);
@@ -29750,6 +30164,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29750
30164
  }
29751
30165
  result = result.replace(fullMatch, () => cached.value);
29752
30166
  twin = twin.replace(fullMatch, () => cached.secret && cached.value ? "***" : cached.value);
30167
+ substitutions.push({
30168
+ token: fullMatch,
30169
+ value: cached.value,
30170
+ secret: cached.secret
30171
+ });
29753
30172
  continue;
29754
30173
  }
29755
30174
  const parts = inner.split(":");
@@ -29777,7 +30196,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29777
30196
  else cacheable = false;
29778
30197
  isSecret = param.secure;
29779
30198
  if (param.secure) {
29780
- if (!decrypt) continue;
30199
+ if (!decrypt) {
30200
+ complete = false;
30201
+ continue;
30202
+ }
29781
30203
  }
29782
30204
  resolved = param.value;
29783
30205
  } else if (service === "ssm-secure") {
@@ -29787,6 +30209,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29787
30209
  resolved = param.value;
29788
30210
  } else {
29789
30211
  this.logger.warn(this.maskSecretsForLog(`Unsupported dynamic reference service: ${this.maskSecretsForLog(nameLogText(String(service)), context)}`, context));
30212
+ complete = false;
29790
30213
  continue;
29791
30214
  }
29792
30215
  if (cacheable) this.cachedDynamicReferences.set(fullMatch, {
@@ -29800,6 +30223,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29800
30223
  }
29801
30224
  result = result.replace(fullMatch, () => resolved);
29802
30225
  twin = twin.replace(fullMatch, () => isSecret && resolved ? "***" : resolved);
30226
+ substitutions.push({
30227
+ token: fullMatch,
30228
+ value: resolved,
30229
+ secret: isSecret
30230
+ });
29803
30231
  } catch (err) {
29804
30232
  if (context?.abandonedResolutions === void 0) throw err;
29805
30233
  if (isDeliberateResolutionRefusal(err)) throw err;
@@ -29812,13 +30240,16 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29812
30240
  }
29813
30241
  return out;
29814
30242
  }));
30243
+ complete = false;
29815
30244
  continue;
29816
30245
  }
29817
30246
  }
29818
30247
  if (context) this.rememberLogTwin(context, result, twin);
29819
30248
  return {
29820
30249
  result,
29821
- twin
30250
+ twin,
30251
+ substitutions,
30252
+ complete
29822
30253
  };
29823
30254
  }
29824
30255
  /**
@@ -30073,7 +30504,7 @@ async function disableInstanceApiTermination(client, instanceId, logger) {
30073
30504
  }));
30074
30505
  logger.debug(`Disabled DisableApiTermination on EC2 Instance ${instanceId} before deletion`);
30075
30506
  } catch (flipError) {
30076
- logger.debug(`Could not disable DisableApiTermination on ${instanceId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
30507
+ logger.debug(`Could not disable DisableApiTermination on ${instanceId}: ${describeAwsFailure(flipError).detail}`);
30077
30508
  }
30078
30509
  }
30079
30510
  /**
@@ -30385,7 +30816,7 @@ function getTopLevelWriteOnlyProperties(resourceType) {
30385
30816
  if (cached) return cached;
30386
30817
  const entry = fetchTopLevelWriteOnlyProperties(resourceType).catch((error) => {
30387
30818
  writeOnlyPropertiesCache.delete(resourceType);
30388
- const message = error instanceof Error ? error.message : String(error);
30819
+ const message = describeAwsFailure(error).detail;
30389
30820
  getLogger().child("WriteOnlyProperties").warn(`Failed to resolve write-only properties for ${resourceType} via cloudformation:DescribeType (${message}). Falling back to a minimal update patch — write-only properties (if any) may be dropped by the Cloud Control read-modify-write update. Grant cloudformation:DescribeType to enable write-only property re-inclusion.`);
30390
30821
  return /* @__PURE__ */ new Set();
30391
30822
  });
@@ -30511,7 +30942,7 @@ function getTopLevelReadOnlyProperties(resourceType) {
30511
30942
  if (cached) return cached;
30512
30943
  const entry = fetchTopLevelReadOnlyProperties(resourceType).catch((error) => {
30513
30944
  readOnlyPropertiesCache.delete(resourceType);
30514
- const message = error instanceof Error ? error.message : String(error);
30945
+ const message = describeAwsFailure(error).detail;
30515
30946
  getLogger().child("ReadOnlyProperties").debug(`Failed to resolve read-only properties for ${displaySafe(resourceType, { asciiOnly: true })} via cloudformation:DescribeType (${message}).`);
30516
30947
  });
30517
30948
  readOnlyPropertiesCache.set(resourceType, entry);
@@ -31729,7 +32160,7 @@ var CloudControlProvider = class {
31729
32160
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
31730
32161
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
31731
32162
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
31732
- const { ASGProvider } = await import("./asg-provider-B8GAVns4.js").then((n) => n.n);
32163
+ const { ASGProvider } = await import("./asg-provider-BOYln2Tw.js").then((n) => n.n);
31733
32164
  const asgProvider = new ASGProvider();
31734
32165
  return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
31735
32166
  }
@@ -34396,7 +34827,7 @@ var CustomResourceProvider = class CustomResourceProvider {
34396
34827
  }
34397
34828
  this.logger.debug(`Successfully deleted custom resource ${logicalId}`);
34398
34829
  } catch (error) {
34399
- this.logger.warn(`Failed to delete custom resource ${logicalId}, but continuing: ${error instanceof Error ? error.message : String(error)}. The Delete handler did not complete, so anything this custom resource manages may still be LIVE — cdkd is KEEPING the state record and the run exits non-zero. ${CR_SKIP_NOT_A_RETRY_CAVEAT} ${DEPLOY_SKIP_CAVEAT}`);
34830
+ this.logger.warn(`Failed to delete custom resource ${logicalId}, but continuing: ${describeAwsFailure(error).detail}. The Delete handler did not complete, so anything this custom resource manages may still be LIVE — cdkd is KEEPING the state record and the run exits non-zero. ${CR_SKIP_NOT_A_RETRY_CAVEAT} ${DEPLOY_SKIP_CAVEAT}`);
34400
34831
  return {
34401
34832
  outcome: "skipped",
34402
34833
  reason: CR_DELETE_INVOKE_FAILED_SKIP_REASON
@@ -34433,7 +34864,7 @@ var CustomResourceProvider = class CustomResourceProvider {
34433
34864
  return false;
34434
34865
  } catch (error) {
34435
34866
  if (error.name === "ResourceNotFoundException") return true;
34436
- this.logger.debug(`GetFunction pre-check for ${serviceToken} failed inconclusively (${error instanceof Error ? error.message : String(error)}); proceeding with the normal delete invoke`);
34867
+ this.logger.debug(`GetFunction pre-check for ${serviceToken} failed inconclusively (${describeAwsFailure(error).detail}); proceeding with the normal delete invoke`);
34437
34868
  return false;
34438
34869
  }
34439
34870
  }
@@ -34510,7 +34941,7 @@ var CustomResourceProvider = class CustomResourceProvider {
34510
34941
  } catch (error) {
34511
34942
  if (delivered || preDeliveryRetries >= this.preDeliveryAuthzMaxRetries || !this.isTransientAuthzThrow(error)) throw error;
34512
34943
  const delayMs = Math.min(250 * Math.pow(2, preDeliveryRetries), IAM_PROPAGATION_MAX_DELAY_MS);
34513
- this.logger.warn(`Custom resource ${operation} for ${logicalId} hit a transient IAM-authorization error before the request was delivered (attempt ${attempt + 1}/${this.preDeliveryAuthzMaxRetries + 1}): ${this.truncateReason(error instanceof Error ? error.message : String(error))}. Retrying in ${delayMs / 1e3}s with a fresh response URL and RequestId.`);
34944
+ this.logger.warn(`Custom resource ${operation} for ${logicalId} hit a transient IAM-authorization error before the request was delivered (attempt ${attempt + 1}/${this.preDeliveryAuthzMaxRetries + 1}): ${this.truncateReason(describeAwsFailure(error).detail)}. Retrying in ${delayMs / 1e3}s with a fresh response URL and RequestId.`);
34514
34945
  if (invocation !== void 0) await this.cleanupResponseObject(invocation.responseKey);
34515
34946
  preDeliveryRetries += 1;
34516
34947
  await this.sleepInterruptibly(delayMs, watch);
@@ -34712,7 +35143,7 @@ var CustomResourceProvider = class CustomResourceProvider {
34712
35143
  maxDelay: 5
34713
35144
  }, { FunctionName: serviceToken });
34714
35145
  } catch (error) {
34715
- this.logger.debug(`Could not recycle backing function for ${logicalId} (${error instanceof Error ? error.message : String(error)}); retrying invoke without a forced cold start`);
35146
+ this.logger.debug(`Could not recycle backing function for ${logicalId} (${describeAwsFailure(error).detail}); retrying invoke without a forced cold start`);
34716
35147
  }
34717
35148
  }
34718
35149
  /**
@@ -35061,7 +35492,7 @@ var CustomResourceProvider = class CustomResourceProvider {
35061
35492
  Key: responseKey
35062
35493
  }));
35063
35494
  } catch (error) {
35064
- this.logger.debug(`Failed to delete custom-resource response object s3://${displaySafe(bucket, { asciiOnly: true }) || "<unrenderable>"}/${displaySafe(responseKey)}; it remains as a current object. Underlying error: ${displaySafe(error instanceof Error ? error.message : String(error)) || "<unrenderable>"}`);
35495
+ this.logger.debug(`Failed to delete custom-resource response object s3://${displaySafe(bucket, { asciiOnly: true }) || "<unrenderable>"}/${displaySafe(responseKey)}; it remains as a current object. Underlying error: ${displaySafe(describeAwsFailure(error).detail) || "<unrenderable>"}`);
35065
35496
  }
35066
35497
  await purgeNoncurrentKeyVersions(this.s3Client, bucket, [responseKey], {
35067
35498
  logger: this.logger,
@@ -35840,7 +36271,7 @@ var IAMRoleProvider = class {
35840
36271
  await this.iamClient.send(new DeleteRoleCommand({ RoleName: roleName }));
35841
36272
  this.logger.debug(`Cleaned up partially-created IAM role ${logicalId} (${roleName}) after wiring failure`);
35842
36273
  } catch (cleanupError) {
35843
- this.logger.warn(`Failed to clean up partially-created IAM role ${logicalId} (${roleName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: detach managed policies (aws iam list-attached-role-policies --role-name ${roleName} then aws iam detach-role-policy --role-name ${roleName} --policy-arn <arn>), delete inline policies (aws iam list-role-policies --role-name ${roleName} then aws iam delete-role-policy --role-name ${roleName} --policy-name <name>), then aws iam delete-role --role-name ${roleName}`);
36274
+ this.logger.warn(`Failed to clean up partially-created IAM role ${logicalId} (${roleName}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: detach managed policies (aws iam list-attached-role-policies --role-name ${roleName} then aws iam detach-role-policy --role-name ${roleName} --policy-arn <arn>), delete inline policies (aws iam list-role-policies --role-name ${roleName} then aws iam delete-role-policy --role-name ${roleName} --policy-name <name>), then aws iam delete-role --role-name ${roleName}`);
35844
36275
  }
35845
36276
  throw innerError;
35846
36277
  }
@@ -35877,8 +36308,8 @@ var IAMRoleProvider = class {
35877
36308
  this.logger.warn(`Skipped deleting old role ${physicalId} during replacement: ${deleteResult.reason}. The old role may be orphaned and require manual cleanup.`);
35878
36309
  }
35879
36310
  } catch (error) {
35880
- orphanReason = `old role ${physicalId} could not be deleted: ${String(error)}`;
35881
- this.logger.warn(`Failed to delete old role ${physicalId} during replacement: ${String(error)}. The old role may be orphaned and require manual cleanup.`);
36311
+ orphanReason = `old role ${physicalId} could not be deleted: ${safeStringify(error)}`;
36312
+ this.logger.warn(`Failed to delete old role ${physicalId} during replacement: ${safeStringify(error)}. The old role may be orphaned and require manual cleanup.`);
35882
36313
  }
35883
36314
  const base = {
35884
36315
  physicalId: createResult.physicalId,
@@ -38147,7 +38578,7 @@ function makeCanonicalizePropertiesFn(registry) {
38147
38578
  if (!registry.hasProvider(resourceType)) return properties;
38148
38579
  return registry.getProvider(resourceType).canonicalizeDesiredProperties?.(resourceType, properties) ?? properties;
38149
38580
  } catch (error) {
38150
- logger.debug(`canonicalizeDesiredProperties failed for ${resourceType}: ${error instanceof Error ? error.message : String(error)}`);
38581
+ logger.debug(`canonicalizeDesiredProperties failed for ${resourceType}: ${describeAwsFailure(error).detail}`);
38151
38582
  return properties;
38152
38583
  }
38153
38584
  };
@@ -44723,5 +45154,5 @@ var DeployEngine = class DeployEngine {
44723
45154
  };
44724
45155
 
44725
45156
  //#endregion
44726
- export { secretBearing as $, withErrorHandling as $i, LockManager as $n, getDefaultStateBucketName as $r, s3BucketArn as $t, extractDeploymentEventError as A, CdkdError as Ai, findActionableSilentDrops as An, parseBootstrapMarker as Ar, isImpossibleEmptyStoredAttribute as At, toCfnInteger as B, MalformedProducerRecordRefusalError as Bi, carriesSecretMask as Bn, dockerSpawnEnvWithSensitive as Br, coerceCfnBoolean as Bt, buildFinalSnapshotIdentifier as C, clearBucketRegionCache as Ci, refuseMalformedOutputs as Cn, rewriteTemplateAssetReferences as Cr, isTerminationProtectionPropagationError as Ct, refusesFinalSnapshot as D, resetAwsClients as Di, repairMalformedOutputsForReadOnly as Dn, ensureAssetStorage as Dr, cfnRefValueFromPhysicalId as Dt, isFinalSnapshotError as E, getAwsClients as Ei, refuseMalformedState as En, assertAssetBucketRegion as Er, carriesFetchableDynamicReference as Et, isStatefulRecreateTargetSync as F, DynamicReferenceRegionAmbiguousError as Fi, TemplateParser as Fn, describeAwsFailure as Fr, isSettledInstanceState as Ft, gray as G, ResourceUpdateNotSupportedError as Gi, isSingleDynamicReferenceToken as Gn, runDockerForeground as Gr, readConfigString as Gt, formatResourceLine as H, PartialFailureError as Hi, dynamicReferenceTokens as Hn, getDockerCmd as Hr, configBooleanRefusal as Ht, renderStatefulReason as I, IntrinsicResolutionRefusalError as Ii, STATE_SOURCED_BASELINE_RULES as In, buildDockerImage as Ir, WAFv2WebACLProvider as It, yellow as J, StateError as Ji, maskSecretsInText as Jn, stripControlChars as Jr, requireConfigObject as Jt, green as K, StackHasActiveImportsError as Ki, markSameGenerationBag as Kn, runDockerStreaming as Kr, replayWarn as Kt, WARM_THROUGHPUT_MEMBERS as L, LocalInvokeBuildError as Li, STATE_SOURCED_CROSS_GENERATION_RULES as Ln, describeDockerCapturedOutput as Lr, normalizeAwsTagsToCfn as Lt, planOrphanAdoption as M, CrossAccountSecretRefusalError as Mi, describeTypeWithThrottleRetry as Mn, validateAssetBucketName as Mr, isUnboundTemplateParameter as Mt, MULTI_REGION_RECREATE_BLOCKED_TYPES as N, DependencyError as Ni, withRetry as Nn, validateContainerRepoName as Nr, parameterTypeMayLoseSecretIdentity as Nt, unsupportedFinalSnapshotError as O, setAwsClients as Oi, repairMalformedResourcePropertiesForReadOnly as On, getBootstrapMarkerKey as Or, coerceParameterTypedValue as Ot, isStatefulRecreateTargetForReplace as P, DeployCancelledError as Pi, DagBuilder as Pn, buildDenyExternalAccessPolicy as Pr, refStateLookupFromResource as Pt, isExportAliasCollision as Q, normalizeAwsError as Qi, scrubResourceRecord as Qn, synthesisStatusMessage as Qr, withSharedDrainBudget as Qt, coerceWarmThroughput as R, LocalStartServiceError as Ri, STATE_SOURCED_READBACK_RULES as Rn, describeDockerExecFailure as Rr, resolveExplicitPhysicalId as Rt, PRE_DELETE_SNAPSHOT_TYPES as S, processStackMessages as Si, refuseMalformedNestedChildOutputs as Sn, loadPublishableAssetManifest as Sr, disableInstanceApiTermination as St, createPreDeleteFinalSnapshot as T, AwsClients as Ti, refuseMalformedResourcesForDestroy as Tn, BOOTSTRAP_MARKER_PREFIX as Tr, carriesDynamicReference as Tt, bold as U, ProvisioningError as Ui, errorCauseChain as Un, partitionSensitiveEnv as Ur, configIntegerRefusal as Ut, toFiniteNumber as V, NestedStackChildDirectDestroyError as Vi, createSecretMasker as Vn, formatDockerLoginError as Vr, coerceCfnInteger as Vt, cyan as W, ResourceTimeoutError as Wi, identityKeyFor as Wn, redactDockerArgvValues as Wr, configStringRefusal as Wt, collectPublishedOutputNames as X, formatError as Xi, recoverMaskedOutput as Xn, getDockerImageBySourceHash as Xr, classifyReplaySecretRegion as Xt, collectDeclaredOutputNames as Y, SynthesisError as Yi, recordMaskOnlyValue as Yn, AssetManifestLoader as Yr, requireConfigString as Yt, exportAliasCollisionScrubWarning as Z, isCdkdError as Zi, redactSecretsForState as Zn, Synthesizer as Zr, producerRegionsFromState as Zt, isSecretBearingReferenceString as _, expectedOwnerParam as _i, malformedRenderedContainersWarning as _n, AssetPublisher as _r, isWaitAbandonedError as _t, DeploymentEventsStore as a, markRedactedCause as aa, resolveStateBucketWithDefault as ai, applyCallerIdentityCredentials as an, formatLockExpiry as ar, clearOnUpdateRemoval as at, bindingSkippedOutputs as b, derivePartitionAndUrlSuffix as bi, malformedStateRefusalMessage as bn, buildAssetRedirectMap as br, deleteIndeterminateGuards as bt, replayFailedOperations as c, stateBucketExistenceConfirmed as ci, INTRINSIC_KEYS as cn, DEFAULT_STATE_PREFIX as cr, createMaskedRetryLogger as ct, updatePartialReason as d, CFN_TEMPLATE_URL_LIMIT as di, hasReadableResources as dn, importableOutputKeys as dr, beginCommandInterruptScope as dt, isMarkedNonRetryable as ea, getLegacyStateBucketName as ei, s3BucketDomainName as en, S3StateBackend as er, secretBearingStateKeyWarning as et, withResourceDeadline as f, MIGRATE_TMP_PREFIX as fi, malformedExportNamesWarning as fn, importableOutputs as fr, endCommandInterruptScope as ft, bagHoldsSecretExpression as g, decodeListingKey as gi, malformedOutputsWarning as gn, shouldRetainResource as gr, CloudControlProvider as gt, computeImplicitDeleteEdges as h, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as hi, malformedOutputsRefusalMessage as hn, orphansCarriedFrom as hr, startInterruptWatch as ht, DeploymentEventsReader as i, markNonRetryable as ia, resolveSkipPrefix as ii, applyRoleArnIfSet as in, forceQuitRecoveryClause as ir, collectInlinePolicyNamesManagedBySiblings as it, makeSiblingClaimReader as j, ConfigError as ji, findSilentDropProperties as jn, readBootstrapMarkerBody as jr, isNamelessDynamicReferenceError as jt, makeCanonicalizePropertiesFn as k, AssetError as ki, repairMalformedResourcesForReadOnly as kn, isCrossRegionRedirect as kr, getAccountInfo as kt, replayRollback as l, warnDeprecatedNoPrefixCliFlag as li, STATE_RESOURCES_MALFORMED as ln, exportNamesCarriedFrom as lr, maskDeep as lt, IMPLICIT_DELETE_DEPENDENCIES as m, uploadCfnTemplate as mi, malformedLocalOutputsWarning as mn, orphansAfterRollback as mr, isInterruptedWaitError as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, isThrottlingError as na, resolveAutoAssetStorage as ni, s3BucketRegionalDomainName as nn, buildForceUnlockCommand as nr, getCurrentResourceSecrets as nt, planFailedOps as o, retryClassificationText as oa, resolveStateBucketWithDefaultAndSource as oi, callerEnvCredentials as on, shellQuote as or, ProviderRegistry as ot, maskingRetryLogger as p, findLargeInlineResources as pi, malformedExportSourceWarning as pn, isReadableBag as pr, interruptWatchListenerCount as pt, red as q, StackTerminationProtectionError as qi, maskSecretsInError as qn, escapeRegExp$1 as qr, requireConfigArray as qt, DeployEngine as r, isTransientServerError as ra, resolveCaptureObservedState as ri, s3BucketWebsiteUrl as rn, buildLockContentionMessage as rr, IAMRoleProvider as rt, planRollback as s, __exportAll as sa, resolveUseCdkBootstrapAssets as si, DiffCalculator as sn, CUSTOM_RESOURCE_RESPONSE_PREFIX as sr, wouldReturnToSdkProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, isRetryableTransientError as ta, resolveApp as ti, s3BucketDualStackDomainName as tn, rebuildClientForBucketRegion as tr, secretSafeKeyDisplay as tt, updatePartialMessage as u, CFN_TEMPLATE_BODY_LIMIT as ui, hasReadableOutputs as un, hasReadableExportSet as ur, maskerOrIdentity as ut, keptWholeReasonText as v, PARTITION_TABLE as vi, malformedResourcePropertiesWarning as vn, stringifyValue as vr, slowCcOperationTimeoutMs as vt, ccRoutedFinalSnapshotError as w, resolveBucketRegion as wi, refuseMalformedOutputsForDestroy as wn, AssetModeResolver as wr, IntrinsicFunctionResolver as wt, ATOMIC_FINAL_SNAPSHOT_TYPES as x, AssemblyReader as xi, producerRecordKey as xn, createAssetRedirectResolver as xr, deleteSkipReason as xt, mergeNoChangeOutputs as y, canonicalizeRegion as yi, malformedResourcesWarning as yn, WorkGraph as yr, UNSPECIFIED_SKIP_REASON as yt, isWarmThroughputDecrease as z, LockError as zi, TEMPLATE_SOURCED_RULES as zn, describeDockerFailure as zr, assertRegionMatch as zt };
44727
- //# sourceMappingURL=deploy-engine-KnCjibgq.js.map
45157
+ export { secretBearing as $, isCdkdError as $i, scrubResourceRecord as $n, Synthesizer as $r, s3BucketArn as $t, extractDeploymentEventError as A, setAwsClients as Ai, repairMalformedResourcesForReadOnly as An, isCrossRegionRedirect as Ar, isImpossibleEmptyStoredAttribute as At, toCfnInteger as B, LocalStartServiceError as Bi, TEMPLATE_SOURCED_RULES as Bn, describeDockerExecFailure as Br, coerceCfnBoolean as Bt, buildFinalSnapshotIdentifier as C, AssemblyReader as Ci, refuseMalformedOutputs as Cn, loadPublishableAssetManifest as Cr, isTerminationProtectionPropagationError as Ct, refusesFinalSnapshot as D, AwsClients as Di, refuseMalformedState as Dn, assertAssetBucketRegion as Dr, cfnRefValueFromPhysicalId as Dt, isFinalSnapshotError as E, resolveBucketRegion as Ei, refuseMalformedResourcesForDestroy as En, BOOTSTRAP_MARKER_PREFIX as Er, carriesFetchableDynamicReference as Et, isStatefulRecreateTargetSync as F, DependencyError as Fi, DagBuilder as Fn, buildDenyExternalAccessPolicy as Fr, isSettledInstanceState as Ft, gray as G, ProvisioningError as Gi, identityKeyFor as Gn, partitionSensitiveEnv as Gr, readConfigString as Gt, formatResourceLine as H, MalformedProducerRecordRefusalError as Hi, createSecretMasker as Hn, dockerSpawnEnvWithSensitive as Hr, configBooleanRefusal as Ht, renderStatefulReason as I, DeployCancelledError as Ii, TemplateParser as In, describeAwsFailure as Ir, WAFv2WebACLProvider as It, yellow as J, StackHasActiveImportsError as Ji, maskSecretsInError as Jn, runDockerStreaming as Jr, requireConfigObject as Jt, green as K, ResourceTimeoutError as Ki, isSingleDynamicReferenceToken as Kn, redactDockerArgvValues as Kr, replayWarn as Kt, WARM_THROUGHPUT_MEMBERS as L, DynamicReferenceRegionAmbiguousError as Li, STATE_SOURCED_BASELINE_RULES as Ln, safeStringify as Lr, normalizeAwsTagsToCfn as Lt, planOrphanAdoption as M, CdkdError as Mi, findSilentDropProperties as Mn, readBootstrapMarkerBody as Mr, isUnboundTemplateParameter as Mt, MULTI_REGION_RECREATE_BLOCKED_TYPES as N, ConfigError as Ni, describeTypeWithThrottleRetry as Nn, validateAssetBucketName as Nr, parameterTypeMayLoseSecretIdentity as Nt, unsupportedFinalSnapshotError as O, getAwsClients as Oi, repairMalformedOutputsForReadOnly as On, ensureAssetStorage as Or, coerceParameterTypedValue as Ot, isStatefulRecreateTargetForReplace as P, CrossAccountSecretRefusalError as Pi, withRetry as Pn, validateContainerRepoName as Pr, refStateLookupFromResource as Pt, isExportAliasCollision as Q, formatError as Qi, redactSecretsForState as Qn, getDockerImageBySourceHash as Qr, withSharedDrainBudget as Qt, coerceWarmThroughput as R, IntrinsicResolutionRefusalError as Ri, STATE_SOURCED_CROSS_GENERATION_RULES as Rn, buildDockerImage as Rr, resolveExplicitPhysicalId as Rt, PRE_DELETE_SNAPSHOT_TYPES as S, derivePartitionAndUrlSuffix as Si, refuseMalformedNestedChildOutputs as Sn, createAssetRedirectResolver as Sr, disableInstanceApiTermination as St, createPreDeleteFinalSnapshot as T, clearBucketRegionCache as Ti, refuseMalformedResourcePropertiesForOrphan as Tn, AssetModeResolver as Tr, carriesDynamicReference as Tt, bold as U, NestedStackChildDirectDestroyError as Ui, dynamicReferenceTokens as Un, formatDockerLoginError as Ur, configIntegerRefusal as Ut, toFiniteNumber as V, LockError as Vi, carriesSecretMask as Vn, describeDockerFailure as Vr, coerceCfnInteger as Vt, cyan as W, PartialFailureError as Wi, errorCauseChain as Wn, getDockerCmd as Wr, configStringRefusal as Wt, collectPublishedOutputNames as X, StateError as Xi, recordMaskOnlyValue as Xn, stripControlChars as Xr, classifyReplaySecretRegion as Xt, collectDeclaredOutputNames as Y, StackTerminationProtectionError as Yi, maskSecretsInText as Yn, escapeRegExp$1 as Yr, requireConfigString as Yt, exportAliasCollisionScrubWarning as Z, SynthesisError as Zi, recoverMaskedOutput as Zn, AssetManifestLoader as Zr, producerRegionsFromState as Zt, isSecretBearingReferenceString as _, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as _i, malformedRenderedContainersWarning as _n, shouldRetainResource as _r, isWaitAbandonedError as _t, DeploymentEventsStore as a, isTransientServerError as aa, resolveCaptureObservedState as ai, applyCallerIdentityCredentials as an, forceQuitRecoveryClause as ar, clearOnUpdateRemoval as at, bindingSkippedOutputs as b, PARTITION_TABLE as bi, malformedStateRefusalMessage as bn, WorkGraph as br, deleteIndeterminateGuards as bt, replayFailedOperations as c, retryClassificationText as ca, resolveStateBucketWithDefaultAndSource as ci, INTRINSIC_KEYS as cn, CUSTOM_RESOURCE_RESPONSE_PREFIX as cr, createMaskedRetryLogger as ct, updatePartialReason as d, warnDeprecatedNoPrefixCliFlag as di, hasReadableResources as dn, hasReadableExportSet as dr, beginCommandInterruptScope as dt, normalizeAwsError as ea, synthesisStatusMessage as ei, s3BucketDomainName as en, LockManager as er, secretBearingStateKeyWarning as et, withResourceDeadline as f, CFN_TEMPLATE_BODY_LIMIT as fi, malformedExportNamesWarning as fn, importableOutputKeys as fr, endCommandInterruptScope as ft, bagHoldsSecretExpression as g, uploadCfnTemplate as gi, malformedOutputsWarning as gn, orphansCarriedFrom as gr, CloudControlProvider as gt, computeImplicitDeleteEdges as h, findLargeInlineResources as hi, malformedOutputsRefusalMessage as hn, orphansAfterRollback as hr, startInterruptWatch as ht, DeploymentEventsReader as i, isThrottlingError as ia, resolveAutoAssetStorage as ii, applyRoleArnIfSet as in, buildLockContentionMessage as ir, collectInlinePolicyNamesManagedBySiblings as it, makeSiblingClaimReader as j, AssetError as ji, findActionableSilentDrops as jn, parseBootstrapMarker as jr, isNamelessDynamicReferenceError as jt, makeCanonicalizePropertiesFn as k, resetAwsClients as ki, repairMalformedResourcePropertiesForReadOnly as kn, getBootstrapMarkerKey as kr, getAccountInfo as kt, replayRollback as l, __exportAll as la, resolveUseCdkBootstrapAssets as li, STATE_RESOURCES_MALFORMED as ln, DEFAULT_STATE_PREFIX as lr, maskDeep as lt, IMPLICIT_DELETE_DEPENDENCIES as m, MIGRATE_TMP_PREFIX as mi, malformedLocalOutputsWarning as mn, isReadableBag as mr, isInterruptedWaitError as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, isMarkedNonRetryable as na, getLegacyStateBucketName as ni, s3BucketRegionalDomainName as nn, rebuildClientForBucketRegion as nr, getCurrentResourceSecrets as nt, planFailedOps as o, markNonRetryable as oa, resolveSkipPrefix as oi, callerEnvCredentials as on, formatLockExpiry as or, ProviderRegistry as ot, maskingRetryLogger as p, CFN_TEMPLATE_URL_LIMIT as pi, malformedExportSourceWarning as pn, importableOutputs as pr, interruptWatchListenerCount as pt, red as q, ResourceUpdateNotSupportedError as qi, markSameGenerationBag as qn, runDockerForeground as qr, requireConfigArray as qt, DeployEngine as r, isRetryableTransientError as ra, resolveApp as ri, s3BucketWebsiteUrl as rn, buildForceUnlockCommand as rr, IAMRoleProvider as rt, planRollback as s, markRedactedCause as sa, resolveStateBucketWithDefault as si, DiffCalculator as sn, shellQuote as sr, wouldReturnToSdkProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, withErrorHandling as ta, getDefaultStateBucketName as ti, s3BucketDualStackDomainName as tn, S3StateBackend as tr, secretSafeKeyDisplay as tt, updatePartialMessage as u, stateBucketExistenceConfirmed as ui, hasReadableOutputs as un, exportNamesCarriedFrom as ur, maskerOrIdentity as ut, keptWholeReasonText as v, decodeListingKey as vi, malformedResourcePropertiesWarning as vn, AssetPublisher as vr, slowCcOperationTimeoutMs as vt, ccRoutedFinalSnapshotError as w, processStackMessages as wi, refuseMalformedOutputsForDestroy as wn, rewriteTemplateAssetReferences as wr, IntrinsicFunctionResolver as wt, ATOMIC_FINAL_SNAPSHOT_TYPES as x, canonicalizeRegion as xi, producerRecordKey as xn, buildAssetRedirectMap as xr, deleteSkipReason as xt, mergeNoChangeOutputs as y, expectedOwnerParam as yi, malformedResourcesWarning as yn, stringifyValue as yr, UNSPECIFIED_SKIP_REASON as yt, isWarmThroughputDecrease as z, LocalInvokeBuildError as zi, STATE_SOURCED_READBACK_RULES as zn, describeDockerCapturedOutput as zr, assertRegionMatch as zt };
45158
+ //# sourceMappingURL=deploy-engine-CBzq85r6.js.map