@go-to-k/cdkd 0.288.6 → 0.289.0

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 { _ as withStackName, d as applyDefaultNameForFallback, f as generateResourceName, h as looksLikeCdkdGeneratedName, m as getCurrentStackName, n as getLogger, p as generateResourceNameWithFallback, r as isStdoutReservedForPayload, s as getLiveRenderer } from "./logger-Dw-3y48G.js";
1
+ import { 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 } from "./logger-D2Md1kTq.js";
2
2
  import { t as awsClientDefaults } from "./aws-client-defaults-D-iYiIJ6.js";
3
- import { t as getCdkdVersion } from "./version-4xTzOaA1.js";
3
+ import { t as getCdkdVersion } from "./version-CCKo6fK2.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";
@@ -9054,7 +9054,8 @@ const STATE_SCHEMA_VERSIONS_READABLE = [
9054
9054
  6,
9055
9055
  7,
9056
9056
  8,
9057
- 9
9057
+ 9,
9058
+ 10
9058
9059
  ];
9059
9060
  /**
9060
9061
  * Returns true when a recorded `DeletionPolicy` should prevent cdkd from
@@ -9126,6 +9127,46 @@ function exportNamesCarriedFrom(previous) {
9126
9127
  function skippedOutputsCarriedFrom(previous) {
9127
9128
  return previous.skippedOutputs === void 0 ? {} : { skippedOutputs: previous.skippedOutputs };
9128
9129
  }
9130
+ /**
9131
+ * Carry {@link StackState.orphans} across a rebuild that does not re-decide it
9132
+ * (issue #2934): absent stays absent, present stays as it was.
9133
+ *
9134
+ * **Every** field-enumerating `StackState` literal must spread this. The field
9135
+ * is the only record that a `Retain`-orphaned resource exists at all, so a save
9136
+ * that omits it does not merely lose a hint — it makes a live, billing AWS
9137
+ * resource untrackable and re-opens the deploy loop the record closes. That is
9138
+ * a stronger duty than {@link skippedOutputsCarriedFrom}'s, whose loss costs a
9139
+ * diff preview.
9140
+ *
9141
+ * Writers that re-DECIDE the set do not call this: the rollback arms append,
9142
+ * and the deploy drops an entry once it has been adopted or found absent from
9143
+ * AWS. Spread-form writers (`{ ...previous, ... }`) carry the field already and
9144
+ * need nothing.
9145
+ */
9146
+ function orphansCarriedFrom(previous) {
9147
+ return previous.orphans === void 0 ? {} : { orphans: previous.orphans };
9148
+ }
9149
+ /**
9150
+ * The `orphans` set a post-rollback save should persist (issue #2934): what the
9151
+ * record already carried, plus what THIS rollback just left in AWS.
9152
+ *
9153
+ * A merge rather than a carry, because a rollback both inherits and produces.
9154
+ * Keyed by `logicalId`, newest wins: a resource orphaned twice (deploy fails,
9155
+ * user retries, it fails again) has one live AWS resource, and the later record
9156
+ * describes the deploy that actually left it there. Keeping both would make the
9157
+ * next adoption pick arbitrarily between two states of the same resource.
9158
+ *
9159
+ * Returns `{}` when there is nothing on either side, so a stack that has never
9160
+ * orphaned anything keeps a byte-identical `state.json` and an old binary sees
9161
+ * exactly what it saw before.
9162
+ */
9163
+ function orphansAfterRollback(previous, newlyOrphaned) {
9164
+ if (previous.orphans === void 0 && newlyOrphaned.length === 0) return {};
9165
+ const byLogicalId = /* @__PURE__ */ new Map();
9166
+ for (const entry of previous.orphans ?? []) byLogicalId.set(entry.logicalId, entry);
9167
+ for (const entry of newlyOrphaned) byLogicalId.set(entry.logicalId, entry);
9168
+ return { orphans: [...byLogicalId.values()] };
9169
+ }
9129
9170
 
9130
9171
  //#endregion
9131
9172
  //#region src/types/rollback-journal.ts
@@ -9673,7 +9714,7 @@ var S3StateBackend = class {
9673
9714
  const { expectedEtag, migrateLegacy } = options;
9674
9715
  const body = {
9675
9716
  ...state,
9676
- version: 9,
9717
+ version: 10,
9677
9718
  stackName,
9678
9719
  region
9679
9720
  };
@@ -14726,13 +14767,22 @@ function redactSecretsForState(bag, secrets, source, rules = TEMPLATE_DERIVED_RU
14726
14767
  * GENERATION as the observed bag beside them (issue #1917 review). Left
14727
14768
  * unspecified, the derivation below is right for every other caller, whose
14728
14769
  * `properties` reach this function untouched.
14770
+ *
14771
+ * That derivation's fail-closed arm asks TWO questions, not one — the secrets
14772
+ * map must be EMPTY and the observed bag must be one THIS RUN produced (issue
14773
+ * [#2906](https://github.com/go-to-k/cdkd/issues/2906)). A caller re-writing a
14774
+ * PRIOR generation's `observedProperties` unchanged therefore keeps it intact
14775
+ * rather than masking positions it cannot pair. A caller whose bag IS fresh but
14776
+ * which does not route it through {@link markSameGenerationBag} should pass
14777
+ * {@link STATE_SOURCED_BASELINE_RULES} through `observedRules` rather than lean
14778
+ * on the derivation.
14729
14779
  */
14730
14780
  function scrubResourceRecord(record, secrets, sourceProperties, observedRules) {
14731
14781
  if (secrets.size === 0 && sourceProperties === void 0 && !record.observedProperties) return record;
14732
14782
  const next = { ...record };
14733
14783
  next.properties = redactSecretsForState(record.properties, secrets, sourceProperties);
14734
14784
  if (record.attributes) next.attributes = redactSecretsForState(record.attributes, secrets);
14735
- if (record.observedProperties) next.observedProperties = redactSecretsForState(record.observedProperties, secrets, sourceProperties ?? next.properties, observedRules ?? (sourceProperties !== void 0 ? TEMPLATE_SOURCED_RULES : secrets.size === 0 ? STATE_SOURCED_BASELINE_RULES : STATE_SOURCED_READBACK_RULES));
14785
+ if (record.observedProperties) next.observedProperties = redactSecretsForState(record.observedProperties, secrets, sourceProperties ?? next.properties, observedRules ?? (sourceProperties !== void 0 ? TEMPLATE_SOURCED_RULES : secrets.size === 0 && isSameGenerationBag(record.observedProperties) ? STATE_SOURCED_BASELINE_RULES : STATE_SOURCED_READBACK_RULES));
14736
14786
  return next;
14737
14787
  }
14738
14788
  /**
@@ -27587,7 +27637,7 @@ var CloudControlProvider = class {
27587
27637
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
27588
27638
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
27589
27639
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
27590
- const { ASGProvider } = await import("./asg-provider-CC6BMuNK.js").then((n) => n.n);
27640
+ const { ASGProvider } = await import("./asg-provider-1XVtAjhm.js").then((n) => n.n);
27591
27641
  const asgProvider = new ASGProvider();
27592
27642
  return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
27593
27643
  }
@@ -31138,7 +31188,7 @@ var ProviderRegistry = class {
31138
31188
  buildUnroutableSilentDropMessage(resourceType, drops) {
31139
31189
  const details = drops.map((d) => ` - ${d.property}: ${d.rationale}`).join("\n");
31140
31190
  const overrideHint = drops.map((d) => `${resourceType}:${d.property}`).join(",");
31141
- return `${resourceType} uses properties cdkd's SDK Provider does not handle, and this type cannot fall back to Cloud Control API (${isNonProvisionable(resourceType) ? "ProvisioningType: NON_PROVISIONABLE — Cloud Control has no handlers for it" : "the type's SDK provider opts out of the Cloud Control fallback (disableCcApiFallback)"}):\n${details}\nRemove the properties, or force the SDK provider path and accept the drop via --allow-unsupported-properties ${overrideHint} (the provider may still reject the resource if the property is required).`;
31191
+ return `${resourceType} uses properties cdkd's SDK Provider does not handle, and this type cannot fall back to Cloud Control API (${isNonProvisionable(resourceType) ? "ProvisioningType: NON_PROVISIONABLE — Cloud Control has no handlers for it" : "the type's SDK provider opts out of the Cloud Control fallback (disableCcApiFallback)"}):\n${details}\nRemove the properties, or force the SDK provider path and accept the drop via --prefer-sdk-route ${overrideHint} (the provider may still reject the resource if the property is required).`;
31142
31192
  }
31143
31193
  /**
31144
31194
  * Legacy entry point that returns just the provider. Delegates to
@@ -31295,15 +31345,23 @@ var ProviderRegistry = class {
31295
31345
  reportSilentDropDecisions(resources) {
31296
31346
  for (const { logicalId, resourceType, properties, provisionedBy } of resources) {
31297
31347
  const drops = findSilentDropProperties(resourceType, properties);
31298
- const overridden = provisionedBy === "cc-api" && !STICKY_CC_MIGRATION_EXEMPT.has(resourceType) ? [] : findAcceptedSilentDrops(resourceType, properties, this.allowedUnsupportedProperties);
31348
+ const stickyCc = provisionedBy === "cc-api" && !STICKY_CC_MIGRATION_EXEMPT.has(resourceType);
31349
+ const overridden = stickyCc ? [] : findAcceptedSilentDrops(resourceType, properties, this.allowedUnsupportedProperties);
31299
31350
  const autoRouted = drops.map(({ property }) => property).filter((property) => !this.allowedUnsupportedProperties.has(`${resourceType}:${property}`));
31300
31351
  if (autoRouted.length > 0) {
31301
31352
  const provider = this.providers.get(resourceType);
31302
31353
  if (isNonProvisionable(resourceType) || provider?.disableCcApiFallback === true) throw new Error(`${logicalId}: ${this.buildUnroutableSilentDropMessage(resourceType, drops.filter((d) => autoRouted.includes(d.property)))}`);
31303
- const message = `${logicalId} (${resourceType}): routing via Cloud Control API (cdkd's SDK Provider does not yet wire ${autoRouted.join(", ")} — CC API will forward the full property map. Override via --allow-unsupported-properties ${autoRouted.map((p) => `${resourceType}:${p}`).join(",")}.)`;
31354
+ const message = `${logicalId} (${resourceType}): routing via Cloud Control API (cdkd's SDK Provider does not yet wire ${autoRouted.join(", ")} — CC API will forward the full property map. Override via --prefer-sdk-route ${autoRouted.map((p) => `${resourceType}:${p}`).join(",")}.)`;
31304
31355
  if (provisionedBy === "cc-api") this.logger.debug(message);
31305
31356
  else this.logger.info(message);
31306
31357
  }
31358
+ const named = drops.map(({ property }) => property).filter((property) => this.allowedUnsupportedProperties.has(`${resourceType}:${property}`));
31359
+ if (named.length > 0 && (stickyCc || autoRouted.length > 0)) {
31360
+ const list = named.join(", ");
31361
+ const isAre = named.length === 1 ? "is" : "are";
31362
+ const [cause, remedy] = stickyCc ? ["this resource's state record already routes it to Cloud Control (provisionedBy: cc-api), which is decided before any property is consulted", "Returning this resource to the SDK provider is a destroy-and-recreate, not a flag change — see docs/cli-deploy-safety.md. Widening --prefer-sdk-route alone cannot do it."] : [`${autoRouted.join(", ")} ${autoRouted.length === 1 ? "is" : "are"} not covered by it, and one uncovered property routes the whole RESOURCE to Cloud Control`, `To keep the resource on its SDK provider, add ${autoRouted.map((p) => `${resourceType}:${p}`).join(",")} to --prefer-sdk-route as well.`];
31363
+ this.logger.warn(`${logicalId} (${resourceType}): --prefer-sdk-route had no effect for ${list} — ${cause}. Cloud Control forwards the full property map, so ${list} ${isAre} written to AWS after all. ${remedy}`);
31364
+ }
31307
31365
  if (overridden.length > 0) {
31308
31366
  const createOnly = getPropertyCoverage(resourceType)?.createOnlyDrops;
31309
31367
  const reroutable = overridden.filter((p) => createOnly?.has(p) !== true);
@@ -31314,7 +31372,7 @@ var ProviderRegistry = class {
31314
31372
  const one = needsRecreate.length === 1;
31315
31373
  remedies.push(`${needsRecreate.join(", ")} ${one ? "is" : "are"} create-only, so removing the override does not apply ${one ? "it" : "them"} either -- a create-only property can only be applied by recreating the resource.`);
31316
31374
  }
31317
- this.logger.warn(`${logicalId} (${resourceType}): ${overridden.join(", ")} will be silently dropped (--allow-unsupported-properties override accepted). ${remedies.join(" ")}`);
31375
+ this.logger.warn(`${logicalId} (${resourceType}): ${overridden.join(", ")} will be silently dropped (--prefer-sdk-route override accepted). ${remedies.join(" ")}`);
31318
31376
  }
31319
31377
  this.reportUnrecognizedProperties(logicalId, resourceType, properties, {
31320
31378
  provisionedBy,
@@ -31378,7 +31436,7 @@ var ProviderRegistry = class {
31378
31436
  const propList = unrecognized.join(", ");
31379
31437
  const overrideHint = unrecognized.map((p) => `${resourceType}:${p}`).join(",");
31380
31438
  const one = unrecognized.length === 1;
31381
- this.logger.warn(`${logicalId} (${resourceType}): ${propList} ${one ? "is" : "are"} not in cdkd's CFn schema snapshot for this type, so ${one ? "it" : "they"} will NOT reach AWS — the deploy will still report success. Anything of these shapes looks the same here: a misspelled name (fix the spelling); a read-only attribute, which is not settable on any engine (remove it); or a property AWS published after cdkd's snapshot, which cdkd should be routing via Cloud Control — please report that one: ${unsupportedPropertyIssueUrl(resourceType, unrecognized[0])}${one ? "" : ` (link is for ${unrecognized[0]})`}. If the drop is intended — an addPropertyOverride escape hatch — silence this via --allow-unsupported-properties ${overrideHint}.`);
31439
+ this.logger.warn(`${logicalId} (${resourceType}): ${propList} ${one ? "is" : "are"} not in cdkd's CFn schema snapshot for this type, so ${one ? "it" : "they"} will NOT reach AWS — the deploy will still report success. Anything of these shapes looks the same here: a misspelled name (fix the spelling); a read-only attribute, which is not settable on any engine (remove it); or a property AWS published after cdkd's snapshot, which cdkd should be routing via Cloud Control — please report that one: ${unsupportedPropertyIssueUrl(resourceType, unrecognized[0])}${one ? "" : ` (link is for ${unrecognized[0]})`}. If the drop is intended — an addPropertyOverride escape hatch — silence this via --prefer-sdk-route ${overrideHint}.`);
31382
31440
  }
31383
31441
  /**
31384
31442
  * Pure-functional discovery of every resource whose template uses one or
@@ -33459,6 +33517,209 @@ var DagExecutor = class {
33459
33517
  }
33460
33518
  };
33461
33519
 
33520
+ //#endregion
33521
+ //#region src/deployment/orphan-adoption.ts
33522
+ /**
33523
+ * True when the template still declares `logicalId` with `resourceType` and
33524
+ * supplies no explicit physical name for it.
33525
+ *
33526
+ * In that shape the name this deploy would generate equals the recorded
33527
+ * `physicalId` BY CONSTRUCTION — `generateResourceName` is deterministic over
33528
+ * exactly (stack name, logical id), truncation included, with no random
33529
+ * component. That matters because the engine cannot DERIVE the name to compare:
33530
+ * the per-type `ResourceNameOptions` live in the providers, and
33531
+ * `looksLikeCdkdGeneratedName`'s own doc records that the engine does not know
33532
+ * which type maps to which.
33533
+ *
33534
+ * An explicitly named resource is never adopted here. Two different reasons
33535
+ * converge on that: a template-supplied name may belong to someone else
33536
+ * entirely, and if the user CHANGED the name there is no collision to solve —
33537
+ * the ordinary CREATE succeeds and the orphan simply stays behind.
33538
+ */
33539
+ function templateStillDeclares(template, record, nameProperties) {
33540
+ const declared = template.Resources?.[record.logicalId];
33541
+ if (!declared) return false;
33542
+ if (declared.Type !== record.state.resourceType) return false;
33543
+ const properties = declared.Properties ?? {};
33544
+ return !nameProperties.some((p) => properties[p] !== void 0 && properties[p] !== null);
33545
+ }
33546
+ /**
33547
+ * Types the allow-list admits but adoption must still refuse (issue #2934).
33548
+ *
33549
+ * The primary gate asks "does cdkd derive a name for this type", which is the
33550
+ * by-construction premise restated. `AWS::Lambda::LayerVersion` passes it —
33551
+ * `FALLBACK_NAME_RULES` carries `LayerName` — while its provider records the
33552
+ * `LayerVersionArn` as the physical id (`lambda-layer-provider.ts:143`), so the
33553
+ * premise is false for it anyway. `AWS::ECS::TaskDefinition` is here as a BELT:
33554
+ * it is absent from both name tables today, so the primary gate already refuses
33555
+ * it, and an entry added there later (its `Family` is a plausible one) would
33556
+ * silently re-admit a type round 5 proved harmful.
33557
+ *
33558
+ * **Membership is decided by the three CONSEQUENCES, never by the id's SHAPE.**
33559
+ * An earlier revision of this doc said "the provider records an AWS-minted
33560
+ * identifier while `explicitNamePropertyFor` answers" — and at least six
33561
+ * admitted types satisfy that: `AWS::SNS::Topic` (ARN), `AWS::Cognito::UserPool`
33562
+ * (`userPoolId`), both ELBv2 types, `AWS::StepFunctions::StateMachine`,
33563
+ * `AWS::ECS::Service`. A maintainer applying it would add SNS Topic — the
33564
+ * module header's own motivating type — and gut the feature. The tests are:
33565
+ *
33566
+ * 1. the create API mints a NEW resource instead of colliding on the name, so
33567
+ * there is no loop to break;
33568
+ * 2. `update()` refuses outright, so an adopted resource's next change is a
33569
+ * REPLACEMENT;
33570
+ * 3. that replacement's delete destroys the very copy `DeletionPolicy: Retain`
33571
+ * preserved.
33572
+ *
33573
+ * All three, together. SNS Topic fails (1): `CreateTopic` returns the EXISTING
33574
+ * topic rather than minting a new one, which is exactly the shape adoption is
33575
+ * for — and is why the module header calls it the type that "raises nothing at
33576
+ * all".
33577
+ */
33578
+ const ADOPTION_REFUSED_TYPES = /* @__PURE__ */ new Set(["AWS::Lambda::LayerVersion", "AWS::ECS::TaskDefinition"]);
33579
+ /**
33580
+ * Decide what to do with each orphan record, before the diff runs.
33581
+ *
33582
+ * Ordering is load-bearing: the AWS existence check runs for EVERY record,
33583
+ * INDEPENDENTLY of whether the template still declares it. The reverse order
33584
+ * left a record whose logical id had left the template never checked, so it
33585
+ * never dropped — present, blocking nothing, surfacing nowhere, and with no
33586
+ * per-record command to clear it.
33587
+ */
33588
+ async function planOrphanAdoption(params) {
33589
+ const outcome = {
33590
+ adopted: {},
33591
+ remaining: [],
33592
+ refusals: [],
33593
+ notices: []
33594
+ };
33595
+ if (params.records.length === 0) return outcome;
33596
+ let siblingClaims;
33597
+ const claims = async () => siblingClaims ??= await params.readSiblingClaims();
33598
+ for (const record of params.records) {
33599
+ const { logicalId, state } = record;
33600
+ if (params.managedLogicalIds.has(logicalId)) {
33601
+ params.logger.debug(`orphan ${logicalId}: already present in state.resources — dropping the stale record`);
33602
+ continue;
33603
+ }
33604
+ let provider;
33605
+ try {
33606
+ provider = params.getProvider(state.resourceType, state.provisionedBy);
33607
+ } catch (error) {
33608
+ outcome.remaining.push(record);
33609
+ outcome.notices.push(`${logicalId} (${state.resourceType}) is still in AWS as ${state.physicalId} from an earlier rollback, but this build cannot route that type (${error instanceof Error ? error.message : String(error)}) — cdkd is not adopting it.`);
33610
+ continue;
33611
+ }
33612
+ if (!provider.import) {
33613
+ outcome.remaining.push(record);
33614
+ outcome.notices.push(`${logicalId} (${state.resourceType}) was left in AWS by an earlier rollback as ${state.physicalId}, but its provider cannot verify it — cdkd is not adopting it.`);
33615
+ continue;
33616
+ }
33617
+ let found;
33618
+ try {
33619
+ found = await provider.import({
33620
+ logicalId,
33621
+ resourceType: state.resourceType,
33622
+ stackName: params.stackName,
33623
+ region: params.region,
33624
+ properties: state.properties,
33625
+ knownPhysicalId: state.physicalId
33626
+ });
33627
+ } catch (error) {
33628
+ outcome.notices.push(`${logicalId} (${state.resourceType}) is recorded as left in AWS as ${state.physicalId}, but cdkd could not confirm it exists (${error instanceof Error ? error.message : String(error)}) — keeping the record and not adopting it this run.`);
33629
+ outcome.remaining.push(record);
33630
+ continue;
33631
+ }
33632
+ if (found !== null && found.physicalId !== state.physicalId) {
33633
+ outcome.remaining.push(record);
33634
+ outcome.notices.push(`${logicalId} (${state.resourceType}): cdkd asked about ${state.physicalId} and its provider answered for ${found.physicalId} — not adopting.`);
33635
+ continue;
33636
+ }
33637
+ if (found === null) {
33638
+ params.logger.debug(`orphan ${logicalId}: ${state.physicalId} no longer exists in AWS — dropping the record`);
33639
+ continue;
33640
+ }
33641
+ if (params.nameProperties(state.resourceType).length === 0 || ADOPTION_REFUSED_TYPES.has(state.resourceType)) {
33642
+ outcome.remaining.push(record);
33643
+ const why = ADOPTION_REFUSED_TYPES.has(state.resourceType) ? "a new deploy of it mints a new resource rather than colliding, and cdkd cannot update one in place — so adopting it would end in a replacement that destroys what DeletionPolicy: Retain preserved" : "cdkd does not derive that resource's physical name, so a new deploy mints a new resource instead of colliding";
33644
+ outcome.notices.push(`${logicalId} (${state.resourceType}) is still in AWS as ${state.physicalId} from an earlier rollback. cdkd does not re-adopt this type: ${why}. Delete it yourself when you no longer need it.`);
33645
+ continue;
33646
+ }
33647
+ if (!templateStillDeclares(params.template, record, params.nameProperties(state.resourceType))) {
33648
+ outcome.remaining.push(record);
33649
+ outcome.notices.push(`${logicalId} (${state.resourceType}) is still in AWS as ${state.physicalId} from an earlier rollback. This deploy does not create it under that name, so cdkd is leaving it alone.`);
33650
+ continue;
33651
+ }
33652
+ if ((await claims()).has(state.physicalId)) {
33653
+ outcome.refusals.push(`${logicalId}: ${state.physicalId} is already recorded by another cdkd stack. cdkd will not adopt a resource another stack manages.`);
33654
+ outcome.remaining.push(record);
33655
+ continue;
33656
+ }
33657
+ const refreshed = Object.create(null);
33658
+ for (const [key, value] of Object.entries(found.attributes ?? {})) {
33659
+ if (carriesSecretMask(value)) continue;
33660
+ refreshed[key] = value;
33661
+ }
33662
+ const mergedAttributes = Object.create(null);
33663
+ for (const [key, value] of Object.entries(refreshed)) mergedAttributes[key] = value;
33664
+ for (const [key, value] of Object.entries(state.attributes ?? {})) mergedAttributes[key] = value;
33665
+ outcome.adopted[logicalId] = {
33666
+ ...state,
33667
+ ...Object.keys(mergedAttributes).length > 0 || state.attributes ? { attributes: mergedAttributes } : {}
33668
+ };
33669
+ }
33670
+ return outcome;
33671
+ }
33672
+ /**
33673
+ * Every physical id recorded by a cdkd stack OTHER than `selfStackName` in
33674
+ * `selfRegion` (issue #2934).
33675
+ *
33676
+ * The orphan record proves cdkd created something under a name; it cannot
33677
+ * prove no one has since taken that resource over. A `cdkd import` into a
33678
+ * different stack during the rollback-to-redeploy window would leave one
33679
+ * physical id in two state files, and either stack's `cdkd destroy` would
33680
+ * then delete the other's live resource. This is the check that refuses it.
33681
+ *
33682
+ * Best-effort per sibling: a state file that fails to load is SKIPPED rather
33683
+ * than failing the caller, because the alternative is that one unreadable
33684
+ * record in an unrelated stack blocks every adoption in the account. That
33685
+ * makes the result a lower bound on what is claimed — stated here because it
33686
+ * is the direction that can let a wrong adoption through, and the reason this
33687
+ * check is one of several rather than the only one.
33688
+ *
33689
+ * Reachability is bounded by what this backend can see: another ACCOUNT's
33690
+ * bucket, and a stack deployed against a different `--state-bucket`, are
33691
+ * invisible here by construction.
33692
+ *
33693
+ * SHARED by `cdkd deploy` and `cdkd diff` (issue go-to-k/cdkd#2943) rather
33694
+ * than copied: the two must agree on which records they refuse, or the
33695
+ * preview stops predicting the deploy — which is the defect that issue is
33696
+ * about. A second implementation is the way they would drift apart.
33697
+ */
33698
+ function makeSiblingClaimReader(params) {
33699
+ const { stateBackend, selfStackName, selfRegion, logger } = params;
33700
+ return async () => {
33701
+ const claimed = /* @__PURE__ */ new Set();
33702
+ let refs;
33703
+ try {
33704
+ refs = await stateBackend.listStacks();
33705
+ } catch (error) {
33706
+ logger.debug(`orphan adoption: could not list sibling stacks — ${error instanceof Error ? error.message : String(error)}`);
33707
+ return claimed;
33708
+ }
33709
+ for (const ref of refs) {
33710
+ if (ref.stackName === selfStackName && ref.region === selfRegion) continue;
33711
+ if (ref.region === void 0) continue;
33712
+ try {
33713
+ const sibling = await stateBackend.getState(ref.stackName, ref.region);
33714
+ for (const record of Object.values(sibling?.state.resources ?? {})) claimed.add(record.physicalId);
33715
+ } catch (error) {
33716
+ logger.debug(`orphan adoption: skipping unreadable state for ${ref.stackName} — ${error instanceof Error ? error.message : String(error)}`);
33717
+ }
33718
+ }
33719
+ return claimed;
33720
+ };
33721
+ }
33722
+
33462
33723
  //#endregion
33463
33724
  //#region src/types/deployment-events.ts
33464
33725
  /**
@@ -35085,7 +35346,8 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
35085
35346
  const result = {
35086
35347
  failures: 0,
35087
35348
  warnings: 0,
35088
- interrupted: false
35349
+ interrupted: false,
35350
+ orphaned: []
35089
35351
  };
35090
35352
  if (operations.length === 0) {
35091
35353
  ctx.logger.info("No completed operations to roll back.");
@@ -35103,7 +35365,7 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
35103
35365
  result.interrupted = true;
35104
35366
  break;
35105
35367
  }
35106
- await replaySingle(otherOps[i], stateResources, stackName, ctx, resolver, orphanLogicalIds, result, options.afterOp, options.isInterrupted);
35368
+ await replaySingle(otherOps[i], stateResources, stackName, ctx, resolver, orphanLogicalIds, result, options.onOrphan, options.afterOp, options.isInterrupted);
35107
35369
  }
35108
35370
  if (!result.interrupted && createOps.length > 0) {
35109
35371
  const sorted = sortRollbackCreates(createOps, stateResources);
@@ -35112,7 +35374,7 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
35112
35374
  result.interrupted = true;
35113
35375
  break;
35114
35376
  }
35115
- await replaySingle(op, stateResources, stackName, ctx, resolver, orphanLogicalIds, result, options.afterOp, options.isInterrupted);
35377
+ await replaySingle(op, stateResources, stackName, ctx, resolver, orphanLogicalIds, result, options.onOrphan, options.afterOp, options.isInterrupted);
35116
35378
  }
35117
35379
  }
35118
35380
  ctx.logger.info("Rollback completed. Some resources may remain if deletion failed.");
@@ -35605,7 +35867,7 @@ function recordAfterRollbackUpdate(restored, result) {
35605
35867
  function recordedPropertiesAfterReplayCreate(restored, result) {
35606
35868
  return result.effectiveProperties === void 0 ? restored.properties : { ...result.effectiveProperties };
35607
35869
  }
35608
- async function replaySingle(op, stateResources, stackName, ctx, resolver, orphanLogicalIds, result, afterOp, isInterrupted) {
35870
+ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphanLogicalIds, result, onOrphan, afterOp, isInterrupted) {
35609
35871
  const action = classifyRollbackOp(op, stateResources, orphanLogicalIds);
35610
35872
  const { logger } = ctx;
35611
35873
  /**
@@ -35674,6 +35936,15 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
35674
35936
  const record = stateResources[op.logicalId];
35675
35937
  const orphanProvisionedBy = effectiveProvisionedBy(record, op.provisionedBy);
35676
35938
  createRollbackRoute = orphanProvisionedBy;
35939
+ if (record) {
35940
+ const orphaned = {
35941
+ logicalId: op.logicalId,
35942
+ orphanedAt: Date.now(),
35943
+ state: record
35944
+ };
35945
+ result.orphaned.push(orphaned);
35946
+ onOrphan?.(orphaned);
35947
+ }
35677
35948
  delete stateResources[op.logicalId];
35678
35949
  logger.info(` Rollback: Leaving ${op.logicalId} (${op.resourceType}) in AWS (DeletionPolicy: Retain) — removed from state`);
35679
35950
  await afterOp?.(op.logicalId);
@@ -35956,7 +36227,8 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
35956
36227
  failures: 0,
35957
36228
  warnings: 0,
35958
36229
  interrupted: false,
35959
- remainingFailedOps: []
36230
+ remainingFailedOps: [],
36231
+ orphaned: []
35960
36232
  };
35961
36233
  const { logger } = ctx;
35962
36234
  const resolver = new ReplayResolvers(ctx.region);
@@ -35998,8 +36270,18 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
35998
36270
  result.warnings++;
35999
36271
  break;
36000
36272
  case "orphan-failed-create-retain": {
36001
- const orphanProvisionedBy = effectiveProvisionedBy(stateResources[op.logicalId], op.provisionedBy);
36273
+ const failedCreateRecord = stateResources[op.logicalId];
36274
+ const orphanProvisionedBy = effectiveProvisionedBy(failedCreateRecord, op.provisionedBy);
36002
36275
  createRollbackRoute = orphanProvisionedBy;
36276
+ if (failedCreateRecord) {
36277
+ const orphaned = {
36278
+ logicalId: op.logicalId,
36279
+ orphanedAt: Date.now(),
36280
+ state: failedCreateRecord
36281
+ };
36282
+ result.orphaned.push(orphaned);
36283
+ options.onOrphan?.(orphaned);
36284
+ }
36003
36285
  delete stateResources[op.logicalId];
36004
36286
  logger.info(` Rollback: leaving partially-created ${op.logicalId} (${op.resourceType}) in AWS (DeletionPolicy: Retain) — removed from state`);
36005
36287
  await options.afterOp?.(op.logicalId);
@@ -36919,6 +37201,20 @@ var DeployEngine = class DeployEngine {
36919
37201
  */
36920
37202
  perResourceTemplateProps = /* @__PURE__ */ new Map();
36921
37203
  /**
37204
+ * The resource TYPE each logical id was resolved as during THIS deploy
37205
+ * (issue #2934), the sibling of {@link perResourceSecrets} and
37206
+ * {@link perResourceTemplateProps}.
37207
+ *
37208
+ * Exists only so the orphan-record redaction can tell "these needles belong
37209
+ * to this record" from "a CDK refactor reused this logical id for a different
37210
+ * resource". Keying that on `state.resources` instead was tried and is WRONG
37211
+ * in the direction that matters: an orphan is by definition NOT in
37212
+ * `resources`, so the gate read false for the record being minted, the
37213
+ * needles went empty, and the plaintext survived into `state.json`. The
37214
+ * real-AWS secret fixture caught it.
37215
+ */
37216
+ perResourceResolvedType = /* @__PURE__ */ new Map();
37217
+ /**
36922
37218
  * Resolved secrets recorded while resolving the stack OUTPUTS (a `CfnOutput`
36923
37219
  * whose Value resolves a `{{resolve:...}}` reference). Separate from the
36924
37220
  * per-resource maps for the same anti-cross-contamination reason. Reset per
@@ -37051,6 +37347,7 @@ var DeployEngine = class DeployEngine {
37051
37347
  this.perResourceSecrets = /* @__PURE__ */ new Map();
37052
37348
  this.noEchoAttributeResources = /* @__PURE__ */ new Map();
37053
37349
  this.perResourceTemplateProps = /* @__PURE__ */ new Map();
37350
+ this.perResourceResolvedType = /* @__PURE__ */ new Map();
37054
37351
  this.attemptedResolvedProps = /* @__PURE__ */ new Map();
37055
37352
  this.outputSecrets = /* @__PURE__ */ new Map();
37056
37353
  this.outputsTemplateSource = Object.create(null);
@@ -37439,10 +37736,18 @@ var DeployEngine = class DeployEngine {
37439
37736
  const templateProps = this.perResourceTemplateProps.get(logicalId);
37440
37737
  resources[logicalId] = scrubResourceRecord(record, secrets ?? /* @__PURE__ */ new Map(), templateProps);
37441
37738
  }
37739
+ const orphans = state.orphans?.map((entry) => {
37740
+ const sameResource = this.perResourceResolvedType.get(entry.logicalId) === entry.state.resourceType;
37741
+ return {
37742
+ ...entry,
37743
+ state: scrubResourceRecord(entry.state, (sameResource ? this.perResourceSecrets.get(entry.logicalId) : void 0) ?? /* @__PURE__ */ new Map(), sameResource ? this.perResourceTemplateProps.get(entry.logicalId) : void 0)
37744
+ };
37745
+ });
37442
37746
  return {
37443
37747
  ...state,
37444
37748
  resources,
37445
- outputs: this.redactOutputs(state.outputs)
37749
+ outputs: this.redactOutputs(state.outputs),
37750
+ ...orphans === void 0 ? {} : { orphans }
37446
37751
  };
37447
37752
  }
37448
37753
  /**
@@ -37615,14 +37920,20 @@ var DeployEngine = class DeployEngine {
37615
37920
  if (this.options.captureObservedState !== true) return;
37616
37921
  if (this.options.dryRun === true) return;
37617
37922
  let toRefresh = 0;
37923
+ let refused = 0;
37618
37924
  const candidates = [];
37619
37925
  for (const [logicalId, resource] of Object.entries(stateResources)) {
37620
37926
  if (resource.observedProperties !== void 0) continue;
37927
+ if (resource.observedBaselineRefused === true) {
37928
+ refused++;
37929
+ continue;
37930
+ }
37621
37931
  candidates.push({
37622
37932
  logicalId,
37623
37933
  resource
37624
37934
  });
37625
37935
  }
37936
+ if (refused > 0) this.logger.debug(`observed-properties auto-refresh SKIPPED for ${refused} resource(s) whose baseline a 'cdkd import' run refused (issue #2944): their recorded properties cannot position the redaction, so capturing an AWS readback against them could persist a resolved secret in plaintext. A deploy that actually CHANGES one of them restores its baseline; a NO_CHANGE deploy does not.`);
37626
37937
  if (candidates.length === 0) return;
37627
37938
  const allSiblings = {};
37628
37939
  for (const [lid, res] of Object.entries(stateResources)) allSiblings[lid] = {
@@ -37672,7 +37983,7 @@ var DeployEngine = class DeployEngine {
37672
37983
  renderer.start();
37673
37984
  const currentStateData = await this.stateBackend.getState(stackName, this.stackRegion);
37674
37985
  const currentState = currentStateData?.state ?? {
37675
- version: 9,
37986
+ version: 10,
37676
37987
  region: this.stackRegion,
37677
37988
  stackName,
37678
37989
  resources: {},
@@ -37707,6 +38018,9 @@ var DeployEngine = class DeployEngine {
37707
38018
  const conditions = await this.resolver.evaluateConditions(context);
37708
38019
  this.logger.debug(`Evaluated ${Object.keys(conditions).length} conditions: ${Object.keys(conditions).join(", ")}`);
37709
38020
  const effectiveTemplate = this.templateParser.filterResourcesByCondition(template, conditions);
38021
+ const orphanCountBeforeAdoption = (currentState.orphans ?? []).length;
38022
+ const orphanPlan = await this.adoptRollbackOrphans(currentState, effectiveTemplate);
38023
+ const orphansChanged = Object.keys(orphanPlan.adopted).length > 0 || (currentState.orphans ?? []).length !== orphanCountBeforeAdoption;
37710
38024
  const resourceTypes = new Set(Object.values(effectiveTemplate.Resources || {}).map((r) => r.Type).filter((type) => type !== "AWS::CDK::Metadata"));
37711
38025
  this.providerRegistry.validateResourceTypes(resourceTypes);
37712
38026
  this.logger.debug(`All resource types validated`);
@@ -37750,12 +38064,13 @@ var DeployEngine = class DeployEngine {
37750
38064
  const observedRefresh = this.observedCaptureTasks.size > 0;
37751
38065
  if (observedRefresh) await this.drainObservedCaptures(currentState.resources);
37752
38066
  const skippedOutputsChanged = !skippedOutputsEqual(currentState.skippedOutputs, this.skippedOutputs);
37753
- if (observedRefresh || outputsChanged || exportSetChanged || skippedOutputsChanged) try {
38067
+ if (observedRefresh || outputsChanged || exportSetChanged || skippedOutputsChanged || orphansChanged) try {
37754
38068
  const refreshedState = {
37755
- version: 9,
38069
+ version: 10,
37756
38070
  region: this.stackRegion,
37757
38071
  stackName: currentState.stackName,
37758
38072
  resources: currentState.resources,
38073
+ ...orphansCarriedFrom(currentState),
37759
38074
  outputs: outputsChanged ? resolvedOutputs : persistedOutputs,
37760
38075
  ...resolutionFailed ? exportNamesCarriedFrom(currentState) : { exportNames: [...this.resolvedExportNames] },
37761
38076
  ...this.skippedOutputs && { skippedOutputs: { ...this.skippedOutputs } },
@@ -37876,13 +38191,14 @@ var DeployEngine = class DeployEngine {
37876
38191
  saveChain = saveChain.then(async () => {
37877
38192
  try {
37878
38193
  const partialState = {
37879
- version: 9,
38194
+ version: 10,
37880
38195
  region: this.stackRegion,
37881
38196
  stackName: currentState.stackName,
37882
38197
  resources: newResources,
37883
38198
  outputs: currentState.outputs,
37884
38199
  ...exportNamesCarriedFrom(currentState),
37885
38200
  ...skippedOutputsCarriedFrom(currentState),
38201
+ ...orphansCarriedFrom(currentState),
37886
38202
  ...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
37887
38203
  lastModified: Date.now()
37888
38204
  };
@@ -38009,13 +38325,14 @@ var DeployEngine = class DeployEngine {
38009
38325
  const initialDeploy = currentEtag === void 0;
38010
38326
  try {
38011
38327
  const preRollbackState = {
38012
- version: 9,
38328
+ version: 10,
38013
38329
  region: this.stackRegion,
38014
38330
  stackName: currentState.stackName,
38015
38331
  resources: newResources,
38016
38332
  outputs: currentState.outputs,
38017
38333
  ...exportNamesCarriedFrom(currentState),
38018
38334
  ...skippedOutputsCarriedFrom(currentState),
38335
+ ...orphansCarriedFrom(currentState),
38019
38336
  ...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
38020
38337
  lastModified: Date.now()
38021
38338
  };
@@ -38031,6 +38348,7 @@ var DeployEngine = class DeployEngine {
38031
38348
  this.logger.warn(`Failed to save partial state before rollback: ${saveError instanceof Error ? saveError.message : String(saveError)}`);
38032
38349
  }
38033
38350
  let autoRollbackClean = false;
38351
+ let rollbackOrphans = [];
38034
38352
  if (error instanceof InterruptedError || isInterruptedWaitError(error)) {
38035
38353
  await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "interrupted", initialDeploy);
38036
38354
  this.logger.info(`Partial state saved (${Object.keys(newResources).length} resources). Run deploy again to resume, 'cdkd rollback' to revert, or destroy to clean up.`);
@@ -38042,17 +38360,20 @@ var DeployEngine = class DeployEngine {
38042
38360
  this.logger.warn("Partial state has been saved. Run 'cdkd deploy' to resume, 'cdkd rollback' to revert, or destroy to clean up.");
38043
38361
  } else {
38044
38362
  await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "auto-rollback-started", initialDeploy);
38045
- autoRollbackClean = (await this.performRollback(completedOperations, newResources, stackName, currentState)).failures === 0;
38363
+ const rollbackResult = await this.performRollback(completedOperations, newResources, stackName, currentState);
38364
+ autoRollbackClean = rollbackResult.failures === 0;
38365
+ rollbackOrphans = rollbackResult.orphaned;
38046
38366
  }
38047
38367
  try {
38048
38368
  const postRollbackState = {
38049
- version: 9,
38369
+ version: 10,
38050
38370
  region: this.stackRegion,
38051
38371
  stackName: currentState.stackName,
38052
38372
  resources: newResources,
38053
38373
  outputs: currentState.outputs,
38054
38374
  ...exportNamesCarriedFrom(currentState),
38055
38375
  ...skippedOutputsCarriedFrom(currentState),
38376
+ ...orphansAfterRollback(currentState, rollbackOrphans),
38056
38377
  ...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
38057
38378
  lastModified: Date.now()
38058
38379
  };
@@ -38064,13 +38385,14 @@ var DeployEngine = class DeployEngine {
38064
38385
  try {
38065
38386
  const freshEtag = (await this.stateBackend.getState(stackName, this.stackRegion))?.etag;
38066
38387
  const postRollbackState = {
38067
- version: 9,
38388
+ version: 10,
38068
38389
  region: this.stackRegion,
38069
38390
  stackName: currentState.stackName,
38070
38391
  resources: newResources,
38071
38392
  outputs: currentState.outputs,
38072
38393
  ...exportNamesCarriedFrom(currentState),
38073
38394
  ...skippedOutputsCarriedFrom(currentState),
38395
+ ...orphansAfterRollback(currentState, rollbackOrphans),
38074
38396
  ...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
38075
38397
  lastModified: Date.now()
38076
38398
  };
@@ -38096,10 +38418,11 @@ var DeployEngine = class DeployEngine {
38096
38418
  }
38097
38419
  return {
38098
38420
  state: {
38099
- version: 9,
38421
+ version: 10,
38100
38422
  region: this.stackRegion,
38101
38423
  stackName: currentState.stackName,
38102
38424
  resources: newResources,
38425
+ ...orphansCarriedFrom(currentState),
38103
38426
  outputs,
38104
38427
  exportNames: [...this.resolvedExportNames],
38105
38428
  ...this.skippedOutputs && { skippedOutputs: { ...this.skippedOutputs } },
@@ -38135,13 +38458,14 @@ var DeployEngine = class DeployEngine {
38135
38458
  */
38136
38459
  async persistStateAfterOutputFailure(stackName, currentState, newResources, currentEtag, pendingMigration) {
38137
38460
  const buildState = () => ({
38138
- version: 9,
38461
+ version: 10,
38139
38462
  region: this.stackRegion,
38140
38463
  stackName: currentState.stackName,
38141
38464
  resources: newResources,
38142
38465
  outputs: currentState.outputs,
38143
38466
  ...exportNamesCarriedFrom(currentState),
38144
38467
  ...skippedOutputsCarriedFrom(currentState),
38468
+ ...orphansCarriedFrom(currentState),
38145
38469
  ...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
38146
38470
  lastModified: Date.now()
38147
38471
  });
@@ -38169,11 +38493,60 @@ var DeployEngine = class DeployEngine {
38169
38493
  * command drives identical semantics). Thin wrapper that builds the
38170
38494
  * executor context from the engine's collaborators and delegates.
38171
38495
  */
38496
+ /**
38497
+ * Re-adopt what a previous rollback left in AWS, before the diff runs
38498
+ * (issue #2934).
38499
+ *
38500
+ * MUTATES `currentState`: adopted records go into `resources` so the diff
38501
+ * sees them, and `orphans` is replaced by the surviving set so every save
38502
+ * on every path below persists the same object. Mutation rather than a
38503
+ * returned copy because `currentState` is read by ~a dozen later sites and
38504
+ * threading a second binding through all of them is how one gets missed.
38505
+ *
38506
+ * Refusals THROW. A record whose name this deploy is about to request, that
38507
+ * cdkd cannot vouch for, is exactly the go-to-k/cdkd#2916 situation: letting
38508
+ * the deploy run would collide and roll back anyway, adding another orphan
38509
+ * on the way.
38510
+ */
38511
+ async adoptRollbackOrphans(currentState, effectiveTemplate) {
38512
+ const records = currentState.orphans ?? [];
38513
+ const plan = await planOrphanAdoption({
38514
+ records,
38515
+ managedLogicalIds: new Set(Object.keys(currentState.resources)),
38516
+ template: effectiveTemplate,
38517
+ stackName: currentState.stackName,
38518
+ region: this.stackRegion,
38519
+ getProvider: (type, provisionedBy) => this.providerRegistry.getProviderFor({
38520
+ resourceType: type,
38521
+ ...provisionedBy !== void 0 && { provisionedBy }
38522
+ }).provider,
38523
+ nameProperties: (type) => {
38524
+ const property = explicitNamePropertyFor(type);
38525
+ return property === void 0 ? [] : [property];
38526
+ },
38527
+ readSiblingClaims: makeSiblingClaimReader({
38528
+ stateBackend: this.stateBackend,
38529
+ selfStackName: currentState.stackName,
38530
+ selfRegion: this.stackRegion,
38531
+ logger: this.logger
38532
+ }),
38533
+ logger: { debug: (m) => this.logger.debug(m) }
38534
+ });
38535
+ for (const notice of plan.notices) this.logger.info(notice);
38536
+ if (plan.refusals.length > 0) throw new Error(`Deploy refused — cdkd left ${plan.refusals.length} resource(s) in AWS that it cannot safely re-adopt:\n ${plan.refusals.join("\n ")}`);
38537
+ for (const [logicalId, record] of Object.entries(plan.adopted)) {
38538
+ currentState.resources[logicalId] = record;
38539
+ this.logger.info(`Adopting ${logicalId} (${record.resourceType}) left in AWS by an earlier rollback as ${record.physicalId}`);
38540
+ }
38541
+ if (records.length > 0) currentState.orphans = plan.remaining;
38542
+ return plan;
38543
+ }
38172
38544
  async performRollback(completedOperations, stateResources, stackName, previousState) {
38173
38545
  const result = await replayRollback(completedOperations, stateResources, stackName, this.rollbackExecutorContext(previousState));
38174
38546
  return {
38175
38547
  failures: result.failures,
38176
- warnings: result.warnings
38548
+ warnings: result.warnings,
38549
+ orphaned: result.orphaned
38177
38550
  };
38178
38551
  }
38179
38552
  /**
@@ -38556,6 +38929,7 @@ var DeployEngine = class DeployEngine {
38556
38929
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
38557
38930
  this.refuseRedactedAttributeReads(logicalId, resourceType, context);
38558
38931
  this.perResourceTemplateProps.set(logicalId, desiredProps);
38932
+ this.perResourceResolvedType.set(logicalId, resourceType);
38559
38933
  const createSecrets = context.recordedSecretValues ?? /* @__PURE__ */ new Map();
38560
38934
  recordNestedStackParameterExpressions(createSecrets, resourceType, resolvedProps, desiredProps);
38561
38935
  this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
@@ -38606,6 +38980,7 @@ var DeployEngine = class DeployEngine {
38606
38980
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
38607
38981
  this.refuseRedactedAttributeReads(logicalId, resourceType, context);
38608
38982
  this.perResourceTemplateProps.set(logicalId, desiredProps);
38983
+ this.perResourceResolvedType.set(logicalId, resourceType);
38609
38984
  recordNestedStackParameterExpressions(updateSecrets, resourceType, resolvedProps, desiredProps);
38610
38985
  this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
38611
38986
  this.attemptedResolvedProps.set(logicalId, resolvedProps);
@@ -39595,5 +39970,5 @@ var DeployEngine = class DeployEngine {
39595
39970
  };
39596
39971
 
39597
39972
  //#endregion
39598
- export { ProviderRegistry as $, formatDockerLoginError as $n, PartialFailureError as $r, STATE_SOURCED_BASELINE_RULES as $t, renderStatefulReason as A, stringifyValue as An, PARTITION_TABLE as Ar, configStringRefusal as At, red as B, getBootstrapMarkerKey as Bn, setAwsClients as Br, s3BucketDomainName as Bt, refusesFinalSnapshot as C, CUSTOM_RESOURCE_RESPONSE_PREFIX as Cn, CFN_TEMPLATE_URL_LIMIT as Cr, refStateLookupFromResource as Ct, MULTI_REGION_RECREATE_BLOCKED_TYPES as D, importableOutputs as Dn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Dr, assertRegionMatch as Dt, extractDeploymentEventError as E, importableOutputKeys as En, uploadCfnTemplate as Er, resolveExplicitPhysicalId as Et, formatResourceLine as F, rewriteTemplateAssetReferences as Fn, clearBucketRegionCache as Fr, requireConfigString as Ft, isExportAliasCollision as G, validateContainerRepoName as Gn, DependencyError as Gr, DiffCalculator as Gt, collectDeclaredOutputNames as H, parseBootstrapMarker as Hn, CdkdError as Hr, s3BucketRegionalDomainName as Ht, bold as I, AssetModeResolver as In, resolveBucketRegion as Ir, classifyReplaySecretRegion as It, secretSafeKeyDisplay as J, buildDockerImage as Jn, IntrinsicResolutionRefusalError as Jr, findSilentDropProperties as Jt, secretBearing as K, buildDenyExternalAccessPolicy as Kn, DeployCancelledError as Kr, INTRINSIC_KEYS as Kt, cyan as L, BOOTSTRAP_MARKER_PREFIX as Ln, AwsClients as Lr, producerRegionsFromState as Lt, coerceWarmThroughput as M, buildAssetRedirectMap as Mn, derivePartitionAndUrlSuffix as Mr, replayWarn as Mt, isWarmThroughputDecrease as N, createAssetRedirectResolver as Nn, AssemblyReader as Nr, requireConfigArray as Nt, isStatefulRecreateTargetForReplace as O, shouldRetainResource as On, displaySafe as Or, coerceCfnBoolean as Ot, toFiniteNumber as P, loadPublishableAssetManifest as Pn, processStackMessages as Pr, requireConfigObject as Pt, clearOnUpdateRemoval as Q, dockerSpawnEnvWithSensitive as Qn, NestedStackChildDirectDestroyError as Qr, TemplateParser as Qt, gray as R, assertAssetBucketRegion as Rn, getAwsClients as Rr, withSharedDrainBudget as Rt, isFinalSnapshotError as S, shellQuote as Sn, CFN_TEMPLATE_BODY_LIMIT as Sr, parameterTypeMayLoseSecretIdentity as St, makeCanonicalizePropertiesFn as T, exportNamesCarriedFrom as Tn, findLargeInlineResources as Tr, normalizeAwsTagsToCfn as Tt, collectPublishedOutputNames as U, readBootstrapMarkerBody as Un, ConfigError as Ur, s3BucketWebsiteUrl as Ut, yellow as V, isCrossRegionRedirect as Vn, AssetError as Vr, s3BucketDualStackDomainName as Vt, exportAliasCollisionScrubWarning as W, validateAssetBucketName as Wn, CrossAccountSecretRefusalError as Wr, applyRoleArnIfSet as Wt, IAMRoleProvider as X, describeDockerExecFailure as Xn, LocalStartServiceError as Xr, withRetry as Xt, getCurrentResourceSecrets as Y, describeDockerCapturedOutput as Yn, LocalInvokeBuildError as Yr, describeTypeWithThrottleRetry as Yt, collectInlinePolicyNamesManagedBySiblings as Z, describeDockerFailure as Zn, LockError as Zr, DagBuilder as Zt, ATOMIC_FINAL_SNAPSHOT_TYPES as _, retryClassificationText as _i, rebuildClientForBucketRegion as _n, resolveStateBucketWithDefault as _r, carriesDynamicReference as _t, DeploymentEventsStore as a, StateError as ai, dynamicReferenceTokens as an, escapeRegExp$1 as ar, endCommandInterruptScope as at, ccRoutedFinalSnapshotError as b, buildLockContentionMessage as bn, stateBucketExistenceConfirmed as br, getAccountInfo as bt, replayFailedOperations as c, isCdkdError as ci, isSingleDynamicReferenceToken as cn, getDockerImageBySourceHash as cr, startInterruptWatch as ct, updatePartialReason as d, isMarkedNonRetryable as di, recordMaskOnlyValue as dn, getDefaultStateBucketName as dr, UNSPECIFIED_SKIP_REASON as dt, ProvisioningError as ei, STATE_SOURCED_CROSS_GENERATION_RULES as en, getDockerCmd as er, wouldReturnToSdkProvider as et, withResourceDeadline as f, isRetryableTransientError as fi, recoverMaskedOutput as fn, getLegacyStateBucketName as fr, deleteIndeterminateGuards as ft, bindingSkippedOutputs as g, markRedactedCause as gi, S3StateBackend as gn, resolveSkipPrefix as gr, IntrinsicFunctionResolver as gt, computeImplicitDeleteEdges as h, markNonRetryable as hi, LockManager as hn, resolveCaptureObservedState as hr, isTerminationProtectionPropagationError as ht, DeploymentEventsReader as i, StackTerminationProtectionError as ii, createSecretMasker as in, runDockerStreaming as ir, beginCommandInterruptScope as it, WARM_THROUGHPUT_MEMBERS as j, WorkGraph as jn, canonicalizeRegion as jr, readConfigString as jt, isStatefulRecreateTargetSync as k, AssetPublisher as kn, expectedOwnerParam as kr, configBooleanRefusal as kt, replayRollback as l, normalizeAwsError as li, maskSecretsInError as ln, Synthesizer as lr, CloudControlProvider as lt, IMPLICIT_DELETE_DEPENDENCIES as m, isTransientServerError as mi, scrubResourceRecord as mn, resolveAutoAssetStorage as mr, disableInstanceApiTermination as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, ResourceUpdateNotSupportedError as ni, TEMPLATE_SOURCED_RULES as nn, redactDockerArgvValues as nr, maskDeep as nt, planFailedOps as o, SynthesisError as oi, errorCauseChain as on, stripControlChars as or, interruptWatchListenerCount as ot, maskingRetryLogger as p, isThrottlingError as pi, redactSecretsForState as pn, resolveApp as pr, deleteSkipReason as pt, secretBearingStateKeyWarning as q, describeAwsFailure as qn, DynamicReferenceRegionAmbiguousError as qr, findActionableSilentDrops as qt, DeployEngine as r, StackHasActiveImportsError as ri, carriesSecretMask as rn, runDockerForeground as rr, maskerOrIdentity as rt, planRollback as s, formatError as si, identityKeyFor as sn, AssetManifestLoader as sr, isInterruptedWaitError as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, ResourceTimeoutError as ti, STATE_SOURCED_READBACK_RULES as tn, partitionSensitiveEnv as tr, createMaskedRetryLogger as tt, updatePartialMessage as u, withErrorHandling as ui, maskSecretsInText as un, synthesisStatusMessage as ur, slowCcOperationTimeoutMs as ut, PRE_DELETE_SNAPSHOT_TYPES as v, __exportAll as vi, UNRENDERABLE as vn, resolveStateBucketWithDefaultAndSource as vr, cfnRefValueFromPhysicalId as vt, unsupportedFinalSnapshotError as w, DEFAULT_STATE_PREFIX as wn, MIGRATE_TMP_PREFIX as wr, WAFv2WebACLProvider as wt, createPreDeleteFinalSnapshot as x, forceQuitRecoveryClause as xn, warnDeprecatedNoPrefixCliFlag as xr, isUnboundTemplateParameter as xt, buildFinalSnapshotIdentifier as y, buildForceUnlockCommand as yn, resolveUseCdkBootstrapAssets as yr, coerceParameterTypedValue as yt, green as z, ensureAssetStorage as zn, resetAwsClients as zr, s3BucketArn as zt };
39599
- //# sourceMappingURL=deploy-engine-umIP3xus.js.map
39973
+ export { collectInlinePolicyNamesManagedBySiblings as $, describeDockerCapturedOutput as $n, LocalInvokeBuildError as $r, DagBuilder as $t, isStatefulRecreateTargetForReplace as A, orphansAfterRollback as An, uploadCfnTemplate as Ar, coerceCfnBoolean as At, gray as B, AssetModeResolver as Bn, resolveBucketRegion as Br, withSharedDrainBudget as Bt, refusesFinalSnapshot as C, forceQuitRecoveryClause as Cn, resolveUseCdkBootstrapAssets as Cr, isUnboundTemplateParameter as Ct, makeSiblingClaimReader as D, exportNamesCarriedFrom as Dn, CFN_TEMPLATE_URL_LIMIT as Dr, normalizeAwsTagsToCfn as Dt, extractDeploymentEventError as E, DEFAULT_STATE_PREFIX as En, CFN_TEMPLATE_BODY_LIMIT as Er, WAFv2WebACLProvider as Et, isWarmThroughputDecrease as F, WorkGraph as Fn, canonicalizeRegion as Fr, requireConfigArray as Ft, collectPublishedOutputNames as G, isCrossRegionRedirect as Gn, AssetError as Gr, s3BucketWebsiteUrl as Gt, red as H, assertAssetBucketRegion as Hn, getAwsClients as Hr, s3BucketDomainName as Ht, toFiniteNumber as I, buildAssetRedirectMap as In, derivePartitionAndUrlSuffix as Ir, requireConfigObject as It, secretBearing as J, validateAssetBucketName as Jn, CrossAccountSecretRefusalError as Jr, INTRINSIC_KEYS as Jt, exportAliasCollisionScrubWarning as K, parseBootstrapMarker as Kn, CdkdError as Kr, applyRoleArnIfSet as Kt, formatResourceLine as L, createAssetRedirectResolver as Ln, AssemblyReader as Lr, requireConfigString as Lt, renderStatefulReason as M, shouldRetainResource as Mn, displaySafe as Mr, configStringRefusal as Mt, WARM_THROUGHPUT_MEMBERS as N, AssetPublisher as Nn, expectedOwnerParam as Nr, readConfigString as Nt, planOrphanAdoption as O, importableOutputKeys as On, MIGRATE_TMP_PREFIX as Or, resolveExplicitPhysicalId as Ot, coerceWarmThroughput as P, stringifyValue as Pn, PARTITION_TABLE as Pr, replayWarn as Pt, IAMRoleProvider as Q, buildDockerImage as Qn, IntrinsicResolutionRefusalError as Qr, withRetry as Qt, bold as R, loadPublishableAssetManifest as Rn, processStackMessages as Rr, classifyReplaySecretRegion as Rt, isFinalSnapshotError as S, __exportAll as Si, buildLockContentionMessage as Sn, resolveStateBucketWithDefaultAndSource as Sr, getAccountInfo as St, makeCanonicalizePropertiesFn as T, CUSTOM_RESOURCE_RESPONSE_PREFIX as Tn, warnDeprecatedNoPrefixCliFlag as Tr, refStateLookupFromResource as Tt, yellow as U, ensureAssetStorage as Un, resetAwsClients as Ur, s3BucketDualStackDomainName as Ut, green as V, BOOTSTRAP_MARKER_PREFIX as Vn, AwsClients as Vr, s3BucketArn as Vt, collectDeclaredOutputNames as W, getBootstrapMarkerKey as Wn, setAwsClients as Wr, s3BucketRegionalDomainName as Wt, secretSafeKeyDisplay as X, buildDenyExternalAccessPolicy as Xn, DeployCancelledError as Xr, findSilentDropProperties as Xt, secretBearingStateKeyWarning as Y, validateContainerRepoName as Yn, DependencyError as Yr, findActionableSilentDrops as Yt, getCurrentResourceSecrets as Z, describeAwsFailure as Zn, DynamicReferenceRegionAmbiguousError as Zr, describeTypeWithThrottleRetry as Zt, ATOMIC_FINAL_SNAPSHOT_TYPES as _, isThrottlingError as _i, LockManager as _n, resolveApp as _r, isTerminationProtectionPropagationError as _t, DeploymentEventsStore as a, ResourceTimeoutError as ai, carriesSecretMask as an, partitionSensitiveEnv as ar, maskerOrIdentity as at, ccRoutedFinalSnapshotError as b, markRedactedCause as bi, UNRENDERABLE as bn, resolveSkipPrefix as br, cfnRefValueFromPhysicalId as bt, replayFailedOperations as c, StackTerminationProtectionError as ci, errorCauseChain as cn, runDockerStreaming as cr, interruptWatchListenerCount as ct, updatePartialReason as d, formatError as di, maskSecretsInError as dn, AssetManifestLoader as dr, CloudControlProvider as dt, LocalStartServiceError as ei, TemplateParser as en, describeDockerExecFailure as er, clearOnUpdateRemoval as et, withResourceDeadline as f, isCdkdError as fi, maskSecretsInText as fn, getDockerImageBySourceHash as fr, slowCcOperationTimeoutMs as ft, bindingSkippedOutputs as g, isRetryableTransientError as gi, scrubResourceRecord as gn, getLegacyStateBucketName as gr, disableInstanceApiTermination as gt, computeImplicitDeleteEdges as h, isMarkedNonRetryable as hi, redactSecretsForState as hn, getDefaultStateBucketName as hr, deleteSkipReason as ht, DeploymentEventsReader as i, ProvisioningError as ii, TEMPLATE_SOURCED_RULES as in, getDockerCmd as ir, maskDeep as it, isStatefulRecreateTargetSync as j, orphansCarriedFrom as jn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as jr, configBooleanRefusal as jt, MULTI_REGION_RECREATE_BLOCKED_TYPES as k, importableOutputs as kn, findLargeInlineResources as kr, assertRegionMatch as kt, replayRollback as l, StateError as li, identityKeyFor as ln, escapeRegExp$1 as lr, isInterruptedWaitError as lt, IMPLICIT_DELETE_DEPENDENCIES as m, withErrorHandling as mi, recoverMaskedOutput as mn, synthesisStatusMessage as mr, deleteIndeterminateGuards as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, NestedStackChildDirectDestroyError as ni, STATE_SOURCED_CROSS_GENERATION_RULES as nn, dockerSpawnEnvWithSensitive as nr, wouldReturnToSdkProvider as nt, planFailedOps as o, ResourceUpdateNotSupportedError as oi, createSecretMasker as on, redactDockerArgvValues as or, beginCommandInterruptScope as ot, maskingRetryLogger as p, normalizeAwsError as pi, recordMaskOnlyValue as pn, Synthesizer as pr, UNSPECIFIED_SKIP_REASON as pt, isExportAliasCollision as q, readBootstrapMarkerBody as qn, ConfigError as qr, DiffCalculator as qt, DeployEngine as r, PartialFailureError as ri, STATE_SOURCED_READBACK_RULES as rn, formatDockerLoginError as rr, createMaskedRetryLogger as rt, planRollback as s, StackHasActiveImportsError as si, dynamicReferenceTokens as sn, runDockerForeground as sr, endCommandInterruptScope as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, LockError as ti, STATE_SOURCED_BASELINE_RULES as tn, describeDockerFailure as tr, ProviderRegistry as tt, updatePartialMessage as u, SynthesisError as ui, isSingleDynamicReferenceToken as un, stripControlChars as ur, startInterruptWatch as ut, PRE_DELETE_SNAPSHOT_TYPES as v, isTransientServerError as vi, S3StateBackend as vn, resolveAutoAssetStorage as vr, IntrinsicFunctionResolver as vt, unsupportedFinalSnapshotError as w, shellQuote as wn, stateBucketExistenceConfirmed as wr, parameterTypeMayLoseSecretIdentity as wt, createPreDeleteFinalSnapshot as x, retryClassificationText as xi, buildForceUnlockCommand as xn, resolveStateBucketWithDefault as xr, coerceParameterTypedValue as xt, buildFinalSnapshotIdentifier as y, markNonRetryable as yi, rebuildClientForBucketRegion as yn, resolveCaptureObservedState as yr, carriesDynamicReference as yt, cyan as z, rewriteTemplateAssetReferences as zn, clearBucketRegionCache as zr, producerRegionsFromState as zt };
39974
+ //# sourceMappingURL=deploy-engine-B6pEfNd9.js.map