@go-to-k/cdkd 0.207.3 → 0.207.5

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.
package/dist/cli.js CHANGED
@@ -11888,6 +11888,33 @@ var SSMParameterProvider = class {
11888
11888
  this.ssmClient = awsClients.ssm;
11889
11889
  }
11890
11890
  /**
11891
+ * Normalize a CFn `AWS::SSM::Parameter.Tags` value into the SDK `Tag[]`
11892
+ * shape. Unlike most CFn resources (whose `Tags` is a `{Key,Value}[]` list),
11893
+ * `AWS::SSM::Parameter.Tags` is a key->value **map** (`{ "Env": "prod" }`) —
11894
+ * CDK synthesizes the map form, so `properties['Tags'].map(...)` throws
11895
+ * `Tags.map is not a function`. Accept the map (canonical) AND the list
11896
+ * (defensive, in case a hand-authored / escape-hatched template supplies it),
11897
+ * coerce each value to a string (SSM tag values must be strings), and drop
11898
+ * `aws:`-prefixed reserved keys (AWS rejects user attempts to set them).
11899
+ */
11900
+ cfnTagsToSdkTags(raw) {
11901
+ if (raw === void 0 || raw === null) return [];
11902
+ const coerce = (v) => typeof v === "string" ? v : typeof v === "number" || typeof v === "boolean" ? String(v) : "";
11903
+ let entries;
11904
+ if (Array.isArray(raw)) entries = raw.map((t) => [t?.["Key"], t?.["Value"]]);
11905
+ else if (typeof raw === "object") entries = Object.entries(raw);
11906
+ else entries = [];
11907
+ const out = [];
11908
+ for (const [key, value] of entries) {
11909
+ if (typeof key !== "string" || key.length === 0 || key.startsWith("aws:")) continue;
11910
+ out.push({
11911
+ Key: key,
11912
+ Value: coerce(value)
11913
+ });
11914
+ }
11915
+ return out;
11916
+ }
11917
+ /**
11891
11918
  * Create an SSM parameter
11892
11919
  */
11893
11920
  async create(logicalId, resourceType, properties) {
@@ -11913,17 +11940,12 @@ var SSMParameterProvider = class {
11913
11940
  if (properties["DataType"]) putParams.DataType = properties["DataType"];
11914
11941
  await this.ssmClient.send(new PutParameterCommand(putParams));
11915
11942
  try {
11916
- if (properties["Tags"]) {
11917
- const ssmTags = properties["Tags"].map((t) => ({
11918
- Key: t.Key,
11919
- Value: t.Value
11920
- }));
11921
- await this.ssmClient.send(new AddTagsToResourceCommand({
11922
- ResourceType: "Parameter",
11923
- ResourceId: name,
11924
- Tags: ssmTags
11925
- }));
11926
- }
11943
+ const ssmTags = this.cfnTagsToSdkTags(properties["Tags"]);
11944
+ if (ssmTags.length > 0) await this.ssmClient.send(new AddTagsToResourceCommand({
11945
+ ResourceType: "Parameter",
11946
+ ResourceId: name,
11947
+ Tags: ssmTags
11948
+ }));
11927
11949
  } catch (innerError) {
11928
11950
  try {
11929
11951
  await this.ssmClient.send(new DeleteParameterCommand({ Name: name }));
@@ -11967,25 +11989,21 @@ var SSMParameterProvider = class {
11967
11989
  if (properties["Policies"] !== void 0) putParams.Policies = properties["Policies"];
11968
11990
  if (properties["DataType"] !== void 0) putParams.DataType = properties["DataType"];
11969
11991
  await this.ssmClient.send(new PutParameterCommand(putParams));
11970
- const newTags = properties["Tags"];
11971
- const oldTags = previousProperties["Tags"];
11972
- if (JSON.stringify(newTags) !== JSON.stringify(oldTags)) {
11973
- if (oldTags && oldTags.length > 0) await this.ssmClient.send(new RemoveTagsFromResourceCommand({
11992
+ const newTags = this.cfnTagsToSdkTags(properties["Tags"]);
11993
+ const oldTags = this.cfnTagsToSdkTags(previousProperties["Tags"]);
11994
+ const tagKey = (t) => t.Key;
11995
+ const sortedJson = (tags) => JSON.stringify([...tags].sort((a, b) => tagKey(a).localeCompare(tagKey(b))));
11996
+ if (sortedJson(newTags) !== sortedJson(oldTags)) {
11997
+ if (oldTags.length > 0) await this.ssmClient.send(new RemoveTagsFromResourceCommand({
11974
11998
  ResourceType: "Parameter",
11975
11999
  ResourceId: physicalId,
11976
12000
  TagKeys: oldTags.map((t) => t.Key)
11977
12001
  }));
11978
- if (newTags && newTags.length > 0) {
11979
- const ssmTags = newTags.map((t) => ({
11980
- Key: t.Key,
11981
- Value: t.Value
11982
- }));
11983
- await this.ssmClient.send(new AddTagsToResourceCommand({
11984
- ResourceType: "Parameter",
11985
- ResourceId: physicalId,
11986
- Tags: ssmTags
11987
- }));
11988
- }
12002
+ if (newTags.length > 0) await this.ssmClient.send(new AddTagsToResourceCommand({
12003
+ ResourceType: "Parameter",
12004
+ ResourceId: physicalId,
12005
+ Tags: newTags
12006
+ }));
11989
12007
  this.logger.debug(`Updated tags for SSM parameter ${physicalId}`);
11990
12008
  }
11991
12009
  this.logger.debug(`Successfully updated SSM parameter ${logicalId}`);
@@ -12096,10 +12114,11 @@ var SSMParameterProvider = class {
12096
12114
  } catch {}
12097
12115
  if (!policiesEmitted) result["Policies"] = [];
12098
12116
  try {
12099
- result["Tags"] = normalizeAwsTagsToCfn((await this.ssmClient.send(new ListTagsForResourceCommand$2({
12117
+ const tagArr = normalizeAwsTagsToCfn((await this.ssmClient.send(new ListTagsForResourceCommand$2({
12100
12118
  ResourceType: "Parameter",
12101
12119
  ResourceId: physicalId
12102
12120
  }))).TagList);
12121
+ result["Tags"] = Object.fromEntries(tagArr.map((t) => [t.Key, t.Value]));
12103
12122
  } catch {}
12104
12123
  return result;
12105
12124
  }
@@ -23170,11 +23189,19 @@ var Route53Provider = class {
23170
23189
  * DISABLED / undefined / NoSuchHostedZone → return early (nothing
23171
23190
  * to do, the delete will proceed normally or hit the existing
23172
23191
  * NoSuchHostedZone short-circuit).
23173
- * 2. ENABLING / ENABLEDissue `UpdateHostedZoneFeatures(false)` then
23174
- * poll `GetHostedZone` until the status settles to DISABLED.
23175
- * 3. DISABLING poll without re-issuing the toggle.
23176
- * 4. *_FAILED / *_HOSTED_ZONE_LOCKED surface the AWS error to the
23177
- * operator (out of scope for cdkd to recover automatically).
23192
+ * 2. ENABLING / ENABLING_HOSTED_ZONE_LOCKEDwait for the enable to
23193
+ * settle (AWS rejects a disable while enabling is in flight), then
23194
+ * fall through to the disable below.
23195
+ * 3. ENABLEDissue `UpdateHostedZoneFeatures(false)` then poll
23196
+ * `GetHostedZone` until the status settles to DISABLED.
23197
+ * 4. DISABLING / DISABLING_HOSTED_ZONE_LOCKED → poll without re-issuing
23198
+ * the toggle. The `*_HOSTED_ZONE_LOCKED` states are transient
23199
+ * sub-states of the enable/disable transition (AWS briefly locks the
23200
+ * zone mid-transition) — they settle to ENABLED / DISABLED on their
23201
+ * own, so cdkd waits through them rather than treating them as a
23202
+ * terminal failure.
23203
+ * 5. *_FAILED → surface the AWS error to the operator (out of scope for
23204
+ * cdkd to recover automatically).
23178
23205
  *
23179
23206
  * Poll budget: env-overridable timeout (default 10 min) + interval
23180
23207
  * (default 15s; tests override via env to keep runs fast). Failure to
@@ -23194,12 +23221,7 @@ var Route53Provider = class {
23194
23221
  }
23195
23222
  };
23196
23223
  const deadline = Date.now() + timeoutMs;
23197
- const TERMINAL_FAILED = new Set([
23198
- "ENABLE_FAILED",
23199
- "DISABLE_FAILED",
23200
- "ENABLING_HOSTED_ZONE_LOCKED",
23201
- "DISABLING_HOSTED_ZONE_LOCKED"
23202
- ]);
23224
+ const TERMINAL_FAILED = new Set(["ENABLE_FAILED", "DISABLE_FAILED"]);
23203
23225
  const waitFor = async (targets, label) => {
23204
23226
  while (Date.now() < deadline) {
23205
23227
  const status = await readStatus();
@@ -23218,8 +23240,8 @@ var Route53Provider = class {
23218
23240
  let current = await readStatus();
23219
23241
  if (current === void 0 || current === "DISABLED") return;
23220
23242
  if (TERMINAL_FAILED.has(current)) throw new ProvisioningError(`Cannot delete hosted zone ${logicalId} (${physicalId}): AcceleratedRecoveryStatus is '${current}' — operator must resolve before destroy can proceed`, "AWS::Route53::HostedZone", logicalId, physicalId);
23221
- if (current === "ENABLING") {
23222
- this.logger.debug(`Hosted zone ${physicalId} is ENABLING; waiting for it to settle before issuing disable`);
23243
+ if (current === "ENABLING" || current === "ENABLING_HOSTED_ZONE_LOCKED") {
23244
+ this.logger.debug(`Hosted zone ${physicalId} is ${current} (an enabling phase); waiting for it to settle before issuing disable`);
23223
23245
  current = await waitFor(new Set(["ENABLED", "DISABLED"]), "ENABLED or DISABLED");
23224
23246
  if (current === void 0 || current === "DISABLED") return;
23225
23247
  }
@@ -23229,7 +23251,7 @@ var Route53Provider = class {
23229
23251
  HostedZoneId: physicalId,
23230
23252
  EnableAcceleratedRecovery: false
23231
23253
  }));
23232
- } else if (current === "DISABLING") this.logger.debug(`Hosted zone ${physicalId} AcceleratedRecovery is already DISABLING; waiting for settle`);
23254
+ } else if (current === "DISABLING" || current === "DISABLING_HOSTED_ZONE_LOCKED") this.logger.debug(`Hosted zone ${physicalId} AcceleratedRecovery is already ${current} (a disabling phase); waiting for settle`);
23233
23255
  const settled = await waitFor(new Set(["DISABLED"]), "DISABLED");
23234
23256
  this.logger.debug(`Hosted zone ${physicalId} AcceleratedRecoveryStatus settled to ${settled ?? "undefined (zone gone)"}`);
23235
23257
  }
@@ -52696,7 +52718,7 @@ function reorderArgs(argv) {
52696
52718
  */
52697
52719
  async function main() {
52698
52720
  const program = new Command();
52699
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.207.3");
52721
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.207.5");
52700
52722
  program.addCommand(createBootstrapCommand());
52701
52723
  program.addCommand(createSynthCommand());
52702
52724
  program.addCommand(createListCommand());