@go-to-k/cdkd 0.290.43 → 0.290.45

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-D-2HeLmd.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-DjBU2Ap3.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-ChfV4K6h.js";
3
+ import { t as getCdkdVersion } from "./version-DMaX1bq2.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";
@@ -3029,6 +3029,91 @@ function renderAssemblyPathEscape(escape, dir, action = "load", provenanceOverri
3029
3029
  return `resolves to '${displaySafe(escape.path)}', outside '${displaySafe(base)}'. ${provenance}`;
3030
3030
  }
3031
3031
 
3032
+ //#endregion
3033
+ //#region src/utils/own-keys.ts
3034
+ /**
3035
+ * Own-key helpers for the bags that reach cdkd through `JSON.parse` — a
3036
+ * `state.json` record, a Cloud Control `Properties` document, a template — and
3037
+ * for the raw SDK readbacks compared against them.
3038
+ *
3039
+ * `JSON.parse` yields a key literally named `__proto__` as an ORDINARY own
3040
+ * data property, and every comparator / rebuild walk over such a bag has to
3041
+ * keep treating it as one. Two idioms silently do not:
3042
+ *
3043
+ * - **Rebuilding onto a `{}` literal.** `out[k] = v` with `k === '__proto__'`
3044
+ * runs `Object.prototype`'s accessor, SETS the node's prototype and DROPS
3045
+ * the key — on BOTH comparison sides when the walk is a canonicalizer, so a
3046
+ * drift at that key is invisible (issue
3047
+ * [#3121](https://github.com/go-to-k/cdkd/issues/3121)), and on the WRITE
3048
+ * path the member vanishes from the payload (issue
3049
+ * [#2899](https://github.com/go-to-k/cdkd/issues/2899)). Rebuild onto
3050
+ * {@link nullPrototypeRecord} (no accessor there, so plain assignment
3051
+ * defines an own key) or, onto an existing plain object, define the key
3052
+ * with {@link defineOwnKey}.
3053
+ * - **`key in bag` membership.** `in` reads the prototype chain, so a key
3054
+ * named `constructor` / `toString` answers `true` for every plain object
3055
+ * and the recursion then walks `Object`'s function. {@link hasOwnKey} asks
3056
+ * the bag alone; {@link ownValue} is the matching read.
3057
+ *
3058
+ * And ONE shape test every such walk needs FIRST: {@link hasPlainPrototype}.
3059
+ * A non-plain object (`Date`, `Uint8Array`, `Map`, a class instance) has no
3060
+ * own enumerable keys, so a key-walk over one FABRICATES `{}` (or an index
3061
+ * map) and any two of them compare equal. Such a value is returned by
3062
+ * IDENTITY and compared as itself.
3063
+ *
3064
+ * Extracted from `src/cli/commands/drift.ts` (issue #2899, swept by PR #3124)
3065
+ * so the analyzer-side canonicalizers (#3121) share ONE spelling rather than a
3066
+ * fourth copy. A LEAF module, deliberately, and it must stay one: a value
3067
+ * import from a module other suites `vi.mock` wholesale reds those suites
3068
+ * with a missing-export failure (which is why `secret-redaction.ts` keeps its
3069
+ * own `hasPlainPrototype` — several drift suites mock that module).
3070
+ */
3071
+ /** Own-key membership: `in` reads the prototype chain, which a `JSON.parse`d bag never means. */
3072
+ function hasOwnKey(target, key) {
3073
+ return Object.prototype.hasOwnProperty.call(target, key);
3074
+ }
3075
+ /** An own-key read: `undefined` for an inherited name (`__proto__`, `constructor`, ...). */
3076
+ function ownValue(target, key) {
3077
+ return hasOwnKey(target, key) ? target[key] : void 0;
3078
+ }
3079
+ /** An ordinary (writable, enumerable, configurable) own data property — never the prototype. */
3080
+ function defineOwnKey(target, key, value) {
3081
+ Object.defineProperty(target, key, {
3082
+ value,
3083
+ writable: true,
3084
+ enumerable: true,
3085
+ configurable: true
3086
+ });
3087
+ }
3088
+ /**
3089
+ * Does this value carry an ORDINARY object prototype?
3090
+ *
3091
+ * `typeof v === 'object'` admits `Date` / `Map` / `Set` / `Uint8Array` / class
3092
+ * instances, whose own enumerable keys are `[]` — so a key-walk over one
3093
+ * reports "no contradiction" between two values that actually differ, and a
3094
+ * rebuild over one fabricates `{}`. A NULL prototype counts as plain: it is
3095
+ * what {@link nullPrototypeRecord} yields, and a walk must be able to re-walk
3096
+ * its own output.
3097
+ */
3098
+ function hasPlainPrototype$1(value) {
3099
+ const proto = Object.getPrototypeOf(value);
3100
+ return proto === Object.prototype || proto === null;
3101
+ }
3102
+ /**
3103
+ * A fresh rebuild target with NO prototype, so `out['__proto__'] = v` defines
3104
+ * an own key instead of setting the prototype. `JSON.stringify`,
3105
+ * `Object.keys` / `entries` and `structuredClone` all read it like a plain
3106
+ * object; only `instanceof Object` and a direct `.hasOwnProperty()` method call
3107
+ * do not, and no consumer on the drift path uses either.
3108
+ *
3109
+ * The type parameter spares a caller with a narrower value type an `as` cast at
3110
+ * every call — `nullPrototypeRecord<string>()` for a logical-id-to-path index.
3111
+ * It defaults to `unknown`, so a zero-argument call is unchanged.
3112
+ */
3113
+ function nullPrototypeRecord() {
3114
+ return Object.create(null);
3115
+ }
3116
+
3032
3117
  //#endregion
3033
3118
  //#region src/synthesis/stack-messages.ts
3034
3119
  /**
@@ -3123,9 +3208,160 @@ function processStackMessages(stacks, logger, options = {}) {
3123
3208
  if (hasWarnings && failAt === "warn") throw new SynthesisError("Found warnings (--strict mode)");
3124
3209
  }
3125
3210
 
3211
+ //#endregion
3212
+ //#region src/synthesis/failed-stages.ts
3213
+ /**
3214
+ * Marks an error that already names the Stage it was raised under, so an outer
3215
+ * Stage does not prepend its own name on the way out. Follows the marker shape
3216
+ * of `markNonRetryable` in `src/deployment/retryable-errors.ts`: a
3217
+ * non-enumerable own property, read by presence.
3218
+ */
3219
+ const STAGE_SCOPED_MARKER = Symbol.for("cdkd.stageScopedError");
3220
+ /**
3221
+ * Re-raise a refusal caught while reading the CONTENTS of a Stage, with the
3222
+ * Stage named (issue [#3482](https://github.com/go-to-k/cdkd/issues/3482)).
3223
+ *
3224
+ * This is NOT a downgrade: every caller throws what this returns. The refusal
3225
+ * texts name the STACK — the stack a Stage produced carries a physical name
3226
+ * that need not embed the Stage's path, so without this the user is not told
3227
+ * which Stage directory to look in.
3228
+ *
3229
+ * The INNERMOST Stage wins: an error arriving already marked is returned
3230
+ * unchanged, so `Outer` does not restate what `Outer/Inner` said more
3231
+ * precisely. `stagePath` is the RAW path and is rendered here, for the reason
3232
+ * {@link FailedStage.stagePath} gives.
3233
+ *
3234
+ * The caught text goes through `displaySafe` although every throw reachable
3235
+ * from the recursion sanitizes at its own origin today: this catch's error
3236
+ * population is the whole recursive subtree, so the guard belongs to the CATCH
3237
+ * rather than to today's set of throws under it. It is therefore the identity
3238
+ * and a mutation probe on it finds no discrimination — stated so the next
3239
+ * reader gets the reason instead of the puzzle.
3240
+ *
3241
+ * No `cause`: the message already embeds the original's text in full, and
3242
+ * `formatError` renders a cause as a `Caused by:` line, which would print the
3243
+ * same sentence twice.
3244
+ */
3245
+ function stageScopedError(stagePath, error) {
3246
+ if (error instanceof Error && STAGE_SCOPED_MARKER in error) return error;
3247
+ const message = displaySafe(error instanceof Error ? error.message : String(error));
3248
+ const scoped = new SynthesisError(`Stage ${renderStagePath(stagePath)}: ${message}`);
3249
+ if (error instanceof Error && typeof error.stack === "string") {
3250
+ const headerLines = `${error.name}: ${error.message}`.split("\n").length;
3251
+ const frames = error.stack.split("\n").slice(headerLines).join("\n");
3252
+ if (frames.length > 0) scoped.stack = `${scoped.name}: ${scoped.message}\n${frames}`;
3253
+ }
3254
+ if (Object.isExtensible(scoped)) Object.defineProperty(scoped, STAGE_SCOPED_MARKER, {
3255
+ value: true,
3256
+ enumerable: false,
3257
+ configurable: true,
3258
+ writable: false
3259
+ });
3260
+ return scoped;
3261
+ }
3262
+ /**
3263
+ * Render the sentence a stack-selection failure appends when a stage failed to
3264
+ * load, so the message reports the failed stage instead of answering "not
3265
+ * found" for a stack that may well exist under it.
3266
+ *
3267
+ * Returns `''` — appending nothing — when no stage failed, which is every
3268
+ * ordinary run. Otherwise it opens with `. ` so it reads as its own sentence
3269
+ * after a head that ends in a stack list.
3270
+ *
3271
+ * When one of the selection `patterns` targets a failed stage, that stage is
3272
+ * named as the explanation. Otherwise every failed stage is listed behind a
3273
+ * `Possibly unrelated:` hedge, since a physical stack name carries no stage
3274
+ * path and the link therefore cannot be proven from the pattern alone (see
3275
+ * `patternTargetsStage`). The sentence itself is spelled the same either way,
3276
+ * so one substring finds it.
3277
+ */
3278
+ function failedStageNote(patterns, failedStages) {
3279
+ if (!failedStages || failedStages.length === 0) return "";
3280
+ const targeted = patterns.length === 0 ? failedStages : failedStages.filter((stage) => patterns.some((pattern) => patternTargetsStage(pattern, stage.stagePath)));
3281
+ const named = targeted.length > 0 ? targeted : failedStages;
3282
+ return ". " + (targeted.length > 0 ? "" : "Possibly unrelated: ") + named.map((stage) => `Stage ${renderStagePath(stage.stagePath)} failed to load, so stacks under it are missing from this list rather than missing from the app: ${stage.reason}`).join(" ");
3283
+ }
3284
+ /**
3285
+ * Render a Stage path into a message.
3286
+ *
3287
+ * `displayIdent` without quotes of ours, and with the cap a legitimately long
3288
+ * hierarchical name needs — the same argument `STACK_REF_MAX_CODE_POINTS`
3289
+ * exists for. See {@link FailedStage.stagePath} for why the stored value stays
3290
+ * raw and only this rendering is sanitized.
3291
+ */
3292
+ function renderStagePath(stagePath) {
3293
+ return displayIdent(stagePath, { maxCodePoints: STACK_REF_MAX_CODE_POINTS });
3294
+ }
3295
+ /**
3296
+ * Whether a user-supplied selection pattern could name a stack under
3297
+ * `stagePath`.
3298
+ *
3299
+ * Mirrors the routing rule in `src/cli/stack-matcher.ts`: a pattern WITHOUT
3300
+ * `/` is matched against the PHYSICAL CloudFormation stack name, which carries
3301
+ * no stage path at all (`MyStage-MyStack` is not decomposable — a stack may
3302
+ * override its own `stackName`), so such a pattern is never attributed to a
3303
+ * stage. A pattern WITH `/` is a display path, and its leading segments are
3304
+ * compared against the stage's, wildcard by wildcard, so `MyStage/MyStack` and
3305
+ * `MyStage/*` both attribute to `MyStage`.
3306
+ */
3307
+ function patternTargetsStage(pattern, stagePath) {
3308
+ if (!pattern.includes("/")) return false;
3309
+ const patternSegments = pattern.split("/");
3310
+ const stageSegments = stagePath.split("/");
3311
+ if (patternSegments.length < stageSegments.length) return false;
3312
+ return stageSegments.every((segment, i) => segmentMatches(patternSegments[i], segment));
3313
+ }
3314
+ /**
3315
+ * Wildcard-aware comparison of ONE path segment, matching how
3316
+ * `stackMatchesPattern` expands `*` in `src/cli/stack-matcher.ts`. The pattern
3317
+ * is the USER's own input, not an assembly-supplied value, so it is expanded
3318
+ * there the same way — metacharacters and all, so the two cannot disagree
3319
+ * about what a pattern means.
3320
+ *
3321
+ * The construction is guarded because SPLITTING on `/` can make an invalid
3322
+ * segment out of a valid pattern (`'(*x/y*)'` splits into `'(*x'`), and this
3323
+ * helper runs when the stack list is EMPTY, which is exactly when
3324
+ * `stackMatchesPattern` never evaluates and therefore never raises first. An
3325
+ * unusable pattern is simply not attributed: the note still prints, hedged,
3326
+ * instead of a `SyntaxError` replacing the message the user needed.
3327
+ */
3328
+ function segmentMatches(patternSegment, segment) {
3329
+ if (!patternSegment.includes("*")) return patternSegment === segment;
3330
+ try {
3331
+ return new RegExp("^" + patternSegment.replace(/\*/g, ".*") + "$").test(segment);
3332
+ } catch {
3333
+ return false;
3334
+ }
3335
+ }
3336
+
3126
3337
  //#endregion
3127
3338
  //#region src/synthesis/assembly-reader.ts
3128
3339
  /**
3340
+ * The failure's own words, carrying NO value the assembly chose.
3341
+ *
3342
+ * Three branches, and each returns a string cdkd controls:
3343
+ *
3344
+ * - a filesystem failure is reduced to its `code` (`ENOENT`, `EACCES`,
3345
+ * `EISDIR`), because Node's `message` for one embeds the path, which is the
3346
+ * value being contained;
3347
+ * - a `JSON.parse` failure is reduced to `invalid JSON`. V8's `SyntaxError`
3348
+ * carries no path, but it DOES echo a short window of the file's own bytes
3349
+ * verbatim (`Unexpected token '.', ". All 3 st"... is not valid JSON`), and
3350
+ * the file is assembly-chosen too. The snippet buys nothing here: the caller
3351
+ * already names the directory;
3352
+ * - anything else answers `unreadable`, and deliberately does NOT fall back to
3353
+ * the wrapper's own message, which is the text this function exists to
3354
+ * exclude. A fallback fires on an input nobody predicted, which is exactly
3355
+ * when the contained value must not come back.
3356
+ */
3357
+ function manifestReadFailureText(error) {
3358
+ const cause = error instanceof CdkdError ? error.cause : error;
3359
+ const code = cause?.code;
3360
+ if (typeof code === "string" && code.length > 0) return displaySafe(code);
3361
+ if (cause instanceof SyntaxError) return "invalid JSON";
3362
+ return "unreadable";
3363
+ }
3364
+ /**
3129
3365
  * Reads and parses Cloud Assembly from cdk.out directory
3130
3366
  *
3131
3367
  * EVERY value this class renders into a message or a log line goes through
@@ -3143,6 +3379,14 @@ function processStackMessages(stacks, logger, options = {}) {
3143
3379
  * still renders in full and byte-identically. The same rule, for the same
3144
3380
  * reason, guards the twin refusals in `src/cli/commands/diff-recursive.ts`
3145
3381
  * (go-to-k/cdkd#3243).
3382
+ *
3383
+ * ONE value leaves this class UNSANITIZED: a failed Stage's path
3384
+ * ([#3482](https://github.com/go-to-k/cdkd/issues/3482)), which is a match key
3385
+ * as well as the subject of a sentence. `failed-stages.ts` renders it at each
3386
+ * display site with `displayIdent` — it is an IDENTIFIER interpolated into
3387
+ * prose rather than free-form text quoted as a value, so the denylist's
3388
+ * tolerance of quotes and spaces is a spoof surface there. See
3389
+ * `FailedStage.stagePath`.
3146
3390
  */
3147
3391
  var AssemblyReader = class {
3148
3392
  logger = getLogger().child("AssemblyReader");
@@ -3161,9 +3405,38 @@ var AssemblyReader = class {
3161
3405
  }
3162
3406
  }
3163
3407
  /**
3408
+ * Read an assembly: all its stacks (recursing into nested assemblies /
3409
+ * Stages) plus the Stages that could not be read at all.
3410
+ *
3411
+ * Only ONE failure is tolerated while walking a Stage — the read of the
3412
+ * Stage's own `manifest.json`, which is the legitimate "this Stage
3413
+ * references a directory that was never synthesized" case. Every REFUSAL
3414
+ * raised while reading a Stage's contents propagates out of the recursion
3415
+ * exactly as it does at the top level (issue
3416
+ * [#3482](https://github.com/go-to-k/cdkd/issues/3482)).
3417
+ */
3418
+ readAssembly(assemblyDir, manifest, assetOutdir = assemblyDir) {
3419
+ const failedStages = [];
3420
+ return {
3421
+ stacks: this.collectStacks(assemblyDir, manifest, assetOutdir, failedStages),
3422
+ failedStages
3423
+ };
3424
+ }
3425
+ /**
3164
3426
  * Get all stacks from assembly (recursively traverses nested assemblies / Stages)
3427
+ *
3428
+ * Discards the failed-Stage records `readAssembly` returns; a caller that
3429
+ * reports on a selection failure wants that method instead.
3165
3430
  */
3166
3431
  getAllStacks(assemblyDir, manifest, assetOutdir = assemblyDir) {
3432
+ return this.readAssembly(assemblyDir, manifest, assetOutdir).stacks;
3433
+ }
3434
+ /**
3435
+ * The recursive half of `readAssembly`. `failedStages` is the accumulator
3436
+ * shared by every level, so a Stage that fails three levels down is still
3437
+ * reported to the top-level caller.
3438
+ */
3439
+ collectStacks(assemblyDir, manifest, assetOutdir, failedStages) {
3167
3440
  if (!manifest.artifacts) {
3168
3441
  this.logger.warn("No artifacts found in manifest");
3169
3442
  return [];
@@ -3177,14 +3450,25 @@ var AssemblyReader = class {
3177
3450
  const props = artifact.properties;
3178
3451
  if (props?.directoryName) {
3179
3452
  const resolved = resolveAssemblyPath(assemblyDir, props.directoryName);
3180
- if (!resolved.contained) throw new SynthesisError(`Nested assembly '${displaySafe(props.directoryName)}' ${renderAssemblyPathEscape(resolved, assemblyDir)}`);
3453
+ if (!resolved.contained) throw new SynthesisError(`Nested assembly ${renderStagePath(props.directoryName)} ${renderAssemblyPathEscape(resolved, assemblyDir)}`);
3181
3454
  const nestedDir = resolved.path;
3455
+ const stagePath = typeof props.displayName === "string" && props.displayName.length > 0 ? props.displayName : artifactId;
3456
+ let nestedManifest;
3457
+ try {
3458
+ nestedManifest = this.readManifest(nestedDir);
3459
+ } catch (error) {
3460
+ const reason = `${manifestReadFailureText(error)} reading ${renderStagePath(props.directoryName)}/manifest.json`;
3461
+ this.logger.warn(`Failed to read nested assembly: ${reason}`);
3462
+ failedStages.push({
3463
+ stagePath,
3464
+ reason
3465
+ });
3466
+ continue;
3467
+ }
3182
3468
  try {
3183
- const nestedManifest = this.readManifest(nestedDir);
3184
- const nestedStacks = this.getAllStacks(nestedDir, nestedManifest, assetOutdir);
3185
- stacks.push(...nestedStacks);
3469
+ stacks.push(...this.collectStacks(nestedDir, nestedManifest, assetOutdir, failedStages));
3186
3470
  } catch (error) {
3187
- this.logger.warn(`Failed to read nested assembly '${displaySafe(props.directoryName)}': ${displaySafe(error instanceof Error ? error.message : String(error))}`);
3471
+ throw stageScopedError(stagePath, error);
3188
3472
  }
3189
3473
  }
3190
3474
  }
@@ -3195,9 +3479,9 @@ var AssemblyReader = class {
3195
3479
  * Get a specific stack by name
3196
3480
  */
3197
3481
  getStack(assemblyDir, manifest, stackName) {
3198
- const stacks = this.getAllStacks(assemblyDir, manifest);
3482
+ const { stacks, failedStages } = this.readAssembly(assemblyDir, manifest);
3199
3483
  const stack = stacks.find((s) => s.stackName === stackName);
3200
- if (!stack) throw new SynthesisError(`Stack '${displaySafe(stackName)}' not found in assembly. Available: ${stacks.map((s) => displaySafe(s.stackName)).join(", ")}`);
3484
+ if (!stack) throw new SynthesisError(`Stack '${displaySafe(stackName)}' not found in assembly. ` + (stacks.length > 0 ? `Available: ${stacks.map((s) => displayIdent(s.stackName, { maxCodePoints: STACK_REF_MAX_CODE_POINTS })).join(", ")}` : "The assembly has no stacks") + failedStageNote([stackName], failedStages));
3201
3485
  return stack;
3202
3486
  }
3203
3487
  /**
@@ -3261,7 +3545,7 @@ var AssemblyReader = class {
3261
3545
  if (dependencyNames.length > 0) this.logger.debug(`Stack '${displaySafe(stackName)}' depends on: [${dependencyNames.map((n) => displaySafe(n)).join(", ")}]`);
3262
3546
  let env;
3263
3547
  if (artifact.environment) env = parseEnvironment(artifact.environment);
3264
- const nestedTemplates = {};
3548
+ const nestedTemplates = nullPrototypeRecord();
3265
3549
  for (const [logicalId, resource] of Object.entries(template.Resources ?? {})) {
3266
3550
  if (resource?.Type !== "AWS::CloudFormation::Stack") continue;
3267
3551
  const assetPath = resource.Metadata?.["aws:asset:path"];
@@ -6414,13 +6698,14 @@ var Synthesizer = class {
6414
6698
  if (isPreSynthesizedAssembly(options.app)) {
6415
6699
  this.logger.debug(`Using pre-synthesized cloud assembly at ${appPath}`);
6416
6700
  const manifest = this.assemblyReader.readManifest(appPath);
6417
- const stacks = this.assemblyReader.getAllStacks(appPath, manifest);
6701
+ const { stacks, failedStages } = this.assemblyReader.readAssembly(appPath, manifest);
6418
6702
  if (!options.deferMacroExpansion) await this.expandMacrosForStacks(stacks, options);
6419
6703
  this.logger.debug(`Loaded ${stacks.length} stack(s) from pre-synthesized assembly`);
6420
6704
  return {
6421
6705
  manifest,
6422
6706
  assemblyDir: appPath,
6423
- stacks
6707
+ stacks,
6708
+ failedStages
6424
6709
  };
6425
6710
  }
6426
6711
  const outputDir = resolve(options.output || "cdk.out");
@@ -6471,7 +6756,7 @@ var Synthesizer = class {
6471
6756
  });
6472
6757
  const manifest = this.assemblyReader.readManifest(outputDir);
6473
6758
  if (!manifest.missing || manifest.missing.length === 0) {
6474
- const stacks = this.assemblyReader.getAllStacks(outputDir, manifest);
6759
+ const { stacks, failedStages } = this.assemblyReader.readAssembly(outputDir, manifest);
6475
6760
  if (!options.deferMacroExpansion) await this.expandMacrosForStacks(stacks, options, {
6476
6761
  region: explicitRegion,
6477
6762
  ...accountId && { accountId }
@@ -6480,7 +6765,8 @@ var Synthesizer = class {
6480
6765
  return {
6481
6766
  manifest,
6482
6767
  assemblyDir: outputDir,
6483
- stacks
6768
+ stacks,
6769
+ failedStages
6484
6770
  };
6485
6771
  }
6486
6772
  const missingKeys = new Set(manifest.missing.map((m) => m.key));
@@ -21695,25 +21981,32 @@ function displayLogicalId(value) {
21695
21981
  /**
21696
21982
  * The DIAGNOSIS sentence itself, with no identity and no remedy in it.
21697
21983
  *
21698
- * ONE spelling, because two copies of a diagnosis are what drift. It is extracted because
21699
- * {@link malformedDestroyResourcesRefusalMessage} needs the same sentence
21700
- * under an identity it does NOT trust, where the detail's substituted
21701
- * `cdkd state show` command must not appear — a difference in the COMMAND, not
21702
- * in the diagnosis.
21984
+ * ONE spelling, because two copies of a diagnosis are what drift. Its two
21985
+ * consumers are the arms of {@link malformedStateDiagnosis}, which differ by
21986
+ * the IDENTITY they may name and not by this sentence — since
21987
+ * go-to-k/cdkd#3516 neither arm carries a command at all, so there is nothing
21988
+ * else for them to differ in.
21703
21989
  */
21704
21990
  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.";
21705
21991
  /**
21706
- * `region` is optional for ONE caller's sake: `cdkd export`'s baseline report,
21707
- * whose loaded region is absent when the record it loaded is a legacy
21708
- * region-less one and no synth region was available to stand in for it. A placeholder there would put a `--stack-region` into a
21709
- * command the reader pastes that selects no record at all — so an absent
21710
- * region drops the clause and the flag rather than inventing one.
21992
+ * Identity plus the diagnosis, and NO command — every consumer appends prose
21993
+ * after this half, so a command baked in here can only land mid-sentence
21994
+ * (go-to-k/cdkd#3516). It used to end on a substituted `cdkd state show`, which
21995
+ * put the one runnable command in four messages one space from the next clause:
21996
+ * a line-select paste then handed `cdkd state show` the following sentence as
21997
+ * positional arguments. The command is {@link inspectCommand}'s, and the
21998
+ * caller ends ON it — the contract that function's own note states, and the
21999
+ * shape {@link malformedDestroyOutputsRefusalMessage} already had. Its
22000
+ * `orphans` twin had it too until this change gave both DESTROY refusals a
22001
+ * per-line shape instead, so that one is no longer the example to copy.
22002
+ *
22003
+ * `stackName` is optional so the withhold arm of
22004
+ * {@link malformedDestroyResourcesRefusalMessage} takes this same helper: that
22005
+ * arm must state the diagnosis under an identity it does not trust, which is
22006
+ * {@link stackClause}'s no-identity form rather than a second spelling.
21711
22007
  */
21712
- function malformedStateDetail(stackName, region) {
21713
- const stack = safeStackName(stackName);
21714
- const where = region === void 0 ? "" : ` (${shellQuote(safeRegion(region))})`;
21715
- const regionFlag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeRegion(region))}`;
21716
- return `State for ${shellQuote(stack)}${where} ${MALFORMED_RESOURCES_DIAGNOSIS} Inspect it with: cdkd state show ${shellQuote(stack)}${regionFlag} --json`;
22008
+ function malformedStateDiagnosis(stackName, region) {
22009
+ return `${stackClause(stackName, region)} ${MALFORMED_RESOURCES_DIAGNOSIS}`;
21717
22010
  }
21718
22011
  /**
21719
22012
  * For a READ-ONLY command: give the record an empty resource bag so the
@@ -21768,7 +22061,52 @@ function repairMalformedResourcesForReadOnly(state) {
21768
22061
  * would tell an operator to re-run a command that attempted nothing.
21769
22062
  */
21770
22063
  function malformedStateRefusalMessage(stackName, region) {
21771
- return `${malformedStateDetail(stackName, region)} This command can WRITE state, so it refuses rather than continuing: saving over a record whose resource map could not be read would replace the evidence with a well-formed empty one and lose it permanently. Repair or remove the record first.`;
22064
+ return `${malformedStateDiagnosis(stackName, region)} This command can WRITE state, so it refuses rather than continuing: saving over a record whose resource map could not be read would replace the evidence with a well-formed empty one and lose it permanently. Repair or remove the record first. Inspect it with: ${inspectCommand(stackName, region)}`;
22065
+ }
22066
+ /**
22067
+ * The destructive template, in the three messages that offer one.
22068
+ *
22069
+ * ONE spelling, because copies are what drift, and they carry it byte-identically
22070
+ * on purpose — a reader who has met one must recognise the others. Two wrap it
22071
+ * in {@link DROP_RECORD_LINE}'s label; `divergentRecordRegionRefusalMessage`
22072
+ * ends on it bare. `<stack>` / `<region>` are LITERAL: nothing may substitute them, for
22073
+ * the reason {@link malformedDestroyResourcesRefusalMessage}'s note gives.
22074
+ */
22075
+ const DROP_RECORD_TEMPLATE = "cdkd state orphan <stack> --stack-region <region>";
22076
+ /**
22077
+ * The same template as a LABELLED line, for the two messages that carry their
22078
+ * commands one per line. The COMMAND is the atom rather than the line, because
22079
+ * the command is what drifts: `divergentRecordRegionRefusalMessage` ends on it
22080
+ * with no label, so THIS PAIR cannot half-land a `--stack-region` rename.
22081
+ * {@link dropRecordCommand} still spells it separately for the `cdkd orphan`
22082
+ * messages, which substitute into it — that one is not covered here.
22083
+ */
22084
+ const DROP_RECORD_LINE = `Drop the record: ${DROP_RECORD_TEMPLATE}`;
22085
+ /**
22086
+ * May this message NAME its target and offer the destructive template beside
22087
+ * it (go-to-k/cdkd#3516 review)?
22088
+ *
22089
+ * Stricter than `safeIdentifier(x) === x`, which is what these two arms used
22090
+ * and which keeps a space, a `:`, a `'`, a `;` and a `|` — the `:` and the
22091
+ * space being the pair a label needs. That was enough while the
22092
+ * message was one paragraph, and stopped being enough the moment the commands
22093
+ * moved onto LABELLED lines: a stack name spelling
22094
+ * `Drop the record: cdkd state orphan prod --stack-region us-east-1` renders
22095
+ * exactly, takes this arm, and lands inside the quoted name on the inspect
22096
+ * line — where a terminal wrap puts cdkd's own label at the start of a visual
22097
+ * line, carrying a destructive command whose holes are already filled. A
22098
+ * line-select copies it. The label vocabulary is what made the forgery
22099
+ * credible, so the gate that admits a name into it is the one that had to
22100
+ * tighten.
22101
+ *
22102
+ * {@link isPasteableIdent} is that gate and the codebase already spends it on
22103
+ * this question (`gc.ts` gates its own destructive hint on the same pair). It
22104
+ * refuses a space and a quote outright while keeping every name CloudFormation
22105
+ * can produce, `Parent~Child` included, so no healthy record loses its
22106
+ * identity here.
22107
+ */
22108
+ function mayNameTargetWithDestructiveRemedy(stackName, region) {
22109
+ return safeStackName(stackName) === stackName && safeRegion(region) === region && isPasteableIdent(stackName) && isPasteableIdent(region);
21772
22110
  }
21773
22111
  /**
21774
22112
  * The DESTROY refusal text for the `resources` bag (issue
@@ -21831,7 +22169,7 @@ function malformedStateRefusalMessage(stackName, region) {
21831
22169
  * destructive command at a DIFFERENT region's record for the same stack. That
21832
22170
  * is the misdirection class {@link stackClause} records for stack names, one
21833
22171
  * field over. Substituting into the read-only `state show` line is the
21834
- * pre-existing behaviour of {@link malformedStateDetail} and is left alone;
22172
+ * pre-existing behaviour of {@link inspectCommand} and is left alone;
21835
22173
  * what this lane must not add is a destructive one.
21836
22174
  *
21837
22175
  * **go-to-k/cdkd#3328 closed the BODY half of that, and the template stays
@@ -21878,23 +22216,28 @@ function malformedStateRefusalMessage(stackName, region) {
21878
22216
  * because a LEGACY record has no key region at all, in which case the value
21879
22217
  * printed is the CLI's own and `--stack-region` must be omitted.
21880
22218
  *
21881
- * **The VERDICT turns on the identifier caps**, which is why the stack name is
21882
- * measured through {@link safeStackName} (`STACK_REF_MAX_CODE_POINTS`) and the
21883
- * region through {@link safeRegion} (128, which no real region approaches). At
21884
- * 128 an ordinary multi-level CDK nested child
22219
+ * **The VERDICT is {@link mayNameTargetWithDestructiveRemedy}** — the identifier
22220
+ * caps AND pasteability, since go-to-k/cdkd#3516 — so the stack name is
22221
+ * measured at `STACK_REF_MAX_CODE_POINTS` and the region at a region's 128,
22222
+ * which no real region approaches. Measuring the STACK at 128 instead is the
22223
+ * trap: an ordinary multi-level CDK nested child
21885
22224
  * (`<root>~<...NestedStackResource><hash>~<...>`, measured past 150 code
21886
- * points) truncates, fails `exact`, and takes the withhold arm on a HEALTHY
21887
- * record — which is fail-safe but makes the fallback the common path for
21888
- * exactly the nested destroys this lane added a guard to (review round 2 of
21889
- * go-to-k/cdkd#3332). The bound is still a bound: a planted multi-kilobyte name
21890
- * is truncated at 1152 and lands in the withhold arm.
22225
+ * points) WOULD truncate there and take the withhold arm on a HEALTHY record,
22226
+ * making the fallback the common path for exactly the nested destroys this
22227
+ * lane added a guard to (review round 2 of go-to-k/cdkd#3332). The bound is
22228
+ * still a bound: a planted multi-kilobyte name is truncated at 1152 and lands
22229
+ * in the withhold arm.
21891
22230
  *
21892
22231
  * Identifiers are sanitized and THEN shell-quoted, for the reasons
21893
22232
  * {@link safeIdentifier}'s note gives.
21894
22233
  */
21895
22234
  function malformedDestroyResourcesRefusalMessage(stackName, region) {
21896
- const exact = safeStackName(stackName) === stackName && safeRegion(region) === region;
21897
- 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)}`}`;
22235
+ const exact = mayNameTargetWithDestructiveRemedy(stackName, region);
22236
+ return [
22237
+ `${malformedStateDiagnosis(exact ? stackName : void 0, exact ? region : void 0)} 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. It is spelled as a template on its own line below rather than handed over ready to run, because that command DELETES a record and a key segment is chosen by anyone who can write this bucket: the key says WHICH record this is, which is not the same as vouching for it as a delete target. 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." : "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."}`,
22238
+ `Inspect the record: ${inspectCommand(exact ? stackName : void 0, exact ? region : void 0)}`,
22239
+ ...exact ? [DROP_RECORD_LINE] : []
22240
+ ].join("\n");
21898
22241
  }
21899
22242
  /**
21900
22243
  * For `cdkd destroy` / `cdkd state destroy`: refuse a record whose `resources`
@@ -21972,11 +22315,11 @@ const STATE_REGION_DIVERGED = "STATE_REGION_DIVERGED";
21972
22315
  */
21973
22316
  function divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBodyRegion, resourceCount) {
21974
22317
  const cap = STACK_REF_MAX_CODE_POINTS;
21975
- const exact = safeIdentifier(stackName, cap) === stackName && safeIdentifier(keyRegion, cap) === keyRegion;
22318
+ const exact = safeIdentifier(stackName, cap) === stackName && safeIdentifier(keyRegion, cap) === keyRegion && isPasteableIdent(stackName) && isPasteableIdent(keyRegion);
21976
22319
  const lists = resourceCount === void 0 ? "its resources map cannot be read" : `it still lists ${resourceCount} resource${resourceCount === 1 ? "" : "s"}`;
21977
22320
  const kind = describeRegionValueKind(divergentBodyRegion);
21978
22321
  const opening = exact ? `cdkd will not destroy stack ${shellQuote(safeIdentifier(stackName, cap))} (${shellQuote(safeIdentifier(keyRegion, cap))}): the state record read from that region's key carries a 'region' of its own (${kind}) that is not the key's, and ${lists}` : `cdkd will not destroy the state record this command loaded: it carries a 'region' of its own (${kind}) that is not the region of the key it was read from, and ${lists}`;
21979
- const remedy = exact ? "Re-run with --verbose to see what the record's region field holds, then either destroy against the region the resources are really in, or repair that field to match the key it is stored under and re-run. To drop the record and leave the live resources standing, spelled out rather than pasteable because that command DELETES a record: cdkd state orphan <stack> --stack-region <region>" : `This record's stack name or region does NOT render exactly — what any surrounding output shows 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)}`;
22322
+ const remedy = exact ? "Re-run with --verbose to see what the record's region field holds, then either destroy against the region the resources are really in, or repair that field to match the key it is stored under and re-run. To drop the record and leave the live resources standing, spelled out rather than pasteable because that command DELETES a record: " + DROP_RECORD_TEMPLATE : `This record's stack name or region does NOT render exactly — what any surrounding output shows 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)}`;
21980
22323
  return `${opening} ${resourceCount === void 0 ? `— so cdkd can neither count what it would delete nor tell which region it is in` : `— so cdkd cannot tell which region those resources are in`}. cdkd stamps the key's region into every record it writes, so this record was not written by cdkd. Destroying against the key's region would issue every delete there; if the record's own region is the honest half, each delete comes back not-found, which this command reads as ALREADY DELETED — it would report success, remove the record, and leave every resource standing in the other region with nothing naming it. ${remedy}`;
21981
22324
  }
21982
22325
  /**
@@ -22028,7 +22371,7 @@ function refuseDivergentRecordRegionForDestroy(state, stackName, keyRegion, dive
22028
22371
  * LAST, for the reasons {@link safeIdentifier}'s note gives.
22029
22372
  */
22030
22373
  function malformedDeployResourcesRefusalMessage(stackName, region) {
22031
- return `${malformedStateDetail(stackName, region)} '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: an unreadable map reads as ZERO recorded resources, so every resource the template declares is planned as a CREATE and the deploy re-provisions a stack that already exists, colliding on each deterministic name and duplicating the rest, then saves a well-formed record over the only evidence anything was wrong. Reading the bag as EMPTY produces that same plan 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 stack with this map read as EMPTY and warns that it did.`;
22374
+ return `${malformedStateDiagnosis(stackName, region)} '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: an unreadable map reads as ZERO recorded resources, so every resource the template declares is planned as a CREATE and the deploy re-provisions a stack that already exists, colliding on each deterministic name and duplicating the rest, then saves a well-formed record over the only evidence anything was wrong. Reading the bag as EMPTY produces that same plan 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 stack with this map read as EMPTY and warns that it did. Inspect it with: ${inspectCommand(stackName, region)}`;
22032
22375
  }
22033
22376
  /**
22034
22377
  * For `cdkd deploy`: refuse a record whose `resources` bag cannot be read
@@ -22119,7 +22462,7 @@ function malformedRenderedContainersWarning(stackName, region, containers) {
22119
22462
  }
22120
22463
  /** The warning a caller of {@link repairMalformedResourcesForReadOnly} emits. */
22121
22464
  function malformedResourcesWarning(stackName, region) {
22122
- return `${malformedStateDetail(stackName, region)} Continuing with an EMPTY resource set: this command's output describes zero resources, which is not the same as the stack having none.`;
22465
+ return `${malformedStateDiagnosis(stackName, region)} Continuing with an EMPTY resource set: this command's output describes zero resources, which is not the same as the stack having none. Inspect it with: ${inspectCommand(stackName, region)}`;
22123
22466
  }
22124
22467
  /**
22125
22468
  * The `outputs` half of {@link repairMalformedResourcesForReadOnly}, for a
@@ -22333,6 +22676,160 @@ function refuseMalformedOutputs(state, stackName, region) {
22333
22676
  throw markNonRetryable(new CdkdError(malformedOutputsRefusalMessage(stackName, region), STATE_RESOURCES_MALFORMED));
22334
22677
  }
22335
22678
  /**
22679
+ * The stand-in row a read-only view lists in its `unreadable` set for an
22680
+ * `orphans` container it could not read, beside
22681
+ * {@link UNREADABLE_RESOURCES_MAP_ROW}'s row for the resource map.
22682
+ */
22683
+ const UNREADABLE_ORPHANS_CONTAINER_ROW = "(orphans container)";
22684
+ /**
22685
+ * Whether the `orphans` CONTAINER is the list every reader of it assumes
22686
+ * (issue go-to-k/cdkd#3379).
22687
+ *
22688
+ * `parseStateBody` validates the record root and its schema version and returns
22689
+ * the cast record otherwise unchanged, so a hand-edited or planted
22690
+ * `"orphans": "abc"`, `5`, `{}` or `{"length": 1}` survives the load and every
22691
+ * reader reaches it on a bare `?? []`, `?.length` or `?.map`.
22692
+ *
22693
+ * ABSENT IS READABLE, for the reason {@link hasReadableOutputs}'s note gives
22694
+ * for its own container and one that is sharper here: an absent `orphans` is
22695
+ * the ORDINARY record. A stack that never had a failed deploy has no orphan
22696
+ * list at all, `JSON.stringify` drops the key when it is undefined, and
22697
+ * `orphansAfterRollback` returns `{}` on `previous.orphans === undefined`
22698
+ * WITH nothing newly orphaned — the pair of conditions that keeps such a
22699
+ * record byte-identical. Warning or refusing on absence would fire on
22700
+ * almost every record in a bucket.
22701
+ *
22702
+ * `null` is NOT readable, which is where this parts from a bare `?? []`: that
22703
+ * admits `null` silently, and the shapes this exists to catch are exactly the
22704
+ * ones it cannot see.
22705
+ *
22706
+ * The ENTRIES are a separate question with a separate answer —
22707
+ * `orphans[<i>].properties` is go-to-k/cdkd#3344, and
22708
+ * {@link refuseMalformedResourcePropertiesForOrphan} is the guard there. This
22709
+ * one says only that the container is a list.
22710
+ */
22711
+ function hasReadableOrphans(state) {
22712
+ return state.orphans === void 0 || Array.isArray(state.orphans);
22713
+ }
22714
+ /**
22715
+ * For a READ-ONLY command: replace an unreadable `orphans` container with an
22716
+ * empty list so the command can report the rest of the record, and return
22717
+ * whether it did, so the caller can warn with
22718
+ * {@link malformedOrphansWarning} and list
22719
+ * {@link UNREADABLE_ORPHANS_CONTAINER_ROW} among what it could not read.
22720
+ *
22721
+ * AT THE LOAD, the placement rule
22722
+ * {@link repairMalformedResourcesForReadOnly}'s note records: `cdkd diff`
22723
+ * reaches the container through `currentState.orphans?.length` before its
22724
+ * adoption preview, so a guard written at the preview leaves the dereference
22725
+ * above it — and for a STRING that dereference is the one that lies, since
22726
+ * `'abc'.length` is 3 and the preview then walks characters.
22727
+ *
22728
+ * READ-ONLY commands only, for the reason {@link refuseMalformedState} gives:
22729
+ * a container laundered into a well-formed empty one is permanent, and for
22730
+ * this container it also erases the only record that resources were left
22731
+ * behind in AWS by an earlier failed deploy.
22732
+ */
22733
+ function repairMalformedOrphansForReadOnly(state) {
22734
+ if (hasReadableOrphans(state)) return false;
22735
+ state.orphans = [];
22736
+ return true;
22737
+ }
22738
+ /**
22739
+ * The warning a caller of {@link repairMalformedOrphansForReadOnly} emits.
22740
+ *
22741
+ * Its own text rather than any of the three above, the rule this module's
22742
+ * every message follows: what continuing EMPTY costs here is not a diff's
22743
+ * left-hand side or a rendered view's rows but the record's evidence that
22744
+ * resources from an earlier failed deploy are still live in AWS. A reader who
22745
+ * sees no adoption preview and no orphan warning will conclude the stack has
22746
+ * none.
22747
+ *
22748
+ * Identifiers are sanitized and THEN shell-quoted and the command is emitted
22749
+ * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
22750
+ */
22751
+ function malformedOrphansWarning(stackName, region) {
22752
+ const stack = safeStackName(stackName);
22753
+ const reg = safeRegion(region);
22754
+ return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'orphans' list — the record is malformed or truncated. Readers reach it on a bare '?? []' or '?.length', which admits a string, a number, a plain object and null alike: a string is WALKED, one garbage orphan per character, and the others read as no orphans at all. Continuing with it EMPTY: this view previews no adoption and names no orphan, which is NOT the same as the record holding none — resources from an earlier failed deploy may still be live in AWS. See the stored value with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
22755
+ }
22756
+ /**
22757
+ * The refusal text for a command that can WRITE the record.
22758
+ *
22759
+ * A DIFFERENT text from the warning because the danger is different and worse:
22760
+ * the reshaping reader is also a writer. `orphansAfterRollback` walks the
22761
+ * container with `for...of`, so over `"abc"` it returns a list holding `"c"`,
22762
+ * and `cdkd rollback` SAVES that record — a damaged container rewritten into a
22763
+ * differently damaged one, silently. `cdkd deploy`'s adoption pass assigns
22764
+ * `currentState.orphans` from what it read, and `cdkd destroy` proceeds through
22765
+ * resource deletion to `deleteState` having never reported the orphans it could
22766
+ * not read.
22767
+ *
22768
+ * Identifiers are sanitized and THEN shell-quoted and the command is emitted
22769
+ * LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
22770
+ */
22771
+ function malformedOrphansRefusalMessage(stackName, region) {
22772
+ const stack = safeStackName(stackName);
22773
+ const reg = safeRegion(region);
22774
+ return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'orphans' list — the record is malformed or truncated. This command can WRITE state, so it refuses rather than continuing: a string container is WALKED one character at a time and written back as a list of character-shaped orphan records, and every other unreadable shape reads as no orphans at all — so a run would delete or adopt against a record whose evidence of resources left live in AWS by an earlier failed deploy it never read. Repair or remove the record first, and no cdkd command repairs this container: rewriting it to [] by hand discards the very evidence this refusal is protecting. Inspect the record with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
22775
+ }
22776
+ /**
22777
+ * The DESTROY refusal text for this container (go-to-k/cdkd#3379 review).
22778
+ *
22779
+ * Its own text rather than {@link malformedOrphansRefusalMessage}, for the
22780
+ * reason every text in this module is its own: that one says the container
22781
+ * would be RESHAPED and written back, which is the rollback mechanism, and a
22782
+ * destroy never reshapes it — `buildDestroySnapshot` carries the container
22783
+ * verbatim through `...rest` into every save it makes, and then either REMOVES
22784
+ * the record (the clean path) or writes that snapshot as the final state, with
22785
+ * the container intact, on the error / interrupt / skip arm. What a destroy
22786
+ * does with the container instead is DECIDE: the count feeds `stillEmpty`, and
22787
+ * the orphan warning above it is the operator's only notice that resources from
22788
+ * an earlier failed deploy are still live in AWS.
22789
+ *
22790
+ * It also owes the remedy the sibling destroy refusal owes, and for the same
22791
+ * reason go-to-k/cdkd#3161 raised against refusing a cleanup command at all: an
22792
+ * operator who wants the record gone needs a way to do it. `cdkd state orphan`
22793
+ * is that way and reads no `orphans` container, so pointing at it is sound —
22794
+ * the same exactness split as {@link malformedDestroyResourcesRefusalMessage},
22795
+ * since a name that does not render faithfully must not become a command
22796
+ * against a record that may not be the damaged one.
22797
+ */
22798
+ function malformedDestroyOrphansRefusalMessage(stackName, region) {
22799
+ const exact = mayNameTargetWithDestructiveRemedy(stackName, region);
22800
+ return [
22801
+ `${`${stackClause(exact ? stackName : void 0, exact ? region : void 0)} has no readable 'orphans' list — the record is malformed or truncated.`} This command DELETES state, so it refuses rather than continuing: an unreadable container counts as no orphans, so the run would proceed through resource deletion to removing state.json while the record's evidence that an earlier failed deploy left resources live in AWS was never read — and that evidence goes with the record. Reading it as EMPTY is that 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 every live resource standing, run 'cdkd state orphan' against the stack and the region THE RECORD'S S3 KEY holds. It is spelled as a template on its own line below rather than handed over ready to run, because that command DELETES a record and a key segment is chosen by anyone who can write this bucket: the key says WHICH record this is, which is not the same as vouching for it as a delete target. 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." : "This record's stack name or region does NOT render exactly, so this message names no target and offers no command against one. List the records as stored with 'cdkd state list --long' and act on the one whose key matches."}`,
22802
+ `Inspect the record: ${inspectCommand(exact ? stackName : void 0, exact ? region : void 0)}`,
22803
+ ...exact ? [DROP_RECORD_LINE] : []
22804
+ ].join("\n");
22805
+ }
22806
+ /**
22807
+ * The destroy-path twin of {@link refuseMalformedOrphans}, carrying the text
22808
+ * above. Both destroy reads take this one: the entry read and the under-lock
22809
+ * re-read, which is the record `stillEmpty` and `deleteState` act on.
22810
+ */
22811
+ function refuseMalformedOrphansForDestroy(state, stackName, region) {
22812
+ if (hasReadableOrphans(state)) return;
22813
+ throw markNonRetryable(new CdkdError(malformedDestroyOrphansRefusalMessage(stackName, region), STATE_RESOURCES_MALFORMED));
22814
+ }
22815
+ /**
22816
+ * For a command that can WRITE state: refuse a record whose `orphans` container
22817
+ * cannot be read.
22818
+ *
22819
+ * A SIBLING of {@link refuseMalformedState} and {@link refuseMalformedOutputs}
22820
+ * rather than a widening of either, for the reason that pair already records: a
22821
+ * record can be malformed in one container alone, and the refusal a user sees
22822
+ * must name the container that is broken.
22823
+ *
22824
+ * CALL IT AT THE LOAD, above the first expression that reads the container, and
22825
+ * on a destroy at the UNDER-LOCK re-read as well — that re-read is the record
22826
+ * the run goes on to act on.
22827
+ */
22828
+ function refuseMalformedOrphans(state, stackName, region) {
22829
+ if (hasReadableOrphans(state)) return;
22830
+ throw markNonRetryable(new CdkdError(malformedOrphansRefusalMessage(stackName, region), STATE_RESOURCES_MALFORMED));
22831
+ }
22832
+ /**
22336
22833
  * The DESTROY refusal text (issue
22337
22834
  * [#3207](https://github.com/go-to-k/cdkd/issues/3207)).
22338
22835
  *
@@ -22483,7 +22980,7 @@ const NAMED_UNREADABLE_PROPERTY_BAGS = 5;
22483
22980
  * A region may also be absent on a v1 record, which predates the
22484
22981
  * region-prefixed key layout. A placeholder would put a `--stack-region` into
22485
22982
  * a pasted command that selects no record at all, so it is dropped for the
22486
- * same reason — the call go-to-k/cdkd#3226 makes for `malformedStateDetail`.
22983
+ * same reason — the call go-to-k/cdkd#3226 makes for `inspectCommand`.
22487
22984
  */
22488
22985
  function stackClause(stackName, region) {
22489
22986
  if (stackName === void 0) return "The state record this command loaded";
@@ -22569,15 +23066,27 @@ function dropRecordCommand(stackName, region, recovery) {
22569
23066
  * something PASTEABLE from — the drop command ({@link dropRecordCommand}), the
22570
23067
  * `cdkd state show` line ({@link orphanInspectCommand}) and the object path
22571
23068
  * ({@link orphanInspectClause}) — so no two of them can disagree about a name
22572
- * (go-to-k/cdkd#3363 review, M0 and M2). What it does NOT cover yet: the
22573
- * destroy refusal and the divergent-region refusal above still spell the same
22574
- * test inline, and the shared {@link inspectCommand} is ungated for its other
22575
- * callers (it renders the stack at that same cap, the region at 128).
23069
+ * (go-to-k/cdkd#3363 review, M0 and M2). The shared {@link inspectCommand}
23070
+ * stays ungated for its other callers, which offer a read only.
23071
+ *
23072
+ * It is NOT the module's gate for a DESTRUCTIVE remedy and must not be unified
23073
+ * with one: the three messages that offer a hole TEMPLATE are all stricter,
23074
+ * adding {@link isPasteableIdent} (go-to-k/cdkd#3516). This one is weaker on
23075
+ * purpose, and the gap is tracked rather than closed (go-to-k/cdkd#3523):
23076
+ * {@link dropRecordCommand} SUBSTITUTES, so tightening it here withholds the
23077
+ * drop command from a legacy record whose name merely needs quoting — the very
23078
+ * path go-to-k/cdkd#3359 built, where `cdkd state show` refuses outright and
23079
+ * this command is the way out. Measured: `It's Legacy` loses it.
22576
23080
  */
22577
23081
  function rendersExactly(value) {
22578
23082
  return safeIdentifier(value, STACK_REF_MAX_CODE_POINTS) === value;
22579
23083
  }
22580
- /** The remedy command {@link stackClause}'s message ends on. */
23084
+ /**
23085
+ * The remedy command a message ends ON — unless the message also offers the
23086
+ * destructive template, in which case it ends the READ's own LINE and
23087
+ * {@link DROP_RECORD_LINE} is last (go-to-k/cdkd#3516). Two of the eight call
23088
+ * sites are that shape; the rest close their string with it.
23089
+ */
22581
23090
  function inspectCommand(stackName, region) {
22582
23091
  if (stackName === void 0) return `cdkd state show ${commandHole("stack")} --stack-region ${commandHole("region")} --json`;
22583
23092
  const flag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeRegion(region))}`;
@@ -33975,7 +34484,7 @@ var CloudControlProvider = class {
33975
34484
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
33976
34485
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
33977
34486
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
33978
- const { ASGProvider } = await import("./asg-provider-C9R-ND4b.js").then((n) => n.n);
34487
+ const { ASGProvider } = await import("./asg-provider-CVB0Ky06.js").then((n) => n.n);
33979
34488
  const asgProvider = new ASGProvider();
33980
34489
  return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
33981
34490
  }
@@ -45660,6 +46169,7 @@ var DeployEngine = class DeployEngine {
45660
46169
  this.healBaseline = currentState.resources ?? {};
45661
46170
  refuseMalformedOutputs(currentState, stackName, this.stackRegion);
45662
46171
  refuseMalformedResourcesForDeploy(currentState, stackName, this.stackRegion);
46172
+ refuseMalformedOrphans(currentState, stackName, this.stackRegion);
45663
46173
  const migrationPending = currentStateData?.migrationPending ?? false;
45664
46174
  this.logger.debug(`Loaded current state: ${Object.keys(currentState.resources).length} resources`);
45665
46175
  if (this.options.onCurrentStateLoaded) await this.options.onCurrentStateLoaded(stackName, currentStateData?.state);
@@ -47683,5 +48193,5 @@ var DeployEngine = class DeployEngine {
47683
48193
  };
47684
48194
 
47685
48195
  //#endregion
47686
- export { yellow as $, getAwsClients as $i, STATE_SOURCED_BASELINE_RULES as $n, validateContainerRepoName as $r, requireConfigObject as $t, createPreDeleteFinalSnapshot as A, isTransientServerError as Aa, ssmResolvedValueType as Ai, malformedResourcePropertiesWarning as An, hasUnverifiableParameterRefusal as Ar, carriesDynamicReference as At, isStatefulRecreateTargetSync as B, producerRecordKey as Bi, refuseMalformedState as Bn, buildAssetRedirectMap as Br, isSettledInstanceState as Bt, namesAnyDeclaredParameter as C, formatError as Ca, resolveCaptureObservedState as Ci, malformedExportSourceWarning as Cn, formatLockExpiry as Cr, slowCcOperationTimeoutMs as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, isMarkedNonRetryable as Da, resolveUseCdkBootstrapAssets as Di, malformedOutputsWarning as Dn, exportNamesCarriedFrom as Dr, disableInstanceApiTermination as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, withErrorHandling as Ea, resolveStateBucketWithDefaultAndSource as Ei, malformedOutputsRefusalMessage as En, DEFAULT_STATE_PREFIX as Er, deleteSkipReason as Et, extractDeploymentEventError as F, safeStringify$1 as Fa, uploadCfnTemplate as Fi, refuseMalformedOutputs as Fn, orphansCarriedFrom as Fr, isImpossibleEmptyStoredAttribute as Ft, toCfnInteger as G, derivePartitionAndUrlSuffix as Gi, safeRegion as Gn, BOOTSTRAP_MARKER_PREFIX as Gr, coerceCfnBoolean as Gt, WARM_THROUGHPUT_MEMBERS as H, expectedOwnerParam as Hi, repairMalformedResourceEntriesForReadOnly as Hn, loadPublishableAssetManifest as Hr, normalizeAwsTagsToCfn as Ht, makeSiblingClaimReader as I, __exportAll as Ia, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Ii, refuseMalformedOutputsForDestroy as In, shouldRetainResource as Ir, isNamelessDynamicReferenceError as It, bold as J, renderAssemblyPathEscape as Ji, findSilentDropProperties as Jn, getBootstrapMarkerKey as Jr, configIntegerRefusal as Jt, toFiniteNumber as K, AssemblyReader as Ki, safeStackName as Kn, assertAssetBucketRegion as Kr, coerceCfnInteger as Kt, planOrphanAdoption as L, injectiveKey as Li, refuseMalformedResourceEntries as Ln, AssetPublisher as Lr, isUnboundTemplateParameter as Lt, refusesFinalSnapshot as M, markRedactedCause as Ma, CFN_TEMPLATE_URL_LIMIT as Mi, malformedStateRefusalMessage as Mn, importableOutputs as Mr, cfnRefValueFromPhysicalId as Mt, unsupportedFinalSnapshotError as N, retryClassificationText as Na, MIGRATE_TMP_PREFIX as Ni, refuseDivergentRecordRegionForDestroy as Nn, isReadableBag as Nr, coerceParameterTypedValue as Nt, buildFinalSnapshotIdentifier as O, isRetryableTransientError as Oa, stateBucketExistenceConfirmed as Oi, malformedRenderedContainersWarning as On, hasReadableExportSet as Or, isTerminationProtectionPropagationError as Ot, makeCanonicalizePropertiesFn as P, describeAwsFailure as Pa, findLargeInlineResources as Pi, refuseMalformedNestedChildOutputs as Pn, orphansAfterRollback as Pr, getAccountInfo as Pt, red as Q, AwsClients as Qi, TemplateParser as Qn, validateAssetBucketName as Qr, requireConfigArray as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, injectiveKeyPrefix as Ri, refuseMalformedResourcePropertiesForOrphan as Rn, stringifyValue as Rr, parameterTypeMayLoseSecretIdentity as Rt, computeParameterTaint as S, SynthesisError as Sa, resolveAutoAssetStorage as Si, malformedExportNamesWarning as Sn, forceQuitRecoveryClause as Sr, isWaitAbandonedError as St, resourcesNamingDeclaredParameter as T, normalizeAwsError as Ta, resolveStateBucketWithDefault as Ti, malformedOrphanRecordsWarning as Tn, CUSTOM_RESOURCE_RESPONSE_PREFIX as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, PARTITION_TABLE as Ui, repairMalformedResourcePropertiesForReadOnly as Un, rewriteTemplateAssetReferences as Ur, resolveExplicitPhysicalId as Ut, renderStatefulReason as V, decodeListingKey as Vi, repairMalformedOutputsForReadOnly as Vn, createAssetRedirectResolver as Vr, WAFv2WebACLProvider as Vt, isWarmThroughputDecrease as W, canonicalizeRegion as Wi, repairMalformedResourcesForReadOnly as Wn, AssetModeResolver as Wr, assertRegionMatch as Wt, gray as X, clearBucketRegionCache as Xi, withRetry as Xn, parseBootstrapMarker as Xr, readConfigString as Xt, cyan as Y, resolveAssemblyPath as Yi, describeTypeWithThrottleRetry as Yn, isCrossRegionRedirect as Yr, configStringRefusal as Yt, green as Z, resolveBucketRegion as Zi, DagBuilder as Zn, readBootstrapMarkerBody as Zr, replayWarn as Zt, bagHoldsSecretExpression as _, ResourceTimeoutError as _a, Synthesizer as _i, UNREADABLE_RESOURCES_MAP_ROW as _n, S3StateBackend as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, CrossAccountSecretRefusalError as aa, describeDockerFailure as ai, s3BucketDomainName as an, dynamicReferenceTokens as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, StackTerminationProtectionError as ba, getLegacyStateBucketName as bi, hasReadableResources as bn, buildForceUnlockCommand as br, startInterruptWatch as bt, replayFailedOperations as c, DynamicReferenceRegionAmbiguousError as ca, getDockerCmd as ci, s3BucketWebsiteUrl as cn, isSingleDynamicReferenceToken as cr, IAMRoleProvider as ct, updatePartialMessage as d, LocalStartServiceError as da, runDockerForeground as di, applyCallerIdentityCredentials as dn, maskSecretsInText as dr, ProviderRegistry as dt, resetAwsClients as ea, buildDenyExternalAccessPolicy as ei, requireConfigString as en, STATE_SOURCED_CROSS_GENERATION_RULES as er, collectDeclaredOutputNames as et, updatePartialReason as f, LockError as fa, runDockerStreaming as fi, callerEnvCredentials as fn, recordMaskOnlyValue as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, ProvisioningError as ga, getDockerImageBySourceHash as gi, STATE_RESOURCES_MALFORMED as gn, LockManager as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, PartialFailureError as ha, AssetManifestLoader as hi, INTRINSIC_KEYS as hn, scrubResourceRecord as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, ConfigError as ia, describeDockerExecFailure as ii, s3BucketArn as in, createSecretMasker as ir, secretBearing as it, isFinalSnapshotError as j, markNonRetryable as ja, CFN_TEMPLATE_BODY_LIMIT as ji, malformedResourcesWarning as jn, importableOutputKeys as jr, carriesFetchableDynamicReference as jt, ccRoutedFinalSnapshotError as k, isThrottlingError as ka, warnDeprecatedNoPrefixCliFlag as ki, malformedResourceEntriesWarning as kn, hasReasonlessBaselineRefusal as kr, IntrinsicFunctionResolver as kt, replayRollback as l, IntrinsicResolutionRefusalError as la, partitionSensitiveEnv as li, applyRoleArnIfSet as ln, markSameGenerationBag as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, NestedStackChildDirectDestroyError as ma, stripControlChars as mi, DiffCalculator as mn, redactSecretsForState as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, AssetError as na, resolveDockerContextDirectory as ni, producerRegionsFromState as nn, TEMPLATE_SOURCED_RULES as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, DependencyError as oa, dockerSpawnEnvWithSensitive as oi, s3BucketDualStackDomainName as on, errorCauseChain as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, MalformedProducerRecordRefusalError as pa, escapeRegExp$1 as pi, envCredentialsAreAssumedRole as pn, recoverMaskedOutput as pr, createMaskedRetryLogger as pt, formatResourceLine as q, processStackMessages as qi, findActionableSilentDrops as qn, ensureAssetStorage as qr, configBooleanRefusal as qt, DeployEngine as r, CdkdError as ra, describeDockerCapturedOutput as ri, withSharedDrainBudget as rn, carriesSecretMask as rr, isExportAliasCollision as rt, planRollback as s, DeployCancelledError as sa, formatDockerLoginError as si, s3BucketRegionalDomainName as sn, identityKeyFor as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, setAwsClients as ta, buildDockerImage as ti, classifyReplaySecretRegion as tn, STATE_SOURCED_READBACK_RULES as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, LocalInvokeBuildError as ua, redactDockerArgvValues as ui, AWS_CREDENTIAL_ENV_KEYS as un, maskSecretsInError as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, ResourceUpdateNotSupportedError as va, synthesisStatusMessage as vi, displayLogicalId as vn, rebuildClientForBucketRegion as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, isCdkdError as wa, resolveSkipPrefix as wi, malformedLocalOutputsWarning as wn, shellQuote as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, StateError as xa, resolveApp as xi, isReadableResourceEntry as xn, buildLockContentionMessage as xr, CloudControlProvider as xt, keptWholeReasonText as y, StackHasActiveImportsError as ya, getDefaultStateBucketName as yi, hasReadableOutputs as yn, UNREPRODUCIBLE_LOCK_CLAUSE as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, producerCoordinateKey as zi, refuseMalformedResourcesForDestroy as zn, WorkGraph as zr, refStateLookupFromResource as zt };
47687
- //# sourceMappingURL=deploy-engine-Bw8VoyEi.js.map
48196
+ export { yellow as $, AssemblyReader as $i, safeStackName as $n, assertAssetBucketRegion as $r, requireConfigObject as $t, createPreDeleteFinalSnapshot as A, ResourceTimeoutError as Aa, resolveCaptureObservedState as Ai, malformedOutputsRefusalMessage as An, formatLockExpiry as Ar, carriesDynamicReference as At, isStatefulRecreateTargetSync as B, isMarkedNonRetryable as Ba, MIGRATE_TMP_PREFIX as Bi, refuseMalformedOrphansForDestroy as Bn, isReadableBag as Br, isSettledInstanceState as Bt, namesAnyDeclaredParameter as C, LocalInvokeBuildError as Ca, getDockerImageBySourceHash as Ci, isReadableResourceEntry as Cn, LockManager as Cr, slowCcOperationTimeoutMs as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, NestedStackChildDirectDestroyError as Da, getLegacyStateBucketName as Di, malformedOrphanRecordsWarning as Dn, buildForceUnlockCommand as Dr, disableInstanceApiTermination as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, MalformedProducerRecordRefusalError as Ea, getDefaultStateBucketName as Ei, malformedLocalOutputsWarning as En, UNREPRODUCIBLE_LOCK_CLAUSE as Er, deleteSkipReason as Et, extractDeploymentEventError as F, SynthesisError as Fa, stateBucketExistenceConfirmed as Fi, malformedResourcesWarning as Fn, hasReadableExportSet as Fr, isImpossibleEmptyStoredAttribute as Ft, toCfnInteger as G, markRedactedCause as Ga, injectiveKeyPrefix as Gi, refuseMalformedResourcesForDestroy as Gn, stringifyValue as Gr, coerceCfnBoolean as Gt, WARM_THROUGHPUT_MEMBERS as H, isThrottlingError as Ha, uploadCfnTemplate as Hi, refuseMalformedOutputsForDestroy as Hn, orphansCarriedFrom as Hr, normalizeAwsTagsToCfn as Ht, makeSiblingClaimReader as I, formatError as Ia, warnDeprecatedNoPrefixCliFlag as Ii, malformedStateRefusalMessage as In, hasReasonlessBaselineRefusal as Ir, isNamelessDynamicReferenceError as It, bold as J, safeStringify$1 as Ja, decodeListingKey as Ji, repairMalformedOutputsForReadOnly as Jn, createAssetRedirectResolver as Jr, configIntegerRefusal as Jt, toFiniteNumber as K, retryClassificationText as Ka, producerCoordinateKey as Ki, refuseMalformedState as Kn, WorkGraph as Kr, coerceCfnInteger as Kt, planOrphanAdoption as L, isCdkdError as La, ssmResolvedValueType as Li, refuseDivergentRecordRegionForDestroy as Ln, hasUnverifiableParameterRefusal as Lr, isUnboundTemplateParameter as Lt, refusesFinalSnapshot as M, StackHasActiveImportsError as Ma, resolveStateBucketWithDefault as Mi, malformedRenderedContainersWarning as Mn, CUSTOM_RESOURCE_RESPONSE_PREFIX as Mr, cfnRefValueFromPhysicalId as Mt, unsupportedFinalSnapshotError as N, StackTerminationProtectionError as Na, resolveStateBucketWithDefaultAndSource as Ni, malformedResourceEntriesWarning as Nn, DEFAULT_STATE_PREFIX as Nr, coerceParameterTypedValue as Nt, buildFinalSnapshotIdentifier as O, PartialFailureError as Oa, resolveApp as Oi, malformedOrphansRefusalMessage as On, buildLockContentionMessage as Or, isTerminationProtectionPropagationError as Ot, makeCanonicalizePropertiesFn as P, StateError as Pa, resolveUseCdkBootstrapAssets as Pi, malformedResourcePropertiesWarning as Pn, exportNamesCarriedFrom as Pr, getAccountInfo as Pt, red as Q, derivePartitionAndUrlSuffix as Qi, safeRegion as Qn, BOOTSTRAP_MARKER_PREFIX as Qr, requireConfigArray as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, normalizeAwsError as Ra, CFN_TEMPLATE_BODY_LIMIT as Ri, refuseMalformedNestedChildOutputs as Rn, importableOutputKeys as Rr, parameterTypeMayLoseSecretIdentity as Rt, computeParameterTaint as S, IntrinsicResolutionRefusalError as Sa, AssetManifestLoader as Si, hasReadableResources as Sn, scrubResourceRecord as Sr, isWaitAbandonedError as St, resourcesNamingDeclaredParameter as T, LockError as Ta, synthesisStatusMessage as Ti, malformedExportSourceWarning as Tn, rebuildClientForBucketRegion as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, isTransientServerError as Ua, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Ui, refuseMalformedResourceEntries as Un, shouldRetainResource as Ur, resolveExplicitPhysicalId as Ut, renderStatefulReason as V, isRetryableTransientError as Va, findLargeInlineResources as Vi, refuseMalformedOutputs as Vn, orphansAfterRollback as Vr, WAFv2WebACLProvider as Vt, isWarmThroughputDecrease as W, markNonRetryable as Wa, injectiveKey as Wi, refuseMalformedResourcePropertiesForOrphan as Wn, AssetPublisher as Wr, assertRegionMatch as Wt, gray as X, PARTITION_TABLE as Xi, repairMalformedResourcePropertiesForReadOnly as Xn, rewriteTemplateAssetReferences as Xr, readConfigString as Xt, cyan as Y, __exportAll as Ya, expectedOwnerParam as Yi, repairMalformedResourceEntriesForReadOnly as Yn, loadPublishableAssetManifest as Yr, configStringRefusal as Yt, green as Z, canonicalizeRegion as Zi, repairMalformedResourcesForReadOnly as Zn, AssetModeResolver as Zr, replayWarn as Zt, bagHoldsSecretExpression as _, ConfigError as _a, redactDockerArgvValues as _i, UNREADABLE_ORPHANS_CONTAINER_ROW as _n, maskSecretsInError as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, nullPrototypeRecord as aa, validateAssetBucketName as ai, s3BucketDomainName as an, TemplateParser as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, DeployCancelledError as ba, escapeRegExp$1 as bi, hasReadableOrphans as bn, recoverMaskedOutput as br, startInterruptWatch as bt, replayFailedOperations as c, resolveAssemblyPath as ca, buildDockerImage as ci, s3BucketWebsiteUrl as cn, STATE_SOURCED_READBACK_RULES as cr, IAMRoleProvider as ct, updatePartialMessage as d, AwsClients as da, describeDockerExecFailure as di, applyCallerIdentityCredentials as dn, createSecretMasker as dr, ProviderRegistry as dt, failedStageNote as ea, ensureAssetStorage as ei, requireConfigString as en, findActionableSilentDrops as er, collectDeclaredOutputNames as et, updatePartialReason as f, getAwsClients as fa, describeDockerFailure as fi, callerEnvCredentials as fn, dynamicReferenceTokens as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, CdkdError as ga, partitionSensitiveEnv as gi, STATE_RESOURCES_MALFORMED as gn, markSameGenerationBag as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, AssetError as ha, getDockerCmd as hi, INTRINSIC_KEYS as hn, isSingleDynamicReferenceToken as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, hasPlainPrototype$1 as ia, readBootstrapMarkerBody as ii, s3BucketArn as in, DagBuilder as ir, secretBearing as it, isFinalSnapshotError as j, ResourceUpdateNotSupportedError as ja, resolveSkipPrefix as ji, malformedOutputsWarning as jn, shellQuote as jr, carriesFetchableDynamicReference as jt, ccRoutedFinalSnapshotError as k, ProvisioningError as ka, resolveAutoAssetStorage as ki, malformedOrphansWarning as kn, forceQuitRecoveryClause as kr, IntrinsicFunctionResolver as kt, replayRollback as l, clearBucketRegionCache as la, resolveDockerContextDirectory as li, applyRoleArnIfSet as ln, TEMPLATE_SOURCED_RULES as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, setAwsClients as ma, formatDockerLoginError as mi, DiffCalculator as mn, identityKeyFor as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, defineOwnKey as na, isCrossRegionRedirect as ni, producerRegionsFromState as nn, describeTypeWithThrottleRetry as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, ownValue as oa, validateContainerRepoName as oi, s3BucketDualStackDomainName as on, STATE_SOURCED_BASELINE_RULES as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, resetAwsClients as pa, dockerSpawnEnvWithSensitive as pi, envCredentialsAreAssumedRole as pn, errorCauseChain as pr, createMaskedRetryLogger as pt, formatResourceLine as q, describeAwsFailure as qa, producerRecordKey as qi, repairMalformedOrphansForReadOnly as qn, buildAssetRedirectMap as qr, configBooleanRefusal as qt, DeployEngine as r, hasOwnKey as ra, parseBootstrapMarker as ri, withSharedDrainBudget as rn, withRetry as rr, isExportAliasCollision as rt, planRollback as s, renderAssemblyPathEscape as sa, buildDenyExternalAccessPolicy as si, s3BucketRegionalDomainName as sn, STATE_SOURCED_CROSS_GENERATION_RULES as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, processStackMessages as ta, getBootstrapMarkerKey as ti, classifyReplaySecretRegion as tn, findSilentDropProperties as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, resolveBucketRegion as ua, describeDockerCapturedOutput as ui, AWS_CREDENTIAL_ENV_KEYS as un, carriesSecretMask as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, CrossAccountSecretRefusalError as va, runDockerForeground as vi, UNREADABLE_RESOURCES_MAP_ROW as vn, maskSecretsInText as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, LocalStartServiceError as wa, Synthesizer as wi, malformedExportNamesWarning as wn, S3StateBackend as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, DynamicReferenceRegionAmbiguousError as xa, stripControlChars as xi, hasReadableOutputs as xn, redactSecretsForState as xr, CloudControlProvider as xt, keptWholeReasonText as y, DependencyError as ya, runDockerStreaming as yi, displayLogicalId as yn, recordMaskOnlyValue as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, withErrorHandling as za, CFN_TEMPLATE_URL_LIMIT as zi, refuseMalformedOrphans as zn, importableOutputs as zr, refStateLookupFromResource as zt };
48197
+ //# sourceMappingURL=deploy-engine-DhZW4if5.js.map