@go-to-k/cdkd 0.263.2 → 0.264.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.
@@ -5821,6 +5821,26 @@ var S3StateBackend = class {
5821
5821
  await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
5822
5822
  }
5823
5823
  /**
5824
+ * Replace the `failedOperations` list on the NEWEST journal segment
5825
+ * (issue #1198) with the ops STILL pending after a `--revert-failed`
5826
+ * replay — an empty list removes the field. Called right after the
5827
+ * failed-op replay, BEFORE the segment's completed ops replay, so a later
5828
+ * completed-op failure that keeps the segment for a re-run does not
5829
+ * re-issue the already-applied failed-op reverts (the journal's
5830
+ * `attemptedProperties` would generate a patch undoing changes that are no
5831
+ * longer present, which can fail on patch-based providers). Per-op — a
5832
+ * partially-successful replay strips only the handled ops. No-op when the
5833
+ * journal / segment / field is absent.
5834
+ */
5835
+ async setRollbackJournalFailedOperations(stackName, region, remaining) {
5836
+ const journal = await this.loadRollbackJournal(stackName, region);
5837
+ const newest = journal?.segments[journal.segments.length - 1];
5838
+ if (!journal || !newest || !newest.failedOperations) return;
5839
+ if (remaining.length === 0) delete newest.failedOperations;
5840
+ else newest.failedOperations = remaining;
5841
+ await this.putRawObject(this.getRollbackJournalKey(stackName, region), JSON.stringify(journal, null, 2));
5842
+ }
5843
+ /**
5824
5844
  * Pop the newest segment off the stack's rollback journal after it has
5825
5845
  * been fully replayed. When the last segment is removed, the journal
5826
5846
  * object is deleted entirely. Returns the number of segments remaining.
@@ -11240,7 +11260,7 @@ var CloudControlProvider = class {
11240
11260
  this.logger.debug(`Deleting resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
11241
11261
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
11242
11262
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
11243
- const { ASGProvider } = await import("./asg-provider-CkNAViXd.js").then((n) => n.n);
11263
+ const { ASGProvider } = await import("./asg-provider-B5N9p1vq.js").then((n) => n.n);
11244
11264
  await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
11245
11265
  return;
11246
11266
  }
@@ -16532,12 +16552,42 @@ function classifyRollbackOp(op, stateResources, orphanLogicalIds) {
16532
16552
  }
16533
16553
  const current = stateResources[op.logicalId];
16534
16554
  if (!current) return "skip-absent";
16535
- if (op.previousState && deepEqual(current.properties, op.previousState.properties)) {
16536
- if (!replacement) return "skip-already-done";
16555
+ if (replacement) {
16556
+ if (current.physicalId === op.previousState.physicalId) return "skip-already-done";
16557
+ if (op.physicalId !== void 0 && current.physicalId !== op.physicalId) {
16558
+ if (deepEqual(current.properties, op.previousState.properties)) return "skip-already-done";
16559
+ return "skip-mismatch";
16560
+ }
16561
+ return op.previousState.updateReplacePolicy === "Retain" ? "reverse-replacement-readopt" : "reverse-replacement";
16537
16562
  }
16563
+ if (op.previousState && deepEqual(current.properties, op.previousState.properties)) return "skip-already-done";
16538
16564
  return "revert";
16539
16565
  }
16540
16566
  /**
16567
+ * Classify what reverting a FAILED in-flight op (issue #1198) will do
16568
+ * against the current state, without touching AWS. Pure — used by both the
16569
+ * command's `--revert-failed` plan preview and {@link replayFailedOperations}.
16570
+ */
16571
+ function classifyFailedOp(op, stateResources) {
16572
+ if (op.changeType === "DELETE") return "skip-failed-noop";
16573
+ const current = stateResources[op.logicalId];
16574
+ if (op.changeType === "CREATE") {
16575
+ if (op.physicalId === void 0) return "skip-failed-unknown";
16576
+ if (!current) return "skip-failed-noop";
16577
+ if (current.physicalId !== op.physicalId) return "skip-failed-noop";
16578
+ return "delete-failed-create";
16579
+ }
16580
+ if (!current || !op.previousState) return "skip-failed-absent";
16581
+ return "revert-failed-update";
16582
+ }
16583
+ /** Build the plan items for a segment's failed ops (issue #1198). */
16584
+ function planFailedOps(failedOps, stateResources) {
16585
+ return failedOps.map((op) => ({
16586
+ op,
16587
+ action: classifyFailedOp(op, stateResources)
16588
+ }));
16589
+ }
16590
+ /**
16541
16591
  * Build the full ordered plan for a list of ops (one segment). Mirrors the
16542
16592
  * replay order: UPDATE/DELETE first (reverse completion order), then CREATE
16543
16593
  * deletions in dependency-aware order.
@@ -16595,7 +16645,7 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
16595
16645
  result.interrupted = true;
16596
16646
  break;
16597
16647
  }
16598
- await replaySingle(otherOps[i], stateResources, stackName, ctx, orphanLogicalIds, result, options.afterOp);
16648
+ await replaySingle(otherOps[i], stateResources, stackName, ctx, orphanLogicalIds, result, options.afterOp, options.isInterrupted);
16599
16649
  }
16600
16650
  if (!result.interrupted && createOps.length > 0) {
16601
16651
  const sorted = sortRollbackCreates(createOps, stateResources);
@@ -16604,7 +16654,7 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
16604
16654
  result.interrupted = true;
16605
16655
  break;
16606
16656
  }
16607
- await replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds, result, options.afterOp);
16657
+ await replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds, result, options.afterOp, options.isInterrupted);
16608
16658
  }
16609
16659
  }
16610
16660
  ctx.logger.info("Rollback completed. Some resources may remain if deletion failed.");
@@ -16614,7 +16664,7 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
16614
16664
  });
16615
16665
  return result;
16616
16666
  }
16617
- async function replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds, result, afterOp) {
16667
+ async function replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds, result, afterOp, isInterrupted) {
16618
16668
  const action = classifyRollbackOp(op, stateResources, orphanLogicalIds);
16619
16669
  const { logger } = ctx;
16620
16670
  try {
@@ -16687,6 +16737,93 @@ async function replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds
16687
16737
  });
16688
16738
  return;
16689
16739
  }
16740
+ case "reverse-replacement-readopt": {
16741
+ const current = stateResources[op.logicalId];
16742
+ const prev = op.previousState;
16743
+ logger.info(` Rollback: Reversing replacement of ${op.logicalId} (${op.resourceType}) — deleting the new resource and re-adopting the retained old one (${prev.physicalId})`);
16744
+ const { provider: newDeleteProvider } = ctx.providerRegistry.getProviderFor({
16745
+ resourceType: op.resourceType,
16746
+ provisionedBy: current.provisionedBy ?? op.provisionedBy
16747
+ });
16748
+ await newDeleteProvider.delete(op.logicalId, current.physicalId, op.resourceType, current.properties, { expectedRegion: ctx.region });
16749
+ stateResources[op.logicalId] = prev;
16750
+ logger.info(` Rollback: ${op.logicalId} restored to the retained old resource`);
16751
+ await afterOp?.(op.logicalId);
16752
+ ctx.recordEvent?.({
16753
+ eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
16754
+ stackName,
16755
+ operation: "UPDATE",
16756
+ logicalId: op.logicalId,
16757
+ resourceType: op.resourceType,
16758
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy }
16759
+ });
16760
+ return;
16761
+ }
16762
+ case "reverse-replacement": {
16763
+ const current = stateResources[op.logicalId];
16764
+ const prev = op.previousState;
16765
+ logger.info(` Rollback: Reversing replacement of ${op.logicalId} (${op.resourceType}) — re-creating the old resource and deleting the new one`);
16766
+ if (STATEFUL_TYPES.has(op.resourceType)) logger.warn(` ⚠ ${op.logicalId} (${op.resourceType}) is a stateful type — the old physical resource's data was destroyed by the replacement and CANNOT be recovered; the re-created resource starts empty.`);
16767
+ const { provider: createProvider } = ctx.providerRegistry.getProviderFor({
16768
+ resourceType: op.resourceType,
16769
+ provisionedBy: prev.provisionedBy
16770
+ });
16771
+ const { provider: newDeleteProvider } = ctx.providerRegistry.getProviderFor({
16772
+ resourceType: op.resourceType,
16773
+ provisionedBy: current.provisionedBy ?? op.provisionedBy
16774
+ });
16775
+ let deletedNewFirst = false;
16776
+ let createResult;
16777
+ try {
16778
+ createResult = await createProvider.create(op.logicalId, op.resourceType, { ...prev.properties });
16779
+ } catch (createError) {
16780
+ const msg = createError instanceof Error ? createError.message : String(createError);
16781
+ if (!(/already exists/i.test(msg) || msg.includes("AlreadyExists"))) throw createError;
16782
+ logger.info(` Rollback: re-create collided with the new resource's name — deleting the new resource (${current.physicalId}) first...`);
16783
+ await newDeleteProvider.delete(op.logicalId, current.physicalId, op.resourceType, current.properties, { expectedRegion: ctx.region });
16784
+ deletedNewFirst = true;
16785
+ delete stateResources[op.logicalId];
16786
+ await afterOp?.(op.logicalId);
16787
+ try {
16788
+ createResult = await withRetry(() => createProvider.create(op.logicalId, op.resourceType, { ...prev.properties }), op.logicalId, {
16789
+ maxRetries: 5,
16790
+ initialDelayMs: 2e3,
16791
+ maxDelayMs: 1e4,
16792
+ logger,
16793
+ ...isInterrupted && {
16794
+ isInterrupted,
16795
+ onInterrupted: () => /* @__PURE__ */ new Error("Rollback interrupted while waiting for the old name to release")
16796
+ },
16797
+ isRetryable: (message) => /already exists/i.test(message) || message.includes("AlreadyExists")
16798
+ });
16799
+ } catch (recreateError) {
16800
+ throw new Error(`Failed to re-create the old ${op.logicalId} after the new resource (${current.physicalId}) was already deleted: ${recreateError instanceof Error ? recreateError.message : String(recreateError)}. The resource is now absent — fix forward with 'cdkd deploy'.`);
16801
+ }
16802
+ }
16803
+ const { observedProperties: _staleObserved, ...prevRecord } = prev;
16804
+ stateResources[op.logicalId] = {
16805
+ ...prevRecord,
16806
+ physicalId: createResult.physicalId,
16807
+ attributes: createResult.attributes ?? {}
16808
+ };
16809
+ await afterOp?.(op.logicalId);
16810
+ if (!deletedNewFirst) try {
16811
+ await newDeleteProvider.delete(op.logicalId, current.physicalId, op.resourceType, current.properties, { expectedRegion: ctx.region });
16812
+ } catch (deleteError) {
16813
+ logger.warn(` Rollback: old ${op.logicalId} re-created, but deleting the new resource (${current.physicalId}) failed: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}. Delete it manually — it is no longer tracked in state.`);
16814
+ result.warnings++;
16815
+ }
16816
+ logger.info(` Rollback: ${op.logicalId} replacement reversed (old resource re-created as ${createResult.physicalId})`);
16817
+ ctx.recordEvent?.({
16818
+ eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
16819
+ stackName,
16820
+ operation: "UPDATE",
16821
+ logicalId: op.logicalId,
16822
+ resourceType: op.resourceType,
16823
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy }
16824
+ });
16825
+ return;
16826
+ }
16690
16827
  case "revert": {
16691
16828
  if (!op.previousState) {
16692
16829
  logger.warn(` Rollback: Cannot restore ${op.logicalId} — no previous state available`);
@@ -16734,6 +16871,115 @@ async function replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds
16734
16871
  });
16735
16872
  }
16736
16873
  }
16874
+ /**
16875
+ * Revert a segment's FAILED in-flight operations (issue #1198). Opt-in via
16876
+ * `cdkd rollback --revert-failed` — the failed resource's remote state is
16877
+ * unknown (the op died partway), so force-applying `previousState` is a
16878
+ * deliberate user decision, never the default. Runs BEFORE the segment's
16879
+ * completed ops (the failed op is the newest work of the failed deploy).
16880
+ *
16881
+ * Best-effort like {@link replayRollback}: per-op failures are caught,
16882
+ * warned, and counted.
16883
+ */
16884
+ async function replayFailedOperations(failedOps, stateResources, stackName, ctx, options = {}) {
16885
+ const result = {
16886
+ failures: 0,
16887
+ warnings: 0,
16888
+ interrupted: false,
16889
+ remainingFailedOps: []
16890
+ };
16891
+ const { logger } = ctx;
16892
+ const emitEnvelope = options.emitEnvelope === true && failedOps.length > 0;
16893
+ if (emitEnvelope) ctx.recordEvent?.({
16894
+ eventType: "ROLLBACK_STARTED",
16895
+ stackName
16896
+ });
16897
+ const pending = /* @__PURE__ */ new Set();
16898
+ for (let i = failedOps.length - 1; i >= 0; i--) {
16899
+ if (options.isInterrupted?.()) {
16900
+ result.interrupted = true;
16901
+ for (let j = i; j >= 0; j--) pending.add(failedOps[j]);
16902
+ break;
16903
+ }
16904
+ const op = failedOps[i];
16905
+ const action = classifyFailedOp(op, stateResources);
16906
+ try {
16907
+ switch (action) {
16908
+ case "skip-failed-noop":
16909
+ logger.info(` Rollback: failed ${op.changeType} of ${op.logicalId} (${op.resourceType}) left nothing to revert, skipping`);
16910
+ break;
16911
+ case "skip-failed-unknown":
16912
+ logger.warn(` Rollback: failed CREATE of ${op.logicalId} (${op.resourceType}) recorded no physical id — if it was partially created in AWS, delete it manually`);
16913
+ result.warnings++;
16914
+ break;
16915
+ case "skip-failed-absent":
16916
+ logger.warn(` Rollback: cannot revert failed UPDATE of ${op.logicalId} — no previous state available, skipping`);
16917
+ result.warnings++;
16918
+ break;
16919
+ case "delete-failed-create": {
16920
+ logger.info(` Rollback: deleting partially-created ${op.logicalId} (${op.resourceType}) (--revert-failed)`);
16921
+ const { provider } = ctx.providerRegistry.getProviderFor({
16922
+ resourceType: op.resourceType,
16923
+ provisionedBy: op.provisionedBy
16924
+ });
16925
+ await provider.delete(op.logicalId, op.physicalId, op.resourceType, void 0, { expectedRegion: ctx.region });
16926
+ delete stateResources[op.logicalId];
16927
+ await options.afterOp?.(op.logicalId);
16928
+ ctx.recordEvent?.({
16929
+ eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
16930
+ stackName,
16931
+ operation: "CREATE",
16932
+ logicalId: op.logicalId,
16933
+ resourceType: op.resourceType,
16934
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy }
16935
+ });
16936
+ break;
16937
+ }
16938
+ case "revert-failed-update": {
16939
+ const current = stateResources[op.logicalId];
16940
+ const prev = op.previousState;
16941
+ logger.info(` Rollback: force-reverting failed UPDATE of ${op.logicalId} (${op.resourceType}) to its pre-deploy properties (--revert-failed; remote state is unknown)`);
16942
+ const { provider } = ctx.providerRegistry.getProviderFor({
16943
+ resourceType: op.resourceType,
16944
+ provisionedBy: op.provisionedBy ?? current.provisionedBy
16945
+ });
16946
+ await provider.update(op.logicalId, current.physicalId, op.resourceType, prev.properties, op.attemptedProperties ?? current.properties);
16947
+ stateResources[op.logicalId] = prev;
16948
+ logger.info(` Rollback: ${op.logicalId} reverted successfully`);
16949
+ await options.afterOp?.(op.logicalId);
16950
+ ctx.recordEvent?.({
16951
+ eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
16952
+ stackName,
16953
+ operation: "UPDATE",
16954
+ logicalId: op.logicalId,
16955
+ resourceType: op.resourceType,
16956
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy }
16957
+ });
16958
+ break;
16959
+ }
16960
+ }
16961
+ } catch (revertError) {
16962
+ logger.warn(` Rollback failed for failed-op ${op.logicalId} (${op.changeType}): ${revertError instanceof Error ? revertError.message : String(revertError)}`);
16963
+ result.failures++;
16964
+ pending.add(op);
16965
+ ctx.recordEvent?.({
16966
+ eventType: "ROLLBACK_RESOURCE_FAILED",
16967
+ stackName,
16968
+ operation: op.changeType,
16969
+ logicalId: op.logicalId,
16970
+ resourceType: op.resourceType,
16971
+ ...op.provisionedBy && { provisionedBy: op.provisionedBy },
16972
+ error: extractDeploymentEventError(revertError)
16973
+ });
16974
+ }
16975
+ }
16976
+ if (emitEnvelope) ctx.recordEvent?.({
16977
+ eventType: "ROLLBACK_FINISHED",
16978
+ stackName
16979
+ });
16980
+ result.remainingFailedOps = failedOps.filter((op) => pending.has(op));
16981
+ return result;
16982
+ }
16737
16983
  function stateResourcesPolicyLabel(op, stateResources) {
16738
16984
  return stateResources[op.logicalId]?.deletionPolicy ?? "Retain";
16739
16985
  }
@@ -16826,7 +17072,7 @@ const FLUSH_INTERVAL_MS = 2e3;
16826
17072
  const FLUSH_EVENT_THRESHOLD = 50;
16827
17073
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
16828
17074
  function getCdkdVersion() {
16829
- return "0.263.2";
17075
+ return "0.264.0";
16830
17076
  }
16831
17077
  /**
16832
17078
  * Generate a time-sortable unique run id, e.g.
@@ -17383,6 +17629,14 @@ var DeployEngine = class {
17383
17629
  */
17384
17630
  recordedOutputReads = [];
17385
17631
  /**
17632
+ * Per-logical-id snapshot of the intrinsic-RESOLVED desired properties
17633
+ * each CREATE / UPDATE attempted (issue #1198). Written just before the
17634
+ * provider call; read only when the op FAILS, to journal the failed op's
17635
+ * `attemptedProperties` so `cdkd rollback --revert-failed` can generate a
17636
+ * patch that undoes a half-applied update.
17637
+ */
17638
+ attemptedResolvedProps = /* @__PURE__ */ new Map();
17639
+ /**
17386
17640
  * Target region for this stack. Required — load-bearing for the
17387
17641
  * region-prefixed S3 state key and recorded in state.json for
17388
17642
  * cross-region destroy.
@@ -17808,6 +18062,7 @@ var DeployEngine = class {
17808
18062
  skipped: 0
17809
18063
  };
17810
18064
  const completedOperations = [];
18065
+ const failedOperations = [];
17811
18066
  let pendingMigration = migrationPending;
17812
18067
  let saveChain = Promise.resolve();
17813
18068
  const saveStateAfterResource = (logicalId) => {
@@ -17869,6 +18124,15 @@ var DeployEngine = class {
17869
18124
  } catch (provisionError) {
17870
18125
  this.interrupted = true;
17871
18126
  this.interruptCause ??= "sibling-failure";
18127
+ failedOperations.push({
18128
+ logicalId,
18129
+ changeType: change.changeType,
18130
+ resourceType: change.resourceType,
18131
+ provisionedBy: newResources[logicalId]?.provisionedBy ?? previousState?.provisionedBy,
18132
+ ...previousState && { previousState },
18133
+ physicalId: newResources[logicalId]?.physicalId ?? previousState?.physicalId,
18134
+ attemptedProperties: this.attemptedResolvedProps.get(logicalId)
18135
+ });
17872
18136
  throw provisionError;
17873
18137
  }
17874
18138
  completedOperations.push({
@@ -17907,6 +18171,14 @@ var DeployEngine = class {
17907
18171
  } catch (provisionError) {
17908
18172
  this.interrupted = true;
17909
18173
  this.interruptCause ??= "sibling-failure";
18174
+ failedOperations.push({
18175
+ logicalId,
18176
+ changeType: "DELETE",
18177
+ resourceType: change.resourceType,
18178
+ provisionedBy: previousState?.provisionedBy,
18179
+ ...previousState && { previousState },
18180
+ physicalId: previousState?.physicalId
18181
+ });
17910
18182
  throw provisionError;
17911
18183
  }
17912
18184
  completedOperations.push({
@@ -17949,16 +18221,16 @@ var DeployEngine = class {
17949
18221
  }
17950
18222
  let autoRollbackClean = false;
17951
18223
  if (error instanceof InterruptedError) {
17952
- await this.writeRollbackJournalSegment(stackName, completedOperations, "interrupted", initialDeploy);
18224
+ await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "interrupted", initialDeploy);
17953
18225
  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.`);
17954
18226
  throw error;
17955
18227
  }
17956
18228
  if (this.options.noRollback) {
17957
- await this.writeRollbackJournalSegment(stackName, completedOperations, "no-rollback-failure", initialDeploy);
18229
+ await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "no-rollback-failure", initialDeploy);
17958
18230
  this.logger.warn("Deployment failed. --no-rollback is set, skipping rollback.");
17959
18231
  this.logger.warn("Partial state has been saved. Run 'cdkd deploy' to resume, 'cdkd rollback' to revert, or destroy to clean up.");
17960
18232
  } else {
17961
- await this.writeRollbackJournalSegment(stackName, completedOperations, "auto-rollback-started", initialDeploy);
18233
+ await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "auto-rollback-started", initialDeploy);
17962
18234
  autoRollbackClean = (await this.performRollback(completedOperations, newResources, stackName)).failures === 0;
17963
18235
  }
17964
18236
  try {
@@ -18003,7 +18275,7 @@ var DeployEngine = class {
18003
18275
  outputs = await this.resolveOutputs(template, newResources, stackName, parameterValues, conditions);
18004
18276
  } catch (outputError) {
18005
18277
  await this.persistStateAfterOutputFailure(stackName, currentState, newResources, currentEtag, pendingMigration);
18006
- await this.writeRollbackJournalSegment(stackName, completedOperations, "no-rollback-failure", currentEtag === void 0);
18278
+ await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "no-rollback-failure", currentEtag === void 0);
18007
18279
  throw outputError;
18008
18280
  }
18009
18281
  return {
@@ -18113,8 +18385,8 @@ var DeployEngine = class {
18113
18385
  * `cdkd rollback`. Best-effort like the partial-state save, but warns
18114
18386
  * LOUDLY on failure — the user just lost the ability to `cdkd rollback`.
18115
18387
  */
18116
- async writeRollbackJournalSegment(stackName, completedOperations, reason, initialDeploy) {
18117
- if (completedOperations.length === 0) return;
18388
+ async writeRollbackJournalSegment(stackName, completedOperations, failedOperations, reason, initialDeploy) {
18389
+ if (completedOperations.length === 0 && failedOperations.length === 0) return;
18118
18390
  try {
18119
18391
  const segment = {
18120
18392
  ...this.options.eventRecorder?.runId !== void 0 && { runId: this.options.eventRecorder.runId },
@@ -18123,7 +18395,8 @@ var DeployEngine = class {
18123
18395
  initialDeploy,
18124
18396
  ...this.options.roleArn && { roleArn: this.options.roleArn },
18125
18397
  cdkdVersion: getCdkdVersion(),
18126
- operations: completedOperations
18398
+ operations: completedOperations,
18399
+ ...failedOperations.length > 0 && { failedOperations }
18127
18400
  };
18128
18401
  await this.stateBackend.appendRollbackJournalSegment(stackName, this.stackRegion, segment);
18129
18402
  this.logger.debug(`Rollback journal segment written (${reason})`);
@@ -18255,6 +18528,7 @@ var DeployEngine = class {
18255
18528
  }, stackName);
18256
18529
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
18257
18530
  this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
18531
+ this.attemptedResolvedProps.set(logicalId, resolvedProps);
18258
18532
  const createDecision = this.providerRegistry.getProviderFor({
18259
18533
  resourceType,
18260
18534
  properties: resolvedProps
@@ -18295,6 +18569,7 @@ var DeployEngine = class {
18295
18569
  }, stackName);
18296
18570
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
18297
18571
  this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
18572
+ this.attemptedResolvedProps.set(logicalId, resolvedProps);
18298
18573
  if (JSON.stringify(resolvedProps) === JSON.stringify(currentProps)) {
18299
18574
  if (change.attributeChanges && change.attributeChanges.length > 0) {
18300
18575
  const attrSummary = change.attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
@@ -18733,5 +19008,5 @@ var DeployEngine = class {
18733
19008
  };
18734
19009
 
18735
19010
  //#endregion
18736
- export { rewriteTemplateAssetReferences as $, StackHasActiveImportsError as $t, disableInstanceApiTermination as A, uploadCfnTemplate as At, DiffCalculator as B, CdkdError as Bt, yellow as C, resolveStateBucketWithDefaultAndSource as Ct, findActionableSilentDrops as D, CFN_TEMPLATE_URL_LIMIT as Dt, ProviderRegistry as E, CFN_TEMPLATE_BODY_LIMIT as Et, WAFv2WebACLProvider as F, AwsClients as Ft, rebuildClientForBucketRegion as G, LocalStartServiceError as Gt, TemplateParser as H, DependencyError as Ht, normalizeAwsTagsToCfn as I, getAwsClients as It, stringifyValue as J, NestedStackChildDirectDestroyError as Jt, shouldRetainResource as K, LockError as Kt, resolveExplicitPhysicalId as L, resetAwsClients as Lt, IntrinsicFunctionResolver as M, AssemblyReader as Mt, cfnRefValueFromPhysicalId as N, clearBucketRegionCache as Nt, CloudControlProvider as O, MIGRATE_TMP_PREFIX as Ot, refStateLookupFromResource as P, resolveBucketRegion as Pt, loadPublishableAssetManifest as Q, ResourceUpdateNotSupportedError as Qt, assertRegionMatch as R, setAwsClients as Rt, red as S, resolveStateBucketWithDefault as St, collectInlinePolicyNamesManagedBySiblings as T, warnDeprecatedNoPrefixCliFlag as Tt, LockManager as U, LocalInvokeBuildError as Ut, DagBuilder as V, ConfigError as Vt, S3StateBackend as W, LocalMigrateError as Wt, buildAssetRedirectMap as X, ProvisioningError as Xt, WorkGraph as Y, PartialFailureError as Yt, createAssetRedirectResolver as Z, ResourceTimeoutError as Zt, formatResourceLine as _, getLegacyStateBucketName as _t, DeploymentEventsStore as a, normalizeAwsError as an, validateAssetBucketName as at, gray as b, resolveCaptureObservedState as bt, withResourceDeadline as c, formatDockerLoginError as ct, IMPLICIT_DELETE_DEPENDENCIES as d, runDockerStreaming as dt, StackTerminationProtectionError as en, AssetModeResolver as et, computeImplicitDeleteEdges as f, AssetManifestLoader as ft, renderStatefulReason as g, getDefaultStateBucketName as gt, isStatefulRecreateTargetSync as h, synthesisStatusMessage as ht, DeploymentEventsReader as i, isCdkdError as in, parseBootstrapMarker as it, isTerminationProtectionPropagationError as j, expectedOwnerParam as jt, slowCcOperationTimeoutMs as k, findLargeInlineResources as kt, withRetry as l, getDockerCmd as lt, MULTI_REGION_RECREATE_BLOCKED_TYPES as m, Synthesizer as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, SynthesisError as nn, ensureAssetStorage as nt, planRollback as o, withErrorHandling as on, validateContainerRepoName as ot, extractDeploymentEventError as p, getDockerImageBySourceHash as pt, AssetPublisher as q, MissingCdkCliError as qt, DeployEngine as r, formatError as rn, getBootstrapMarkerKey as rt, replayRollback as s, __exportAll as sn, buildDockerImage as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, StateError as tn, BOOTSTRAP_MARKER_PREFIX as tt, isRetryableTransientError as u, runDockerForeground as ut, bold as v, resolveApp as vt, IAMRoleProvider as w, resolveUseCdkBootstrapAssets as wt, green as x, resolveSkipPrefix as xt, cyan as y, resolveAutoAssetStorage as yt, applyRoleArnIfSet as z, AssetError as zt };
18737
- //# sourceMappingURL=deploy-engine-j-e2Q0XH.js.map
19011
+ export { createAssetRedirectResolver as $, ResourceTimeoutError as $t, CloudControlProvider as A, MIGRATE_TMP_PREFIX as At, assertRegionMatch as B, setAwsClients as Bt, green as C, resolveSkipPrefix as Ct, collectInlinePolicyNamesManagedBySiblings as D, warnDeprecatedNoPrefixCliFlag as Dt, IAMRoleProvider as E, resolveUseCdkBootstrapAssets as Et, cfnRefValueFromPhysicalId as F, clearBucketRegionCache as Ft, LockManager as G, LocalInvokeBuildError as Gt, DiffCalculator as H, CdkdError as Ht, refStateLookupFromResource as I, resolveBucketRegion as It, shouldRetainResource as J, LockError as Jt, S3StateBackend as K, LocalMigrateError as Kt, WAFv2WebACLProvider as L, AwsClients as Lt, disableInstanceApiTermination as M, uploadCfnTemplate as Mt, isTerminationProtectionPropagationError as N, expectedOwnerParam as Nt, ProviderRegistry as O, CFN_TEMPLATE_BODY_LIMIT as Ot, IntrinsicFunctionResolver as P, AssemblyReader as Pt, buildAssetRedirectMap as Q, ProvisioningError as Qt, normalizeAwsTagsToCfn as R, getAwsClients as Rt, gray as S, resolveCaptureObservedState as St, yellow as T, resolveStateBucketWithDefaultAndSource as Tt, DagBuilder as U, ConfigError as Ut, applyRoleArnIfSet as V, AssetError as Vt, TemplateParser as W, DependencyError as Wt, stringifyValue as X, NestedStackChildDirectDestroyError as Xt, AssetPublisher as Y, MissingCdkCliError as Yt, WorkGraph as Z, PartialFailureError as Zt, isStatefulRecreateTargetSync as _, synthesisStatusMessage as _t, DeploymentEventsStore as a, formatError as an, getBootstrapMarkerKey as at, bold as b, resolveApp as bt, replayFailedOperations as c, withErrorHandling as cn, validateContainerRepoName as ct, withRetry as d, getDockerCmd as dt, ResourceUpdateNotSupportedError as en, loadPublishableAssetManifest as et, isRetryableTransientError as f, runDockerForeground as ft, MULTI_REGION_RECREATE_BLOCKED_TYPES as g, Synthesizer as gt, extractDeploymentEventError as h, getDockerImageBySourceHash as ht, DeploymentEventsReader as i, SynthesisError as in, ensureAssetStorage as it, slowCcOperationTimeoutMs as j, findLargeInlineResources as jt, findActionableSilentDrops as k, CFN_TEMPLATE_URL_LIMIT as kt, replayRollback as l, __exportAll as ln, buildDockerImage as lt, computeImplicitDeleteEdges as m, AssetManifestLoader as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, StackTerminationProtectionError as nn, AssetModeResolver as nt, planFailedOps as o, isCdkdError as on, parseBootstrapMarker as ot, IMPLICIT_DELETE_DEPENDENCIES as p, runDockerStreaming as pt, rebuildClientForBucketRegion as q, LocalStartServiceError as qt, DeployEngine as r, StateError as rn, BOOTSTRAP_MARKER_PREFIX as rt, planRollback as s, normalizeAwsError as sn, validateAssetBucketName as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, StackHasActiveImportsError as tn, rewriteTemplateAssetReferences as tt, withResourceDeadline as u, formatDockerLoginError as ut, renderStatefulReason as v, getDefaultStateBucketName as vt, red as w, resolveStateBucketWithDefault as wt, cyan as x, resolveAutoAssetStorage as xt, formatResourceLine as y, getLegacyStateBucketName as yt, resolveExplicitPhysicalId as z, resetAwsClients as zt };
19012
+ //# sourceMappingURL=deploy-engine-hlS6y_-0.js.map