@go-to-k/cdkd 0.282.2 → 0.282.4

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { $ as configStringRefusal, $t as MIGRATE_TMP_PREFIX, A as green, At as validateContainerRepoName, B as slowCcOperationTimeoutMs, Bt as getDefaultStateBucketName, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as NestedStackChildDirectDestroyError, Ct as rewriteTemplateAssetReferences, D as bold, Dn as ResourceUpdateNotSupportedError, Dt as getBootstrapMarkerKey, E as formatResourceLine, En as ResourceTimeoutError, Et as ensureAssetStorage, F as clearOnUpdateRemoval, Fn as withErrorHandling, Ft as runDockerStreaming, G as getAccountInfo, Gt as resolveSkipPrefix, H as isTerminationProtectionPropagationError, Ht as resolveApp, I as ProviderRegistry, It as AssetManifestLoader, J as normalizeAwsTagsToCfn, Jt as resolveUseCdkBootstrapAssets, K as refStateLookupFromResource, Kt as resolveStateBucketWithDefault, L as findActionableSilentDrops, Lt as getDockerImageBySourceHash, M as yellow, Mt as formatDockerLoginError, N as IAMRoleProvider, Nt as getDockerCmd, O as cyan, On as StackHasActiveImportsError, Ot as parseBootstrapMarker, P as collectInlinePolicyNamesManagedBySiblings, Pn as normalizeAwsError, Pt as runDockerForeground, Q as configBooleanRefusal, Qt as CFN_TEMPLATE_URL_LIMIT, R as findSilentDropProperties, Rt as Synthesizer, S as extractDeploymentEventError, Sn as MissingCdkCliError, St as loadPublishableAssetManifest, T as renderStatefulReason, Tn as ProvisioningError, Tt as BOOTSTRAP_MARKER_PREFIX, U as IntrinsicFunctionResolver, Ut as resolveAutoAssetStorage, V as disableInstanceApiTermination, Vt as getLegacyStateBucketName, W as cfnRefValueFromPhysicalId, Wt as resolveCaptureObservedState, X as assertRegionMatch, Xt as warnDeprecatedNoPrefixCliFlag, Y as resolveExplicitPhysicalId, Yt as stateBucketExistenceConfirmed, Z as coerceCfnBoolean, Zt as CFN_TEMPLATE_BODY_LIMIT, _ as createPreDeleteFinalSnapshot, _n as DeployCancelledError, _t as AssetPublisher, a as DeploymentEventsStore, an as AssemblyReader, at as applyRoleArnIfSet, b as unsupportedFinalSnapshotError, bn as LocalStartServiceError, bt as buildAssetRedirectMap, c as replayFailedOperations, cn as resolveBucketRegion, ct as withRetry, d as IMPLICIT_DELETE_DEPENDENCIES, dn as resetAwsClients, dt as DagBuilder, en as findLargeInlineResources, et as readConfigString, f as computeImplicitDeleteEdges, fn as setAwsClients, ft as TemplateParser, g as ccRoutedFinalSnapshotError, gt as shouldRetainResource, h as buildFinalSnapshotIdentifier, ht as rebuildClientForBucketRegion, i as DeploymentEventsReader, in as derivePartitionAndUrlSuffix, it as requireConfigString, j as red, jt as buildDockerImage, k as gray, kn as StackTerminationProtectionError, kt as validateAssetBucketName, l as replayRollback, ln as AwsClients, lt as isRetryableTransientError, m as PRE_DELETE_SNAPSHOT_TYPES, mn as CdkdError, mt as S3StateBackend, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as expectedOwnerParam, nt as requireConfigArray, o as planFailedOps, on as processStackMessages, ot as DiffCalculator, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pt as LockManager, q as WAFv2WebACLProvider, qt as resolveStateBucketWithDefaultAndSource, r as DeployEngine, rn as PARTITION_TABLE, rt as requireConfigObject, s as planRollback, st as describeTypeWithThrottleRetry, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as uploadCfnTemplate, tt as replayWarn, u as withResourceDeadline, un as getAwsClients, ut as isThrottlingError, v as isFinalSnapshotError, vn as LocalInvokeBuildError$1, vt as stringifyValue, w as isStatefulRecreateTargetSync, wn as PartialFailureError, wt as AssetModeResolver, x as makeCanonicalizePropertiesFn, xt as createAssetRedirectResolver, y as refusesFinalSnapshot, yn as LocalMigrateError, yt as WorkGraph, z as CloudControlProvider, zt as synthesisStatusMessage } from "./deploy-engine-6sSRIhrN.js";
2
+ import { $ as configStringRefusal, $t as resolveUseCdkBootstrapAssets, A as green, An as ProvisioningError, At as BOOTSTRAP_MARKER_PREFIX, B as slowCcOperationTimeoutMs, Bn as withErrorHandling, Bt as runDockerStreaming, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as LocalInvokeBuildError$1, Ct as stringifyValue, D as bold, Dn as MissingCdkCliError, Dt as loadPublishableAssetManifest, E as formatResourceLine, Et as createAssetRedirectResolver, F as clearOnUpdateRemoval, Ft as validateContainerRepoName, G as getAccountInfo, Gt as getDefaultStateBucketName, H as isTerminationProtectionPropagationError, Ht as getDockerImageBySourceHash, I as ProviderRegistry, It as buildDockerImage, J as normalizeAwsTagsToCfn, Jt as resolveAutoAssetStorage, K as refStateLookupFromResource, Kt as getLegacyStateBucketName, L as findActionableSilentDrops, Lt as formatDockerLoginError, M as yellow, Mn as ResourceUpdateNotSupportedError, Mt as getBootstrapMarkerKey, N as IAMRoleProvider, Nn as StackHasActiveImportsError, Nt as parseBootstrapMarker, O as cyan, On as NestedStackChildDirectDestroyError, Ot as rewriteTemplateAssetReferences, P as collectInlinePolicyNamesManagedBySiblings, Pn as StackTerminationProtectionError, Pt as validateAssetBucketName, Q as configBooleanRefusal, Qt as resolveStateBucketWithDefaultAndSource, R as findSilentDropProperties, Rt as getDockerCmd, S as extractDeploymentEventError, Sn as DeployCancelledError, St as AssetPublisher, T as renderStatefulReason, Tn as LocalStartServiceError, Tt as buildAssetRedirectMap, U as IntrinsicFunctionResolver, Ut as Synthesizer, V as disableInstanceApiTermination, Vt as AssetManifestLoader, W as cfnRefValueFromPhysicalId, Wt as synthesisStatusMessage, X as assertRegionMatch, Xt as resolveSkipPrefix, Y as resolveExplicitPhysicalId, Yt as resolveCaptureObservedState, Z as coerceCfnBoolean, Zt as resolveStateBucketWithDefault, _ as createPreDeleteFinalSnapshot, _n as setAwsClients, _t as TemplateParser, a as DeploymentEventsStore, an as findLargeInlineResources, at as s3BucketArn, b as unsupportedFinalSnapshotError, bt as rebuildClientForBucketRegion, c as replayFailedOperations, cn as PARTITION_TABLE, ct as s3BucketRegionalDomainName, d as IMPLICIT_DELETE_DEPENDENCIES, dn as processStackMessages, dt as DiffCalculator, en as stateBucketExistenceConfirmed, et as readConfigString, f as computeImplicitDeleteEdges, ft as describeTypeWithThrottleRetry, g as ccRoutedFinalSnapshotError, gn as resetAwsClients, gt as DagBuilder, h as buildFinalSnapshotIdentifier, hn as getAwsClients, ht as isThrottlingError, i as DeploymentEventsReader, in as MIGRATE_TMP_PREFIX, it as requireConfigString, j as red, jn as ResourceTimeoutError, jt as ensureAssetStorage, k as gray, kn as PartialFailureError, kt as AssetModeResolver, l as replayRollback, ln as derivePartitionAndUrlSuffix, lt as s3BucketWebsiteUrl, m as PRE_DELETE_SNAPSHOT_TYPES, mn as AwsClients, mt as isRetryableTransientError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as CFN_TEMPLATE_BODY_LIMIT, nt as requireConfigArray, o as planFailedOps, on as uploadCfnTemplate, ot as s3BucketDomainName, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as resolveBucketRegion, pt as withRetry, q as WAFv2WebACLProvider, qt as resolveApp, r as DeployEngine, rn as CFN_TEMPLATE_URL_LIMIT, rt as requireConfigObject, s as planRollback, sn as expectedOwnerParam, st as s3BucketDualStackDomainName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as warnDeprecatedNoPrefixCliFlag, tt as replayWarn, u as withResourceDeadline, un as AssemblyReader, ut as applyRoleArnIfSet, v as isFinalSnapshotError, vt as LockManager, w as isStatefulRecreateTargetSync, wn as LocalMigrateError, wt as WorkGraph, x as makeCanonicalizePropertiesFn, xt as shouldRetainResource, y as refusesFinalSnapshot, yn as CdkdError, yt as S3StateBackend, z as CloudControlProvider, zn as normalizeAwsError, zt as runDockerForeground } from "./deploy-engine-CnxJLy3Y.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
4
- import { t as ASGProvider } from "./asg-provider-B5EgvcoP.js";
4
+ import { t as ASGProvider } from "./asg-provider-D9VJTwn3.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -5981,11 +5981,11 @@ var S3BucketProvider = class S3BucketProvider {
5981
5981
  async buildAttributes(bucketName) {
5982
5982
  const region = await this.getRegion();
5983
5983
  return {
5984
- Arn: `arn:aws:s3:::${bucketName}`,
5985
- DomainName: `${bucketName}.s3.amazonaws.com`,
5986
- DualStackDomainName: `${bucketName}.s3.dualstack.${region}.amazonaws.com`,
5987
- RegionalDomainName: `${bucketName}.s3.${region}.amazonaws.com`,
5988
- WebsiteURL: `http://${bucketName}.s3-website-${region}.amazonaws.com`
5984
+ Arn: s3BucketArn(bucketName, region),
5985
+ DomainName: s3BucketDomainName(bucketName, region),
5986
+ DualStackDomainName: s3BucketDualStackDomainName(bucketName, region),
5987
+ RegionalDomainName: s3BucketRegionalDomainName(bucketName, region),
5988
+ WebsiteURL: s3BucketWebsiteUrl(bucketName, region)
5989
5989
  };
5990
5990
  }
5991
5991
  /**
@@ -20350,7 +20350,7 @@ const EC2_NETWORK_ACL_ENTRY_ID_FORMAT = {
20350
20350
  * `DestinationCidrBlock || DestinationIpv6CidrBlock || DestinationPrefixListId`
20351
20351
  * chain resolves them.
20352
20352
  */
20353
- const ROUTE_DESTINATION_KEYS = [
20353
+ const ROUTE_DESTINATION_KEYS$1 = [
20354
20354
  "DestinationCidrBlock",
20355
20355
  "DestinationIpv6CidrBlock",
20356
20356
  "DestinationPrefixListId"
@@ -20377,7 +20377,7 @@ const ROUTE_DESTINATION_KEYS = [
20377
20377
  * `resolvedProps`, which it records for every resource that does NOT narrow.
20378
20378
  */
20379
20379
  function narrowRouteDestinations(properties) {
20380
- const declared = ROUTE_DESTINATION_KEYS.filter((key) => Boolean(properties[key]));
20380
+ const declared = ROUTE_DESTINATION_KEYS$1.filter((key) => Boolean(properties[key]));
20381
20381
  const narrowed = { ...properties };
20382
20382
  for (const losingKey of declared.slice(1)) delete narrowed[losingKey];
20383
20383
  return {
@@ -59107,6 +59107,36 @@ const COMPOSITE_ID_SPLITTERS = {
59107
59107
  propertiesOverlay: { VpcId: vpcId }
59108
59108
  };
59109
59109
  },
59110
+ "AWS::EC2::Route": (physicalId, properties) => {
59111
+ const parts = physicalId.split("|");
59112
+ if (parts.length !== 2) throw new Error(`expected 2 parts ('<routeTableId>|<destination>'), got ${parts.length}: '${physicalId}'`);
59113
+ const [routeTableId, destination] = parts;
59114
+ if (!routeTableId.trim() || !destination.trim()) throw new Error(`empty part in '<routeTableId>|<destination>': '${physicalId}'`);
59115
+ return {
59116
+ resourceIdentifier: {
59117
+ RouteTableId: routeTableId,
59118
+ CidrBlock: resolveRouteDestination(destination, properties)
59119
+ },
59120
+ propertiesOverlay: { RouteTableId: routeTableId }
59121
+ };
59122
+ },
59123
+ "AWS::EC2::EIP": (physicalId) => {
59124
+ const parts = physicalId.split("|");
59125
+ if (parts.length !== 2) throw new Error(`expected 2 parts ('<publicIp>|<allocationId>'), got ${parts.length}: '${physicalId}'. CloudFormation identifies an AWS::EC2::EIP by BOTH fields, and neither can be recovered from the other; re-deploy the resource to refresh state`);
59126
+ const [first, second] = parts;
59127
+ if (!first.trim() || !second.trim()) throw new Error(`empty part in '<publicIp>|<allocationId>': '${physicalId}'`);
59128
+ const allocationFirst = first.startsWith(EIP_ALLOCATION_ID_PREFIX);
59129
+ const publicIp = allocationFirst ? second : first;
59130
+ const allocationId = allocationFirst ? first : second;
59131
+ if (!allocationId.startsWith(EIP_ALLOCATION_ID_PREFIX) || !EIP_PUBLIC_IP_PATTERN.test(publicIp)) throw new Error(`'${physicalId}' is not an '<publicIp>|<allocationId>' pair: CloudFormation identifies an AWS::EC2::EIP by [PublicIp, AllocationId], so one segment must be an allocation id ('${EIP_ALLOCATION_ID_PREFIX}…') and the other a dotted-quad public IP. State entry may be corrupt or written by an older cdkd binary; re-deploy the resource to refresh state`);
59132
+ return {
59133
+ resourceIdentifier: {
59134
+ PublicIp: publicIp,
59135
+ AllocationId: allocationId
59136
+ },
59137
+ propertiesOverlay: {}
59138
+ };
59139
+ },
59110
59140
  "AWS::ApiGateway::Deployment": restApiChildSplitter({
59111
59141
  resourceType: "AWS::ApiGateway::Deployment",
59112
59142
  childField: "DeploymentId",
@@ -59167,6 +59197,21 @@ const COMPOSITE_ID_SPLITTERS = {
59167
59197
  Namespace: namespace
59168
59198
  } };
59169
59199
  },
59200
+ "AWS::Lambda::EventInvokeConfig": (physicalId) => {
59201
+ if (!physicalId.trim()) throw new Error("empty physical id for AWS::Lambda::EventInvokeConfig (expected '<functionName>|<qualifier>' or a bare function name)");
59202
+ const separator = physicalId.indexOf("|");
59203
+ if (separator === -1) return { resourceIdentifier: {
59204
+ FunctionName: physicalId,
59205
+ Qualifier: "$LATEST"
59206
+ } };
59207
+ const functionName = physicalId.slice(0, separator);
59208
+ const qualifier = physicalId.slice(separator + 1);
59209
+ if (!functionName.trim() || !qualifier.trim()) throw new Error(`empty part in '<functionName>|<qualifier>': '${physicalId}'`);
59210
+ return { resourceIdentifier: {
59211
+ FunctionName: functionName,
59212
+ Qualifier: qualifier
59213
+ } };
59214
+ },
59170
59215
  "AWS::Lambda::Permission": (physicalId, properties) => {
59171
59216
  const functionName = readStringProperty(properties, "FunctionName", "AWS::Lambda::Permission");
59172
59217
  return {
@@ -59179,11 +59224,44 @@ const COMPOSITE_ID_SPLITTERS = {
59179
59224
  }
59180
59225
  };
59181
59226
  /**
59182
- * The two values CFn's `AWS::EC2::VPCGatewayAttachment.AttachmentType` takes.
59183
- * The field is `readOnlyProperties`, so cdkd never sends it it only has to
59184
- * be reproduced for the IMPORT identifier map.
59185
- */
59186
- const GATEWAY_ATTACHMENT_TYPES = ["InternetGateway", "VPN"];
59227
+ * The prefix every EC2 Elastic IP allocation id carries. Used to discriminate
59228
+ * the two segments of an `AWS::EC2::EIP` physicalId by SHAPE rather than by
59229
+ * position see the splitter for why the order is not relied on.
59230
+ */
59231
+ const EIP_ALLOCATION_ID_PREFIX = "eipalloc-";
59232
+ /**
59233
+ * The other half of the same discriminator: an Elastic IP's public address is
59234
+ * always a dotted quad (EIPs are IPv4-only). Shape-only — the octet RANGES are
59235
+ * not checked, because this exists to tell the two segments apart, not to
59236
+ * validate an address AWS itself minted.
59237
+ */
59238
+ const EIP_PUBLIC_IP_PATTERN = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
59239
+ const GATEWAY_ATTACHMENT_TYPE_IGW = "IGW";
59240
+ const GATEWAY_ATTACHMENT_TYPE_VGW = "VGW";
59241
+ /**
59242
+ * The values AWS actually uses for `AWS::EC2::VPCGatewayAttachment`'s
59243
+ * `AttachmentType`, plus the two spellings issue #1691 guessed.
59244
+ *
59245
+ * `IGW` / `VGW` are what every real writer produces: Cloud Control stores the
59246
+ * primaryIdentifier verbatim, so a CC-written cdkd state record carries one of
59247
+ * them as segment 0. `InternetGateway` / `VPN` were never written by anything —
59248
+ * they were produced by THIS table on the way OUT, and CloudFormation rejects
59249
+ * them (`Invalid request provided: Invalid Attachment Type 'InternetGateway'`;
59250
+ * the IMPORT changeset never reaches CREATE_COMPLETE). They are kept purely as
59251
+ * input compatibility, so a physicalId hand-written from the old comment, or
59252
+ * supplied via `cdkd import --resource`, normalizes instead of falling through
59253
+ * to the property-derivation arms. Nothing in cdkd can put them in state.
59254
+ *
59255
+ * `Object.hasOwn` at the lookup site, not a bare index: a bare index on an
59256
+ * object literal answers for inherited members too, so a first segment of
59257
+ * `constructor` would resolve to a function rather than missing.
59258
+ */
59259
+ const GATEWAY_ATTACHMENT_TYPE_ALIASES = {
59260
+ [GATEWAY_ATTACHMENT_TYPE_IGW]: GATEWAY_ATTACHMENT_TYPE_IGW,
59261
+ [GATEWAY_ATTACHMENT_TYPE_VGW]: GATEWAY_ATTACHMENT_TYPE_VGW,
59262
+ InternetGateway: GATEWAY_ATTACHMENT_TYPE_IGW,
59263
+ VPN: GATEWAY_ATTACHMENT_TYPE_VGW
59264
+ };
59187
59265
  /**
59188
59266
  * Resolve `AttachmentType` for an `AWS::EC2::VPCGatewayAttachment` from the
59189
59267
  * first segment of cdkd's composite physicalId plus the recorded properties.
@@ -59191,19 +59269,154 @@ const GATEWAY_ATTACHMENT_TYPES = ["InternetGateway", "VPN"];
59191
59269
  * The Cloud-Control-written shape already carries the attachment type verbatim
59192
59270
  * (it is the CFn primaryIdentifier's first field). The SDK-written shape
59193
59271
  * carries the gateway id instead, so the type is derived from WHICH gateway
59194
- * property cdkd recorded — never hardcoded to `InternetGateway`, which would
59195
- * ship a wrong identifier for a VPN attachment and make CFn's identifier-match
59196
- * reject the import.
59272
+ * property cdkd recorded — never hardcoded to the internet-gateway value, which
59273
+ * would ship a wrong identifier for a VPN attachment and make CFn's
59274
+ * identifier-match reject the import.
59275
+ *
59276
+ * The VALUES are `IGW` / `VGW`, measured live (Cloud Control `ListResources`,
59277
+ * us-east-1, 2026-08-13) against a VPC carrying both an internet-gateway and a
59278
+ * virtual-private-gateway attachment:
59279
+ *
59280
+ * `IGW|vpc-…` -> {"AttachmentType":"IGW","VpcId":"vpc-…"}
59281
+ * `VGW|vpc-…` -> {"AttachmentType":"VGW","VpcId":"vpc-…"}
59282
+ *
59283
+ * The registry schema does not enumerate them (`AttachmentType` is a bare
59284
+ * `{"type": "string"}` whose description only says it distinguishes the two
59285
+ * kinds), which is how the spelled-out `InternetGateway` / `VPN` guesses this
59286
+ * function shipped with in issue #1691 went unnoticed: they are plausible, they
59287
+ * satisfy every unit test written against them, and CFn only rejects them at
59288
+ * changeset-create time — measured 2026-08-13 as `Invalid request provided:
59289
+ * Invalid Attachment Type 'InternetGateway'` (issue #1771).
59197
59290
  */
59198
59291
  function resolveGatewayAttachmentType(firstSegment, properties) {
59199
- if (GATEWAY_ATTACHMENT_TYPES.includes(firstSegment)) return firstSegment;
59200
- if (typeof properties["InternetGatewayId"] === "string" && properties["InternetGatewayId"]) return "InternetGateway";
59201
- if (typeof properties["VpnGatewayId"] === "string" && properties["VpnGatewayId"]) return "VPN";
59202
- if (firstSegment.startsWith("igw-")) return "InternetGateway";
59203
- if (firstSegment.startsWith("vgw-")) return "VPN";
59292
+ if (Object.hasOwn(GATEWAY_ATTACHMENT_TYPE_ALIASES, firstSegment)) return GATEWAY_ATTACHMENT_TYPE_ALIASES[firstSegment];
59293
+ if (typeof properties["InternetGatewayId"] === "string" && properties["InternetGatewayId"]) return GATEWAY_ATTACHMENT_TYPE_IGW;
59294
+ if (typeof properties["VpnGatewayId"] === "string" && properties["VpnGatewayId"]) return GATEWAY_ATTACHMENT_TYPE_VGW;
59295
+ if (firstSegment.startsWith("igw-")) return GATEWAY_ATTACHMENT_TYPE_IGW;
59296
+ if (firstSegment.startsWith("vgw-")) return GATEWAY_ATTACHMENT_TYPE_VGW;
59204
59297
  throw new Error(`cannot determine AttachmentType for AWS::EC2::VPCGatewayAttachment: cdkd state's properties carry neither 'InternetGatewayId' nor 'VpnGatewayId', and the physical id segment '${firstSegment}' is not a recognized gateway id. State entry may be corrupt or written by an older cdkd binary; re-deploy the resource to refresh state.`);
59205
59298
  }
59206
59299
  /**
59300
+ * The `AWS::EC2::Route` destination keys, in CloudFormation's own precedence
59301
+ * order — the same order (and the same list) `narrowRouteDestinations` in
59302
+ * `src/provisioning/providers/ec2-provider.ts` resolves them in when it decides
59303
+ * which one `createRoute` actually sends, i.e. which one ends up in the
59304
+ * physicalId's destination segment. Restated here rather than imported so this
59305
+ * command does not pull the EC2 provider (and its SDK client) into the export
59306
+ * module graph.
59307
+ */
59308
+ const ROUTE_DESTINATION_KEYS = [
59309
+ "DestinationCidrBlock",
59310
+ "DestinationIpv6CidrBlock",
59311
+ "DestinationPrefixListId"
59312
+ ];
59313
+ /**
59314
+ * Resolve the value CFn's read-only `AWS::EC2::Route.CidrBlock` identifier
59315
+ * field holds, from cdkd's physicalId destination segment plus the recorded
59316
+ * properties.
59317
+ *
59318
+ * The segment is the starting point — it is the destination cdkd sent to
59319
+ * `CreateRoute` (SDK path) or the `CidrBlock` AWS itself reported (Cloud Control
59320
+ * path), and `CidrBlock` holds whichever destination kind the route declares,
59321
+ * measured live; see the splitter's comment. But it is NOT returned verbatim:
59322
+ * EC2 clears host bits on the way in, so the SDK path can have stored a
59323
+ * destination AWS never held, and the identifier is always the CANONICAL form.
59324
+ *
59325
+ * The recorded properties are then read to CROSS-CHECK it, the way
59326
+ * {@link resolveGatewayAttachmentType} reads them to recover a field cdkd never
59327
+ * stores. Two very different things can make them disagree, and conflating them
59328
+ * is why this is not a plain warn:
59329
+ *
59330
+ * - **Benign.** One side carries AWS's CANONICALIZED CIDR and the other what
59331
+ * the user wrote; CFn documents rewriting e.g. `100.68.0.18/18` to
59332
+ * `100.68.0.0/18`. The identifier is CORRECT here, so refusing would block an
59333
+ * export that would have succeeded. Both sides are compared in canonical
59334
+ * form, so this case never even registers as a divergence.
59335
+ * - **Dangerous.** If state is merely stale, the id's destination can name a
59336
+ * DIFFERENT route that still exists in the same table. IMPORT then succeeds
59337
+ * against the wrong resource, and phase 2's UPDATE reconciles it to the
59338
+ * template — REPLACING, i.e. DELETING, a route the user never targeted.
59339
+ * Silently continuing here trades an opaque failure for data loss.
59340
+ *
59341
+ * So the outcome depends on whether the benign explanation is DECIDABLE, which
59342
+ * {@link routeDestinationNormalizationIsModelled} answers per declared value.
59343
+ * When every declared destination is a shape cdkd models — an IPv4 CIDR or a
59344
+ * prefix-list id — normalization either explains the difference or it does not,
59345
+ * and a non-match is refused. When any declared destination is an IPv6 CIDR,
59346
+ * whose AWS-side canonicalization cdkd does not reproduce, the divergence is
59347
+ * reported as a WARNING naming the replace-the-wrong-route outcome, because
59348
+ * refusing on an undecidable signal would block exports that are fine.
59349
+ *
59350
+ * Properties that declare NO destination at all are NOT treated as suspicious:
59351
+ * a partial / hand-edited state record must not become a refusal, and the id
59352
+ * alone is enough to build the identifier.
59353
+ */
59354
+ function resolveRouteDestination(segment, properties) {
59355
+ const identifier = canonicalizeIpv4Cidr(segment) ?? segment;
59356
+ const declared = ROUTE_DESTINATION_KEYS.filter((key) => typeof properties[key] === "string" && properties[key] !== "");
59357
+ if (declared.length === 0) return identifier;
59358
+ const declaredValues = declared.map((key) => String(properties[key]));
59359
+ if (declaredValues.some((value) => (canonicalizeIpv4Cidr(value) ?? value) === identifier)) return identifier;
59360
+ const shared = `AWS::EC2::Route: cdkd state's recorded properties declare ${declared.map((key) => `${key}='${String(properties[key])}'`).join(", ")}, but the physical id's destination segment is '${segment}'. CloudFormation identifies the route by the destination, so IMPORT would adopt whatever route currently sits at '${identifier}' — and if that is a DIFFERENT route than the template declares, phase 2 would then REPLACE (delete) it. The state entry is stale; re-deploy the resource to refresh it`;
59361
+ if (declaredValues.every((value) => routeDestinationNormalizationIsModelled(value))) throw new Error(`${shared}.`);
59362
+ getLogger().warn(`${shared}, or pass the resource through 'cdkd import --resource' with the correct id. Continuing with the physical id because at least one recorded destination is an IPv6 CIDR, whose AWS-side canonicalization cdkd does not model — so the difference may be benign.`);
59363
+ return identifier;
59364
+ }
59365
+ /**
59366
+ * An EC2 managed prefix list id (`pl-` + hex). Matched EXACTLY rather than by
59367
+ * prefix so a malformed value falls into the unmodelled class instead of being
59368
+ * treated as a comparable destination.
59369
+ */
59370
+ const ROUTE_PREFIX_LIST_ID_PATTERN = /^pl-[0-9a-f]+$/;
59371
+ /**
59372
+ * True when cdkd models how AWS normalizes this destination value, i.e. when a
59373
+ * mismatch against the physical id's segment is CONCLUSIVE rather than possibly
59374
+ * explained by a rewrite cdkd cannot reproduce.
59375
+ *
59376
+ * Two classes qualify:
59377
+ * - an IPv4 CIDR, whose host-bit rewrite {@link canonicalizeIpv4Cidr} reproduces;
59378
+ * - a prefix-list id, measured to be stored verbatim on both sides, so a
59379
+ * `pl-AAA` vs `pl-BBB` difference is a genuine wrong-route signal.
59380
+ *
59381
+ * An IPv6 CIDR does not: AWS canonicalizes those too (zero-run compression,
59382
+ * host-bit clearing) and cdkd does not reproduce it, so a mismatch there could
59383
+ * still be the same route written two ways.
59384
+ */
59385
+ function routeDestinationNormalizationIsModelled(value) {
59386
+ return canonicalizeIpv4Cidr(value) !== void 0 || ROUTE_PREFIX_LIST_ID_PATTERN.test(value);
59387
+ }
59388
+ /**
59389
+ * Return the host-bit-cleared form of an IPv4 CIDR (`100.68.0.18/18` ->
59390
+ * `100.68.0.0/18`), or `undefined` when the input is not an IPv4 CIDR at all
59391
+ * (an IPv6 CIDR, a `pl-…` prefix-list id, or anything malformed).
59392
+ *
59393
+ * This exists to recognize the ONE benign reason an `AWS::EC2::Route`'s stored
59394
+ * destination can differ from its physicalId segment: AWS rewrites a
59395
+ * non-canonical CIDR on `CreateRoute`, and the Cloud Control path records what
59396
+ * AWS returned while the template kept what the user wrote. Returning
59397
+ * `undefined` for the shapes it does not model is load-bearing — the caller
59398
+ * uses it to decide whether a divergence is conclusive or merely unexplained.
59399
+ */
59400
+ function canonicalizeIpv4Cidr(value) {
59401
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/.exec(value);
59402
+ if (!match) return void 0;
59403
+ const octets = [
59404
+ match[1],
59405
+ match[2],
59406
+ match[3],
59407
+ match[4]
59408
+ ].map(Number);
59409
+ const prefixLength = Number(match[5]);
59410
+ if (prefixLength > 32 || octets.some((octet) => octet > 255)) return void 0;
59411
+ const network = ((octets[0] << 24 | octets[1] << 16 | octets[2] << 8 | octets[3]) >>> 0 & (prefixLength === 0 ? 0 : 4294967295 << 32 - prefixLength >>> 0)) >>> 0;
59412
+ return `${[
59413
+ network >>> 24,
59414
+ network >>> 16 & 255,
59415
+ network >>> 8 & 255,
59416
+ network & 255
59417
+ ].join(".")}/${prefixLength}`;
59418
+ }
59419
+ /**
59207
59420
  * Build a splitter for an `AWS::ApiGateway::*` child type whose CFn primary
59208
59421
  * identifier is the parent `RestApiId` plus one child field.
59209
59422
  *
@@ -60201,7 +60414,7 @@ async function buildImportPlan(state, template, cfnClient, parentStackName, opti
60201
60414
  * IMPORT pre-flight and this resolution.
60202
60415
  */
60203
60416
  function resolveResourceIdentifier(resourceType, logicalId, physicalId, properties, attributes, entry) {
60204
- const compositeIdentifier = COMPOSITE_PHYSICAL_ID_IDENTIFIERS[resourceType];
60417
+ const compositeIdentifier = Object.hasOwn(COMPOSITE_PHYSICAL_ID_IDENTIFIERS, resourceType) ? COMPOSITE_PHYSICAL_ID_IDENTIFIERS[resourceType] : void 0;
60205
60418
  if (compositeIdentifier) {
60206
60419
  if (entry.fields.length !== 1 || entry.fields[0] !== compositeIdentifier.field) throw new Error(`${resourceType} is registered in COMPOSITE_PHYSICAL_ID_IDENTIFIERS as identified by '${compositeIdentifier.field}', but CloudFormation now reports primaryIdentifier [${entry.fields.join(", ")}]. The registry schema changed under cdkd — update the entry in src/cli/commands/export.ts (or move the type to COMPOSITE_ID_SPLITTERS if its identifier is now composite too)`);
60207
60420
  const value = compositeIdentifier.resolve({
@@ -60215,7 +60428,7 @@ function resolveResourceIdentifier(resourceType, logicalId, physicalId, properti
60215
60428
  };
60216
60429
  }
60217
60430
  if (entry.fields.length === 1) return { resourceIdentifier: { [entry.fields[0]]: physicalId } };
60218
- const splitter = COMPOSITE_ID_SPLITTERS[resourceType];
60431
+ const splitter = Object.hasOwn(COMPOSITE_ID_SPLITTERS, resourceType) ? COMPOSITE_ID_SPLITTERS[resourceType] : void 0;
60219
60432
  if (!splitter) throw new Error(`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`);
60220
60433
  let result;
60221
60434
  try {
@@ -75550,7 +75763,7 @@ function createMigrateCommand() {
75550
75763
  */
75551
75764
  function buildProgram() {
75552
75765
  const program = new Command();
75553
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.282.2");
75766
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.282.4");
75554
75767
  program.hook("preAction", (_thisCommand, actionCommand) => {
75555
75768
  const { profile } = actionCommand.optsWithGlobals();
75556
75769
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;