@go-to-k/cdkd 0.286.1 → 0.286.2

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.
@@ -1,6 +1,6 @@
1
1
  import { _ as withStackName, d as applyDefaultNameForFallback, f as generateResourceName, h as looksLikeCdkdGeneratedName, m as getCurrentStackName, n as getLogger, p as generateResourceNameWithFallback, r as isStdoutReservedForPayload, s as getLiveRenderer } from "./logger-Dw-3y48G.js";
2
2
  import { t as awsClientDefaults } from "./aws-client-defaults-D-iYiIJ6.js";
3
- import { t as getCdkdVersion } from "./version-CnQK6Jeh.js";
3
+ import { t as getCdkdVersion } from "./version-Crg_SdRh.js";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { randomUUID } from "node:crypto";
6
6
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -836,6 +836,116 @@ function isNameCooldownError(message) {
836
836
  function isRecreateRetryableError(message) {
837
837
  return isNameCollisionError(message) || isNameCooldownError(message);
838
838
  }
839
+ /**
840
+ * The Cloud Control exception NAME for "this resource type ships no handler
841
+ * for the action you asked for" (issue
842
+ * [#2520](https://github.com/go-to-k/cdkd/issues/2520)).
843
+ *
844
+ * A NAME, not a message fragment: AWS SDK v3 sets `error.name` to the service
845
+ * exception's own identifier, which is a wire-level contract, while the prose
846
+ * beside it is text AWS is free to reword. The sibling READ classifier in
847
+ * `src/cli/commands/drift.ts` (`NO_READ_HANDLER_NAMES`) already keys on this
848
+ * same name for the GET direction.
849
+ */
850
+ const CC_UNSUPPORTED_ACTION_ERROR_NAME = "UnsupportedActionException";
851
+ /**
852
+ * The AWS prose the update-not-supported classifier accepted before the
853
+ * structured signal existed. Kept as a TOP-LEVEL-only fallback — see
854
+ * {@link isUpdateUnsupportedError} for why it is not walked down the chain.
855
+ */
856
+ const CC_UPDATE_UNSUPPORTED_MESSAGE_FALLBACK = "does not support UPDATE";
857
+ /**
858
+ * True when a failed `provider.update()` for `logicalId` was rejected because
859
+ * the resource type has no UPDATE handler at all — the signal the deploy
860
+ * engine's update-failure fallback fires on, turning the update into a
861
+ * replacement.
862
+ *
863
+ * ## Why the chain is walked
864
+ *
865
+ * `CloudControlProvider.handleError` WRAPS the raw AWS rejection in a
866
+ * `ProvisioningError` and interpolates `err.message` only; the exception name
867
+ * is never copied into the wrapper's text. Measured 2026-09-04: `aws
868
+ * cloudcontrol update-resource --type-name AWS::DocDB::DBCluster` answers
869
+ * `UnsupportedActionException` with the message `Resource type
870
+ * AWS::DocDB::DBCluster does not support UPDATE action`, which does not repeat
871
+ * the name. That is why the predicate's pre-#2520
872
+ * `message.includes('UnsupportedActionException')` half matched nothing cdkd
873
+ * produces, and why the structured read has to look one link down.
874
+ *
875
+ * Two structured signals, both read off a link rather than out of prose:
876
+ *
877
+ * - `name` — the synchronous `UpdateResource` rejection, one cause link below
878
+ * the provider's wrapper.
879
+ * - `ccErrorCode` PLUS `ccOperation === 'UPDATE'` — the two fields
880
+ * `CloudControlOperationFailedError` carries for an asynchronous
881
+ * progress-event failure, read structurally exactly as
882
+ * `cloud-control-provider.ts` reads the code for `AlreadyExists` /
883
+ * `NotFound`. No async occurrence has been MEASURED
884
+ * (`UnsupportedActionException` is raised synchronously by `UpdateResource`
885
+ * today); the arm exists so the async shape cannot silently fall through to
886
+ * prose, and it is pinned by unit cases built from the real error class.
887
+ * `ccOperation` is required rather than decorative precisely BECAUSE the
888
+ * arm is unmeasured: a CREATE or DELETE sub-operation reporting the same
889
+ * code says nothing about whether the type has an UPDATE handler, and
890
+ * reading the code alone would let it trigger a DELETE + CREATE. The
891
+ * narrowing is not absolute and the gap is stated rather than papered over:
892
+ * such a failure arriving at the TOP level still classifies if its own
893
+ * MESSAGE quotes AWS's prose. Unreachable today —
894
+ * `CloudControlOperationFailedError`'s message is built as
895
+ * `${operation} failed for <id>: <StatusMessage>`, so a CREATE's text
896
+ * cannot contain the UPDATE phrase unless AWS puts it there — and closing
897
+ * it would mean anchoring the prose read on the operation too, which would
898
+ * narrow the retained pre-#2520 reach rather than preserve it.
899
+ *
900
+ * ## Why the walk stops at another resource's error
901
+ *
902
+ * `logicalId` is not decoration — it is the fence that keeps a chain walk from
903
+ * being WIDER than the message read it replaces. `NestedStackProvider.update`
904
+ * runs a whole child deploy inside the PARENT's `provider.update()` call, so a
905
+ * child resource's Cloud Control rejection propagates into the parent's update
906
+ * catch, several cause links down. An unanchored walk would classify that as
907
+ * "the nested stack cannot be updated in place" and DELETE + CREATE the entire
908
+ * child stack. The pre-#2520 message read was immune by accident — the child
909
+ * engine's wrapper is `Failed to update resource <child>`, which quotes no AWS
910
+ * text — and this anchor makes the immunity deliberate: `ProvisioningError`
911
+ * and `ResourceUpdateNotSupportedError` both carry `logicalId`, so the walk
912
+ * stops dead at the first link that names a resource other than the one being
913
+ * updated.
914
+ *
915
+ * The prose fallback is read at the TOP LEVEL ONLY, exactly as the pre-#2520
916
+ * predicate did, and for the same asymmetry: missing the signal fails the
917
+ * deploy (safe), matching it too broadly replaces a resource nobody asked to
918
+ * replace (unsafe). It is read INSIDE the walk, after the anchor, so the
919
+ * anchor governs every route into a `true` — ordered ahead of it, the
920
+ * nested-stack immunity would rest on the child engine's wrapper happening to
921
+ * quote no AWS text, which is a property of another file.
922
+ *
923
+ * ## Codes deliberately NOT matched
924
+ *
925
+ * The Cloud Control handler error code `NotUpdatable` reports "this particular
926
+ * patch is not applicable" (a create-only property, an invalid document)
927
+ * rather than "the type has no UPDATE handler", and cdkd already routes the
928
+ * create-only case through its own property-driven replacement — accepting it
929
+ * here would convert ordinary update rejections into replacements.
930
+ * `TypeNotFoundException`, which `handleError` wraps into the SAME sentence as
931
+ * the unsupported-action case, is not matched either: an unregistered type has
932
+ * no replacement story, so it must keep failing the deploy rather than
933
+ * deleting the resource.
934
+ */
935
+ function isUpdateUnsupportedError(error, logicalId) {
936
+ let current = error;
937
+ for (let depth = 0; current !== null && current !== void 0 && depth < MAX_CAUSE_CHAIN_DEPTH; depth++) {
938
+ const link = current;
939
+ if (typeof link.logicalId === "string" && link.logicalId !== logicalId) return false;
940
+ if (link.name === "UnsupportedActionException") return true;
941
+ if (link.ccErrorCode === "UnsupportedActionException" && link.ccOperation === "UPDATE") return true;
942
+ if (depth === 0) {
943
+ if ((current instanceof Error ? current.message : String(current)).includes("does not support UPDATE")) return true;
944
+ }
945
+ current = link.cause;
946
+ }
947
+ return false;
948
+ }
839
949
 
840
950
  //#endregion
841
951
  //#region src/utils/error-handler.ts
@@ -21642,7 +21752,8 @@ function ccProtectionProperty(resourceType) {
21642
21752
  const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21643
21753
  "Alexa::ASK::Skill",
21644
21754
  "AWS::AmazonMQ::ConfigurationAssociation",
21645
- "AWS::ApiGatewayV2::ApiGatewayManagedOverrides",
21755
+ "AWS::Amplify::Jobs",
21756
+ "AWS::AmplifyUIBuilder::CodegenJob",
21646
21757
  "AWS::AppMesh::GatewayRoute",
21647
21758
  "AWS::AppMesh::Mesh",
21648
21759
  "AWS::AppMesh::Route",
@@ -21651,64 +21762,90 @@ const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21651
21762
  "AWS::AppMesh::VirtualRouter",
21652
21763
  "AWS::AppMesh::VirtualService",
21653
21764
  "AWS::AppStream::Fleet",
21765
+ "AWS::AppStream::StackFleetAssociation",
21654
21766
  "AWS::AppSync::ApiCache",
21655
21767
  "AWS::Artifact::Report",
21656
21768
  "AWS::Athena::Session",
21657
21769
  "AWS::AutoScalingPlans::ScalingPlan",
21658
21770
  "AWS::BackupSearch::SearchJob",
21771
+ "AWS::BackupSearch::SearchResultExportJob",
21659
21772
  "AWS::BCMDataExports::Table",
21773
+ "AWS::Bedrock::AsyncInvoke",
21660
21774
  "AWS::Bedrock::DefaultPromptRouter",
21775
+ "AWS::Bedrock::FlowExecution",
21776
+ "AWS::Bedrock::FoundationModel",
21777
+ "AWS::Bedrock::ImportedModel",
21778
+ "AWS::Bedrock::ModelImportJob",
21661
21779
  "AWS::Bedrock::ModelInvocationJob",
21780
+ "AWS::BedrockAgentCore::ConfigurationBundleVersion",
21781
+ "AWS::BedrockAgentCore::HarnessVersion",
21782
+ "AWS::BedrockAgentCore::PolicyGeneration",
21662
21783
  "AWS::BedrockAgentCore::TokenVault",
21784
+ "AWS::Braket::Job",
21785
+ "AWS::Cassandra::Stream",
21663
21786
  "AWS::Cloud9::EnvironmentEC2",
21664
21787
  "AWS::CloudFormation::Macro",
21665
21788
  "AWS::CloudFormation::ResourceScan",
21666
21789
  "AWS::CloudFormation::WaitCondition",
21667
21790
  "AWS::CloudFront::StreamingDistribution",
21668
21791
  "AWS::CodeArtifact::Package",
21669
- "AWS::CodeBuild::ReportGroup",
21792
+ "AWS::CodeBuild::Build",
21793
+ "AWS::CodeBuild::BuildBatch",
21670
21794
  "AWS::CodeBuild::Sandbox",
21671
- "AWS::CodeBuild::SourceCredential",
21672
21795
  "AWS::CodeStar::GitHubRepository",
21673
21796
  "AWS::CognitoSync::Dataset",
21797
+ "AWS::Comprehend::DocumentClassificationJob",
21798
+ "AWS::Comprehend::DominantLanguageDetectionJob",
21799
+ "AWS::Comprehend::EntitiesDetectionJob",
21800
+ "AWS::Comprehend::FlywheelDataset",
21801
+ "AWS::Comprehend::SentimentDetectionJob",
21802
+ "AWS::Comprehend::TargetedSentimentDetectionJob",
21674
21803
  "AWS::Config::ConfigurationRecorder",
21675
21804
  "AWS::Config::DeliveryChannel",
21676
21805
  "AWS::Config::OrganizationConfigRule",
21806
+ "AWS::ControlCatalog::CommonControl",
21807
+ "AWS::ControlCatalog::Control",
21677
21808
  "AWS::ControlCatalog::Objective",
21809
+ "AWS::DataExchange::Assets",
21810
+ "AWS::DataExchange::EntitledDataSets",
21811
+ "AWS::DataExchange::Job",
21812
+ "AWS::DataSync::TaskExecution",
21678
21813
  "AWS::DAX::Cluster",
21679
- "AWS::DAX::ParameterGroup",
21680
21814
  "AWS::DAX::SubnetGroup",
21815
+ "AWS::Deadline::Job",
21681
21816
  "AWS::DirectoryService::MicrosoftAD",
21682
- "AWS::DMS::EventSubscription",
21683
21817
  "AWS::DMS::ReplicationInstance",
21684
- "AWS::DMS::ReplicationSubnetGroup",
21685
- "AWS::DMS::ReplicationTask",
21686
- "AWS::DocDB::DBClusterParameterGroup",
21818
+ "AWS::DRS::RecoveryInstance",
21687
21819
  "AWS::DynamoDB::Export",
21820
+ "AWS::DynamoDB::Stream",
21688
21821
  "AWS::EC2::ClientVpnAuthorizationRule",
21689
21822
  "AWS::EC2::ClientVpnEndpoint",
21690
21823
  "AWS::EC2::ClientVpnRoute",
21691
21824
  "AWS::EC2::ClientVpnTargetNetworkAssociation",
21825
+ "AWS::EC2::ExportInstanceTask",
21692
21826
  "AWS::EC2::NetworkInterfacePermission",
21827
+ "AWS::EC2::ReplaceRootVolumeTask",
21828
+ "AWS::EC2::VpnConnectionDeviceType",
21693
21829
  "AWS::EC2::VPNGatewayRoutePropagation",
21830
+ "AWS::ECRPublic::Registry",
21831
+ "AWS::ECS::ContainerInstance",
21832
+ "AWS::ECS::Task",
21694
21833
  "AWS::ElastiCache::ReservedCacheNode",
21695
21834
  "AWS::ElastiCache::SecurityGroup",
21696
21835
  "AWS::ElastiCache::SecurityGroupIngress",
21697
21836
  "AWS::ElasticLoadBalancingV2::ListenerCertificate",
21698
21837
  "AWS::Elasticsearch::Domain",
21699
21838
  "AWS::EMR::NotebookExecution",
21839
+ "AWS::EMRContainers::JobRun",
21840
+ "AWS::EMRServerless::JobRun",
21700
21841
  "AWS::Events::Replay",
21842
+ "AWS::FIS::Experiment",
21701
21843
  "AWS::FIS::SafetyLever",
21702
21844
  "AWS::FSx::Snapshot",
21703
21845
  "AWS::FSx::StorageVirtualMachine",
21704
- "AWS::FSx::Volume",
21705
- "AWS::Glue::Classifier",
21706
- "AWS::Glue::CustomEntityType",
21707
- "AWS::Glue::DataQualityRuleset",
21708
21846
  "AWS::Glue::DevEndpoint",
21709
- "AWS::Glue::MLTransform",
21710
21847
  "AWS::Glue::Partition",
21711
- "AWS::Glue::TableOptimizer",
21848
+ "AWS::Glue::TableVersion",
21712
21849
  "AWS::Greengrass::ConnectorDefinition",
21713
21850
  "AWS::Greengrass::ConnectorDefinitionVersion",
21714
21851
  "AWS::Greengrass::CoreDefinition",
@@ -21730,11 +21867,18 @@ const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21730
21867
  "AWS::IdentityStore::AllGroupMemberships",
21731
21868
  "AWS::ImageBuilder::AllImageBuildVersions",
21732
21869
  "AWS::ImageBuilder::AllWorkflowBuildVersions",
21870
+ "AWS::ImageBuilder::LifecycleExecution",
21733
21871
  "AWS::ImageBuilder::WorkflowExecution",
21734
21872
  "AWS::ImageBuilder::WorkflowStepExecution",
21873
+ "AWS::InternetMonitor::InternetEvent",
21874
+ "AWS::IoT::Index",
21735
21875
  "AWS::IoT::PolicyPrincipalAttachment",
21736
21876
  "AWS::IoT::ThingPrincipalAttachment",
21877
+ "AWS::IoTDeviceAdvisor::SuiteRun",
21737
21878
  "AWS::IoTThingsGraph::FlowTemplate",
21879
+ "AWS::IoTTwinMaker::MetadataTransferJob",
21880
+ "AWS::IVS::Composition",
21881
+ "AWS::KafkaConnect::ConnectorOperation",
21738
21882
  "AWS::KinesisAnalytics::Application",
21739
21883
  "AWS::KinesisAnalytics::ApplicationOutput",
21740
21884
  "AWS::KinesisAnalytics::ApplicationReferenceDataSource",
@@ -21744,22 +21888,32 @@ const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21744
21888
  "AWS::LakeFormation::DataLakeSettings",
21745
21889
  "AWS::LakeFormation::Permissions",
21746
21890
  "AWS::LakeFormation::Resource",
21891
+ "AWS::Lambda::DurableExecution",
21892
+ "AWS::Lightsail::ExportSnapshotRecord",
21893
+ "AWS::Location::Job",
21894
+ "AWS::Macie2::ClassificationJob",
21747
21895
  "AWS::ManagedBlockchain::Member",
21748
21896
  "AWS::ManagedBlockchain::Node",
21749
21897
  "AWS::MediaConnect::Offering",
21750
21898
  "AWS::MediaConnect::Reservation",
21751
21899
  "AWS::MediaConvert::JobTemplate",
21752
- "AWS::MediaConvert::Preset",
21753
21900
  "AWS::MediaConvert::Queue",
21754
21901
  "AWS::MediaLive::Channel",
21755
21902
  "AWS::MediaLive::Input",
21756
21903
  "AWS::MediaLive::InputSecurityGroup",
21757
21904
  "AWS::MediaLive::Offering",
21758
21905
  "AWS::MediaPackage::HarvestJob",
21906
+ "AWS::MediaPackageV2::HarvestJob",
21759
21907
  "AWS::MediaStore::Container",
21908
+ "AWS::MedicalImaging::ImageSet",
21760
21909
  "AWS::MemoryDB::MultiRegionParameterGroup",
21761
21910
  "AWS::MemoryDB::ReservedNode",
21911
+ "AWS::NeptuneGraph::ExportTask",
21912
+ "AWS::NovaAct::WorkflowRun",
21913
+ "AWS::Omics::ReadSet",
21762
21914
  "AWS::Omics::Reference",
21915
+ "AWS::Omics::Run",
21916
+ "AWS::Omics::Task",
21763
21917
  "AWS::OpsWorks::App",
21764
21918
  "AWS::OpsWorks::ElasticLoadBalancerAttachment",
21765
21919
  "AWS::OpsWorks::Instance",
@@ -21767,8 +21921,14 @@ const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21767
21921
  "AWS::OpsWorks::Stack",
21768
21922
  "AWS::OpsWorks::UserProfile",
21769
21923
  "AWS::OpsWorks::Volume",
21924
+ "AWS::Organizations::Root",
21770
21925
  "AWS::OSIS::PipelineBlueprint",
21926
+ "AWS::PartnerCentral::ConnectionPreferences",
21927
+ "AWS::PartnerCentral::Partner",
21928
+ "AWS::Personalize::BatchInferenceJob",
21929
+ "AWS::Personalize::BatchSegmentJob",
21771
21930
  "AWS::Personalize::DataDeletionJob",
21931
+ "AWS::Personalize::DatasetExportJob",
21772
21932
  "AWS::Personalize::Recipe",
21773
21933
  "AWS::Pinpoint::ADMChannel",
21774
21934
  "AWS::Pinpoint::APNSChannel",
@@ -21793,33 +21953,50 @@ const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21793
21953
  "AWS::PinpointEmail::DedicatedIpPool",
21794
21954
  "AWS::PinpointEmail::Identity",
21795
21955
  "AWS::QLDB::Ledger",
21956
+ "AWS::QuickSight::AssetBundleExportJob",
21957
+ "AWS::QuickSight::AssetBundleImportJob",
21796
21958
  "AWS::RDS::DBSecurityGroup",
21797
21959
  "AWS::RDS::DBSecurityGroupIngress",
21960
+ "AWS::RDS::ReservedDBInstance",
21798
21961
  "AWS::Redshift::ClusterSecurityGroup",
21799
21962
  "AWS::Redshift::ClusterSecurityGroupIngress",
21963
+ "AWS::Redshift::DataShare",
21800
21964
  "AWS::RedshiftServerless::RecoveryPoint",
21965
+ "AWS::ResilienceHub::RecommendationTemplate",
21801
21966
  "AWS::Route53::RecordSetGroup",
21967
+ "AWS::Route53Resolver::FirewallConfig",
21968
+ "AWS::SageMaker::AutoMLJob",
21802
21969
  "AWS::SageMaker::CodeRepository",
21803
- "AWS::SageMaker::EndpointConfig",
21970
+ "AWS::SageMaker::ExperimentTrialComponent",
21971
+ "AWS::SageMaker::HubContentVersion",
21972
+ "AWS::SageMaker::HyperParameterTuningJob",
21804
21973
  "AWS::SageMaker::ModelCardExportJob",
21805
21974
  "AWS::SageMaker::MonitoringScheduleAlert",
21806
21975
  "AWS::SageMaker::NotebookInstance",
21807
21976
  "AWS::SageMaker::NotebookInstanceLifecycleConfig",
21977
+ "AWS::SageMaker::OptimizationJob",
21978
+ "AWS::SageMaker::PipelineExecution",
21979
+ "AWS::SageMaker::TrainingJob",
21808
21980
  "AWS::SageMaker::TransformJob",
21809
21981
  "AWS::SageMaker::Workteam",
21810
- "AWS::SDB::Domain",
21982
+ "AWS::SavingsPlans::SavingsPlan",
21983
+ "AWS::SecurityAgent::PentestTask",
21811
21984
  "AWS::ServiceDiscovery::Instance",
21812
- "AWS::SES::ReceiptFilter",
21813
- "AWS::SES::ReceiptRule",
21814
- "AWS::SES::ReceiptRuleSet",
21985
+ "AWS::ServiceQuotas::Quota",
21815
21986
  "AWS::Signer::SigningJob",
21987
+ "AWS::SSM::AutomationExecution",
21988
+ "AWS::SSM::ManagedInstance",
21816
21989
  "AWS::SSM::Session",
21817
21990
  "AWS::SSO::ApplicationProvider",
21818
21991
  "AWS::States::Execution",
21819
21992
  "AWS::StepFunctions::MapRun",
21820
21993
  "AWS::ThinClient::SoftwareSet",
21994
+ "AWS::Transcribe::CallAnalyticsJob",
21995
+ "AWS::Transcribe::MedicalScribeJob",
21821
21996
  "AWS::Transcribe::MedicalTranscriptionJob",
21997
+ "AWS::Transcribe::TranscriptionJob",
21822
21998
  "AWS::UserNotifications::ManagedNotificationConfiguration",
21999
+ "AWS::UserNotifications::NotificationEvent",
21823
22000
  "AWS::WAF::ByteMatchSet",
21824
22001
  "AWS::WAF::IPSet",
21825
22002
  "AWS::WAF::Rule",
@@ -21837,7 +22014,9 @@ const NON_PROVISIONABLE_TYPES = /* @__PURE__ */ new Set([
21837
22014
  "AWS::WAFRegional::SqlInjectionMatchSet",
21838
22015
  "AWS::WAFRegional::WebACL",
21839
22016
  "AWS::WAFRegional::WebACLAssociation",
21840
- "AWS::WAFRegional::XssMatchSet"
22017
+ "AWS::WAFRegional::XssMatchSet",
22018
+ "AWS::Wisdom::Session",
22019
+ "AWS::WorkSpaces::WorkSpaceApplication"
21841
22020
  ]);
21842
22021
 
21843
22022
  //#endregion
@@ -22346,7 +22525,7 @@ var CloudControlProvider = class {
22346
22525
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
22347
22526
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
22348
22527
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
22349
- const { ASGProvider } = await import("./asg-provider-BocQJsjl.js").then((n) => n.n);
22528
+ const { ASGProvider } = await import("./asg-provider-CSEPihOt.js").then((n) => n.n);
22350
22529
  return withIndeterminateGuard(await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
22351
22530
  }
22352
22531
  const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
@@ -29274,6 +29453,7 @@ const STATEFUL_TYPES = /* @__PURE__ */ new Set([
29274
29453
  "AWS::Cognito::UserPool",
29275
29454
  "AWS::SecretsManager::Secret",
29276
29455
  "AWS::SSM::Parameter",
29456
+ "AWS::CloudHSM::Cluster",
29277
29457
  "AWS::KMS::Key",
29278
29458
  "AWS::KMS::ReplicaKey",
29279
29459
  "AWS::CodeCommit::Repository",
@@ -29294,6 +29474,9 @@ const STATEFUL_TYPES = /* @__PURE__ */ new Set([
29294
29474
  "AWS::RedshiftServerless::Snapshot",
29295
29475
  "AWS::NeptuneGraph::Graph",
29296
29476
  "AWS::NeptuneGraph::GraphSnapshot",
29477
+ "AWS::RDS::DBSnapshot",
29478
+ "AWS::RDS::ClusterSnapshot",
29479
+ "AWS::DynamoDB::Backup",
29297
29480
  "AWS::MemoryDB::Cluster",
29298
29481
  "AWS::MemoryDB::MultiRegionCluster",
29299
29482
  "AWS::ElastiCache::ServerlessCache",
@@ -29319,6 +29502,7 @@ const STATEFUL_TYPES = /* @__PURE__ */ new Set([
29319
29502
  "AWS::S3Outposts::Bucket",
29320
29503
  "AWS::HealthImaging::Datastore",
29321
29504
  "AWS::HealthLake::FHIRDatastore",
29505
+ "AWS::FSx::Volume",
29322
29506
  "AWS::SES::MailManagerArchive",
29323
29507
  "AWS::WorkspacesInstances::Volume",
29324
29508
  "AWS::IoTAnalytics::Channel",
@@ -29341,6 +29525,7 @@ const STATEFUL_TYPES = /* @__PURE__ */ new Set([
29341
29525
  "AWS::Connect::DataTable",
29342
29526
  "AWS::AppConfig::ConfigurationProfile",
29343
29527
  "AWS::AIOps::InvestigationGroup",
29528
+ "AWS::IoTSiteWise::Workspace",
29344
29529
  "AWS::Rbin::Rule",
29345
29530
  "AWS::SMSVOICE::PhoneNumber",
29346
29531
  "AWS::SMSVOICE::SenderId"
@@ -34099,42 +34284,64 @@ var DeployEngine = class {
34099
34284
  expectedRegion: this.stackRegion
34100
34285
  })), logicalId, void 0, void 0, updateProvider);
34101
34286
  } catch (updateError) {
34102
- const msg = updateError instanceof Error ? updateError.message : String(updateError);
34103
- const ccUnsupported = msg.includes("UnsupportedActionException") || msg.includes("does not support UPDATE");
34287
+ const ccUnsupported = isUpdateUnsupportedError(updateError, logicalId);
34104
34288
  const replaceOptIn = updateError instanceof ResourceUpdateNotSupportedError && this.options.replace === true;
34105
34289
  if (ccUnsupported || replaceOptIn) {
34106
- const statefulReason = isStatefulRecreateTargetForReplace(resourceType, currentProps);
34107
- if (statefulReason && this.options.forceStatefulRecreation !== true) {
34108
- const retainNote = updateReplacePolicy === "Retain" ? " Note: UpdateReplacePolicy: Retain does NOT protect this path — the replacement deletes the old resource regardless." : "";
34109
- throw markNonRetryable(new CdkdError((replaceOptIn ? `--replace would DELETE + CREATE the stateful resource ${logicalId} (${resourceType}) ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.` : `${logicalId} (${resourceType}) cannot be updated in place by the provisioning layer it routes through, so applying this change would DELETE + CREATE it — but it is a stateful resource: ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the update.`) + retainNote, "STATEFUL_REPLACE_BLOCKED", updateError instanceof Error ? updateError : void 0));
34110
- }
34111
- this.logger.info(`UPDATE not supported for ${logicalId} (${resourceType}), replacing (DELETE CREATE)`);
34112
- const fallbackFinalSnapshotId = await this.prepareFinalSnapshotForDelete(logicalId, resourceType, currentResource, template?.Resources?.[logicalId]?.UpdateReplacePolicy ?? currentResource.updateReplacePolicy);
34113
- let fallbackDeleteResult = void 0;
34114
- try {
34115
- fallbackDeleteResult = await updateProvider.delete(logicalId, currentResource.physicalId, resourceType, currentProps, {
34116
- expectedRegion: this.stackRegion,
34117
- forceDataDelete: this.options.forceStatefulRecreation === true,
34118
- ...fallbackFinalSnapshotId !== void 0 && { finalSnapshotIdentifier: fallbackFinalSnapshotId }
34119
- });
34120
- } catch (deleteError) {
34121
- const deleteMsg = deleteError instanceof Error ? deleteError.message : String(deleteError);
34122
- if (deleteMsg.includes("does not exist") || deleteMsg.includes("not found") || deleteMsg.includes("NotFound")) this.logger.debug(`Old resource ${logicalId} already gone, proceeding with CREATE`);
34123
- else throw deleteError;
34290
+ const retainOldOnReplace = updateReplacePolicy === "Retain";
34291
+ const statefulReason = retainOldOnReplace ? null : isStatefulRecreateTargetForReplace(resourceType, currentProps);
34292
+ if (statefulReason && this.options.forceStatefulRecreation !== true) throw markNonRetryable(new CdkdError(replaceOptIn ? `--replace would DELETE + CREATE the stateful resource ${logicalId} (${resourceType}) — ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.` : `${logicalId} (${resourceType}) cannot be updated in place by the provisioning layer it routes through, so applying this change would DELETE + CREATE it but it is a stateful resource: ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the update.`, "STATEFUL_REPLACE_BLOCKED", updateError instanceof Error ? updateError : void 0));
34293
+ this.logger.info(retainOldOnReplace ? `UPDATE not supported for ${logicalId} (${resourceType}), replacing (CREATE only UpdateReplacePolicy: Retain keeps the old resource)` : `UPDATE not supported for ${logicalId} (${resourceType}), replacing (DELETE CREATE)`);
34294
+ if (!retainOldOnReplace) {
34295
+ const fallbackFinalSnapshotId = await this.prepareFinalSnapshotForDelete(logicalId, resourceType, currentResource, template?.Resources?.[logicalId]?.UpdateReplacePolicy ?? currentResource.updateReplacePolicy);
34296
+ let fallbackDeleteResult = void 0;
34297
+ try {
34298
+ fallbackDeleteResult = await updateProvider.delete(logicalId, currentResource.physicalId, resourceType, currentProps, {
34299
+ expectedRegion: this.stackRegion,
34300
+ forceDataDelete: this.options.forceStatefulRecreation === true,
34301
+ ...fallbackFinalSnapshotId !== void 0 && { finalSnapshotIdentifier: fallbackFinalSnapshotId }
34302
+ });
34303
+ } catch (deleteError) {
34304
+ const deleteMsg = deleteError instanceof Error ? deleteError.message : String(deleteError);
34305
+ if (deleteMsg.includes("does not exist") || deleteMsg.includes("not found") || deleteMsg.includes("NotFound")) this.logger.debug(`Old resource ${logicalId} already gone, proceeding with CREATE`);
34306
+ else throw deleteError;
34307
+ }
34308
+ const fallbackSkipReason = deleteSkipReason(fallbackDeleteResult);
34309
+ if (fallbackSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, fallbackSkipReason, "during the UPDATE-not-supported replacement"));
34124
34310
  }
34125
- const fallbackSkipReason = deleteSkipReason(fallbackDeleteResult);
34126
- if (fallbackSkipReason !== void 0) throw new Error(deleteSkippedMessage(logicalId, currentResource.physicalId, fallbackSkipReason, "during the UPDATE-not-supported replacement"));
34127
34311
  const replDecision = this.providerRegistry.getProviderFor({
34128
34312
  resourceType,
34129
34313
  properties: resolvedProps
34130
34314
  });
34131
34315
  const replProvider = replDecision.provider;
34132
34316
  const replProps = replDecision.provisionedBy === "cc-api" ? this.preparePropertiesForCcApi(resourceType, resolvedProps, logicalId) : resolvedProps;
34133
- const createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replProvider);
34317
+ let retainedSurvivorReason;
34318
+ let createResult;
34319
+ try {
34320
+ createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replProvider);
34321
+ } catch (createError) {
34322
+ if (!retainOldOnReplace) throw createError;
34323
+ if (!isNameCollisionError(createError instanceof Error ? createError.message : String(createError))) throw createError;
34324
+ const nameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
34325
+ throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement because the provisioning layer cannot update it in place — but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. ${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed. Removing UpdateReplacePolicy: Retain lets cdkd delete the old resource first, which destroys it and any data it holds.`, "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
34326
+ }
34327
+ if (retainOldOnReplace) {
34328
+ if (createResult.physicalId === currentResource.physicalId) {
34329
+ const idempotentNameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
34330
+ throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement, but its Create API is name-idempotent: the create returned the existing resource (${currentResource.physicalId}) instead of creating a new one, and UpdateReplacePolicy: Retain pins that resource in place, so the new properties were not applied. ${idempotentNameOrigin.descriptor}. ${idempotentNameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed.`, "NAMED_REPLACEMENT_IDEMPOTENT_CREATE"));
34331
+ }
34332
+ this.logger.warn(` ⚠ ${logicalId} has UpdateReplacePolicy: Retain — the old physical resource (${currentResource.physicalId}) is RETAINED and is no longer tracked by cdkd: it keeps running and incurring cost, and \`cdkd destroy\` will not remove it. Delete it yourself once you no longer need its data.`);
34333
+ retainedSurvivorReason = `UpdateReplacePolicy: Retain kept the old ${resourceType} (${currentResource.physicalId}), now untracked by cdkd`;
34334
+ }
34134
34335
  const replacementResult = {
34135
34336
  physicalId: createResult.physicalId,
34136
34337
  wasReplaced: true,
34137
- ...createResult.attributes && { attributes: createResult.attributes }
34338
+ ...createResult.attributes && { attributes: createResult.attributes },
34339
+ ...createResult.noEchoAttributes === true && { noEchoAttributes: true },
34340
+ ...createResult.noEchoAttributeNames && { noEchoAttributeNames: createResult.noEchoAttributeNames },
34341
+ ...retainedSurvivorReason !== void 0 ? {
34342
+ outcome: "partial",
34343
+ reason: retainedSurvivorReason
34344
+ } : { outcome: "updated" }
34138
34345
  };
34139
34346
  if (createResult.effectiveProperties) replacementResult.effectiveProperties = createResult.effectiveProperties;
34140
34347
  result = replacementResult;
@@ -34280,8 +34487,12 @@ var DeployEngine = class {
34280
34487
  * connect the message to their code at all.
34281
34488
  *
34282
34489
  * `descriptor` names WHERE the name came from; `remedy` is the accurate
34283
- * first option. Both callers append the shared `--replace` alternative,
34284
- * which is identical in either case.
34490
+ * first option. What each caller appends after it differs: the two
34491
+ * property-driven create-first sites append the shared `--replace`
34492
+ * alternative, while the update-failure fallback's two `Retain` refusals
34493
+ * (issue #2518) append the Retain clause instead — under `Retain` no flag
34494
+ * frees the name, so offering `--replace` there would send the user to a
34495
+ * flag that changes nothing.
34285
34496
  *
34286
34497
  * Classification is best-effort by construction (see
34287
34498
  * {@link looksLikeCdkdGeneratedName}) and falls back to the pre-#1636
@@ -34608,4 +34819,4 @@ var DeployEngine = class {
34608
34819
 
34609
34820
  //#endregion
34610
34821
  export { beginCommandInterruptScope as $, resolveAutoAssetStorage as $n, isTransientServerError as $r, maskSecretsInError as $t, formatResourceLine as A, ensureAssetStorage as An, DependencyError as Ar, requireConfigString as At, isExportAliasCollision as B, dockerSpawnEnvWithSensitive as Bn, ResourceTimeoutError as Br, INTRINSIC_KEYS as Bt, unsupportedFinalSnapshotError as C, loadPublishableAssetManifest as Cn, getAwsClients as Cr, coerceCfnBoolean as Ct, isStatefulRecreateTargetForReplace as D, AssetModeResolver as Dn, CdkdError as Dr, replayWarn as Dt, MULTI_REGION_RECREATE_BLOCKED_TYPES as E, stripControlChars as En, AssetError as Er, readConfigString as Et, red as F, validateAssetBucketName as Fn, LocalStartServiceError as Fr, s3BucketDualStackDomainName as Ft, collectInlinePolicyNamesManagedBySiblings as G, runDockerStreaming as Gn, SynthesisError as Gr, STATE_SOURCED_CROSS_GENERATION_RULES as Gt, stateKeySecretExposure as H, getDockerCmd as Hn, StackHasActiveImportsError as Hr, withRetry as Ht, yellow as I, validateContainerRepoName as In, LockError as Ir, s3BucketRegionalDomainName as It, findActionableSilentDrops as J, Synthesizer as Jn, normalizeAwsError as Jr, carriesSecretMask as Jt, clearOnUpdateRemoval as K, AssetManifestLoader as Kn, formatError as Kr, STATE_SOURCED_READBACK_RULES as Kt, collectDeclaredOutputNames as L, buildDenyExternalAccessPolicy as Ln, NestedStackChildDirectDestroyError as Lr, s3BucketWebsiteUrl as Lt, cyan as M, isCrossRegionRedirect as Mn, DynamicReferenceRegionAmbiguousError as Mr, producerRegionsFromState as Mt, gray as N, parseBootstrapMarker as Nn, IntrinsicResolutionRefusalError as Nr, s3BucketArn as Nt, isStatefulRecreateTargetSync as O, BOOTSTRAP_MARKER_PREFIX as On, ConfigError as Or, requireConfigArray as Ot, green as P, readBootstrapMarkerBody as Pn, LocalInvokeBuildError as Pr, s3BucketDomainName as Pt, maskerOrIdentity as Q, resolveApp as Qn, isThrottlingError as Qr, isSingleDynamicReferenceToken as Qt, collectPublishedOutputNames as R, describeAwsFailure as Rn, PartialFailureError as Rr, applyRoleArnIfSet as Rt, refusesFinalSnapshot as S, createAssetRedirectResolver as Sn, AwsClients as Sr, assertRegionMatch as St, extractDeploymentEventError as T, escapeRegExp$1 as Tn, setAwsClients as Tr, configStringRefusal as Tt, getCurrentResourceSecrets as U, partitionSensitiveEnv as Un, StackTerminationProtectionError as Ur, DagBuilder as Ut, secretBearingStateKeyWarning as V, formatDockerLoginError as Vn, ResourceUpdateNotSupportedError as Vr, describeTypeWithThrottleRetry as Vt, IAMRoleProvider as W, runDockerForeground as Wn, StateError as Wr, TemplateParser as Wt, createMaskedRetryLogger as X, getDefaultStateBucketName as Xn, isMarkedNonRetryable as Xr, dynamicReferenceTokens as Xt, findSilentDropProperties as Y, synthesisStatusMessage as Yn, withErrorHandling as Yr, createSecretMasker as Yt, maskDeep as Z, getLegacyStateBucketName as Zn, isRetryableTransientError as Zr, errorCauseChain as Zt, PRE_DELETE_SNAPSHOT_TYPES as _, shouldRetainResource as _n, derivePartitionAndUrlSuffix as _r, parameterTypeMayLoseSecretIdentity as _t, DeploymentEventsStore as a, LockManager as an, stateBucketExistenceConfirmed as ar, slowCcOperationTimeoutMs as at, createPreDeleteFinalSnapshot as b, WorkGraph as bn, clearBucketRegionCache as br, normalizeAwsTagsToCfn as bt, replayFailedOperations as c, UNRENDERABLE as cn, CFN_TEMPLATE_URL_LIMIT as cr, deleteSkipReason as ct, updatePartialReason as d, forceQuitRecoveryClause as dn, uploadCfnTemplate as dr, IntrinsicFunctionResolver as dt, markNonRetryable as ei, maskSecretsInText as en, resolveCaptureObservedState as er, endCommandInterruptScope as et, withResourceDeadline as f, CUSTOM_RESOURCE_RESPONSE_PREFIX as fn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as fr, carriesDynamicReference as ft, ATOMIC_FINAL_SNAPSHOT_TYPES as g, importableOutputs as gn, canonicalizeRegion as gr, isUnboundTemplateParameter as gt, computeImplicitDeleteEdges as h, importableOutputKeys as hn, PARTITION_TABLE as hr, getAccountInfo as ht, DeploymentEventsReader as i, scrubResourceRecord as in, resolveUseCdkBootstrapAssets as ir, CloudControlProvider as it, bold as j, getBootstrapMarkerKey as jn, DeployCancelledError as jr, classifyReplaySecretRegion as jt, renderStatefulReason as k, assertAssetBucketRegion as kn, CrossAccountSecretRefusalError as kr, requireConfigObject as kt, replayRollback as l, buildForceUnlockCommand as ln, MIGRATE_TMP_PREFIX as lr, disableInstanceApiTermination as lt, IMPLICIT_DELETE_DEPENDENCIES as m, exportNamesCarriedFrom as mn, expectedOwnerParam as mr, coerceParameterTypedValue as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, retryClassificationText as ni, recoverMaskedOutput as nn, resolveStateBucketWithDefault as nr, isInterruptedWaitError as nt, planFailedOps as o, S3StateBackend as on, warnDeprecatedNoPrefixCliFlag as or, UNSPECIFIED_SKIP_REASON as ot, maskingRetryLogger as p, DEFAULT_STATE_PREFIX as pn, displaySafe as pr, cfnRefValueFromPhysicalId as pt, ProviderRegistry as q, getDockerImageBySourceHash as qn, isCdkdError as qr, TEMPLATE_SOURCED_RULES as qt, DeployEngine as r, __exportAll as ri, redactSecretsForState as rn, resolveStateBucketWithDefaultAndSource as rr, startInterruptWatch as rt, planRollback as s, rebuildClientForBucketRegion as sn, CFN_TEMPLATE_BODY_LIMIT as sr, deleteIndeterminateGuards as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, markRedactedCause as ti, recordMaskOnlyValue as tn, resolveSkipPrefix as tr, interruptWatchListenerCount as tt, updatePartialMessage as u, buildLockContentionMessage as un, findLargeInlineResources as ur, isTerminationProtectionPropagationError as ut, buildFinalSnapshotIdentifier as v, AssetPublisher as vn, AssemblyReader as vr, refStateLookupFromResource as vt, makeCanonicalizePropertiesFn as w, rewriteTemplateAssetReferences as wn, resetAwsClients as wr, configBooleanRefusal as wt, isFinalSnapshotError as x, buildAssetRedirectMap as xn, resolveBucketRegion as xr, resolveExplicitPhysicalId as xt, ccRoutedFinalSnapshotError as y, stringifyValue as yn, processStackMessages as yr, WAFv2WebACLProvider as yt, exportAliasCollisionScrubWarning as z, buildDockerImage as zn, ProvisioningError as zr, DiffCalculator as zt };
34611
- //# sourceMappingURL=deploy-engine-D0RCEQ6D.js.map
34822
+ //# sourceMappingURL=deploy-engine-BoSlW08T.js.map