@go-to-k/cdkd 0.94.0 → 0.94.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.
package/dist/cli.js CHANGED
@@ -80029,7 +80029,8 @@ var PRIMARY_IDENTIFIER_FALLBACK = {
80029
80029
  };
80030
80030
  var COMPOSITE_ID_SPLITTERS = {
80031
80031
  // cdkd stores `restApiId|resourceId|httpMethod` (apigateway-provider.ts);
80032
- // CFn primary identifier is [RestApiId, ResourceId, HttpMethod] — same order.
80032
+ // CFn primary identifier is [RestApiId, ResourceId, HttpMethod] — same
80033
+ // order, and all three are writable Properties of AWS::ApiGateway::Method.
80033
80034
  "AWS::ApiGateway::Method": (id) => {
80034
80035
  const parts = id.split("|");
80035
80036
  if (parts.length !== 3) {
@@ -80037,28 +80038,98 @@ var COMPOSITE_ID_SPLITTERS = {
80037
80038
  `expected 3 parts (restApiId|resourceId|httpMethod), got ${parts.length}: '${id}'`
80038
80039
  );
80039
80040
  }
80040
- return { RestApiId: parts[0], ResourceId: parts[1], HttpMethod: parts[2] };
80041
+ const map = { RestApiId: parts[0], ResourceId: parts[1], HttpMethod: parts[2] };
80042
+ return { resourceIdentifier: map };
80041
80043
  },
80042
80044
  // cdkd stores `restApiId|resourceId` (apigateway-provider.ts);
80043
- // CFn primary identifier is [RestApiId, ResourceId].
80045
+ // CFn primary identifier is [RestApiId, ResourceId] — both are writable
80046
+ // Properties of AWS::ApiGateway::Resource.
80044
80047
  "AWS::ApiGateway::Resource": (id) => {
80045
80048
  const parts = id.split("|");
80046
80049
  if (parts.length !== 2) {
80047
80050
  throw new Error(`expected 2 parts (restApiId|resourceId), got ${parts.length}: '${id}'`);
80048
80051
  }
80049
- return { RestApiId: parts[0], ResourceId: parts[1] };
80052
+ const map = { RestApiId: parts[0], ResourceId: parts[1] };
80053
+ return { resourceIdentifier: map };
80050
80054
  },
80051
80055
  // cdkd stores `IGW|VpcId` (ec2-provider.ts);
80052
80056
  // CFn primary identifier is [VpcId, InternetGatewayId] — DIFFERENT order
80053
- // from cdkd. Splitter reorders explicitly.
80057
+ // from cdkd. Splitter reorders explicitly. Both are writable Properties.
80054
80058
  "AWS::EC2::VPCGatewayAttachment": (id) => {
80055
80059
  const parts = id.split("|");
80056
80060
  if (parts.length !== 2) {
80057
80061
  throw new Error(`expected 2 parts (IGW|VpcId), got ${parts.length}: '${id}'`);
80058
80062
  }
80059
- return { VpcId: parts[1], InternetGatewayId: parts[0] };
80063
+ const map = { VpcId: parts[1], InternetGatewayId: parts[0] };
80064
+ return { resourceIdentifier: map };
80065
+ },
80066
+ // cdkd stores just `IntegrationId` (apigatewayv2-provider.ts); the parent
80067
+ // `ApiId` lives in cdkd state's properties (`properties.ApiId`). CFn primary
80068
+ // identifier is [ApiId, IntegrationId]. ApiId IS a writable Property
80069
+ // (already in synth template via Ref); IntegrationId is tagged
80070
+ // `readOnlyProperties: ['/properties/IntegrationId']` in the CFn schema —
80071
+ // exclude it from propertiesOverlay so CFn doesn't reject writing a
80072
+ // read-only property at changeset-create.
80073
+ "AWS::ApiGatewayV2::Integration": (physicalId, properties) => {
80074
+ const apiId = readStringProperty(properties, "ApiId", "AWS::ApiGatewayV2::Integration");
80075
+ return {
80076
+ resourceIdentifier: { ApiId: apiId, IntegrationId: physicalId },
80077
+ propertiesOverlay: { ApiId: apiId }
80078
+ };
80079
+ },
80080
+ // cdkd stores just `RouteId` (apigatewayv2-provider.ts); parent `ApiId`
80081
+ // comes from properties. CFn primary identifier is [ApiId, RouteId]. Same
80082
+ // overlay narrowing as Integration above.
80083
+ "AWS::ApiGatewayV2::Route": (physicalId, properties) => {
80084
+ const apiId = readStringProperty(properties, "ApiId", "AWS::ApiGatewayV2::Route");
80085
+ return {
80086
+ resourceIdentifier: { ApiId: apiId, RouteId: physicalId },
80087
+ propertiesOverlay: { ApiId: apiId }
80088
+ };
80089
+ },
80090
+ // NOTE: `AWS::ApiGatewayV2::Stage` is intentionally NOT in this map.
80091
+ // (1) AWS reports its primaryIdentifier as `['/properties/Id']` (single-key),
80092
+ // so cdkd's single-key resolution path handles it without a splitter.
80093
+ // (2) But AWS CloudFormation does NOT support `AWS::ApiGatewayV2::Stage` in
80094
+ // IMPORT changesets (CreateChangeSet rejects with "ResourceTypes
80095
+ // [AWS::ApiGatewayV2::Stage] are not supported for Import"). This means
80096
+ // `cdkd export` cannot complete on any stack that includes an HttpApi
80097
+ // (CDK auto-creates a `$default` Stage). Tracked in a follow-up issue
80098
+ // (link in PR description); the workaround design is open
80099
+ // (pre-delete + phase-2-CREATE vs hard-block-with-clear-error).
80100
+ // cdkd stores `StatementId` (lambda-permission-provider.ts:124); for state
80101
+ // entries written by the older CC-API path (pre-SDK-provider), physicalId
80102
+ // may instead be the legacy `<functionArn>|<statementId>` shape — the
80103
+ // provider's own delete / update / getAttribute paths normalize via
80104
+ // `physicalId.split('|').pop()` (see lambda-permission-provider.ts:160 /
80105
+ // 222 / 290). Mirror that here so legacy state still produces the
80106
+ // correct CFn Id field; otherwise CFn IMPORT's identifier-match would
80107
+ // compare `Id: '<arn>|<sid>'` against the AWS-current Sid and reject.
80108
+ //
80109
+ // CFn primary identifier is [FunctionName, Id] (note: CFn schema calls
80110
+ // the field `Id`, not `StatementId`). FunctionName IS a writable
80111
+ // Property; `Id` is tagged `readOnlyProperties: ['/properties/Id']` in
80112
+ // the CFn schema (it's set at create time by AWS, not by the user).
80113
+ // Narrow overlay to FunctionName so CFn doesn't reject writing read-only
80114
+ // `Id` at changeset-create.
80115
+ "AWS::Lambda::Permission": (physicalId, properties) => {
80116
+ const functionName = readStringProperty(properties, "FunctionName", "AWS::Lambda::Permission");
80117
+ const statementId = physicalId.includes("|") ? physicalId.split("|").pop() : physicalId;
80118
+ return {
80119
+ resourceIdentifier: { FunctionName: functionName, Id: statementId },
80120
+ propertiesOverlay: { FunctionName: functionName }
80121
+ };
80060
80122
  }
80061
80123
  };
80124
+ function readStringProperty(properties, key, resourceType) {
80125
+ const v = properties[key];
80126
+ if (typeof v !== "string" || !v) {
80127
+ throw new Error(
80128
+ `cdkd state's properties for ${resourceType} is missing '${key}' (the parent identifier required to build the CFn ResourceIdentifier map). State entry may be corrupt or written by an older cdkd binary; re-deploy the resource to refresh state.`
80129
+ );
80130
+ }
80131
+ return v;
80132
+ }
80062
80133
  async function exportCommand(stackArg, options) {
80063
80134
  const logger = getLogger();
80064
80135
  if (options.verbose) {
@@ -80436,11 +80507,12 @@ async function buildImportPlan(state, template, cfnClient) {
80436
80507
  });
80437
80508
  continue;
80438
80509
  }
80439
- let resourceIdentifier;
80510
+ let resolved;
80440
80511
  try {
80441
- resourceIdentifier = await resolveResourceIdentifier(
80512
+ resolved = await resolveResourceIdentifier(
80442
80513
  resourceType,
80443
80514
  stateEntry.physicalId,
80515
+ stateEntry.properties ?? {},
80444
80516
  cfnClient,
80445
80517
  identifierCache
80446
80518
  );
@@ -80456,19 +80528,21 @@ async function buildImportPlan(state, template, cfnClient) {
80456
80528
  logicalId,
80457
80529
  resourceType,
80458
80530
  physicalId: stateEntry.physicalId,
80459
- resourceIdentifier
80531
+ resourceIdentifier: resolved.resourceIdentifier,
80532
+ propertiesOverlay: resolved.propertiesOverlay ?? resolved.resourceIdentifier
80460
80533
  });
80461
80534
  }
80462
80535
  return { phase1Imports, phase2Creates, blocked };
80463
80536
  }
80464
- async function resolveResourceIdentifier(resourceType, physicalId, cfnClient, cache2) {
80537
+ async function resolveResourceIdentifier(resourceType, physicalId, properties, cfnClient, cache2) {
80465
80538
  let entry = cache2.get(resourceType);
80466
80539
  if (entry === void 0) {
80467
80540
  entry = await fetchPrimaryIdentifier(resourceType, cfnClient);
80468
80541
  cache2.set(resourceType, entry);
80469
80542
  }
80470
80543
  if (entry.fields.length === 1) {
80471
- return { [entry.fields[0]]: physicalId };
80544
+ const map = { [entry.fields[0]]: physicalId };
80545
+ return { resourceIdentifier: map };
80472
80546
  }
80473
80547
  const splitter = COMPOSITE_ID_SPLITTERS[resourceType];
80474
80548
  if (!splitter) {
@@ -80476,22 +80550,22 @@ async function resolveResourceIdentifier(resourceType, physicalId, cfnClient, ca
80476
80550
  `resource type uses a composite primary identifier (${entry.fields.length} fields: ${entry.fields.join(", ")}); add an entry to COMPOSITE_ID_SPLITTERS in src/cli/commands/export.ts that parses cdkd's physicalId for this type, or destroy the resource first and let CFn create it fresh`
80477
80551
  );
80478
80552
  }
80479
- let split;
80553
+ let result;
80480
80554
  try {
80481
- split = splitter(physicalId);
80555
+ result = splitter(physicalId, properties);
80482
80556
  } catch (err) {
80483
80557
  throw new Error(
80484
80558
  `composite-id splitter for ${resourceType} failed: ` + (err instanceof Error ? err.message : String(err))
80485
80559
  );
80486
80560
  }
80487
80561
  for (const f of entry.fields) {
80488
- if (!(f in split)) {
80562
+ if (!(f in result.resourceIdentifier)) {
80489
80563
  throw new Error(
80490
- `composite-id splitter for ${resourceType} did not produce field '${f}' (produced: ${Object.keys(split).join(", ")})`
80564
+ `composite-id splitter for ${resourceType} did not produce field '${f}' (produced: ${Object.keys(result.resourceIdentifier).join(", ")})`
80491
80565
  );
80492
80566
  }
80493
80567
  }
80494
- return split;
80568
+ return result;
80495
80569
  }
80496
80570
  async function fetchPrimaryIdentifier(resourceType, cfnClient) {
80497
80571
  try {
@@ -80614,7 +80688,8 @@ function overlayResourceIdentifierOnProperties(resource, entry) {
80614
80688
  const r = resource;
80615
80689
  const existingProperties = r["Properties"];
80616
80690
  const properties = existingProperties && typeof existingProperties === "object" && !Array.isArray(existingProperties) ? { ...existingProperties } : {};
80617
- for (const [field, value] of Object.entries(entry.resourceIdentifier)) {
80691
+ const overlay = entry.propertiesOverlay ?? entry.resourceIdentifier;
80692
+ for (const [field, value] of Object.entries(overlay)) {
80618
80693
  properties[field] = value;
80619
80694
  }
80620
80695
  return { ...r, Properties: properties };
@@ -80982,7 +81057,7 @@ function reorderArgs(argv) {
80982
81057
  }
80983
81058
  async function main() {
80984
81059
  const program = new Command18();
80985
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.94.0");
81060
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.94.1");
80986
81061
  program.addCommand(createBootstrapCommand());
80987
81062
  program.addCommand(createSynthCommand());
80988
81063
  program.addCommand(createListCommand());