@go-to-k/cdkd 0.61.0 → 0.63.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
@@ -30482,22 +30482,42 @@ import {
30482
30482
  PutBucketOwnershipControlsCommand,
30483
30483
  PutBucketNotificationConfigurationCommand,
30484
30484
  PutBucketCorsCommand,
30485
+ DeleteBucketCorsCommand,
30485
30486
  PutBucketLifecycleConfigurationCommand,
30487
+ DeleteBucketLifecycleCommand,
30486
30488
  PutPublicAccessBlockCommand,
30487
30489
  PutBucketEncryptionCommand as PutBucketEncryptionCommand2,
30488
30490
  PutBucketLoggingCommand,
30489
30491
  PutBucketWebsiteCommand,
30492
+ DeleteBucketWebsiteCommand,
30490
30493
  PutBucketAccelerateConfigurationCommand,
30491
30494
  PutBucketMetricsConfigurationCommand,
30495
+ DeleteBucketMetricsConfigurationCommand,
30492
30496
  PutBucketAnalyticsConfigurationCommand,
30497
+ DeleteBucketAnalyticsConfigurationCommand,
30493
30498
  PutBucketIntelligentTieringConfigurationCommand,
30499
+ DeleteBucketIntelligentTieringConfigurationCommand,
30494
30500
  PutBucketInventoryConfigurationCommand,
30501
+ DeleteBucketInventoryConfigurationCommand,
30495
30502
  PutBucketReplicationCommand,
30503
+ DeleteBucketReplicationCommand,
30496
30504
  PutObjectLockConfigurationCommand,
30497
30505
  GetBucketEncryptionCommand,
30498
30506
  GetBucketTaggingCommand,
30499
30507
  GetBucketVersioningCommand,
30500
30508
  GetPublicAccessBlockCommand,
30509
+ GetBucketLifecycleConfigurationCommand,
30510
+ GetBucketCorsCommand,
30511
+ GetBucketWebsiteCommand,
30512
+ GetBucketLoggingCommand,
30513
+ GetBucketNotificationConfigurationCommand,
30514
+ GetBucketReplicationCommand,
30515
+ GetObjectLockConfigurationCommand,
30516
+ GetBucketAccelerateConfigurationCommand,
30517
+ ListBucketMetricsConfigurationsCommand,
30518
+ ListBucketAnalyticsConfigurationsCommand,
30519
+ ListBucketIntelligentTieringConfigurationsCommand,
30520
+ ListBucketInventoryConfigurationsCommand,
30501
30521
  NoSuchBucket,
30502
30522
  ListObjectVersionsCommand,
30503
30523
  DeleteObjectsCommand
@@ -30834,6 +30854,16 @@ var S3BucketProvider = class {
30834
30854
  * SDK: PutBucketLogging with BucketLoggingStatus.LoggingEnabled
30835
30855
  */
30836
30856
  async applyLoggingConfiguration(bucketName, loggingConfig) {
30857
+ if (!loggingConfig || !loggingConfig["DestinationBucketName"]) {
30858
+ await this.s3Client.send(
30859
+ new PutBucketLoggingCommand({
30860
+ Bucket: bucketName,
30861
+ BucketLoggingStatus: {}
30862
+ })
30863
+ );
30864
+ this.logger.debug(`Cleared logging configuration on bucket ${bucketName}`);
30865
+ return;
30866
+ }
30837
30867
  await this.s3Client.send(
30838
30868
  new PutBucketLoggingCommand({
30839
30869
  Bucket: bucketName,
@@ -30919,6 +30949,77 @@ var S3BucketProvider = class {
30919
30949
  );
30920
30950
  this.logger.debug(`Applied accelerate configuration to bucket ${bucketName}`);
30921
30951
  }
30952
+ /**
30953
+ * Apply notification configuration (full-replace via PutBucketNotificationConfiguration)
30954
+ *
30955
+ * CFn property: NotificationConfiguration with TopicConfigurations,
30956
+ * QueueConfigurations, LambdaConfigurations, EventBridgeConfiguration.
30957
+ * SDK uses the same structure (PutBucketNotificationConfiguration replaces
30958
+ * the entire notification configuration in one call).
30959
+ */
30960
+ async applyNotificationConfiguration(bucketName, notifConfig) {
30961
+ const cfg = {};
30962
+ if (notifConfig) {
30963
+ const topics = notifConfig["TopicConfigurations"];
30964
+ if (topics && Array.isArray(topics) && topics.length > 0) {
30965
+ cfg.TopicConfigurations = topics.map((t) => ({
30966
+ Id: t["Id"],
30967
+ TopicArn: t["Topic"] ?? t["TopicArn"],
30968
+ Events: t["Event"] !== void 0 ? [t["Event"]] : t["Events"],
30969
+ Filter: this.cfnNotifFilterToSdk(t["Filter"])
30970
+ }));
30971
+ }
30972
+ const queues = notifConfig["QueueConfigurations"];
30973
+ if (queues && Array.isArray(queues) && queues.length > 0) {
30974
+ cfg.QueueConfigurations = queues.map((q) => ({
30975
+ Id: q["Id"],
30976
+ QueueArn: q["Queue"] ?? q["QueueArn"],
30977
+ Events: q["Event"] !== void 0 ? [q["Event"]] : q["Events"],
30978
+ Filter: this.cfnNotifFilterToSdk(q["Filter"])
30979
+ }));
30980
+ }
30981
+ const lambdas = notifConfig["LambdaConfigurations"];
30982
+ if (lambdas && Array.isArray(lambdas) && lambdas.length > 0) {
30983
+ cfg.LambdaFunctionConfigurations = lambdas.map((l) => ({
30984
+ Id: l["Id"],
30985
+ LambdaFunctionArn: l["Function"] ?? l["LambdaFunctionArn"],
30986
+ Events: l["Event"] !== void 0 ? [l["Event"]] : l["Events"],
30987
+ Filter: this.cfnNotifFilterToSdk(l["Filter"])
30988
+ }));
30989
+ }
30990
+ const eb = notifConfig["EventBridgeConfiguration"];
30991
+ if (eb !== void 0) {
30992
+ cfg.EventBridgeConfiguration = {};
30993
+ }
30994
+ }
30995
+ await this.s3Client.send(
30996
+ new PutBucketNotificationConfigurationCommand({
30997
+ Bucket: bucketName,
30998
+ NotificationConfiguration: cfg
30999
+ })
31000
+ );
31001
+ this.logger.debug(`Applied notification configuration to bucket ${bucketName}`);
31002
+ }
31003
+ /**
31004
+ * Convert CFn notification Filter ({ S3Key: { Rules: [{ Name, Value }] } })
31005
+ * to SDK NotificationConfigurationFilter.Key.FilterRules.
31006
+ */
31007
+ cfnNotifFilterToSdk(filter) {
31008
+ if (!filter || typeof filter !== "object")
31009
+ return void 0;
31010
+ const f = filter;
31011
+ const s3Key = f["S3Key"];
31012
+ if (!s3Key)
31013
+ return void 0;
31014
+ const rules = s3Key["Rules"];
31015
+ if (!rules || !Array.isArray(rules) || rules.length === 0)
31016
+ return void 0;
31017
+ return {
31018
+ Key: {
31019
+ FilterRules: rules.filter((r) => r.Name !== void 0 && r.Value !== void 0).map((r) => ({ Name: r.Name, Value: r.Value }))
31020
+ }
31021
+ };
31022
+ }
30922
31023
  /**
30923
31024
  * Apply metrics configurations
30924
31025
  *
@@ -31214,20 +31315,226 @@ var S3BucketProvider = class {
31214
31315
  );
31215
31316
  this.logger.debug(`Applied ownership controls to bucket ${bucketName}`);
31216
31317
  }
31318
+ const publicAccessBlock = properties["PublicAccessBlockConfiguration"];
31319
+ if (publicAccessBlock) {
31320
+ await this.applyPublicAccessBlockConfiguration(bucketName, publicAccessBlock);
31321
+ }
31322
+ const bucketEncryption = properties["BucketEncryption"];
31323
+ if (bucketEncryption?.ServerSideEncryptionConfiguration && Array.isArray(bucketEncryption.ServerSideEncryptionConfiguration) && bucketEncryption.ServerSideEncryptionConfiguration.length > 0) {
31324
+ await this.applyBucketEncryption(bucketName, bucketEncryption);
31325
+ }
31326
+ }
31327
+ /**
31328
+ * Diff CFn-shape sub-config values between previous and new state.
31329
+ *
31330
+ * Three transitions:
31331
+ * - undefined -> defined (value differs from previous, OR previous undefined): Put
31332
+ * - defined -> undefined: Delete
31333
+ * - defined -> defined (different): Put
31334
+ * - unchanged: skip
31335
+ *
31336
+ * For the array-shaped configs (Metrics / Analytics / IntelligentTier /
31337
+ * Inventory) this is per-id rather than per-config — see the dedicated
31338
+ * helpers below.
31339
+ */
31340
+ async diffSubConfig(_bucketName, oldVal, newVal, onPut, onDelete) {
31341
+ const same = JSON.stringify(oldVal ?? null) === JSON.stringify(newVal ?? null);
31342
+ if (same)
31343
+ return;
31344
+ if (newVal === void 0 || newVal === null) {
31345
+ await onDelete();
31346
+ return;
31347
+ }
31348
+ await onPut(newVal);
31349
+ }
31350
+ /**
31351
+ * Per-id diff for the four array-shaped configs (MetricsConfigurations,
31352
+ * AnalyticsConfigurations, IntelligentTieringConfigurations,
31353
+ * InventoryConfigurations). Each AWS API operates on one config per
31354
+ * (bucket, id) pair: Put-on-add or Put-on-change, Delete-on-removed.
31355
+ */
31356
+ async diffArrayConfigById(_bucketName, oldArr, newArr, onPut, onDelete) {
31357
+ const oldById = /* @__PURE__ */ new Map();
31358
+ for (const c of oldArr ?? []) {
31359
+ const id = c["Id"];
31360
+ if (id)
31361
+ oldById.set(id, c);
31362
+ }
31363
+ const newById = /* @__PURE__ */ new Map();
31364
+ for (const c of newArr ?? []) {
31365
+ const id = c["Id"];
31366
+ if (id)
31367
+ newById.set(id, c);
31368
+ }
31369
+ for (const [id, cfg] of newById) {
31370
+ const old = oldById.get(id);
31371
+ if (!old || JSON.stringify(old) !== JSON.stringify(cfg)) {
31372
+ await onPut(id, cfg);
31373
+ }
31374
+ }
31375
+ for (const id of oldById.keys()) {
31376
+ if (!newById.has(id)) {
31377
+ await onDelete(id);
31378
+ }
31379
+ }
31380
+ }
31381
+ /**
31382
+ * Apply the diff between previous and new sub-configs, issuing Put / Delete
31383
+ * SDK calls only for differing keys. Called from `update()`.
31384
+ *
31385
+ * Versioning / PublicAccessBlock / Tags / OwnershipControls / BucketEncryption
31386
+ * stay on `applyConfiguration` (the unconditional always-PUT path) because
31387
+ * their AWS APIs don't have a clean "delete" counterpart and they
31388
+ * round-trip safely as no-ops when state == AWS-current. The 12 sub-configs
31389
+ * below DO have proper Put/Delete pairs so the diff path is preferable.
31390
+ */
31391
+ async applySubConfigDiffs(bucketName, properties, previousProperties) {
31392
+ await this.diffSubConfig(
31393
+ bucketName,
31394
+ previousProperties["LifecycleConfiguration"],
31395
+ properties["LifecycleConfiguration"],
31396
+ async (cfg) => {
31397
+ if (!cfg.Rules || !Array.isArray(cfg.Rules) || cfg.Rules.length === 0)
31398
+ return;
31399
+ await this.applyLifecycleConfiguration(bucketName, cfg);
31400
+ },
31401
+ async () => {
31402
+ await this.s3Client.send(new DeleteBucketLifecycleCommand({ Bucket: bucketName }));
31403
+ this.logger.debug(`Deleted lifecycle configuration on bucket ${bucketName}`);
31404
+ }
31405
+ );
31406
+ await this.diffSubConfig(
31407
+ bucketName,
31408
+ previousProperties["CorsConfiguration"],
31409
+ properties["CorsConfiguration"],
31410
+ async (cfg) => {
31411
+ if (!cfg.CorsRules || !Array.isArray(cfg.CorsRules) || cfg.CorsRules.length === 0)
31412
+ return;
31413
+ await this.applyCorsConfiguration(bucketName, cfg);
31414
+ },
31415
+ async () => {
31416
+ await this.s3Client.send(new DeleteBucketCorsCommand({ Bucket: bucketName }));
31417
+ this.logger.debug(`Deleted CORS configuration on bucket ${bucketName}`);
31418
+ }
31419
+ );
31420
+ await this.diffSubConfig(
31421
+ bucketName,
31422
+ previousProperties["WebsiteConfiguration"],
31423
+ properties["WebsiteConfiguration"],
31424
+ async (cfg) => this.applyWebsiteConfiguration(bucketName, cfg),
31425
+ async () => {
31426
+ await this.s3Client.send(new DeleteBucketWebsiteCommand({ Bucket: bucketName }));
31427
+ this.logger.debug(`Deleted website configuration on bucket ${bucketName}`);
31428
+ }
31429
+ );
31430
+ await this.diffSubConfig(
31431
+ bucketName,
31432
+ previousProperties["LoggingConfiguration"],
31433
+ properties["LoggingConfiguration"],
31434
+ async (cfg) => this.applyLoggingConfiguration(bucketName, cfg),
31435
+ async () => this.applyLoggingConfiguration(bucketName, void 0)
31436
+ );
31437
+ await this.diffSubConfig(
31438
+ bucketName,
31439
+ previousProperties["NotificationConfiguration"],
31440
+ properties["NotificationConfiguration"],
31441
+ async (cfg) => this.applyNotificationConfiguration(bucketName, cfg),
31442
+ async () => this.applyNotificationConfiguration(bucketName, void 0)
31443
+ );
31444
+ await this.diffSubConfig(
31445
+ bucketName,
31446
+ previousProperties["ReplicationConfiguration"],
31447
+ properties["ReplicationConfiguration"],
31448
+ async (cfg) => this.applyReplicationConfiguration(bucketName, cfg),
31449
+ async () => {
31450
+ await this.s3Client.send(new DeleteBucketReplicationCommand({ Bucket: bucketName }));
31451
+ this.logger.debug(`Deleted replication configuration on bucket ${bucketName}`);
31452
+ }
31453
+ );
31454
+ await this.diffSubConfig(
31455
+ bucketName,
31456
+ previousProperties["ObjectLockConfiguration"],
31457
+ properties["ObjectLockConfiguration"],
31458
+ async (cfg) => this.applyObjectLockConfiguration(bucketName, cfg),
31459
+ async () => {
31460
+ await this.s3Client.send(
31461
+ new PutObjectLockConfigurationCommand({
31462
+ Bucket: bucketName,
31463
+ ObjectLockConfiguration: { ObjectLockEnabled: "Enabled" }
31464
+ })
31465
+ );
31466
+ this.logger.debug(`Cleared object lock rule on bucket ${bucketName}`);
31467
+ }
31468
+ );
31469
+ await this.diffSubConfig(
31470
+ bucketName,
31471
+ previousProperties["AccelerateConfiguration"],
31472
+ properties["AccelerateConfiguration"],
31473
+ async (cfg) => this.applyAccelerateConfiguration(bucketName, cfg),
31474
+ async () => this.applyAccelerateConfiguration(bucketName, { AccelerationStatus: "Suspended" })
31475
+ );
31476
+ await this.diffArrayConfigById(
31477
+ bucketName,
31478
+ previousProperties["MetricsConfigurations"],
31479
+ properties["MetricsConfigurations"],
31480
+ async (_id, cfg) => this.applyMetricsConfigurations(bucketName, [cfg]),
31481
+ async (id) => {
31482
+ await this.s3Client.send(
31483
+ new DeleteBucketMetricsConfigurationCommand({ Bucket: bucketName, Id: id })
31484
+ );
31485
+ this.logger.debug(`Deleted metrics configuration ${id} on bucket ${bucketName}`);
31486
+ }
31487
+ );
31488
+ await this.diffArrayConfigById(
31489
+ bucketName,
31490
+ previousProperties["AnalyticsConfigurations"],
31491
+ properties["AnalyticsConfigurations"],
31492
+ async (_id, cfg) => this.applyAnalyticsConfigurations(bucketName, [cfg]),
31493
+ async (id) => {
31494
+ await this.s3Client.send(
31495
+ new DeleteBucketAnalyticsConfigurationCommand({ Bucket: bucketName, Id: id })
31496
+ );
31497
+ this.logger.debug(`Deleted analytics configuration ${id} on bucket ${bucketName}`);
31498
+ }
31499
+ );
31500
+ await this.diffArrayConfigById(
31501
+ bucketName,
31502
+ previousProperties["IntelligentTieringConfigurations"],
31503
+ properties["IntelligentTieringConfigurations"],
31504
+ async (_id, cfg) => this.applyIntelligentTieringConfigurations(bucketName, [cfg]),
31505
+ async (id) => {
31506
+ await this.s3Client.send(
31507
+ new DeleteBucketIntelligentTieringConfigurationCommand({
31508
+ Bucket: bucketName,
31509
+ Id: id
31510
+ })
31511
+ );
31512
+ this.logger.debug(
31513
+ `Deleted intelligent tiering configuration ${id} on bucket ${bucketName}`
31514
+ );
31515
+ }
31516
+ );
31517
+ await this.diffArrayConfigById(
31518
+ bucketName,
31519
+ previousProperties["InventoryConfigurations"],
31520
+ properties["InventoryConfigurations"],
31521
+ async (_id, cfg) => this.applyInventoryConfigurations(bucketName, [cfg]),
31522
+ async (id) => {
31523
+ await this.s3Client.send(
31524
+ new DeleteBucketInventoryConfigurationCommand({ Bucket: bucketName, Id: id })
31525
+ );
31526
+ this.logger.debug(`Deleted inventory configuration ${id} on bucket ${bucketName}`);
31527
+ }
31528
+ );
31529
+ }
31530
+ /**
31531
+ * Apply ALL sub-configs unconditionally on initial create. Used by
31532
+ * `create()` so the bucket starts out matching the template.
31533
+ */
31534
+ async applyAllSubConfigsForCreate(bucketName, properties) {
31217
31535
  const notifConfig = properties["NotificationConfiguration"];
31218
- if (notifConfig?.["EventBridgeConfiguration"]) {
31219
- const ebConfig = notifConfig["EventBridgeConfiguration"];
31220
- await this.s3Client.send(
31221
- new PutBucketNotificationConfigurationCommand({
31222
- Bucket: bucketName,
31223
- NotificationConfiguration: {
31224
- EventBridgeConfiguration: {
31225
- EventBridgeEnabled: ebConfig.EventBridgeEnabled ?? true
31226
- }
31227
- }
31228
- })
31229
- );
31230
- this.logger.debug(`Applied EventBridge notification to bucket ${bucketName}`);
31536
+ if (notifConfig) {
31537
+ await this.applyNotificationConfiguration(bucketName, notifConfig);
31231
31538
  }
31232
31539
  const corsConfig = properties["CorsConfiguration"];
31233
31540
  if (corsConfig?.CorsRules && Array.isArray(corsConfig.CorsRules) && corsConfig.CorsRules.length > 0) {
@@ -31237,16 +31544,8 @@ var S3BucketProvider = class {
31237
31544
  if (lifecycleConfig?.Rules && Array.isArray(lifecycleConfig.Rules) && lifecycleConfig.Rules.length > 0) {
31238
31545
  await this.applyLifecycleConfiguration(bucketName, lifecycleConfig);
31239
31546
  }
31240
- const publicAccessBlock = properties["PublicAccessBlockConfiguration"];
31241
- if (publicAccessBlock) {
31242
- await this.applyPublicAccessBlockConfiguration(bucketName, publicAccessBlock);
31243
- }
31244
- const bucketEncryption = properties["BucketEncryption"];
31245
- if (bucketEncryption?.ServerSideEncryptionConfiguration && Array.isArray(bucketEncryption.ServerSideEncryptionConfiguration) && bucketEncryption.ServerSideEncryptionConfiguration.length > 0) {
31246
- await this.applyBucketEncryption(bucketName, bucketEncryption);
31247
- }
31248
31547
  const loggingConfig = properties["LoggingConfiguration"];
31249
- if (loggingConfig) {
31548
+ if (loggingConfig?.["DestinationBucketName"]) {
31250
31549
  await this.applyLoggingConfiguration(bucketName, loggingConfig);
31251
31550
  }
31252
31551
  const websiteConfig = properties["WebsiteConfiguration"];
@@ -31316,6 +31615,7 @@ var S3BucketProvider = class {
31316
31615
  }
31317
31616
  }
31318
31617
  await this.applyConfiguration(bucketName, properties);
31618
+ await this.applyAllSubConfigsForCreate(bucketName, properties);
31319
31619
  const attributes = await this.buildAttributes(bucketName);
31320
31620
  this.logger.debug(`Successfully created S3 bucket ${logicalId}: ${bucketName}`);
31321
31621
  return {
@@ -31355,6 +31655,7 @@ var S3BucketProvider = class {
31355
31655
  /* skipTags */
31356
31656
  true
31357
31657
  );
31658
+ await this.applySubConfigDiffs(physicalId, properties, previousProperties);
31358
31659
  await this.applyTagDiff(
31359
31660
  physicalId,
31360
31661
  previousProperties["Tags"],
@@ -31417,20 +31718,23 @@ var S3BucketProvider = class {
31417
31718
  * into a single CFn-shaped object. Each call can throw a "feature not
31418
31719
  * configured" error (`NoSuchBucketConfiguration`,
31419
31720
  * `ServerSideEncryptionConfigurationNotFoundError`, `NoSuchTagSet`,
31420
- * `NoSuchPublicAccessBlockConfiguration`) — those are caught individually
31421
- * and the corresponding key is omitted from the result, NOT treated as
31422
- * the bucket being absent.
31721
+ * `NoSuchPublicAccessBlockConfiguration`, etc.) — those are caught
31722
+ * individually and the corresponding key is emitted as a CFn-shape
31723
+ * placeholder (per docs/provider-development.md § 3b: always-emit
31724
+ * user-controllable top-level keys), NOT treated as the bucket being
31725
+ * absent.
31423
31726
  *
31424
31727
  * Only the bucket-gone case (`NoSuchBucket`, HTTP 404 from `HeadBucket`)
31425
31728
  * returns `undefined`.
31426
31729
  *
31427
31730
  * Coverage: `BucketName`, `VersioningConfiguration`, `BucketEncryption`,
31428
- * `PublicAccessBlockConfiguration`, `Tags`. Other configuration
31429
- * properties (Lifecycle, CORS, Website, Logging, Notification,
31430
- * Replication, ObjectLock, Accelerate, Metrics/Analytics/IntelligentTier/
31431
- * Inventory) are out of scope for v1 — they each need their own GET +
31432
- * shape mapping; CC API drift detection picks them up via `GetResource`
31433
- * once a user works through the SDK provider boundary.
31731
+ * `PublicAccessBlockConfiguration`, `Tags`, plus all 12 sub-configs:
31732
+ * `LifecycleConfiguration`, `CorsConfiguration`, `WebsiteConfiguration`,
31733
+ * `LoggingConfiguration`, `NotificationConfiguration`,
31734
+ * `ReplicationConfiguration`, `ObjectLockConfiguration`,
31735
+ * `AccelerateConfiguration`, `MetricsConfigurations`,
31736
+ * `AnalyticsConfigurations`, `IntelligentTieringConfigurations`,
31737
+ * `InventoryConfigurations`.
31434
31738
  */
31435
31739
  async readCurrentState(physicalId, _logicalId, _resourceType) {
31436
31740
  try {
@@ -31442,17 +31746,75 @@ var S3BucketProvider = class {
31442
31746
  }
31443
31747
  throw err;
31444
31748
  }
31445
- const result = {
31446
- BucketName: physicalId
31749
+ const [
31750
+ versioning,
31751
+ encryption,
31752
+ pab,
31753
+ tags,
31754
+ lifecycle,
31755
+ cors,
31756
+ website,
31757
+ logging,
31758
+ notification,
31759
+ replication,
31760
+ objectLock,
31761
+ accelerate,
31762
+ metrics,
31763
+ analytics,
31764
+ intelligentTier,
31765
+ inventory
31766
+ ] = await Promise.all([
31767
+ this.readVersioning(physicalId),
31768
+ this.readEncryption(physicalId),
31769
+ this.readPublicAccessBlock(physicalId),
31770
+ this.readTags(physicalId),
31771
+ this.readLifecycle(physicalId),
31772
+ this.readCors(physicalId),
31773
+ this.readWebsite(physicalId),
31774
+ this.readLogging(physicalId),
31775
+ this.readNotification(physicalId),
31776
+ this.readReplication(physicalId),
31777
+ this.readObjectLock(physicalId),
31778
+ this.readAccelerate(physicalId),
31779
+ this.readMetricsList(physicalId),
31780
+ this.readAnalyticsList(physicalId),
31781
+ this.readIntelligentTieringList(physicalId),
31782
+ this.readInventoryList(physicalId)
31783
+ ]);
31784
+ return {
31785
+ BucketName: physicalId,
31786
+ VersioningConfiguration: versioning,
31787
+ BucketEncryption: encryption,
31788
+ PublicAccessBlockConfiguration: pab,
31789
+ Tags: tags,
31790
+ LifecycleConfiguration: lifecycle,
31791
+ CorsConfiguration: cors,
31792
+ WebsiteConfiguration: website,
31793
+ LoggingConfiguration: logging,
31794
+ NotificationConfiguration: notification,
31795
+ ReplicationConfiguration: replication,
31796
+ ObjectLockConfiguration: objectLock,
31797
+ AccelerateConfiguration: accelerate,
31798
+ MetricsConfigurations: metrics,
31799
+ AnalyticsConfigurations: analytics,
31800
+ IntelligentTieringConfigurations: intelligentTier,
31801
+ InventoryConfigurations: inventory
31447
31802
  };
31448
- {
31449
- const resp = await this.s3Client.send(new GetBucketVersioningCommand({ Bucket: physicalId }));
31450
- result["VersioningConfiguration"] = { Status: resp.Status ?? "Suspended" };
31451
- }
31803
+ }
31804
+ // -------------------------------------------------------------------
31805
+ // readCurrentState helpers one per sub-config. Each catches the
31806
+ // "feature not configured" error and returns the always-emit
31807
+ // placeholder shape per docs/provider-development.md § 3b.
31808
+ // -------------------------------------------------------------------
31809
+ async readVersioning(bucket) {
31810
+ const resp = await this.s3Client.send(new GetBucketVersioningCommand({ Bucket: bucket }));
31811
+ return { Status: resp.Status ?? "Suspended" };
31812
+ }
31813
+ async readEncryption(bucket) {
31452
31814
  try {
31453
- const resp = await this.s3Client.send(new GetBucketEncryptionCommand({ Bucket: physicalId }));
31815
+ const resp = await this.s3Client.send(new GetBucketEncryptionCommand({ Bucket: bucket }));
31454
31816
  const rules = resp.ServerSideEncryptionConfiguration?.Rules ?? [];
31455
- result["BucketEncryption"] = {
31817
+ return {
31456
31818
  ServerSideEncryptionConfiguration: rules.map((rule) => {
31457
31819
  const out = {};
31458
31820
  const sse = rule.ApplyServerSideEncryptionByDefault;
@@ -31472,17 +31834,16 @@ var S3BucketProvider = class {
31472
31834
  } catch (err) {
31473
31835
  const e = err;
31474
31836
  if (e.name === "ServerSideEncryptionConfigurationNotFoundError") {
31475
- result["BucketEncryption"] = { ServerSideEncryptionConfiguration: [] };
31476
- } else {
31477
- throw err;
31837
+ return { ServerSideEncryptionConfiguration: [] };
31478
31838
  }
31839
+ throw err;
31479
31840
  }
31841
+ }
31842
+ async readPublicAccessBlock(bucket) {
31480
31843
  try {
31481
- const resp = await this.s3Client.send(
31482
- new GetPublicAccessBlockCommand({ Bucket: physicalId })
31483
- );
31844
+ const resp = await this.s3Client.send(new GetPublicAccessBlockCommand({ Bucket: bucket }));
31484
31845
  const cfg = resp.PublicAccessBlockConfiguration;
31485
- result["PublicAccessBlockConfiguration"] = {
31846
+ return {
31486
31847
  BlockPublicAcls: cfg?.BlockPublicAcls ?? false,
31487
31848
  BlockPublicPolicy: cfg?.BlockPublicPolicy ?? false,
31488
31849
  IgnorePublicAcls: cfg?.IgnorePublicAcls ?? false,
@@ -31491,28 +31852,593 @@ var S3BucketProvider = class {
31491
31852
  } catch (err) {
31492
31853
  const e = err;
31493
31854
  if (e.name === "NoSuchPublicAccessBlockConfiguration") {
31494
- result["PublicAccessBlockConfiguration"] = {
31855
+ return {
31495
31856
  BlockPublicAcls: false,
31496
31857
  BlockPublicPolicy: false,
31497
31858
  IgnorePublicAcls: false,
31498
31859
  RestrictPublicBuckets: false
31499
31860
  };
31500
- } else {
31501
- throw err;
31502
31861
  }
31862
+ throw err;
31863
+ }
31864
+ }
31865
+ async readTags(bucket) {
31866
+ try {
31867
+ const resp = await this.s3Client.send(new GetBucketTaggingCommand({ Bucket: bucket }));
31868
+ return normalizeAwsTagsToCfn(resp.TagSet);
31869
+ } catch (err) {
31870
+ const e = err;
31871
+ if (e.name === "NoSuchTagSet")
31872
+ return [];
31873
+ throw err;
31874
+ }
31875
+ }
31876
+ async readLifecycle(bucket) {
31877
+ try {
31878
+ const resp = await this.s3Client.send(
31879
+ new GetBucketLifecycleConfigurationCommand({ Bucket: bucket })
31880
+ );
31881
+ const rules = resp.Rules ?? [];
31882
+ return {
31883
+ Rules: rules.map((r) => {
31884
+ const out = {};
31885
+ if (r.ID !== void 0)
31886
+ out["Id"] = r.ID;
31887
+ if (r.Status !== void 0)
31888
+ out["Status"] = r.Status;
31889
+ if (r.Prefix !== void 0)
31890
+ out["Prefix"] = r.Prefix;
31891
+ if (r.Expiration) {
31892
+ const exp = {};
31893
+ if (r.Expiration.Days !== void 0)
31894
+ exp["Days"] = r.Expiration.Days;
31895
+ if (r.Expiration.Date !== void 0)
31896
+ exp["Date"] = r.Expiration.Date.toISOString();
31897
+ if (r.Expiration.ExpiredObjectDeleteMarker !== void 0)
31898
+ exp["ExpiredObjectDeleteMarker"] = r.Expiration.ExpiredObjectDeleteMarker;
31899
+ out["Expiration"] = exp;
31900
+ }
31901
+ if (r.Transitions && r.Transitions.length > 0) {
31902
+ out["Transitions"] = r.Transitions.map((t) => {
31903
+ const item = {};
31904
+ if (t.Days !== void 0)
31905
+ item["TransitionInDays"] = t.Days;
31906
+ if (t.Date !== void 0)
31907
+ item["TransitionDate"] = t.Date.toISOString();
31908
+ if (t.StorageClass !== void 0)
31909
+ item["StorageClass"] = t.StorageClass;
31910
+ return item;
31911
+ });
31912
+ }
31913
+ if (r.NoncurrentVersionExpiration) {
31914
+ const nve = {};
31915
+ if (r.NoncurrentVersionExpiration.NoncurrentDays !== void 0)
31916
+ nve["NoncurrentDays"] = r.NoncurrentVersionExpiration.NoncurrentDays;
31917
+ if (r.NoncurrentVersionExpiration.NewerNoncurrentVersions !== void 0)
31918
+ nve["NewerNoncurrentVersions"] = r.NoncurrentVersionExpiration.NewerNoncurrentVersions;
31919
+ out["NoncurrentVersionExpiration"] = nve;
31920
+ }
31921
+ if (r.NoncurrentVersionTransitions && r.NoncurrentVersionTransitions.length > 0) {
31922
+ out["NoncurrentVersionTransitions"] = r.NoncurrentVersionTransitions.map((nvt) => {
31923
+ const item = {};
31924
+ if (nvt.NoncurrentDays !== void 0)
31925
+ item["NoncurrentDays"] = nvt.NoncurrentDays;
31926
+ if (nvt.StorageClass !== void 0)
31927
+ item["StorageClass"] = nvt.StorageClass;
31928
+ if (nvt.NewerNoncurrentVersions !== void 0)
31929
+ item["NewerNoncurrentVersions"] = nvt.NewerNoncurrentVersions;
31930
+ return item;
31931
+ });
31932
+ }
31933
+ if (r.AbortIncompleteMultipartUpload) {
31934
+ out["AbortIncompleteMultipartUpload"] = {
31935
+ DaysAfterInitiation: r.AbortIncompleteMultipartUpload.DaysAfterInitiation
31936
+ };
31937
+ }
31938
+ if (r.Filter) {
31939
+ const f = r.Filter;
31940
+ const cfnFilter = {};
31941
+ const and = f["And"];
31942
+ const tagOnly = f["Tag"];
31943
+ if (and) {
31944
+ if (and["Prefix"] !== void 0)
31945
+ cfnFilter["Prefix"] = and["Prefix"];
31946
+ if (and["Tags"])
31947
+ cfnFilter["TagFilters"] = and["Tags"];
31948
+ if (and["ObjectSizeGreaterThan"] !== void 0)
31949
+ cfnFilter["ObjectSizeGreaterThan"] = and["ObjectSizeGreaterThan"];
31950
+ if (and["ObjectSizeLessThan"] !== void 0)
31951
+ cfnFilter["ObjectSizeLessThan"] = and["ObjectSizeLessThan"];
31952
+ } else if (tagOnly) {
31953
+ cfnFilter["TagFilters"] = [tagOnly];
31954
+ } else {
31955
+ if (f["Prefix"] !== void 0)
31956
+ cfnFilter["Prefix"] = f["Prefix"];
31957
+ if (f["ObjectSizeGreaterThan"] !== void 0)
31958
+ cfnFilter["ObjectSizeGreaterThan"] = f["ObjectSizeGreaterThan"];
31959
+ if (f["ObjectSizeLessThan"] !== void 0)
31960
+ cfnFilter["ObjectSizeLessThan"] = f["ObjectSizeLessThan"];
31961
+ }
31962
+ if (Object.keys(cfnFilter).length > 0)
31963
+ out["Filter"] = cfnFilter;
31964
+ }
31965
+ return out;
31966
+ })
31967
+ };
31968
+ } catch (err) {
31969
+ const e = err;
31970
+ if (e.name === "NoSuchLifecycleConfiguration")
31971
+ return { Rules: [] };
31972
+ throw err;
31973
+ }
31974
+ }
31975
+ async readCors(bucket) {
31976
+ try {
31977
+ const resp = await this.s3Client.send(new GetBucketCorsCommand({ Bucket: bucket }));
31978
+ const rules = resp.CORSRules ?? [];
31979
+ return {
31980
+ CorsRules: rules.map((r) => {
31981
+ const out = {};
31982
+ if (r.ID !== void 0)
31983
+ out["Id"] = r.ID;
31984
+ if (r.AllowedHeaders !== void 0)
31985
+ out["AllowedHeaders"] = r.AllowedHeaders;
31986
+ if (r.AllowedMethods !== void 0)
31987
+ out["AllowedMethods"] = r.AllowedMethods;
31988
+ if (r.AllowedOrigins !== void 0)
31989
+ out["AllowedOrigins"] = r.AllowedOrigins;
31990
+ if (r.ExposeHeaders !== void 0)
31991
+ out["ExposedHeaders"] = r.ExposeHeaders;
31992
+ if (r.MaxAgeSeconds !== void 0)
31993
+ out["MaxAge"] = r.MaxAgeSeconds;
31994
+ return out;
31995
+ })
31996
+ };
31997
+ } catch (err) {
31998
+ const e = err;
31999
+ if (e.name === "NoSuchCORSConfiguration")
32000
+ return { CorsRules: [] };
32001
+ throw err;
32002
+ }
32003
+ }
32004
+ async readWebsite(bucket) {
32005
+ try {
32006
+ const resp = await this.s3Client.send(new GetBucketWebsiteCommand({ Bucket: bucket }));
32007
+ const out = {};
32008
+ if (resp.IndexDocument?.Suffix !== void 0) {
32009
+ out["IndexDocument"] = resp.IndexDocument.Suffix;
32010
+ }
32011
+ if (resp.ErrorDocument?.Key !== void 0) {
32012
+ out["ErrorDocument"] = resp.ErrorDocument.Key;
32013
+ }
32014
+ if (resp.RedirectAllRequestsTo) {
32015
+ const redirect = {};
32016
+ if (resp.RedirectAllRequestsTo.HostName !== void 0)
32017
+ redirect["HostName"] = resp.RedirectAllRequestsTo.HostName;
32018
+ if (resp.RedirectAllRequestsTo.Protocol !== void 0)
32019
+ redirect["Protocol"] = resp.RedirectAllRequestsTo.Protocol;
32020
+ out["RedirectAllRequestsTo"] = redirect;
32021
+ }
32022
+ if (resp.RoutingRules && resp.RoutingRules.length > 0) {
32023
+ out["RoutingRules"] = resp.RoutingRules.map((rr) => {
32024
+ const ruleOut = {};
32025
+ if (rr.Condition) {
32026
+ const c = {};
32027
+ if (rr.Condition.HttpErrorCodeReturnedEquals !== void 0)
32028
+ c["HttpErrorCodeReturnedEquals"] = rr.Condition.HttpErrorCodeReturnedEquals;
32029
+ if (rr.Condition.KeyPrefixEquals !== void 0)
32030
+ c["KeyPrefixEquals"] = rr.Condition.KeyPrefixEquals;
32031
+ ruleOut["RoutingRuleCondition"] = c;
32032
+ }
32033
+ if (rr.Redirect) {
32034
+ const r = {};
32035
+ if (rr.Redirect.HostName !== void 0)
32036
+ r["HostName"] = rr.Redirect.HostName;
32037
+ if (rr.Redirect.HttpRedirectCode !== void 0)
32038
+ r["HttpRedirectCode"] = rr.Redirect.HttpRedirectCode;
32039
+ if (rr.Redirect.Protocol !== void 0)
32040
+ r["Protocol"] = rr.Redirect.Protocol;
32041
+ if (rr.Redirect.ReplaceKeyPrefixWith !== void 0)
32042
+ r["ReplaceKeyPrefixWith"] = rr.Redirect.ReplaceKeyPrefixWith;
32043
+ if (rr.Redirect.ReplaceKeyWith !== void 0)
32044
+ r["ReplaceKeyWith"] = rr.Redirect.ReplaceKeyWith;
32045
+ ruleOut["RedirectRule"] = r;
32046
+ }
32047
+ return ruleOut;
32048
+ });
32049
+ }
32050
+ return out;
32051
+ } catch (err) {
32052
+ const e = err;
32053
+ if (e.name === "NoSuchWebsiteConfiguration")
32054
+ return {};
32055
+ throw err;
32056
+ }
32057
+ }
32058
+ async readLogging(bucket) {
32059
+ const resp = await this.s3Client.send(new GetBucketLoggingCommand({ Bucket: bucket }));
32060
+ if (!resp.LoggingEnabled)
32061
+ return {};
32062
+ const out = {};
32063
+ if (resp.LoggingEnabled.TargetBucket !== void 0)
32064
+ out["DestinationBucketName"] = resp.LoggingEnabled.TargetBucket;
32065
+ if (resp.LoggingEnabled.TargetPrefix !== void 0)
32066
+ out["LogFilePrefix"] = resp.LoggingEnabled.TargetPrefix;
32067
+ return out;
32068
+ }
32069
+ async readNotification(bucket) {
32070
+ const resp = await this.s3Client.send(
32071
+ new GetBucketNotificationConfigurationCommand({ Bucket: bucket })
32072
+ );
32073
+ const out = {};
32074
+ if (resp.TopicConfigurations && resp.TopicConfigurations.length > 0) {
32075
+ out["TopicConfigurations"] = resp.TopicConfigurations.map((t) => {
32076
+ const e = {};
32077
+ if (t.Id !== void 0)
32078
+ e["Id"] = t.Id;
32079
+ if (t.TopicArn !== void 0)
32080
+ e["Topic"] = t.TopicArn;
32081
+ if (t.Events !== void 0)
32082
+ e["Events"] = t.Events;
32083
+ if (t.Filter)
32084
+ e["Filter"] = this.sdkNotifFilterToCfn(t.Filter);
32085
+ return e;
32086
+ });
32087
+ }
32088
+ if (resp.QueueConfigurations && resp.QueueConfigurations.length > 0) {
32089
+ out["QueueConfigurations"] = resp.QueueConfigurations.map((q) => {
32090
+ const e = {};
32091
+ if (q.Id !== void 0)
32092
+ e["Id"] = q.Id;
32093
+ if (q.QueueArn !== void 0)
32094
+ e["Queue"] = q.QueueArn;
32095
+ if (q.Events !== void 0)
32096
+ e["Events"] = q.Events;
32097
+ if (q.Filter)
32098
+ e["Filter"] = this.sdkNotifFilterToCfn(q.Filter);
32099
+ return e;
32100
+ });
32101
+ }
32102
+ if (resp.LambdaFunctionConfigurations && resp.LambdaFunctionConfigurations.length > 0) {
32103
+ out["LambdaConfigurations"] = resp.LambdaFunctionConfigurations.map((l) => {
32104
+ const e = {};
32105
+ if (l.Id !== void 0)
32106
+ e["Id"] = l.Id;
32107
+ if (l.LambdaFunctionArn !== void 0)
32108
+ e["Function"] = l.LambdaFunctionArn;
32109
+ if (l.Events !== void 0)
32110
+ e["Events"] = l.Events;
32111
+ if (l.Filter)
32112
+ e["Filter"] = this.sdkNotifFilterToCfn(l.Filter);
32113
+ return e;
32114
+ });
32115
+ }
32116
+ if (resp.EventBridgeConfiguration) {
32117
+ out["EventBridgeConfiguration"] = {};
32118
+ }
32119
+ return out;
32120
+ }
32121
+ sdkNotifFilterToCfn(filter) {
32122
+ if (!filter || typeof filter !== "object")
32123
+ return {};
32124
+ const f = filter;
32125
+ const key = f["Key"];
32126
+ if (!key)
32127
+ return {};
32128
+ const filterRules = key["FilterRules"];
32129
+ if (!filterRules)
32130
+ return {};
32131
+ return {
32132
+ S3Key: {
32133
+ Rules: filterRules.map((r) => ({ Name: r.Name, Value: r.Value }))
32134
+ }
32135
+ };
32136
+ }
32137
+ async readReplication(bucket) {
32138
+ try {
32139
+ const resp = await this.s3Client.send(new GetBucketReplicationCommand({ Bucket: bucket }));
32140
+ const cfg = resp.ReplicationConfiguration;
32141
+ if (!cfg)
32142
+ return {};
32143
+ const out = {};
32144
+ if (cfg.Role !== void 0)
32145
+ out["Role"] = cfg.Role;
32146
+ if (cfg.Rules) {
32147
+ out["Rules"] = cfg.Rules.map((r) => {
32148
+ const ruleOut = {};
32149
+ if (r.ID !== void 0)
32150
+ ruleOut["Id"] = r.ID;
32151
+ if (r.Status !== void 0)
32152
+ ruleOut["Status"] = r.Status;
32153
+ if (r.Priority !== void 0)
32154
+ ruleOut["Priority"] = r.Priority;
32155
+ if (r.Prefix !== void 0)
32156
+ ruleOut["Prefix"] = r.Prefix;
32157
+ if (r.Destination) {
32158
+ const d = {};
32159
+ if (r.Destination.Bucket !== void 0)
32160
+ d["Bucket"] = r.Destination.Bucket;
32161
+ if (r.Destination.Account !== void 0)
32162
+ d["Account"] = r.Destination.Account;
32163
+ if (r.Destination.StorageClass !== void 0)
32164
+ d["StorageClass"] = r.Destination.StorageClass;
32165
+ ruleOut["Destination"] = d;
32166
+ }
32167
+ if (r.Filter) {
32168
+ const f = r.Filter;
32169
+ const cfnFilter = {};
32170
+ const and = f["And"];
32171
+ const tagOnly = f["Tag"];
32172
+ if (and) {
32173
+ if (and["Prefix"] !== void 0)
32174
+ cfnFilter["Prefix"] = and["Prefix"];
32175
+ const tags = and["Tags"];
32176
+ if (tags && tags.length > 0)
32177
+ cfnFilter["TagFilter"] = tags[0];
32178
+ } else if (tagOnly) {
32179
+ cfnFilter["TagFilter"] = tagOnly;
32180
+ } else if (f["Prefix"] !== void 0) {
32181
+ cfnFilter["Prefix"] = f["Prefix"];
32182
+ }
32183
+ if (Object.keys(cfnFilter).length > 0)
32184
+ ruleOut["Filter"] = cfnFilter;
32185
+ }
32186
+ if (r.DeleteMarkerReplication) {
32187
+ ruleOut["DeleteMarkerReplication"] = {
32188
+ Status: r.DeleteMarkerReplication.Status
32189
+ };
32190
+ }
32191
+ return ruleOut;
32192
+ });
32193
+ }
32194
+ return out;
32195
+ } catch (err) {
32196
+ const e = err;
32197
+ if (e.name === "ReplicationConfigurationNotFoundError")
32198
+ return {};
32199
+ throw err;
31503
32200
  }
32201
+ }
32202
+ async readObjectLock(bucket) {
31504
32203
  try {
31505
- const resp = await this.s3Client.send(new GetBucketTaggingCommand({ Bucket: physicalId }));
31506
- result["Tags"] = normalizeAwsTagsToCfn(resp.TagSet);
32204
+ const resp = await this.s3Client.send(
32205
+ new GetObjectLockConfigurationCommand({ Bucket: bucket })
32206
+ );
32207
+ const cfg = resp.ObjectLockConfiguration;
32208
+ if (!cfg)
32209
+ return {};
32210
+ const out = {};
32211
+ if (cfg.ObjectLockEnabled !== void 0)
32212
+ out["ObjectLockEnabled"] = cfg.ObjectLockEnabled;
32213
+ if (cfg.Rule?.DefaultRetention) {
32214
+ const r = cfg.Rule.DefaultRetention;
32215
+ const retention = {};
32216
+ if (r.Mode !== void 0)
32217
+ retention["Mode"] = r.Mode;
32218
+ if (r.Days !== void 0)
32219
+ retention["Days"] = r.Days;
32220
+ if (r.Years !== void 0)
32221
+ retention["Years"] = r.Years;
32222
+ out["Rule"] = { DefaultRetention: retention };
32223
+ }
32224
+ return out;
31507
32225
  } catch (err) {
31508
32226
  const e = err;
31509
- if (e.name === "NoSuchTagSet") {
31510
- result["Tags"] = [];
32227
+ if (e.name === "ObjectLockConfigurationNotFoundError" || e.name === "NoSuchBucketConfiguration") {
32228
+ return {};
32229
+ }
32230
+ throw err;
32231
+ }
32232
+ }
32233
+ async readAccelerate(bucket) {
32234
+ const resp = await this.s3Client.send(
32235
+ new GetBucketAccelerateConfigurationCommand({ Bucket: bucket })
32236
+ );
32237
+ return { AccelerationStatus: resp.Status ?? "Suspended" };
32238
+ }
32239
+ async readMetricsList(bucket) {
32240
+ const out = [];
32241
+ let continuationToken;
32242
+ while (true) {
32243
+ const resp = await this.s3Client.send(
32244
+ new ListBucketMetricsConfigurationsCommand({
32245
+ Bucket: bucket,
32246
+ ContinuationToken: continuationToken
32247
+ })
32248
+ );
32249
+ for (const c of resp.MetricsConfigurationList ?? []) {
32250
+ out.push(this.metricsSdkToCfn(c));
32251
+ }
32252
+ if (!resp.IsTruncated)
32253
+ break;
32254
+ continuationToken = resp.NextContinuationToken;
32255
+ }
32256
+ return out;
32257
+ }
32258
+ metricsSdkToCfn(c) {
32259
+ const out = {};
32260
+ if (c["Id"] !== void 0)
32261
+ out["Id"] = c["Id"];
32262
+ const f = c["Filter"];
32263
+ if (f) {
32264
+ const and = f["And"];
32265
+ const tagOnly = f["Tag"];
32266
+ if (and) {
32267
+ if (and["Prefix"] !== void 0)
32268
+ out["Prefix"] = and["Prefix"];
32269
+ if (and["Tags"])
32270
+ out["TagFilters"] = and["Tags"];
32271
+ if (and["AccessPointArn"] !== void 0)
32272
+ out["AccessPointArn"] = and["AccessPointArn"];
32273
+ } else if (tagOnly) {
32274
+ out["TagFilters"] = [tagOnly];
31511
32275
  } else {
31512
- throw err;
32276
+ if (f["Prefix"] !== void 0)
32277
+ out["Prefix"] = f["Prefix"];
32278
+ if (f["AccessPointArn"] !== void 0)
32279
+ out["AccessPointArn"] = f["AccessPointArn"];
31513
32280
  }
31514
32281
  }
31515
- return result;
32282
+ return out;
32283
+ }
32284
+ async readAnalyticsList(bucket) {
32285
+ const out = [];
32286
+ let continuationToken;
32287
+ while (true) {
32288
+ const resp = await this.s3Client.send(
32289
+ new ListBucketAnalyticsConfigurationsCommand({
32290
+ Bucket: bucket,
32291
+ ContinuationToken: continuationToken
32292
+ })
32293
+ );
32294
+ for (const c of resp.AnalyticsConfigurationList ?? []) {
32295
+ out.push(this.analyticsSdkToCfn(c));
32296
+ }
32297
+ if (!resp.IsTruncated)
32298
+ break;
32299
+ continuationToken = resp.NextContinuationToken;
32300
+ }
32301
+ return out;
32302
+ }
32303
+ analyticsSdkToCfn(c) {
32304
+ const out = {};
32305
+ if (c["Id"] !== void 0)
32306
+ out["Id"] = c["Id"];
32307
+ const f = c["Filter"];
32308
+ if (f) {
32309
+ const and = f["And"];
32310
+ const tagOnly = f["Tag"];
32311
+ if (and) {
32312
+ if (and["Prefix"] !== void 0)
32313
+ out["Prefix"] = and["Prefix"];
32314
+ if (and["Tags"])
32315
+ out["TagFilters"] = and["Tags"];
32316
+ } else if (tagOnly) {
32317
+ out["TagFilters"] = [tagOnly];
32318
+ } else if (f["Prefix"] !== void 0) {
32319
+ out["Prefix"] = f["Prefix"];
32320
+ }
32321
+ }
32322
+ const sca = c["StorageClassAnalysis"];
32323
+ if (sca?.["DataExport"]) {
32324
+ const dataExport = sca["DataExport"];
32325
+ const dest = dataExport["Destination"];
32326
+ const s3Dest = dest?.["S3BucketDestination"];
32327
+ out["StorageClassAnalysis"] = {
32328
+ DataExport: {
32329
+ OutputSchemaVersion: dataExport["OutputSchemaVersion"],
32330
+ Destination: s3Dest ? {
32331
+ S3BucketDestination: {
32332
+ BucketArn: s3Dest["Bucket"],
32333
+ BucketAccountId: s3Dest["BucketAccountId"],
32334
+ Format: s3Dest["Format"],
32335
+ Prefix: s3Dest["Prefix"]
32336
+ }
32337
+ } : void 0
32338
+ }
32339
+ };
32340
+ }
32341
+ return out;
32342
+ }
32343
+ async readIntelligentTieringList(bucket) {
32344
+ const out = [];
32345
+ let continuationToken;
32346
+ while (true) {
32347
+ const resp = await this.s3Client.send(
32348
+ new ListBucketIntelligentTieringConfigurationsCommand({
32349
+ Bucket: bucket,
32350
+ ContinuationToken: continuationToken
32351
+ })
32352
+ );
32353
+ for (const c of resp.IntelligentTieringConfigurationList ?? []) {
32354
+ out.push(this.intelligentTieringSdkToCfn(c));
32355
+ }
32356
+ if (!resp.IsTruncated)
32357
+ break;
32358
+ continuationToken = resp.NextContinuationToken;
32359
+ }
32360
+ return out;
32361
+ }
32362
+ intelligentTieringSdkToCfn(c) {
32363
+ const out = {};
32364
+ if (c["Id"] !== void 0)
32365
+ out["Id"] = c["Id"];
32366
+ if (c["Status"] !== void 0)
32367
+ out["Status"] = c["Status"];
32368
+ if (c["Tierings"]) {
32369
+ const tierings = c["Tierings"];
32370
+ out["Tierings"] = tierings.map((t) => ({
32371
+ AccessTier: t["AccessTier"],
32372
+ Days: t["Days"]
32373
+ }));
32374
+ }
32375
+ const f = c["Filter"];
32376
+ if (f) {
32377
+ const and = f["And"];
32378
+ const tagOnly = f["Tag"];
32379
+ if (and) {
32380
+ if (and["Prefix"] !== void 0)
32381
+ out["Prefix"] = and["Prefix"];
32382
+ if (and["Tags"])
32383
+ out["TagFilters"] = and["Tags"];
32384
+ } else if (tagOnly) {
32385
+ out["TagFilters"] = [tagOnly];
32386
+ } else if (f["Prefix"] !== void 0) {
32387
+ out["Prefix"] = f["Prefix"];
32388
+ }
32389
+ }
32390
+ return out;
32391
+ }
32392
+ async readInventoryList(bucket) {
32393
+ const out = [];
32394
+ let continuationToken;
32395
+ while (true) {
32396
+ const resp = await this.s3Client.send(
32397
+ new ListBucketInventoryConfigurationsCommand({
32398
+ Bucket: bucket,
32399
+ ContinuationToken: continuationToken
32400
+ })
32401
+ );
32402
+ for (const c of resp.InventoryConfigurationList ?? []) {
32403
+ out.push(this.inventorySdkToCfn(c));
32404
+ }
32405
+ if (!resp.IsTruncated)
32406
+ break;
32407
+ continuationToken = resp.NextContinuationToken;
32408
+ }
32409
+ return out;
32410
+ }
32411
+ inventorySdkToCfn(c) {
32412
+ const out = {};
32413
+ if (c["Id"] !== void 0)
32414
+ out["Id"] = c["Id"];
32415
+ if (c["IsEnabled"] !== void 0)
32416
+ out["Enabled"] = c["IsEnabled"];
32417
+ if (c["IncludedObjectVersions"] !== void 0)
32418
+ out["IncludedObjectVersions"] = c["IncludedObjectVersions"];
32419
+ const schedule = c["Schedule"];
32420
+ if (schedule?.["Frequency"] !== void 0)
32421
+ out["ScheduleFrequency"] = schedule["Frequency"];
32422
+ if (c["OptionalFields"] !== void 0)
32423
+ out["OptionalFields"] = c["OptionalFields"];
32424
+ const dest = c["Destination"];
32425
+ const s3Dest = dest?.["S3BucketDestination"];
32426
+ if (s3Dest) {
32427
+ const cfnDest = {};
32428
+ if (s3Dest["Bucket"] !== void 0)
32429
+ cfnDest["BucketArn"] = s3Dest["Bucket"];
32430
+ if (s3Dest["AccountId"] !== void 0)
32431
+ cfnDest["BucketAccountId"] = s3Dest["AccountId"];
32432
+ if (s3Dest["Format"] !== void 0)
32433
+ cfnDest["Format"] = s3Dest["Format"];
32434
+ if (s3Dest["Prefix"] !== void 0)
32435
+ cfnDest["Prefix"] = s3Dest["Prefix"];
32436
+ out["Destination"] = cfnDest;
32437
+ }
32438
+ const filter = c["Filter"];
32439
+ if (filter?.["Prefix"] !== void 0)
32440
+ out["Prefix"] = filter["Prefix"];
32441
+ return out;
31516
32442
  }
31517
32443
  /**
31518
32444
  * Adopt an existing S3 bucket into cdkd state.
@@ -41291,6 +42217,42 @@ var EC2Provider = class {
41291
42217
  throw err;
41292
42218
  }
41293
42219
  }
42220
+ /**
42221
+ * Drift-unknown paths per resource type.
42222
+ *
42223
+ * The 6 EC2 sub-resource types (`AWS::EC2::Route` /
42224
+ * `VPCGatewayAttachment` / `SubnetRouteTableAssociation` /
42225
+ * `SecurityGroupIngress` / `NetworkAclEntry` /
42226
+ * `SubnetNetworkAclAssociation`) have NO AWS-side `Tags` API — the
42227
+ * underlying AWS objects (route entries, NACL entries, route-table
42228
+ * associations, NACL associations, IGW attachments) are not
42229
+ * tag-bearing on AWS, and the corresponding CFn schemas do not model
42230
+ * `Tags` either. Declaring `'Tags'` here is defense-in-depth: if a
42231
+ * future CFn schema revision adds `Tags` to one of these types, or
42232
+ * cdkd state somehow carries `Tags` for one of them via a custom
42233
+ * property override, the drift comparator will skip the path
42234
+ * instead of firing guaranteed false-positive drift on every clean
42235
+ * run.
42236
+ *
42237
+ * Other EC2 types (`VPC` / `Subnet` / `InternetGateway` /
42238
+ * `NatGateway` / `RouteTable` / `SecurityGroup` / `Instance` /
42239
+ * `NetworkAcl`) have first-class Tags support via
42240
+ * `DescribeTags` — they surface `Tags` directly in
42241
+ * `readCurrentState` and don't need this declaration.
42242
+ */
42243
+ getDriftUnknownPaths(resourceType) {
42244
+ switch (resourceType) {
42245
+ case "AWS::EC2::Route":
42246
+ case "AWS::EC2::VPCGatewayAttachment":
42247
+ case "AWS::EC2::SubnetRouteTableAssociation":
42248
+ case "AWS::EC2::SecurityGroupIngress":
42249
+ case "AWS::EC2::NetworkAclEntry":
42250
+ case "AWS::EC2::SubnetNetworkAclAssociation":
42251
+ return ["Tags"];
42252
+ default:
42253
+ return [];
42254
+ }
42255
+ }
41294
42256
  async readVpcCurrentState(physicalId) {
41295
42257
  const resp = await this.ec2Client.send(new DescribeVpcsCommand2({ VpcIds: [physicalId] }));
41296
42258
  const vpc = resp.Vpcs?.[0];
@@ -57018,6 +57980,349 @@ var KinesisStreamProvider = class {
57018
57980
  }
57019
57981
  };
57020
57982
 
57983
+ // src/provisioning/providers/kinesis-streamconsumer-provider.ts
57984
+ import {
57985
+ KinesisClient as KinesisClient2,
57986
+ RegisterStreamConsumerCommand,
57987
+ DeregisterStreamConsumerCommand,
57988
+ DescribeStreamConsumerCommand,
57989
+ ListTagsForResourceCommand as ListTagsForResourceCommand18,
57990
+ TagResourceCommand as TagResourceCommand15,
57991
+ UntagResourceCommand as UntagResourceCommand15,
57992
+ ResourceNotFoundException as ResourceNotFoundException14
57993
+ } from "@aws-sdk/client-kinesis";
57994
+ var KinesisStreamConsumerProvider = class {
57995
+ client;
57996
+ providerRegion = process.env["AWS_REGION"];
57997
+ logger = getLogger().child("KinesisStreamConsumerProvider");
57998
+ handledProperties = /* @__PURE__ */ new Map([
57999
+ ["AWS::Kinesis::StreamConsumer", /* @__PURE__ */ new Set(["ConsumerName", "StreamARN", "Tags"])]
58000
+ ]);
58001
+ getClient() {
58002
+ if (!this.client) {
58003
+ this.client = new KinesisClient2(this.providerRegion ? { region: this.providerRegion } : {});
58004
+ }
58005
+ return this.client;
58006
+ }
58007
+ /**
58008
+ * Register a Kinesis stream consumer.
58009
+ *
58010
+ * Polls `DescribeStreamConsumer` until ConsumerStatus flips from
58011
+ * `CREATING` to `ACTIVE` (matches CFn behavior). 1s polling interval
58012
+ * is faster than the CC API exponential backoff used to be.
58013
+ */
58014
+ async create(logicalId, resourceType, properties) {
58015
+ const consumerName = properties["ConsumerName"];
58016
+ const streamArn = properties["StreamARN"];
58017
+ if (!consumerName) {
58018
+ throw new ProvisioningError(
58019
+ "AWS::Kinesis::StreamConsumer requires ConsumerName",
58020
+ resourceType,
58021
+ logicalId
58022
+ );
58023
+ }
58024
+ if (!streamArn) {
58025
+ throw new ProvisioningError(
58026
+ "AWS::Kinesis::StreamConsumer requires StreamARN",
58027
+ resourceType,
58028
+ logicalId
58029
+ );
58030
+ }
58031
+ this.logger.debug(`Registering Kinesis stream consumer ${logicalId}: ${consumerName}`);
58032
+ const tagList = Array.isArray(properties["Tags"]) ? properties["Tags"] : void 0;
58033
+ const tagMap = tagListToMap(tagList);
58034
+ try {
58035
+ const resp = await this.getClient().send(
58036
+ new RegisterStreamConsumerCommand({
58037
+ StreamARN: streamArn,
58038
+ ConsumerName: consumerName,
58039
+ ...tagMap && Object.keys(tagMap).length > 0 ? { Tags: tagMap } : {}
58040
+ })
58041
+ );
58042
+ const consumer = resp.Consumer;
58043
+ if (!consumer?.ConsumerARN || !consumer.ConsumerName) {
58044
+ throw new ProvisioningError(
58045
+ "RegisterStreamConsumer did not return ConsumerARN/ConsumerName",
58046
+ resourceType,
58047
+ logicalId
58048
+ );
58049
+ }
58050
+ const consumerArn = consumer.ConsumerARN;
58051
+ await this.waitForConsumerActive(consumerArn);
58052
+ this.logger.debug(`Successfully registered Kinesis stream consumer ${logicalId}`);
58053
+ return {
58054
+ physicalId: consumerArn,
58055
+ attributes: {
58056
+ ConsumerARN: consumerArn,
58057
+ ConsumerName: consumer.ConsumerName,
58058
+ ConsumerStatus: consumer.ConsumerStatus,
58059
+ ConsumerCreationTimestamp: consumer.ConsumerCreationTimestamp?.toISOString() ?? void 0,
58060
+ // CFn `Id` for StreamConsumer is the ConsumerARN (matches the
58061
+ // CFn return-values doc).
58062
+ Id: consumerArn,
58063
+ StreamARN: streamArn
58064
+ }
58065
+ };
58066
+ } catch (error) {
58067
+ if (error instanceof ProvisioningError)
58068
+ throw error;
58069
+ const cause = error instanceof Error ? error : void 0;
58070
+ throw new ProvisioningError(
58071
+ `Failed to register Kinesis stream consumer ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
58072
+ resourceType,
58073
+ logicalId,
58074
+ consumerName,
58075
+ cause
58076
+ );
58077
+ }
58078
+ }
58079
+ /**
58080
+ * Update is a no-op for the immutable `ConsumerName` / `StreamARN`
58081
+ * fields (the deploy engine's replacement-detection layer triggers
58082
+ * DELETE + CREATE for those changes). Tags ARE mutable via
58083
+ * `TagResource` / `UntagResource` so the diff is applied here.
58084
+ *
58085
+ * If a non-Tags property changes, throw `ResourceUpdateNotSupportedError`
58086
+ * — `cdkd drift --revert` will surface that to the user with the
58087
+ * "use cdkd deploy --replace" suggestion.
58088
+ */
58089
+ async update(logicalId, physicalId, resourceType, properties, previousProperties) {
58090
+ const newConsumerName = properties["ConsumerName"];
58091
+ const oldConsumerName = previousProperties["ConsumerName"];
58092
+ const newStreamArn = properties["StreamARN"];
58093
+ const oldStreamArn = previousProperties["StreamARN"];
58094
+ if (newConsumerName !== oldConsumerName || newStreamArn !== oldStreamArn) {
58095
+ throw new ResourceUpdateNotSupportedError(
58096
+ resourceType,
58097
+ logicalId,
58098
+ "AWS::Kinesis::StreamConsumer ConsumerName / StreamARN are immutable; re-deploy with cdkd deploy --replace, or destroy + redeploy"
58099
+ );
58100
+ }
58101
+ await this.applyTagDiff(
58102
+ physicalId,
58103
+ previousProperties["Tags"],
58104
+ properties["Tags"]
58105
+ );
58106
+ let attrs = {};
58107
+ try {
58108
+ const resp = await this.getClient().send(
58109
+ new DescribeStreamConsumerCommand({ ConsumerARN: physicalId })
58110
+ );
58111
+ const desc = resp.ConsumerDescription;
58112
+ if (desc) {
58113
+ attrs = {
58114
+ ConsumerARN: desc.ConsumerARN,
58115
+ ConsumerName: desc.ConsumerName,
58116
+ ConsumerStatus: desc.ConsumerStatus,
58117
+ ConsumerCreationTimestamp: desc.ConsumerCreationTimestamp?.toISOString() ?? void 0,
58118
+ Id: desc.ConsumerARN,
58119
+ StreamARN: desc.StreamARN
58120
+ };
58121
+ }
58122
+ } catch (err) {
58123
+ this.logger.debug(
58124
+ `DescribeStreamConsumer(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`
58125
+ );
58126
+ }
58127
+ return {
58128
+ physicalId,
58129
+ wasReplaced: false,
58130
+ attributes: attrs
58131
+ };
58132
+ }
58133
+ /**
58134
+ * Deregister a Kinesis stream consumer.
58135
+ *
58136
+ * Per CFn semantics, DELETE returns once `DeregisterStreamConsumer`
58137
+ * returns — AWS handles eventual disappearance asynchronously, but
58138
+ * cdkd does not need to poll for that. `ResourceNotFoundException`
58139
+ * is treated as idempotent success (subject to the standard region
58140
+ * verification for delete idempotency).
58141
+ */
58142
+ async delete(logicalId, physicalId, resourceType, _properties, context) {
58143
+ this.logger.debug(`Deregistering Kinesis stream consumer ${logicalId}: ${physicalId}`);
58144
+ try {
58145
+ await this.getClient().send(new DeregisterStreamConsumerCommand({ ConsumerARN: physicalId }));
58146
+ this.logger.debug(`Successfully deregistered Kinesis stream consumer ${logicalId}`);
58147
+ } catch (error) {
58148
+ if (error instanceof ResourceNotFoundException14) {
58149
+ const clientRegion = await this.getClient().config.region();
58150
+ assertRegionMatch(
58151
+ clientRegion,
58152
+ context?.expectedRegion,
58153
+ resourceType,
58154
+ logicalId,
58155
+ physicalId
58156
+ );
58157
+ this.logger.debug(`Kinesis stream consumer ${physicalId} not found, skipping`);
58158
+ return;
58159
+ }
58160
+ const cause = error instanceof Error ? error : void 0;
58161
+ throw new ProvisioningError(
58162
+ `Failed to deregister Kinesis stream consumer ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
58163
+ resourceType,
58164
+ logicalId,
58165
+ physicalId,
58166
+ cause
58167
+ );
58168
+ }
58169
+ }
58170
+ async getAttribute(physicalId, _resourceType, attributeName) {
58171
+ if (attributeName === "ConsumerARN" || attributeName === "Id") {
58172
+ return physicalId;
58173
+ }
58174
+ const resp = await this.getClient().send(
58175
+ new DescribeStreamConsumerCommand({ ConsumerARN: physicalId })
58176
+ );
58177
+ const desc = resp.ConsumerDescription;
58178
+ if (!desc)
58179
+ return void 0;
58180
+ switch (attributeName) {
58181
+ case "ConsumerName":
58182
+ return desc.ConsumerName;
58183
+ case "ConsumerStatus":
58184
+ return desc.ConsumerStatus;
58185
+ case "ConsumerCreationTimestamp":
58186
+ return desc.ConsumerCreationTimestamp?.toISOString() ?? void 0;
58187
+ case "StreamARN":
58188
+ return desc.StreamARN;
58189
+ default:
58190
+ return void 0;
58191
+ }
58192
+ }
58193
+ /**
58194
+ * Read the AWS-current StreamConsumer configuration in CFn-property shape.
58195
+ *
58196
+ * Surfaces `ConsumerName` + `StreamARN` (the only user-controllable
58197
+ * top-level CFn properties). AWS-managed read-only fields
58198
+ * (`ConsumerARN`, `ConsumerCreationTimestamp`, `ConsumerStatus`) are
58199
+ * omitted — they are not in `handledProperties` and surface only as
58200
+ * `getAttribute` results.
58201
+ *
58202
+ * `Tags` are surfaced via `ListTagsForResource(ResourceARN=ConsumerARN)`
58203
+ * with `aws:*` filtered out and the always-emit `[]` placeholder
58204
+ * pattern (PR #145). The CFn schema for `AWS::Kinesis::StreamConsumer`
58205
+ * does not currently model Tags as a top-level property, but cdkd
58206
+ * surfaces it defensively so future schema revisions or custom
58207
+ * property overrides can round-trip cleanly.
58208
+ *
58209
+ * Returns `undefined` when the consumer is gone
58210
+ * (`ResourceNotFoundException`).
58211
+ */
58212
+ async readCurrentState(physicalId, _logicalId, resourceType) {
58213
+ if (resourceType !== "AWS::Kinesis::StreamConsumer")
58214
+ return void 0;
58215
+ let desc;
58216
+ try {
58217
+ const resp = await this.getClient().send(
58218
+ new DescribeStreamConsumerCommand({ ConsumerARN: physicalId })
58219
+ );
58220
+ desc = resp.ConsumerDescription;
58221
+ } catch (err) {
58222
+ if (err instanceof ResourceNotFoundException14)
58223
+ return void 0;
58224
+ throw err;
58225
+ }
58226
+ if (!desc)
58227
+ return void 0;
58228
+ const result = {};
58229
+ if (desc.ConsumerName !== void 0)
58230
+ result["ConsumerName"] = desc.ConsumerName;
58231
+ if (desc.StreamARN !== void 0)
58232
+ result["StreamARN"] = desc.StreamARN;
58233
+ try {
58234
+ const tagsResp = await this.getClient().send(
58235
+ new ListTagsForResourceCommand18({ ResourceARN: physicalId })
58236
+ );
58237
+ result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
58238
+ } catch (err) {
58239
+ if (err instanceof ResourceNotFoundException14)
58240
+ return void 0;
58241
+ this.logger.debug(
58242
+ `ListTagsForResource(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`
58243
+ );
58244
+ result["Tags"] = [];
58245
+ }
58246
+ return result;
58247
+ }
58248
+ /**
58249
+ * Apply a diff between old and new CFn-shape Tags arrays via Kinesis's
58250
+ * generic `TagResource` (TagMap shape) / `UntagResource` (TagKeys list)
58251
+ * APIs. Mirrors `KinesisStreamProvider.applyTagDiff`, except the
58252
+ * Kinesis service splits the per-resource-type tag APIs vs the generic
58253
+ * tag APIs — StreamConsumer uses the generic ones (which accept any
58254
+ * Kinesis resource ARN).
58255
+ */
58256
+ async applyTagDiff(consumerArn, oldTagsRaw, newTagsRaw) {
58257
+ const oldMap = tagListToMap(oldTagsRaw) ?? {};
58258
+ const newMap = tagListToMap(newTagsRaw) ?? {};
58259
+ const tagsToAdd = {};
58260
+ for (const [k, v] of Object.entries(newMap)) {
58261
+ if (oldMap[k] !== v)
58262
+ tagsToAdd[k] = v;
58263
+ }
58264
+ const tagsToRemove = [];
58265
+ for (const k of Object.keys(oldMap)) {
58266
+ if (!(k in newMap))
58267
+ tagsToRemove.push(k);
58268
+ }
58269
+ if (tagsToRemove.length > 0) {
58270
+ await this.getClient().send(
58271
+ new UntagResourceCommand15({ ResourceARN: consumerArn, TagKeys: tagsToRemove })
58272
+ );
58273
+ this.logger.debug(
58274
+ `Removed ${tagsToRemove.length} tag(s) from Kinesis stream consumer ${consumerArn}`
58275
+ );
58276
+ }
58277
+ if (Object.keys(tagsToAdd).length > 0) {
58278
+ await this.getClient().send(
58279
+ new TagResourceCommand15({ ResourceARN: consumerArn, Tags: tagsToAdd })
58280
+ );
58281
+ this.logger.debug(
58282
+ `Added/updated ${Object.keys(tagsToAdd).length} tag(s) on Kinesis stream consumer ${consumerArn}`
58283
+ );
58284
+ }
58285
+ }
58286
+ /**
58287
+ * Poll DescribeStreamConsumer until the consumer reaches `ACTIVE`.
58288
+ *
58289
+ * Uses 1s polling intervals — consumer registration is typically
58290
+ * sub-second, but AWS can take up to ~30s under load. Caps at 60
58291
+ * attempts (1 minute total) which is bounded above by the per-resource
58292
+ * `--resource-timeout` deadline.
58293
+ */
58294
+ async waitForConsumerActive(consumerArn, maxAttempts = 60) {
58295
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
58296
+ const resp = await this.getClient().send(
58297
+ new DescribeStreamConsumerCommand({ ConsumerARN: consumerArn })
58298
+ );
58299
+ const status = resp.ConsumerDescription?.ConsumerStatus;
58300
+ this.logger.debug(
58301
+ `Consumer ${consumerArn} status: ${status} (attempt ${attempt}/${maxAttempts})`
58302
+ );
58303
+ if (status === "ACTIVE")
58304
+ return;
58305
+ if (status !== "CREATING") {
58306
+ throw new Error(`Unexpected consumer status: ${status}`);
58307
+ }
58308
+ await new Promise((resolve4) => setTimeout(resolve4, 1e3));
58309
+ }
58310
+ throw new Error(
58311
+ `Consumer ${consumerArn} did not reach ACTIVE status within ${maxAttempts} seconds`
58312
+ );
58313
+ }
58314
+ };
58315
+ function tagListToMap(tags) {
58316
+ if (!tags || tags.length === 0)
58317
+ return void 0;
58318
+ const out = {};
58319
+ for (const t of tags) {
58320
+ if (t.Key !== void 0 && t.Value !== void 0)
58321
+ out[t.Key] = t.Value;
58322
+ }
58323
+ return Object.keys(out).length > 0 ? out : void 0;
58324
+ }
58325
+
57021
58326
  // src/provisioning/providers/efs-provider.ts
57022
58327
  import {
57023
58328
  EFSClient,
@@ -57831,7 +59136,7 @@ import {
57831
59136
  DescribeDeliveryStreamCommand,
57832
59137
  ListDeliveryStreamsCommand,
57833
59138
  ListTagsForDeliveryStreamCommand,
57834
- ResourceNotFoundException as ResourceNotFoundException14
59139
+ ResourceNotFoundException as ResourceNotFoundException15
57835
59140
  } from "@aws-sdk/client-firehose";
57836
59141
  var FirehoseProvider = class {
57837
59142
  client;
@@ -58064,7 +59369,7 @@ var FirehoseProvider = class {
58064
59369
  );
58065
59370
  this.logger.debug(`Successfully deleted Firehose delivery stream ${logicalId}`);
58066
59371
  } catch (error) {
58067
- if (error instanceof ResourceNotFoundException14) {
59372
+ if (error instanceof ResourceNotFoundException15) {
58068
59373
  const clientRegion = await this.getClient().config.region();
58069
59374
  assertRegionMatch(
58070
59375
  clientRegion,
@@ -58243,7 +59548,7 @@ var FirehoseProvider = class {
58243
59548
  );
58244
59549
  desc = resp.DeliveryStreamDescription;
58245
59550
  } catch (err) {
58246
- if (err instanceof ResourceNotFoundException14)
59551
+ if (err instanceof ResourceNotFoundException15)
58247
59552
  return void 0;
58248
59553
  throw err;
58249
59554
  }
@@ -58314,7 +59619,7 @@ var FirehoseProvider = class {
58314
59619
  );
58315
59620
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
58316
59621
  } catch (err) {
58317
- if (err instanceof ResourceNotFoundException14)
59622
+ if (err instanceof ResourceNotFoundException15)
58318
59623
  return void 0;
58319
59624
  this.logger.debug(
58320
59625
  `Firehose ListTagsForDeliveryStream(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`
@@ -58358,7 +59663,7 @@ var FirehoseProvider = class {
58358
59663
  );
58359
59664
  return { physicalId: explicit, attributes: {} };
58360
59665
  } catch (err) {
58361
- if (err instanceof ResourceNotFoundException14)
59666
+ if (err instanceof ResourceNotFoundException15)
58362
59667
  return null;
58363
59668
  throw err;
58364
59669
  }
@@ -58993,7 +60298,7 @@ import {
58993
60298
  UpdateProjectCommand,
58994
60299
  BatchGetProjectsCommand,
58995
60300
  ListProjectsCommand,
58996
- ResourceNotFoundException as ResourceNotFoundException15
60301
+ ResourceNotFoundException as ResourceNotFoundException16
58997
60302
  } from "@aws-sdk/client-codebuild";
58998
60303
  var CodeBuildProvider = class {
58999
60304
  client;
@@ -59231,7 +60536,7 @@ var CodeBuildProvider = class {
59231
60536
  await this.getClient().send(new DeleteProjectCommand({ name: physicalId }));
59232
60537
  this.logger.debug(`Successfully deleted CodeBuild Project ${logicalId}`);
59233
60538
  } catch (error) {
59234
- if (error instanceof ResourceNotFoundException15) {
60539
+ if (error instanceof ResourceNotFoundException16) {
59235
60540
  const clientRegion = await this.getClient().config.region();
59236
60541
  assertRegionMatch(
59237
60542
  clientRegion,
@@ -59302,7 +60607,7 @@ var CodeBuildProvider = class {
59302
60607
  );
59303
60608
  project = resp.projects?.[0];
59304
60609
  } catch (err) {
59305
- if (err instanceof ResourceNotFoundException15)
60610
+ if (err instanceof ResourceNotFoundException16)
59306
60611
  return void 0;
59307
60612
  throw err;
59308
60613
  }
@@ -59549,7 +60854,7 @@ var CodeBuildProvider = class {
59549
60854
  );
59550
60855
  return resp.projects?.[0]?.name ? { physicalId: explicit, attributes: {} } : null;
59551
60856
  } catch (err) {
59552
- if (err instanceof ResourceNotFoundException15)
60857
+ if (err instanceof ResourceNotFoundException16)
59553
60858
  return null;
59554
60859
  throw err;
59555
60860
  }
@@ -59589,7 +60894,7 @@ import {
59589
60894
  GetVectorBucketCommand,
59590
60895
  ListIndexesCommand,
59591
60896
  ListVectorBucketsCommand,
59592
- ListTagsForResourceCommand as ListTagsForResourceCommand18,
60897
+ ListTagsForResourceCommand as ListTagsForResourceCommand19,
59593
60898
  DeleteIndexCommand
59594
60899
  } from "@aws-sdk/client-s3vectors";
59595
60900
  var S3VectorsProvider = class {
@@ -59823,7 +61128,7 @@ var S3VectorsProvider = class {
59823
61128
  continue;
59824
61129
  try {
59825
61130
  const tagsResp = await this.getClient().send(
59826
- new ListTagsForResourceCommand18({ resourceArn: bucket.vectorBucketArn })
61131
+ new ListTagsForResourceCommand19({ resourceArn: bucket.vectorBucketArn })
59827
61132
  );
59828
61133
  if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
59829
61134
  return { physicalId: bucket.vectorBucketName, attributes: {} };
@@ -60167,7 +61472,7 @@ import {
60167
61472
  ListNamespacesCommand as ListNamespacesCommand2,
60168
61473
  ListTablesCommand as ListTablesCommand2,
60169
61474
  ListTableBucketsCommand,
60170
- ListTagsForResourceCommand as ListTagsForResourceCommand19,
61475
+ ListTagsForResourceCommand as ListTagsForResourceCommand20,
60171
61476
  NotFoundException as NotFoundException6
60172
61477
  } from "@aws-sdk/client-s3tables";
60173
61478
  var S3TablesProvider = class {
@@ -60651,7 +61956,7 @@ var S3TablesProvider = class {
60651
61956
  if (input.cdkPath) {
60652
61957
  try {
60653
61958
  const tagsResp = await this.getClient().send(
60654
- new ListTagsForResourceCommand19({ resourceArn: bucket.arn })
61959
+ new ListTagsForResourceCommand20({ resourceArn: bucket.arn })
60655
61960
  );
60656
61961
  if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
60657
61962
  return { physicalId: bucket.arn, attributes: {} };
@@ -60731,7 +62036,7 @@ var S3TablesProvider = class {
60731
62036
  continue;
60732
62037
  try {
60733
62038
  const tagsResp = await this.getClient().send(
60734
- new ListTagsForResourceCommand19({ resourceArn: table.tableARN })
62039
+ new ListTagsForResourceCommand20({ resourceArn: table.tableARN })
60735
62040
  );
60736
62041
  if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
60737
62042
  return {
@@ -60816,8 +62121,8 @@ import {
60816
62121
  SetRepositoryPolicyCommand,
60817
62122
  PutImageScanningConfigurationCommand,
60818
62123
  PutImageTagMutabilityCommand,
60819
- TagResourceCommand as TagResourceCommand15,
60820
- ListTagsForResourceCommand as ListTagsForResourceCommand20,
62124
+ TagResourceCommand as TagResourceCommand16,
62125
+ ListTagsForResourceCommand as ListTagsForResourceCommand21,
60821
62126
  LifecyclePolicyNotFoundException,
60822
62127
  RepositoryNotFoundException
60823
62128
  } from "@aws-sdk/client-ecr";
@@ -61005,7 +62310,7 @@ var ECRProvider = class {
61005
62310
  const repoArn = describeResponse.repositories?.[0]?.repositoryArn;
61006
62311
  if (repoArn && newTags) {
61007
62312
  await this.getClient().send(
61008
- new TagResourceCommand15({
62313
+ new TagResourceCommand16({
61009
62314
  resourceArn: repoArn,
61010
62315
  tags: newTags
61011
62316
  })
@@ -61147,7 +62452,7 @@ var ECRProvider = class {
61147
62452
  if (r.repositoryArn) {
61148
62453
  try {
61149
62454
  const tagsResp = await this.getClient().send(
61150
- new ListTagsForResourceCommand20({ resourceArn: r.repositoryArn })
62455
+ new ListTagsForResourceCommand21({ resourceArn: r.repositoryArn })
61151
62456
  );
61152
62457
  const tags = normalizeAwsTagsToCfn(tagsResp.tags);
61153
62458
  result["Tags"] = tags;
@@ -61193,7 +62498,7 @@ var ECRProvider = class {
61193
62498
  continue;
61194
62499
  try {
61195
62500
  const tagsResp = await this.getClient().send(
61196
- new ListTagsForResourceCommand20({ resourceArn: repo.repositoryArn })
62501
+ new ListTagsForResourceCommand21({ resourceArn: repo.repositoryArn })
61197
62502
  );
61198
62503
  if (matchesCdkPath(tagsResp.tags, input.cdkPath)) {
61199
62504
  return { physicalId: repo.repositoryName, attributes: {} };
@@ -62252,6 +63557,7 @@ function registerAllProviders(registry) {
62252
63557
  registry.register("AWS::KMS::Key", kmsProvider);
62253
63558
  registry.register("AWS::KMS::Alias", kmsProvider);
62254
63559
  registry.register("AWS::Kinesis::Stream", new KinesisStreamProvider());
63560
+ registry.register("AWS::Kinesis::StreamConsumer", new KinesisStreamConsumerProvider());
62255
63561
  const efsProvider = new EFSProvider();
62256
63562
  registry.register("AWS::EFS::FileSystem", efsProvider);
62257
63563
  registry.register("AWS::EFS::MountTarget", efsProvider);
@@ -67067,7 +68373,7 @@ function reorderArgs(argv) {
67067
68373
  }
67068
68374
  async function main() {
67069
68375
  const program = new Command14();
67070
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.61.0");
68376
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.63.0");
67071
68377
  program.addCommand(createBootstrapCommand());
67072
68378
  program.addCommand(createSynthCommand());
67073
68379
  program.addCommand(createListCommand());