@go-to-k/cdkd 0.278.22 → 0.278.24

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 isThrottlingError, $t as setAwsClients, A as red, At as getLegacyStateBucketName, B as isTerminationProtectionPropagationError, Bt as CFN_TEMPLATE_BODY_LIMIT, C as isStatefulRecreateTargetSync, Ct as runDockerForeground, D as cyan, Dt as Synthesizer, E as bold, Et as getDockerImageBySourceHash, F as ProviderRegistry, Ft as resolveStateBucketWithDefault, G as normalizeAwsTagsToCfn, Gt as expectedOwnerParam, H as cfnRefValueFromPhysicalId, Ht as MIGRATE_TMP_PREFIX, I as findActionableSilentDrops, It as resolveStateBucketWithDefaultAndSource, J as applyRoleArnIfSet, K as resolveExplicitPhysicalId, Kt as AssemblyReader, L as CloudControlProvider, Lt as resolveUseCdkBootstrapAssets, M as IAMRoleProvider, Mt as resolveAutoAssetStorage, N as collectInlinePolicyNamesManagedBySiblings, Nt as resolveCaptureObservedState, O as gray, Ot as synthesisStatusMessage, P as clearOnUpdateRemoval, Pt as resolveSkipPrefix, Q as isRetryableTransientError, Qt as resetAwsClients, R as slowCcOperationTimeoutMs, Rt as stateBucketExistenceConfirmed, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, Sn as withErrorHandling, St as getDockerCmd, T as formatResourceLine, Tt as AssetManifestLoader, U as refStateLookupFromResource, Ut as findLargeInlineResources, V as IntrinsicFunctionResolver, Vt as CFN_TEMPLATE_URL_LIMIT, W as WAFv2WebACLProvider, Wt as uploadCfnTemplate, X as describeTypeWithThrottleRetry, Xt as AwsClients, Y as DiffCalculator, Yt as resolveBucketRegion, Z as withRetry, Zt as getAwsClients, _ as createPreDeleteFinalSnapshot, _t as parseBootstrapMarker, a as DeploymentEventsStore, an as LocalInvokeBuildError$1, at as shouldRetainResource, b as unsupportedFinalSnapshotError, bt as buildDockerImage, c as replayFailedOperations, ct as WorkGraph, d as IMPLICIT_DELETE_DEPENDENCIES, dn as PartialFailureError, dt as loadPublishableAssetManifest, et as DagBuilder, f as computeImplicitDeleteEdges, fn as ProvisioningError, ft as rewriteTemplateAssetReferences, g as ccRoutedFinalSnapshotError, gn as StackTerminationProtectionError, gt as getBootstrapMarkerKey, h as buildFinalSnapshotIdentifier, hn as StackHasActiveImportsError, ht as ensureAssetStorage, i as DeploymentEventsReader, in as DeployCancelledError, it as rebuildClientForBucketRegion, j as yellow, jt as resolveApp, k as green, kt as getDefaultStateBucketName, l as replayRollback, ln as MissingCdkCliError, lt as buildAssetRedirectMap, m as PRE_DELETE_SNAPSHOT_TYPES, mn as ResourceUpdateNotSupportedError, mt as BOOTSTRAP_MARKER_PREFIX, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as LockManager, o as planFailedOps, on as LocalMigrateError, ot as AssetPublisher, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as ResourceTimeoutError, pt as AssetModeResolver, q as assertRegionMatch, qt as processStackMessages, r as DeployEngine, rt as S3StateBackend, s as planRollback, sn as LocalStartServiceError, st as stringifyValue, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as CdkdError, tt as TemplateParser, u as withResourceDeadline, un as NestedStackChildDirectDestroyError, ut as createAssetRedirectResolver, v as isFinalSnapshotError, vt as validateAssetBucketName, w as renderStatefulReason, wt as runDockerStreaming, x as extractDeploymentEventError, xn as normalizeAwsError, xt as formatDockerLoginError, y as refusesFinalSnapshot, yt as validateContainerRepoName, z as disableInstanceApiTermination, zt as warnDeprecatedNoPrefixCliFlag } from "./deploy-engine-CkuG2VD5.js";
2
+ import { $ as isThrottlingError, $t as setAwsClients, A as red, At as getLegacyStateBucketName, B as isTerminationProtectionPropagationError, Bt as CFN_TEMPLATE_BODY_LIMIT, C as isStatefulRecreateTargetSync, Ct as runDockerForeground, D as cyan, Dt as Synthesizer, E as bold, Et as getDockerImageBySourceHash, F as ProviderRegistry, Ft as resolveStateBucketWithDefault, G as normalizeAwsTagsToCfn, Gt as expectedOwnerParam, H as cfnRefValueFromPhysicalId, Ht as MIGRATE_TMP_PREFIX, I as findActionableSilentDrops, It as resolveStateBucketWithDefaultAndSource, J as applyRoleArnIfSet, K as resolveExplicitPhysicalId, Kt as AssemblyReader, L as CloudControlProvider, Lt as resolveUseCdkBootstrapAssets, M as IAMRoleProvider, Mt as resolveAutoAssetStorage, N as collectInlinePolicyNamesManagedBySiblings, Nt as resolveCaptureObservedState, O as gray, Ot as synthesisStatusMessage, P as clearOnUpdateRemoval, Pt as resolveSkipPrefix, Q as isRetryableTransientError, Qt as resetAwsClients, R as slowCcOperationTimeoutMs, Rt as stateBucketExistenceConfirmed, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, Sn as withErrorHandling, St as getDockerCmd, T as formatResourceLine, Tt as AssetManifestLoader, U as refStateLookupFromResource, Ut as findLargeInlineResources, V as IntrinsicFunctionResolver, Vt as CFN_TEMPLATE_URL_LIMIT, W as WAFv2WebACLProvider, Wt as uploadCfnTemplate, X as describeTypeWithThrottleRetry, Xt as AwsClients, Y as DiffCalculator, Yt as resolveBucketRegion, Z as withRetry, Zt as getAwsClients, _ as createPreDeleteFinalSnapshot, _t as parseBootstrapMarker, a as DeploymentEventsStore, an as LocalInvokeBuildError$1, at as shouldRetainResource, b as unsupportedFinalSnapshotError, bt as buildDockerImage, c as replayFailedOperations, ct as WorkGraph, d as IMPLICIT_DELETE_DEPENDENCIES, dn as PartialFailureError, dt as loadPublishableAssetManifest, et as DagBuilder, f as computeImplicitDeleteEdges, fn as ProvisioningError, ft as rewriteTemplateAssetReferences, g as ccRoutedFinalSnapshotError, gn as StackTerminationProtectionError, gt as getBootstrapMarkerKey, h as buildFinalSnapshotIdentifier, hn as StackHasActiveImportsError, ht as ensureAssetStorage, i as DeploymentEventsReader, in as DeployCancelledError, it as rebuildClientForBucketRegion, j as yellow, jt as resolveApp, k as green, kt as getDefaultStateBucketName, l as replayRollback, ln as MissingCdkCliError, lt as buildAssetRedirectMap, m as PRE_DELETE_SNAPSHOT_TYPES, mn as ResourceUpdateNotSupportedError, mt as BOOTSTRAP_MARKER_PREFIX, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as LockManager, o as planFailedOps, on as LocalMigrateError, ot as AssetPublisher, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as ResourceTimeoutError, pt as AssetModeResolver, q as assertRegionMatch, qt as processStackMessages, r as DeployEngine, rt as S3StateBackend, s as planRollback, sn as LocalStartServiceError, st as stringifyValue, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as CdkdError, tt as TemplateParser, u as withResourceDeadline, un as NestedStackChildDirectDestroyError, ut as createAssetRedirectResolver, v as isFinalSnapshotError, vt as validateAssetBucketName, w as renderStatefulReason, wt as runDockerStreaming, x as extractDeploymentEventError, xn as normalizeAwsError, xt as formatDockerLoginError, y as refusesFinalSnapshot, yt as validateContainerRepoName, z as disableInstanceApiTermination, zt as warnDeprecatedNoPrefixCliFlag } from "./deploy-engine-DlLaOrHh.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as withSkipPrefix, i as runStackBuffered, n as getLogger, o as PATTERN_B_NAME_OPTIONS, p as withStackName, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-BYMEE-BS.js";
4
- import { t as ASGProvider } from "./asg-provider-BBsW05cu.js";
4
+ import { t as ASGProvider } from "./asg-provider-cNZXiMc7.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";
@@ -52,7 +52,7 @@ import { AddCustomAttributesCommand, CognitoIdentityProviderClient, CreateUserPo
52
52
  import { CreateHttpNamespaceCommand, CreatePrivateDnsNamespaceCommand, CreatePublicDnsNamespaceCommand, CreateServiceCommand as CreateServiceCommand$1, DeleteNamespaceCommand, DeleteServiceAttributesCommand, DeleteServiceCommand as DeleteServiceCommand$1, GetNamespaceCommand, GetOperationCommand, GetServiceAttributesCommand, GetServiceCommand, ListNamespacesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$14, NamespaceNotFound, ServiceDiscoveryClient, ServiceNotFound, TagResourceCommand as TagResourceCommand$15, UntagResourceCommand as UntagResourceCommand$15, UpdateHttpNamespaceCommand, UpdatePrivateDnsNamespaceCommand, UpdatePublicDnsNamespaceCommand, UpdateServiceAttributesCommand, UpdateServiceCommand as UpdateServiceCommand$1 } from "@aws-sdk/client-servicediscovery";
53
53
  import { AppSyncClient, CreateApiKeyCommand, CreateDataSourceCommand, CreateGraphqlApiCommand, CreateResolverCommand, DeleteApiKeyCommand, DeleteDataSourceCommand, DeleteGraphqlApiCommand, DeleteResolverCommand, GetDataSourceCommand, GetGraphqlApiCommand, GetIntrospectionSchemaCommand, GetResolverCommand, ListApiKeysCommand, NotFoundException as NotFoundException$4, StartSchemaCreationCommand, TagResourceCommand as TagResourceCommand$16, UntagResourceCommand as UntagResourceCommand$16, UpdateApiKeyCommand, UpdateDataSourceCommand, UpdateGraphqlApiCommand, UpdateResolverCommand } from "@aws-sdk/client-appsync";
54
54
  import { parse, print } from "graphql";
55
- import { CrawlerRunningException, CreateConnectionCommand, CreateCrawlerCommand, CreateDatabaseCommand, CreateJobCommand, CreateSecurityConfigurationCommand, CreateTableCommand as CreateTableCommand$1, CreateTriggerCommand, CreateWorkflowCommand, DeleteConnectionCommand, DeleteCrawlerCommand, DeleteDatabaseCommand, DeleteJobCommand, DeleteSecurityConfigurationCommand, DeleteTableCommand as DeleteTableCommand$1, DeleteTriggerCommand, DeleteWorkflowCommand, EntityNotFoundException, GetConnectionCommand, GetCrawlerCommand, GetDatabaseCommand, GetJobCommand, GetSecurityConfigurationCommand, GetTableCommand, GetTagsCommand, GetTriggerCommand, GetWorkflowCommand, GlueClient, StartCrawlerScheduleCommand, StartTriggerCommand, StopCrawlerCommand, StopCrawlerScheduleCommand, StopTriggerCommand, UpdateConnectionCommand, UpdateCrawlerCommand, UpdateDatabaseCommand, UpdateJobCommand, UpdateTableCommand as UpdateTableCommand$1, UpdateTriggerCommand, UpdateWorkflowCommand } from "@aws-sdk/client-glue";
55
+ import { ConcurrentModificationException, CrawlerRunningException, CreateConnectionCommand, CreateCrawlerCommand, CreateDatabaseCommand, CreateJobCommand, CreateSecurityConfigurationCommand, CreateTableCommand as CreateTableCommand$1, CreateTriggerCommand, CreateWorkflowCommand, DeleteConnectionCommand, DeleteCrawlerCommand, DeleteDatabaseCommand, DeleteJobCommand, DeleteSecurityConfigurationCommand, DeleteTableCommand as DeleteTableCommand$1, DeleteTriggerCommand, DeleteWorkflowCommand, EntityNotFoundException, GetConnectionCommand, GetCrawlerCommand, GetDatabaseCommand, GetJobCommand, GetSecurityConfigurationCommand, GetTableCommand, GetTagsCommand, GetTriggerCommand, GetWorkflowCommand, GlueClient, StartCrawlerScheduleCommand, StartTriggerCommand, StopCrawlerCommand, StopCrawlerScheduleCommand, StopTriggerCommand, UpdateConnectionCommand, UpdateCrawlerCommand, UpdateDatabaseCommand, UpdateJobCommand, UpdateTableCommand as UpdateTableCommand$1, UpdateTriggerCommand, UpdateWorkflowCommand } from "@aws-sdk/client-glue";
56
56
  import { BudgetsClient, CreateBudgetCommand, CreateNotificationCommand, CreateSubscriberCommand, DeleteBudgetCommand, DeleteNotificationCommand, DeleteSubscriberCommand, DescribeBudgetCommand, DuplicateRecordException, NotFoundException as NotFoundException$5, TagResourceCommand as TagResourceCommand$17, UntagResourceCommand as UntagResourceCommand$17, UpdateBudgetCommand } from "@aws-sdk/client-budgets";
57
57
  import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPeriodCommand, DeleteStreamCommand, DeregisterStreamConsumerCommand, DescribeStreamCommand, DescribeStreamConsumerCommand, DescribeStreamSummaryCommand, IncreaseStreamRetentionPeriodCommand, KinesisClient, ListTagsForResourceCommand as ListTagsForResourceCommand$15, ListTagsForStreamCommand, RegisterStreamConsumerCommand, RemoveTagsFromStreamCommand, ResourceNotFoundException as ResourceNotFoundException$10, StartStreamEncryptionCommand, StopStreamEncryptionCommand, TagResourceCommand as TagResourceCommand$18, UntagResourceCommand as UntagResourceCommand$18, UpdateShardCountCommand, UpdateStreamModeCommand } from "@aws-sdk/client-kinesis";
58
58
  import { CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ResourceNotFoundException as ResourceNotFoundException$11, SchedulerClient, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
@@ -24885,6 +24885,7 @@ var ECSProvider = class {
24885
24885
  if (!mappings) return void 0;
24886
24886
  return mappings.map((m) => ({
24887
24887
  containerPort: m["ContainerPort"],
24888
+ containerPortRange: m["ContainerPortRange"],
24888
24889
  hostPort: m["HostPort"],
24889
24890
  protocol: m["Protocol"],
24890
24891
  appProtocol: m["AppProtocol"],
@@ -25393,7 +25394,8 @@ var ECSProvider = class {
25393
25394
  targetGroupArn: lb["TargetGroupArn"],
25394
25395
  containerName: lb["ContainerName"],
25395
25396
  containerPort: lb["ContainerPort"],
25396
- loadBalancerName: lb["LoadBalancerName"]
25397
+ loadBalancerName: lb["LoadBalancerName"],
25398
+ advancedConfiguration: lb["AdvancedConfiguration"] ? pascalToCamelCaseKeys(lb["AdvancedConfiguration"]) : void 0
25397
25399
  }));
25398
25400
  }
25399
25401
  /**
@@ -33046,10 +33048,10 @@ var GlueProvider = class {
33046
33048
  default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId);
33047
33049
  }
33048
33050
  }
33049
- async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
33051
+ async update(logicalId, physicalId, resourceType, properties, previousProperties) {
33050
33052
  switch (resourceType) {
33051
- case "AWS::Glue::Database": return this.updateDatabase(logicalId, physicalId, resourceType, properties);
33052
- case "AWS::Glue::Table": return this.updateTable(logicalId, physicalId, resourceType, properties);
33053
+ case "AWS::Glue::Database": return this.updateDatabase(logicalId, physicalId, resourceType, properties, previousProperties);
33054
+ case "AWS::Glue::Table": return this.updateTable(logicalId, physicalId, resourceType, properties, previousProperties);
33053
33055
  default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
33054
33056
  }
33055
33057
  }
@@ -33082,16 +33084,19 @@ var GlueProvider = class {
33082
33084
  throw new ProvisioningError(`Failed to create Glue Database ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
33083
33085
  }
33084
33086
  }
33085
- async updateDatabase(logicalId, physicalId, resourceType, properties) {
33087
+ async updateDatabase(logicalId, physicalId, resourceType, properties, previousProperties) {
33086
33088
  this.logger.debug(`Updating Glue Database ${logicalId}: ${physicalId}`);
33087
33089
  const databaseInput = properties["DatabaseInput"];
33088
33090
  if (!databaseInput) throw new ProvisioningError(`DatabaseInput is required for Glue Database update ${logicalId}`, resourceType, logicalId, physicalId);
33089
33091
  const catalogId = properties["CatalogId"];
33092
+ const liveParameters = await this.readLiveDatabaseParameters(logicalId, resourceType, physicalId, catalogId);
33090
33093
  try {
33094
+ const builtDatabaseInput = this.buildDatabaseInput(databaseInput, physicalId);
33095
+ this.preserveAwsManagedParameters(builtDatabaseInput, databaseInput["Parameters"], (previousProperties?.["DatabaseInput"])?.["Parameters"], liveParameters);
33091
33096
  await this.getClient().send(new UpdateDatabaseCommand({
33092
33097
  ...catalogId !== void 0 && { CatalogId: catalogId },
33093
33098
  Name: physicalId,
33094
- DatabaseInput: this.buildDatabaseInput(databaseInput, physicalId)
33099
+ DatabaseInput: builtDatabaseInput
33095
33100
  }));
33096
33101
  this.logger.debug(`Successfully updated Glue Database ${logicalId}`);
33097
33102
  return {
@@ -33151,7 +33156,7 @@ var GlueProvider = class {
33151
33156
  throw new ProvisioningError(`Failed to create Glue Table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
33152
33157
  }
33153
33158
  }
33154
- async updateTable(logicalId, physicalId, resourceType, properties) {
33159
+ async updateTable(logicalId, physicalId, resourceType, properties, previousProperties) {
33155
33160
  this.logger.debug(`Updating Glue Table ${logicalId}: ${physicalId}`);
33156
33161
  const [databaseName, tableName] = physicalId.split("|");
33157
33162
  if (!databaseName || !tableName) throw new ProvisioningError(`Invalid Glue Table physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
@@ -33160,11 +33165,15 @@ var GlueProvider = class {
33160
33165
  const catalogId = properties["CatalogId"];
33161
33166
  const updateIcebergKey = findIcebergTableInputKey(properties);
33162
33167
  if (updateIcebergKey !== void 0) this.logger.warn(icebergTableInputRefusalMessage(logicalId, updateIcebergKey, "update"));
33168
+ const live = await this.readLiveTableState(logicalId, resourceType, physicalId, databaseName, tableName, catalogId);
33163
33169
  try {
33170
+ const builtTableInput = this.buildTableInput(tableInput, tableName);
33171
+ this.preserveAwsManagedParameters(builtTableInput, tableInput["Parameters"], (previousProperties?.["TableInput"])?.["Parameters"], live.parameters);
33164
33172
  await this.getClient().send(new UpdateTableCommand$1({
33165
- CatalogId: catalogId,
33173
+ ...catalogId !== void 0 && { CatalogId: catalogId },
33166
33174
  DatabaseName: databaseName,
33167
- TableInput: this.buildTableInput(tableInput, tableName)
33175
+ TableInput: builtTableInput,
33176
+ ...live.versionId !== void 0 && { VersionId: live.versionId }
33168
33177
  }));
33169
33178
  this.logger.debug(`Successfully updated Glue Table ${logicalId}`);
33170
33179
  return {
@@ -33173,7 +33182,13 @@ var GlueProvider = class {
33173
33182
  };
33174
33183
  } catch (error) {
33175
33184
  const cause = error instanceof Error ? error : void 0;
33176
- throw new ProvisioningError(`Failed to update Glue Table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
33185
+ let message = `Failed to update Glue Table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`;
33186
+ if (error instanceof ConcurrentModificationException) {
33187
+ message += ". Another writer changed the table between cdkd's pre-update read and its UpdateTable call.";
33188
+ message += live.versionId !== void 0 ? ` cdkd sent the version it read (${live.versionId}) as a precondition and AWS rejected the write, rather than let it put back the AWS-managed Parameters read a moment earlier — which for an Apache Iceberg table would have pinned it to an older metadata_location (an effective snapshot rollback).` : " AWS returned no VersionId on the pre-update read, so cdkd could not attach a precondition; AWS rejected the write on its own.";
33189
+ message += ` Re-run the deploy to pick up the current values.`;
33190
+ }
33191
+ throw new ProvisioningError(message, resourceType, logicalId, physicalId, cause);
33177
33192
  }
33178
33193
  }
33179
33194
  async deleteTable(logicalId, physicalId, resourceType, _properties, context) {
@@ -33200,6 +33215,150 @@ var GlueProvider = class {
33200
33215
  }
33201
33216
  }
33202
33217
  /**
33218
+ * Merge AWS-AUTHORED `Parameters` back into a full-replace update payload
33219
+ * (issue [#1461](https://github.com/go-to-k/cdkd/issues/1461)).
33220
+ *
33221
+ * `UpdateTable` / `UpdateDatabase` replace `TableInput` / `DatabaseInput`
33222
+ * **wholesale**: whatever the payload omits is erased. `Parameters` is a
33223
+ * general-purpose bag that AWS itself writes into, so keys with NO template
33224
+ * representation were wiped by the first unrelated edit. For an Apache
33225
+ * Iceberg table that is not cosmetic — `table_type: ICEBERG` and
33226
+ * `metadata_location` are what make the table readable as Iceberg by
33227
+ * Athena / Spark / EMR, and losing them silently degrades it to a plain
33228
+ * external table pointing at Iceberg data files. Verified live 2026-08-10
33229
+ * in us-east-1: a deploy changing only `TableInput.Description` left
33230
+ * `Table.Parameters` as `null`. The same exposure covers a Glue crawler's
33231
+ * `classification`, `EXTERNAL`, `comment`, and Lake Formation markers.
33232
+ *
33233
+ * The merge is keyed on **"present in NEITHER template side"**, not on
33234
+ * "absent from the desired side" — the latter would make user-authored
33235
+ * parameters unremovable, i.e. the mirror image of the bug:
33236
+ *
33237
+ * | key in desired | key in previous | outcome |
33238
+ * | -------------- | --------------- | ------------------------------------ |
33239
+ * | yes | (either) | the user's value wins |
33240
+ * | no | yes | the USER REMOVED it -> stays removed |
33241
+ * | no | no | AWS-AUTHORED -> preserved from live |
33242
+ *
33243
+ * That keeps this provider on the repo's established clear-on-removal
33244
+ * position (docs/provider-development.md §2a, issue #1155): a removal the
33245
+ * user expressed in the template still reaches AWS. Glue's update APIs are
33246
+ * full-replace, so removal needs no explicit reset sentinel — omitting the
33247
+ * key IS the reset, and the only thing this helper adds back is the set of
33248
+ * keys the user never authored in the first place. The generalized rule for
33249
+ * any full-replace update API lives in docs/provider-development.md §2b.
33250
+ *
33251
+ * Audited siblings that do NOT get this treatment: `JobUpdate`'s
33252
+ * `DefaultArguments` / `NonOverridableArguments`, `ConnectionInput`'s
33253
+ * `ConnectionProperties`, `WorkflowUpdate.DefaultRunProperties` and
33254
+ * `Crawler.Configuration` are purely USER-authored bags — AWS does not
33255
+ * write into them, so merging live values back would only resurrect
33256
+ * console-side additions and break `cdkd drift --revert`.
33257
+ *
33258
+ * `desiredParameters` / `previousParameters` are the raw CFn-side maps
33259
+ * (their KEY SET is all that matters here; `buildTableInput` already
33260
+ * stringified the desired VALUES into `built.Parameters`).
33261
+ */
33262
+ preserveAwsManagedParameters(built, desiredParameters, previousParameters, liveParameters) {
33263
+ if (!liveParameters || Object.keys(liveParameters).length === 0) return;
33264
+ const desiredKeys = parameterKeySet(desiredParameters);
33265
+ const previousKeys = parameterKeySet(previousParameters);
33266
+ const awsAuthored = {};
33267
+ for (const [key, value] of Object.entries(liveParameters)) {
33268
+ if (desiredKeys.has(key) || previousKeys.has(key)) continue;
33269
+ awsAuthored[key] = value;
33270
+ }
33271
+ if (Object.keys(awsAuthored).length === 0) return;
33272
+ built.Parameters = {
33273
+ ...awsAuthored,
33274
+ ...built.Parameters ?? {}
33275
+ };
33276
+ }
33277
+ /**
33278
+ * The live table state {@link preserveAwsManagedParameters} needs: its
33279
+ * current `Parameters` plus the `VersionId` that pins them.
33280
+ *
33281
+ * A missing table returns empty rather than throwing: `UpdateTable` is about
33282
+ * to surface the real, more actionable error. Any OTHER failure is fatal by
33283
+ * design — degrading to "skip the merge" would silently reinstate the very
33284
+ * wipe this read exists to prevent, and the wrapped cause keeps a transient
33285
+ * throttle retryable by the deploy engine's outer `withRetry` (every
33286
+ * `provider.update()` call site wraps it, including both rollback arms since
33287
+ * this issue).
33288
+ *
33289
+ * **Why `VersionId` matters and why it is SCOPED.** Reading `Parameters`
33290
+ * here and writing them back in the next call opens a TOCTOU window: an
33291
+ * Apache Iceberg commit from Spark / Athena / EMR landing in between would
33292
+ * be undone by writing back the `metadata_location` we read, pinning the
33293
+ * table to an older snapshot — silent data-visibility loss, strictly worse
33294
+ * than the bug this read fixes. `UpdateTableRequest.VersionId` is AWS's
33295
+ * optimistic-concurrency token for exactly this
33296
+ * (`ConcurrentModificationException` is a documented `UpdateTable` error),
33297
+ * so the caller sends the version it read and a concurrent commit makes the
33298
+ * update fail loudly instead of silently rolling back.
33299
+ *
33300
+ * It is sent UNCONDITIONALLY whenever this read returned a version, and the
33301
+ * earlier attempt to scope it to "only when the merge wrote back live
33302
+ * values" was wrong on both counts. Wrong on SAFETY: the merge also reports
33303
+ * nothing-written-back when the live read came back EMPTY, and that update
33304
+ * still ships a wholesale `TableInput` replace — so a commit landing in the
33305
+ * window would have been wiped with no guard at all, i.e. #1461 surviving
33306
+ * its own fix. Wrong on its PREMISE: this read runs milliseconds before the
33307
+ * send on every update, so a pure template push (`cdkd drift --revert`, the
33308
+ * case the scoping was meant to protect) carries a FRESH version too. An
33309
+ * unconditional guard therefore cannot fire spuriously — it fires only when
33310
+ * somebody else genuinely wrote in between, which is exactly when a revert
33311
+ * should stop and be re-run against current values rather than clobber a
33312
+ * change it never saw.
33313
+ *
33314
+ * The precondition's real-AWS semantics are pinned by the `data-analytics`
33315
+ * integ, which advances a table's version out of band and asserts cdkd's
33316
+ * update is REFUSED — without that, "AWS silently ignores a stale VersionId"
33317
+ * would make this guard a placebo.
33318
+ */
33319
+ async readLiveTableState(logicalId, resourceType, physicalId, databaseName, tableName, catalogId) {
33320
+ try {
33321
+ const resp = await this.getClient().send(new GetTableCommand({
33322
+ ...catalogId !== void 0 && { CatalogId: catalogId },
33323
+ DatabaseName: databaseName,
33324
+ Name: tableName
33325
+ }));
33326
+ return {
33327
+ parameters: resp.Table?.Parameters,
33328
+ versionId: resp.Table?.VersionId
33329
+ };
33330
+ } catch (error) {
33331
+ if (error instanceof EntityNotFoundException) return {
33332
+ parameters: void 0,
33333
+ versionId: void 0
33334
+ };
33335
+ throw new ProvisioningError(preUpdateReadFailureMessage("Table", "glue:GetTable", logicalId, error), resourceType, logicalId, physicalId, error instanceof Error ? error : void 0);
33336
+ }
33337
+ }
33338
+ /**
33339
+ * `Database.Parameters` as AWS currently holds them, for
33340
+ * {@link preserveAwsManagedParameters}. Same not-found / fail-closed
33341
+ * contract as {@link readLiveTableState}.
33342
+ *
33343
+ * There is NO `VersionId` analogue here: `UpdateDatabaseRequest` has no such
33344
+ * member (verified against `@aws-sdk/client-glue`), so the database merge
33345
+ * carries the TOCTOU exposure the table merge closes. It is far narrower in
33346
+ * practice — nothing commits to a Glue DATABASE out of band the way an
33347
+ * Iceberg engine commits to a table — but it is real, and is written up in
33348
+ * docs/supported-resources.md rather than left implicit.
33349
+ */
33350
+ async readLiveDatabaseParameters(logicalId, resourceType, physicalId, catalogId) {
33351
+ try {
33352
+ return (await this.getClient().send(new GetDatabaseCommand({
33353
+ ...catalogId !== void 0 && { CatalogId: catalogId },
33354
+ Name: physicalId
33355
+ }))).Database?.Parameters;
33356
+ } catch (error) {
33357
+ if (error instanceof EntityNotFoundException) return void 0;
33358
+ throw new ProvisioningError(preUpdateReadFailureMessage("Database", "glue:GetDatabase", logicalId, error), resourceType, logicalId, physicalId, error instanceof Error ? error : void 0);
33359
+ }
33360
+ }
33361
+ /**
33203
33362
  * Build DatabaseInput for Glue API from CFn template properties.
33204
33363
  *
33205
33364
  * Used by both `createDatabase` and `updateDatabase` so the same
@@ -33213,7 +33372,7 @@ var GlueProvider = class {
33213
33372
  const result = { Name: databaseInput["Name"] ?? fallbackName };
33214
33373
  if (databaseInput["Description"] !== void 0) result.Description = databaseInput["Description"];
33215
33374
  if (databaseInput["LocationUri"] !== void 0) result.LocationUri = databaseInput["LocationUri"];
33216
- if (databaseInput["Parameters"] !== void 0) result.Parameters = databaseInput["Parameters"];
33375
+ if (databaseInput["Parameters"] !== void 0) result.Parameters = stringifyParameterValues(databaseInput["Parameters"]);
33217
33376
  return result;
33218
33377
  }
33219
33378
  /**
@@ -33223,12 +33382,7 @@ var GlueProvider = class {
33223
33382
  const result = { Name: tableInput["Name"] ?? fallbackName };
33224
33383
  if (tableInput["Description"] !== void 0) result.Description = tableInput["Description"];
33225
33384
  if (tableInput["TableType"] !== void 0) result.TableType = tableInput["TableType"];
33226
- if (tableInput["Parameters"] !== void 0) {
33227
- const rawParams = tableInput["Parameters"];
33228
- const params = {};
33229
- for (const [k, v] of Object.entries(rawParams)) params[k] = String(v);
33230
- result.Parameters = params;
33231
- }
33385
+ if (tableInput["Parameters"] !== void 0) result.Parameters = stringifyParameterValues(tableInput["Parameters"]);
33232
33386
  if (tableInput["Owner"] !== void 0) result.Owner = tableInput["Owner"];
33233
33387
  if (tableInput["Retention"] !== void 0) result.Retention = tableInput["Retention"];
33234
33388
  if (tableInput["ViewOriginalText"] !== void 0) result.ViewOriginalText = tableInput["ViewOriginalText"];
@@ -33300,10 +33454,11 @@ var GlueProvider = class {
33300
33454
  * the provider's `create()` only handles Database/Table; CC API picks
33301
33455
  * up drift detection for the rest.
33302
33456
  */
33303
- async readCurrentState(physicalId, _logicalId, resourceType) {
33457
+ async readCurrentState(physicalId, _logicalId, resourceType, properties) {
33458
+ const catalogId = properties?.["CatalogId"];
33304
33459
  switch (resourceType) {
33305
- case "AWS::Glue::Database": return this.readDatabase(physicalId);
33306
- case "AWS::Glue::Table": return this.readTable(physicalId);
33460
+ case "AWS::Glue::Database": return this.readDatabase(physicalId, catalogId);
33461
+ case "AWS::Glue::Table": return this.readTable(physicalId, catalogId);
33307
33462
  default: return;
33308
33463
  }
33309
33464
  }
@@ -33321,10 +33476,13 @@ var GlueProvider = class {
33321
33476
  if (resourceType === "AWS::Glue::Table") return ["OpenTableFormatInput"];
33322
33477
  return [];
33323
33478
  }
33324
- async readDatabase(physicalId) {
33479
+ async readDatabase(physicalId, catalogId) {
33325
33480
  let db;
33326
33481
  try {
33327
- db = (await this.getClient().send(new GetDatabaseCommand({ Name: physicalId }))).Database;
33482
+ db = (await this.getClient().send(new GetDatabaseCommand({
33483
+ ...catalogId !== void 0 && { CatalogId: catalogId },
33484
+ Name: physicalId
33485
+ }))).Database;
33328
33486
  } catch (err) {
33329
33487
  if (err instanceof EntityNotFoundException) return void 0;
33330
33488
  throw err;
@@ -33339,12 +33497,13 @@ var GlueProvider = class {
33339
33497
  if (db.Name !== void 0) result["DatabaseName"] = db.Name;
33340
33498
  return result;
33341
33499
  }
33342
- async readTable(physicalId) {
33500
+ async readTable(physicalId, catalogId) {
33343
33501
  const [databaseName, tableName] = physicalId.split("|");
33344
33502
  if (!databaseName || !tableName) return void 0;
33345
33503
  let table;
33346
33504
  try {
33347
33505
  table = (await this.getClient().send(new GetTableCommand({
33506
+ ...catalogId !== void 0 && { CatalogId: catalogId },
33348
33507
  DatabaseName: databaseName,
33349
33508
  Name: tableName
33350
33509
  }))).Table;
@@ -34161,6 +34320,35 @@ function buildJobCommonFields(p) {
34161
34320
  return r;
34162
34321
  }
34163
34322
  /**
34323
+ * CFn `Parameters` map -> the SDK's `Record<string, string>`. CDK may deliver
34324
+ * booleans / numbers; the SDK member is string-valued.
34325
+ */
34326
+ function stringifyParameterValues(raw) {
34327
+ const params = {};
34328
+ for (const [k, v] of Object.entries(raw ?? {})) params[k] = String(v);
34329
+ return params;
34330
+ }
34331
+ /**
34332
+ * Key set of a CFn-side `Parameters` map, for
34333
+ * {@link GlueProvider.preserveAwsManagedParameters}.
34334
+ *
34335
+ * A non-object (absent, or an unresolved intrinsic) contributes NO keys — so
34336
+ * a template that declares no `Parameters` at all can never be mistaken for
34337
+ * one that removed a key, and every live key stays preserved.
34338
+ */
34339
+ function parameterKeySet(value) {
34340
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return /* @__PURE__ */ new Set();
34341
+ return new Set(Object.keys(value));
34342
+ }
34343
+ /**
34344
+ * Message for a failed pre-update `Get*` read (issue #1461). Names the IAM
34345
+ * action so a permission gap is one line away from fixed, and says what the
34346
+ * read is FOR so the failure does not read as gratuitous.
34347
+ */
34348
+ function preUpdateReadFailureMessage(kind, iamAction, logicalId, error) {
34349
+ return `Failed to read the current Glue ${kind} ${logicalId} before update: ${error instanceof Error ? error.message : String(error)}. cdkd reads the live ${kind.toLowerCase()} so AWS-managed Parameters (Apache Iceberg's table_type / metadata_location, a crawler's classification, Lake Formation markers) survive an update that Glue applies as a full replace. Grant ${iamAction} to the deploy identity — proceeding without the read would silently erase them.`;
34350
+ }
34351
+ /**
34164
34352
  * Coerce a CFn-delivered numeric property (often a string like `"10"`) to a
34165
34353
  * JS number at the SDK wire boundary. Non-finite / unparseable inputs are
34166
34354
  * returned unchanged so AWS surfaces a clear validation error rather than
@@ -65598,7 +65786,7 @@ function createMigrateCommand() {
65598
65786
  */
65599
65787
  function buildProgram() {
65600
65788
  const program = new Command();
65601
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.22");
65789
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.24");
65602
65790
  program.hook("preAction", (_thisCommand, actionCommand) => {
65603
65791
  const { profile } = actionCommand.optsWithGlobals();
65604
65792
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;