@go-to-k/cdkd 0.40.0 → 0.41.0

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
@@ -9747,6 +9747,42 @@ var IAMInstanceProfileProvider = class {
9747
9747
  );
9748
9748
  }
9749
9749
  }
9750
+ /**
9751
+ * Read the AWS-current IAM instance profile configuration in CFn-property
9752
+ * shape.
9753
+ *
9754
+ * Issues a single `GetInstanceProfile` and surfaces the keys `create()`
9755
+ * accepts (`InstanceProfileName`, `Path`, `Roles`). The Roles list maps
9756
+ * the inline `Role[]` (each carrying `{RoleName, Arn, ...}`) back to the
9757
+ * `string[]` of role names that CFn / cdkd state holds.
9758
+ *
9759
+ * Returns `undefined` when the profile is gone (`NoSuchEntityException`).
9760
+ */
9761
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
9762
+ let profile;
9763
+ try {
9764
+ const resp = await this.iamClient.send(
9765
+ new GetInstanceProfileCommand({ InstanceProfileName: physicalId })
9766
+ );
9767
+ profile = resp.InstanceProfile;
9768
+ } catch (err) {
9769
+ if (err instanceof NoSuchEntityException3)
9770
+ return void 0;
9771
+ throw err;
9772
+ }
9773
+ if (!profile)
9774
+ return void 0;
9775
+ const result = {};
9776
+ if (profile.InstanceProfileName !== void 0) {
9777
+ result["InstanceProfileName"] = profile.InstanceProfileName;
9778
+ }
9779
+ if (profile.Path !== void 0)
9780
+ result["Path"] = profile.Path;
9781
+ const roleNames = (profile.Roles ?? []).map((r) => r.RoleName).filter((n) => !!n);
9782
+ if (roleNames.length > 0)
9783
+ result["Roles"] = roleNames;
9784
+ return result;
9785
+ }
9750
9786
  /**
9751
9787
  * Adopt an existing IAM instance profile into cdkd state.
9752
9788
  *
@@ -10799,6 +10835,123 @@ var IAMUserGroupProvider = class {
10799
10835
  );
10800
10836
  }
10801
10837
  }
10838
+ // ─── readCurrentState dispatch ───────────────────────────────────
10839
+ /**
10840
+ * Read the AWS-current configuration for an IAM user / group /
10841
+ * UserToGroupAddition in CFn-property shape.
10842
+ *
10843
+ * - **AWS::IAM::User**: `GetUser` for `UserName`, `Path`,
10844
+ * `PermissionsBoundary` (re-shaped from `PermissionsBoundary.Arn`);
10845
+ * `ListAttachedUserPolicies` for `ManagedPolicyArns`;
10846
+ * `ListGroupsForUser` for `Groups`. `Tags`, `LoginProfile`, and
10847
+ * `Policies` (inline policy bodies) are intentionally omitted —
10848
+ * same shape decisions as `iam-role-provider` (LoginProfile contains a
10849
+ * one-time password and inline policy bodies cost N extra round-trips
10850
+ * that are out of scope for v1).
10851
+ * - **AWS::IAM::Group**: `GetGroup` for `GroupName`, `Path`;
10852
+ * `ListAttachedGroupPolicies` for `ManagedPolicyArns`. `Policies`
10853
+ * (inline policy bodies) is omitted for the same reason as User /
10854
+ * Role.
10855
+ * - **AWS::IAM::UserToGroupAddition**: SKIPPED — returns `undefined`
10856
+ * because the resource is metadata-only (group-membership attachments
10857
+ * written via `AddUserToGroup`). A meaningful drift check would
10858
+ * require both the `GroupName` and the source-of-truth `Users` list
10859
+ * from state, neither of which `readCurrentState` receives. The
10860
+ * drift comparator falls back to "drift unknown" and the user can
10861
+ * inspect the membership manually.
10862
+ *
10863
+ * Returns `undefined` when the user / group is gone
10864
+ * (`NoSuchEntityException`).
10865
+ */
10866
+ async readCurrentState(physicalId, logicalId, resourceType) {
10867
+ switch (resourceType) {
10868
+ case "AWS::IAM::User":
10869
+ return this.readUserCurrentState(physicalId);
10870
+ case "AWS::IAM::Group":
10871
+ return this.readGroupCurrentState(physicalId);
10872
+ case "AWS::IAM::UserToGroupAddition":
10873
+ return void 0;
10874
+ default:
10875
+ this.logger.debug(
10876
+ `readCurrentState: unsupported resource type ${resourceType} for ${logicalId}`
10877
+ );
10878
+ return void 0;
10879
+ }
10880
+ }
10881
+ async readUserCurrentState(physicalId) {
10882
+ let user;
10883
+ try {
10884
+ const resp = await this.iamClient.send(new GetUserCommand({ UserName: physicalId }));
10885
+ user = resp.User;
10886
+ } catch (err) {
10887
+ if (err instanceof NoSuchEntityException4)
10888
+ return void 0;
10889
+ throw err;
10890
+ }
10891
+ if (!user)
10892
+ return void 0;
10893
+ const result = {};
10894
+ if (user.UserName !== void 0)
10895
+ result["UserName"] = user.UserName;
10896
+ if (user.Path !== void 0)
10897
+ result["Path"] = user.Path;
10898
+ if (user.PermissionsBoundary?.PermissionsBoundaryArn !== void 0) {
10899
+ result["PermissionsBoundary"] = user.PermissionsBoundary.PermissionsBoundaryArn;
10900
+ }
10901
+ try {
10902
+ const attached = await this.iamClient.send(
10903
+ new ListAttachedUserPoliciesCommand({ UserName: physicalId })
10904
+ );
10905
+ const arns = (attached.AttachedPolicies ?? []).map((p) => p.PolicyArn).filter((arn) => !!arn);
10906
+ if (arns.length > 0)
10907
+ result["ManagedPolicyArns"] = arns;
10908
+ } catch (err) {
10909
+ if (!(err instanceof NoSuchEntityException4))
10910
+ throw err;
10911
+ }
10912
+ try {
10913
+ const groups = await this.iamClient.send(
10914
+ new ListGroupsForUserCommand({ UserName: physicalId })
10915
+ );
10916
+ const names = (groups.Groups ?? []).map((g) => g.GroupName).filter((n) => !!n);
10917
+ if (names.length > 0)
10918
+ result["Groups"] = names;
10919
+ } catch (err) {
10920
+ if (!(err instanceof NoSuchEntityException4))
10921
+ throw err;
10922
+ }
10923
+ return result;
10924
+ }
10925
+ async readGroupCurrentState(physicalId) {
10926
+ let group;
10927
+ try {
10928
+ const resp = await this.iamClient.send(new GetGroupCommand({ GroupName: physicalId }));
10929
+ group = resp.Group;
10930
+ } catch (err) {
10931
+ if (err instanceof NoSuchEntityException4)
10932
+ return void 0;
10933
+ throw err;
10934
+ }
10935
+ if (!group)
10936
+ return void 0;
10937
+ const result = {};
10938
+ if (group.GroupName !== void 0)
10939
+ result["GroupName"] = group.GroupName;
10940
+ if (group.Path !== void 0)
10941
+ result["Path"] = group.Path;
10942
+ try {
10943
+ const attached = await this.iamClient.send(
10944
+ new ListAttachedGroupPoliciesCommand({ GroupName: physicalId })
10945
+ );
10946
+ const arns = (attached.AttachedPolicies ?? []).map((p) => p.PolicyArn).filter((arn) => !!arn);
10947
+ if (arns.length > 0)
10948
+ result["ManagedPolicyArns"] = arns;
10949
+ } catch (err) {
10950
+ if (!(err instanceof NoSuchEntityException4))
10951
+ throw err;
10952
+ }
10953
+ return result;
10954
+ }
10802
10955
  // ─── Import dispatch ──────────────────────────────────────────────
10803
10956
  /**
10804
10957
  * Adopt an existing IAM user / group / user-to-group addition into cdkd state.
@@ -12002,6 +12155,7 @@ var S3BucketProvider = class {
12002
12155
  import {
12003
12156
  PutBucketPolicyCommand as PutBucketPolicyCommand2,
12004
12157
  DeleteBucketPolicyCommand,
12158
+ GetBucketPolicyCommand,
12005
12159
  NoSuchBucket as NoSuchBucket2
12006
12160
  } from "@aws-sdk/client-s3";
12007
12161
  init_aws_clients();
@@ -12159,6 +12313,43 @@ var S3BucketPolicyProvider = class {
12159
12313
  );
12160
12314
  }
12161
12315
  }
12316
+ /**
12317
+ * Read the AWS-current S3 bucket policy in CFn-property shape.
12318
+ *
12319
+ * Issues `GetBucketPolicy` against the bucket (physicalId === bucket
12320
+ * name) and surfaces:
12321
+ * - `Bucket` — derived directly from `physicalId`.
12322
+ * - `PolicyDocument` — JSON-parsed back to the object form cdkd state
12323
+ * typically holds.
12324
+ *
12325
+ * Returns `undefined` when the bucket is gone (`NoSuchBucket`) or when
12326
+ * no policy is currently attached (`NoSuchBucketPolicy`).
12327
+ */
12328
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
12329
+ let policyJson;
12330
+ try {
12331
+ const resp = await this.s3Client.send(new GetBucketPolicyCommand({ Bucket: physicalId }));
12332
+ policyJson = resp.Policy;
12333
+ } catch (err) {
12334
+ if (err instanceof NoSuchBucket2)
12335
+ return void 0;
12336
+ const e = err;
12337
+ if (e.name === "NoSuchBucketPolicy")
12338
+ return void 0;
12339
+ throw err;
12340
+ }
12341
+ if (!policyJson)
12342
+ return void 0;
12343
+ const result = {
12344
+ Bucket: physicalId
12345
+ };
12346
+ try {
12347
+ result["PolicyDocument"] = JSON.parse(policyJson);
12348
+ } catch {
12349
+ result["PolicyDocument"] = policyJson;
12350
+ }
12351
+ return result;
12352
+ }
12162
12353
  /**
12163
12354
  * Adopt an existing S3 bucket policy into cdkd state.
12164
12355
  *
@@ -12582,7 +12773,10 @@ var SQSQueueProvider = class {
12582
12773
  };
12583
12774
 
12584
12775
  // src/provisioning/providers/sqs-queue-policy-provider.ts
12585
- import { SetQueueAttributesCommand as SetQueueAttributesCommand2 } from "@aws-sdk/client-sqs";
12776
+ import {
12777
+ SetQueueAttributesCommand as SetQueueAttributesCommand2,
12778
+ GetQueueAttributesCommand as GetQueueAttributesCommand2
12779
+ } from "@aws-sdk/client-sqs";
12586
12780
  init_aws_clients();
12587
12781
  var SQSQueuePolicyProvider = class {
12588
12782
  sqsClient;
@@ -12735,6 +12929,52 @@ var SQSQueuePolicyProvider = class {
12735
12929
  );
12736
12930
  }
12737
12931
  }
12932
+ /**
12933
+ * Read the AWS-current SQS queue policy in CFn-property shape.
12934
+ *
12935
+ * The provider's `create()` records `physicalId` as the first queue URL
12936
+ * in the `Queues` array. Drift here surfaces:
12937
+ * - `Queues` — single-element array containing `physicalId`. The full
12938
+ * state list of queues isn't recoverable from AWS (no reverse index)
12939
+ * and the comparator only descends into keys present in state, so a
12940
+ * state with multiple queues will still surface drift on
12941
+ * `PolicyDocument` for the first queue (the most common drift case).
12942
+ * - `PolicyDocument` — fetched via `GetQueueAttributes` for
12943
+ * `Policy`, JSON-parsed back to the object form cdkd state holds.
12944
+ *
12945
+ * Returns `undefined` when the queue is gone (`QueueDoesNotExist`) or
12946
+ * when no policy is currently attached (the `Policy` attribute is
12947
+ * absent / empty).
12948
+ */
12949
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
12950
+ let policyAttr;
12951
+ try {
12952
+ const resp = await this.sqsClient.send(
12953
+ new GetQueueAttributesCommand2({
12954
+ QueueUrl: physicalId,
12955
+ AttributeNames: ["Policy"]
12956
+ })
12957
+ );
12958
+ policyAttr = resp.Attributes?.["Policy"];
12959
+ } catch (err) {
12960
+ const e = err;
12961
+ if (e.name === "QueueDoesNotExist" || typeof e.message === "string" && e.message.includes("does not exist")) {
12962
+ return void 0;
12963
+ }
12964
+ throw err;
12965
+ }
12966
+ if (!policyAttr)
12967
+ return void 0;
12968
+ const result = {
12969
+ Queues: [physicalId]
12970
+ };
12971
+ try {
12972
+ result["PolicyDocument"] = JSON.parse(policyAttr);
12973
+ } catch {
12974
+ result["PolicyDocument"] = policyAttr;
12975
+ }
12976
+ return result;
12977
+ }
12738
12978
  /**
12739
12979
  * Adopt an existing SQS queue policy into cdkd state.
12740
12980
  *
@@ -13407,7 +13647,7 @@ var SNSSubscriptionProvider = class {
13407
13647
  };
13408
13648
 
13409
13649
  // src/provisioning/providers/sns-topic-policy-provider.ts
13410
- import { SetTopicAttributesCommand as SetTopicAttributesCommand2 } from "@aws-sdk/client-sns";
13650
+ import { SetTopicAttributesCommand as SetTopicAttributesCommand2, GetTopicAttributesCommand as GetTopicAttributesCommand2 } from "@aws-sdk/client-sns";
13411
13651
  init_aws_clients();
13412
13652
  var SNSTopicPolicyProvider = class {
13413
13653
  logger = getLogger().child("SNSTopicPolicyProvider");
@@ -13543,6 +13783,57 @@ var SNSTopicPolicyProvider = class {
13543
13783
  }
13544
13784
  this.logger.debug(`Successfully deleted SNS topic policy ${logicalId}`);
13545
13785
  }
13786
+ /**
13787
+ * Read the AWS-current SNS topic policy in CFn-property shape.
13788
+ *
13789
+ * The provider's `create()` builds `physicalId` as a comma-joined list
13790
+ * of topic ARNs. We:
13791
+ * 1. Split the physical id back into the list of topic ARNs and surface
13792
+ * them as `Topics` (matching `create()` shape).
13793
+ * 2. Fetch `GetTopicAttributes` on the FIRST topic to retrieve the
13794
+ * `Policy` attribute and surface it as `PolicyDocument` (JSON-parsed
13795
+ * to match the object form cdkd state holds).
13796
+ *
13797
+ * Single-topic fetch is intentional: cdkd applies the same policy to
13798
+ * every topic in `Topics`, so the body is the same on each. A future
13799
+ * enhancement could verify per-topic that the policy actually matches
13800
+ * (catches manual divergence between multiple targets), but the bulk of
13801
+ * drift cases involve a single topic and the body content is what users
13802
+ * actually care about.
13803
+ *
13804
+ * Returns `undefined` when no topics are listed in the physical id, or
13805
+ * when the first listed topic is gone (`NotFoundException`).
13806
+ */
13807
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
13808
+ const topics = physicalId.split(",").filter((t) => t.length > 0);
13809
+ if (topics.length === 0)
13810
+ return void 0;
13811
+ const firstTopic = topics[0];
13812
+ let policyAttr;
13813
+ try {
13814
+ const resp = await getAwsClients().sns.send(
13815
+ new GetTopicAttributesCommand2({ TopicArn: firstTopic })
13816
+ );
13817
+ policyAttr = resp.Attributes?.["Policy"];
13818
+ } catch (err) {
13819
+ const e = err;
13820
+ if (e.name === "NotFoundException" || e.name === "NotFound" || typeof e.message === "string" && e.message.includes("does not exist")) {
13821
+ return void 0;
13822
+ }
13823
+ throw err;
13824
+ }
13825
+ const result = {
13826
+ Topics: topics
13827
+ };
13828
+ if (policyAttr) {
13829
+ try {
13830
+ result["PolicyDocument"] = JSON.parse(policyAttr);
13831
+ } catch {
13832
+ result["PolicyDocument"] = policyAttr;
13833
+ }
13834
+ }
13835
+ return result;
13836
+ }
13546
13837
  /**
13547
13838
  * Adopt an existing SNS topic policy into cdkd state.
13548
13839
  *
@@ -14793,6 +15084,66 @@ var LambdaUrlProvider = class {
14793
15084
  throw err;
14794
15085
  }
14795
15086
  }
15087
+ /**
15088
+ * Read the AWS-current Lambda Function URL configuration in CFn-property
15089
+ * shape.
15090
+ *
15091
+ * Issues `GetFunctionUrlConfig` with the parent function's ARN/name (the
15092
+ * physical id) and surfaces `AuthType`, `InvokeMode`, and `Cors`.
15093
+ * AWS-managed fields (`FunctionUrl`, `FunctionArn`, `CreationTime`,
15094
+ * `LastModifiedTime`) are filtered at the wire layer.
15095
+ *
15096
+ * `TargetFunctionArn` is surfaced from `physicalId` (the create() flow
15097
+ * stores the parent function's ARN/name there). `Qualifier` is NOT
15098
+ * available from `GetFunctionUrlConfig` (it's only an input on Create);
15099
+ * cdkd state stores it but AWS does not surface it back, so we omit it
15100
+ * from the snapshot — the comparator's "key absent in state never
15101
+ * drifts" rule handles the omission cleanly when state lacks Qualifier
15102
+ * too, and cases where state HAS Qualifier surface as drift only when
15103
+ * the qualifier was changed via Update (which the SDK supports through
15104
+ * `physicalId` rather than the qualifier itself).
15105
+ *
15106
+ * Returns `undefined` when the URL config is gone
15107
+ * (`ResourceNotFoundException`).
15108
+ */
15109
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
15110
+ let resp;
15111
+ try {
15112
+ resp = await this.lambdaClient.send(
15113
+ new GetFunctionUrlConfigCommand2({ FunctionName: physicalId })
15114
+ );
15115
+ } catch (err) {
15116
+ if (err instanceof ResourceNotFoundException3)
15117
+ return void 0;
15118
+ throw err;
15119
+ }
15120
+ const result = {
15121
+ TargetFunctionArn: physicalId
15122
+ };
15123
+ if (resp.AuthType !== void 0)
15124
+ result["AuthType"] = resp.AuthType;
15125
+ if (resp.InvokeMode !== void 0)
15126
+ result["InvokeMode"] = resp.InvokeMode;
15127
+ if (resp.Cors !== void 0) {
15128
+ const cors = {};
15129
+ if (resp.Cors.AllowOrigins)
15130
+ cors["AllowOrigins"] = [...resp.Cors.AllowOrigins];
15131
+ if (resp.Cors.AllowMethods)
15132
+ cors["AllowMethods"] = [...resp.Cors.AllowMethods];
15133
+ if (resp.Cors.AllowHeaders)
15134
+ cors["AllowHeaders"] = [...resp.Cors.AllowHeaders];
15135
+ if (resp.Cors.ExposeHeaders)
15136
+ cors["ExposeHeaders"] = [...resp.Cors.ExposeHeaders];
15137
+ if (resp.Cors.MaxAge !== void 0)
15138
+ cors["MaxAge"] = resp.Cors.MaxAge;
15139
+ if (resp.Cors.AllowCredentials !== void 0) {
15140
+ cors["AllowCredentials"] = resp.Cors.AllowCredentials;
15141
+ }
15142
+ if (Object.keys(cors).length > 0)
15143
+ result["Cors"] = cors;
15144
+ }
15145
+ return result;
15146
+ }
14796
15147
  /**
14797
15148
  * Adopt an existing Lambda Function URL into cdkd state.
14798
15149
  *
@@ -15055,6 +15406,96 @@ var LambdaEventSourceMappingProvider = class {
15055
15406
  );
15056
15407
  }
15057
15408
  }
15409
+ /**
15410
+ * Read the AWS-current Lambda event source mapping configuration in
15411
+ * CFn-property shape.
15412
+ *
15413
+ * Issues `GetEventSourceMapping` for the UUID and surfaces the keys
15414
+ * `create()` accepts. AWS-managed fields (`UUID`, `LastModified`,
15415
+ * `LastProcessingResult`, `State`, `StateTransitionReason`,
15416
+ * `EventSourceMappingArn`) are filtered at the wire layer.
15417
+ *
15418
+ * `FunctionName` is surfaced as the AWS `FunctionArn` (which is what
15419
+ * `GetEventSourceMapping` returns) — cdkd state typically holds this
15420
+ * resolved ARN form already after intrinsic resolution. The drift
15421
+ * comparator can match against both forms when state holds a name vs an
15422
+ * ARN; mismatched-shape false positives are out of scope for v1.
15423
+ *
15424
+ * `Tags` is omitted: cdkd `create()` reshapes CFn tag arrays into a
15425
+ * tags map at create time, but `GetEventSourceMapping` does not return
15426
+ * tags (`ListTags(Resource: arn)` does). Same shape-decision rationale
15427
+ * as Lambda function tags drift — out of scope for v1.
15428
+ *
15429
+ * Returns `undefined` when the mapping is gone
15430
+ * (`ResourceNotFoundException`).
15431
+ */
15432
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
15433
+ let resp;
15434
+ try {
15435
+ resp = await this.lambdaClient.send(new GetEventSourceMappingCommand({ UUID: physicalId }));
15436
+ } catch (err) {
15437
+ if (err instanceof ResourceNotFoundException4)
15438
+ return void 0;
15439
+ throw err;
15440
+ }
15441
+ const result = {};
15442
+ if (resp.FunctionArn !== void 0)
15443
+ result["FunctionName"] = resp.FunctionArn;
15444
+ if (resp.EventSourceArn !== void 0)
15445
+ result["EventSourceArn"] = resp.EventSourceArn;
15446
+ if (resp.BatchSize !== void 0)
15447
+ result["BatchSize"] = resp.BatchSize;
15448
+ if (resp.StartingPosition !== void 0)
15449
+ result["StartingPosition"] = resp.StartingPosition;
15450
+ if (resp.MaximumBatchingWindowInSeconds !== void 0) {
15451
+ result["MaximumBatchingWindowInSeconds"] = resp.MaximumBatchingWindowInSeconds;
15452
+ }
15453
+ if (resp.MaximumRetryAttempts !== void 0) {
15454
+ result["MaximumRetryAttempts"] = resp.MaximumRetryAttempts;
15455
+ }
15456
+ if (resp.BisectBatchOnFunctionError !== void 0) {
15457
+ result["BisectBatchOnFunctionError"] = resp.BisectBatchOnFunctionError;
15458
+ }
15459
+ if (resp.MaximumRecordAgeInSeconds !== void 0) {
15460
+ result["MaximumRecordAgeInSeconds"] = resp.MaximumRecordAgeInSeconds;
15461
+ }
15462
+ if (resp.ParallelizationFactor !== void 0) {
15463
+ result["ParallelizationFactor"] = resp.ParallelizationFactor;
15464
+ }
15465
+ if (resp.FilterCriteria !== void 0)
15466
+ result["FilterCriteria"] = resp.FilterCriteria;
15467
+ if (resp.DestinationConfig !== void 0) {
15468
+ result["DestinationConfig"] = resp.DestinationConfig;
15469
+ }
15470
+ if (resp.TumblingWindowInSeconds !== void 0) {
15471
+ result["TumblingWindowInSeconds"] = resp.TumblingWindowInSeconds;
15472
+ }
15473
+ if (resp.FunctionResponseTypes !== void 0 && resp.FunctionResponseTypes.length > 0) {
15474
+ result["FunctionResponseTypes"] = [...resp.FunctionResponseTypes];
15475
+ }
15476
+ if (resp.SourceAccessConfigurations !== void 0 && resp.SourceAccessConfigurations.length > 0) {
15477
+ result["SourceAccessConfigurations"] = resp.SourceAccessConfigurations;
15478
+ }
15479
+ if (resp.SelfManagedEventSource !== void 0) {
15480
+ result["SelfManagedEventSource"] = resp.SelfManagedEventSource;
15481
+ }
15482
+ if (resp.SelfManagedKafkaEventSourceConfig !== void 0) {
15483
+ result["SelfManagedKafkaEventSourceConfig"] = resp.SelfManagedKafkaEventSourceConfig;
15484
+ }
15485
+ if (resp.AmazonManagedKafkaEventSourceConfig !== void 0) {
15486
+ result["AmazonManagedKafkaEventSourceConfig"] = resp.AmazonManagedKafkaEventSourceConfig;
15487
+ }
15488
+ if (resp.DocumentDBEventSourceConfig !== void 0) {
15489
+ result["DocumentDBEventSourceConfig"] = resp.DocumentDBEventSourceConfig;
15490
+ }
15491
+ if (resp.ScalingConfig !== void 0)
15492
+ result["ScalingConfig"] = resp.ScalingConfig;
15493
+ if (resp.State !== void 0) {
15494
+ const enabled = resp.State === "Enabled" || resp.State === "Enabling" || resp.State === "Updating";
15495
+ result["Enabled"] = enabled;
15496
+ }
15497
+ return result;
15498
+ }
15058
15499
  /**
15059
15500
  * Adopt an existing Lambda event source mapping into cdkd state.
15060
15501
  *
@@ -15223,6 +15664,57 @@ var LambdaLayerVersionProvider = class {
15223
15664
  );
15224
15665
  }
15225
15666
  }
15667
+ /**
15668
+ * Read the AWS-current Lambda layer version configuration in CFn-property
15669
+ * shape.
15670
+ *
15671
+ * Issues `GetLayerVersionByArn` (the physical id is the version ARN) and
15672
+ * surfaces `LayerName`, `Description`, `CompatibleRuntimes`,
15673
+ * `CompatibleArchitectures`, and `LicenseInfo`. AWS-managed fields
15674
+ * (`Version`, `CreatedDate`, `LayerVersionArn`, `LayerArn`,
15675
+ * `Content.CodeSize`, `Content.CodeSha256`) are filtered at the wire
15676
+ * layer.
15677
+ *
15678
+ * `Content` is intentionally omitted: like Lambda function `Code`, the
15679
+ * `GetLayerVersionByArn` response contains a pre-signed S3 URL for the
15680
+ * deployed content, not the asset hash cdkd state stored. The two could
15681
+ * never match, so excluding it avoids a guaranteed false-positive.
15682
+ *
15683
+ * `LayerName` is derived from the ARN tail when not surfaced directly:
15684
+ * the version ARN format is
15685
+ * `arn:aws:lambda:<region>:<account>:layer:<name>:<version>`.
15686
+ *
15687
+ * Returns `undefined` when the layer version is gone
15688
+ * (`ResourceNotFoundException`).
15689
+ */
15690
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
15691
+ let resp;
15692
+ try {
15693
+ resp = await this.lambdaClient.send(new GetLayerVersionByArnCommand({ Arn: physicalId }));
15694
+ } catch (err) {
15695
+ if (err instanceof ResourceNotFoundException5)
15696
+ return void 0;
15697
+ throw err;
15698
+ }
15699
+ const result = {};
15700
+ const arnParts = physicalId.split(":");
15701
+ if (arnParts.length >= 7 && arnParts[6]) {
15702
+ result["LayerName"] = arnParts[6];
15703
+ }
15704
+ if (resp.Description !== void 0 && resp.Description !== "") {
15705
+ result["Description"] = resp.Description;
15706
+ }
15707
+ if (resp.CompatibleRuntimes !== void 0 && resp.CompatibleRuntimes.length > 0) {
15708
+ result["CompatibleRuntimes"] = [...resp.CompatibleRuntimes];
15709
+ }
15710
+ if (resp.CompatibleArchitectures !== void 0 && resp.CompatibleArchitectures.length > 0) {
15711
+ result["CompatibleArchitectures"] = [...resp.CompatibleArchitectures];
15712
+ }
15713
+ if (resp.LicenseInfo !== void 0 && resp.LicenseInfo !== "") {
15714
+ result["LicenseInfo"] = resp.LicenseInfo;
15715
+ }
15716
+ return result;
15717
+ }
15226
15718
  /**
15227
15719
  * Adopt an existing Lambda layer version into cdkd state.
15228
15720
  *
@@ -17900,7 +18392,10 @@ import {
17900
18392
  CreateVpcCommand,
17901
18393
  DeleteVpcCommand,
17902
18394
  ModifyVpcAttributeCommand,
18395
+ DescribeVpcAttributeCommand,
17903
18396
  DescribeVpcsCommand as DescribeVpcsCommand2,
18397
+ DescribeInternetGatewaysCommand,
18398
+ DescribeRouteTablesCommand as DescribeRouteTablesCommand2,
17904
18399
  CreateSubnetCommand,
17905
18400
  DeleteSubnetCommand,
17906
18401
  CreateInternetGatewayCommand,
@@ -20060,6 +20555,223 @@ var EC2Provider = class {
20060
20555
  throw error;
20061
20556
  }
20062
20557
  }
20558
+ /**
20559
+ * Read the AWS-current EC2 networking resource configuration in
20560
+ * CFn-property shape.
20561
+ *
20562
+ * Supported types (highest-value drift coverage):
20563
+ * - **AWS::EC2::VPC**: `DescribeVpcs` for `CidrBlock` + `InstanceTenancy`;
20564
+ * `DescribeVpcAttribute(enableDnsHostnames|enableDnsSupport)` for the
20565
+ * DNS booleans (CFn defaults: hostnames=false, support=true — we only
20566
+ * surface them if AWS reports them, so the comparator's "key-absent
20567
+ * never drifts" rule applies cleanly to state without these keys).
20568
+ * - **AWS::EC2::Subnet**: `DescribeSubnets` for `VpcId`, `CidrBlock`,
20569
+ * `AvailabilityZone`, `MapPublicIpOnLaunch`.
20570
+ * - **AWS::EC2::InternetGateway**: `DescribeInternetGateways` for
20571
+ * existence verification. The provider only handles `Tags`, which is
20572
+ * out of scope for v1 drift.
20573
+ * - **AWS::EC2::NatGateway**: `DescribeNatGateways` for `SubnetId`,
20574
+ * `AllocationId`, `ConnectivityType`, `PrivateIpAddress`.
20575
+ * - **AWS::EC2::RouteTable**: `DescribeRouteTables` for `VpcId`.
20576
+ * - **AWS::EC2::SecurityGroup**: `DescribeSecurityGroups` for
20577
+ * `GroupName`, `GroupDescription`, `VpcId`. Ingress / egress rules
20578
+ * are NOT surfaced — the CFn shape is rule-list-style, while AWS
20579
+ * returns IpPermissions in a different normalized form, and a
20580
+ * faithful reverse-mapping is out of scope for v1.
20581
+ * - **AWS::EC2::Instance**: `DescribeInstances` for `ImageId`,
20582
+ * `InstanceType`, `KeyName`, `SubnetId`. SecurityGroupIds /
20583
+ * BlockDeviceMappings shape-match is out of scope for v1.
20584
+ * - **AWS::EC2::NetworkAcl**: `DescribeNetworkAcls` for `VpcId`.
20585
+ *
20586
+ * Skipped (return `undefined`, falls through to the comparator's
20587
+ * "unsupported" outcome):
20588
+ * - **AWS::EC2::VPCGatewayAttachment**: physical id is
20589
+ * `IGW|VpcId`. The two ids are immutable inputs to the SDK call;
20590
+ * drift detection on this resource has no useful signal beyond
20591
+ * existence verification (which the user can do via the parent IGW
20592
+ * / VPC drift report).
20593
+ * - **AWS::EC2::Route**, **AWS::EC2::SubnetRouteTableAssociation**,
20594
+ * **AWS::EC2::SecurityGroupIngress**, **AWS::EC2::NetworkAclEntry**,
20595
+ * **AWS::EC2::SubnetNetworkAclAssociation**: rule / association
20596
+ * sub-resources whose AWS API surfaces them inside the parent's
20597
+ * list, not as standalone Get* responses. v1 drift coverage focuses
20598
+ * on top-level resources where the property shape comparison is
20599
+ * cheap and unambiguous; these sub-resources need a more elaborate
20600
+ * extraction layer that's out of scope for this PR.
20601
+ *
20602
+ * Returns `undefined` when the resource is gone (any `*NotFound` /
20603
+ * `Invalid*` error from the EC2 SDK matches `isNotFoundError`).
20604
+ */
20605
+ async readCurrentState(physicalId, logicalId, resourceType) {
20606
+ try {
20607
+ switch (resourceType) {
20608
+ case "AWS::EC2::VPC":
20609
+ return await this.readVpcCurrentState(physicalId);
20610
+ case "AWS::EC2::Subnet":
20611
+ return await this.readSubnetCurrentState(physicalId);
20612
+ case "AWS::EC2::InternetGateway":
20613
+ return await this.readInternetGatewayCurrentState(physicalId);
20614
+ case "AWS::EC2::NatGateway":
20615
+ return await this.readNatGatewayCurrentState(physicalId);
20616
+ case "AWS::EC2::RouteTable":
20617
+ return await this.readRouteTableCurrentState(physicalId);
20618
+ case "AWS::EC2::SecurityGroup":
20619
+ return await this.readSecurityGroupCurrentState(physicalId);
20620
+ case "AWS::EC2::Instance":
20621
+ return await this.readInstanceCurrentState(physicalId);
20622
+ case "AWS::EC2::NetworkAcl":
20623
+ return await this.readNetworkAclCurrentState(physicalId);
20624
+ default:
20625
+ this.logger.debug(
20626
+ `readCurrentState: unsupported resource type ${resourceType} for ${logicalId}`
20627
+ );
20628
+ return void 0;
20629
+ }
20630
+ } catch (err) {
20631
+ if (this.isNotFoundError(err))
20632
+ return void 0;
20633
+ throw err;
20634
+ }
20635
+ }
20636
+ async readVpcCurrentState(physicalId) {
20637
+ const resp = await this.ec2Client.send(new DescribeVpcsCommand2({ VpcIds: [physicalId] }));
20638
+ const vpc = resp.Vpcs?.[0];
20639
+ if (!vpc)
20640
+ return void 0;
20641
+ const result = {};
20642
+ if (vpc.CidrBlock !== void 0)
20643
+ result["CidrBlock"] = vpc.CidrBlock;
20644
+ if (vpc.InstanceTenancy !== void 0)
20645
+ result["InstanceTenancy"] = vpc.InstanceTenancy;
20646
+ try {
20647
+ const dnsHost = await this.ec2Client.send(
20648
+ new DescribeVpcAttributeCommand({ VpcId: physicalId, Attribute: "enableDnsHostnames" })
20649
+ );
20650
+ if (dnsHost.EnableDnsHostnames?.Value !== void 0) {
20651
+ result["EnableDnsHostnames"] = dnsHost.EnableDnsHostnames.Value;
20652
+ }
20653
+ } catch (err) {
20654
+ if (!this.isNotFoundError(err))
20655
+ throw err;
20656
+ }
20657
+ try {
20658
+ const dnsSupp = await this.ec2Client.send(
20659
+ new DescribeVpcAttributeCommand({ VpcId: physicalId, Attribute: "enableDnsSupport" })
20660
+ );
20661
+ if (dnsSupp.EnableDnsSupport?.Value !== void 0) {
20662
+ result["EnableDnsSupport"] = dnsSupp.EnableDnsSupport.Value;
20663
+ }
20664
+ } catch (err) {
20665
+ if (!this.isNotFoundError(err))
20666
+ throw err;
20667
+ }
20668
+ return result;
20669
+ }
20670
+ async readSubnetCurrentState(physicalId) {
20671
+ const resp = await this.ec2Client.send(new DescribeSubnetsCommand2({ SubnetIds: [physicalId] }));
20672
+ const subnet = resp.Subnets?.[0];
20673
+ if (!subnet)
20674
+ return void 0;
20675
+ const result = {};
20676
+ if (subnet.VpcId !== void 0)
20677
+ result["VpcId"] = subnet.VpcId;
20678
+ if (subnet.CidrBlock !== void 0)
20679
+ result["CidrBlock"] = subnet.CidrBlock;
20680
+ if (subnet.AvailabilityZone !== void 0) {
20681
+ result["AvailabilityZone"] = subnet.AvailabilityZone;
20682
+ }
20683
+ if (subnet.MapPublicIpOnLaunch !== void 0) {
20684
+ result["MapPublicIpOnLaunch"] = subnet.MapPublicIpOnLaunch;
20685
+ }
20686
+ return result;
20687
+ }
20688
+ async readInternetGatewayCurrentState(physicalId) {
20689
+ const resp = await this.ec2Client.send(
20690
+ new DescribeInternetGatewaysCommand({ InternetGatewayIds: [physicalId] })
20691
+ );
20692
+ const igw = resp.InternetGateways?.[0];
20693
+ if (!igw)
20694
+ return void 0;
20695
+ return {};
20696
+ }
20697
+ async readNatGatewayCurrentState(physicalId) {
20698
+ const resp = await this.ec2Client.send(
20699
+ new DescribeNatGatewaysCommand({ NatGatewayIds: [physicalId] })
20700
+ );
20701
+ const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
20702
+ if (!gw)
20703
+ return void 0;
20704
+ const result = {};
20705
+ if (gw.SubnetId !== void 0)
20706
+ result["SubnetId"] = gw.SubnetId;
20707
+ if (gw.ConnectivityType !== void 0)
20708
+ result["ConnectivityType"] = gw.ConnectivityType;
20709
+ const primary = gw.NatGatewayAddresses?.[0];
20710
+ if (primary?.AllocationId !== void 0)
20711
+ result["AllocationId"] = primary.AllocationId;
20712
+ if (primary?.PrivateIp !== void 0)
20713
+ result["PrivateIpAddress"] = primary.PrivateIp;
20714
+ return result;
20715
+ }
20716
+ async readRouteTableCurrentState(physicalId) {
20717
+ const resp = await this.ec2Client.send(
20718
+ new DescribeRouteTablesCommand2({ RouteTableIds: [physicalId] })
20719
+ );
20720
+ const rt = resp.RouteTables?.[0];
20721
+ if (!rt)
20722
+ return void 0;
20723
+ const result = {};
20724
+ if (rt.VpcId !== void 0)
20725
+ result["VpcId"] = rt.VpcId;
20726
+ return result;
20727
+ }
20728
+ async readSecurityGroupCurrentState(physicalId) {
20729
+ const resp = await this.ec2Client.send(
20730
+ new DescribeSecurityGroupsCommand2({ GroupIds: [physicalId] })
20731
+ );
20732
+ const sg = resp.SecurityGroups?.[0];
20733
+ if (!sg)
20734
+ return void 0;
20735
+ const result = {};
20736
+ if (sg.GroupName !== void 0)
20737
+ result["GroupName"] = sg.GroupName;
20738
+ if (sg.Description !== void 0)
20739
+ result["GroupDescription"] = sg.Description;
20740
+ if (sg.VpcId !== void 0)
20741
+ result["VpcId"] = sg.VpcId;
20742
+ return result;
20743
+ }
20744
+ async readInstanceCurrentState(physicalId) {
20745
+ const resp = await this.ec2Client.send(
20746
+ new DescribeInstancesCommand({ InstanceIds: [physicalId] })
20747
+ );
20748
+ const instance = resp.Reservations?.[0]?.Instances?.[0];
20749
+ if (!instance || instance.State?.Name === "terminated" || instance.State?.Name === "shutting-down") {
20750
+ return void 0;
20751
+ }
20752
+ const result = {};
20753
+ if (instance.ImageId !== void 0)
20754
+ result["ImageId"] = instance.ImageId;
20755
+ if (instance.InstanceType !== void 0)
20756
+ result["InstanceType"] = instance.InstanceType;
20757
+ if (instance.KeyName !== void 0)
20758
+ result["KeyName"] = instance.KeyName;
20759
+ if (instance.SubnetId !== void 0)
20760
+ result["SubnetId"] = instance.SubnetId;
20761
+ return result;
20762
+ }
20763
+ async readNetworkAclCurrentState(physicalId) {
20764
+ const resp = await this.ec2Client.send(
20765
+ new DescribeNetworkAclsCommand({ NetworkAclIds: [physicalId] })
20766
+ );
20767
+ const acl = resp.NetworkAcls?.[0];
20768
+ if (!acl)
20769
+ return void 0;
20770
+ const result = {};
20771
+ if (acl.VpcId !== void 0)
20772
+ result["VpcId"] = acl.VpcId;
20773
+ return result;
20774
+ }
20063
20775
  async verifyExplicit(resourceType, physicalId) {
20064
20776
  try {
20065
20777
  switch (resourceType) {
@@ -22542,6 +23254,23 @@ function pascalToCamelCaseKeys(value) {
22542
23254
  }
22543
23255
  return value;
22544
23256
  }
23257
+ function camelToPascalCaseKeys(value) {
23258
+ if (value === null || value === void 0) {
23259
+ return value;
23260
+ }
23261
+ if (Array.isArray(value)) {
23262
+ return value.map(camelToPascalCaseKeys);
23263
+ }
23264
+ if (typeof value === "object") {
23265
+ const result = {};
23266
+ for (const [key, val] of Object.entries(value)) {
23267
+ const pascalKey = key.charAt(0).toUpperCase() + key.slice(1);
23268
+ result[pascalKey] = camelToPascalCaseKeys(val);
23269
+ }
23270
+ return result;
23271
+ }
23272
+ return value;
23273
+ }
22545
23274
  var AgentCoreRuntimeProvider = class {
22546
23275
  client;
22547
23276
  logger = getLogger().child("AgentCoreRuntimeProvider");
@@ -22776,6 +23505,68 @@ var AgentCoreRuntimeProvider = class {
22776
23505
  }
22777
23506
  throw new Error(`Unsupported attribute: ${attributeName} for AWS::BedrockAgentCore::Runtime`);
22778
23507
  }
23508
+ /**
23509
+ * Read the AWS-current BedrockAgentCore Runtime configuration in
23510
+ * CFn-property shape.
23511
+ *
23512
+ * Issues `GetAgentRuntime` (the physical id is the runtime id) and
23513
+ * surfaces the keys `create()` accepts. The SDK returns camelCase keys
23514
+ * (`agentRuntimeName`, `roleArn`, `agentRuntimeArtifact`, etc.); we
23515
+ * re-shape back to PascalCase via `camelToPascalCaseKeys` so the
23516
+ * comparator matches cdkd state.
23517
+ *
23518
+ * `ProtocolConfiguration` parity: `create()` accepts a CFn-style string
23519
+ * (`"HTTP"`) and converts it to `{serverProtocol: "HTTP"}` for the SDK.
23520
+ * The SDK returns the object form. We surface the object form here; if
23521
+ * cdkd state holds the original string the comparator will report drift
23522
+ * — users can inspect and dismiss this case manually. (A more elaborate
23523
+ * shape negotiation belongs in a follow-up that knows about both forms.)
23524
+ *
23525
+ * `ClientToken` is omitted: AWS does not surface it back via
23526
+ * `GetAgentRuntime` (it's an idempotency token only meaningful at create
23527
+ * time).
23528
+ *
23529
+ * Returns `undefined` when the runtime is gone
23530
+ * (`ResourceNotFoundException`).
23531
+ */
23532
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
23533
+ let resp;
23534
+ try {
23535
+ resp = await this.client.send(new GetAgentRuntimeCommand({ agentRuntimeId: physicalId }));
23536
+ } catch (err) {
23537
+ if (err instanceof ResourceNotFoundException11)
23538
+ return void 0;
23539
+ throw err;
23540
+ }
23541
+ const result = {};
23542
+ if (resp.agentRuntimeName !== void 0) {
23543
+ result["AgentRuntimeName"] = resp.agentRuntimeName;
23544
+ }
23545
+ if (resp.roleArn !== void 0)
23546
+ result["RoleArn"] = resp.roleArn;
23547
+ if (resp.agentRuntimeArtifact !== void 0) {
23548
+ result["AgentRuntimeArtifact"] = camelToPascalCaseKeys(resp.agentRuntimeArtifact);
23549
+ }
23550
+ if (resp.networkConfiguration !== void 0) {
23551
+ result["NetworkConfiguration"] = camelToPascalCaseKeys(resp.networkConfiguration);
23552
+ }
23553
+ if (resp.description !== void 0 && resp.description !== "") {
23554
+ result["Description"] = resp.description;
23555
+ }
23556
+ if (resp.authorizerConfiguration !== void 0) {
23557
+ result["AuthorizerConfiguration"] = camelToPascalCaseKeys(resp.authorizerConfiguration);
23558
+ }
23559
+ if (resp.protocolConfiguration !== void 0) {
23560
+ result["ProtocolConfiguration"] = camelToPascalCaseKeys(resp.protocolConfiguration);
23561
+ }
23562
+ if (resp.lifecycleConfiguration !== void 0) {
23563
+ result["LifecycleConfiguration"] = camelToPascalCaseKeys(resp.lifecycleConfiguration);
23564
+ }
23565
+ if (resp.environmentVariables !== void 0) {
23566
+ result["EnvironmentVariables"] = resp.environmentVariables;
23567
+ }
23568
+ return result;
23569
+ }
22779
23570
  /**
22780
23571
  * Adopt an existing BedrockAgentCore Runtime into cdkd state.
22781
23572
  *
@@ -33311,6 +34102,49 @@ var S3VectorsProvider = class {
33311
34102
  nextToken = listResult.nextToken;
33312
34103
  } while (nextToken);
33313
34104
  }
34105
+ /**
34106
+ * Read the AWS-current S3 Vector Bucket configuration in CFn-property
34107
+ * shape.
34108
+ *
34109
+ * Issues `GetVectorBucket` for the bucket name (the physical id) and
34110
+ * surfaces `VectorBucketName` and `EncryptionConfiguration` (re-shaping
34111
+ * the camelCase SDK response back to PascalCase CFn property names —
34112
+ * `sseType` → `SSEType`, `kmsKeyArn` → `KMSKeyArn`).
34113
+ *
34114
+ * Returns `undefined` when the bucket is gone (`NotFoundException` /
34115
+ * `NoSuchVectorBucket`).
34116
+ */
34117
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
34118
+ let resp;
34119
+ try {
34120
+ resp = await this.getClient().send(
34121
+ new GetVectorBucketCommand({ vectorBucketName: physicalId })
34122
+ );
34123
+ } catch (err) {
34124
+ if (this.isNotFoundError(err))
34125
+ return void 0;
34126
+ throw err;
34127
+ }
34128
+ const result = {};
34129
+ const bucket = resp.vectorBucket;
34130
+ if (bucket?.vectorBucketName !== void 0) {
34131
+ result["VectorBucketName"] = bucket.vectorBucketName;
34132
+ } else {
34133
+ result["VectorBucketName"] = physicalId;
34134
+ }
34135
+ if (bucket?.encryptionConfiguration) {
34136
+ const enc = {};
34137
+ if (bucket.encryptionConfiguration.sseType !== void 0) {
34138
+ enc["SSEType"] = bucket.encryptionConfiguration.sseType;
34139
+ }
34140
+ if (bucket.encryptionConfiguration.kmsKeyArn !== void 0) {
34141
+ enc["KMSKeyArn"] = bucket.encryptionConfiguration.kmsKeyArn;
34142
+ }
34143
+ if (Object.keys(enc).length > 0)
34144
+ result["EncryptionConfiguration"] = enc;
34145
+ }
34146
+ return result;
34147
+ }
33314
34148
  /**
33315
34149
  * Adopt an existing S3 Vector Bucket into cdkd state.
33316
34150
  *
@@ -33580,6 +34414,48 @@ var S3DirectoryBucketProvider = class {
33580
34414
  continuationToken = listResponse.IsTruncated ? listResponse.NextContinuationToken : void 0;
33581
34415
  } while (continuationToken);
33582
34416
  }
34417
+ /**
34418
+ * Read the AWS-current S3 Express Directory Bucket configuration in
34419
+ * CFn-property shape.
34420
+ *
34421
+ * Issues `HeadBucket` to verify existence and surfaces `BucketName`
34422
+ * (the physicalId). `DataRedundancy` and `LocationName` are not exposed
34423
+ * by any cheap S3 Express API — the only way to inspect them is by
34424
+ * parsing the bucket name's `--<az-id>--x-s3` suffix, which is best
34425
+ * effort. We surface them when they are recoverable from the bucket
34426
+ * name to give the comparator a chance to detect mismatches.
34427
+ *
34428
+ * `--<az-id>--x-s3` suffix parsing: directory bucket names follow the
34429
+ * format `<base>--<az-id>--x-s3`, e.g.
34430
+ * `my-bucket--use1-az1--x-s3`. We don't reverse the AZ-ID -> AZ-name
34431
+ * mapping here (that would require a per-call EC2 `DescribeAvailabilityZones`
34432
+ * round-trip); state's `LocationName` is `us-east-1a--x-s3`-style,
34433
+ * while the bucket name carries the AZ-ID `use1-az1`. Cross-region
34434
+ * mapping is too expensive for v1 — we omit `LocationName` from the
34435
+ * snapshot and rely on the comparator's "key absent in state never
34436
+ * drifts" rule to no-op against state.
34437
+ *
34438
+ * Returns `undefined` when the bucket is gone (`HeadBucket` returns
34439
+ * `NotFound` / `NoSuchBucket`).
34440
+ */
34441
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
34442
+ try {
34443
+ await this.s3Client.send(new HeadBucketCommand4({ Bucket: physicalId }));
34444
+ } catch (err) {
34445
+ const e = err;
34446
+ if (e.name === "NotFound" || e.name === "NoSuchBucket" || e.name === "BucketNotFound") {
34447
+ return void 0;
34448
+ }
34449
+ throw err;
34450
+ }
34451
+ const result = {
34452
+ BucketName: physicalId
34453
+ };
34454
+ if (physicalId.endsWith("--x-s3")) {
34455
+ result["DataRedundancy"] = "SingleAvailabilityZone";
34456
+ }
34457
+ return result;
34458
+ }
33583
34459
  /**
33584
34460
  * Adopt an existing S3 Express Directory Bucket into cdkd state.
33585
34461
  *
@@ -33984,6 +34860,97 @@ var S3TablesProvider = class {
33984
34860
  );
33985
34861
  }
33986
34862
  }
34863
+ // ─── readCurrentState dispatch ───────────────────────────────────
34864
+ /**
34865
+ * Read the AWS-current S3 Tables resource configuration in CFn-property
34866
+ * shape.
34867
+ *
34868
+ * - **AWS::S3Tables::TableBucket**: `GetTableBucket` for the ARN; we
34869
+ * surface `TableBucketName` (the only mutable cdkd-managed property).
34870
+ * - **AWS::S3Tables::Namespace**: parses `tableBucketARN|namespace`
34871
+ * from physical id and surfaces `TableBucketARN` and `Namespace`
34872
+ * (as a `string[]` with one entry, matching `create()`'s shape).
34873
+ * No GetNamespace call — the physical id IS the source of truth and
34874
+ * AWS surfaces no additional managed fields cdkd cares about.
34875
+ * - **AWS::S3Tables::Table**: parses `tableBucketARN|namespace|name`
34876
+ * from physical id, calls `GetTable` to verify existence and recover
34877
+ * `format`, surfaces `TableBucketARN`, `Namespace` (string), `Name`,
34878
+ * `Format`.
34879
+ *
34880
+ * Returns `undefined` when the resource is gone (`NotFoundException`).
34881
+ */
34882
+ async readCurrentState(physicalId, logicalId, resourceType) {
34883
+ switch (resourceType) {
34884
+ case "AWS::S3Tables::TableBucket":
34885
+ return this.readTableBucketCurrentState(physicalId);
34886
+ case "AWS::S3Tables::Namespace":
34887
+ return this.readNamespaceCurrentState(physicalId);
34888
+ case "AWS::S3Tables::Table":
34889
+ return this.readTableCurrentState(physicalId);
34890
+ default:
34891
+ this.logger.debug(
34892
+ `readCurrentState: unsupported resource type ${resourceType} for ${logicalId}`
34893
+ );
34894
+ return void 0;
34895
+ }
34896
+ }
34897
+ async readTableBucketCurrentState(physicalId) {
34898
+ let bucket;
34899
+ try {
34900
+ const resp = await this.getClient().send(
34901
+ new GetTableBucketCommand({ tableBucketARN: physicalId })
34902
+ );
34903
+ bucket = resp;
34904
+ } catch (err) {
34905
+ if (err instanceof NotFoundException6)
34906
+ return void 0;
34907
+ throw err;
34908
+ }
34909
+ const result = {};
34910
+ if (bucket.name !== void 0)
34911
+ result["TableBucketName"] = bucket.name;
34912
+ return result;
34913
+ }
34914
+ // eslint-disable-next-line @typescript-eslint/require-await -- structural; physical id is the source of truth
34915
+ async readNamespaceCurrentState(physicalId) {
34916
+ const [tableBucketARN, namespaceName] = physicalId.split("|");
34917
+ if (!tableBucketARN || !namespaceName)
34918
+ return void 0;
34919
+ return {
34920
+ TableBucketARN: tableBucketARN,
34921
+ Namespace: [namespaceName]
34922
+ };
34923
+ }
34924
+ async readTableCurrentState(physicalId) {
34925
+ const parts = physicalId.split("|");
34926
+ if (parts.length < 3)
34927
+ return void 0;
34928
+ const [tableBucketARN, namespace, name] = parts;
34929
+ if (!tableBucketARN || !namespace || !name)
34930
+ return void 0;
34931
+ let resp;
34932
+ try {
34933
+ resp = await this.getClient().send(
34934
+ new GetTableCommand2({
34935
+ tableBucketARN,
34936
+ namespace,
34937
+ name
34938
+ })
34939
+ );
34940
+ } catch (err) {
34941
+ if (err instanceof NotFoundException6)
34942
+ return void 0;
34943
+ throw err;
34944
+ }
34945
+ const result = {
34946
+ TableBucketARN: tableBucketARN,
34947
+ Namespace: namespace,
34948
+ Name: resp.name ?? name
34949
+ };
34950
+ if (resp.format !== void 0)
34951
+ result["Format"] = resp.format;
34952
+ return result;
34953
+ }
33987
34954
  // ─── Import dispatch ──────────────────────────────────────────────
33988
34955
  /**
33989
34956
  * Adopt an existing S3 Tables resource into cdkd state.
@@ -40389,7 +41356,7 @@ function reorderArgs(argv) {
40389
41356
  }
40390
41357
  async function main() {
40391
41358
  const program = new Command14();
40392
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.40.0");
41359
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.41.0");
40393
41360
  program.addCommand(createBootstrapCommand());
40394
41361
  program.addCommand(createSynthCommand());
40395
41362
  program.addCommand(createListCommand());