cdk-local 0.30.0 → 0.32.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 +5 -5
- package/dist/cli.js +2 -2
- package/dist/{docker-cmd-DvoehoBl.js → docker-cmd--8TRSn9z.js} +7 -3
- package/dist/docker-cmd--8TRSn9z.js.map +1 -0
- package/dist/index.d.ts +66 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{local-list-Qa6V8bzl.js → local-list-DdmjsVLF.js} +203 -92
- package/dist/local-list-DdmjsVLF.js.map +1 -0
- package/package.json +1 -1
- package/dist/docker-cmd-DvoehoBl.js.map +0 -1
- package/dist/local-list-Qa6V8bzl.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as runDockerStreaming, c as getEmbedConfig, i as runDockerForeground, n as formatDockerLoginError, o as spawnStreaming, r as getDockerCmd, s as getLogger, u as setEmbedConfig } from "./docker-cmd
|
|
1
|
+
import { a as runDockerStreaming, c as getEmbedConfig, i as runDockerForeground, n as formatDockerLoginError, o as spawnStreaming, r as getDockerCmd, s as getLogger, u as setEmbedConfig } from "./docker-cmd--8TRSn9z.js";
|
|
2
2
|
import { cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
@@ -91,17 +91,6 @@ function appOptions() {
|
|
|
91
91
|
* Context options.
|
|
92
92
|
*/
|
|
93
93
|
const contextOptions = [new Option("-c, --context <key=value...>", "Set context values (can be specified multiple times)")];
|
|
94
|
-
/**
|
|
95
|
-
* `-i, --interactive` — present an arrow-key picker to choose the
|
|
96
|
-
* target(s) for this command instead of typing a CDK path / logical ID.
|
|
97
|
-
* Added to the four run commands (NOT `list`, which lists everything).
|
|
98
|
-
* Requires a TTY; in a non-interactive shell the command errors with a
|
|
99
|
-
* clear message. The required-target commands (`invoke` / `run-task` /
|
|
100
|
-
* `start-service`) also auto-launch the picker when the target is
|
|
101
|
-
* omitted in a TTY; `start-api` shows it only with the explicit flag
|
|
102
|
-
* (a bare `start-api` keeps serving every discovered API).
|
|
103
|
-
*/
|
|
104
|
-
const interactiveOption = new Option("-i, --interactive", "Pick the target(s) from an interactive list instead of passing them as arguments (requires a TTY)").default(false);
|
|
105
94
|
const IAM_ROLE_ARN_REGEX = /^arn:[^:]+:iam::\d+:role\//;
|
|
106
95
|
function parseAssumeRoleToken(raw, previous) {
|
|
107
96
|
const acc = previous ?? { perLambda: {} };
|
|
@@ -2000,7 +1989,7 @@ function readApiCdkPath(logicalId, template) {
|
|
|
2000
1989
|
|
|
2001
1990
|
//#endregion
|
|
2002
1991
|
//#region src/local/target-lister.ts
|
|
2003
|
-
function makeEntry(stackName, logicalId, cdkPath) {
|
|
1992
|
+
function makeEntry(stackName, logicalId, cdkPath, kind) {
|
|
2004
1993
|
const entry = {
|
|
2005
1994
|
logicalId,
|
|
2006
1995
|
stackName,
|
|
@@ -2008,8 +1997,17 @@ function makeEntry(stackName, logicalId, cdkPath) {
|
|
|
2008
1997
|
};
|
|
2009
1998
|
const display = cdkPath ? cdkPath.replace(/\/Resource$/, "") : void 0;
|
|
2010
1999
|
if (display) entry.displayPath = display;
|
|
2000
|
+
if (kind) entry.kind = kind;
|
|
2011
2001
|
return entry;
|
|
2012
2002
|
}
|
|
2003
|
+
/** Map a discovered route's `source` to the human-readable surface kind. */
|
|
2004
|
+
function apiKindLabel(source) {
|
|
2005
|
+
switch (source) {
|
|
2006
|
+
case "http-api": return "HTTP API v2";
|
|
2007
|
+
case "rest-v1": return "REST API v1";
|
|
2008
|
+
case "function-url": return "Function URL";
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2013
2011
|
function scanByType(stacks, type) {
|
|
2014
2012
|
const entries = [];
|
|
2015
2013
|
for (const stack of stacks) {
|
|
@@ -2038,22 +2036,22 @@ function scanByType(stacks, type) {
|
|
|
2038
2036
|
*/
|
|
2039
2037
|
function listApiSurfaces(stacks) {
|
|
2040
2038
|
const byKey = /* @__PURE__ */ new Map();
|
|
2041
|
-
const add = (stackName, logicalId, cdkPath) => {
|
|
2039
|
+
const add = (stackName, logicalId, cdkPath, kind) => {
|
|
2042
2040
|
const key = `${stackName}:${logicalId}`;
|
|
2043
|
-
if (!byKey.has(key)) byKey.set(key, makeEntry(stackName, logicalId, cdkPath));
|
|
2041
|
+
if (!byKey.has(key)) byKey.set(key, makeEntry(stackName, logicalId, cdkPath, kind));
|
|
2044
2042
|
};
|
|
2045
2043
|
try {
|
|
2046
2044
|
for (const route of discoverRoutes(stacks)) {
|
|
2047
2045
|
if (!route.apiStackName) continue;
|
|
2048
2046
|
const logicalId = route.source === "function-url" ? route.lambdaLogicalId : route.apiLogicalId;
|
|
2049
2047
|
if (!logicalId) continue;
|
|
2050
|
-
add(route.apiStackName, logicalId, route.apiCdkPath);
|
|
2048
|
+
add(route.apiStackName, logicalId, route.apiCdkPath, apiKindLabel(route.source));
|
|
2051
2049
|
}
|
|
2052
2050
|
} catch (err) {
|
|
2053
2051
|
getLogger().warn(`Could not enumerate REST / HTTP / Function URL targets: ${err instanceof Error ? err.message : String(err)}`);
|
|
2054
2052
|
}
|
|
2055
2053
|
const { apis, errors } = discoverWebSocketApis(stacks);
|
|
2056
|
-
for (const api of apis) add(api.apiStackName, api.apiLogicalId, api.apiCdkPath);
|
|
2054
|
+
for (const api of apis) add(api.apiStackName, api.apiLogicalId, api.apiCdkPath, "WebSocket");
|
|
2057
2055
|
for (const e of errors) getLogger().warn(`Could not enumerate a WebSocket API target: ${e}`);
|
|
2058
2056
|
return [...byKey.values()];
|
|
2059
2057
|
}
|
|
@@ -2099,7 +2097,7 @@ function toOption(entry) {
|
|
|
2099
2097
|
value,
|
|
2100
2098
|
label: value
|
|
2101
2099
|
};
|
|
2102
|
-
if (entry.
|
|
2100
|
+
if (entry.kind) option.hint = entry.kind;
|
|
2103
2101
|
return option;
|
|
2104
2102
|
}
|
|
2105
2103
|
/**
|
|
@@ -2123,19 +2121,25 @@ async function pickOneTarget(message, entries) {
|
|
|
2123
2121
|
* The key hint is baked into the message because multi-select's
|
|
2124
2122
|
* space-to-toggle is not discoverable — users expect enter to pick the
|
|
2125
2123
|
* highlighted row and miss that nothing is selected yet.
|
|
2124
|
+
*
|
|
2125
|
+
* When `preselectAll` is true, every row starts selected (via
|
|
2126
|
+
* `@clack/prompts` `initialValues`) so a bare Enter confirms the whole
|
|
2127
|
+
* set — used by `start-api`, whose long-standing default is "serve every
|
|
2128
|
+
* discovered API". The user deselects rows to serve a subset.
|
|
2126
2129
|
*/
|
|
2127
|
-
async function pickManyTargets(message, entries) {
|
|
2130
|
+
async function pickManyTargets(message, entries, options = {}) {
|
|
2131
|
+
const opts = entries.map(toOption);
|
|
2128
2132
|
const chosen = await multiselect({
|
|
2129
2133
|
message: `${message} (space to select, enter to confirm)`,
|
|
2130
|
-
options:
|
|
2131
|
-
required: true
|
|
2134
|
+
options: opts,
|
|
2135
|
+
required: true,
|
|
2136
|
+
...options.preselectAll && { initialValues: opts.map((o) => o.value) }
|
|
2132
2137
|
});
|
|
2133
2138
|
if (isCancel(chosen)) throw new TargetSelectionCancelledError();
|
|
2134
2139
|
return chosen;
|
|
2135
2140
|
}
|
|
2136
|
-
function ensureCanPrompt(
|
|
2141
|
+
function ensureCanPrompt(onMissing) {
|
|
2137
2142
|
if (isInteractive()) return;
|
|
2138
|
-
if (interactive) throw new InteractiveTtyRequiredError("`-i/--interactive` requires an interactive terminal, but stdin/stdout is not a TTY.");
|
|
2139
2143
|
throw onMissing();
|
|
2140
2144
|
}
|
|
2141
2145
|
function ensureHasCandidates(count, noun) {
|
|
@@ -2144,17 +2148,15 @@ function ensureHasCandidates(count, noun) {
|
|
|
2144
2148
|
}
|
|
2145
2149
|
/**
|
|
2146
2150
|
* Resolve a single positional target, prompting interactively when the
|
|
2147
|
-
*
|
|
2151
|
+
* target is omitted in a TTY.
|
|
2148
2152
|
*
|
|
2149
|
-
* - `provided` set
|
|
2150
|
-
* - `-i` set → always prompt (any `provided` value is ignored).
|
|
2153
|
+
* - `provided` set → returned as-is (no prompt).
|
|
2151
2154
|
* - omitted, TTY → prompt.
|
|
2152
2155
|
* - omitted, no TTY → `onMissing()` (the command's required-arg error).
|
|
2153
2156
|
*/
|
|
2154
2157
|
async function resolveSingleTarget(provided, params) {
|
|
2155
|
-
if (provided
|
|
2156
|
-
|
|
2157
|
-
ensureCanPrompt(params.interactive, params.onMissing);
|
|
2158
|
+
if (provided) return provided;
|
|
2159
|
+
ensureCanPrompt(params.onMissing);
|
|
2158
2160
|
ensureHasCandidates(params.entries.length, params.noun);
|
|
2159
2161
|
return pickOneTarget(params.message, params.entries);
|
|
2160
2162
|
}
|
|
@@ -2164,9 +2166,8 @@ async function resolveSingleTarget(provided, params) {
|
|
|
2164
2166
|
* rules as {@link resolveSingleTarget}.
|
|
2165
2167
|
*/
|
|
2166
2168
|
async function resolveMultiTarget(provided, params) {
|
|
2167
|
-
if (provided.length > 0
|
|
2168
|
-
|
|
2169
|
-
ensureCanPrompt(params.interactive, params.onMissing);
|
|
2169
|
+
if (provided.length > 0) return provided;
|
|
2170
|
+
ensureCanPrompt(params.onMissing);
|
|
2170
2171
|
ensureHasCandidates(params.entries.length, params.noun);
|
|
2171
2172
|
return pickManyTargets(params.message, params.entries);
|
|
2172
2173
|
}
|
|
@@ -7303,11 +7304,10 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7303
7304
|
};
|
|
7304
7305
|
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
7305
7306
|
const lambda = resolveLambdaTarget(await resolveSingleTarget(target, {
|
|
7306
|
-
interactive: options.interactive,
|
|
7307
7307
|
entries: listTargets(stacks).lambdas,
|
|
7308
7308
|
message: "Select a Lambda function to invoke",
|
|
7309
7309
|
noun: "Lambda functions",
|
|
7310
|
-
onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} invoke requires a <target> (a Lambda display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or
|
|
7310
|
+
onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} invoke requires a <target> (a Lambda display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or run it in a TTY to pick interactively.`, "LOCAL_INVOKE_TARGET_REQUIRED")
|
|
7311
7311
|
}), stacks);
|
|
7312
7312
|
const targetLabel = lambda.kind === "zip" ? lambda.runtime : "container image";
|
|
7313
7313
|
logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${targetLabel})`);
|
|
@@ -7781,7 +7781,7 @@ function pickReferencedLogicalId(intrinsic) {
|
|
|
7781
7781
|
}
|
|
7782
7782
|
function createLocalInvokeCommand(opts = {}) {
|
|
7783
7783
|
setEmbedConfig(opts.embedConfig);
|
|
7784
|
-
const invoke = new Command("invoke").description("Run a Lambda function locally in a Docker container (RIE-backed). Target accepts a CDK display path (MyStack/MyApi/Handler) or stack-qualified logical ID (MyStack:MyApiHandler1234ABCD). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal
|
|
7784
|
+
const invoke = new Command("invoke").description("Run a Lambda function locally in a Docker container (RIE-backed). Target accepts a CDK display path (MyStack/MyApi/Handler) or stack-qualified logical ID (MyStack:MyApiHandler1234ABCD). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick the Lambda from a list.").argument("[target]", "CDK display path or stack-qualified logical ID of the Lambda to invoke (omit to pick interactively in a TTY)").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for IMAGE local-build path; `docker build` does not pull base layers by default")).addOption(new Option("--no-build", "Skip docker build on the IMAGE local-build path (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ZIP Lambdas and the IMAGE ECR-pull path. Compatible with --no-pull.")).addOption(new Option("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(new Option("--container-host <host>", "Host to bind the RIE port to").default("127.0.0.1")).addOption(new Option("--assume-role [arn]", "Assume the Lambda's deployed execution role and forward STS-issued temp credentials to the container so the handler runs with the deployed function's narrow permissions. Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) auto-resolves the function's execution role ARN from state (requires an active state source); (3) `--no-assume-role` explicitly opts out. Off by default — when omitted, the developer's shell credentials are forwarded unchanged (SAM-compatible default). STS failures degrade to a warn + dev-creds fallback.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers. 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("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass an explicit value when CFn stack name differs. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).action(withErrorHandling(async (target, options) => {
|
|
7785
7785
|
await localInvokeCommand(target, options, opts.extraStateProviders);
|
|
7786
7786
|
}));
|
|
7787
7787
|
[
|
|
@@ -7789,7 +7789,6 @@ function createLocalInvokeCommand(opts = {}) {
|
|
|
7789
7789
|
...appOptions(),
|
|
7790
7790
|
...contextOptions
|
|
7791
7791
|
].forEach((option) => invoke.addOption(option));
|
|
7792
|
-
invoke.addOption(interactiveOption);
|
|
7793
7792
|
invoke.addOption(deprecatedRegionOption);
|
|
7794
7793
|
return invoke;
|
|
7795
7794
|
}
|
|
@@ -13031,14 +13030,15 @@ async function verifySigV4(req, loadCredentials, opts = {}) {
|
|
|
13031
13030
|
local = await loadCredentials();
|
|
13032
13031
|
} catch (err) {
|
|
13033
13032
|
const reason = err instanceof Error ? err.message : String(err);
|
|
13033
|
+
const { sigV4StrictByDefault, sigV4OptFlag: optFlag } = getEmbedConfig();
|
|
13034
13034
|
if (opts.strict && !opts.oacFronted) {
|
|
13035
|
-
logger.warn(`AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified.
|
|
13035
|
+
logger.warn(sigV4StrictByDefault ? `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified. cdk-local denies unverifiable IAM requests by default; pass ${optFlag} to warn-and-pass, or configure AWS credentials cdk-local can read.` : `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified. ${optFlag} is set, so cdk-local denies unverifiable IAM requests; remove ${optFlag} to warn-and-pass (the default), or configure AWS credentials cdk-local can read.`);
|
|
13036
13036
|
return {
|
|
13037
13037
|
allow: false,
|
|
13038
13038
|
identityHash: void 0
|
|
13039
13039
|
};
|
|
13040
13040
|
}
|
|
13041
|
-
logger.warn(opts.oacFronted ? `AWS_IAM authorizer: Function URL is fronted by CloudFront OAC (CloudFront re-signs origin requests in production), and local AWS credentials could not be resolved (${reason}). Passing through with unverified principalId 'unverified-no-creds'. Do NOT trust event.requestContext.identity.accessKey in handler code.` : `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it against AWS's copy of the secret). Passing through with unverified principalId 'unverified-no-creds' — cdk-local's default for unverifiable IAM requests; pass
|
|
13041
|
+
logger.warn(opts.oacFronted ? `AWS_IAM authorizer: Function URL is fronted by CloudFront OAC (CloudFront re-signs origin requests in production), and local AWS credentials could not be resolved (${reason}). Passing through with unverified principalId 'unverified-no-creds'. Do NOT trust event.requestContext.identity.accessKey in handler code.` : sigV4StrictByDefault ? `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it against AWS's copy of the secret). ${optFlag} is set; passing through with unverified principalId 'unverified-no-creds'. Do NOT trust event.requestContext.identity.accessKey in handler code.` : `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it against AWS's copy of the secret). Passing through with unverified principalId 'unverified-no-creds' — cdk-local's default for unverifiable IAM requests; pass ${optFlag} to deny instead. Do NOT trust event.requestContext.identity.accessKey in handler code.`);
|
|
13042
13042
|
return {
|
|
13043
13043
|
allow: true,
|
|
13044
13044
|
principalId: "unverified-no-creds",
|
|
@@ -13048,9 +13048,10 @@ async function verifySigV4(req, loadCredentials, opts = {}) {
|
|
|
13048
13048
|
if (local.accessKeyId.toLowerCase() !== parsed.credentialAccessKeyId.toLowerCase()) {
|
|
13049
13049
|
const warned = opts.warnedForeignIds;
|
|
13050
13050
|
const dedupKey = parsed.credentialAccessKeyId.toLowerCase();
|
|
13051
|
+
const { sigV4StrictByDefault, sigV4OptFlag: optFlag } = getEmbedConfig();
|
|
13051
13052
|
if (opts.strict && !opts.oacFronted) {
|
|
13052
13053
|
if (!warned || !warned.has(dedupKey)) {
|
|
13053
|
-
logger.warn(`AWS_IAM authorizer: request signed with access-key-id '${parsed.credentialAccessKeyId}', which differs from the AWS credentials cdk-local resolved locally — SigV4 (HMAC / shared-secret) can only be verified with the signer's own credentials, never a federated / Cognito Identity Pool / cross-account signer's.
|
|
13054
|
+
logger.warn(sigV4StrictByDefault ? `AWS_IAM authorizer: request signed with access-key-id '${parsed.credentialAccessKeyId}', which differs from the AWS credentials cdk-local resolved locally — SigV4 (HMAC / shared-secret) can only be verified with the signer's own credentials, never a federated / Cognito Identity Pool / cross-account signer's. cdk-local denies it by default; pass ${optFlag} to warn-and-pass, or sign the request with the same credentials cdk-local resolves locally.` : `AWS_IAM authorizer: request signed with access-key-id '${parsed.credentialAccessKeyId}', which differs from the AWS credentials cdk-local resolved locally — SigV4 (HMAC / shared-secret) can only be verified with the signer's own credentials, never a federated / Cognito Identity Pool / cross-account signer's. ${optFlag} is set, so cdk-local denies it; remove ${optFlag} to warn-and-pass (the default), or sign the request with the same credentials cdk-local resolves locally.`);
|
|
13054
13055
|
warned?.add(dedupKey);
|
|
13055
13056
|
}
|
|
13056
13057
|
return {
|
|
@@ -13059,7 +13060,7 @@ async function verifySigV4(req, loadCredentials, opts = {}) {
|
|
|
13059
13060
|
};
|
|
13060
13061
|
}
|
|
13061
13062
|
if (!warned || !warned.has(dedupKey)) {
|
|
13062
|
-
logger.warn(opts.oacFronted ? `AWS_IAM authorizer: Function URL is fronted by CloudFront OAC — in production CloudFront re-signs the origin request, so the local client's signature (access-key-id '${parsed.credentialAccessKeyId}') cannot be verified. Passing through with unverified principalId 'unverified-foreign-identity'. Do NOT trust event.requestContext.authorizer.principalId in handler code.` : `AWS_IAM authorizer: request signed with access-key-id '${parsed.credentialAccessKeyId}', a federated / Cognito Identity Pool / cross-account signer cdk-local cannot verify locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it because AWS holds the secret). Passing through with unverified principalId 'unverified-foreign-identity' — cdk-local's default for unverifiable IAM requests; pass
|
|
13063
|
+
logger.warn(opts.oacFronted ? `AWS_IAM authorizer: Function URL is fronted by CloudFront OAC — in production CloudFront re-signs the origin request, so the local client's signature (access-key-id '${parsed.credentialAccessKeyId}') cannot be verified. Passing through with unverified principalId 'unverified-foreign-identity'. Do NOT trust event.requestContext.authorizer.principalId in handler code.` : sigV4StrictByDefault ? `AWS_IAM authorizer: request signed with access-key-id '${parsed.credentialAccessKeyId}', a federated / Cognito Identity Pool / cross-account signer cdk-local cannot verify locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it because AWS holds the secret). ${optFlag} is set; passing through with unverified principalId 'unverified-foreign-identity'. Do NOT trust event.requestContext.authorizer.principalId in handler code.` : `AWS_IAM authorizer: request signed with access-key-id '${parsed.credentialAccessKeyId}', a federated / Cognito Identity Pool / cross-account signer cdk-local cannot verify locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it because AWS holds the secret). Passing through with unverified principalId 'unverified-foreign-identity' — cdk-local's default for unverifiable IAM requests; pass ${optFlag} to deny instead. Do NOT trust event.requestContext.authorizer.principalId in handler code.`);
|
|
13063
13064
|
warned?.add(dedupKey);
|
|
13064
13065
|
}
|
|
13065
13066
|
return {
|
|
@@ -14659,6 +14660,27 @@ function filterRoutesByApiIdentifier(routes, identifier) {
|
|
|
14659
14660
|
return routes.filter((rwa) => routeMatchesIdentifier(rwa.route, identifier));
|
|
14660
14661
|
}
|
|
14661
14662
|
/**
|
|
14663
|
+
* Filter the route list to the UNION of several user-supplied
|
|
14664
|
+
* identifiers — the variadic `cdkl start-api <target...>` shape, where
|
|
14665
|
+
* passing two or more API identifiers serves exactly that subset (each
|
|
14666
|
+
* on its own port, via {@link groupRoutesByServer}).
|
|
14667
|
+
*
|
|
14668
|
+
* A route is kept when it matches ANY of the identifiers (same matching
|
|
14669
|
+
* rules as {@link filterRoutesByApiIdentifier}). Output order is the
|
|
14670
|
+
* input route order, so {@link groupRoutesByServer}'s stable grouping is
|
|
14671
|
+
* preserved. An empty `identifiers` list returns every route unchanged
|
|
14672
|
+
* (the "serve all" default path never calls this with an empty set, but
|
|
14673
|
+
* the no-op behavior keeps the helper total).
|
|
14674
|
+
*
|
|
14675
|
+
* Returns an empty array when no route matches any identifier — the
|
|
14676
|
+
* caller surfaces a "no API matched" error with the available
|
|
14677
|
+
* identifiers (see {@link availableApiIdentifiers}).
|
|
14678
|
+
*/
|
|
14679
|
+
function filterRoutesByApiIdentifiers(routes, identifiers) {
|
|
14680
|
+
if (identifiers.length === 0) return [...routes];
|
|
14681
|
+
return routes.filter((rwa) => identifiers.some((id) => routeMatchesIdentifier(rwa.route, id)));
|
|
14682
|
+
}
|
|
14683
|
+
/**
|
|
14662
14684
|
* Predicate behind {@link filterRoutesByApiIdentifier} and
|
|
14663
14685
|
* {@link availableApiIdentifiers}'s primary-form selection. Exported
|
|
14664
14686
|
* for test coverage only — the production code path goes through
|
|
@@ -14948,20 +14970,20 @@ function createAuthorizerCache(opts = {}) {
|
|
|
14948
14970
|
|
|
14949
14971
|
//#endregion
|
|
14950
14972
|
//#region src/cli/commands/local-start-api.ts
|
|
14951
|
-
async function localStartApiCommand(
|
|
14973
|
+
async function localStartApiCommand(targets, options, extraStateProviders) {
|
|
14952
14974
|
const logger = getLogger();
|
|
14953
14975
|
if (options.verbose) logger.setLevel("debug");
|
|
14954
|
-
let
|
|
14976
|
+
let apiFilters = [...targets];
|
|
14955
14977
|
if (options.api !== void 0) {
|
|
14956
|
-
if (
|
|
14978
|
+
if (targets.length > 0) throw new Error(`Cannot specify both positional target(s) ([${targets.join(", ")}]) and --api flag ('${options.api}'). Use one or the other. The positional form is preferred — '--api' is a deprecated alias.`);
|
|
14957
14979
|
logger.warn(`[deprecated] --api <id> will be removed in a future major release. Use the positional argument instead: '${getEmbedConfig().cliName} start-api <id>'.`);
|
|
14958
|
-
|
|
14980
|
+
apiFilters = [options.api];
|
|
14959
14981
|
}
|
|
14960
|
-
|
|
14961
|
-
let
|
|
14982
|
+
const shouldPromptBare = shouldPromptBareMultiSelect(apiFilters, options.allStacks, isInteractive());
|
|
14983
|
+
let effectiveTargets = [...apiFilters];
|
|
14962
14984
|
const interactivePicked = { value: false };
|
|
14963
|
-
const allStacksConflictList = allStacksConflicts(options,
|
|
14964
|
-
if (allStacksConflictList.length > 0) throw new Error(`--all-stacks serves every stack's API and cannot be combined with a
|
|
14985
|
+
const allStacksConflictList = allStacksConflicts(options, targets, apiFilters);
|
|
14986
|
+
if (allStacksConflictList.length > 0) throw new Error(`--all-stacks serves every stack's API and cannot be combined with a target subset selector (${allStacksConflictList.join(", ")}). Drop --all-stacks to target specific APIs, or drop the selector to serve them all. The bare --from-cfn-stack flag (no value) IS compatible with --all-stacks.`);
|
|
14965
14987
|
warnIfDeprecatedRegion(options);
|
|
14966
14988
|
await applyRoleArnIfSet({
|
|
14967
14989
|
roleArn: options.roleArn,
|
|
@@ -14982,6 +15004,7 @@ async function localStartApiCommand(target, options, extraStateProviders) {
|
|
|
14982
15004
|
let sigV4CredentialsLoader;
|
|
14983
15005
|
const sigV4WarnedForeignIds = /* @__PURE__ */ new Set();
|
|
14984
15006
|
const fromCfnTipEmitted = { value: false };
|
|
15007
|
+
const unmatchedTargetWarned = /* @__PURE__ */ new Set();
|
|
14985
15008
|
/**
|
|
14986
15009
|
* One synth + discover + build pass. Returns the next-state
|
|
14987
15010
|
* material. Reused on initial boot AND every hot-reload firing.
|
|
@@ -15005,17 +15028,17 @@ async function localStartApiCommand(target, options, extraStateProviders) {
|
|
|
15005
15028
|
...Object.keys(context).length > 0 && { context }
|
|
15006
15029
|
};
|
|
15007
15030
|
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
15008
|
-
if (
|
|
15031
|
+
if (shouldPromptBare && !interactivePicked.value) {
|
|
15009
15032
|
const apis = listTargets(stacks).apis;
|
|
15010
15033
|
if (apis.length === 0) throw new Error(`No APIs found in this CDK app to choose from. Run \`${getEmbedConfig().cliName} list\` to see what is available.`);
|
|
15011
|
-
const picked = await
|
|
15012
|
-
|
|
15013
|
-
|
|
15034
|
+
const picked = await pickManyTargets("Select APIs to serve", apis, { preselectAll: true });
|
|
15035
|
+
apiFilters = picked;
|
|
15036
|
+
effectiveTargets = picked;
|
|
15014
15037
|
interactivePicked.value = true;
|
|
15015
15038
|
}
|
|
15016
15039
|
const cfnStackFallback = typeof options.fromCfnStack === "string" ? options.fromCfnStack : void 0;
|
|
15017
|
-
const targetStackPrefix =
|
|
15018
|
-
const targetStacks = pickTargetStacks(stacks, options.stack, cfnStackFallback, targetStackPrefix, options.allStacks);
|
|
15040
|
+
const targetStackPrefix = deriveSynthStackPrefix(effectiveTargets);
|
|
15041
|
+
const targetStacks = pickTargetStacks(stacks, options.stack, cfnStackFallback, targetStackPrefix, options.allStacks || shouldSynthAllStacks(effectiveTargets, options.stack, cfnStackFallback));
|
|
15019
15042
|
if (targetStacks.length === 0) throw new Error("No stacks matched. Pass --stack <name> (or --from-cfn-stack <name>) or run from a single-stack app.");
|
|
15020
15043
|
const routedStackNames = targetStacks.map((s) => s.stackName);
|
|
15021
15044
|
tryEmitFromCfnRedundancyTipOnce(options.fromCfnStack, routedStackNames, fromCfnTipEmitted, (routedStackName) => {
|
|
@@ -15041,12 +15064,15 @@ async function localStartApiCommand(target, options, extraStateProviders) {
|
|
|
15041
15064
|
}
|
|
15042
15065
|
attachStageContext(routes, stageMap);
|
|
15043
15066
|
let routesWithAuth = attachAuthorizers(targetStacks, routes);
|
|
15044
|
-
if (
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
if (filtered.length === 0) {
|
|
15067
|
+
if (apiFilters.length > 0) {
|
|
15068
|
+
const { filtered, unmatched } = resolveApiTargetSubset(routesWithAuth, apiFilters, targetStacks.map((s) => s.stackName));
|
|
15069
|
+
if (unmatched.length > 0) {
|
|
15048
15070
|
const available = availableApiIdentifiers(routesWithAuth).join(", ") || "(none)";
|
|
15049
|
-
|
|
15071
|
+
for (const id of unmatched) {
|
|
15072
|
+
if (unmatchedTargetWarned.has(id)) continue;
|
|
15073
|
+
unmatchedTargetWarned.add(id);
|
|
15074
|
+
logger.warn(`Target '${id}' did not match any discovered API; it is ignored. Available identifiers: ${available}.`);
|
|
15075
|
+
}
|
|
15050
15076
|
}
|
|
15051
15077
|
routesWithAuth = filtered;
|
|
15052
15078
|
}
|
|
@@ -15437,7 +15463,7 @@ function pickTargetStacks(stacks, pattern, cfnStackFallback, targetFallback, all
|
|
|
15437
15463
|
}
|
|
15438
15464
|
/**
|
|
15439
15465
|
* Issue #55: `--all-stacks` serves every stack's API as a union, so it
|
|
15440
|
-
* cannot be combined with a selector that names
|
|
15466
|
+
* cannot be combined with a selector that names a target subset.
|
|
15441
15467
|
* Returns the human-readable list of conflicting selectors (empty when
|
|
15442
15468
|
* `--all-stacks` is off or there is no conflict).
|
|
15443
15469
|
*
|
|
@@ -15451,31 +15477,121 @@ function pickTargetStacks(stacks, pattern, cfnStackFallback, targetFallback, all
|
|
|
15451
15477
|
*
|
|
15452
15478
|
* @internal exported for unit tests.
|
|
15453
15479
|
*/
|
|
15454
|
-
function allStacksConflicts(options,
|
|
15480
|
+
function allStacksConflicts(options, targets, apiFilters) {
|
|
15455
15481
|
if (!options.allStacks) return [];
|
|
15456
15482
|
const conflicts = [];
|
|
15457
|
-
if (
|
|
15483
|
+
if (apiFilters.length > 0) conflicts.push(targets.length > 0 ? `target(s) [${targets.join(", ")}]` : `--api '${options.api}'`);
|
|
15458
15484
|
if (options.stack !== void 0) conflicts.push(`--stack '${options.stack}'`);
|
|
15459
15485
|
if (typeof options.fromCfnStack === "string") conflicts.push(`--from-cfn-stack '${options.fromCfnStack}'`);
|
|
15460
15486
|
return conflicts;
|
|
15461
15487
|
}
|
|
15462
15488
|
/**
|
|
15463
|
-
*
|
|
15464
|
-
*
|
|
15465
|
-
*
|
|
15466
|
-
*
|
|
15467
|
-
*
|
|
15468
|
-
*
|
|
15489
|
+
* Resolve the variadic `cdkl start-api <target...>` subset against the
|
|
15490
|
+
* discovered route surface — the pure core of the subset-serving path.
|
|
15491
|
+
*
|
|
15492
|
+
* Behavior:
|
|
15493
|
+
* - Rejects a BARE logical id (no `:`, no `/`) when the app has more than
|
|
15494
|
+
* one stack: a bare id is ambiguous because two stacks can carry the
|
|
15495
|
+
* same logical id (mirrors `cdkl invoke` / `cdkl run-task`'s resolver).
|
|
15496
|
+
* THROWS with the disambiguation hint.
|
|
15497
|
+
* - Filters routes to the UNION of the identifiers via
|
|
15498
|
+
* {@link filterRoutesByApiIdentifiers}. THROWS when the union is empty
|
|
15499
|
+
* (no identifier matched anything), listing the available identifiers.
|
|
15500
|
+
* - Returns the surviving union in `filtered` and the identifiers that
|
|
15501
|
+
* matched nothing in `unmatched`. A single typo among valid ids keeps
|
|
15502
|
+
* the siblings in `filtered` and surfaces the typo via `unmatched`;
|
|
15503
|
+
* the caller is responsible for warning (so the warning can be gated
|
|
15504
|
+
* one-shot across `--watch` reloads — see the call site).
|
|
15505
|
+
*
|
|
15506
|
+
* `availableApiIdentifiers(routes)` is computed ONCE here (not per-id) so
|
|
15507
|
+
* the resolution is O(N·M) rather than O(N²·M).
|
|
15508
|
+
*
|
|
15509
|
+
* @internal exported for unit tests + library consumers (re-exported from
|
|
15510
|
+
* the package entry).
|
|
15511
|
+
*/
|
|
15512
|
+
function resolveApiTargetSubset(routes, identifiers, stackNames) {
|
|
15513
|
+
if (stackNames.length > 1) {
|
|
15514
|
+
for (const id of identifiers) if (!id.includes(":") && !id.includes("/")) throw new Error(`Multiple stacks in app, target '${id}' is missing a stack prefix. Use 'StackName:${id}' or 'StackName/${id}' (Construct path form). Available stacks: ${stackNames.join(", ")}.`);
|
|
15515
|
+
}
|
|
15516
|
+
const filtered = filterRoutesByApiIdentifiers(routes, identifiers);
|
|
15517
|
+
if (filtered.length === 0) {
|
|
15518
|
+
const available = availableApiIdentifiers(routes).join(", ") || "(none)";
|
|
15519
|
+
throw new Error(`Target(s) [${identifiers.join(", ")}] did not match any discovered API. Available identifiers: ${available}.`);
|
|
15520
|
+
}
|
|
15521
|
+
return {
|
|
15522
|
+
filtered,
|
|
15523
|
+
unmatched: identifiers.filter((id) => filterRoutesByApiIdentifiers(routes, [id]).length === 0)
|
|
15524
|
+
};
|
|
15525
|
+
}
|
|
15526
|
+
/**
|
|
15527
|
+
* Derive the single synth stack prefix shared by every supplied target,
|
|
15528
|
+
* for the synth-scope optimization (item 5 of the start-api subset UX).
|
|
15529
|
+
*
|
|
15530
|
+
* Each target's stack prefix is the segment before its first `/` (the
|
|
15531
|
+
* `<StackName>/<construct>` Construct-path form). Returns:
|
|
15532
|
+
* - `undefined` when `targets` is empty (serve-all path — no prefix).
|
|
15533
|
+
* - `undefined` when ANY target lacks a `/` (bare logical id — the synth
|
|
15534
|
+
* target can't be inferred from it, so fall back to the existing
|
|
15535
|
+
* single-stack auto-pick / multi-stack rejection path).
|
|
15536
|
+
* - `undefined` when targets span MORE THAN ONE distinct prefix (the
|
|
15537
|
+
* subset crosses stacks, so synth must cover all of them — see
|
|
15538
|
+
* {@link shouldSynthAllStacks}).
|
|
15539
|
+
* - the shared prefix when every target carries the SAME `<StackName>/`
|
|
15540
|
+
* prefix — keeping the single-stack synth optimization.
|
|
15541
|
+
*
|
|
15542
|
+
* @internal exported for unit tests.
|
|
15543
|
+
*/
|
|
15544
|
+
function deriveSynthStackPrefix(targets) {
|
|
15545
|
+
if (targets.length === 0) return void 0;
|
|
15546
|
+
const prefixes = /* @__PURE__ */ new Set();
|
|
15547
|
+
for (const t of targets) {
|
|
15548
|
+
const slash = t.indexOf("/");
|
|
15549
|
+
if (slash === -1) return void 0;
|
|
15550
|
+
prefixes.add(t.slice(0, slash));
|
|
15551
|
+
}
|
|
15552
|
+
return prefixes.size === 1 ? [...prefixes][0] : void 0;
|
|
15553
|
+
}
|
|
15554
|
+
/**
|
|
15555
|
+
* Decide whether synth should cover ALL stacks for the given target
|
|
15556
|
+
* subset (item 5). Synth is scoped to one stack only when a single stack
|
|
15557
|
+
* can be pinned; otherwise we synth every stack and the union is filtered
|
|
15558
|
+
* down by `apiFilters` afterwards.
|
|
15559
|
+
*
|
|
15560
|
+
* Returns `true` (synth all) when there ARE explicit targets but no
|
|
15561
|
+
* single stack can be pinned from them — i.e. `--stack` is unset, an
|
|
15562
|
+
* explicit `--from-cfn-stack <name>` is unset, AND
|
|
15563
|
+
* {@link deriveSynthStackPrefix} can't resolve one shared prefix (targets
|
|
15564
|
+
* span stacks, or any target is a bare logical id). Returns `false` when
|
|
15565
|
+
* there are no targets (serve-all already synths everything via the
|
|
15566
|
+
* regular path) or a stack is otherwise pinned.
|
|
15567
|
+
*
|
|
15568
|
+
* @internal exported for unit tests.
|
|
15569
|
+
*/
|
|
15570
|
+
function shouldSynthAllStacks(targets, stackPattern, cfnStackFallback) {
|
|
15571
|
+
if (targets.length === 0) return false;
|
|
15572
|
+
if (stackPattern !== void 0 || cfnStackFallback !== void 0) return false;
|
|
15573
|
+
return deriveSynthStackPrefix(targets) === void 0;
|
|
15574
|
+
}
|
|
15575
|
+
/**
|
|
15576
|
+
* Decide whether bare `start-api` should open the pre-selected-all
|
|
15577
|
+
* multi-select picker. The picker runs ONLY when:
|
|
15578
|
+
* - no explicit API subset was named (`apiFilters` empty — neither
|
|
15579
|
+
* positional `<targets...>` nor the deprecated `--api`),
|
|
15580
|
+
* - `--all-stacks` was not passed (that path already serves every API),
|
|
15581
|
+
* - AND stdin/stdout is a TTY.
|
|
15582
|
+
*
|
|
15583
|
+
* In a non-TTY (CI / pipe) this returns `false`, and the caller serves
|
|
15584
|
+
* EVERY discovered API without prompting — start-api's one intentional
|
|
15585
|
+
* asymmetry vs invoke / run-task (which error when bare in a non-TTY),
|
|
15586
|
+
* because start-api legitimately has a "serve all" default.
|
|
15469
15587
|
*
|
|
15470
|
-
* Extracted as a pure
|
|
15471
|
-
*
|
|
15588
|
+
* Extracted as a pure function (TTY is passed in) so the decision is
|
|
15589
|
+
* unit-testable without booting the server or juggling global TTY state.
|
|
15472
15590
|
*
|
|
15473
15591
|
* @internal exported for unit tests.
|
|
15474
15592
|
*/
|
|
15475
|
-
function
|
|
15476
|
-
|
|
15477
|
-
if (apiFilter !== void 0 || allStacks) throw new Error("`-i/--interactive` cannot be combined with a positional target, --api, or --all-stacks; it interactively picks one API to serve. Drop the selector, or drop -i.");
|
|
15478
|
-
if (!isInteractive()) throw new InteractiveTtyRequiredError("`-i/--interactive` requires an interactive terminal, but stdin/stdout is not a TTY.");
|
|
15593
|
+
function shouldPromptBareMultiSelect(apiFilters, allStacks, isTty) {
|
|
15594
|
+
return apiFilters.length === 0 && !allStacks && isTty;
|
|
15479
15595
|
}
|
|
15480
15596
|
/**
|
|
15481
15597
|
* Decide whether the `--from-cfn-stack <name>` redundancy tip should
|
|
@@ -16563,15 +16679,14 @@ function resolveMtlsConfig(options) {
|
|
|
16563
16679
|
*/
|
|
16564
16680
|
function createLocalStartApiCommand(opts = {}) {
|
|
16565
16681
|
setEmbedConfig(opts.embedConfig);
|
|
16566
|
-
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). 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("[
|
|
16567
|
-
await localStartApiCommand(
|
|
16682
|
+
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). 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("[targets...]", `Optional API subset filter. Pass one or more identifiers to serve exactly that subset (the union; each on its own port). Each 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 in a TTY, a multi-select picker opens with every API pre-selected (Enter serves all, deselect to pick a subset); when omitted in a non-TTY (CI / pipe) every discovered API is served. Mirrors \`${getEmbedConfig().cliName} invoke\` / \`${getEmbedConfig().cliName} 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("--all-stacks", "Serve every stack's API in a multi-stack app (each API on its own port) instead of erroring out. Mutually exclusive with a positional target subset, --stack, and an explicit --from-cfn-stack <name>; the bare --from-cfn-stack flag stays compatible (binds each routed stack to its own CFn stack).").default(false)).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 the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). 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 <targets...> argument instead. Accepts a SINGLE identifier; for a subset pass multiple positional targets. 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-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources 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 resolved stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).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=${getEmbedConfig().resourceNamePrefix}-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("--strict-sigv4", "Opt-in: DENY AWS_IAM SigV4 requests that cannot be cryptographically verified (foreign access-key-id — e.g. a federated / Cognito Identity Pool / cross-account signer — OR no local AWS credentials configured) instead of the default warn-and-pass. DEFAULT off: cdk-local warn-and-passes unverifiable IAM requests with a placeholder principalId so local dev exercises app logic without reproducing an auth boundary it cannot fully emulate. OAC-fronted Function URLs always warn-and-pass regardless.").default(false)).action(withErrorHandling(async (targets, options) => {
|
|
16683
|
+
await localStartApiCommand(targets, options, opts.extraStateProviders);
|
|
16568
16684
|
}));
|
|
16569
16685
|
[
|
|
16570
16686
|
...commonOptions(),
|
|
16571
16687
|
...appOptions(),
|
|
16572
16688
|
...contextOptions
|
|
16573
16689
|
].forEach((opt) => startApi.addOption(opt));
|
|
16574
|
-
startApi.addOption(interactiveOption);
|
|
16575
16690
|
startApi.addOption(deprecatedRegionOption);
|
|
16576
16691
|
return startApi;
|
|
16577
16692
|
}
|
|
@@ -17627,11 +17742,10 @@ async function localRunTaskCommand(target, options, extraStateProviders) {
|
|
|
17627
17742
|
};
|
|
17628
17743
|
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
17629
17744
|
const resolvedTarget = await resolveSingleTarget(target, {
|
|
17630
|
-
interactive: options.interactive,
|
|
17631
17745
|
entries: listTargets(stacks).ecsTaskDefinitions,
|
|
17632
17746
|
message: "Select an ECS task definition to run",
|
|
17633
17747
|
noun: "ECS task definitions",
|
|
17634
|
-
onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} run-task requires a <target> (an ECS task definition display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or
|
|
17748
|
+
onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} run-task requires a <target> (an ECS task definition display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or run it in a TTY to pick interactively.`, "LOCAL_RUN_TASK_TARGET_REQUIRED")
|
|
17635
17749
|
});
|
|
17636
17750
|
const candidate = pickCandidateStack$1(parseEcsTarget(resolvedTarget).stackPattern, stacks);
|
|
17637
17751
|
stateProvider = createLocalStateProvider(options, candidate?.stackName ?? "", await resolveCfnFallbackRegion(options, candidate?.region), extraStateProviders);
|
|
@@ -17858,7 +17972,7 @@ async function resolveSidecarCredentials(options, assumedCredentials) {
|
|
|
17858
17972
|
}
|
|
17859
17973
|
function createLocalRunTaskCommand(opts = {}) {
|
|
17860
17974
|
setEmbedConfig(opts.embedConfig);
|
|
17861
|
-
const cmd = new Command("run-task").description("Run an AWS::ECS::TaskDefinition locally — pulls/builds images, sets up a per-task docker network with the AWS-published metadata-endpoints sidecar, and starts every container in dependsOn order. Target accepts a CDK display path (MyStack/MyService/TaskDef) or stack-qualified logical ID (MyStack:MyServiceTaskDefXYZ1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal
|
|
17975
|
+
const cmd = new Command("run-task").description("Run an AWS::ECS::TaskDefinition locally — pulls/builds images, sets up a per-task docker network with the AWS-published metadata-endpoints sidecar, and starts every container in dependsOn order. Target accepts a CDK display path (MyStack/MyService/TaskDef) or stack-qualified logical ID (MyStack:MyServiceTaskDefXYZ1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick the task definition from a list.").argument("[target]", "CDK display path or stack-qualified logical ID of the AWS::ECS::TaskDefinition to run (omit to pick interactively in a TTY)").addOption(new Option("--cluster <name>", "Cluster name surfaced to ECS_CONTAINER_METADATA_URI_V4 and used as the docker network prefix").default(getEmbedConfig().resourceNamePrefix)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"ContainerName\":{\"KEY\":\"VALUE\"}, \"Parameters\":{}})")).addOption(new Option("--container-host <ip>", "Host IP to bind published container ports to. Must be a numeric IP (Docker rejects hostnames here)").default("127.0.0.1")).addOption(new Option("--host-port <containerPort=hostPort...>", "Publish a container port on a specific host port (e.g. 80=8080); repeatable. Default: host port == container port. Use this on macOS to map a privileged container port (< 1024) to a non-privileged host port and avoid the Docker Desktop admin-password prompt.")).addOption(new Option("--assume-task-role [arn]", "Assume the task definition's TaskRoleArn (or the supplied ARN) and forward STS-issued temp credentials via the metadata sidecar so containers run with the deployed function role. Bare flag uses the template's TaskRoleArn; pass an explicit ARN to override.")).addOption(new Option("--no-pull", "Skip docker pull for every container image and the metadata sidecar")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--platform <platform>", "Force docker --platform (linux/amd64 or linux/arm64). Default: inferred from task RuntimePlatform.CpuArchitecture")).addOption(new Option("--keep-running", "Don't docker rm -f the user containers on task exit (network + sidecar are still torn down). Use when you want to docker exec into a stopped container for post-mortems.").default(false)).addOption(new Option("--detach", "Start the containers in the background and exit (skip log streaming + auto teardown). Useful in CI smoke tests; caller manages container lifecycle.").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", `Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in container env vars / secrets / image URIs with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (\`cdk deploy\`). Bare form uses the ${getEmbedConfig().binaryName} stack name; pass an explicit value when the CFn stack name differs. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).`)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).action(withErrorHandling(async (target, options) => {
|
|
17862
17976
|
await localRunTaskCommand(target, options, opts.extraStateProviders);
|
|
17863
17977
|
}));
|
|
17864
17978
|
[
|
|
@@ -17866,7 +17980,6 @@ function createLocalRunTaskCommand(opts = {}) {
|
|
|
17866
17980
|
...appOptions(),
|
|
17867
17981
|
...contextOptions
|
|
17868
17982
|
].forEach((opt) => cmd.addOption(opt));
|
|
17869
|
-
cmd.addOption(interactiveOption);
|
|
17870
17983
|
cmd.addOption(deprecatedRegionOption);
|
|
17871
17984
|
return cmd;
|
|
17872
17985
|
}
|
|
@@ -18604,7 +18717,7 @@ function pickEssentialContainerId(instance, service) {
|
|
|
18604
18717
|
const defaultWaitForExitImpl = async (containerId) => {
|
|
18605
18718
|
const { execFile } = await import("node:child_process");
|
|
18606
18719
|
const { promisify } = await import("node:util");
|
|
18607
|
-
const { getDockerCmd } = await import("./docker-cmd
|
|
18720
|
+
const { getDockerCmd } = await import("./docker-cmd--8TRSn9z.js").then((n) => n.t);
|
|
18608
18721
|
const { stdout } = await promisify(execFile)(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
|
|
18609
18722
|
const code = parseInt(stdout.trim(), 10);
|
|
18610
18723
|
return Number.isFinite(code) ? code : -1;
|
|
@@ -18624,7 +18737,7 @@ const EXIT_LOG_TAIL_LINES = 50;
|
|
|
18624
18737
|
const defaultReadContainerLogsImpl = async (containerId) => {
|
|
18625
18738
|
const { execFile } = await import("node:child_process");
|
|
18626
18739
|
const { promisify } = await import("node:util");
|
|
18627
|
-
const { getDockerCmd } = await import("./docker-cmd
|
|
18740
|
+
const { getDockerCmd } = await import("./docker-cmd--8TRSn9z.js").then((n) => n.t);
|
|
18628
18741
|
const { stdout, stderr } = await promisify(execFile)(getDockerCmd(), [
|
|
18629
18742
|
"logs",
|
|
18630
18743
|
"--tail",
|
|
@@ -19040,11 +19153,10 @@ async function localStartServiceCommand(targets, options, extraStateProviders) {
|
|
|
19040
19153
|
};
|
|
19041
19154
|
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
19042
19155
|
const resolvedTargets = await resolveMultiTarget(targets, {
|
|
19043
|
-
interactive: options.interactive,
|
|
19044
19156
|
entries: listTargets(stacks).ecsServices,
|
|
19045
19157
|
message: "Select one or more ECS services to run",
|
|
19046
19158
|
noun: "ECS services",
|
|
19047
|
-
onMissing: () => new LocalStartServiceError(`${getEmbedConfig().cliName} start-service requires at least one <target>. Pass one or more service paths like 'Stack/Orders' 'Stack/Frontend', or run it in a TTY
|
|
19159
|
+
onMissing: () => new LocalStartServiceError(`${getEmbedConfig().cliName} start-service requires at least one <target>. Pass one or more service paths like 'Stack/Orders' 'Stack/Frontend', or run it in a TTY to pick interactively.`)
|
|
19048
19160
|
});
|
|
19049
19161
|
rejectExplicitCfnStackWithMultipleStacks(options, resolvedTargets.length);
|
|
19050
19162
|
perTarget = resolvedTargets.map((t) => ({
|
|
@@ -19336,7 +19448,7 @@ async function resolveSharedSidecarCredentials(options) {
|
|
|
19336
19448
|
}
|
|
19337
19449
|
function createLocalStartServiceCommand(opts = {}) {
|
|
19338
19450
|
setEmbedConfig(opts.embedConfig);
|
|
19339
|
-
const cmd = new Command("start-service").description(`Run one or more AWS::ECS::Service resources locally as a long-running emulator. Spins up DesiredCount task replicas per service (clamped by --max-tasks) using the same per-task docker network + metadata sidecar pattern as \`${getEmbedConfig().cliName} run-task\`, then keeps each replica running and restarts it on exit per --restart-policy. ^C tears every replica + sidecar + network down. Each <target> accepts a CDK display path (MyStack/MyService) or stack-qualified logical ID (MyStack:MyServiceXYZ); single-stack apps may omit the stack prefix. When two or more <target>s are supplied, every service is booted into a shared Cloud Map / Service Connect registry so peer services discover each other via docker --add-host overlay. Omit <targets> in an interactive terminal
|
|
19451
|
+
const cmd = new Command("start-service").description(`Run one or more AWS::ECS::Service resources locally as a long-running emulator. Spins up DesiredCount task replicas per service (clamped by --max-tasks) using the same per-task docker network + metadata sidecar pattern as \`${getEmbedConfig().cliName} run-task\`, then keeps each replica running and restarts it on exit per --restart-policy. ^C tears every replica + sidecar + network down. Each <target> accepts a CDK display path (MyStack/MyService) or stack-qualified logical ID (MyStack:MyServiceXYZ); single-stack apps may omit the stack prefix. When two or more <target>s are supplied, every service is booted into a shared Cloud Map / Service Connect registry so peer services discover each other via docker --add-host overlay. Omit <targets> in an interactive terminal to multi-select the services from a list.`).argument("[targets...]", "One or more CDK display paths or stack-qualified logical IDs of the AWS::ECS::Service resources to run (omit to multi-select interactively in a TTY)").addOption(new Option("--cluster <name>", "Cluster name surfaced to ECS_CONTAINER_METADATA_URI_V4 and used as the docker network prefix").default(getEmbedConfig().resourceNamePrefix)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"ContainerName\":{\"KEY\":\"VALUE\"}, \"Parameters\":{}})")).addOption(new Option("--container-host <ip>", "Host IP to bind published container ports to. Must be a numeric IP (Docker rejects hostnames here)").default("127.0.0.1")).addOption(new Option("--host-port <containerPort=hostPort...>", "Publish a container port on a specific host port (e.g. 80=8080); repeatable. Default: host port == container port. Use this on macOS to map a privileged container port (< 1024) to a non-privileged host port and avoid the Docker Desktop admin-password prompt. (Single-replica services only — multi-replica services do not publish host ports.)")).addOption(new Option("--assume-task-role [arn]", "Assume the task definition's TaskRoleArn (or the supplied ARN) and forward STS-issued temp credentials via the metadata sidecar so containers run with the deployed task role. Bare flag uses the template's TaskRoleArn; pass an explicit ARN to override.")).addOption(new Option("--no-pull", "Skip docker pull for every container image and the metadata sidecar")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries.")).addOption(new Option("--platform <platform>", "Force docker --platform (linux/amd64 or linux/arm64). Default: inferred from task RuntimePlatform.CpuArchitecture")).addOption(new Option("--max-tasks <n>", `Hard cap on local replica count. Caps the template DesiredCount so local dev machines don't run an unbounded number of containers. Cannot exceed ${83} due to the per-replica link-local /24 subnet allocator's range.`).default(3).argParser(parseMaxTasks)).addOption(new Option("--restart-policy <policy>", "How to react when an essential container exits. 'on-failure' (default) restarts only on non-zero exit; 'always' restarts on every exit; 'none' shuts the replica down and runs the service degraded.").default("on-failure").argParser(parseRestartPolicy)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", `Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in container env vars / secrets / image URIs with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (\`cdk deploy\`). Bare form uses the ${getEmbedConfig().binaryName} stack name; pass an explicit value when the CFn stack name differs. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).`)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).action(withErrorHandling(async (targets, options) => {
|
|
19340
19452
|
await localStartServiceCommand(targets, options, opts.extraStateProviders);
|
|
19341
19453
|
}));
|
|
19342
19454
|
[
|
|
@@ -19344,7 +19456,6 @@ function createLocalStartServiceCommand(opts = {}) {
|
|
|
19344
19456
|
...appOptions(),
|
|
19345
19457
|
...contextOptions
|
|
19346
19458
|
].forEach((opt) => cmd.addOption(opt));
|
|
19347
|
-
cmd.addOption(interactiveOption);
|
|
19348
19459
|
cmd.addOption(deprecatedRegionOption);
|
|
19349
19460
|
return cmd;
|
|
19350
19461
|
}
|
|
@@ -19388,7 +19499,7 @@ function formatTargetListing(listing, cliName, options = {}) {
|
|
|
19388
19499
|
const long = options.long ?? false;
|
|
19389
19500
|
return "\n" + [
|
|
19390
19501
|
formatSection("Lambda Functions", `${cliName} invoke <target>`, listing.lambdas, long),
|
|
19391
|
-
formatSection("APIs", `${cliName} start-api [target]`, listing.apis, long),
|
|
19502
|
+
formatSection("APIs", `${cliName} start-api [target...]`, listing.apis, long),
|
|
19392
19503
|
formatSection("ECS Services", `${cliName} start-service <target...>`, listing.ecsServices, long),
|
|
19393
19504
|
formatSection("ECS Task Definitions", `${cliName} run-task <target>`, listing.ecsTaskDefinitions, long)
|
|
19394
19505
|
].filter((lines) => lines.length > 0).map((lines) => lines.join("\n")).join("\n\n");
|
|
@@ -19398,14 +19509,14 @@ function formatSection(title, command, entries, long) {
|
|
|
19398
19509
|
const lines = [`${title} -> ${command}`];
|
|
19399
19510
|
for (const entry of entries) {
|
|
19400
19511
|
const primary = entry.displayPath ?? entry.qualifiedId;
|
|
19401
|
-
lines.push(` ${primary}`);
|
|
19512
|
+
lines.push(entry.kind ? ` ${primary} (${entry.kind})` : ` ${primary}`);
|
|
19402
19513
|
if (long && entry.displayPath) lines.push(` ${entry.qualifiedId}`);
|
|
19403
19514
|
}
|
|
19404
19515
|
return lines;
|
|
19405
19516
|
}
|
|
19406
19517
|
function createLocalListCommand(opts = {}) {
|
|
19407
19518
|
setEmbedConfig(opts.embedConfig);
|
|
19408
|
-
const cmd = new Command("list").alias("ls").description("List the runnable targets in the synthesized CDK app, grouped by the command that runs them: Lambda functions (invoke), API Gateway REST v1 / HTTP v2 / Function URL / WebSocket surfaces (start-api), ECS services (start-service), and ECS task definitions (run-task). Each target is shown by its CDK display path; pass -l to also print the stack-qualified logical ID. Tip: you usually do not need to copy these — just run the command (e.g. `invoke`) and pick from the list
|
|
19519
|
+
const cmd = new Command("list").alias("ls").description("List the runnable targets in the synthesized CDK app, grouped by the command that runs them: Lambda functions (invoke), API Gateway REST v1 / HTTP v2 / Function URL / WebSocket surfaces (start-api), ECS services (start-service), and ECS task definitions (run-task). Each target is shown by its CDK display path; pass -l to also print the stack-qualified logical ID. Tip: you usually do not need to copy these — just run the command (e.g. `invoke`) with no target in a terminal and pick from the list.").addOption(new Option("-l, --long", "Also print each target's stack-qualified logical ID (<Stack>:<LogicalId>) beneath it").default(false)).action(withErrorHandling(async (options) => {
|
|
19409
19520
|
await localListCommand(options);
|
|
19410
19521
|
}));
|
|
19411
19522
|
[
|
|
@@ -19418,5 +19529,5 @@ function createLocalListCommand(opts = {}) {
|
|
|
19418
19529
|
}
|
|
19419
19530
|
|
|
19420
19531
|
//#endregion
|
|
19421
|
-
export {
|
|
19422
|
-
//# sourceMappingURL=local-list-
|
|
19532
|
+
export { handleConnectionsRequest as $, invokeRequestAuthorizer as A, discoverWebSocketApis as At, applyAuthorizerOverlay as B, buildJwksUrlFromIssuer as C, resolveCfnRegion as Ct, buildMethodArn as D, resolveSsmParameters as Dt, verifyJwtAuthorizer as E, collectSsmParameterRefs as Et, buildCorsConfigFromCloudFrontChain as F, resolveLambdaArnIntrinsic as Ft, selectIntegrationResponse as G, buildRestV1Event as H, isFunctionUrlOacFronted as I, HOST_GATEWAY_MIN_VERSION as J, tryParseStatus as K, matchPreflight as L, attachAuthorizers as M, parseSelectionExpressionPath as Mt, applyCorsResponseHeaders as N, discoverRoutes as Nt, computeRequestIdentityHash as O, countTargets as Ot, buildCorsConfigByApiId as P, pickRefLogicalId as Pt, buildMgmtEndpointEnvUrl as Q, matchRoute as R, buildCognitoJwksUrl as S, resolveCfnFallbackRegion as St, verifyCognitoJwt as T, CfnLocalStateProvider as Tt, evaluateResponseParameters as U, buildHttpApiV2Event as V, pickResponseTemplate as W, bufferToBody as X, probeHostGatewaySupport as Y, ConnectionRegistry as Z, readMtlsMaterialsFromDisk as _, tryResolveImageFnJoin as _t, CloudMapRegistry as a, resolveRuntimeCodeMountPath as at, resolveServiceIntegrationParameters as b, isCfnFlagPresent as bt, createLocalStartApiCommand as c, EcsTaskResolutionError as ct, attachStageContext as d, substituteEnvVarsFromState as dt, parseConnectionsPath as et, buildStageMap as f, substituteEnvVarsFromStateAsync as ft, groupRoutesByServer as g, substituteImagePlaceholders as gt, filterRoutesByApiIdentifiers as h, derivePseudoParametersFromRegion as ht, buildCloudMapIndex as i, createLocalInvokeCommand as it, invokeTokenAuthorizer as j, discoverWebSocketApisOrThrow as jt, evaluateCachedLambdaPolicy as k, listTargets as kt, resolveApiTargetSubset as l, substituteAgainstState as lt, filterRoutesByApiIdentifier as m, materializeLayerFromArn as mt, formatTargetListing as n, buildDisconnectEvent as nt, getContainerNetworkIp as o, resolveRuntimeFileExtension as ot, availableApiIdentifiers as p, resolveEnvVars as pt, VtlEvaluationError as q, createLocalStartServiceCommand as r, buildMessageEvent as rt, createLocalRunTaskCommand as s, resolveRuntimeImage as st, createLocalListCommand as t, buildConnectEvent as tt, createAuthorizerCache as u, substituteAgainstStateAsync as ut, startApiServer as v, LocalStateSourceError as vt, createJwksCache as w, resolveCfnStackName as wt, defaultCredentialsLoader as x, rejectExplicitCfnStackWithMultipleStacks as xt, resolveSelectionExpression as y, createLocalStateProvider as yt, translateLambdaResponse as z };
|
|
19533
|
+
//# sourceMappingURL=local-list-DdmjsVLF.js.map
|