@go-to-k/cdkd 0.114.0 → 0.115.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/README.md +12 -2
- package/dist/cli.js +278 -58
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-Br8DvrvB.js → deploy-engine-CAg_d5uX.js} +27 -10
- package/dist/deploy-engine-CAg_d5uX.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-Br8DvrvB.js.map +0 -1
package/README.md
CHANGED
|
@@ -459,8 +459,18 @@ One server per discovered API — authorizers, CORS configs, and stage
|
|
|
459
459
|
variables stay scoped to the owning API. Supports REST v1 + HTTP API +
|
|
460
460
|
Function URL with AWS_PROXY integrations; Lambda TOKEN / REQUEST,
|
|
461
461
|
Cognito User Pool, and HTTP v2 JWT authorizers (JWKS-verified); CORS
|
|
462
|
-
preflight
|
|
463
|
-
|
|
462
|
+
preflight (HTTP API v2 `CorsConfiguration` + REST v1 OPTIONS MOCK
|
|
463
|
+
preflight from `defaultCorsPreflightOptions`); hot reload via `--watch`;
|
|
464
|
+
deploy-state-backed env var substitution via `--from-state`.
|
|
465
|
+
|
|
466
|
+
Routes whose integration cdkd cannot emulate (non-AWS_PROXY REST v1
|
|
467
|
+
types other than the MOCK CORS preflight subset, HTTP API v2 service
|
|
468
|
+
integrations, WebSocket APIs, Function URLs with IAM auth or
|
|
469
|
+
RESPONSE_STREAM, cross-stack Lambda Arn references) **do not block
|
|
470
|
+
boot** — the server starts with a per-route `[warn]` summary and
|
|
471
|
+
returns HTTP 501 + the reason in the JSON body if and when the route is
|
|
472
|
+
hit. This lets you run the rest of your API surface locally while the
|
|
473
|
+
unsupported routes stay on the deployed API.
|
|
464
474
|
|
|
465
475
|
### `local run-task`
|
|
466
476
|
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-CuHRHcyW.js";
|
|
3
|
-
import { A as resolveApp, B as CdkdError, C as AssetPublisher, D as Synthesizer, E as buildDockerImage, F as warnDeprecatedNoPrefixCliFlag, G as PartialFailureError, I as AssemblyReader, J as ResourceUpdateNotSupportedError, K as ProvisioningError, M as resolveSkipPrefix, N as resolveStateBucketWithDefault, O as getDefaultStateBucketName, P as resolveStateBucketWithDefaultAndSource, R as resolveBucketRegion, S as shouldRetainResource, T as WorkGraph, U as LocalInvokeBuildError, X as StackHasActiveImportsError, Y as RouteDiscoveryError, Z as StackTerminationProtectionError, _ as DiffCalculator, a as withRetry, at as getLogger, b as LockManager, c as collectInlinePolicyNamesManagedBySiblings, ct as getLiveRenderer, d as normalizeAwsTagsToCfn, dt as generateResourceName, f as resolveExplicitPhysicalId, ft as generateResourceNameWithFallback, g as IntrinsicFunctionResolver, h as assertRegionMatch, i as withResourceDeadline, j as resolveCaptureObservedState, k as getLegacyStateBucketName, l as CDK_PATH_TAG, lt as PATTERN_B_NAME_PROPERTIES, m as CloudControlProvider, mt as withStackName, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as normalizeAwsError, o as IMPLICIT_DELETE_DEPENDENCIES, p as ProviderRegistry, pt as withSkipPrefix, q as ResourceTimeoutError, r as DeployEngine, rt as withErrorHandling, s as IAMRoleProvider, st as runStackBuffered, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as matchesCdkPath, ut as PATTERN_B_RESOURCE_TYPES, v as DagBuilder, w as stringifyValue, x as S3StateBackend, y as TemplateParser } from "./deploy-engine-
|
|
3
|
+
import { A as resolveApp, B as CdkdError, C as AssetPublisher, D as Synthesizer, E as buildDockerImage, F as warnDeprecatedNoPrefixCliFlag, G as PartialFailureError, I as AssemblyReader, J as ResourceUpdateNotSupportedError, K as ProvisioningError, M as resolveSkipPrefix, N as resolveStateBucketWithDefault, O as getDefaultStateBucketName, P as resolveStateBucketWithDefaultAndSource, R as resolveBucketRegion, S as shouldRetainResource, T as WorkGraph, U as LocalInvokeBuildError, X as StackHasActiveImportsError, Y as RouteDiscoveryError, Z as StackTerminationProtectionError, _ as DiffCalculator, a as withRetry, at as getLogger, b as LockManager, c as collectInlinePolicyNamesManagedBySiblings, ct as getLiveRenderer, d as normalizeAwsTagsToCfn, dt as generateResourceName, f as resolveExplicitPhysicalId, ft as generateResourceNameWithFallback, g as IntrinsicFunctionResolver, h as assertRegionMatch, i as withResourceDeadline, j as resolveCaptureObservedState, k as getLegacyStateBucketName, l as CDK_PATH_TAG, lt as PATTERN_B_NAME_PROPERTIES, m as CloudControlProvider, mt as withStackName, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as normalizeAwsError, o as IMPLICIT_DELETE_DEPENDENCIES, p as ProviderRegistry, pt as withSkipPrefix, q as ResourceTimeoutError, r as DeployEngine, rt as withErrorHandling, s as IAMRoleProvider, st as runStackBuffered, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as matchesCdkPath, ut as PATTERN_B_RESOURCE_TYPES, v as DagBuilder, w as stringifyValue, x as S3StateBackend, y as TemplateParser } from "./deploy-engine-CAg_d5uX.js";
|
|
4
4
|
import { createHash, createPublicKey, createVerify, randomBytes, randomUUID } from "node:crypto";
|
|
5
5
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListBucketsCommand, ListDirectoryBucketsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
6
6
|
import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachUserPolicyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachUserPolicyCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListInstanceProfilesCommand, ListUserPoliciesCommand, ListUserTagsCommand, ListUsersCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagUserCommand, UntagUserCommand, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
|
|
@@ -38192,7 +38192,7 @@ const INVOKE_ARN_MARKER = ":lambda:path/2015-03-31/functions/";
|
|
|
38192
38192
|
* names the surface-level problem (the caller's location prefix +
|
|
38193
38193
|
* `shortJson` rendering is layered on top). Never throws.
|
|
38194
38194
|
*/
|
|
38195
|
-
function resolveLambdaArnIntrinsic
|
|
38195
|
+
function resolveLambdaArnIntrinsic(value) {
|
|
38196
38196
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {
|
|
38197
38197
|
kind: "unsupported",
|
|
38198
38198
|
detail: "expected an object intrinsic"
|
|
@@ -38319,8 +38319,16 @@ function resolveFnSubInvokeArn(arg) {
|
|
|
38319
38319
|
* lambdaLogicalId, stage) tuple is identical — different stacks may
|
|
38320
38320
|
* legitimately host different APIs that mount the same path.
|
|
38321
38321
|
*
|
|
38322
|
-
*
|
|
38323
|
-
*
|
|
38322
|
+
* Each route is one of three classes (see {@link DiscoveredRoute}):
|
|
38323
|
+
* - normal (no flag set);
|
|
38324
|
+
* - synthetic CORS preflight (`mockCors` set);
|
|
38325
|
+
* - deferred-error unsupported (`unsupported` set).
|
|
38326
|
+
*
|
|
38327
|
+
* Throws {@link RouteDiscoveryError} only on template-structural failures
|
|
38328
|
+
* the discovery layer cannot generate a meaningful route from (e.g.
|
|
38329
|
+
* missing Integration property, ParentId cycle, non-Ref RestApiId). Per-
|
|
38330
|
+
* route integration unsupportedness now flows through `unsupported` and
|
|
38331
|
+
* is surfaced as HTTP 501 at request time.
|
|
38324
38332
|
*/
|
|
38325
38333
|
function discoverRoutes(stacks) {
|
|
38326
38334
|
const routes = [];
|
|
@@ -38345,7 +38353,7 @@ function discoverRoutes(stacks) {
|
|
|
38345
38353
|
errors.push(err instanceof Error ? err.message : String(err));
|
|
38346
38354
|
}
|
|
38347
38355
|
}
|
|
38348
|
-
if (errors.length > 0) throw new RouteDiscoveryError(`cdkd local start-api: ${errors.length}
|
|
38356
|
+
if (errors.length > 0) throw new RouteDiscoveryError(`cdkd local start-api: ${errors.length} malformed route(s) in the synthesized template:\n` + errors.map((e) => ` - ${e}`).join("\n"));
|
|
38349
38357
|
return routes;
|
|
38350
38358
|
}
|
|
38351
38359
|
/**
|
|
@@ -38355,8 +38363,18 @@ function discoverRoutes(stacks) {
|
|
|
38355
38363
|
* the full path, then looks up the corresponding Stage (when one is
|
|
38356
38364
|
* attached to the same RestApi) so `requestContext.stage` is realistic.
|
|
38357
38365
|
*
|
|
38358
|
-
*
|
|
38359
|
-
*
|
|
38366
|
+
* Per-integration classification (see {@link DiscoveredRoute}):
|
|
38367
|
+
* - `Integration.Type === 'AWS_PROXY'` → normal route.
|
|
38368
|
+
* - `HttpMethod === 'OPTIONS'` + `Type === 'MOCK'` + `IntegrationResponses`
|
|
38369
|
+
* contain literal `method.response.header.*` mapping params → synthetic
|
|
38370
|
+
* CORS preflight (`mockCors` set). Emulates CDK's
|
|
38371
|
+
* `defaultCorsPreflightOptions` output.
|
|
38372
|
+
* - All other `Integration.Type` values (`MOCK` without CORS shape,
|
|
38373
|
+
* `AWS`, `HTTP`, `HTTP_PROXY`) → unsupported route. The HTTP server
|
|
38374
|
+
* returns 501 when the route is hit; boot proceeds.
|
|
38375
|
+
*
|
|
38376
|
+
* Hard-errors on template-structural problems (missing Integration,
|
|
38377
|
+
* non-Ref RestApiId, ParentId-chain failures).
|
|
38360
38378
|
*
|
|
38361
38379
|
* Method.HttpMethod values of `'ANY'` are returned as a single route with
|
|
38362
38380
|
* `method='ANY'`; the matcher routes any HTTP method to the Lambda.
|
|
@@ -38365,10 +38383,6 @@ function discoverRestV1Method(logicalId, resource, template, stackName) {
|
|
|
38365
38383
|
const props = resource.Properties ?? {};
|
|
38366
38384
|
const integration = props["Integration"];
|
|
38367
38385
|
if (!integration) throw new Error(`${stackName}/${logicalId} (AWS::ApiGateway::Method): missing Integration property`);
|
|
38368
|
-
const integrationType = integration["Type"];
|
|
38369
|
-
if (integrationType !== "AWS_PROXY") throw new Error(`${stackName}/${logicalId} (AWS::ApiGateway::Method): integration type '${String(integrationType)}' is not supported (only AWS_PROXY). MOCK / AWS / HTTP / HTTP_PROXY require mapping templates that cdkd cannot emulate.`);
|
|
38370
|
-
const integrationUri = integration["Uri"];
|
|
38371
|
-
const lambdaLogicalId = resolveLambdaArnIntrinsic(integrationUri, `${stackName}/${logicalId}.Integration.Uri`);
|
|
38372
38386
|
const restApiId = props["RestApiId"];
|
|
38373
38387
|
const restApiLogicalId = pickRefLogicalId$2(restApiId);
|
|
38374
38388
|
if (!restApiLogicalId) throw new Error(`${stackName}/${logicalId} (AWS::ApiGateway::Method): RestApiId must be a { Ref: '...' } reference (got ${shortJson$1(restApiId)}).`);
|
|
@@ -38377,10 +38391,7 @@ function discoverRestV1Method(logicalId, resource, template, stackName) {
|
|
|
38377
38391
|
const httpMethod = stringifyValue(props["HttpMethod"] ?? "ANY");
|
|
38378
38392
|
const stage = pickRestV1Stage(restApiLogicalId, template);
|
|
38379
38393
|
const restApiCdkPath = readApiCdkPath(restApiLogicalId, template);
|
|
38380
|
-
|
|
38381
|
-
method: httpMethod,
|
|
38382
|
-
pathPattern: path,
|
|
38383
|
-
lambdaLogicalId,
|
|
38394
|
+
const baseRoute = {
|
|
38384
38395
|
source: "rest-v1",
|
|
38385
38396
|
apiVersion: "v1",
|
|
38386
38397
|
stage,
|
|
@@ -38388,7 +38399,98 @@ function discoverRestV1Method(logicalId, resource, template, stackName) {
|
|
|
38388
38399
|
apiStackName: stackName,
|
|
38389
38400
|
...restApiCdkPath !== void 0 && { apiCdkPath: restApiCdkPath },
|
|
38390
38401
|
declaredAt: `${stackName}/${logicalId}`
|
|
38402
|
+
};
|
|
38403
|
+
const integrationType = integration["Type"];
|
|
38404
|
+
if (integrationType === "MOCK") {
|
|
38405
|
+
const preflight = httpMethod === "OPTIONS" ? extractRestV1MockCorsConfig(integration) : void 0;
|
|
38406
|
+
if (preflight) return [{
|
|
38407
|
+
...baseRoute,
|
|
38408
|
+
method: "OPTIONS",
|
|
38409
|
+
pathPattern: path,
|
|
38410
|
+
lambdaLogicalId: "",
|
|
38411
|
+
mockCors: preflight
|
|
38412
|
+
}];
|
|
38413
|
+
return [{
|
|
38414
|
+
...baseRoute,
|
|
38415
|
+
method: httpMethod,
|
|
38416
|
+
pathPattern: path,
|
|
38417
|
+
lambdaLogicalId: "",
|
|
38418
|
+
unsupported: { reason: `${stackName}/${logicalId}: MOCK integration is not emulated (only the CORS preflight subset, where HttpMethod=OPTIONS and IntegrationResponses carry literal method.response.header.* values, is supported).` }
|
|
38419
|
+
}];
|
|
38420
|
+
}
|
|
38421
|
+
if (integrationType !== "AWS_PROXY") return [{
|
|
38422
|
+
...baseRoute,
|
|
38423
|
+
method: httpMethod,
|
|
38424
|
+
pathPattern: path,
|
|
38425
|
+
lambdaLogicalId: "",
|
|
38426
|
+
unsupported: { reason: `${stackName}/${logicalId}: REST v1 integration type '${String(integrationType)}' is not supported (only AWS_PROXY and the MOCK CORS preflight subset).` }
|
|
38427
|
+
}];
|
|
38428
|
+
const integrationUri = integration["Uri"];
|
|
38429
|
+
const arnOutcome = resolveLambdaArnOutcome(integrationUri);
|
|
38430
|
+
if (arnOutcome.kind === "unsupported") return [{
|
|
38431
|
+
...baseRoute,
|
|
38432
|
+
method: httpMethod,
|
|
38433
|
+
pathPattern: path,
|
|
38434
|
+
lambdaLogicalId: "",
|
|
38435
|
+
unsupported: { reason: `${stackName}/${logicalId}.Integration.Uri: ${arnOutcome.detail} (got ${shortJson$1(integrationUri)}). Lambda Arn intrinsics on cross-stack / imported references are not resolvable locally; deploy the producer stack and use \`cdkd local invoke --from-state\` shapes if you need it.` }
|
|
38391
38436
|
}];
|
|
38437
|
+
return [{
|
|
38438
|
+
...baseRoute,
|
|
38439
|
+
method: httpMethod,
|
|
38440
|
+
pathPattern: path,
|
|
38441
|
+
lambdaLogicalId: arnOutcome.logicalId
|
|
38442
|
+
}];
|
|
38443
|
+
}
|
|
38444
|
+
/**
|
|
38445
|
+
* Extract the canonical CORS-preflight headers from a REST v1 MOCK
|
|
38446
|
+
* Method's `Integration.IntegrationResponses[0]`. Returns `undefined`
|
|
38447
|
+
* when the shape isn't a CORS preflight (no IntegrationResponses, no
|
|
38448
|
+
* `method.response.header.*` mapping parameters, or any individual
|
|
38449
|
+
* mapping parameter we could not evaluate locally — see below).
|
|
38450
|
+
*
|
|
38451
|
+
* AWS represents header literals in `ResponseParameters` with surrounding
|
|
38452
|
+
* single-quotes (e.g. `"'*'"` for `*`). The single-quote wrappers are
|
|
38453
|
+
* stripped to produce the canonical header value the local server emits.
|
|
38454
|
+
*
|
|
38455
|
+
* **All-or-nothing**: if any `method.response.header.*` entry is
|
|
38456
|
+
* intrinsic-valued (`Fn::Sub`, `Ref` etc.), unquoted, or otherwise
|
|
38457
|
+
* not a string-literal-with-quotes, the WHOLE preflight falls through
|
|
38458
|
+
* to the unsupported class. Emitting a partial preflight with some
|
|
38459
|
+
* headers missing would silently break CORS in the browser (the
|
|
38460
|
+
* preflight succeeds, then the actual request hits a CORS error the
|
|
38461
|
+
* user has to debug through Network panel) — caller's the better
|
|
38462
|
+
* place to surface the underlying VTL-requirement via the 501 path.
|
|
38463
|
+
*
|
|
38464
|
+
* Only the first `IntegrationResponses` entry is consulted. CDK's
|
|
38465
|
+
* `defaultCorsPreflightOptions` emits exactly one entry; hand-rolled
|
|
38466
|
+
* multi-status MOCK preflights are an unsupported v1 limitation.
|
|
38467
|
+
*/
|
|
38468
|
+
function extractRestV1MockCorsConfig(integration) {
|
|
38469
|
+
const responses = integration["IntegrationResponses"];
|
|
38470
|
+
if (!Array.isArray(responses) || responses.length === 0) return void 0;
|
|
38471
|
+
const first = responses[0];
|
|
38472
|
+
if (!first || typeof first !== "object") return void 0;
|
|
38473
|
+
const entry = first;
|
|
38474
|
+
const responseParameters = entry["ResponseParameters"];
|
|
38475
|
+
if (!responseParameters || typeof responseParameters !== "object" || Array.isArray(responseParameters)) return;
|
|
38476
|
+
const headers = {};
|
|
38477
|
+
let sawAnyHeader = false;
|
|
38478
|
+
for (const [key, raw] of Object.entries(responseParameters)) {
|
|
38479
|
+
const m = /^method\.response\.header\.(.+)$/.exec(key);
|
|
38480
|
+
if (!m) continue;
|
|
38481
|
+
sawAnyHeader = true;
|
|
38482
|
+
const headerName = m[1];
|
|
38483
|
+
if (typeof raw !== "string") return void 0;
|
|
38484
|
+
if (raw.length < 2 || raw[0] !== "'" || raw[raw.length - 1] !== "'") return void 0;
|
|
38485
|
+
headers[headerName] = raw.slice(1, -1);
|
|
38486
|
+
}
|
|
38487
|
+
if (!sawAnyHeader) return void 0;
|
|
38488
|
+
const statusCodeRaw = entry["StatusCode"];
|
|
38489
|
+
const parsed = typeof statusCodeRaw === "string" ? Number.parseInt(statusCodeRaw, 10) : NaN;
|
|
38490
|
+
return {
|
|
38491
|
+
statusCode: Number.isFinite(parsed) ? parsed : 204,
|
|
38492
|
+
headers
|
|
38493
|
+
};
|
|
38392
38494
|
}
|
|
38393
38495
|
/**
|
|
38394
38496
|
* Walk a chain of `AWS::ApiGateway::Resource` parent pointers up to the
|
|
@@ -38462,27 +38564,29 @@ function discoverHttpApiRoute(logicalId, resource, template, stackName) {
|
|
|
38462
38564
|
const apiId = props["ApiId"];
|
|
38463
38565
|
const apiLogicalId = pickRefLogicalId$2(apiId);
|
|
38464
38566
|
if (!apiLogicalId) throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): ApiId must be { Ref: '...' } (got ${shortJson$1(apiId)}).`);
|
|
38567
|
+
const routeKey = props["RouteKey"];
|
|
38568
|
+
if (typeof routeKey !== "string" || routeKey.length === 0) throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): RouteKey must be a string`);
|
|
38569
|
+
const apiCdkPath = readApiCdkPath(apiLogicalId, template);
|
|
38465
38570
|
const apiResource = template.Resources?.[apiLogicalId];
|
|
38466
38571
|
if (apiResource?.Type === "AWS::ApiGatewayV2::Api") {
|
|
38467
|
-
if ((apiResource.Properties ?? {})["ProtocolType"] === "WEBSOCKET")
|
|
38572
|
+
if ((apiResource.Properties ?? {})["ProtocolType"] === "WEBSOCKET") return [{
|
|
38573
|
+
method: "ANY",
|
|
38574
|
+
pathPattern: routeKey,
|
|
38575
|
+
lambdaLogicalId: "",
|
|
38576
|
+
source: "http-api",
|
|
38577
|
+
apiVersion: "v2",
|
|
38578
|
+
stage: "$default",
|
|
38579
|
+
apiLogicalId,
|
|
38580
|
+
apiStackName: stackName,
|
|
38581
|
+
...apiCdkPath !== void 0 && { apiCdkPath },
|
|
38582
|
+
declaredAt: `${stackName}/${logicalId}`,
|
|
38583
|
+
unsupported: { reason: `${stackName}/${logicalId}: WebSocket APIs are not supported in cdkd local start-api.` }
|
|
38584
|
+
}];
|
|
38468
38585
|
}
|
|
38469
|
-
const routeKey = props["RouteKey"];
|
|
38470
|
-
if (typeof routeKey !== "string" || routeKey.length === 0) throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): RouteKey must be a string`);
|
|
38471
|
-
const target = props["Target"];
|
|
38472
|
-
const integrationLogicalId = parseHttpApiTargetIntegration(target, `${stackName}/${logicalId}.Target`);
|
|
38473
|
-
const integration = template.Resources?.[integrationLogicalId];
|
|
38474
|
-
if (!integration || integration.Type !== "AWS::ApiGatewayV2::Integration") throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): Target points at '${integrationLogicalId}' which is not an AWS::ApiGatewayV2::Integration`);
|
|
38475
|
-
const integrationProps = integration.Properties ?? {};
|
|
38476
|
-
const integrationType = integrationProps["IntegrationType"];
|
|
38477
|
-
if (integrationType !== "AWS_PROXY") throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): integration type '${String(integrationType)}' is not supported (only AWS_PROXY).`);
|
|
38478
|
-
if (integrationProps["IntegrationSubtype"] !== void 0) throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): IntegrationSubtype '${stringifyValue(integrationProps["IntegrationSubtype"])}' is not supported (ApiGatewayV2 service integrations like SQS/EventBridge cannot run locally).`);
|
|
38479
|
-
const lambdaLogicalId = resolveLambdaArnIntrinsic(integrationProps["IntegrationUri"], `${stackName}/${integrationLogicalId}.IntegrationUri`);
|
|
38480
38586
|
const { method, pathPattern } = parseRouteKey(routeKey);
|
|
38481
|
-
const
|
|
38482
|
-
return [{
|
|
38587
|
+
const baseRoute = {
|
|
38483
38588
|
method,
|
|
38484
38589
|
pathPattern,
|
|
38485
|
-
lambdaLogicalId,
|
|
38486
38590
|
source: "http-api",
|
|
38487
38591
|
apiVersion: "v2",
|
|
38488
38592
|
stage: "$default",
|
|
@@ -38490,35 +38594,82 @@ function discoverHttpApiRoute(logicalId, resource, template, stackName) {
|
|
|
38490
38594
|
apiStackName: stackName,
|
|
38491
38595
|
...apiCdkPath !== void 0 && { apiCdkPath },
|
|
38492
38596
|
declaredAt: `${stackName}/${logicalId}`
|
|
38597
|
+
};
|
|
38598
|
+
const target = props["Target"];
|
|
38599
|
+
const integrationLogicalId = parseHttpApiTargetIntegration(target, `${stackName}/${logicalId}.Target`);
|
|
38600
|
+
const integration = template.Resources?.[integrationLogicalId];
|
|
38601
|
+
if (!integration || integration.Type !== "AWS::ApiGatewayV2::Integration") throw new Error(`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): Target points at '${integrationLogicalId}' which is not an AWS::ApiGatewayV2::Integration`);
|
|
38602
|
+
const integrationProps = integration.Properties ?? {};
|
|
38603
|
+
const integrationType = integrationProps["IntegrationType"];
|
|
38604
|
+
if (integrationType !== "AWS_PROXY") return [{
|
|
38605
|
+
...baseRoute,
|
|
38606
|
+
lambdaLogicalId: "",
|
|
38607
|
+
unsupported: { reason: `${stackName}/${logicalId}: HTTP API v2 integration type '${String(integrationType)}' is not supported (only AWS_PROXY).` }
|
|
38608
|
+
}];
|
|
38609
|
+
if (integrationProps["IntegrationSubtype"] !== void 0) return [{
|
|
38610
|
+
...baseRoute,
|
|
38611
|
+
lambdaLogicalId: "",
|
|
38612
|
+
unsupported: { reason: `${stackName}/${logicalId}: HTTP API v2 service integration with IntegrationSubtype '${stringifyValue(integrationProps["IntegrationSubtype"])}' is not supported (cdkd cannot proxy directly to SQS / EventBridge / etc.).` }
|
|
38613
|
+
}];
|
|
38614
|
+
const arnOutcome = resolveLambdaArnOutcome(integrationProps["IntegrationUri"]);
|
|
38615
|
+
if (arnOutcome.kind === "unsupported") return [{
|
|
38616
|
+
...baseRoute,
|
|
38617
|
+
lambdaLogicalId: "",
|
|
38618
|
+
unsupported: { reason: `${stackName}/${integrationLogicalId}.IntegrationUri: ${arnOutcome.detail} (got ${shortJson$1(integrationProps["IntegrationUri"])}). Lambda Arn intrinsics on cross-stack / imported references are not resolvable locally.` }
|
|
38619
|
+
}];
|
|
38620
|
+
return [{
|
|
38621
|
+
...baseRoute,
|
|
38622
|
+
lambdaLogicalId: arnOutcome.logicalId
|
|
38493
38623
|
}];
|
|
38494
38624
|
}
|
|
38495
38625
|
/**
|
|
38496
38626
|
* Discover the synthetic `ANY /{proxy+}` route from an
|
|
38497
38627
|
* `AWS::Lambda::Url` resource.
|
|
38498
38628
|
*
|
|
38499
|
-
*
|
|
38500
|
-
*
|
|
38501
|
-
*
|
|
38502
|
-
*
|
|
38629
|
+
* Per-shape classification:
|
|
38630
|
+
* - `AuthType === 'NONE'` + `InvokeMode !== 'RESPONSE_STREAM'` → normal route.
|
|
38631
|
+
* - `AuthType !== 'NONE'` (e.g. `AWS_IAM`) → deferred-error
|
|
38632
|
+
* unsupported. Boot proceeds; HTTP 501 + `reason` at request time.
|
|
38633
|
+
* IAM auth would need SigV4 verification cdkd cannot emulate.
|
|
38634
|
+
* - `InvokeMode === 'RESPONSE_STREAM'` → deferred-error unsupported.
|
|
38635
|
+
* The RIE container does not implement `InvokeWithResponseStream`.
|
|
38636
|
+
*
|
|
38637
|
+
* The Lambda Arn intrinsic resolution still **hard-errors** when it
|
|
38638
|
+
* cannot pin down a same-template Lambda — Function URLs have no other
|
|
38639
|
+
* identifying info (no RouteKey / RestApi parent), so the route would
|
|
38640
|
+
* be uninformative as a deferred-501 entry.
|
|
38503
38641
|
*/
|
|
38504
38642
|
function discoverFunctionUrl(logicalId, resource, template, stackName) {
|
|
38505
38643
|
const props = resource.Properties ?? {};
|
|
38506
|
-
const authType = props["AuthType"];
|
|
38507
|
-
if (authType !== "NONE") throw new Error(`${stackName}/${logicalId} (AWS::Lambda::Url): AuthType '${String(authType)}' is not supported (only NONE — IAM auth requires SigV4 verification cdkd cannot emulate locally; deferred follow-up PR).`);
|
|
38508
|
-
if (props["InvokeMode"] === "RESPONSE_STREAM") throw new Error(`${stackName}/${logicalId} (AWS::Lambda::Url): InvokeMode RESPONSE_STREAM is not supported (deferred follow-up PR).`);
|
|
38509
38644
|
const targetArn = props["TargetFunctionArn"];
|
|
38510
|
-
const
|
|
38645
|
+
const arnOutcome = resolveLambdaArnOutcome(targetArn);
|
|
38646
|
+
if (arnOutcome.kind === "unsupported") throw new Error(`${stackName}/${logicalId}.TargetFunctionArn: ${arnOutcome.detail} (got ${shortJson$1(targetArn)}).`);
|
|
38647
|
+
const lambdaLogicalId = arnOutcome.logicalId;
|
|
38511
38648
|
const lambdaCdkPath = readApiCdkPath(lambdaLogicalId, template);
|
|
38512
|
-
|
|
38649
|
+
const baseRoute = {
|
|
38513
38650
|
method: "ANY",
|
|
38514
38651
|
pathPattern: "/{proxy+}",
|
|
38515
|
-
lambdaLogicalId,
|
|
38516
38652
|
source: "function-url",
|
|
38517
38653
|
apiVersion: "v2",
|
|
38518
38654
|
stage: "$default",
|
|
38519
38655
|
apiStackName: stackName,
|
|
38520
38656
|
...lambdaCdkPath !== void 0 && { apiCdkPath: lambdaCdkPath },
|
|
38521
38657
|
declaredAt: `${stackName}/${logicalId}`
|
|
38658
|
+
};
|
|
38659
|
+
const authType = props["AuthType"];
|
|
38660
|
+
if (authType !== "NONE") return [{
|
|
38661
|
+
...baseRoute,
|
|
38662
|
+
lambdaLogicalId,
|
|
38663
|
+
unsupported: { reason: `${stackName}/${logicalId}: AuthType '${String(authType)}' is not supported (only NONE — IAM auth requires SigV4 verification cdkd cannot emulate locally).` }
|
|
38664
|
+
}];
|
|
38665
|
+
if (props["InvokeMode"] === "RESPONSE_STREAM") return [{
|
|
38666
|
+
...baseRoute,
|
|
38667
|
+
lambdaLogicalId,
|
|
38668
|
+
unsupported: { reason: `${stackName}/${logicalId}: InvokeMode RESPONSE_STREAM is not supported (cdkd's RIE container does not implement InvokeWithResponseStream).` }
|
|
38669
|
+
}];
|
|
38670
|
+
return [{
|
|
38671
|
+
...baseRoute,
|
|
38672
|
+
lambdaLogicalId
|
|
38522
38673
|
}];
|
|
38523
38674
|
}
|
|
38524
38675
|
/**
|
|
@@ -38541,13 +38692,11 @@ function readApiCdkPath(logicalId, template) {
|
|
|
38541
38692
|
* invoke-ARN `Fn::Join` wrapper / the `Fn::Sub` invoke-ARN wrapper (both
|
|
38542
38693
|
* 1-arg and 2-arg forms).
|
|
38543
38694
|
*
|
|
38544
|
-
*
|
|
38545
|
-
*
|
|
38546
|
-
*
|
|
38547
|
-
*
|
|
38548
|
-
*
|
|
38549
|
-
* so the top-level catch in `discoverRoutes` re-wraps it as
|
|
38550
|
-
* `RouteDiscoveryError` along with sibling errors.
|
|
38695
|
+
* Non-throwing: returns the shared resolver's discriminated union
|
|
38696
|
+
* unchanged so each call site can decide whether to surface the
|
|
38697
|
+
* unsupported case as a per-route `unsupported` flag (the new default)
|
|
38698
|
+
* or as a hard error (Function URLs, which lack route-level identity
|
|
38699
|
+
* without their Lambda).
|
|
38551
38700
|
*
|
|
38552
38701
|
* **Why we don't reuse `src/deployment/intrinsic-function-resolver.ts`**:
|
|
38553
38702
|
* that resolver is deploy-state-coupled — it pulls in STS / EC2 / Secrets
|
|
@@ -38555,10 +38704,8 @@ function readApiCdkPath(logicalId, template) {
|
|
|
38555
38704
|
* `cdkd local start-api` runs purely against the synthesized template
|
|
38556
38705
|
* and doesn't have any of that.
|
|
38557
38706
|
*/
|
|
38558
|
-
function
|
|
38559
|
-
|
|
38560
|
-
if (outcome.kind === "resolved") return outcome.logicalId;
|
|
38561
|
-
throw new Error(`${location}: ${outcome.detail} (got ${shortJson$1(value)}). Only { Ref: <LambdaLogicalId> }, { 'Fn::GetAtt': [<LambdaLogicalId>, 'Arn'] }, the REST v1 invoke-ARN Fn::Join wrapper, and the Fn::Sub invoke-ARN wrapper are supported. Other intrinsics (Fn::Sub against arbitrary templates, etc.) require deploy-state and are not supported in cdkd local start-api.`);
|
|
38707
|
+
function resolveLambdaArnOutcome(value) {
|
|
38708
|
+
return resolveLambdaArnIntrinsic(value);
|
|
38562
38709
|
}
|
|
38563
38710
|
/**
|
|
38564
38711
|
* Parse an HTTP API Route's `Target` into the integration's logical ID.
|
|
@@ -39850,7 +39997,7 @@ function resolveHttpApiAuthorizer(authorizerLogicalId, routeAuthorizationScopes,
|
|
|
39850
39997
|
* the offending route + raw intrinsic named.
|
|
39851
39998
|
*/
|
|
39852
39999
|
function resolveLambdaArn(value, location) {
|
|
39853
|
-
const outcome = resolveLambdaArnIntrinsic
|
|
40000
|
+
const outcome = resolveLambdaArnIntrinsic(value);
|
|
39854
40001
|
if (outcome.kind === "resolved") return outcome.logicalId;
|
|
39855
40002
|
throw new RouteDiscoveryError(`${location}: ${outcome.detail} (got ${shortJson(value)}). Only { Ref }, { Fn::GetAtt: [..., 'Arn'] }, the REST v1 invoke-ARN Fn::Join wrapper, and the Fn::Sub invoke-ARN wrapper are supported.`);
|
|
39856
40003
|
}
|
|
@@ -40024,6 +40171,10 @@ function attachAuthorizers(stacks, routes) {
|
|
|
40024
40171
|
const out = [];
|
|
40025
40172
|
const errors = [];
|
|
40026
40173
|
for (const route of routes) {
|
|
40174
|
+
if (route.unsupported || route.mockCors) {
|
|
40175
|
+
out.push({ route });
|
|
40176
|
+
continue;
|
|
40177
|
+
}
|
|
40027
40178
|
const stack = stackByRoute.get(route.declaredAt);
|
|
40028
40179
|
if (!stack) {
|
|
40029
40180
|
out.push({ route });
|
|
@@ -40778,6 +40929,14 @@ async function handleRequest(req, res, state, opts) {
|
|
|
40778
40929
|
writeError(res, 404, "{\"message\":\"Not Found\"}");
|
|
40779
40930
|
return;
|
|
40780
40931
|
}
|
|
40932
|
+
if (match.route.mockCors) {
|
|
40933
|
+
writeMockCorsPreflight(res, match.route.mockCors);
|
|
40934
|
+
return;
|
|
40935
|
+
}
|
|
40936
|
+
if (match.route.unsupported) {
|
|
40937
|
+
writeNotImplemented(res, match.route.unsupported.reason);
|
|
40938
|
+
return;
|
|
40939
|
+
}
|
|
40781
40940
|
const authorizer = state.routes.find((r) => r.route.declaredAt === match.route.declaredAt && r.route.method === match.route.method)?.authorizer;
|
|
40782
40941
|
const snapshot = {
|
|
40783
40942
|
method,
|
|
@@ -41191,6 +41350,35 @@ function writeError(res, statusCode, body = "{\"message\":\"Internal server erro
|
|
|
41191
41350
|
res.setHeader("content-length", String(Buffer.byteLength(body, "utf-8")));
|
|
41192
41351
|
res.end(body);
|
|
41193
41352
|
}
|
|
41353
|
+
/**
|
|
41354
|
+
* Write the 501 Not Implemented response surfaced for routes the
|
|
41355
|
+
* discovery layer flagged as `unsupported`. The integration's reason
|
|
41356
|
+
* (e.g. "MOCK integration is not emulated", "WebSocket APIs are not
|
|
41357
|
+
* supported") is echoed in the body so the user gets a precise pointer
|
|
41358
|
+
* at first hit instead of a generic 502.
|
|
41359
|
+
*/
|
|
41360
|
+
function writeNotImplemented(res, reason) {
|
|
41361
|
+
const body = JSON.stringify({
|
|
41362
|
+
message: "Not Implemented",
|
|
41363
|
+
reason
|
|
41364
|
+
});
|
|
41365
|
+
res.statusCode = 501;
|
|
41366
|
+
res.setHeader("content-type", "application/json");
|
|
41367
|
+
res.setHeader("content-length", String(Buffer.byteLength(body, "utf-8")));
|
|
41368
|
+
res.end(body);
|
|
41369
|
+
}
|
|
41370
|
+
/**
|
|
41371
|
+
* Write the canonical CORS preflight response derived from a REST v1
|
|
41372
|
+
* MOCK Method's `Integration.IntegrationResponses[0].ResponseParameters`.
|
|
41373
|
+
* Headers are emitted verbatim — the discovery layer already stripped
|
|
41374
|
+
* AWS's literal single-quote wrappers and dropped any non-literal
|
|
41375
|
+
* (intrinsic-valued) entries.
|
|
41376
|
+
*/
|
|
41377
|
+
function writeMockCorsPreflight(res, preflight) {
|
|
41378
|
+
res.statusCode = preflight.statusCode;
|
|
41379
|
+
for (const [name, value] of Object.entries(preflight.headers)) res.setHeader(name, value);
|
|
41380
|
+
res.end();
|
|
41381
|
+
}
|
|
41194
41382
|
|
|
41195
41383
|
//#endregion
|
|
41196
41384
|
//#region src/local/api-server-grouping.ts
|
|
@@ -41817,6 +42005,7 @@ async function localStartApiCommand(target, options) {
|
|
|
41817
42005
|
if (basePort !== 0) nextPort += 1;
|
|
41818
42006
|
}
|
|
41819
42007
|
printPerServerRouteTables(servers);
|
|
42008
|
+
warnUnsupportedRoutes(servers.flatMap((s) => s.group.routes.map((r) => r.route)), logger);
|
|
41820
42009
|
logger.info(`Per-Lambda concurrency: ${perLambdaConcurrency} (override with --per-lambda-concurrency)`);
|
|
41821
42010
|
for (const { group, server } of servers) process.stdout.write(`Server listening on http://${server.host}:${server.port} (${group.displayName})\n`);
|
|
41822
42011
|
process.stdout.write("^C to stop and clean up containers.\n");
|
|
@@ -41935,11 +42124,16 @@ function pickTargetStacks(stacks, pattern) {
|
|
|
41935
42124
|
function uniqueLambdaIds(routes, routesWithAuth) {
|
|
41936
42125
|
const seen = /* @__PURE__ */ new Set();
|
|
41937
42126
|
const out = [];
|
|
41938
|
-
for (const r of routes)
|
|
41939
|
-
|
|
41940
|
-
|
|
42127
|
+
for (const r of routes) {
|
|
42128
|
+
if (r.unsupported || r.mockCors) continue;
|
|
42129
|
+
if (r.lambdaLogicalId.length === 0) continue;
|
|
42130
|
+
if (!seen.has(r.lambdaLogicalId)) {
|
|
42131
|
+
seen.add(r.lambdaLogicalId);
|
|
42132
|
+
out.push(r.lambdaLogicalId);
|
|
42133
|
+
}
|
|
41941
42134
|
}
|
|
41942
42135
|
for (const entry of routesWithAuth) {
|
|
42136
|
+
if (entry.route.unsupported || entry.route.mockCors) continue;
|
|
41943
42137
|
const auth = entry.authorizer;
|
|
41944
42138
|
if (!auth) continue;
|
|
41945
42139
|
if (auth.kind === "lambda-token" || auth.kind === "lambda-request") {
|
|
@@ -42138,6 +42332,13 @@ function resolveAssetCodePath(stack, logicalId, resource) {
|
|
|
42138
42332
|
/**
|
|
42139
42333
|
* Print the discovered route table to stdout. Format mirrors the spec
|
|
42140
42334
|
* doc's example so verify.sh / users can read it at a glance.
|
|
42335
|
+
*
|
|
42336
|
+
* Routes with `unsupported` or `mockCors` are annotated so the user can
|
|
42337
|
+
* tell at a glance which routes will dispatch to a Lambda vs which
|
|
42338
|
+
* return 501 / 204 directly:
|
|
42339
|
+
* - normal: `GET /items -> Handler (HTTP API)`
|
|
42340
|
+
* - mockCors: `OPTIONS /items -> [MOCK CORS preflight] (REST v1, stage 'prod')`
|
|
42341
|
+
* - unsupported: `POST /admin -> [501 Not Implemented] (HTTP API)`
|
|
42141
42342
|
*/
|
|
42142
42343
|
function printRouteTable(routes) {
|
|
42143
42344
|
const sorted = [...routes.map((r) => r.route)].sort((a, b) => {
|
|
@@ -42149,7 +42350,8 @@ function printRouteTable(routes) {
|
|
|
42149
42350
|
process.stdout.write("Discovered routes:\n");
|
|
42150
42351
|
for (const r of sorted) {
|
|
42151
42352
|
const sourceLabel = r.source === "http-api" ? "HTTP API" : r.source === "rest-v1" ? `REST v1, stage '${r.stage}'` : "Function URL";
|
|
42152
|
-
|
|
42353
|
+
const target = r.mockCors ? "[MOCK CORS preflight]" : r.unsupported ? "[501 Not Implemented]" : r.lambdaLogicalId;
|
|
42354
|
+
process.stdout.write(` ${r.method.padEnd(methodWidth)} ${r.pathPattern.padEnd(pathWidth)} -> ${target} (${sourceLabel})\n`);
|
|
42153
42355
|
}
|
|
42154
42356
|
process.stdout.write("\n");
|
|
42155
42357
|
}
|
|
@@ -42292,6 +42494,21 @@ function printPerServerRouteTables(servers) {
|
|
|
42292
42494
|
}
|
|
42293
42495
|
}
|
|
42294
42496
|
/**
|
|
42497
|
+
* Surface every `unsupported` route (deferred 501) as a startup warn so
|
|
42498
|
+
* the user sees what isn't reachable BEFORE they try to curl it. One
|
|
42499
|
+
* warn line per route — the route's `unsupported.reason` already names
|
|
42500
|
+
* the offender + the underlying limitation, so we just prefix with
|
|
42501
|
+
* method + path. Returns the number of unsupported routes so the caller
|
|
42502
|
+
* can emit a single-line summary header above the list.
|
|
42503
|
+
*/
|
|
42504
|
+
function warnUnsupportedRoutes(routes, logger) {
|
|
42505
|
+
const unsupported = routes.filter((r) => r.unsupported);
|
|
42506
|
+
if (unsupported.length === 0) return 0;
|
|
42507
|
+
logger.warn(`${unsupported.length} route(s) will respond HTTP 501 Not Implemented when hit (boot continued):`);
|
|
42508
|
+
for (const r of unsupported) logger.warn(` - ${r.method} ${r.pathPattern}: ${r.unsupported.reason}`);
|
|
42509
|
+
return unsupported.length;
|
|
42510
|
+
}
|
|
42511
|
+
/**
|
|
42295
42512
|
* One reload cycle for the multi-server topology (issue #260). The
|
|
42296
42513
|
* watcher serializes calls via a chain promise; this function:
|
|
42297
42514
|
*
|
|
@@ -42331,13 +42548,16 @@ async function reloadAllServers(args) {
|
|
|
42331
42548
|
pool: newPool,
|
|
42332
42549
|
corsConfigByApiId: material.corsConfigByApiId
|
|
42333
42550
|
};
|
|
42334
|
-
booted.server.setServerState(newState)
|
|
42551
|
+
const previousState = booted.server.setServerState(newState);
|
|
42552
|
+
booted.group = group;
|
|
42553
|
+
previousState.pool.dispose().catch((err) => {
|
|
42335
42554
|
logger.debug(`Previous pool dispose() failed for ${group.displayName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
42336
42555
|
});
|
|
42337
42556
|
}
|
|
42338
42557
|
lastAssetPaths.value = computeAssetPaths(material.specs);
|
|
42339
42558
|
if (watcher) watcher.update([output, ...lastAssetPaths.value]);
|
|
42340
42559
|
printPerServerRouteTables(servers);
|
|
42560
|
+
warnUnsupportedRoutes(servers.flatMap((s) => s.group.routes.map((r) => r.route)), logger);
|
|
42341
42561
|
}
|
|
42342
42562
|
/**
|
|
42343
42563
|
* Returns true when any value in the function's template env map is a
|
|
@@ -45300,7 +45520,7 @@ function reorderArgs(argv) {
|
|
|
45300
45520
|
*/
|
|
45301
45521
|
async function main() {
|
|
45302
45522
|
const program = new Command();
|
|
45303
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
45523
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.115.0");
|
|
45304
45524
|
program.addCommand(createBootstrapCommand());
|
|
45305
45525
|
program.addCommand(createSynthCommand());
|
|
45306
45526
|
program.addCommand(createListCommand());
|