@go-to-k/cdkd 0.281.15 → 0.281.17

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 replayWarn, $t as findLargeInlineResources, A as green, At as buildDockerImage, B as slowCcOperationTimeoutMs, Bt as getLegacyStateBucketName, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as ResourceTimeoutError, Ct as AssetModeResolver, D as bold, Dt as parseBootstrapMarker, E as formatResourceLine, En as StackTerminationProtectionError, Et as getBootstrapMarkerKey, F as clearOnUpdateRemoval, Ft as AssetManifestLoader, G as getAccountInfo, Gt as resolveStateBucketWithDefault, H as isTerminationProtectionPropagationError, Ht as resolveAutoAssetStorage, I as ProviderRegistry, It as getDockerImageBySourceHash, J as normalizeAwsTagsToCfn, Jt as stateBucketExistenceConfirmed, K as refStateLookupFromResource, Kt as resolveStateBucketWithDefaultAndSource, L as findActionableSilentDrops, Lt as Synthesizer, M as yellow, Mn as withErrorHandling, Mt as getDockerCmd, N as IAMRoleProvider, Nt as runDockerForeground, O as cyan, Ot as validateAssetBucketName, P as collectInlinePolicyNamesManagedBySiblings, Pt as runDockerStreaming, Q as readConfigString, Qt as MIGRATE_TMP_PREFIX, R as findSilentDropProperties, Rt as synthesisStatusMessage, S as extractDeploymentEventError, Sn as ProvisioningError, St as rewriteTemplateAssetReferences, T as renderStatefulReason, Tn as StackHasActiveImportsError, Tt as ensureAssetStorage, U as IntrinsicFunctionResolver, Ut as resolveCaptureObservedState, V as disableInstanceApiTermination, Vt as resolveApp, W as cfnRefValueFromPhysicalId, Wt as resolveSkipPrefix, X as assertRegionMatch, Xt as CFN_TEMPLATE_BODY_LIMIT, Y as resolveExplicitPhysicalId, Yt as warnDeprecatedNoPrefixCliFlag, Z as configStringRefusal, Zt as CFN_TEMPLATE_URL_LIMIT, _ as createPreDeleteFinalSnapshot, _n as LocalStartServiceError, _t as stringifyValue, a as DeploymentEventsStore, an as resolveBucketRegion, at as DiffCalculator, b as unsupportedFinalSnapshotError, bn as NestedStackChildDirectDestroyError, bt as createAssetRedirectResolver, c as replayFailedOperations, cn as resetAwsClients, ct as isRetryableTransientError, d as IMPLICIT_DELETE_DEPENDENCIES, dn as CdkdError, dt as TemplateParser, en as uploadCfnTemplate, et as requireConfigArray, f as computeImplicitDeleteEdges, ft as LockManager, g as ccRoutedFinalSnapshotError, gn as LocalMigrateError, gt as AssetPublisher, h as buildFinalSnapshotIdentifier, hn as LocalInvokeBuildError$1, ht as shouldRetainResource, i as DeploymentEventsReader, it as applyRoleArnIfSet, j as red, jn as normalizeAwsError, jt as formatDockerLoginError, k as gray, kt as validateContainerRepoName, l as replayRollback, ln as setAwsClients, lt as isThrottlingError, m as PRE_DELETE_SNAPSHOT_TYPES, mn as DeployCancelledError, mt as rebuildClientForBucketRegion, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as AssemblyReader, nt as requireConfigString, o as planFailedOps, on as AwsClients, ot as describeTypeWithThrottleRetry, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pt as S3StateBackend, q as WAFv2WebACLProvider, qt as resolveUseCdkBootstrapAssets, r as DeployEngine, rn as processStackMessages, rt as derivePartitionAndUrlSuffix, s as planRollback, sn as getAwsClients, st as withRetry, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as expectedOwnerParam, tt as requireConfigObject, u as withResourceDeadline, ut as DagBuilder, v as isFinalSnapshotError, vt as WorkGraph, w as isStatefulRecreateTargetSync, wn as ResourceUpdateNotSupportedError, wt as BOOTSTRAP_MARKER_PREFIX, x as makeCanonicalizePropertiesFn, xn as PartialFailureError, xt as loadPublishableAssetManifest, y as refusesFinalSnapshot, yn as MissingCdkCliError, yt as buildAssetRedirectMap, z as CloudControlProvider, zt as getDefaultStateBucketName } from "./deploy-engine-B2MDP-jK.js";
2
+ import { $ as replayWarn, $t as findLargeInlineResources, A as green, At as buildDockerImage, B as slowCcOperationTimeoutMs, Bt as getLegacyStateBucketName, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as ResourceTimeoutError, Ct as AssetModeResolver, D as bold, Dt as parseBootstrapMarker, E as formatResourceLine, En as StackTerminationProtectionError, Et as getBootstrapMarkerKey, F as clearOnUpdateRemoval, Ft as AssetManifestLoader, G as getAccountInfo, Gt as resolveStateBucketWithDefault, H as isTerminationProtectionPropagationError, Ht as resolveAutoAssetStorage, I as ProviderRegistry, It as getDockerImageBySourceHash, J as normalizeAwsTagsToCfn, Jt as stateBucketExistenceConfirmed, K as refStateLookupFromResource, Kt as resolveStateBucketWithDefaultAndSource, L as findActionableSilentDrops, Lt as Synthesizer, M as yellow, Mn as withErrorHandling, Mt as getDockerCmd, N as IAMRoleProvider, Nt as runDockerForeground, O as cyan, Ot as validateAssetBucketName, P as collectInlinePolicyNamesManagedBySiblings, Pt as runDockerStreaming, Q as readConfigString, Qt as MIGRATE_TMP_PREFIX, R as findSilentDropProperties, Rt as synthesisStatusMessage, S as extractDeploymentEventError, Sn as ProvisioningError, St as rewriteTemplateAssetReferences, T as renderStatefulReason, Tn as StackHasActiveImportsError, Tt as ensureAssetStorage, U as IntrinsicFunctionResolver, Ut as resolveCaptureObservedState, V as disableInstanceApiTermination, Vt as resolveApp, W as cfnRefValueFromPhysicalId, Wt as resolveSkipPrefix, X as assertRegionMatch, Xt as CFN_TEMPLATE_BODY_LIMIT, Y as resolveExplicitPhysicalId, Yt as warnDeprecatedNoPrefixCliFlag, Z as configStringRefusal, Zt as CFN_TEMPLATE_URL_LIMIT, _ as createPreDeleteFinalSnapshot, _n as LocalStartServiceError, _t as stringifyValue, a as DeploymentEventsStore, an as resolveBucketRegion, at as DiffCalculator, b as unsupportedFinalSnapshotError, bn as NestedStackChildDirectDestroyError, bt as createAssetRedirectResolver, c as replayFailedOperations, cn as resetAwsClients, ct as isRetryableTransientError, d as IMPLICIT_DELETE_DEPENDENCIES, dn as CdkdError, dt as TemplateParser, en as uploadCfnTemplate, et as requireConfigArray, f as computeImplicitDeleteEdges, ft as LockManager, g as ccRoutedFinalSnapshotError, gn as LocalMigrateError, gt as AssetPublisher, h as buildFinalSnapshotIdentifier, hn as LocalInvokeBuildError$1, ht as shouldRetainResource, i as DeploymentEventsReader, it as applyRoleArnIfSet, j as red, jn as normalizeAwsError, jt as formatDockerLoginError, k as gray, kt as validateContainerRepoName, l as replayRollback, ln as setAwsClients, lt as isThrottlingError, m as PRE_DELETE_SNAPSHOT_TYPES, mn as DeployCancelledError, mt as rebuildClientForBucketRegion, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as AssemblyReader, nt as requireConfigString, o as planFailedOps, on as AwsClients, ot as describeTypeWithThrottleRetry, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pt as S3StateBackend, q as WAFv2WebACLProvider, qt as resolveUseCdkBootstrapAssets, r as DeployEngine, rn as processStackMessages, rt as derivePartitionAndUrlSuffix, s as planRollback, sn as getAwsClients, st as withRetry, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as expectedOwnerParam, tt as requireConfigObject, u as withResourceDeadline, ut as DagBuilder, v as isFinalSnapshotError, vt as WorkGraph, w as isStatefulRecreateTargetSync, wn as ResourceUpdateNotSupportedError, wt as BOOTSTRAP_MARKER_PREFIX, x as makeCanonicalizePropertiesFn, xn as PartialFailureError, xt as loadPublishableAssetManifest, y as refusesFinalSnapshot, yn as MissingCdkCliError, yt as buildAssetRedirectMap, z as CloudControlProvider, zt as getDefaultStateBucketName } from "./deploy-engine-B6DcyQpS.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-CgQFJdPo.js";
4
+ import { t as ASGProvider } from "./asg-provider-MpqWnvQI.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";
@@ -12194,6 +12194,43 @@ function packCompositeId(resourceType, logicalId, segments, options) {
12194
12194
  else throw new ProvisioningError(refusal, resourceType, logicalId);
12195
12195
  return segments.map((segment) => String(segment.value)).join("|");
12196
12196
  }
12197
+ /** Render the expected id shape, e.g. `<databaseName>|<tableName>`. */
12198
+ function formatShape(segments) {
12199
+ return segments.map((segment) => `<${segment}>`).join("|");
12200
+ }
12201
+ /**
12202
+ * The message EVERY malformed-composite-id decode site emits (issue
12203
+ * [#1657](https://github.com/go-to-k/cdkd/issues/1657)).
12204
+ *
12205
+ * ## Why one builder
12206
+ *
12207
+ * Roughly half the decode sites stated the expected shape and half only echoed
12208
+ * the value back, and the format is documented nowhere else — so on the silent
12209
+ * half the message was the user's only possible route to the answer and it did
12210
+ * not carry it. Routing the sites that already got it right through the same
12211
+ * builder is what stops them drifting back.
12212
+ *
12213
+ * ## This is a WORDING fix, not an acceptance change
12214
+ *
12215
+ * Each caller keeps its own split-and-guard exactly as it was. The arities
12216
+ * genuinely differ (some sites accept AT LEAST N segments, some destructure the
12217
+ * first N and tolerate extras — the #1672 ambiguity, tracked separately), and
12218
+ * folding them into one predicate here would silently change which ids deploy.
12219
+ *
12220
+ * ## The `skipping` variant
12221
+ *
12222
+ * On the DELETE path the established policy is warn-and-continue, so a
12223
+ * malformed record leaves the AWS resource ALIVE while `cdkd destroy` reports
12224
+ * success. That policy is not changed here — but the warning now says what the
12225
+ * skip costs, because an orphan the user is never told about is one they cannot
12226
+ * go and delete.
12227
+ */
12228
+ function compositeIdFormatMessage(format, logicalId, physicalId, options) {
12229
+ const accepted = format.alsoAccepts ? `"${formatShape(format.segments)}" or ${format.alsoAccepts}` : `"${formatShape(format.segments)}"`;
12230
+ const head = `Invalid physicalId format for ${format.label} ${logicalId}: expected ${accepted}, got "${physicalId}"`;
12231
+ if (!options?.skipping) return head;
12232
+ return `${head}. Skipping the delete — the AWS resource is LEFT IN PLACE and cdkd will report this delete as successful, so delete it by hand (or repair the id in state.json and re-run) if it still exists. NOTE this arm is reached from cdkd destroy AND from the deploy engine's replacement / rollback deletes.`;
12233
+ }
12197
12234
 
12198
12235
  //#endregion
12199
12236
  //#region src/provisioning/providers/lambda-event-invoke-config-provider.ts
@@ -14219,13 +14256,17 @@ var DynamoDBGlobalTableProvider = class {
14219
14256
  if (!attributeDefinitions) throw new ProvisioningError(`AttributeDefinitions is required for DynamoDB GlobalTable ${logicalId}`, resourceType, logicalId);
14220
14257
  let billingMode;
14221
14258
  let billingModeSubstituted = false;
14259
+ let billingModeAbsentOnReplay = false;
14222
14260
  try {
14223
14261
  const billingReplayWarn = replayWarn(this.logger, context).onUnusable;
14224
14262
  billingMode = requireConfigString(properties["BillingMode"], "PAY_PER_REQUEST", "AWS::DynamoDB::GlobalTable BillingMode", billingReplayWarn ? { onUnusable: (message) => {
14225
14263
  billingModeSubstituted = true;
14226
14264
  billingReplayWarn(message);
14227
14265
  } } : {});
14228
- if (billingReplayWarn && properties["BillingMode"] === void 0) this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: the state record declares no BillingMode, so this replay creates the table PAY_PER_REQUEST. If it was PROVISIONED, set the mode in the template and redeploy.`);
14266
+ if (billingReplayWarn && properties["BillingMode"] === void 0) {
14267
+ billingModeAbsentOnReplay = true;
14268
+ this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: the state record declares no BillingMode, so this replay creates the table PAY_PER_REQUEST. If it was PROVISIONED, set the mode in the template and redeploy.`);
14269
+ }
14229
14270
  } catch (error) {
14230
14271
  throw new ProvisioningError(error instanceof Error ? error.message : String(error), resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
14231
14272
  }
@@ -14240,10 +14281,11 @@ var DynamoDBGlobalTableProvider = class {
14240
14281
  const diagnostics = [];
14241
14282
  if (billingMode === "PROVISIONED") createParams.ProvisionedThroughput = derivePerCallProvisionedThroughput(properties, currentRegion, "min", diagnostics);
14242
14283
  let effectiveProperties;
14243
- if (billingModeSubstituted) effectiveProperties = {
14284
+ if (billingModeSubstituted) effectiveProperties = stripProvisionedCapacityKeys({
14244
14285
  ...properties,
14245
14286
  BillingMode: billingMode
14246
- };
14287
+ });
14288
+ else if (billingModeAbsentOnReplay) effectiveProperties = stripProvisionedCapacityKeys(properties);
14247
14289
  const streamSpecInput = properties["StreamSpecification"];
14248
14290
  const needsStream = replicas.some((r) => r["Region"] !== currentRegion) || replicas.length > 1;
14249
14291
  if (streamSpecInput != null) {
@@ -14274,12 +14316,28 @@ var DynamoDBGlobalTableProvider = class {
14274
14316
  };
14275
14317
  }
14276
14318
  let sdkIndexes;
14319
+ let indexesOmitted = false;
14277
14320
  try {
14278
14321
  const onUnusableCreateIndexes = replayWarn(this.logger, context).onUnusable;
14279
- sdkIndexes = toSdkGlobalSecondaryIndexes(properties, currentRegion, billingMode, "min", diagnostics, onUnusableCreateIndexes && ((message) => onUnusableCreateIndexes(`${message} Omitting the malformed block, so this create carries NO indexes; the same value is REFUSED on a template-path create`)));
14322
+ sdkIndexes = toSdkGlobalSecondaryIndexes(properties, currentRegion, billingMode, "min", diagnostics, onUnusableCreateIndexes && ((message) => {
14323
+ indexesOmitted = true;
14324
+ onUnusableCreateIndexes(`${message} Omitting the malformed block, so this create carries NO indexes; the same value is REFUSED on a template-path create`);
14325
+ }));
14280
14326
  } catch (error) {
14281
14327
  throw new ProvisioningError(error instanceof Error ? error.message : String(error), resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
14282
14328
  }
14329
+ if (indexesOmitted) {
14330
+ effectiveProperties = { ...effectiveProperties ?? properties };
14331
+ delete effectiveProperties["GlobalSecondaryIndexes"];
14332
+ const replicasForOmit = effectiveProperties["Replicas"];
14333
+ if (Array.isArray(replicasForOmit)) effectiveProperties["Replicas"] = replicasForOmit.map((entry) => {
14334
+ const replica = asRecord$1(entry);
14335
+ if (!replica || replica["Region"] !== currentRegion) return entry;
14336
+ const copy = { ...replica };
14337
+ delete copy["GlobalSecondaryIndexes"];
14338
+ return copy;
14339
+ });
14340
+ }
14283
14341
  if (sdkIndexes.length > 0) createParams.GlobalSecondaryIndexes = sdkIndexes;
14284
14342
  if (properties["LocalSecondaryIndexes"]) createParams.LocalSecondaryIndexes = properties["LocalSecondaryIndexes"];
14285
14343
  if (properties["SSESpecification"]) {
@@ -16425,6 +16483,82 @@ function toSdkGlobalSecondaryIndexes(properties, region, billingMode, source = "
16425
16483
  return result;
16426
16484
  }
16427
16485
  /**
16486
+ * Remove every PROVISIONED-only capacity member from a desired-property bag
16487
+ * (issue #1726).
16488
+ *
16489
+ * Used by `create()`'s `BillingMode` warn-and-SUBSTITUTE arm and by its ABSENT
16490
+ * sibling: whenever the create resolves to `PAY_PER_REQUEST` on a bag that was
16491
+ * not written for it, the same create skips `createParams.ProvisionedThroughput`
16492
+ * and every per-index / per-replica provisioned member is dropped before the
16493
+ * call (each of the reads below is gated on `billingMode === 'PROVISIONED'`).
16494
+ * Recording those keys describes capacity AWS never received.
16495
+ *
16496
+ * The set is the intersection of two questions, and BOTH are needed — taking
16497
+ * either alone is what the review of the first cut corrected:
16498
+ *
16499
+ * - **what could not have been SENT** — every member `toSdkGlobalSecondaryIndexes`
16500
+ * / `toSdkReplicaThroughputOverrides` read behind a PROVISIONED gate, which
16501
+ * includes the two legacy SDK-shaped spellings a pre-#1387 cdkd wrote into
16502
+ * state (`GlobalSecondaryIndexes[].ProvisionedThroughput`,
16503
+ * `Replicas[].ProvisionedThroughputOverride`). A state replay is exactly that
16504
+ * population, so leaving them out made the strip narrower than its own rule.
16505
+ * - **what `readCurrentState` can REPORT under the new mode** — the top-level
16506
+ * `WriteProvisionedThroughputSettings` emits `{}` for an on-demand table and
16507
+ * every other member here is omitted entirely, so a surviving key is a record
16508
+ * the readback can never match.
16509
+ *
16510
+ * DELIBERATELY NOT removed: every `*OnDemand*` member. `OnDemandThroughput` is
16511
+ * attached to `CreateTable` precisely when the mode is not PROVISIONED, so those
16512
+ * WERE sent — a blanket "strip anything throughput-shaped" would record a loss
16513
+ * that did not happen, and a unit row plus an integ phase fence exactly that.
16514
+ *
16515
+ * Pure and non-mutating at every level — the caller's bag is
16516
+ * `previousState.properties` on the replay path and the rollback executor
16517
+ * spreads the answer shallowly, so an in-place edit would corrupt a record the
16518
+ * caller still holds.
16519
+ */
16520
+ function stripProvisionedCapacityKeys(properties) {
16521
+ const result = { ...properties };
16522
+ delete result["WriteProvisionedThroughputSettings"];
16523
+ const indexes = result["GlobalSecondaryIndexes"];
16524
+ if (Array.isArray(indexes)) result["GlobalSecondaryIndexes"] = indexes.map((entry) => {
16525
+ const gsi = asRecord$1(entry);
16526
+ if (!gsi) return entry;
16527
+ const copy = { ...gsi };
16528
+ delete copy["WriteProvisionedThroughputSettings"];
16529
+ delete copy["ReadProvisionedThroughputSettings"];
16530
+ delete copy["ProvisionedThroughput"];
16531
+ return copy;
16532
+ });
16533
+ const replicas = result["Replicas"];
16534
+ if (Array.isArray(replicas)) result["Replicas"] = replicas.map((entry) => {
16535
+ const replica = asRecord$1(entry);
16536
+ if (!replica) return entry;
16537
+ const copy = { ...replica };
16538
+ delete copy["ReadProvisionedThroughputSettings"];
16539
+ delete copy["ProvisionedThroughputOverride"];
16540
+ const replicaIndexes = copy["GlobalSecondaryIndexes"];
16541
+ if (Array.isArray(replicaIndexes)) {
16542
+ const kept = replicaIndexes.map((indexEntry) => {
16543
+ const gsi = asRecord$1(indexEntry);
16544
+ if (!gsi) return indexEntry;
16545
+ const indexCopy = { ...gsi };
16546
+ delete indexCopy["ReadProvisionedThroughputSettings"];
16547
+ delete indexCopy["ProvisionedThroughputOverride"];
16548
+ return indexCopy;
16549
+ }).filter((entry) => {
16550
+ const gsi = asRecord$1(entry);
16551
+ if (!gsi) return true;
16552
+ return Object.keys(gsi).some((k) => k !== "IndexName");
16553
+ });
16554
+ if (kept.length > 0) copy["GlobalSecondaryIndexes"] = kept;
16555
+ else delete copy["GlobalSecondaryIndexes"];
16556
+ }
16557
+ return copy;
16558
+ });
16559
+ return result;
16560
+ }
16561
+ /**
16428
16562
  * True when a CFn sub-object is nothing but an unresolved intrinsic
16429
16563
  * (`{"Fn::If": […]}` / `{"Ref": …}`), i.e. the template DID declare the block
16430
16564
  * but its value could not be resolved to a shape with members.
@@ -19200,6 +19334,32 @@ function canonicalizeIpProtocolValue(value) {
19200
19334
 
19201
19335
  //#endregion
19202
19336
  //#region src/provisioning/providers/ec2-provider.ts
19337
+ /** Shapes of the four `AWS::EC2::*` composite physicalIds (issue #1657). */
19338
+ const EC2_VPC_GATEWAY_ATTACHMENT_ID_FORMAT = {
19339
+ label: "VPCGatewayAttachment",
19340
+ segments: ["internetGatewayId", "vpcId"]
19341
+ };
19342
+ const EC2_ROUTE_ID_FORMAT = {
19343
+ label: "Route",
19344
+ segments: ["routeTableId", "destination"]
19345
+ };
19346
+ const EC2_SG_INGRESS_ID_FORMAT = {
19347
+ label: "SecurityGroupIngress",
19348
+ segments: [
19349
+ "groupId",
19350
+ "ipProtocol",
19351
+ "fromPort",
19352
+ "toPort"
19353
+ ]
19354
+ };
19355
+ const EC2_NETWORK_ACL_ENTRY_ID_FORMAT = {
19356
+ label: "NetworkAclEntry",
19357
+ segments: [
19358
+ "networkAclId",
19359
+ "ruleNumber",
19360
+ "egress"
19361
+ ]
19362
+ };
19203
19363
  /**
19204
19364
  * The `AWS::EC2::Route` destination keys, in CloudFormation's own precedence
19205
19365
  * order — which is also the order `createRoute`'s
@@ -20092,7 +20252,7 @@ var EC2Provider = class {
20092
20252
  async deleteVpcGatewayAttachment(logicalId, physicalId, resourceType, context) {
20093
20253
  this.logger.debug(`Deleting VPCGatewayAttachment ${logicalId}: ${physicalId}`);
20094
20254
  const parts = physicalId.split("|");
20095
- if (parts.length !== 2) throw new ProvisioningError(`Invalid physicalId format for VPCGatewayAttachment ${logicalId}: expected "IGW|VpcId", got "${physicalId}"`, resourceType, logicalId, physicalId);
20255
+ if (parts.length !== 2) throw new ProvisioningError(compositeIdFormatMessage(EC2_VPC_GATEWAY_ATTACHMENT_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
20096
20256
  const [internetGatewayId, vpcId] = parts;
20097
20257
  try {
20098
20258
  await this.withDependencyViolationRetry(() => this.ec2Client.send(new DetachInternetGatewayCommand({
@@ -20285,7 +20445,7 @@ var EC2Provider = class {
20285
20445
  async deleteRoute(logicalId, physicalId, resourceType, context) {
20286
20446
  this.logger.debug(`Deleting Route ${logicalId}: ${physicalId}`);
20287
20447
  const parts = physicalId.split("|");
20288
- if (parts.length !== 2) throw new ProvisioningError(`Invalid physicalId format for Route ${logicalId}: expected "RouteTableId|Destination", got "${physicalId}"`, resourceType, logicalId, physicalId);
20448
+ if (parts.length !== 2) throw new ProvisioningError(compositeIdFormatMessage(EC2_ROUTE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
20289
20449
  const [routeTableId, destination] = parts;
20290
20450
  try {
20291
20451
  const destinationParam = destination?.includes(":") ? { DestinationIpv6CidrBlock: destination } : destination?.startsWith("pl-") ? { DestinationPrefixListId: destination } : { DestinationCidrBlock: destination };
@@ -20629,7 +20789,7 @@ var EC2Provider = class {
20629
20789
  async deleteSecurityGroupIngress(logicalId, physicalId, resourceType, properties, context) {
20630
20790
  this.logger.debug(`Deleting SecurityGroupIngress ${logicalId}: ${physicalId}`);
20631
20791
  const parts = physicalId.split("|");
20632
- if (parts.length !== 4) throw new ProvisioningError(`Invalid physicalId format for SecurityGroupIngress ${logicalId}: expected "GroupId|Protocol|FromPort|ToPort", got "${physicalId}"`, resourceType, logicalId, physicalId);
20792
+ if (parts.length !== 4) throw new ProvisioningError(compositeIdFormatMessage(EC2_SG_INGRESS_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
20633
20793
  const [groupId, ipProtocol, fromPortStr, toPortStr] = parts;
20634
20794
  const ipPermission = properties ? this.buildIpPermission(properties) : {
20635
20795
  IpProtocol: ipProtocol,
@@ -21319,7 +21479,7 @@ var EC2Provider = class {
21319
21479
  this.logger.debug(`Deleting NetworkAclEntry ${logicalId}: ${physicalId}`);
21320
21480
  const parts = physicalId.split("|");
21321
21481
  if (parts.length < 3) {
21322
- this.logger.warn(`Invalid NetworkAclEntry physical ID format: ${physicalId}, skipping`);
21482
+ this.logger.warn(compositeIdFormatMessage(EC2_NETWORK_ACL_ENTRY_ID_FORMAT, logicalId, physicalId, { skipping: true }));
21323
21483
  return;
21324
21484
  }
21325
21485
  const networkAclId = parts[0];
@@ -21629,7 +21789,7 @@ var EC2Provider = class {
21629
21789
  * Skipped (return `undefined`, falls through to the comparator's
21630
21790
  * "unsupported" outcome):
21631
21791
  * - **AWS::EC2::VPCGatewayAttachment**: physical id is
21632
- * `IGW|VpcId`. The two ids are immutable inputs to the SDK call;
21792
+ * `<internetGatewayId>|<vpcId>`. The two ids are immutable inputs to the SDK call;
21633
21793
  * drift detection on this resource has no useful signal beyond
21634
21794
  * existence verification (which the user can do via the parent IGW
21635
21795
  * / VPC drift report).
@@ -22321,6 +22481,15 @@ function isDefaultEgressRule(rule) {
22321
22481
 
22322
22482
  //#endregion
22323
22483
  //#region src/provisioning/providers/apigateway-provider.ts
22484
+ /** Shape of an `AWS::ApiGateway::Method` physicalId (issue #1657). */
22485
+ const APIGW_METHOD_ID_FORMAT = {
22486
+ label: "API Gateway Method",
22487
+ segments: [
22488
+ "restApiId",
22489
+ "resourceId",
22490
+ "httpMethod"
22491
+ ]
22492
+ };
22324
22493
  /**
22325
22494
  * AWS API Gateway Provider
22326
22495
  *
@@ -23306,7 +23475,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
23306
23475
  async updateMethod(logicalId, physicalId, resourceType, properties, previousProperties) {
23307
23476
  this.logger.debug(`Updating API Gateway Method ${logicalId}: ${physicalId}`);
23308
23477
  const parts = physicalId.split("|");
23309
- if (parts.length !== 3) throw new ProvisioningError(`Invalid physicalId format for API Gateway Method ${logicalId}: expected "restApiId|resourceId|httpMethod", got "${physicalId}"`, resourceType, logicalId, physicalId);
23478
+ if (parts.length !== 3) throw new ProvisioningError(compositeIdFormatMessage(APIGW_METHOD_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
23310
23479
  const [restApiId, resourceId, httpMethod] = parts;
23311
23480
  const patchOperations = [];
23312
23481
  for (const { key, path } of [
@@ -23380,7 +23549,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
23380
23549
  async deleteMethod(logicalId, physicalId, resourceType, context) {
23381
23550
  this.logger.debug(`Deleting API Gateway Method ${logicalId}: ${physicalId}`);
23382
23551
  const parts = physicalId.split("|");
23383
- if (parts.length !== 3) throw new ProvisioningError(`Invalid physicalId format for API Gateway Method ${logicalId}: expected "restApiId|resourceId|httpMethod", got "${physicalId}"`, resourceType, logicalId, physicalId);
23552
+ if (parts.length !== 3) throw new ProvisioningError(compositeIdFormatMessage(APIGW_METHOD_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
23384
23553
  const [restApiId, resourceId, httpMethod] = parts;
23385
23554
  try {
23386
23555
  await this.apiGatewayClient.send(new DeleteMethodCommand({
@@ -37181,6 +37350,23 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
37181
37350
 
37182
37351
  //#endregion
37183
37352
  //#region src/provisioning/providers/appsync-provider.ts
37353
+ /** Shapes of the three `AWS::AppSync::*` child composite physicalIds (issue #1657). */
37354
+ const APPSYNC_DATASOURCE_ID_FORMAT = {
37355
+ label: "AppSync DataSource",
37356
+ segments: ["apiId", "name"]
37357
+ };
37358
+ const APPSYNC_RESOLVER_ID_FORMAT = {
37359
+ label: "AppSync Resolver",
37360
+ segments: [
37361
+ "apiId",
37362
+ "typeName",
37363
+ "fieldName"
37364
+ ]
37365
+ };
37366
+ const APPSYNC_APIKEY_ID_FORMAT = {
37367
+ label: "AppSync ApiKey",
37368
+ segments: ["apiId", "apiKeyId"]
37369
+ };
37184
37370
  const MUTABLE_GRAPHQL_API_CONFIG_PROPERTIES = [
37185
37371
  "UserPoolConfig",
37186
37372
  "OpenIDConnectConfig",
@@ -37651,7 +37837,7 @@ var AppSyncProvider = class {
37651
37837
  if (next !== void 0 && prev !== void 0 && next !== prev) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS AppSync DataSource.${field} is immutable — destroy + redeploy to change`);
37652
37838
  }
37653
37839
  const [apiId, name] = physicalId.split("|");
37654
- if (!apiId || !name) throw new ProvisioningError(`Invalid DataSource physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
37840
+ if (!apiId || !name) throw new ProvisioningError(compositeIdFormatMessage(APPSYNC_DATASOURCE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
37655
37841
  const type = properties["Type"] ?? previousProperties["Type"];
37656
37842
  if (![
37657
37843
  "Description",
@@ -37689,7 +37875,7 @@ var AppSyncProvider = class {
37689
37875
  if (next !== void 0 && prev !== void 0 && next !== prev) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS AppSync Resolver.${field} is immutable — destroy + redeploy to change`);
37690
37876
  }
37691
37877
  const parts = physicalId.split("|");
37692
- if (parts.length < 3) throw new ProvisioningError(`Invalid Resolver physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
37878
+ if (parts.length < 3) throw new ProvisioningError(compositeIdFormatMessage(APPSYNC_RESOLVER_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
37693
37879
  const [apiId, typeName, fieldName] = parts;
37694
37880
  if (![
37695
37881
  "DataSourceName",
@@ -37723,7 +37909,7 @@ var AppSyncProvider = class {
37723
37909
  async updateApiKey(logicalId, physicalId, resourceType, properties, previousProperties) {
37724
37910
  if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS AppSync ApiKey.ApiId is immutable — destroy + redeploy to change");
37725
37911
  const [apiId, apiKeyId] = physicalId.split("|");
37726
- if (!apiId || !apiKeyId) throw new ProvisioningError(`Invalid ApiKey physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
37912
+ if (!apiId || !apiKeyId) throw new ProvisioningError(compositeIdFormatMessage(APPSYNC_APIKEY_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
37727
37913
  const newDesc = properties["Description"];
37728
37914
  const oldDesc = previousProperties["Description"];
37729
37915
  const newExp = properties["Expires"];
@@ -38429,7 +38615,7 @@ var AppSyncProvider = class {
38429
38615
  this.logger.debug(`Deleting DataSource ${logicalId}: ${physicalId}`);
38430
38616
  const [apiId, name] = physicalId.split("|");
38431
38617
  if (!apiId || !name) {
38432
- this.logger.warn(`Invalid DataSource physical ID format: ${physicalId}, skipping`);
38618
+ this.logger.warn(compositeIdFormatMessage(APPSYNC_DATASOURCE_ID_FORMAT, logicalId, physicalId, { skipping: true }));
38433
38619
  return;
38434
38620
  }
38435
38621
  try {
@@ -38492,7 +38678,7 @@ var AppSyncProvider = class {
38492
38678
  this.logger.debug(`Deleting Resolver ${logicalId}: ${physicalId}`);
38493
38679
  const parts = physicalId.split("|");
38494
38680
  if (parts.length < 3) {
38495
- this.logger.warn(`Invalid Resolver physical ID format: ${physicalId}, skipping`);
38681
+ this.logger.warn(compositeIdFormatMessage(APPSYNC_RESOLVER_ID_FORMAT, logicalId, physicalId, { skipping: true }));
38496
38682
  return;
38497
38683
  }
38498
38684
  const [apiId, typeName, fieldName] = parts;
@@ -38548,7 +38734,7 @@ var AppSyncProvider = class {
38548
38734
  this.logger.debug(`Deleting ApiKey ${logicalId}: ${physicalId}`);
38549
38735
  const [apiId, apiKeyId] = physicalId.split("|");
38550
38736
  if (!apiId || !apiKeyId) {
38551
- this.logger.warn(`Invalid ApiKey physical ID format: ${physicalId}, skipping`);
38737
+ this.logger.warn(compositeIdFormatMessage(APPSYNC_APIKEY_ID_FORMAT, logicalId, physicalId, { skipping: true }));
38552
38738
  return;
38553
38739
  }
38554
38740
  try {
@@ -38935,6 +39121,11 @@ var AppSyncProvider = class {
38935
39121
 
38936
39122
  //#endregion
38937
39123
  //#region src/provisioning/providers/glue-provider.ts
39124
+ /** Shape of an `AWS::Glue::Table` physicalId, for every decode site (issue #1657). */
39125
+ const GLUE_TABLE_ID_FORMAT = {
39126
+ label: "Glue Table",
39127
+ segments: ["databaseName", "tableName"]
39128
+ };
38938
39129
  /**
38939
39130
  * Read a template-borne value that is about to be forwarded to a Glue read
38940
39131
  * API as a string.
@@ -39232,7 +39423,7 @@ var GlueProvider = class {
39232
39423
  async updateTable(logicalId, physicalId, resourceType, properties, previousProperties) {
39233
39424
  this.logger.debug(`Updating Glue Table ${logicalId}: ${physicalId}`);
39234
39425
  const [databaseName, tableName] = physicalId.split("|");
39235
- if (!databaseName || !tableName) throw new ProvisioningError(`Invalid Glue Table physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
39426
+ if (!databaseName || !tableName) throw new ProvisioningError(compositeIdFormatMessage(GLUE_TABLE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
39236
39427
  const tableInput = properties["TableInput"];
39237
39428
  if (!tableInput) throw new ProvisioningError(`TableInput is required for Glue Table update ${logicalId}`, resourceType, logicalId, physicalId);
39238
39429
  const catalogId = properties["CatalogId"];
@@ -39269,7 +39460,7 @@ var GlueProvider = class {
39269
39460
  this.logger.debug(`Deleting Glue Table ${logicalId}: ${physicalId}`);
39270
39461
  const [databaseName, tableName] = physicalId.split("|");
39271
39462
  if (!databaseName || !tableName) {
39272
- this.logger.warn(`Invalid Glue Table physical ID format: ${physicalId}, skipping`);
39463
+ this.logger.warn(compositeIdFormatMessage(GLUE_TABLE_ID_FORMAT, logicalId, physicalId, { skipping: true }));
39273
39464
  return;
39274
39465
  }
39275
39466
  const target = deleteCatalogId(properties);
@@ -50232,6 +50423,20 @@ var S3DirectoryBucketProvider = class {
50232
50423
 
50233
50424
  //#endregion
50234
50425
  //#region src/provisioning/providers/s3-tables-provider.ts
50426
+ /** Shapes of the two `AWS::S3Tables::*` composite physicalIds (issue #1657). */
50427
+ const S3_TABLES_NAMESPACE_ID_FORMAT = {
50428
+ label: "S3 Tables Namespace",
50429
+ segments: ["tableBucketARN", "namespace"]
50430
+ };
50431
+ const S3_TABLES_TABLE_ID_FORMAT = {
50432
+ label: "S3 Tables Table",
50433
+ segments: [
50434
+ "tableBucketARN",
50435
+ "namespace",
50436
+ "name"
50437
+ ],
50438
+ alsoAccepts: "a table ARN"
50439
+ };
50235
50440
  /**
50236
50441
  * Parse cdkd's composite namespace physicalId `<tableBucketARN>|<namespace>`.
50237
50442
  *
@@ -50478,7 +50683,7 @@ var S3TablesProvider = class {
50478
50683
  async deleteNamespace(logicalId, physicalId, resourceType, context) {
50479
50684
  this.logger.debug(`Deleting S3 Tables Namespace ${logicalId}: ${physicalId}`);
50480
50685
  const [tableBucketARN, namespaceName] = physicalId.split("|");
50481
- if (!tableBucketARN || !namespaceName) throw new ProvisioningError(`Invalid physical ID format for S3 Tables Namespace ${logicalId}: ${physicalId}`, resourceType, logicalId, physicalId);
50686
+ if (!tableBucketARN || !namespaceName) throw new ProvisioningError(compositeIdFormatMessage(S3_TABLES_NAMESPACE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
50482
50687
  try {
50483
50688
  await this.getClient().send(new DeleteNamespaceCommand$1({
50484
50689
  tableBucketARN,
@@ -50892,7 +51097,7 @@ var S3TablesProvider = class {
50892
51097
  this.logger.debug(`S3 Tables Table ${physicalId} does not exist, skipping deletion`);
50893
51098
  return;
50894
51099
  }
50895
- if (resolved === "unparseable") throw new ProvisioningError(`Invalid physical ID format for S3 Tables Table ${logicalId}: ${physicalId} (expected '<tableBucketARN>|<namespace>|<name>' or a table ARN)`, resourceType, logicalId, physicalId);
51100
+ if (resolved === "unparseable") throw new ProvisioningError(compositeIdFormatMessage(S3_TABLES_TABLE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
50896
51101
  const { tableBucketARN, namespace, name } = resolved;
50897
51102
  try {
50898
51103
  await this.getClient().send(new DeleteTableCommand$2({
@@ -51013,7 +51218,7 @@ var S3TablesProvider = class {
51013
51218
  if (removedKeys.length === 0 && Object.keys(upserts).length === 0) return;
51014
51219
  const resolvedParts = await this.resolveTableParts(physicalId);
51015
51220
  if (resolvedParts === "not-found") throw new ProvisioningError(`applyTableTagsDiff: table '${physicalId}' no longer exists (state is out of sync) — refusing to silently drop the tag update`, resourceType, logicalId, physicalId);
51016
- if (resolvedParts === "unparseable") throw new ProvisioningError(`applyTableTagsDiff: cannot derive table ARN from physicalId '${physicalId}' (expected '<bucketArn>|<namespace>|<name>' or a table ARN) — refusing to silently drop the tag update`, resourceType, logicalId, physicalId);
51221
+ if (resolvedParts === "unparseable") throw new ProvisioningError(`applyTableTagsDiff: ${compositeIdFormatMessage(S3_TABLES_TABLE_ID_FORMAT, logicalId, physicalId)}. Cannot derive the table ARN for the tag update, and refusing to silently drop it.`, resourceType, logicalId, physicalId);
51017
51222
  const { tableBucketARN, namespace, name } = resolvedParts;
51018
51223
  const resourceArn = await this.lookupTableArn(tableBucketARN, namespace, name);
51019
51224
  if (!resourceArn) throw new ProvisioningError(`applyTableTagsDiff: GetTable returned no tableARN for ${physicalId} — table is gone or state is out-of-sync. Refusing to silently drop the tag update (run 'cdkd state orphan ${logicalId}' to clean up if the table was deleted out-of-band).`, resourceType, logicalId, physicalId);
@@ -73857,7 +74062,7 @@ function createMigrateCommand() {
73857
74062
  */
73858
74063
  function buildProgram() {
73859
74064
  const program = new Command();
73860
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.15");
74065
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.17");
73861
74066
  program.hook("preAction", (_thisCommand, actionCommand) => {
73862
74067
  const { profile } = actionCommand.optsWithGlobals();
73863
74068
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;