@go-to-k/cdkd 0.161.1 → 0.161.3
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,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { _ as withSkipPrefix, a as runDockerStreaming, c as getLogger, d as getLiveRenderer, f as PATTERN_B_NAME_PROPERTIES, g as generateResourceNameWithFallback, h as generateResourceName, i as runDockerForeground, n as formatDockerLoginError, p as PATTERN_B_RESOURCE_TYPES, r as getDockerCmd, u as runStackBuffered, v as withStackName } from "./docker-cmd-iDMcWcre.js";
|
|
3
|
-
import { A as S3StateBackend, B as resolveCaptureObservedState, C as assertRegionMatch, D as DagBuilder, E as DiffCalculator, F as buildDockerImage, G as CFN_TEMPLATE_BODY_LIMIT, H as resolveStateBucketWithDefault, I as Synthesizer, J as findLargeInlineResources, K as CFN_TEMPLATE_URL_LIMIT, L as getDefaultStateBucketName, M as AssetPublisher, N as stringifyValue, O as TemplateParser, P as WorkGraph, Q as resolveBucketRegion, R as getLegacyStateBucketName, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveStateBucketWithDefaultAndSource, V as resolveSkipPrefix, W as warnDeprecatedNoPrefixCliFlag, X as AssemblyReader, Y as uploadCfnTemplate, _ as matchesCdkPath, a as withRetry, at as LocalStartServiceError, b as ProviderRegistry, bt as normalizeAwsError, c as bold, ct as NestedStackChildDirectDestroyError, d as green, dt as ResourceTimeoutError, et as CdkdError, f as red, ft as ResourceUpdateNotSupportedError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, ht as StackTerminationProtectionError, i as withResourceDeadline, it as LocalMigrateError, j as shouldRetainResource, k as LockManager, l as cyan, lt as PartialFailureError, m as IAMRoleProvider, mt as StackHasActiveImportsError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as RouteDiscoveryError, q as MIGRATE_TMP_PREFIX, r as DeployEngine, rt as LocalInvokeBuildError, s as formatResourceLine, st as MissingCdkCliError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ProvisioningError, v as normalizeAwsTagsToCfn, w as IntrinsicFunctionResolver, x as findActionableSilentDrops, xt as withErrorHandling, y as resolveExplicitPhysicalId, z as resolveApp } from "./deploy-engine-
|
|
3
|
+
import { A as S3StateBackend, B as resolveCaptureObservedState, C as assertRegionMatch, D as DagBuilder, E as DiffCalculator, F as buildDockerImage, G as CFN_TEMPLATE_BODY_LIMIT, H as resolveStateBucketWithDefault, I as Synthesizer, J as findLargeInlineResources, K as CFN_TEMPLATE_URL_LIMIT, L as getDefaultStateBucketName, M as AssetPublisher, N as stringifyValue, O as TemplateParser, P as WorkGraph, Q as resolveBucketRegion, R as getLegacyStateBucketName, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveStateBucketWithDefaultAndSource, V as resolveSkipPrefix, W as warnDeprecatedNoPrefixCliFlag, X as AssemblyReader, Y as uploadCfnTemplate, _ as matchesCdkPath, a as withRetry, at as LocalStartServiceError, b as ProviderRegistry, bt as normalizeAwsError, c as bold, ct as NestedStackChildDirectDestroyError, d as green, dt as ResourceTimeoutError, et as CdkdError, f as red, ft as ResourceUpdateNotSupportedError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, ht as StackTerminationProtectionError, i as withResourceDeadline, it as LocalMigrateError, j as shouldRetainResource, k as LockManager, l as cyan, lt as PartialFailureError, m as IAMRoleProvider, mt as StackHasActiveImportsError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as RouteDiscoveryError, q as MIGRATE_TMP_PREFIX, r as DeployEngine, rt as LocalInvokeBuildError, s as formatResourceLine, st as MissingCdkCliError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ProvisioningError, v as normalizeAwsTagsToCfn, w as IntrinsicFunctionResolver, x as findActionableSilentDrops, xt as withErrorHandling, y as resolveExplicitPhysicalId, z as resolveApp } from "./deploy-engine-D4iGkZAC.js";
|
|
4
4
|
import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-B15NAPbL.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, createHmac, createPublicKey, createVerify, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -43106,9 +43106,14 @@ function substituteAgainstState(value, contextOrResources) {
|
|
|
43106
43106
|
if (intrinsic === "Fn::GetAtt") return resolveGetAtt(arg, context);
|
|
43107
43107
|
if (intrinsic === "Fn::Sub") return resolveSub(arg, context);
|
|
43108
43108
|
if (intrinsic === "Fn::Join") return resolveJoin(arg, context);
|
|
43109
|
+
if (intrinsic === "Fn::Select") return resolveSelect(arg, context);
|
|
43110
|
+
if (intrinsic === "Fn::Split") return {
|
|
43111
|
+
kind: "unresolved",
|
|
43112
|
+
reason: `Fn::Split returns an array, which is not a valid env-var value (use Fn::Select to pick one element)`
|
|
43113
|
+
};
|
|
43109
43114
|
return {
|
|
43110
43115
|
kind: "unresolved",
|
|
43111
|
-
reason: `unsupported intrinsic '${intrinsic}' (supported: Ref, Fn::GetAtt, Fn::Sub, Fn::Join)`
|
|
43116
|
+
reason: `unsupported intrinsic '${intrinsic}' (supported: Ref, Fn::GetAtt, Fn::Sub, Fn::Join, Fn::Select, Fn::Split)`
|
|
43112
43117
|
};
|
|
43113
43118
|
}
|
|
43114
43119
|
function isContext(v) {
|
|
@@ -43322,6 +43327,121 @@ function resolveJoin(arg, context) {
|
|
|
43322
43327
|
};
|
|
43323
43328
|
}
|
|
43324
43329
|
/**
|
|
43330
|
+
* `Fn::Select: [<index>, <list>]` — pick the indexed element of an
|
|
43331
|
+
* array. Mirrors the semantics of `resolveImageIntrinsic`'s `Fn::Select`
|
|
43332
|
+
* branch in `src/local/intrinsic-image.ts` so the two resolvers behave
|
|
43333
|
+
* the same way for the same template shape.
|
|
43334
|
+
*
|
|
43335
|
+
* - Index may be a number (`0`) OR a numeric string (`'0'`) — CFn
|
|
43336
|
+
* templates often carry the string form after a JSON round-trip.
|
|
43337
|
+
* - List may be a resolved-array intrinsic (today only `Fn::Split`
|
|
43338
|
+
* produces a `string[]`) OR a literal `[...]` array of intrinsics
|
|
43339
|
+
* resolved on the fly.
|
|
43340
|
+
* - Out-of-bounds / negative / non-finite index reports unresolved.
|
|
43341
|
+
*/
|
|
43342
|
+
function resolveSelect(arg, context) {
|
|
43343
|
+
if (!Array.isArray(arg) || arg.length !== 2) return {
|
|
43344
|
+
kind: "unresolved",
|
|
43345
|
+
reason: `Fn::Select expects [index, list], got ${Array.isArray(arg) ? `array of length ${arg.length}` : typeof arg}`
|
|
43346
|
+
};
|
|
43347
|
+
const [rawIndex, listArg] = arg;
|
|
43348
|
+
let index;
|
|
43349
|
+
if (typeof rawIndex === "number") index = rawIndex;
|
|
43350
|
+
else if (typeof rawIndex === "string" && /^-?\d+$/.test(rawIndex)) index = Number.parseInt(rawIndex, 10);
|
|
43351
|
+
if (index === void 0 || !Number.isFinite(index)) return {
|
|
43352
|
+
kind: "unresolved",
|
|
43353
|
+
reason: `Fn::Select index must be a finite number (or numeric string), got ${typeof rawIndex}`
|
|
43354
|
+
};
|
|
43355
|
+
if (index < 0) return {
|
|
43356
|
+
kind: "unresolved",
|
|
43357
|
+
reason: `Fn::Select index must be non-negative, got ${index}`
|
|
43358
|
+
};
|
|
43359
|
+
const list = resolveAny(listArg, context);
|
|
43360
|
+
if (list.kind === "unresolved") return {
|
|
43361
|
+
kind: "unresolved",
|
|
43362
|
+
reason: `Fn::Select list: ${list.reason}`
|
|
43363
|
+
};
|
|
43364
|
+
if (Array.isArray(list.value)) {
|
|
43365
|
+
if (index >= list.value.length) return {
|
|
43366
|
+
kind: "unresolved",
|
|
43367
|
+
reason: `Fn::Select index ${index} out of bounds (list length ${list.value.length})`
|
|
43368
|
+
};
|
|
43369
|
+
return {
|
|
43370
|
+
kind: "literal",
|
|
43371
|
+
value: list.value[index]
|
|
43372
|
+
};
|
|
43373
|
+
}
|
|
43374
|
+
return {
|
|
43375
|
+
kind: "unresolved",
|
|
43376
|
+
reason: `Fn::Select list must resolve to an array, got ${typeof list.value}`
|
|
43377
|
+
};
|
|
43378
|
+
}
|
|
43379
|
+
/**
|
|
43380
|
+
* `Fn::Split: [<delimiter>, <string>]` — split a string into a
|
|
43381
|
+
* `string[]`. Only callable through `resolveAny` (i.e. inside
|
|
43382
|
+
* `Fn::Select`); the top-level dispatcher rejects bare `Fn::Split`
|
|
43383
|
+
* since an array cannot be an env-var value.
|
|
43384
|
+
*
|
|
43385
|
+
* The string argument can itself be an intrinsic (typical CDK shape:
|
|
43386
|
+
* `Fn::Split: [':', { 'Fn::GetAtt': [<Secret>, 'SecretArn'] }]`); it's
|
|
43387
|
+
* resolved through `substituteAgainstState` so we don't accidentally
|
|
43388
|
+
* admit nested-array shapes there.
|
|
43389
|
+
*/
|
|
43390
|
+
function resolveSplitAsArray(arg, context) {
|
|
43391
|
+
if (!Array.isArray(arg) || arg.length !== 2) return {
|
|
43392
|
+
kind: "unresolved",
|
|
43393
|
+
reason: `Fn::Split expects [delimiter, string], got ${Array.isArray(arg) ? `array of length ${arg.length}` : typeof arg}`
|
|
43394
|
+
};
|
|
43395
|
+
const [delim, src] = arg;
|
|
43396
|
+
if (typeof delim !== "string") return {
|
|
43397
|
+
kind: "unresolved",
|
|
43398
|
+
reason: `Fn::Split delimiter must be a string, got ${typeof delim}`
|
|
43399
|
+
};
|
|
43400
|
+
const sub = substituteAgainstState(src, context);
|
|
43401
|
+
if (sub.kind !== "literal") return {
|
|
43402
|
+
kind: "unresolved",
|
|
43403
|
+
reason: `Fn::Split string argument: ${sub.reason}`
|
|
43404
|
+
};
|
|
43405
|
+
if (typeof sub.value !== "string") return {
|
|
43406
|
+
kind: "unresolved",
|
|
43407
|
+
reason: `Fn::Split string argument must resolve to a string, got ${typeof sub.value}`
|
|
43408
|
+
};
|
|
43409
|
+
return {
|
|
43410
|
+
kind: "literal",
|
|
43411
|
+
value: sub.value.split(delim)
|
|
43412
|
+
};
|
|
43413
|
+
}
|
|
43414
|
+
/**
|
|
43415
|
+
* Array-tolerant resolver used by `Fn::Select`'s `list` argument.
|
|
43416
|
+
* Returns either the scalar `StateSubstitutionResult` shape (delegating
|
|
43417
|
+
* to `substituteAgainstState`) OR a `{kind: 'literal', value: string[]}`
|
|
43418
|
+
* when the node is `Fn::Split` / a literal array of intrinsics.
|
|
43419
|
+
*
|
|
43420
|
+
* Top-level `substituteAgainstState` deliberately doesn't go through
|
|
43421
|
+
* this helper — env-var values can't be arrays, and the asymmetry
|
|
43422
|
+
* matches `intrinsic-image.ts`'s `resolveImageIntrinsic` (scalar) vs
|
|
43423
|
+
* `resolveImageIntrinsicAny` (scalar OR array) split.
|
|
43424
|
+
*/
|
|
43425
|
+
function resolveAny(value, context) {
|
|
43426
|
+
if (Array.isArray(value)) {
|
|
43427
|
+
const out = [];
|
|
43428
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
43429
|
+
const sub = substituteAgainstState(value[i], context);
|
|
43430
|
+
if (sub.kind !== "literal") return {
|
|
43431
|
+
kind: "unresolved",
|
|
43432
|
+
reason: `list element [${i}]: ${sub.reason}`
|
|
43433
|
+
};
|
|
43434
|
+
out.push(String(sub.value));
|
|
43435
|
+
}
|
|
43436
|
+
return {
|
|
43437
|
+
kind: "literal",
|
|
43438
|
+
value: out
|
|
43439
|
+
};
|
|
43440
|
+
}
|
|
43441
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && Object.prototype.hasOwnProperty.call(value, "Fn::Split")) return resolveSplitAsArray(value["Fn::Split"], context);
|
|
43442
|
+
return substituteAgainstState(value, context);
|
|
43443
|
+
}
|
|
43444
|
+
/**
|
|
43325
43445
|
* Async sibling of {@link substituteAgainstState}. Same semantics for every
|
|
43326
43446
|
* intrinsic the sync path supports; additionally consults the
|
|
43327
43447
|
* `crossStackResolver` (when supplied on the context) for `Fn::ImportValue`
|
|
@@ -43351,12 +43471,12 @@ async function substituteAgainstStateAsync(value, contextOrResources) {
|
|
|
43351
43471
|
};
|
|
43352
43472
|
const intrinsic = keys[0];
|
|
43353
43473
|
const arg = obj[intrinsic];
|
|
43354
|
-
if (intrinsic === "Ref" || intrinsic === "Fn::GetAtt" || intrinsic === "Fn::Sub" || intrinsic === "Fn::Join") return substituteAgainstState(value, context);
|
|
43474
|
+
if (intrinsic === "Ref" || intrinsic === "Fn::GetAtt" || intrinsic === "Fn::Sub" || intrinsic === "Fn::Join" || intrinsic === "Fn::Select" || intrinsic === "Fn::Split") return substituteAgainstState(value, context);
|
|
43355
43475
|
if (intrinsic === "Fn::ImportValue") return resolveImportValueAsync(arg, context);
|
|
43356
43476
|
if (intrinsic === "Fn::GetStackOutput") return resolveGetStackOutputAsync(arg, context);
|
|
43357
43477
|
return {
|
|
43358
43478
|
kind: "unresolved",
|
|
43359
|
-
reason: `unsupported intrinsic '${intrinsic}' (supported: Ref, Fn::GetAtt, Fn::Sub, Fn::Join, Fn::ImportValue, Fn::GetStackOutput)`
|
|
43479
|
+
reason: `unsupported intrinsic '${intrinsic}' (supported: Ref, Fn::GetAtt, Fn::Sub, Fn::Join, Fn::Select, Fn::Split, Fn::ImportValue, Fn::GetStackOutput)`
|
|
43360
43480
|
};
|
|
43361
43481
|
}
|
|
43362
43482
|
/**
|
|
@@ -46638,7 +46758,7 @@ function buildAwsIntegrationConfig(integration, stackName, logicalId) {
|
|
|
46638
46758
|
const uri = integration["Uri"];
|
|
46639
46759
|
if (!uriContainsLambdaMarker(uri)) return {
|
|
46640
46760
|
kind: "unsupported",
|
|
46641
|
-
reason: `${stackName}/${logicalId}: REST v1 AWS integration targeting a non-Lambda service (Uri ${shortJson$1(uri)}) is not emulated locally in cdkd v1. Lambda non-proxy AWS integrations are supported; direct AWS service integrations (S3 / SQS / SNS / DynamoDB) require deploying to AWS. See docs/local-emulation.md.`
|
|
46761
|
+
reason: `${stackName}/${logicalId}: REST v1 AWS integration targeting a non-Lambda service (Uri ${shortJson$1(uri)}) is not emulated locally in cdkd v1. Lambda non-proxy AWS integrations are supported; direct AWS service integrations (S3 / SQS / SNS / DynamoDB) require deploying to AWS. See https://github.com/go-to-k/cdkd/blob/main/docs/local-emulation.md.`
|
|
46642
46762
|
};
|
|
46643
46763
|
const arnOutcome = resolveLambdaArnOutcome(uri);
|
|
46644
46764
|
if (arnOutcome.kind === "unsupported") return {
|
|
@@ -54529,7 +54649,7 @@ function warnVpcConfigLambdas(routesWithAuth, stacks) {
|
|
|
54529
54649
|
const resource = stack.template.Resources?.[logicalId];
|
|
54530
54650
|
if (!resource || resource.Type !== "AWS::Lambda::Function") continue;
|
|
54531
54651
|
const vpcConfig = (resource.Properties ?? {})["VpcConfig"];
|
|
54532
|
-
if (vpcConfig && typeof vpcConfig === "object" && Object.keys(vpcConfig).length > 0) logger.warn(`Lambda ${logicalId} has VpcConfig — local container will reach external services via the host's network, NOT through the deployed VPC's NAT/private subnets. Calls to private RDS/ElastiCache will fail. See docs/cli-reference.md (cdkd local start-api — Limitations) for details.`);
|
|
54652
|
+
if (vpcConfig && typeof vpcConfig === "object" && Object.keys(vpcConfig).length > 0) logger.warn(`Lambda ${logicalId} has VpcConfig — local container will reach external services via the host's network, NOT through the deployed VPC's NAT/private subnets. Calls to private RDS/ElastiCache will fail. See https://github.com/go-to-k/cdkd/blob/main/docs/cli-reference.md (cdkd local start-api — Limitations) for details.`);
|
|
54533
54653
|
break;
|
|
54534
54654
|
}
|
|
54535
54655
|
}
|
|
@@ -54549,7 +54669,7 @@ function warnIamRoutes(routesWithAuth) {
|
|
|
54549
54669
|
const iamRoutes = [];
|
|
54550
54670
|
for (const entry of routesWithAuth) if (entry.authorizer?.kind === "iam") iamRoutes.push(entry.route.declaredAt);
|
|
54551
54671
|
if (iamRoutes.length === 0) return false;
|
|
54552
|
-
logger.warn(`${iamRoutes.length} route(s) declare AuthorizationType: AWS_IAM — cdkd local start-api verifies SigV4 signatures against your local AWS credentials, but does NOT emulate IAM policy evaluation (resource / action / condition rules). Signature-verified callers reach the handler under their own identity; downstream authorization is the dev's responsibility. See docs/cli-reference.md (cdkd local start-api — AWS_IAM authorizer) for details.`);
|
|
54672
|
+
logger.warn(`${iamRoutes.length} route(s) declare AuthorizationType: AWS_IAM — cdkd local start-api verifies SigV4 signatures against your local AWS credentials, but does NOT emulate IAM policy evaluation (resource / action / condition rules). Signature-verified callers reach the handler under their own identity; downstream authorization is the dev's responsibility. See https://github.com/go-to-k/cdkd/blob/main/docs/cli-reference.md (cdkd local start-api — AWS_IAM authorizer) for details.`);
|
|
54553
54673
|
for (const declaredAt of iamRoutes) logger.warn(` - ${declaredAt}`);
|
|
54554
54674
|
return true;
|
|
54555
54675
|
}
|
|
@@ -55305,7 +55425,7 @@ function resolveMtlsConfig(options) {
|
|
|
55305
55425
|
* Builder for the `start-api` subcommand. Wired up by `local.ts`.
|
|
55306
55426
|
*/
|
|
55307
55427
|
function createLocalStartApiCommand() {
|
|
55308
|
-
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see docs/local-emulation.md). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Bare <arn> = global default; <LogicalId>=<arn> = per-Lambda override (repeatable). Per-Lambda > global > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--watch", "Hot-reload: re-synth + re-discover routes when cdk.out/ or asset directories change. Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers (issue #448). Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--from-state", "Read cdkd S3 state for every routed stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::Join (and AWS pseudo parameters) in Lambda env vars with the deployed physical IDs / attributes. Off by default — pre-PR warn-and-drop semantics are preserved. Turn on for stacks already deployed via cdkd deploy. Mirrors `cdkd local invoke --from-state` / `cdkd local run-task --from-state`. Re-runs against fresh state on every hot-reload firing (--watch).").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via DescribeStackResources and substitute Ref / Fn::ImportValue in Lambda env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn DescribeStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).")).addOption(new Option("--mtls-truststore <path>", "PEM-encoded CA bundle for client-certificate verification (mutual TLS). When set, the local server switches from HTTP to HTTPS and the TLS handshake rejects clients whose certificate doesn't chain to one of these CAs. Verified certs are surfaced on the Lambda event under requestContext.identity.clientCert (REST v1) / requestContext.authentication.clientCert (HTTP API v2). Must be set together with --mtls-cert + --mtls-key; partial flag sets are rejected. Generate a CA + server + client cert for local dev: openssl req -x509 -newkey rsa:2048 -nodes -keyout ca-key.pem -out ca.pem -subj \"/CN=cdkd-local-ca\" -days 365; openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-csr.pem -subj \"/CN=localhost\"; openssl x509 -req -in server-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365; openssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-csr.pem -subj \"/CN=client\"; openssl x509 -req -in client-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365; curl --cacert ca.pem --cert client-cert.pem --key client-key.pem https://localhost:<port>/...")).addOption(new Option("--mtls-cert <path>", "PEM-encoded server certificate for mutual TLS. Self-signed is fine for local dev. Must be set together with --mtls-truststore + --mtls-key.")).addOption(new Option("--mtls-key <path>", "PEM-encoded server private key matching --mtls-cert. Must be set together with --mtls-truststore + --mtls-cert.")).addOption(new Option("--allow-unverified-sigv4", "Opt-in: allow AWS_IAM SigV4 requests that cannot be cryptographically verified (foreign access-key-id, OR no local AWS credentials configured) to pass through with a placeholder principalId. DEFAULT off — fail-closed so unauthenticated bypass is impossible against `event.requestContext.identity.accessKey`-trusting handler code. Use only in dev loops where you understand the risk.").default(false)).action(withErrorHandling(localStartApiCommand));
|
|
55428
|
+
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see https://github.com/go-to-k/cdkd/blob/main/docs/local-emulation.md). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Bare <arn> = global default; <LogicalId>=<arn> = per-Lambda override (repeatable). Per-Lambda > global > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--watch", "Hot-reload: re-synth + re-discover routes when cdk.out/ or asset directories change. Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers (issue #448). Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--from-state", "Read cdkd S3 state for every routed stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::Join (and AWS pseudo parameters) in Lambda env vars with the deployed physical IDs / attributes. Off by default — pre-PR warn-and-drop semantics are preserved. Turn on for stacks already deployed via cdkd deploy. Mirrors `cdkd local invoke --from-state` / `cdkd local run-task --from-state`. Re-runs against fresh state on every hot-reload firing (--watch).").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via DescribeStackResources and substitute Ref / Fn::ImportValue in Lambda env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn DescribeStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).")).addOption(new Option("--mtls-truststore <path>", "PEM-encoded CA bundle for client-certificate verification (mutual TLS). When set, the local server switches from HTTP to HTTPS and the TLS handshake rejects clients whose certificate doesn't chain to one of these CAs. Verified certs are surfaced on the Lambda event under requestContext.identity.clientCert (REST v1) / requestContext.authentication.clientCert (HTTP API v2). Must be set together with --mtls-cert + --mtls-key; partial flag sets are rejected. Generate a CA + server + client cert for local dev: openssl req -x509 -newkey rsa:2048 -nodes -keyout ca-key.pem -out ca.pem -subj \"/CN=cdkd-local-ca\" -days 365; openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-csr.pem -subj \"/CN=localhost\"; openssl x509 -req -in server-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365; openssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-csr.pem -subj \"/CN=client\"; openssl x509 -req -in client-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365; curl --cacert ca.pem --cert client-cert.pem --key client-key.pem https://localhost:<port>/...")).addOption(new Option("--mtls-cert <path>", "PEM-encoded server certificate for mutual TLS. Self-signed is fine for local dev. Must be set together with --mtls-truststore + --mtls-key.")).addOption(new Option("--mtls-key <path>", "PEM-encoded server private key matching --mtls-cert. Must be set together with --mtls-truststore + --mtls-cert.")).addOption(new Option("--allow-unverified-sigv4", "Opt-in: allow AWS_IAM SigV4 requests that cannot be cryptographically verified (foreign access-key-id, OR no local AWS credentials configured) to pass through with a placeholder principalId. DEFAULT off — fail-closed so unauthenticated bypass is impossible against `event.requestContext.identity.accessKey`-trusting handler code. Use only in dev loops where you understand the risk.").default(false)).action(withErrorHandling(localStartApiCommand));
|
|
55309
55429
|
[
|
|
55310
55430
|
...commonOptions,
|
|
55311
55431
|
...appOptions,
|
|
@@ -59644,7 +59764,7 @@ function reorderArgs(argv) {
|
|
|
59644
59764
|
*/
|
|
59645
59765
|
async function main() {
|
|
59646
59766
|
const program = new Command();
|
|
59647
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.161.
|
|
59767
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.161.3");
|
|
59648
59768
|
program.addCommand(createBootstrapCommand());
|
|
59649
59769
|
program.addCommand(createSynthCommand());
|
|
59650
59770
|
program.addCommand(createListCommand());
|