@go-to-k/cdkd 0.46.1 → 0.47.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.
Binary file
package/dist/index.js CHANGED
@@ -2922,8 +2922,8 @@ import {
2922
2922
  } from "@aws-sdk/client-s3";
2923
2923
 
2924
2924
  // src/types/state.ts
2925
- var STATE_SCHEMA_VERSION_LEGACY = 1;
2926
- var STATE_SCHEMA_VERSION_CURRENT = 2;
2925
+ var STATE_SCHEMA_VERSION_CURRENT = 3;
2926
+ var STATE_SCHEMA_VERSIONS_READABLE = [1, 2, 3];
2927
2927
 
2928
2928
  // src/state/s3-state-backend.ts
2929
2929
  var LEGACY_KEY_DEPTH = 2;
@@ -3406,9 +3406,9 @@ var S3StateBackend = class {
3406
3406
  );
3407
3407
  }
3408
3408
  const v = parsed.version;
3409
- if (v !== STATE_SCHEMA_VERSION_LEGACY && v !== STATE_SCHEMA_VERSION_CURRENT && v !== void 0) {
3409
+ if (v !== void 0 && !STATE_SCHEMA_VERSIONS_READABLE.includes(v)) {
3410
3410
  throw new StateError(
3411
- `Unsupported state schema version ${String(v)} for stack '${stackName}'. This cdkd binary supports versions ${String(STATE_SCHEMA_VERSION_LEGACY)} and ${String(STATE_SCHEMA_VERSION_CURRENT)}. Upgrade cdkd to a version that supports schema ${String(v)}.`
3411
+ `Unsupported state schema version ${String(v)} for stack '${stackName}'. This cdkd binary supports versions ${STATE_SCHEMA_VERSIONS_READABLE.join(", ")}. Upgrade cdkd to a version that supports schema ${String(v)}.`
3412
3412
  );
3413
3413
  }
3414
3414
  return parsed;
@@ -8727,10 +8727,23 @@ var DeployEngine = class {
8727
8727
  this.options.noRollback = options.noRollback ?? false;
8728
8728
  this.options.resourceWarnAfterMs = options.resourceWarnAfterMs ?? DEFAULT_RESOURCE_WARN_AFTER_MS;
8729
8729
  this.options.resourceTimeoutMs = options.resourceTimeoutMs ?? DEFAULT_RESOURCE_TIMEOUT_MS;
8730
+ this.options.captureObservedState = options.captureObservedState ?? true;
8730
8731
  }
8731
8732
  logger = getLogger().child("DeployEngine");
8732
8733
  resolver;
8733
8734
  interrupted = false;
8735
+ /**
8736
+ * In-flight `provider.readCurrentState` promises kicked off after a
8737
+ * successful CREATE / UPDATE. The deploy critical path does NOT
8738
+ * `await` these; instead they're drained at the end of `doDeploy`
8739
+ * (success path only) and the resolved values are merged into
8740
+ * `ResourceState.observedProperties` before the final state save.
8741
+ *
8742
+ * Each Promise resolves to the AWS-current snapshot, or `undefined`
8743
+ * if the provider does not implement `readCurrentState` or the call
8744
+ * threw — never rejects, so an unhandled-rejection cannot escape.
8745
+ */
8746
+ observedCaptureTasks = /* @__PURE__ */ new Map();
8734
8747
  /**
8735
8748
  * Target region for this stack. Required — load-bearing for the
8736
8749
  * region-prefixed S3 state key and recorded in state.json for
@@ -8743,6 +8756,61 @@ var DeployEngine = class {
8743
8756
  async deploy(stackName, template) {
8744
8757
  return withStackName(stackName, () => this.doDeploy(stackName, template));
8745
8758
  }
8759
+ /**
8760
+ * Kick off `provider.readCurrentState` for a freshly-created/updated
8761
+ * resource without blocking the deploy critical path. The promise
8762
+ * lands in `observedCaptureTasks` keyed by `logicalId`; the deploy's
8763
+ * success-path drain (`drainObservedCaptures`) awaits the full set
8764
+ * and merges the resolved values into `ResourceState.observedProperties`
8765
+ * before the final state save.
8766
+ *
8767
+ * Errors are swallowed at the Promise level — readCurrentState
8768
+ * failing must not fail the deploy. The map entry resolves to
8769
+ * `undefined` for failures and for providers without
8770
+ * `readCurrentState`; both translate to "no observedProperties" at
8771
+ * the merge step, which is fine: drift falls back to comparing
8772
+ * against `properties`.
8773
+ */
8774
+ kickOffObservedCapture(provider, logicalId, physicalId, resourceType, resolvedProps) {
8775
+ if (this.options.captureObservedState !== true)
8776
+ return;
8777
+ if (!provider.readCurrentState)
8778
+ return;
8779
+ const promise = provider.readCurrentState(physicalId, logicalId, resourceType, resolvedProps).catch((err) => {
8780
+ this.logger.debug(
8781
+ `observedProperties capture for ${logicalId} (${resourceType}) failed: ${err instanceof Error ? err.message : String(err)} \u2014 drift will fall back to template properties for this resource until the next successful deploy.`
8782
+ );
8783
+ return void 0;
8784
+ });
8785
+ this.observedCaptureTasks.set(logicalId, promise);
8786
+ }
8787
+ /**
8788
+ * Wait for every in-flight `readCurrentState` promise from the
8789
+ * deploy's success path, then merge each resolved snapshot into the
8790
+ * matching `ResourceState.observedProperties`. After this runs the
8791
+ * map is drained so a subsequent deploy starts fresh.
8792
+ *
8793
+ * Called from `doDeploy` immediately before the final `saveState`.
8794
+ * The rollback / failure paths intentionally do NOT call this — a
8795
+ * failed deploy's partial state is already inconsistent, and waiting
8796
+ * on potentially many in-flight reads would slow down the rollback
8797
+ * itself.
8798
+ */
8799
+ async drainObservedCaptures(stateResources) {
8800
+ if (this.observedCaptureTasks.size === 0)
8801
+ return;
8802
+ const entries = Array.from(this.observedCaptureTasks.entries());
8803
+ this.observedCaptureTasks.clear();
8804
+ const resolved = await Promise.all(entries.map(([, p]) => p));
8805
+ for (let i = 0; i < entries.length; i++) {
8806
+ const logicalId = entries[i][0];
8807
+ const observed = resolved[i];
8808
+ const target = stateResources[logicalId];
8809
+ if (target && observed !== void 0) {
8810
+ target.observedProperties = observed;
8811
+ }
8812
+ }
8813
+ }
8746
8814
  async doDeploy(stackName, template) {
8747
8815
  const startTime = Date.now();
8748
8816
  this.logger.debug(`Starting deployment for stack: ${stackName}`);
@@ -8859,6 +8927,7 @@ var DeployEngine = class {
8859
8927
  progress,
8860
8928
  migrationPending
8861
8929
  );
8930
+ await this.drainObservedCaptures(newState.resources);
8862
8931
  const newEtag = await this.stateBackend.saveState(stackName, this.stackRegion, newState);
8863
8932
  this.logger.debug(`State saved (ETag: ${newEtag})`);
8864
8933
  const durationMs = Date.now() - startTime;
@@ -8874,6 +8943,7 @@ var DeployEngine = class {
8874
8943
  } finally {
8875
8944
  renderer.stop();
8876
8945
  process.removeListener("SIGINT", sigintHandler);
8946
+ this.observedCaptureTasks.clear();
8877
8947
  try {
8878
8948
  await this.lockManager.releaseLock(stackName, this.stackRegion);
8879
8949
  this.logger.debug("Lock released");
@@ -9427,6 +9497,13 @@ var DeployEngine = class {
9427
9497
  ...result.attributes && { attributes: result.attributes },
9428
9498
  ...dependencies && dependencies.length > 0 && { dependencies }
9429
9499
  };
9500
+ this.kickOffObservedCapture(
9501
+ provider,
9502
+ logicalId,
9503
+ result.physicalId,
9504
+ resourceType,
9505
+ resolvedProps
9506
+ );
9430
9507
  if (counts)
9431
9508
  counts.created++;
9432
9509
  if (progress)
@@ -9505,6 +9582,13 @@ var DeployEngine = class {
9505
9582
  ...createResult.attributes && { attributes: createResult.attributes },
9506
9583
  ...dependencies && dependencies.length > 0 && { dependencies }
9507
9584
  };
9585
+ this.kickOffObservedCapture(
9586
+ provider,
9587
+ logicalId,
9588
+ createResult.physicalId,
9589
+ resourceType,
9590
+ resolvedProps
9591
+ );
9508
9592
  if (counts)
9509
9593
  counts.updated++;
9510
9594
  if (progress)
@@ -9583,6 +9667,13 @@ var DeployEngine = class {
9583
9667
  ...result.attributes && { attributes: result.attributes },
9584
9668
  ...dependencies && dependencies.length > 0 && { dependencies }
9585
9669
  };
9670
+ this.kickOffObservedCapture(
9671
+ provider,
9672
+ logicalId,
9673
+ result.physicalId,
9674
+ resourceType,
9675
+ resolvedProps
9676
+ );
9586
9677
  if (counts)
9587
9678
  counts.updated++;
9588
9679
  if (progress)