@go-to-k/cdkd 0.99.3 → 0.100.1

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.
@@ -3311,7 +3311,8 @@ const STATE_SCHEMA_VERSIONS_READABLE = [
3311
3311
  1,
3312
3312
  2,
3313
3313
  3,
3314
- 4
3314
+ 4,
3315
+ 5
3315
3316
  ];
3316
3317
 
3317
3318
  //#endregion
@@ -3528,7 +3529,7 @@ var S3StateBackend = class {
3528
3529
  const { expectedEtag, migrateLegacy } = options;
3529
3530
  const body = {
3530
3531
  ...state,
3531
- version: 4,
3532
+ version: 5,
3532
3533
  stackName,
3533
3534
  region
3534
3535
  };
@@ -4911,16 +4912,18 @@ var DiffCalculator = class DiffCalculator {
4911
4912
  const rawDesiredProps = desiredResource.Properties || {};
4912
4913
  const desiredPropsForCompare = resolveFn ? await this.resolveBestEffort(rawDesiredProps, resolveFn) : rawDesiredProps;
4913
4914
  const propertyChanges = this.compareProperties(desiredResource.Type, currentResource.properties, desiredPropsForCompare);
4914
- if (propertyChanges.length > 0) {
4915
+ const attributeChanges = this.compareAttributes(currentResource, desiredResource);
4916
+ if (propertyChanges.length > 0 || attributeChanges.length > 0) {
4915
4917
  changes.set(logicalId, {
4916
4918
  logicalId,
4917
4919
  changeType: "UPDATE",
4918
4920
  resourceType: desiredResource.Type,
4919
4921
  currentProperties: currentResource.properties,
4920
4922
  desiredProperties: rawDesiredProps,
4921
- propertyChanges
4923
+ propertyChanges,
4924
+ ...attributeChanges.length > 0 && { attributeChanges }
4922
4925
  });
4923
- this.logger.debug(`UPDATE: ${logicalId} (${propertyChanges.length} property changes)`);
4926
+ this.logger.debug(`UPDATE: ${logicalId} (${propertyChanges.length} property changes, ${attributeChanges.length} attribute changes)`);
4924
4927
  } else {
4925
4928
  changes.set(logicalId, {
4926
4929
  logicalId,
@@ -4964,6 +4967,29 @@ var DiffCalculator = class DiffCalculator {
4964
4967
  return resolved;
4965
4968
  }
4966
4969
  /**
4970
+ * Compare CloudFormation template-level attributes (`DeletionPolicy`,
4971
+ * `UpdateReplacePolicy`) between cdkd state and the synth template.
4972
+ *
4973
+ * Schema v5+ records these in `ResourceState`; state written by an older
4974
+ * cdkd binary has the fields undefined. Treating `undefined === undefined`
4975
+ * as "no change" means the first post-upgrade deploy of an unchanged
4976
+ * template doesn't spuriously fire an attribute diff.
4977
+ */
4978
+ compareAttributes(currentResource, desiredResource) {
4979
+ const changes = [];
4980
+ if (currentResource.deletionPolicy !== desiredResource.DeletionPolicy) changes.push({
4981
+ attribute: "DeletionPolicy",
4982
+ oldValue: currentResource.deletionPolicy,
4983
+ newValue: desiredResource.DeletionPolicy
4984
+ });
4985
+ if (currentResource.updateReplacePolicy !== desiredResource.UpdateReplacePolicy) changes.push({
4986
+ attribute: "UpdateReplacePolicy",
4987
+ oldValue: currentResource.updateReplacePolicy,
4988
+ newValue: desiredResource.UpdateReplacePolicy
4989
+ });
4990
+ return changes;
4991
+ }
4992
+ /**
4967
4993
  * Compare properties and return list of changes
4968
4994
  *
4969
4995
  * Uses ReplacementRulesRegistry to determine which property changes require replacement.
@@ -5339,7 +5365,7 @@ var IntrinsicFunctionResolver = class {
5339
5365
  async constructAttribute(resource, attributeName, _context) {
5340
5366
  const { resourceType, physicalId } = resource;
5341
5367
  const { region, accountId, partition } = await getAccountInfo(this.resolverRegion);
5342
- if (resourceType === "AWS::DynamoDB::Table") switch (attributeName) {
5368
+ if (resourceType === "AWS::DynamoDB::Table" || resourceType === "AWS::DynamoDB::GlobalTable") switch (attributeName) {
5343
5369
  case "Arn": return `arn:${partition}:dynamodb:${region}:${accountId}:table/${physicalId}`;
5344
5370
  case "StreamArn": return;
5345
5371
  default: return physicalId;
@@ -8548,7 +8574,7 @@ var DeployEngine = class {
8548
8574
  try {
8549
8575
  const currentStateData = await this.stateBackend.getState(stackName, this.stackRegion);
8550
8576
  const currentState = currentStateData?.state ?? {
8551
- version: 4,
8577
+ version: 5,
8552
8578
  region: this.stackRegion,
8553
8579
  stackName,
8554
8580
  resources: {},
@@ -8589,7 +8615,7 @@ var DeployEngine = class {
8589
8615
  await this.drainObservedCaptures(currentState.resources);
8590
8616
  try {
8591
8617
  const refreshedState = {
8592
- version: 4,
8618
+ version: 5,
8593
8619
  region: this.stackRegion,
8594
8620
  stackName: currentState.stackName,
8595
8621
  resources: currentState.resources,
@@ -8687,7 +8713,7 @@ var DeployEngine = class {
8687
8713
  saveChain = saveChain.then(async () => {
8688
8714
  try {
8689
8715
  const partialState = {
8690
- version: 4,
8716
+ version: 5,
8691
8717
  region: this.stackRegion,
8692
8718
  stackName: currentState.stackName,
8693
8719
  resources: newResources,
@@ -8793,7 +8819,7 @@ var DeployEngine = class {
8793
8819
  } catch (error) {
8794
8820
  try {
8795
8821
  const preRollbackState = {
8796
- version: 4,
8822
+ version: 5,
8797
8823
  region: this.stackRegion,
8798
8824
  stackName: currentState.stackName,
8799
8825
  resources: newResources,
@@ -8822,7 +8848,7 @@ var DeployEngine = class {
8822
8848
  } else await this.performRollback(completedOperations, newResources, stackName);
8823
8849
  try {
8824
8850
  const postRollbackState = {
8825
- version: 4,
8851
+ version: 5,
8826
8852
  region: this.stackRegion,
8827
8853
  stackName: currentState.stackName,
8828
8854
  resources: newResources,
@@ -8837,7 +8863,7 @@ var DeployEngine = class {
8837
8863
  try {
8838
8864
  const freshEtag = (await this.stateBackend.getState(stackName, this.stackRegion))?.etag;
8839
8865
  const postRollbackState = {
8840
- version: 4,
8866
+ version: 5,
8841
8867
  region: this.stackRegion,
8842
8868
  stackName: currentState.stackName,
8843
8869
  resources: newResources,
@@ -8856,7 +8882,7 @@ var DeployEngine = class {
8856
8882
  const outputs = await this.resolveOutputs(template, newResources, stackName, parameterValues, conditions);
8857
8883
  return {
8858
8884
  state: {
8859
- version: 4,
8885
+ version: 5,
8860
8886
  region: this.stackRegion,
8861
8887
  stackName: currentState.stackName,
8862
8888
  resources: newResources,
@@ -9054,12 +9080,14 @@ var DeployEngine = class {
9054
9080
  const { provider: createProvider, properties: createProps } = this.selectProviderWithSafetyNet(provider, resourceType, resolvedProps, logicalId);
9055
9081
  const result = await this.withRetry(() => createProvider.create(logicalId, resourceType, createProps), logicalId, void 0, void 0, provider);
9056
9082
  const dependencies = this.extractAllDependencies(template, logicalId);
9083
+ const templateAttrs = this.extractTemplateAttributes(template, logicalId);
9057
9084
  stateResources[logicalId] = {
9058
9085
  physicalId: result.physicalId,
9059
9086
  resourceType,
9060
9087
  properties: resolvedProps,
9061
9088
  ...result.attributes && { attributes: result.attributes },
9062
- ...dependencies && dependencies.length > 0 && { dependencies }
9089
+ ...dependencies && dependencies.length > 0 && { dependencies },
9090
+ ...templateAttrs
9063
9091
  };
9064
9092
  this.kickOffObservedCapture(provider, logicalId, result.physicalId, resourceType, resolvedProps);
9065
9093
  if (counts) counts.created++;
@@ -9082,6 +9110,20 @@ var DeployEngine = class {
9082
9110
  }, stackName);
9083
9111
  const resolvedProps = await this.resolver.resolve(desiredProps, context);
9084
9112
  if (JSON.stringify(resolvedProps) === JSON.stringify(currentProps)) {
9113
+ if (change.attributeChanges && change.attributeChanges.length > 0) {
9114
+ const attrSummary = change.attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
9115
+ this.logger.info(` ↻ ${logicalId} (${resourceType}) attribute update: ${attrSummary}`);
9116
+ stateResources[logicalId] = {
9117
+ ...currentResource,
9118
+ ...this.extractTemplateAttributes(template, logicalId)
9119
+ };
9120
+ if (counts) counts.updated++;
9121
+ if (progress) progress.current++;
9122
+ const attrPrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
9123
+ renderer.removeTask(logicalId);
9124
+ this.logger.info(`${attrPrefix}✅ ${logicalId} (${resourceType}) updated (metadata)`);
9125
+ break;
9126
+ }
9085
9127
  this.logger.debug(`Skipping ${logicalId}: no actual changes after intrinsic function resolution`);
9086
9128
  if (counts) counts.skipped++;
9087
9129
  break;
@@ -9109,7 +9151,8 @@ var DeployEngine = class {
9109
9151
  resourceType,
9110
9152
  properties: resolvedProps,
9111
9153
  ...createResult.attributes && { attributes: createResult.attributes },
9112
- ...dependencies && dependencies.length > 0 && { dependencies }
9154
+ ...dependencies && dependencies.length > 0 && { dependencies },
9155
+ ...this.extractTemplateAttributes(template, logicalId)
9113
9156
  };
9114
9157
  this.kickOffObservedCapture(provider, logicalId, createResult.physicalId, resourceType, resolvedProps);
9115
9158
  if (counts) counts.updated++;
@@ -9149,7 +9192,8 @@ var DeployEngine = class {
9149
9192
  resourceType,
9150
9193
  properties: resolvedProps,
9151
9194
  ...result.attributes && { attributes: result.attributes },
9152
- ...dependencies && dependencies.length > 0 && { dependencies }
9195
+ ...dependencies && dependencies.length > 0 && { dependencies },
9196
+ ...this.extractTemplateAttributes(template, logicalId)
9153
9197
  };
9154
9198
  this.kickOffObservedCapture(provider, logicalId, result.physicalId, resourceType, resolvedProps);
9155
9199
  if (counts) counts.updated++;
@@ -9207,6 +9251,22 @@ var DeployEngine = class {
9207
9251
  return deps.size > 0 ? [...deps] : void 0;
9208
9252
  }
9209
9253
  /**
9254
+ * Read `DeletionPolicy` / `UpdateReplacePolicy` from the synth template
9255
+ * so they can be persisted in `ResourceState` (schema v5+). Always returns
9256
+ * both keys (`undefined` when the template does not carry the attribute)
9257
+ * so that spreading into an existing `ResourceState` reliably overrides a
9258
+ * previously-recorded value back to `undefined` — required when the user
9259
+ * removes the attribute from their CDK code. `JSON.stringify` then omits
9260
+ * the `undefined` keys when state is serialized to S3.
9261
+ */
9262
+ extractTemplateAttributes(template, logicalId) {
9263
+ const resource = template?.Resources?.[logicalId];
9264
+ return {
9265
+ deletionPolicy: resource?.DeletionPolicy,
9266
+ updateReplacePolicy: resource?.UpdateReplacePolicy
9267
+ };
9268
+ }
9269
+ /**
9210
9270
  * Build a per-resource map of "must be deleted before me" dependencies for
9211
9271
  * the DELETE phase, derived from state-recorded dependencies plus implicit
9212
9272
  * type-based ordering rules.
@@ -9363,4 +9423,4 @@ var DeployEngine = class {
9363
9423
 
9364
9424
  //#endregion
9365
9425
  export { formatError as $, resolveCaptureObservedState as A, ConfigError as B, stringifyValue as C, getDefaultStateBucketName as D, Synthesizer as E, AssemblyReader as F, ProvisioningError as G, LocalInvokeBuildError as H, clearBucketRegionCache as I, RouteDiscoveryError as J, ResourceTimeoutError as K, resolveBucketRegion as L, resolveStateBucketWithDefault as M, resolveStateBucketWithDefaultAndSource as N, getLegacyStateBucketName as O, warnDeprecatedNoPrefixCliFlag as P, SynthesisError as Q, AssetError as R, AssetPublisher as S, buildDockerImage as T, LockError as U, DependencyError as V, PartialFailureError as W, StackTerminationProtectionError as X, StackHasActiveImportsError as Y, StateError as Z, DiffCalculator as _, withRetry as a, setLogger as at, LockManager as b, collectInlinePolicyNamesManagedBySiblings as c, PATTERN_B_NAME_PROPERTIES as ct, normalizeAwsTagsToCfn as d, generateResourceNameWithFallback as dt, isCdkdError as et, resolveExplicitPhysicalId as f, withSkipPrefix as ft, IntrinsicFunctionResolver as g, assertRegionMatch as h, withResourceDeadline as i, getLogger as it, resolveSkipPrefix as j, resolveApp as k, CDK_PATH_TAG as l, PATTERN_B_RESOURCE_TYPES as lt, CloudControlProvider as m, DEFAULT_RESOURCE_WARN_AFTER_MS as n, withErrorHandling as nt, IMPLICIT_DELETE_DEPENDENCIES as o, runStackBuffered as ot, ProviderRegistry as p, withStackName as pt, ResourceUpdateNotSupportedError as q, DeployEngine as r, ConsoleLogger as rt, IAMRoleProvider as s, getLiveRenderer as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, normalizeAwsError as tt, matchesCdkPath as u, generateResourceName as ut, DagBuilder as v, WorkGraph as w, S3StateBackend as x, TemplateParser as y, CdkdError as z };
9366
- //# sourceMappingURL=deploy-engine-D44ADMVs.js.map
9426
+ //# sourceMappingURL=deploy-engine-CYrZgRDF.js.map