@go-to-k/cdkd 0.226.0 → 0.227.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { A as withErrorHandling, B as generateResourceNameWithFallback, C as StackHasActiveImportsError, F as getLiveRenderer, H as withStackName, I as PATTERN_B_NAME_PROPERTIES, L as PATTERN_B_RESOURCE_TYPES, M as getLogger, P as runStackBuffered, S as ResourceUpdateNotSupportedError, V as withSkipPrefix, _ as MissingCdkCliError, a as assertRegionMatch, b as ProvisioningError, f as LocalInvokeBuildError$1, i as resolveExplicitPhysicalId, k as normalizeAwsError, l as CdkdError, m as LocalStartServiceError, n as matchesCdkPath, o as disableInstanceApiTermination, p as LocalMigrateError, r as normalizeAwsTagsToCfn, s as isTerminationProtectionPropagationError, t as CDK_PATH_TAG, v as NestedStackChildDirectDestroyError, w as StackTerminationProtectionError, x as ResourceTimeoutError, y as PartialFailureError, z as generateResourceName } from "./import-helpers-wLipXr5g.js";
3
3
  import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-pjPwZz1r.js";
4
- import { $ as AssemblyReader, A as shouldRetainResource, B as getDefaultStateBucketName, C as applyRoleArnIfSet, D as LockManager, E as TemplateParser, F as formatDockerLoginError, G as resolveStateBucketWithDefault, H as resolveApp, I as getDockerCmd, J as CFN_TEMPLATE_BODY_LIMIT, K as resolveStateBucketWithDefaultAndSource, L as runDockerForeground, M as stringifyValue, N as WorkGraph, O as S3StateBackend, P as buildDockerImage, Q as uploadCfnTemplate, R as runDockerStreaming, S as IntrinsicFunctionResolver, T as DagBuilder, U as resolveCaptureObservedState, V as getLegacyStateBucketName, W as resolveSkipPrefix, X as MIGRATE_TMP_PREFIX, Y as CFN_TEMPLATE_URL_LIMIT, Z as findLargeInlineResources, _ as IAMRoleProvider, a as withRetry, b as findActionableSilentDrops, c as computeImplicitDeleteEdges, d as bold, f as cyan, g as yellow, h as red, i as withResourceDeadline, j as AssetPublisher, k as rebuildClientForBucketRegion, l as extractDeploymentEventError, m as green, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as isRetryableTransientError, p as gray, q as warnDeprecatedNoPrefixCliFlag, r as DeployEngine, s as IMPLICIT_DELETE_DEPENDENCIES, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as resolveBucketRegion, u as formatResourceLine, v as collectInlinePolicyNamesManagedBySiblings, w as DiffCalculator, x as CloudControlProvider, y as ProviderRegistry, z as Synthesizer } from "./deploy-engine-DM557Qjg.js";
4
+ import { $ as findLargeInlineResources, A as shouldRetainResource, B as getDockerImageBySourceHash, C as applyRoleArnIfSet, D as LockManager, E as TemplateParser, F as formatDockerLoginError, G as resolveCaptureObservedState, H as getDefaultStateBucketName, I as getDockerCmd, J as resolveStateBucketWithDefaultAndSource, K as resolveSkipPrefix, L as runDockerForeground, M as stringifyValue, N as WorkGraph, O as S3StateBackend, P as buildDockerImage, Q as MIGRATE_TMP_PREFIX, R as runDockerStreaming, S as IntrinsicFunctionResolver, T as DagBuilder, U as getLegacyStateBucketName, V as Synthesizer, W as resolveApp, X as CFN_TEMPLATE_BODY_LIMIT, Y as warnDeprecatedNoPrefixCliFlag, Z as CFN_TEMPLATE_URL_LIMIT, _ as IAMRoleProvider, a as withRetry, b as findActionableSilentDrops, c as computeImplicitDeleteEdges, d as bold, et as uploadCfnTemplate, f as cyan, g as yellow, h as red, i as withResourceDeadline, j as AssetPublisher, k as rebuildClientForBucketRegion, l as extractDeploymentEventError, m as green, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as isRetryableTransientError, p as gray, q as resolveStateBucketWithDefault, r as DeployEngine, rt as resolveBucketRegion, s as IMPLICIT_DELETE_DEPENDENCIES, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as AssemblyReader, u as formatResourceLine, v as collectInlinePolicyNamesManagedBySiblings, w as DiffCalculator, x as CloudControlProvider, y as ProviderRegistry, z as AssetManifestLoader } from "./deploy-engine-Bl_Ka0hj.js";
5
5
  import { t as ASGProvider } from "./asg-provider-B_hrCxRx.js";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { randomBytes, randomUUID } from "node:crypto";
@@ -32,13 +32,13 @@ import { tmpdir } from "node:os";
32
32
  import { AssociateVPCWithHostedZoneCommand, ChangeResourceRecordSetsCommand, ChangeTagsForResourceCommand, CreateHostedZoneCommand, CreateQueryLoggingConfigCommand, DeleteHostedZoneCommand, DeleteQueryLoggingConfigCommand, DisassociateVPCFromHostedZoneCommand, GetHostedZoneCommand, ListHostedZonesByNameCommand, ListHostedZonesCommand, ListQueryLoggingConfigsCommand, ListResourceRecordSetsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$6, Route53Client, UpdateHostedZoneCommentCommand, UpdateHostedZoneFeaturesCommand } from "@aws-sdk/client-route-53";
33
33
  import { AddTagsCommand, CreateListenerCommand, CreateLoadBalancerCommand, CreateTargetGroupCommand, DeleteListenerCommand, DeleteLoadBalancerCommand, DeleteTargetGroupCommand, DescribeListenerAttributesCommand, DescribeListenersCommand, DescribeLoadBalancerAttributesCommand, DescribeLoadBalancersCommand, DescribeTagsCommand, DescribeTargetGroupsCommand, ElasticLoadBalancingV2Client, ModifyListenerAttributesCommand, ModifyListenerCommand, ModifyLoadBalancerAttributesCommand, ModifyTargetGroupCommand, RemoveTagsCommand, SetIpAddressTypeCommand, SetSecurityGroupsCommand, SetSubnetsCommand } from "@aws-sdk/client-elastic-load-balancing-v2";
34
34
  import { CreateAliasCommand, CreateKeyCommand, DeleteAliasCommand, DescribeKeyCommand, DisableKeyCommand, DisableKeyRotationCommand, EnableKeyCommand, EnableKeyRotationCommand, GetKeyPolicyCommand, GetKeyRotationStatusCommand, KMSClient, ListAliasesCommand, ListKeysCommand, ListResourceTagsCommand, NotFoundException as NotFoundException$2, PutKeyPolicyCommand, ScheduleKeyDeletionCommand, TagResourceCommand as TagResourceCommand$9, UntagResourceCommand as UntagResourceCommand$9, UpdateAliasCommand, UpdateKeyDescriptionCommand } from "@aws-sdk/client-kms";
35
+ import { join as join$1 } from "path";
35
36
  import { CreateRepositoryCommand, DeleteLifecyclePolicyCommand, DeleteRepositoryCommand, DeleteRepositoryPolicyCommand, DescribeRepositoriesCommand, ECRClient, GetAuthorizationTokenCommand, GetLifecyclePolicyCommand, LifecyclePolicyNotFoundException, ListTagsForResourceCommand as ListTagsForResourceCommand$7, PutImageScanningConfigurationCommand, PutImageTagMutabilityCommand, PutLifecyclePolicyCommand, RepositoryNotFoundException, SetRepositoryPolicyCommand, TagResourceCommand as TagResourceCommand$10 } from "@aws-sdk/client-ecr";
36
37
  import graphlib from "graphlib";
37
38
  import { AddTagsToResourceCommand as AddTagsToResourceCommand$1, CreateDBClusterCommand, CreateDBInstanceCommand, CreateDBProxyCommand, CreateDBProxyEndpointCommand, CreateDBSubnetGroupCommand, DBProxyEndpointNotFoundFault, DBProxyNotFoundFault, DBProxyTargetGroupNotFoundFault, DBProxyTargetNotFoundFault, DeleteDBClusterCommand, DeleteDBInstanceCommand, DeleteDBProxyCommand, DeleteDBProxyEndpointCommand, DeleteDBSubnetGroupCommand, DeregisterDBProxyTargetsCommand, DescribeDBClustersCommand, DescribeDBInstancesCommand, DescribeDBProxiesCommand, DescribeDBProxyEndpointsCommand, DescribeDBProxyTargetGroupsCommand, DescribeDBProxyTargetsCommand, DescribeDBSubnetGroupsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$8, ModifyDBClusterCommand, ModifyDBInstanceCommand, ModifyDBProxyCommand, ModifyDBProxyEndpointCommand, ModifyDBProxyTargetGroupCommand, ModifyDBSubnetGroupCommand, RDSClient, RegisterDBProxyTargetsCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$1 } from "@aws-sdk/client-rds";
38
39
  import { AddTagsToResourceCommand as AddTagsToResourceCommand$2, CreateCacheClusterCommand, CreateCacheSubnetGroupCommand, DeleteCacheClusterCommand, DeleteCacheSubnetGroupCommand, DescribeCacheClustersCommand, DescribeCacheSubnetGroupsCommand, ElastiCacheClient, ListTagsForResourceCommand as ListTagsForResourceCommand$9, ModifyCacheClusterCommand, ModifyCacheSubnetGroupCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$2 } from "@aws-sdk/client-elasticache";
39
40
  import { Command, Option } from "commander";
40
41
  import { writeFileSync as writeFileSync$1 } from "fs";
41
- import { join as join$1 } from "path";
42
42
  import * as readline$1 from "node:readline/promises";
43
43
  import readline from "node:readline/promises";
44
44
  import * as zlib from "node:zlib";
@@ -67,7 +67,6 @@ import { A2A_CONTAINER_PORT, A2A_PATH, AGENTCORE_A2A_PROTOCOL, AGENTCORE_AGUI_PR
67
67
  import { createServer } from "node:net";
68
68
  import { promisify } from "node:util";
69
69
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
70
- import { readFile } from "fs/promises";
71
70
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
72
71
  import { WebSocketServer } from "ws";
73
72
 
@@ -1553,7 +1552,7 @@ const FLUSH_INTERVAL_MS = 2e3;
1553
1552
  const FLUSH_EVENT_THRESHOLD = 50;
1554
1553
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
1555
1554
  function getCdkdVersion() {
1556
- return "0.226.0";
1555
+ return "0.227.1";
1557
1556
  }
1558
1557
  /**
1559
1558
  * Generate a time-sortable unique run id, e.g.
@@ -9758,6 +9757,7 @@ var DynamoDBTableProvider = class {
9758
9757
  this.logger.debug(`Updated WarmThroughput on DynamoDB table ${physicalId}`);
9759
9758
  }
9760
9759
  }
9760
+ if (JSON.stringify(properties["GlobalSecondaryIndexes"]) !== JSON.stringify(previousProperties["GlobalSecondaryIndexes"])) await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"]);
9761
9761
  if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) await this.applyPointInTimeRecovery(physicalId, properties["PointInTimeRecoverySpecification"], previousProperties["PointInTimeRecoverySpecification"]);
9762
9762
  if (JSON.stringify(properties["TimeToLiveSpecification"]) !== JSON.stringify(previousProperties["TimeToLiveSpecification"])) await this.applyTimeToLive(physicalId, properties["TimeToLiveSpecification"], previousProperties["TimeToLiveSpecification"]);
9763
9763
  if (JSON.stringify(properties["ResourcePolicy"]) !== JSON.stringify(previousProperties["ResourcePolicy"])) {
@@ -10083,6 +10083,79 @@ var DynamoDBTableProvider = class {
10083
10083
  throw new Error(`Table ${tableName} did not reach ACTIVE status within ${maxAttempts} seconds after UpdateTable`);
10084
10084
  }
10085
10085
  /**
10086
+ * Poll DescribeTable until the table is ACTIVE AND every Global Secondary
10087
+ * Index is ACTIVE (not CREATING / UPDATING / DELETING / BACKFILLING). Used
10088
+ * between GSI mutations because a freshly-created index keeps backfilling
10089
+ * after the table itself returns to ACTIVE, and AWS rejects the next GSI op
10090
+ * until the prior index settles.
10091
+ */
10092
+ async waitForTableAndIndexesActive(tableName, maxAttempts = 1800) {
10093
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
10094
+ const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName }))).Table;
10095
+ const tableActive = table?.TableStatus === "ACTIVE";
10096
+ const indexesActive = (table?.GlobalSecondaryIndexes ?? []).every((gsi) => gsi.IndexStatus === "ACTIVE");
10097
+ if (tableActive && indexesActive) return;
10098
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
10099
+ }
10100
+ throw new Error(`Table ${tableName} and its global secondary indexes did not reach ACTIVE within ${maxAttempts} seconds after UpdateTable`);
10101
+ }
10102
+ /**
10103
+ * Apply Global Secondary Index add / remove / per-index throughput changes
10104
+ * via UpdateTable's `GlobalSecondaryIndexUpdates`.
10105
+ *
10106
+ * AWS constraints mirrored here:
10107
+ * - At most ONE GSI Create or Delete per UpdateTable call; a second
10108
+ * mutation while the table / an index is still building is rejected. Each
10109
+ * op therefore runs in its own UpdateTable and waits for ACTIVE before the
10110
+ * next (creating GSIs also go through a BACKFILLING phase that ACTIVE
10111
+ * covers).
10112
+ * - A GSI `Create` must carry the AttributeDefinitions for the new index's
10113
+ * key attributes — the full desired AttributeDefinitions array is passed
10114
+ * so every newly-referenced attribute is defined.
10115
+ * - On an existing same-name index, only a PROVISIONED `ProvisionedThroughput`
10116
+ * (RCU/WCU) change is mutable in place and is issued as an `Update`. A
10117
+ * `KeySchema` / `Projection` change is immutable in place (AWS models it as
10118
+ * a delete + re-create); since the diff keys GSIs by name it would not emit
10119
+ * a remove-then-add pair, so this method throws on such a change rather than
10120
+ * silently dropping it.
10121
+ */
10122
+ async applyGsiUpdates(physicalId, resourceType, logicalId, previousGsis, desiredGsis, desiredAttributeDefinitions) {
10123
+ const prev = previousGsis ?? [];
10124
+ const desired = desiredGsis ?? [];
10125
+ const prevByName = new Map(prev.filter((g) => g.IndexName).map((g) => [g.IndexName, g]));
10126
+ const desiredByName = new Map(desired.filter((g) => g.IndexName).map((g) => [g.IndexName, g]));
10127
+ const ops = [];
10128
+ for (const name of prevByName.keys()) if (!desiredByName.has(name)) ops.push({ Delete: { IndexName: name } });
10129
+ for (const [name, gsi] of desiredByName) if (!prevByName.has(name)) {
10130
+ if (!gsi.KeySchema) throw new ProvisioningError(`GlobalSecondaryIndex ${name} on DynamoDB table ${logicalId} is missing KeySchema`, resourceType, logicalId, physicalId);
10131
+ ops.push({ Create: {
10132
+ IndexName: name,
10133
+ KeySchema: gsi.KeySchema,
10134
+ Projection: gsi.Projection,
10135
+ ...gsi.ProvisionedThroughput ? { ProvisionedThroughput: gsi.ProvisionedThroughput } : {},
10136
+ ...gsi.OnDemandThroughput ? { OnDemandThroughput: gsi.OnDemandThroughput } : {}
10137
+ } });
10138
+ } else {
10139
+ const before = prevByName.get(name);
10140
+ if (JSON.stringify(before.KeySchema) !== JSON.stringify(gsi.KeySchema) || JSON.stringify(before.Projection) !== JSON.stringify(gsi.Projection)) throw new ProvisioningError(`GlobalSecondaryIndex ${name} on DynamoDB table ${logicalId} changed its KeySchema or Projection, which DynamoDB cannot modify in place. Rename the index (so it is dropped and re-created) or replace the table.`, resourceType, logicalId, physicalId);
10141
+ if (gsi.ProvisionedThroughput && JSON.stringify(before.ProvisionedThroughput) !== JSON.stringify(gsi.ProvisionedThroughput)) ops.push({ Update: {
10142
+ IndexName: name,
10143
+ ProvisionedThroughput: gsi.ProvisionedThroughput
10144
+ } });
10145
+ }
10146
+ for (const op of ops) {
10147
+ const input = {
10148
+ TableName: physicalId,
10149
+ GlobalSecondaryIndexUpdates: [op]
10150
+ };
10151
+ if (op.Create && desiredAttributeDefinitions) input.AttributeDefinitions = desiredAttributeDefinitions;
10152
+ await this.dynamoDBClient.send(new UpdateTableCommand(input));
10153
+ await this.waitForTableAndIndexesActive(physicalId);
10154
+ const verb = op.Create ? "created" : op.Delete ? "deleted" : "updated";
10155
+ this.logger.debug(`${verb} GSI ${op.Create?.IndexName ?? op.Delete?.IndexName ?? op.Update?.IndexName} on DynamoDB table ${physicalId}`);
10156
+ }
10157
+ }
10158
+ /**
10086
10159
  * Resolve a single `Fn::GetAtt` attribute for an existing DynamoDB table.
10087
10160
  *
10088
10161
  * CloudFormation's `AWS::DynamoDB::Table` exposes `Arn`, `StreamArn`
@@ -12093,6 +12166,21 @@ var CloudWatchAlarmProvider = class {
12093
12166
  "EvaluateLowSampleCountPercentile",
12094
12167
  "ThresholdMetricId"
12095
12168
  ])]]);
12169
+ /**
12170
+ * Properties this provider deliberately does NOT wire through to the SDK,
12171
+ * with a one-line rationale per entry (consumed by the property-coverage
12172
+ * check, issue #391).
12173
+ *
12174
+ * `EvaluationCriteria` / `EvaluationInterval` appear in the CloudFormation
12175
+ * `AWS::CloudWatch::Alarm` registry schema but are absent from BOTH the AWS
12176
+ * SDK `PutMetricAlarm` input (`@aws-sdk/client-cloudwatch`) AND the
12177
+ * aws-cdk-lib `CfnAlarm` L1 — a newer CFn-schema surface ahead of SDK / CDK
12178
+ * support, so there is no wire path to forward them and no CDK app can emit
12179
+ * them. Per the #609 backfillability rule (a property absent from EITHER the
12180
+ * SDK create input OR the CDK L1 is not backfillable), they are classified
12181
+ * unhandled-by-design rather than left as a "not yet implemented" TODO.
12182
+ */
12183
+ unhandledByDesign = new Map([["AWS::CloudWatch::Alarm", new Map([["EvaluationCriteria", "Absent from both the SDK PutMetricAlarm input and the aws-cdk-lib CfnAlarm L1 (a newer CFn-schema-only property ahead of SDK/CDK support); no wire path to forward it and no CDK app can emit it."], ["EvaluationInterval", "Absent from both the SDK PutMetricAlarm input and the aws-cdk-lib CfnAlarm L1 (a newer CFn-schema-only property ahead of SDK/CDK support); no wire path to forward it and no CDK app can emit it."]])]]);
12096
12184
  constructor() {
12097
12185
  const awsClients = getAwsClients();
12098
12186
  this.cloudWatchClient = awsClients.cloudWatch;
@@ -19294,6 +19382,7 @@ var AgentCoreRuntimeProvider = class {
19294
19382
  */
19295
19383
  var StepFunctionsProvider = class {
19296
19384
  sfnClient;
19385
+ s3Client;
19297
19386
  providerRegion = process.env["AWS_REGION"];
19298
19387
  logger = getLogger().child("StepFunctionsProvider");
19299
19388
  handledProperties = new Map([["AWS::StepFunctions::StateMachine", new Set([
@@ -19305,6 +19394,7 @@ var StepFunctionsProvider = class {
19305
19394
  "Tags",
19306
19395
  "DefinitionString",
19307
19396
  "Definition",
19397
+ "DefinitionS3Location",
19308
19398
  "DefinitionSubstitutions",
19309
19399
  "EncryptionConfiguration"
19310
19400
  ])]]);
@@ -19312,6 +19402,10 @@ var StepFunctionsProvider = class {
19312
19402
  if (!this.sfnClient) this.sfnClient = new SFNClient(this.providerRegion ? { region: this.providerRegion } : {});
19313
19403
  return this.sfnClient;
19314
19404
  }
19405
+ getS3Client() {
19406
+ if (!this.s3Client) this.s3Client = new S3Client(this.providerRegion ? { region: this.providerRegion } : {});
19407
+ return this.s3Client;
19408
+ }
19315
19409
  /**
19316
19410
  * Create a Step Functions state machine
19317
19411
  */
@@ -19321,7 +19415,7 @@ var StepFunctionsProvider = class {
19321
19415
  const roleArn = properties["RoleArn"];
19322
19416
  if (!roleArn) throw new ProvisioningError(`RoleArn is required for Step Functions state machine ${logicalId}`, resourceType, logicalId);
19323
19417
  try {
19324
- const definitionString = this.buildDefinitionString(properties);
19418
+ const definitionString = await this.buildDefinitionString(properties);
19325
19419
  let tags;
19326
19420
  if (properties["Tags"]) tags = properties["Tags"].map((tag) => ({
19327
19421
  key: tag.Key,
@@ -19364,7 +19458,7 @@ var StepFunctionsProvider = class {
19364
19458
  async update(logicalId, physicalId, resourceType, properties, previousProperties) {
19365
19459
  this.logger.debug(`Updating Step Functions state machine ${logicalId}: ${physicalId}`);
19366
19460
  try {
19367
- const definitionString = this.buildDefinitionString(properties);
19461
+ const definitionString = await this.buildDefinitionString(properties);
19368
19462
  const encryptionConfiguration = mapEncryptionConfiguration(properties["EncryptionConfiguration"]);
19369
19463
  const loggingConfiguration = mapLoggingConfiguration(properties["LoggingConfiguration"]);
19370
19464
  const tracingConfiguration = mapTracingConfiguration(properties["TracingConfiguration"]);
@@ -19564,10 +19658,22 @@ var StepFunctionsProvider = class {
19564
19658
  return false;
19565
19659
  }
19566
19660
  /**
19567
- * Build definition string from CDK properties.
19568
- * Handles both DefinitionString (string) and DefinitionString (object) forms.
19661
+ * Build the state-machine definition string from CDK properties.
19662
+ *
19663
+ * Precedence (mirrors CloudFormation): an inline `DefinitionString` /
19664
+ * `Definition` wins over `DefinitionS3Location`. The inline forms are
19665
+ * returned verbatim — any `DefinitionSubstitutions` they need are already
19666
+ * folded into the template as `Fn::Sub` and resolved by cdkd's intrinsic
19667
+ * resolver before the provider sees them.
19668
+ *
19669
+ * `DefinitionS3Location` ({@link https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-s3location.html S3Location})
19670
+ * has no SDK `CreateStateMachine` field — CloudFormation reads the S3 object
19671
+ * and inlines its contents as the `definition`. cdkd does the same: fetch
19672
+ * the object body, then apply `DefinitionSubstitutions` ourselves because
19673
+ * the intrinsic resolver cannot reach into S3 content (unlike the inline
19674
+ * path, where substitutions arrive pre-resolved).
19569
19675
  */
19570
- buildDefinitionString(properties) {
19676
+ async buildDefinitionString(properties) {
19571
19677
  const definitionString = properties["DefinitionString"];
19572
19678
  const definition = properties["Definition"];
19573
19679
  if (definitionString !== void 0) {
@@ -19578,8 +19684,44 @@ var StepFunctionsProvider = class {
19578
19684
  if (typeof definition === "string") return definition;
19579
19685
  return JSON.stringify(definition);
19580
19686
  }
19687
+ const s3Location = properties["DefinitionS3Location"];
19688
+ if (s3Location?.Bucket && s3Location.Key) {
19689
+ const body = await this.fetchDefinitionFromS3(s3Location.Bucket, s3Location.Key, s3Location.Version);
19690
+ return this.applyDefinitionSubstitutions(body, properties["DefinitionSubstitutions"]);
19691
+ }
19581
19692
  return "{}";
19582
19693
  }
19694
+ /**
19695
+ * Fetch a state-machine definition (Amazon States Language JSON/YAML) from
19696
+ * S3 and return its body as a UTF-8 string. Honors an optional object
19697
+ * version for versioning-enabled buckets.
19698
+ */
19699
+ async fetchDefinitionFromS3(bucket, key, version) {
19700
+ this.logger.debug(`Fetching state-machine definition from s3://${bucket}/${key}${version ? `?versionId=${version}` : ""}`);
19701
+ const resp = await this.getS3Client().send(new GetObjectCommand({
19702
+ Bucket: bucket,
19703
+ Key: key,
19704
+ ...version && { VersionId: version }
19705
+ }));
19706
+ if (!resp.Body) throw new Error(`DefinitionS3Location object s3://${bucket}/${key} returned no body`);
19707
+ const body = await resp.Body.transformToString();
19708
+ if (body.length === 0) throw new Error(`DefinitionS3Location object s3://${bucket}/${key} returned an empty body`);
19709
+ return body;
19710
+ }
19711
+ /**
19712
+ * Apply CloudFormation `DefinitionSubstitutions` (a `{ name: value }` map) to
19713
+ * a definition body by replacing each `${name}` token with its value.
19714
+ * Returns the body unchanged when no substitutions are supplied.
19715
+ */
19716
+ applyDefinitionSubstitutions(body, substitutions) {
19717
+ if (substitutions === null || typeof substitutions !== "object" || Array.isArray(substitutions)) return body;
19718
+ let result = body;
19719
+ for (const [name, value] of Object.entries(substitutions)) {
19720
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") continue;
19721
+ result = result.split(`\${${name}}`).join(String(value));
19722
+ }
19723
+ return result;
19724
+ }
19583
19725
  };
19584
19726
  /**
19585
19727
  * Translate a CFn-shape `EncryptionConfiguration` (PascalCase) into the SDK's
@@ -47532,133 +47674,6 @@ const STREAM_PRELUDE_SEPARATOR = Buffer.from([
47532
47674
  0
47533
47675
  ]);
47534
47676
 
47535
- //#endregion
47536
- //#region src/assets/asset-manifest-loader.ts
47537
- /**
47538
- * Asset manifest loader
47539
- *
47540
- * Loads and parses CDK asset manifests from the CDK output directory
47541
- */
47542
- var AssetManifestLoader = class {
47543
- logger = getLogger().child("AssetManifestLoader");
47544
- /**
47545
- * Load asset manifest from CDK output directory
47546
- *
47547
- * @param cdkOutputDir CDK output directory (e.g., "cdk.out")
47548
- * @param stackName Stack name
47549
- * @returns Asset manifest or null if not found
47550
- */
47551
- async loadManifest(cdkOutputDir, stackName) {
47552
- const manifestPath = join$1(cdkOutputDir, `${stackName}.assets.json`);
47553
- try {
47554
- this.logger.debug(`Loading asset manifest from: ${manifestPath}`);
47555
- const content = await readFile(manifestPath, "utf-8");
47556
- const manifest = JSON.parse(content);
47557
- this.logger.debug(`Loaded asset manifest: ${Object.keys(manifest.files).length} file assets, ${Object.keys(manifest.dockerImages).length} docker image assets`);
47558
- return manifest;
47559
- } catch (error) {
47560
- if (error.code === "ENOENT") {
47561
- this.logger.debug(`Asset manifest not found: ${manifestPath}`);
47562
- return null;
47563
- }
47564
- throw new Error(`Failed to load asset manifest from ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
47565
- }
47566
- }
47567
- /**
47568
- * Get file assets from manifest (excludes CloudFormation templates)
47569
- *
47570
- * @param manifest Asset manifest
47571
- * @returns Map of asset hash to file asset
47572
- */
47573
- getFileAssets(manifest) {
47574
- const fileAssets = /* @__PURE__ */ new Map();
47575
- for (const [assetHash, asset] of Object.entries(manifest.files)) {
47576
- if (asset.source.path.endsWith(".json") || asset.source.path.endsWith(".template.json")) {
47577
- this.logger.debug(`Skipping CloudFormation template asset: ${asset.displayName}`);
47578
- continue;
47579
- }
47580
- fileAssets.set(assetHash, asset);
47581
- }
47582
- this.logger.debug(`Found ${fileAssets.size} file assets (excluding templates)`);
47583
- return fileAssets;
47584
- }
47585
- /**
47586
- * Get asset source path (absolute path)
47587
- *
47588
- * @param cdkOutputDir CDK output directory
47589
- * @param asset File asset
47590
- * @returns Absolute path to asset source
47591
- */
47592
- getAssetSourcePath(cdkOutputDir, asset) {
47593
- return join$1(cdkOutputDir, asset.source.path);
47594
- }
47595
- /**
47596
- * Resolve asset destination values (replace ${AWS::AccountId}, ${AWS::Region}, etc.)
47597
- *
47598
- * @param value Value with placeholders
47599
- * @param accountId AWS account ID
47600
- * @param region AWS region
47601
- * @param partition AWS partition (default: "aws")
47602
- * @returns Resolved value
47603
- */
47604
- resolveAssetDestinationValue(value, accountId, region, partition = "aws") {
47605
- return value.replace(/\$\{AWS::AccountId\}/g, accountId).replace(/\$\{AWS::Region\}/g, region).replace(/\$\{AWS::Partition\}/g, partition);
47606
- }
47607
- };
47608
- /**
47609
- * Look up the docker-image asset that backs a Lambda's `Code.ImageUri`.
47610
- *
47611
- * The CDK template synthesizes `Code.ImageUri` as a `Fn::Sub` whose body
47612
- * references the bootstrap ECR repo and ends in `:<hash>` — that hash is
47613
- * the same key used in `manifest.dockerImages[<hash>]`. cdkd extracts the
47614
- * hash by walking known image-URI shapes; on miss, when the manifest has
47615
- * exactly one Docker image, we fall back to it (single-asset heuristic) so
47616
- * locally-built non-bootstrapped images still work. This is documented as
47617
- * a v1 limitation; immutable digest pins (`@sha256:<digest>`) hit the same
47618
- * fallback path.
47619
- *
47620
- * Returns the `(hash, asset)` pair when matched, or `undefined` when both
47621
- * the regex AND the single-asset fallback miss (typically: 0 docker assets,
47622
- * or 2+ docker assets with no hash match — the caller should treat this as
47623
- * "fall through to the ECR-pull path").
47624
- *
47625
- * Exported as a free function (not a method) so the local-invoke modules
47626
- * can reuse it without depending on the `AssetManifestLoader` instance —
47627
- * the manifest itself is a plain JSON shape.
47628
- */
47629
- function getDockerImageBySourceHash(manifest, imageUri) {
47630
- const dockerImages = manifest.dockerImages ?? {};
47631
- const entries = Object.entries(dockerImages);
47632
- if (entries.length === 0) return void 0;
47633
- const hash = extractHashFromImageUri(imageUri);
47634
- if (hash !== void 0) {
47635
- const asset = dockerImages[hash];
47636
- if (asset) return {
47637
- hash,
47638
- asset
47639
- };
47640
- }
47641
- if (entries.length === 1) {
47642
- const [singleHash, singleAsset] = entries[0];
47643
- return {
47644
- hash: singleHash,
47645
- asset: singleAsset
47646
- };
47647
- }
47648
- }
47649
- /**
47650
- * Extract the source hash from a Lambda `Code.ImageUri` string. CDK's
47651
- * bootstrap layout ends every image URI in `:<hex-hash>`, and that hash
47652
- * is the same key used in the asset manifest's `dockerImages` map.
47653
- *
47654
- * Returns `undefined` for shapes we can't parse (digest pins, missing tag,
47655
- * etc.) — the caller falls back to the single-asset heuristic.
47656
- */
47657
- function extractHashFromImageUri(imageUri) {
47658
- if (imageUri.includes("@sha256:")) return void 0;
47659
- return /:([a-f0-9]{8,})$/.exec(imageUri)?.[1];
47660
- }
47661
-
47662
47677
  //#endregion
47663
47678
  //#region src/utils/single-flight.ts
47664
47679
  /**
@@ -54681,7 +54696,7 @@ function reorderArgs(argv) {
54681
54696
  async function main() {
54682
54697
  installPipeCloseHandler();
54683
54698
  const program = new Command();
54684
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.226.0");
54699
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.227.1");
54685
54700
  program.addCommand(createBootstrapCommand());
54686
54701
  program.addCommand(createSynthCommand());
54687
54702
  program.addCommand(createListCommand());