@go-to-k/cdkd 0.137.3 → 0.138.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 +182 -84
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -55,7 +55,7 @@ import { AddTagsCommand as AddTagsCommand$1, CloudTrailClient, CreateTrailComman
|
|
|
55
55
|
import { BatchGetProjectsCommand, CodeBuildClient, CreateProjectCommand, DeleteProjectCommand, ListProjectsCommand, ResourceNotFoundException as ResourceNotFoundException$9, UpdateProjectCommand } from "@aws-sdk/client-codebuild";
|
|
56
56
|
import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$18, ListVectorBucketsCommand, S3VectorsClient } from "@aws-sdk/client-s3vectors";
|
|
57
57
|
import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$19, NotFoundException as NotFoundException$5, S3TablesClient } from "@aws-sdk/client-s3tables";
|
|
58
|
-
import { AttachTrafficSourcesCommand, AutoScalingClient, CreateAutoScalingGroupCommand, DeleteAutoScalingGroupCommand, DeleteLifecycleHookCommand, DeleteNotificationConfigurationCommand, DescribeAutoScalingGroupsCommand, DescribeLifecycleHooksCommand, DescribeNotificationConfigurationsCommand, DescribeTrafficSourcesCommand, DetachTrafficSourcesCommand, DisableMetricsCollectionCommand, EnableMetricsCollectionCommand, PutLifecycleHookCommand, PutNotificationConfigurationCommand, UpdateAutoScalingGroupCommand } from "@aws-sdk/client-auto-scaling";
|
|
58
|
+
import { AttachLoadBalancerTargetGroupsCommand, AttachLoadBalancersCommand, AttachTrafficSourcesCommand, AutoScalingClient, CreateAutoScalingGroupCommand, CreateOrUpdateTagsCommand, DeleteAutoScalingGroupCommand, DeleteLifecycleHookCommand, DeleteNotificationConfigurationCommand, DeleteTagsCommand as DeleteTagsCommand$1, DescribeAutoScalingGroupsCommand, DescribeLifecycleHooksCommand, DescribeNotificationConfigurationsCommand, DescribeTrafficSourcesCommand, DetachLoadBalancerTargetGroupsCommand, DetachLoadBalancersCommand, DetachTrafficSourcesCommand, DisableMetricsCollectionCommand, EnableMetricsCollectionCommand, PutLifecycleHookCommand, PutNotificationConfigurationCommand, UpdateAutoScalingGroupCommand } from "@aws-sdk/client-auto-scaling";
|
|
59
59
|
import * as readline from "node:readline/promises";
|
|
60
60
|
import { Document, Pair, Scalar, YAMLMap, YAMLSeq, parse as parse$1, stringify } from "yaml";
|
|
61
61
|
import { mkdir, mkdtemp } from "node:fs/promises";
|
|
@@ -29963,27 +29963,36 @@ var ECRProvider = class {
|
|
|
29963
29963
|
* Groups` already provides.
|
|
29964
29964
|
*
|
|
29965
29965
|
* Update has narrower coverage than create: AWS does not support modifying
|
|
29966
|
-
* `AutoScalingGroupName` (immutable)
|
|
29967
|
-
*
|
|
29968
|
-
*
|
|
29969
|
-
* `
|
|
29970
|
-
*
|
|
29971
|
-
*
|
|
29972
|
-
*
|
|
29973
|
-
*
|
|
29974
|
-
*
|
|
29975
|
-
*
|
|
29976
|
-
*
|
|
29977
|
-
*
|
|
29978
|
-
* InstancesPolicy / LaunchTemplate.
|
|
29966
|
+
* `AutoScalingGroupName` (immutable) — that diff still surfaces
|
|
29967
|
+
* `ResourceUpdateNotSupportedError` so the caller can `cdkd deploy
|
|
29968
|
+
* --replace`. The mutable fields handled in-place via
|
|
29969
|
+
* `UpdateAutoScalingGroup` include MinSize / MaxSize / DesiredCapacity /
|
|
29970
|
+
* VPCZoneIdentifier / HealthCheckType / HealthCheckGracePeriod /
|
|
29971
|
+
* DefaultCooldown / Cooldown / NewInstancesProtectedFromScaleIn /
|
|
29972
|
+
* MaxInstanceLifetime / TerminationPolicies / CapacityRebalance /
|
|
29973
|
+
* ServiceLinkedRoleARN / Context / DesiredCapacityType /
|
|
29974
|
+
* DefaultInstanceWarmup / AvailabilityZones / AvailabilityZoneDistribution
|
|
29975
|
+
* / AvailabilityZoneImpairmentPolicy / SkipZonalShiftValidation /
|
|
29976
|
+
* CapacityReservationSpecification / InstanceMaintenancePolicy /
|
|
29977
|
+
* DeletionProtection / MixedInstancesPolicy / LaunchTemplate.
|
|
29979
29978
|
*
|
|
29980
29979
|
* Sub-shape diffs are applied via dedicated AWS APIs before the main
|
|
29981
|
-
* `UpdateAutoScalingGroup` call:
|
|
29982
|
-
* `
|
|
29983
|
-
* `
|
|
29984
|
-
*
|
|
29985
|
-
* `
|
|
29986
|
-
*
|
|
29980
|
+
* `UpdateAutoScalingGroup` call:
|
|
29981
|
+
* - `Tags` → `CreateOrUpdateTags` / `DeleteTags` (#475)
|
|
29982
|
+
* - `LoadBalancerNames` → `AttachLoadBalancers` /
|
|
29983
|
+
* `DetachLoadBalancers` (#476)
|
|
29984
|
+
* - `TargetGroupARNs` → `AttachLoadBalancerTargetGroups` /
|
|
29985
|
+
* `DetachLoadBalancerTargetGroups` (#476)
|
|
29986
|
+
* - `MetricsCollection` → `EnableMetricsCollection` /
|
|
29987
|
+
* `DisableMetricsCollection`
|
|
29988
|
+
* - `LifecycleHookSpecificationList` → per-entry `PutLifecycleHook` /
|
|
29989
|
+
* `DeleteLifecycleHook`
|
|
29990
|
+
* - `TrafficSources` → `AttachTrafficSources` /
|
|
29991
|
+
* `DetachTrafficSources`
|
|
29992
|
+
* - `NotificationConfigurations` → per-topic
|
|
29993
|
+
* `PutNotificationConfiguration` /
|
|
29994
|
+
* `DeleteNotificationConfiguration`
|
|
29995
|
+
*
|
|
29987
29996
|
* Each helper is a no-op when the before/after JSON is identical.
|
|
29988
29997
|
*/
|
|
29989
29998
|
var ASGProvider = class {
|
|
@@ -30091,10 +30100,10 @@ var ASGProvider = class {
|
|
|
30091
30100
|
this.logger.debug(`Updating AutoScalingGroup ${logicalId}: ${physicalId}`);
|
|
30092
30101
|
const stringEq = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
30093
30102
|
if (!stringEq(properties["AutoScalingGroupName"], previousProperties["AutoScalingGroupName"])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AutoScalingGroupName is immutable on AWS — UpdateAutoScalingGroup does not accept a new name; the name is fixed at creation. Use cdkd deploy --replace to replace the group.");
|
|
30094
|
-
if (!stringEq(properties["Tags"] ?? [], previousProperties["Tags"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "Tags updates on AWS::AutoScaling::AutoScalingGroup are not yet implemented in cdkd (AWS exposes CreateOrUpdateTags / DeleteTags); use cdkd deploy --replace, or update the tags via AWS console / CLI.");
|
|
30095
|
-
if (!stringEq(properties["LoadBalancerNames"] ?? [], previousProperties["LoadBalancerNames"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "LoadBalancerNames diffs on AWS::AutoScaling::AutoScalingGroup are not yet implemented in cdkd (AWS exposes AttachLoadBalancers / DetachLoadBalancers); use cdkd deploy --replace.");
|
|
30096
|
-
if (!stringEq(properties["TargetGroupARNs"] ?? [], previousProperties["TargetGroupARNs"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "TargetGroupARNs diffs on AWS::AutoScaling::AutoScalingGroup are not yet implemented in cdkd (AWS exposes AttachLoadBalancerTargetGroups / DetachLoadBalancerTargetGroups); use cdkd deploy --replace.");
|
|
30097
30103
|
try {
|
|
30104
|
+
await this.applyTagsDiff(physicalId, properties["Tags"], previousProperties["Tags"]);
|
|
30105
|
+
await this.applyLoadBalancerNamesDiff(physicalId, properties["LoadBalancerNames"], previousProperties["LoadBalancerNames"]);
|
|
30106
|
+
await this.applyTargetGroupArnsDiff(physicalId, properties["TargetGroupARNs"], previousProperties["TargetGroupARNs"]);
|
|
30098
30107
|
await this.applyMetricsCollectionDiff(physicalId, properties["MetricsCollection"], previousProperties["MetricsCollection"]);
|
|
30099
30108
|
await this.applyLifecycleHooksDiff(physicalId, properties["LifecycleHookSpecificationList"], previousProperties["LifecycleHookSpecificationList"]);
|
|
30100
30109
|
await this.applyTrafficSourcesDiff(physicalId, properties["TrafficSources"], previousProperties["TrafficSources"]);
|
|
@@ -30354,6 +30363,99 @@ var ASGProvider = class {
|
|
|
30354
30363
|
sleep(ms) {
|
|
30355
30364
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
30356
30365
|
}
|
|
30366
|
+
/**
|
|
30367
|
+
* Diff and apply changes to the ASG's `Tags` property via the
|
|
30368
|
+
* `CreateOrUpdateTags` / `DeleteTags` AWS APIs (#475). CFn Tags shape is
|
|
30369
|
+
* `[{Key, Value, PropagateAtLaunch}]`; AWS Tag input adds `ResourceId`
|
|
30370
|
+
* (= the ASG name) and `ResourceType: 'auto-scaling-group'`.
|
|
30371
|
+
*
|
|
30372
|
+
* Diff semantics:
|
|
30373
|
+
* - Removed keys → `DeleteTags`.
|
|
30374
|
+
* - Added keys → `CreateOrUpdateTags`.
|
|
30375
|
+
* - Modified value or `PropagateAtLaunch` flag → `CreateOrUpdateTags`
|
|
30376
|
+
* (the AWS API upserts by `(ResourceId, ResourceType, Key)` tuple, so
|
|
30377
|
+
* a single upsert call replaces the old value).
|
|
30378
|
+
*
|
|
30379
|
+
* No-op when before/after JSON is identical.
|
|
30380
|
+
*/
|
|
30381
|
+
async applyTagsDiff(physicalId, next, prev) {
|
|
30382
|
+
if (JSON.stringify(next ?? []) === JSON.stringify(prev ?? [])) return;
|
|
30383
|
+
const nextEntries = Array.isArray(next) ? next : [];
|
|
30384
|
+
const prevEntries = Array.isArray(prev) ? prev : [];
|
|
30385
|
+
const nextByKey = /* @__PURE__ */ new Map();
|
|
30386
|
+
for (const t of nextEntries) if (t.Key) nextByKey.set(t.Key, t);
|
|
30387
|
+
const prevByKey = /* @__PURE__ */ new Map();
|
|
30388
|
+
for (const t of prevEntries) if (t.Key) prevByKey.set(t.Key, t);
|
|
30389
|
+
const toDelete = [];
|
|
30390
|
+
for (const [key, tag] of prevByKey) if (!nextByKey.has(key)) toDelete.push(tag);
|
|
30391
|
+
if (toDelete.length > 0) await this.getClient().send(new DeleteTagsCommand$1({ Tags: toDelete.map((t) => ({
|
|
30392
|
+
ResourceId: physicalId,
|
|
30393
|
+
ResourceType: "auto-scaling-group",
|
|
30394
|
+
Key: t.Key
|
|
30395
|
+
})) }));
|
|
30396
|
+
const toUpsert = [];
|
|
30397
|
+
for (const [key, tag] of nextByKey) {
|
|
30398
|
+
const before = prevByKey.get(key);
|
|
30399
|
+
if (JSON.stringify(before) === JSON.stringify(tag)) continue;
|
|
30400
|
+
toUpsert.push(tag);
|
|
30401
|
+
}
|
|
30402
|
+
if (toUpsert.length > 0) await this.getClient().send(new CreateOrUpdateTagsCommand({ Tags: toUpsert.map((t) => ({
|
|
30403
|
+
ResourceId: physicalId,
|
|
30404
|
+
ResourceType: "auto-scaling-group",
|
|
30405
|
+
Key: t.Key,
|
|
30406
|
+
...t.Value !== void 0 && { Value: t.Value },
|
|
30407
|
+
...t.PropagateAtLaunch !== void 0 && { PropagateAtLaunch: t.PropagateAtLaunch }
|
|
30408
|
+
})) }));
|
|
30409
|
+
}
|
|
30410
|
+
/**
|
|
30411
|
+
* Diff `LoadBalancerNames` (Classic Load Balancers) and issue
|
|
30412
|
+
* `AttachLoadBalancers` / `DetachLoadBalancers` for the delta (#476).
|
|
30413
|
+
* Names are opaque strings; AWS allows N attached LBs per ASG so this
|
|
30414
|
+
* helper batches every add into one Attach call and every remove into
|
|
30415
|
+
* one Detach call. No-op when before/after JSON is identical.
|
|
30416
|
+
*/
|
|
30417
|
+
async applyLoadBalancerNamesDiff(physicalId, next, prev) {
|
|
30418
|
+
if (JSON.stringify(next ?? []) === JSON.stringify(prev ?? [])) return;
|
|
30419
|
+
const nextNames = (Array.isArray(next) ? next : []).filter((n) => typeof n === "string");
|
|
30420
|
+
const prevNames = (Array.isArray(prev) ? prev : []).filter((n) => typeof n === "string");
|
|
30421
|
+
const nextSet = new Set(nextNames);
|
|
30422
|
+
const prevSet = new Set(prevNames);
|
|
30423
|
+
const toAttach = nextNames.filter((n) => !prevSet.has(n));
|
|
30424
|
+
const toDetach = prevNames.filter((n) => !nextSet.has(n));
|
|
30425
|
+
if (toDetach.length > 0) await this.getClient().send(new DetachLoadBalancersCommand({
|
|
30426
|
+
AutoScalingGroupName: physicalId,
|
|
30427
|
+
LoadBalancerNames: toDetach
|
|
30428
|
+
}));
|
|
30429
|
+
if (toAttach.length > 0) await this.getClient().send(new AttachLoadBalancersCommand({
|
|
30430
|
+
AutoScalingGroupName: physicalId,
|
|
30431
|
+
LoadBalancerNames: toAttach
|
|
30432
|
+
}));
|
|
30433
|
+
}
|
|
30434
|
+
/**
|
|
30435
|
+
* Diff `TargetGroupARNs` (ALB / NLB target groups) and issue
|
|
30436
|
+
* `AttachLoadBalancerTargetGroups` /
|
|
30437
|
+
* `DetachLoadBalancerTargetGroups` for the delta (#476). Target-group
|
|
30438
|
+
* ARNs are opaque strings; same per-call batching pattern as
|
|
30439
|
+
* `applyLoadBalancerNamesDiff`. No-op when before/after JSON is
|
|
30440
|
+
* identical.
|
|
30441
|
+
*/
|
|
30442
|
+
async applyTargetGroupArnsDiff(physicalId, next, prev) {
|
|
30443
|
+
if (JSON.stringify(next ?? []) === JSON.stringify(prev ?? [])) return;
|
|
30444
|
+
const nextArns = (Array.isArray(next) ? next : []).filter((a) => typeof a === "string");
|
|
30445
|
+
const prevArns = (Array.isArray(prev) ? prev : []).filter((a) => typeof a === "string");
|
|
30446
|
+
const nextSet = new Set(nextArns);
|
|
30447
|
+
const prevSet = new Set(prevArns);
|
|
30448
|
+
const toAttach = nextArns.filter((a) => !prevSet.has(a));
|
|
30449
|
+
const toDetach = prevArns.filter((a) => !nextSet.has(a));
|
|
30450
|
+
if (toDetach.length > 0) await this.getClient().send(new DetachLoadBalancerTargetGroupsCommand({
|
|
30451
|
+
AutoScalingGroupName: physicalId,
|
|
30452
|
+
TargetGroupARNs: toDetach
|
|
30453
|
+
}));
|
|
30454
|
+
if (toAttach.length > 0) await this.getClient().send(new AttachLoadBalancerTargetGroupsCommand({
|
|
30455
|
+
AutoScalingGroupName: physicalId,
|
|
30456
|
+
TargetGroupARNs: toAttach
|
|
30457
|
+
}));
|
|
30458
|
+
}
|
|
30357
30459
|
async applyMetricsCollectionDiff(physicalId, next, prev) {
|
|
30358
30460
|
if (JSON.stringify(next ?? []) === JSON.stringify(prev ?? [])) return;
|
|
30359
30461
|
const nextEntries = Array.isArray(next) ? next : [];
|
|
@@ -39898,6 +40000,25 @@ function resolveFnSubInvokeArn(arg) {
|
|
|
39898
40000
|
};
|
|
39899
40001
|
}
|
|
39900
40002
|
|
|
40003
|
+
//#endregion
|
|
40004
|
+
//#region src/local/intrinsic-utils.ts
|
|
40005
|
+
/**
|
|
40006
|
+
* If `value` is a `{ Ref: <string> }` intrinsic, return the referenced
|
|
40007
|
+
* logical ID. Otherwise return `null`.
|
|
40008
|
+
*
|
|
40009
|
+
* Shared across the `src/local/*` resolvers (route discovery, authorizer
|
|
40010
|
+
* resolution, stage attachment) so future intrinsic-shape extensions
|
|
40011
|
+
* (e.g. accepting `Fn::Sub`-bound Refs in REST v1 ResourceId / ParentId)
|
|
40012
|
+
* land in one place instead of three.
|
|
40013
|
+
*/
|
|
40014
|
+
function pickRefLogicalId(value) {
|
|
40015
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
40016
|
+
const ref = value["Ref"];
|
|
40017
|
+
if (typeof ref === "string") return ref;
|
|
40018
|
+
}
|
|
40019
|
+
return null;
|
|
40020
|
+
}
|
|
40021
|
+
|
|
39901
40022
|
//#endregion
|
|
39902
40023
|
//#region src/local/httpv2-service-integration.ts
|
|
39903
40024
|
const logger = getLogger();
|
|
@@ -40363,7 +40484,7 @@ function discoverRestV1Method(logicalId, resource, template, stackName) {
|
|
|
40363
40484
|
const integration = props["Integration"];
|
|
40364
40485
|
if (!integration) throw new Error(`${stackName}/${logicalId} (AWS::ApiGateway::Method): missing Integration property`);
|
|
40365
40486
|
const restApiId = props["RestApiId"];
|
|
40366
|
-
const restApiLogicalId = pickRefLogicalId
|
|
40487
|
+
const restApiLogicalId = pickRefLogicalId(restApiId);
|
|
40367
40488
|
if (!restApiLogicalId) throw new Error(`${stackName}/${logicalId} (AWS::ApiGateway::Method): RestApiId must be a { Ref: '...' } reference (got ${shortJson$1(restApiId)}).`);
|
|
40368
40489
|
const resourceId = props["ResourceId"];
|
|
40369
40490
|
const path = buildRestV1Path(resourceId, restApiLogicalId, template, stackName, logicalId);
|
|
@@ -40723,7 +40844,7 @@ function buildRestV1Path(resourceIdIntrinsic, restApiLogicalId, template, stackN
|
|
|
40723
40844
|
if (Array.isArray(arg) && arg.length === 2 && arg[1] === "RootResourceId") return "/";
|
|
40724
40845
|
}
|
|
40725
40846
|
}
|
|
40726
|
-
const resourceLogicalId = pickRefLogicalId
|
|
40847
|
+
const resourceLogicalId = pickRefLogicalId(resourceIdIntrinsic);
|
|
40727
40848
|
if (!resourceLogicalId) throw new Error(`${stackName}/${methodLogicalId}: ResourceId must be { Ref: '...' } or { 'Fn::GetAtt': [..., 'RootResourceId'] } (got ${shortJson$1(resourceIdIntrinsic)}).`);
|
|
40728
40849
|
const segments = [];
|
|
40729
40850
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -40743,7 +40864,7 @@ function buildRestV1Path(resourceIdIntrinsic, restApiLogicalId, template, stackN
|
|
|
40743
40864
|
const arg = parentId["Fn::GetAtt"];
|
|
40744
40865
|
if (Array.isArray(arg) && arg[1] === "RootResourceId") break;
|
|
40745
40866
|
}
|
|
40746
|
-
cursor = pickRefLogicalId
|
|
40867
|
+
cursor = pickRefLogicalId(parentId) ?? void 0;
|
|
40747
40868
|
}
|
|
40748
40869
|
return "/" + segments.join("/");
|
|
40749
40870
|
}
|
|
@@ -40758,7 +40879,7 @@ function pickRestV1Stage(restApiLogicalId, template) {
|
|
|
40758
40879
|
for (const [, resource] of Object.entries(resources)) {
|
|
40759
40880
|
if (resource.Type !== "AWS::ApiGateway::Stage") continue;
|
|
40760
40881
|
const props = resource.Properties ?? {};
|
|
40761
|
-
if (pickRefLogicalId
|
|
40882
|
+
if (pickRefLogicalId(props["RestApiId"]) === restApiLogicalId) {
|
|
40762
40883
|
const stageName = props["StageName"];
|
|
40763
40884
|
if (typeof stageName === "string") return stageName;
|
|
40764
40885
|
}
|
|
@@ -40777,7 +40898,7 @@ function pickRestV1Stage(restApiLogicalId, template) {
|
|
|
40777
40898
|
function discoverHttpApiRoute(logicalId, resource, template, stackName) {
|
|
40778
40899
|
const props = resource.Properties ?? {};
|
|
40779
40900
|
const apiId = props["ApiId"];
|
|
40780
|
-
const apiLogicalId = pickRefLogicalId
|
|
40901
|
+
const apiLogicalId = pickRefLogicalId(apiId);
|
|
40781
40902
|
if (!apiLogicalId) throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): ApiId must be { Ref: '...' } (got ${shortJson$1(apiId)}).`);
|
|
40782
40903
|
const routeKey = props["RouteKey"];
|
|
40783
40904
|
if (typeof routeKey !== "string" || routeKey.length === 0) throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): RouteKey must be a string`);
|
|
@@ -40990,11 +41111,11 @@ function parseHttpApiTargetIntegration(target, location) {
|
|
|
40990
41111
|
const sep = join[0];
|
|
40991
41112
|
const parts = join[1];
|
|
40992
41113
|
if (sep === "/" && parts.length === 2 && parts[0] === "integrations") {
|
|
40993
|
-
const ref = pickRefLogicalId
|
|
41114
|
+
const ref = pickRefLogicalId(parts[1]);
|
|
40994
41115
|
if (ref) return ref;
|
|
40995
41116
|
}
|
|
40996
41117
|
if (sep === "" && parts.length === 2 && parts[0] === "integrations/") {
|
|
40997
|
-
const ref = pickRefLogicalId
|
|
41118
|
+
const ref = pickRefLogicalId(parts[1]);
|
|
40998
41119
|
if (ref) return ref;
|
|
40999
41120
|
}
|
|
41000
41121
|
}
|
|
@@ -41014,7 +41135,7 @@ function parseHttpApiTargetIntegration(target, location) {
|
|
|
41014
41135
|
if (m) {
|
|
41015
41136
|
const bound = bindings[m[1]];
|
|
41016
41137
|
if (bound !== void 0) {
|
|
41017
|
-
const ref = pickRefLogicalId
|
|
41138
|
+
const ref = pickRefLogicalId(bound);
|
|
41018
41139
|
if (ref) return ref;
|
|
41019
41140
|
}
|
|
41020
41141
|
}
|
|
@@ -41040,17 +41161,6 @@ function parseRouteKey(routeKey) {
|
|
|
41040
41161
|
};
|
|
41041
41162
|
}
|
|
41042
41163
|
/**
|
|
41043
|
-
* If `value` is a `{ Ref: <string> }` intrinsic, return the referenced
|
|
41044
|
-
* logical ID. Otherwise return `null`.
|
|
41045
|
-
*/
|
|
41046
|
-
function pickRefLogicalId$3(value) {
|
|
41047
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
41048
|
-
const ref = value["Ref"];
|
|
41049
|
-
if (typeof ref === "string") return ref;
|
|
41050
|
-
}
|
|
41051
|
-
return null;
|
|
41052
|
-
}
|
|
41053
|
-
/**
|
|
41054
41164
|
* Compact JSON for error messages — caps long objects so a malformed
|
|
41055
41165
|
* intrinsic doesn't dump the whole template into a stderr line.
|
|
41056
41166
|
*/
|
|
@@ -41142,7 +41252,7 @@ function collectAuthRoutesForApi(apiLogicalId, template, _stackName) {
|
|
|
41142
41252
|
for (const [, resource] of Object.entries(resources)) {
|
|
41143
41253
|
if (resource.Type !== "AWS::ApiGatewayV2::Route") continue;
|
|
41144
41254
|
const props = resource.Properties ?? {};
|
|
41145
|
-
if (pickRefLogicalId
|
|
41255
|
+
if (pickRefLogicalId(props["ApiId"]) !== apiLogicalId) continue;
|
|
41146
41256
|
const authType = props["AuthorizationType"];
|
|
41147
41257
|
if (authType === void 0) continue;
|
|
41148
41258
|
const routeKey = props["RouteKey"];
|
|
@@ -41194,7 +41304,7 @@ function pickStage$1(apiLogicalId, template) {
|
|
|
41194
41304
|
for (const [, resource] of Object.entries(resources)) {
|
|
41195
41305
|
if (resource.Type !== "AWS::ApiGatewayV2::Stage") continue;
|
|
41196
41306
|
const props = resource.Properties ?? {};
|
|
41197
|
-
if (pickRefLogicalId
|
|
41307
|
+
if (pickRefLogicalId(props["ApiId"]) === apiLogicalId) {
|
|
41198
41308
|
const stageName = props["StageName"];
|
|
41199
41309
|
if (typeof stageName === "string" && stageName.length > 0) return stageName;
|
|
41200
41310
|
}
|
|
@@ -41215,7 +41325,7 @@ function collectRoutesForApi(apiLogicalId, template, stackName) {
|
|
|
41215
41325
|
for (const [routeLogicalId, resource] of Object.entries(resources)) {
|
|
41216
41326
|
if (resource.Type !== "AWS::ApiGatewayV2::Route") continue;
|
|
41217
41327
|
const props = resource.Properties ?? {};
|
|
41218
|
-
if (pickRefLogicalId
|
|
41328
|
+
if (pickRefLogicalId(props["ApiId"]) !== apiLogicalId) continue;
|
|
41219
41329
|
const declaredAt = `${stackName}/${routeLogicalId}`;
|
|
41220
41330
|
const routeKey = props["RouteKey"];
|
|
41221
41331
|
if (typeof routeKey !== "string" || routeKey.length === 0) throw new Error(`${declaredAt}: RouteKey must be a non-empty string.`);
|
|
@@ -41263,11 +41373,11 @@ function parseRouteTarget(target, location) {
|
|
|
41263
41373
|
const sep = join[0];
|
|
41264
41374
|
const parts = join[1];
|
|
41265
41375
|
if (sep === "/" && parts.length === 2 && parts[0] === "integrations") {
|
|
41266
|
-
const ref = pickRefLogicalId
|
|
41376
|
+
const ref = pickRefLogicalId(parts[1]);
|
|
41267
41377
|
if (ref) return ref;
|
|
41268
41378
|
}
|
|
41269
41379
|
if (sep === "" && parts.length === 2 && parts[0] === "integrations/") {
|
|
41270
|
-
const ref = pickRefLogicalId
|
|
41380
|
+
const ref = pickRefLogicalId(parts[1]);
|
|
41271
41381
|
if (ref) return ref;
|
|
41272
41382
|
}
|
|
41273
41383
|
}
|
|
@@ -41288,7 +41398,7 @@ function parseRouteTarget(target, location) {
|
|
|
41288
41398
|
if (m) {
|
|
41289
41399
|
const bound = bindings[m[1]];
|
|
41290
41400
|
if (bound !== void 0) {
|
|
41291
|
-
const ref = pickRefLogicalId
|
|
41401
|
+
const ref = pickRefLogicalId(bound);
|
|
41292
41402
|
if (ref) return ref;
|
|
41293
41403
|
}
|
|
41294
41404
|
}
|
|
@@ -41297,13 +41407,6 @@ function parseRouteTarget(target, location) {
|
|
|
41297
41407
|
}
|
|
41298
41408
|
throw new Error(`${location}: Target must be 'integrations/<id>' literal, Fn::Join with the documented shapes, or Fn::Sub with an 'integrations/\${...}' template.`);
|
|
41299
41409
|
}
|
|
41300
|
-
function pickRefLogicalId$2(value) {
|
|
41301
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
41302
|
-
const ref = value["Ref"];
|
|
41303
|
-
if (typeof ref === "string") return ref;
|
|
41304
|
-
}
|
|
41305
|
-
return null;
|
|
41306
|
-
}
|
|
41307
41410
|
function readApiCdkPath(logicalId, template) {
|
|
41308
41411
|
const resource = template.Resources?.[logicalId];
|
|
41309
41412
|
if (!resource) return void 0;
|
|
@@ -45119,11 +45222,22 @@ function parseCognitoIssuer(issuer) {
|
|
|
45119
45222
|
};
|
|
45120
45223
|
}
|
|
45121
45224
|
/**
|
|
45122
|
-
* Pull a string out of a
|
|
45123
|
-
*
|
|
45124
|
-
*
|
|
45125
|
-
*
|
|
45126
|
-
*
|
|
45225
|
+
* Pull a string out of a literal / `Fn::GetAtt` entry under `ProviderARNs`.
|
|
45226
|
+
*
|
|
45227
|
+
* CDK's `apigateway.CognitoUserPoolsAuthorizer` emits a `Fn::GetAtt:
|
|
45228
|
+
* [<UserPool>, 'Arn']` reference, which is the canonical shape any user
|
|
45229
|
+
* who writes `new CognitoUserPoolsAuthorizer(this, 'auth', { cognitoUserPools: [pool] })`
|
|
45230
|
+
* ends up with (#470). Without `--from-state` we cannot resolve the
|
|
45231
|
+
* deployed pool ARN, so we synthesize an obviously-unreachable placeholder
|
|
45232
|
+
* pointing at a non-existent pool id — the JWKS fetch will fail and
|
|
45233
|
+
* cognito-jwt.ts's pass-through fallback (PR #234) admits every JWT
|
|
45234
|
+
* without signature verification. The warn log names the affected
|
|
45235
|
+
* authorizer + the recommended explicit `providerArns` workaround so
|
|
45236
|
+
* developers who DO want real verification know how to switch over.
|
|
45237
|
+
*
|
|
45238
|
+
* The `location` argument carries the full
|
|
45239
|
+
* `<stack>/<authorizer>.ProviderARNs[<idx>]` path so the warn / error
|
|
45240
|
+
* names the offending entry exactly.
|
|
45127
45241
|
*/
|
|
45128
45242
|
function pickStringFromArn(value, location) {
|
|
45129
45243
|
if (typeof value === "string") return value;
|
|
@@ -45131,7 +45245,11 @@ function pickStringFromArn(value, location) {
|
|
|
45131
45245
|
const obj = value;
|
|
45132
45246
|
if ("Fn::GetAtt" in obj) {
|
|
45133
45247
|
const arg = obj["Fn::GetAtt"];
|
|
45134
|
-
if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string" && arg[1] === "Arn")
|
|
45248
|
+
if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string" && arg[1] === "Arn") {
|
|
45249
|
+
const logicalId = arg[0];
|
|
45250
|
+
getLogger().warn(`${location}: uses Fn::GetAtt against logical ID '${logicalId}'. cdkd local start-api cannot resolve the deployed user pool ARN — synthesizing an unreachable placeholder so JWKS pass-through admits every token. For real signature verification, set 'providerArns: [pool.userPoolArn]' explicitly on the CDK construct.`);
|
|
45251
|
+
return `arn:aws:cognito-idp:us-east-1:000000000000:userpool/us-east-1_cdkdplaceholder${logicalId}`;
|
|
45252
|
+
}
|
|
45135
45253
|
}
|
|
45136
45254
|
}
|
|
45137
45255
|
throw new RouteDiscoveryError(`${location}: must be a literal string (got ${shortJson(value)}).`);
|
|
@@ -45218,7 +45336,7 @@ function detectRestV1Authorizer(methodResource, methodLogicalId, stack) {
|
|
|
45218
45336
|
declaredAt: `${stack.stackName}/${methodLogicalId}`
|
|
45219
45337
|
};
|
|
45220
45338
|
const authorizerId = props["AuthorizerId"];
|
|
45221
|
-
const refLogicalId = pickRefLogicalId
|
|
45339
|
+
const refLogicalId = pickRefLogicalId(authorizerId);
|
|
45222
45340
|
if (!refLogicalId) throw new RouteDiscoveryError(`${stack.stackName}/${methodLogicalId}: AuthorizationType='${stringifyValue(authType)}' but AuthorizerId is missing or not a {Ref:...}.`);
|
|
45223
45341
|
return resolveRestV1Authorizer(refLogicalId, stack.template, stack.stackName, `${stack.stackName}/${methodLogicalId}`);
|
|
45224
45342
|
}
|
|
@@ -45227,18 +45345,11 @@ function detectHttpApiAuthorizer(routeResource, routeLogicalId, stack) {
|
|
|
45227
45345
|
const authType = props["AuthorizationType"];
|
|
45228
45346
|
if (authType === void 0 || authType === "NONE") return void 0;
|
|
45229
45347
|
const authorizerId = props["AuthorizerId"];
|
|
45230
|
-
const refLogicalId = pickRefLogicalId
|
|
45348
|
+
const refLogicalId = pickRefLogicalId(authorizerId);
|
|
45231
45349
|
if (!refLogicalId) throw new RouteDiscoveryError(`${stack.stackName}/${routeLogicalId}: AuthorizationType='${stringifyValue(authType)}' but AuthorizerId is missing or not a {Ref:...}.`);
|
|
45232
45350
|
const scopesRaw = props["AuthorizationScopes"];
|
|
45233
45351
|
return resolveHttpApiAuthorizer(refLogicalId, Array.isArray(scopesRaw) ? scopesRaw.filter((s) => typeof s === "string") : void 0, stack.template, stack.stackName, `${stack.stackName}/${routeLogicalId}`);
|
|
45234
45352
|
}
|
|
45235
|
-
function pickRefLogicalId$1(value) {
|
|
45236
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
45237
|
-
const ref = value["Ref"];
|
|
45238
|
-
if (typeof ref === "string") return ref;
|
|
45239
|
-
}
|
|
45240
|
-
return null;
|
|
45241
|
-
}
|
|
45242
45353
|
function shortJson(value) {
|
|
45243
45354
|
try {
|
|
45244
45355
|
const s = JSON.stringify(value);
|
|
@@ -47809,19 +47920,6 @@ function attachStageContext(routes, stageMap) {
|
|
|
47809
47920
|
route.stage = stage.stageName;
|
|
47810
47921
|
}
|
|
47811
47922
|
}
|
|
47812
|
-
/**
|
|
47813
|
-
* If `value` is a `{ Ref: <string> }` intrinsic, return the referenced
|
|
47814
|
-
* logical ID. Otherwise return `null`. (Duplicated structurally from
|
|
47815
|
-
* `route-discovery.ts` — both modules walk the template independently
|
|
47816
|
-
* and shouldn't grow a coupling for a 5-line helper.)
|
|
47817
|
-
*/
|
|
47818
|
-
function pickRefLogicalId(value) {
|
|
47819
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
47820
|
-
const ref = value["Ref"];
|
|
47821
|
-
if (typeof ref === "string") return ref;
|
|
47822
|
-
}
|
|
47823
|
-
return null;
|
|
47824
|
-
}
|
|
47825
47923
|
|
|
47826
47924
|
//#endregion
|
|
47827
47925
|
//#region src/local/file-watcher.ts
|
|
@@ -54164,7 +54262,7 @@ function reorderArgs(argv) {
|
|
|
54164
54262
|
*/
|
|
54165
54263
|
async function main() {
|
|
54166
54264
|
const program = new Command();
|
|
54167
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
54265
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.138.0");
|
|
54168
54266
|
program.addCommand(createBootstrapCommand());
|
|
54169
54267
|
program.addCommand(createSynthCommand());
|
|
54170
54268
|
program.addCommand(createListCommand());
|