cdk-local 0.154.0 → 0.155.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 +4 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/internal.d.ts +214 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-CJfNARFz.js → local-studio-CsftJJ1r.js} +857 -68
- package/dist/local-studio-CsftJJ1r.js.map +1 -0
- package/dist/{local-studio-DDFmguSG.d.ts → local-studio-D5Ycx74D.d.ts} +12 -2
- package/dist/local-studio-D5Ycx74D.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/local-studio-CJfNARFz.js.map +0 -1
- package/dist/local-studio-DDFmguSG.d.ts.map +0 -1
|
@@ -30,7 +30,7 @@ import { StringDecoder } from "node:string_decoder";
|
|
|
30
30
|
import { promisify } from "node:util";
|
|
31
31
|
import { ECRClient, GetAuthorizationTokenCommand } from "@aws-sdk/client-ecr";
|
|
32
32
|
import { readFile } from "fs/promises";
|
|
33
|
-
import { basename as basename$1, dirname as dirname$1, join as join$1 } from "path";
|
|
33
|
+
import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, posix, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
|
|
34
34
|
import { WebSocket, WebSocketServer } from "ws";
|
|
35
35
|
import { Readable } from "node:stream";
|
|
36
36
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
@@ -46,6 +46,10 @@ import * as vm from "node:vm";
|
|
|
46
46
|
import "@aws-sdk/signature-v4a";
|
|
47
47
|
import { CloudFrontClient, paginateListKeyValueStores } from "@aws-sdk/client-cloudfront";
|
|
48
48
|
import { CloudFrontKeyValueStoreClient, GetKeyCommand, ResourceNotFoundException } from "@aws-sdk/client-cloudfront-keyvaluestore";
|
|
49
|
+
import { existsSync as existsSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
|
|
50
|
+
import { request as request$2 } from "http";
|
|
51
|
+
import { execFile as execFile$1, spawn as spawn$1 } from "child_process";
|
|
52
|
+
import { promisify as promisify$1 } from "util";
|
|
49
53
|
import { EventEmitter } from "node:events";
|
|
50
54
|
|
|
51
55
|
//#region src/utils/url-authority.ts
|
|
@@ -1595,14 +1599,14 @@ function parseTarget(target) {
|
|
|
1595
1599
|
function resolveLambdaTarget(target, stacks) {
|
|
1596
1600
|
if (stacks.length === 0) throw new LocalInvokeResolutionError("No stacks found in the synthesized assembly.");
|
|
1597
1601
|
const parsed = parseTarget(target);
|
|
1598
|
-
const stack = pickStack$
|
|
1602
|
+
const stack = pickStack$6(parsed, stacks, target);
|
|
1599
1603
|
const template = stack.template;
|
|
1600
1604
|
const resources = template.Resources ?? {};
|
|
1601
1605
|
let match;
|
|
1602
1606
|
if (parsed.isPath) {
|
|
1603
1607
|
const index = buildCdkPathIndex(template);
|
|
1604
1608
|
const lambdaMatches = resolveCdkPathToLogicalIds(parsed.pathOrId, index).filter(({ logicalId }) => resources[logicalId]?.Type === "AWS::Lambda::Function");
|
|
1605
|
-
if (lambdaMatches.length === 0) throw notFoundError$
|
|
1609
|
+
if (lambdaMatches.length === 0) throw notFoundError$4(target, stack, resources);
|
|
1606
1610
|
if (lambdaMatches.length > 1) throw new LocalInvokeResolutionError(`Target '${target}' matches ${lambdaMatches.length} Lambda functions in ${displayStackName(stack.stackName)}: ` + lambdaMatches.map((m) => displayIdent(m.logicalId, { listMember: true })).join(", ") + ". Refine the path or use the stack:LogicalId form.");
|
|
1607
1611
|
const m = lambdaMatches[0];
|
|
1608
1612
|
match = {
|
|
@@ -1611,7 +1615,7 @@ function resolveLambdaTarget(target, stacks) {
|
|
|
1611
1615
|
};
|
|
1612
1616
|
} else {
|
|
1613
1617
|
const resource = resources[parsed.pathOrId];
|
|
1614
|
-
if (!resource) throw notFoundError$
|
|
1618
|
+
if (!resource) throw notFoundError$4(target, stack, resources);
|
|
1615
1619
|
match = {
|
|
1616
1620
|
logicalId: parsed.pathOrId,
|
|
1617
1621
|
resource
|
|
@@ -1624,7 +1628,7 @@ function resolveLambdaTarget(target, stacks) {
|
|
|
1624
1628
|
}
|
|
1625
1629
|
return extractLambdaProperties(stack, logicalId, resource, resources);
|
|
1626
1630
|
}
|
|
1627
|
-
function pickStack$
|
|
1631
|
+
function pickStack$6(parsed, stacks, target) {
|
|
1628
1632
|
const selection = selectTargetStack(parsed, target, stacks);
|
|
1629
1633
|
switch (selection.kind) {
|
|
1630
1634
|
case "found": return selection.stack;
|
|
@@ -1957,7 +1961,7 @@ function describeLayerEntry(entry) {
|
|
|
1957
1961
|
return Object.prototype.toString.call(entry);
|
|
1958
1962
|
}
|
|
1959
1963
|
}
|
|
1960
|
-
function notFoundError$
|
|
1964
|
+
function notFoundError$4(target, stack, resources) {
|
|
1961
1965
|
const lambdas = [];
|
|
1962
1966
|
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
1963
1967
|
if (resource.Type !== "AWS::Lambda::Function") continue;
|
|
@@ -2002,7 +2006,7 @@ var AgentCoreResolutionError = class AgentCoreResolutionError extends Error {
|
|
|
2002
2006
|
function resolveAgentCoreTarget(target, stacks, imageContext) {
|
|
2003
2007
|
if (stacks.length === 0) throw new AgentCoreResolutionError("No stacks found in the synthesized assembly.");
|
|
2004
2008
|
const parsed = parseTarget(target);
|
|
2005
|
-
const stack = pickStack$
|
|
2009
|
+
const stack = pickStack$5(parsed, stacks, target);
|
|
2006
2010
|
const resources = stack.template.Resources ?? {};
|
|
2007
2011
|
const { logicalId, resource } = matchRuntime(parsed, target, stack, resources);
|
|
2008
2012
|
if (resource.Type !== "AWS::BedrockAgentCore::Runtime") throw new AgentCoreResolutionError(`Resource ${displayIdent(logicalId)} in ${stack.stackName} is ${resource.Type}, not ${AGENTCORE_RUNTIME_TYPE}. ${getEmbedConfig().cliName} invoke-agentcore only runs Bedrock AgentCore Runtime resources.`);
|
|
@@ -2011,7 +2015,7 @@ function resolveAgentCoreTarget(target, stacks, imageContext) {
|
|
|
2011
2015
|
function pickAgentCoreCandidateStack(target, stacks) {
|
|
2012
2016
|
return candidateTargetStack(parseTarget(target), target, stacks);
|
|
2013
2017
|
}
|
|
2014
|
-
function pickStack$
|
|
2018
|
+
function pickStack$5(parsed, stacks, target) {
|
|
2015
2019
|
const selection = selectTargetStack(parsed, target, stacks);
|
|
2016
2020
|
switch (selection.kind) {
|
|
2017
2021
|
case "found": return selection.stack;
|
|
@@ -2024,7 +2028,7 @@ function matchRuntime(parsed, target, stack, resources) {
|
|
|
2024
2028
|
if (parsed.isPath) {
|
|
2025
2029
|
const index = buildCdkPathIndex(stack.template);
|
|
2026
2030
|
const runtimeMatches = resolveCdkPathToLogicalIds(parsed.pathOrId, index).filter(({ logicalId }) => resources[logicalId]?.Type === AGENTCORE_RUNTIME_TYPE);
|
|
2027
|
-
if (runtimeMatches.length === 0) throw notFoundError$
|
|
2031
|
+
if (runtimeMatches.length === 0) throw notFoundError$3(target, stack, resources);
|
|
2028
2032
|
if (runtimeMatches.length > 1) throw new AgentCoreResolutionError(`Target '${target}' matches ${runtimeMatches.length} AgentCore Runtimes in ${stack.stackName}: ` + runtimeMatches.map((m) => m.logicalId).join(", ") + ". Refine the path or use the stack:LogicalId form.");
|
|
2029
2033
|
const m = runtimeMatches[0];
|
|
2030
2034
|
return {
|
|
@@ -2033,13 +2037,13 @@ function matchRuntime(parsed, target, stack, resources) {
|
|
|
2033
2037
|
};
|
|
2034
2038
|
}
|
|
2035
2039
|
const resource = resources[parsed.pathOrId];
|
|
2036
|
-
if (!resource) throw notFoundError$
|
|
2040
|
+
if (!resource) throw notFoundError$3(target, stack, resources);
|
|
2037
2041
|
return {
|
|
2038
2042
|
logicalId: parsed.pathOrId,
|
|
2039
2043
|
resource
|
|
2040
2044
|
};
|
|
2041
2045
|
}
|
|
2042
|
-
function notFoundError$
|
|
2046
|
+
function notFoundError$3(target, stack, resources) {
|
|
2043
2047
|
const available = Object.entries(resources).filter(([, r]) => r.Type === AGENTCORE_RUNTIME_TYPE).map(([id]) => id);
|
|
2044
2048
|
const hint = available.length > 0 ? `Available AgentCore Runtimes in ${stack.stackName}: ${available.join(", ")}.` : `No ${AGENTCORE_RUNTIME_TYPE} resources found in ${stack.stackName}.`;
|
|
2045
2049
|
return new AgentCoreResolutionError(`Target '${target}' not found. ${hint}`);
|
|
@@ -3531,7 +3535,8 @@ function listTargets(stacks) {
|
|
|
3531
3535
|
ecsTaskDefinitions: sortEntries(scanByType(stacks, "AWS::ECS::TaskDefinition")),
|
|
3532
3536
|
agentCoreRuntimes: sortEntries(scanAgentCoreRuntimes(stacks)),
|
|
3533
3537
|
loadBalancers: sortEntries(scanApplicationLoadBalancers(stacks)),
|
|
3534
|
-
cloudFrontDistributions: sortEntries(scanByType(stacks, "AWS::CloudFront::Distribution"))
|
|
3538
|
+
cloudFrontDistributions: sortEntries(scanByType(stacks, "AWS::CloudFront::Distribution")),
|
|
3539
|
+
webFunctions: sortEntries(scanByType(stacks, "AWS::Lambda::WebFunction"))
|
|
3535
3540
|
};
|
|
3536
3541
|
}
|
|
3537
3542
|
const pathOf$1 = (e) => e.displayPath ?? e.qualifiedId;
|
|
@@ -3554,7 +3559,7 @@ function sortApiEntries(entries) {
|
|
|
3554
3559
|
});
|
|
3555
3560
|
}
|
|
3556
3561
|
function countTargets(listing) {
|
|
3557
|
-
return listing.lambdas.length + listing.apis.length + listing.ecsServices.length + listing.ecsTaskDefinitions.length + listing.agentCoreRuntimes.length + listing.loadBalancers.length + listing.cloudFrontDistributions.length;
|
|
3562
|
+
return listing.lambdas.length + listing.apis.length + listing.ecsServices.length + listing.ecsTaskDefinitions.length + listing.agentCoreRuntimes.length + listing.loadBalancers.length + listing.cloudFrontDistributions.length + listing.webFunctions.length;
|
|
3558
3563
|
}
|
|
3559
3564
|
|
|
3560
3565
|
//#endregion
|
|
@@ -5095,28 +5100,28 @@ function parseEcsTarget(target) {
|
|
|
5095
5100
|
function resolveEcsTaskTarget(target, stacks, context) {
|
|
5096
5101
|
if (stacks.length === 0) throw new EcsTaskResolutionError("No stacks found in the synthesized assembly.");
|
|
5097
5102
|
const parsed = parseEcsTarget(target);
|
|
5098
|
-
const stack = pickStack$
|
|
5103
|
+
const stack = pickStack$4(parsed, stacks, target);
|
|
5099
5104
|
const resources = stack.template.Resources ?? {};
|
|
5100
5105
|
let logicalId;
|
|
5101
5106
|
let resource;
|
|
5102
5107
|
if (parsed.isPath) {
|
|
5103
5108
|
const index = buildCdkPathIndex(stack.template);
|
|
5104
5109
|
const taskDefs = resolveCdkPathToLogicalIds(parsed.pathOrId, index).filter(({ logicalId: l }) => resources[l]?.Type === "AWS::ECS::TaskDefinition");
|
|
5105
|
-
if (taskDefs.length === 0) throw notFoundError$
|
|
5110
|
+
if (taskDefs.length === 0) throw notFoundError$2(target, stack, resources);
|
|
5106
5111
|
if (taskDefs.length > 1) throw new EcsTaskResolutionError(`Target '${target}' matches ${taskDefs.length} task definitions in ${stack.stackName}: ` + taskDefs.map((t) => t.logicalId).join(", ") + ". Refine the path or use the stack:LogicalId form.");
|
|
5107
5112
|
logicalId = taskDefs[0].logicalId;
|
|
5108
5113
|
resource = resources[logicalId];
|
|
5109
5114
|
} else {
|
|
5110
5115
|
resource = resources[parsed.pathOrId];
|
|
5111
|
-
if (!resource) throw notFoundError$
|
|
5116
|
+
if (!resource) throw notFoundError$2(target, stack, resources);
|
|
5112
5117
|
logicalId = parsed.pathOrId;
|
|
5113
5118
|
}
|
|
5114
|
-
if (!logicalId || !resource) throw notFoundError$
|
|
5119
|
+
if (!logicalId || !resource) throw notFoundError$2(target, stack, resources);
|
|
5115
5120
|
if (resource.Type === "AWS::Lambda::Function") throw new EcsTaskResolutionError(`Resource ${displayIdent(logicalId)} in ${stack.stackName} is a Lambda function, not an ECS task definition. Use \`${getEmbedConfig().cliName} invoke\` for Lambda; \`${getEmbedConfig().cliName} run-task\` is ECS only.`);
|
|
5116
5121
|
if (resource.Type !== "AWS::ECS::TaskDefinition") throw new EcsTaskResolutionError(`Resource ${displayIdent(logicalId)} in ${stack.stackName} is ${displayIdent(resource.Type)}, not an AWS::ECS::TaskDefinition.`);
|
|
5117
5122
|
return extractTaskDefinitionProperties(stack, logicalId, resource, context);
|
|
5118
5123
|
}
|
|
5119
|
-
function pickStack$
|
|
5124
|
+
function pickStack$4(parsed, stacks, target) {
|
|
5120
5125
|
const selection = selectTargetStack(parsed, target, stacks);
|
|
5121
5126
|
switch (selection.kind) {
|
|
5122
5127
|
case "found": return selection.stack;
|
|
@@ -5545,7 +5550,7 @@ function pickStringArray$1(value) {
|
|
|
5545
5550
|
for (const v of value) if (typeof v === "string") out.push(v);
|
|
5546
5551
|
return out;
|
|
5547
5552
|
}
|
|
5548
|
-
function notFoundError$
|
|
5553
|
+
function notFoundError$2(target, stack, resources) {
|
|
5549
5554
|
const tasks = [];
|
|
5550
5555
|
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
5551
5556
|
if (resource.Type !== "AWS::ECS::TaskDefinition") continue;
|
|
@@ -6488,7 +6493,7 @@ function pushMap(hash, name, value) {
|
|
|
6488
6493
|
|
|
6489
6494
|
//#endregion
|
|
6490
6495
|
//#region src/local/docker-runner.ts
|
|
6491
|
-
const execFileAsync$
|
|
6496
|
+
const execFileAsync$6 = promisify(execFile);
|
|
6492
6497
|
var DockerRunnerError = class DockerRunnerError extends Error {
|
|
6493
6498
|
constructor(message) {
|
|
6494
6499
|
super(message);
|
|
@@ -6535,7 +6540,7 @@ async function pullImage(image, skipPull, platform) {
|
|
|
6535
6540
|
}
|
|
6536
6541
|
}
|
|
6537
6542
|
async function runDetached(opts) {
|
|
6538
|
-
const args = [
|
|
6543
|
+
const args = opts.autoRemove === false ? ["run", "-d"] : [
|
|
6539
6544
|
"run",
|
|
6540
6545
|
"-d",
|
|
6541
6546
|
"--rm"
|
|
@@ -6579,7 +6584,7 @@ async function runDetached(opts) {
|
|
|
6579
6584
|
if (refusal !== void 0) throw new DockerRunnerError(refusal);
|
|
6580
6585
|
warnFinchArgvExposure(forwardedKeys);
|
|
6581
6586
|
try {
|
|
6582
|
-
const { stdout } = await execFileAsync$
|
|
6587
|
+
const { stdout } = await execFileAsync$6(getDockerCmd(), args, {
|
|
6583
6588
|
maxBuffer: 10 * 1024 * 1024,
|
|
6584
6589
|
...execEnvForSecrets(passthroughEnv)
|
|
6585
6590
|
});
|
|
@@ -6620,7 +6625,7 @@ function createPrefixedLineRelay(prefix, out) {
|
|
|
6620
6625
|
}
|
|
6621
6626
|
};
|
|
6622
6627
|
}
|
|
6623
|
-
function streamLogs(containerId) {
|
|
6628
|
+
function streamLogs(containerId, opts = {}) {
|
|
6624
6629
|
const proc = spawn(getDockerCmd(), [
|
|
6625
6630
|
"logs",
|
|
6626
6631
|
"-f",
|
|
@@ -6630,6 +6635,11 @@ function streamLogs(containerId) {
|
|
|
6630
6635
|
"pipe",
|
|
6631
6636
|
"pipe"
|
|
6632
6637
|
] });
|
|
6638
|
+
if (opts.onOutput) {
|
|
6639
|
+
const tap = opts.onOutput;
|
|
6640
|
+
proc.stdout?.on("data", (chunk) => tap(chunk));
|
|
6641
|
+
proc.stderr?.on("data", (chunk) => tap(chunk));
|
|
6642
|
+
}
|
|
6633
6643
|
let flush = () => void 0;
|
|
6634
6644
|
if (process.env["CDKL_PREFIX_CONTAINER_OUTPUT"] === "1") {
|
|
6635
6645
|
const tag = `[${flattenToOneLine(containerId.slice(0, 12)).replace(/[\]\s]/g, "_")}] `;
|
|
@@ -6656,7 +6666,7 @@ async function removeContainer(containerId) {
|
|
|
6656
6666
|
if (!containerId) return;
|
|
6657
6667
|
const logger = getLogger().child("docker");
|
|
6658
6668
|
try {
|
|
6659
|
-
await execFileAsync$
|
|
6669
|
+
await execFileAsync$6(getDockerCmd(), [
|
|
6660
6670
|
"rm",
|
|
6661
6671
|
"-f",
|
|
6662
6672
|
containerId
|
|
@@ -6670,7 +6680,7 @@ async function removeContainer(containerId) {
|
|
|
6670
6680
|
async function ensureDockerAvailable() {
|
|
6671
6681
|
const cmd = getDockerCmd();
|
|
6672
6682
|
try {
|
|
6673
|
-
await execFileAsync$
|
|
6683
|
+
await execFileAsync$6(cmd, [
|
|
6674
6684
|
"version",
|
|
6675
6685
|
"--format",
|
|
6676
6686
|
"{{.Server.Version}}"
|
|
@@ -14095,7 +14105,7 @@ async function resolveLambdaContainerEnvWith(lambda, options, profileCredentials
|
|
|
14095
14105
|
for (const key of audit.resolvedKeys) logger.debug(`${label}: substituted env var ${key}`);
|
|
14096
14106
|
let unresolved = audit.unresolved;
|
|
14097
14107
|
const resolvedKeys = [...audit.resolvedKeys];
|
|
14098
|
-
if (unresolved.length > 0 && stateProvider.resolveDeployedFunctionEnv) {
|
|
14108
|
+
if (unresolved.length > 0 && options.deployedFunctionLookups !== false && stateProvider.resolveDeployedFunctionEnv) {
|
|
14099
14109
|
const physicalId = loaded.resources[lambda.logicalId]?.physicalId;
|
|
14100
14110
|
if (physicalId) {
|
|
14101
14111
|
const deployedEnv = await stateProvider.resolveDeployedFunctionEnv(physicalId);
|
|
@@ -14137,7 +14147,9 @@ async function resolveLambdaContainerEnvWith(lambda, options, profileCredentials
|
|
|
14137
14147
|
});
|
|
14138
14148
|
let resolvedAssumeRoleArn;
|
|
14139
14149
|
try {
|
|
14140
|
-
|
|
14150
|
+
const fromTemplate = options.assumeRole === true && options.deployedFunctionLookups === false && stateForRoleHint ? await resolveTemplateRoleArnFromState(lambda.resource.Properties?.["Role"], stateForRoleHint, lambda.stack.template, () => resolvePseudoParametersForInvoke(lambda.stack.region, options)) : void 0;
|
|
14151
|
+
if (fromTemplate !== void 0) logger.info(`--assume-role: auto-resolved execution role from state: ${flattenToOneLine(fromTemplate)}`);
|
|
14152
|
+
resolvedAssumeRoleArn = fromTemplate ?? await resolveAssumeRoleArnForLambda(options.assumeRole, stateForRoleHint, options.deployedFunctionLookups === false ? void 0 : stateProvider, lambda.logicalId);
|
|
14141
14153
|
} finally {
|
|
14142
14154
|
stateProvider?.dispose();
|
|
14143
14155
|
}
|
|
@@ -14248,6 +14260,28 @@ function resolveExecutionRoleArnFromState(state, logicalId, roleProperty = "Role
|
|
|
14248
14260
|
}
|
|
14249
14261
|
}
|
|
14250
14262
|
}
|
|
14263
|
+
async function resolveTemplateRoleArnFromState(templateRole, state, template, pseudo) {
|
|
14264
|
+
if (isIamRoleArn(templateRole)) return templateRole;
|
|
14265
|
+
if (!templateRole || typeof templateRole !== "object" || Array.isArray(templateRole)) return;
|
|
14266
|
+
const ref = pickReferencedLogicalId(templateRole);
|
|
14267
|
+
if (ref === void 0) return void 0;
|
|
14268
|
+
const roleResource = template.Resources?.[ref];
|
|
14269
|
+
if (roleResource?.Type !== "AWS::IAM::Role") return void 0;
|
|
14270
|
+
const deployed = state.resources[ref];
|
|
14271
|
+
if (!deployed) return void 0;
|
|
14272
|
+
const cached = deployed.attributes?.["Arn"];
|
|
14273
|
+
if (isIamRoleArn(cached)) return cached;
|
|
14274
|
+
const physicalId = deployed.physicalId;
|
|
14275
|
+
if (isIamRoleArn(physicalId)) return physicalId;
|
|
14276
|
+
if (typeof physicalId !== "string" || !/^[\w+=,.@-]{1,64}$/.test(physicalId)) return void 0;
|
|
14277
|
+
const rawPath = roleResource.Properties?.["Path"];
|
|
14278
|
+
if (rawPath !== void 0 && typeof rawPath !== "string") return void 0;
|
|
14279
|
+
const rolePath = rawPath ?? "/";
|
|
14280
|
+
const bag = await pseudo();
|
|
14281
|
+
if (!bag?.accountId) return void 0;
|
|
14282
|
+
const arn = `arn:${bag.partition ?? "aws"}:iam::${bag.accountId}:role${rolePath}${physicalId}`;
|
|
14283
|
+
return isIamRoleArn(arn) ? arn : void 0;
|
|
14284
|
+
}
|
|
14251
14285
|
function pickReferencedLogicalId(intrinsic) {
|
|
14252
14286
|
if ("Ref" in intrinsic && typeof intrinsic["Ref"] === "string") return intrinsic["Ref"];
|
|
14253
14287
|
if ("Fn::GetAtt" in intrinsic) {
|
|
@@ -15996,7 +16030,7 @@ async function runAgentCoreWatchLoop(args) {
|
|
|
15996
16030
|
}
|
|
15997
16031
|
}
|
|
15998
16032
|
}
|
|
15999
|
-
const execFileAsync$
|
|
16033
|
+
const execFileAsync$5 = promisify(execFile);
|
|
16000
16034
|
function describeExecError(err) {
|
|
16001
16035
|
if (!(err instanceof Error)) return String(err);
|
|
16002
16036
|
const stderr = err.stderr;
|
|
@@ -16008,7 +16042,7 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
|
|
|
16008
16042
|
const dockerCmd = getDockerCmd();
|
|
16009
16043
|
let workdir;
|
|
16010
16044
|
try {
|
|
16011
|
-
const { stdout } = await execFileAsync$
|
|
16045
|
+
const { stdout } = await execFileAsync$5(dockerCmd, [
|
|
16012
16046
|
"inspect",
|
|
16013
16047
|
"--format",
|
|
16014
16048
|
"{{.Config.WorkingDir}}",
|
|
@@ -16021,7 +16055,7 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
|
|
|
16021
16055
|
const workdirDest = workdir.endsWith("/") ? workdir : `${workdir}/`;
|
|
16022
16056
|
logger.info(`Soft-reload: docker cp ${flattenToOneLine(newAssetSourceDir)} -> ${containerId}:${workdirDest}; restart.`);
|
|
16023
16057
|
try {
|
|
16024
|
-
await execFileAsync$
|
|
16058
|
+
await execFileAsync$5(dockerCmd, [
|
|
16025
16059
|
"cp",
|
|
16026
16060
|
`${newAssetSourceDir}/.`,
|
|
16027
16061
|
`${containerId}:${workdirDest}`
|
|
@@ -16030,7 +16064,7 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
|
|
|
16030
16064
|
throw new CdkLocalError(`softReloadAgentContainer: docker cp into '${containerId}:${workdir}' failed: ${describeExecError(err)}.`, "LOCAL_INVOKE_AGENTCORE_WATCH_SOFT_RELOAD_CP_FAILED");
|
|
16031
16065
|
}
|
|
16032
16066
|
try {
|
|
16033
|
-
await execFileAsync$
|
|
16067
|
+
await execFileAsync$5(dockerCmd, ["restart", containerId]);
|
|
16034
16068
|
} catch (err) {
|
|
16035
16069
|
throw new CdkLocalError(`softReloadAgentContainer: docker restart of '${containerId}' failed: ${describeExecError(err)}.`, "LOCAL_INVOKE_AGENTCORE_WATCH_SOFT_RELOAD_RESTART_FAILED");
|
|
16036
16070
|
}
|
|
@@ -16206,7 +16240,7 @@ function writePrefixedLines(prefix, buffer, out) {
|
|
|
16206
16240
|
|
|
16207
16241
|
//#endregion
|
|
16208
16242
|
//#region src/local/ecs-network.ts
|
|
16209
|
-
const execFileAsync$
|
|
16243
|
+
const execFileAsync$4 = promisify(execFile);
|
|
16210
16244
|
const METADATA_ENDPOINT_IMAGE = "amazon/amazon-ecs-local-container-endpoints:latest-amd64";
|
|
16211
16245
|
const METADATA_ENDPOINT_IP = "169.254.170.2";
|
|
16212
16246
|
const DEFAULT_METADATA_ENDPOINT_SUBNET = "169.254.170.0/24";
|
|
@@ -16242,7 +16276,7 @@ async function sweepOrphanedSvcNetworks(prefix) {
|
|
|
16242
16276
|
const filter = `${prefix}-svc-`;
|
|
16243
16277
|
let names;
|
|
16244
16278
|
try {
|
|
16245
|
-
const { stdout } = await execFileAsync$
|
|
16279
|
+
const { stdout } = await execFileAsync$4(getDockerCmd(), [
|
|
16246
16280
|
"network",
|
|
16247
16281
|
"ls",
|
|
16248
16282
|
"--filter",
|
|
@@ -16260,7 +16294,7 @@ async function sweepOrphanedSvcNetworks(prefix) {
|
|
|
16260
16294
|
for (const name of names) {
|
|
16261
16295
|
let attached;
|
|
16262
16296
|
try {
|
|
16263
|
-
const { stdout } = await execFileAsync$
|
|
16297
|
+
const { stdout } = await execFileAsync$4(getDockerCmd(), [
|
|
16264
16298
|
"network",
|
|
16265
16299
|
"inspect",
|
|
16266
16300
|
name,
|
|
@@ -16288,7 +16322,7 @@ async function createNetworkAndSidecar(args) {
|
|
|
16288
16322
|
await pullImage(METADATA_ENDPOINT_IMAGE, skipPull);
|
|
16289
16323
|
logger.info(`Creating docker network ${networkName} (subnet ${cidr})...`);
|
|
16290
16324
|
try {
|
|
16291
|
-
await execFileAsync$
|
|
16325
|
+
await execFileAsync$4(getDockerCmd(), [
|
|
16292
16326
|
"network",
|
|
16293
16327
|
"create",
|
|
16294
16328
|
"--driver",
|
|
@@ -16325,7 +16359,7 @@ async function createNetworkAndSidecar(args) {
|
|
|
16325
16359
|
warnFinchArgvExposure(Object.keys(sidecarPassthroughEnv));
|
|
16326
16360
|
logger.info(`Starting ECS local-container-endpoints sidecar at ${sidecarIp}...`);
|
|
16327
16361
|
try {
|
|
16328
|
-
const { stdout } = await execFileAsync$
|
|
16362
|
+
const { stdout } = await execFileAsync$4(getDockerCmd(), sidecarArgs, {
|
|
16329
16363
|
maxBuffer: 10 * 1024 * 1024,
|
|
16330
16364
|
...execEnvForSecrets(sidecarPassthroughEnv)
|
|
16331
16365
|
});
|
|
@@ -16373,7 +16407,7 @@ async function destroyNetworkOnly(networkName) {
|
|
|
16373
16407
|
if (!networkName) return;
|
|
16374
16408
|
const logger = getLogger().child("ecs-network");
|
|
16375
16409
|
try {
|
|
16376
|
-
await execFileAsync$
|
|
16410
|
+
await execFileAsync$4(getDockerCmd(), [
|
|
16377
16411
|
"network",
|
|
16378
16412
|
"rm",
|
|
16379
16413
|
networkName
|
|
@@ -16487,7 +16521,7 @@ async function resolveSsm(entry, shape, client) {
|
|
|
16487
16521
|
|
|
16488
16522
|
//#endregion
|
|
16489
16523
|
//#region src/local/ecs-task-runner.ts
|
|
16490
|
-
const execFileAsync$
|
|
16524
|
+
const execFileAsync$3 = promisify(execFile);
|
|
16491
16525
|
var EcsTaskRunnerError = class EcsTaskRunnerError extends Error {
|
|
16492
16526
|
constructor(message) {
|
|
16493
16527
|
super(message);
|
|
@@ -16530,7 +16564,7 @@ async function cleanupEcsRun(state, options) {
|
|
|
16530
16564
|
if (state.network && !state.network.ownedByCaller) await destroyTaskNetwork(state.network);
|
|
16531
16565
|
state.network = void 0;
|
|
16532
16566
|
for (const v of state.dockerVolumeNames) try {
|
|
16533
|
-
await execFileAsync$
|
|
16567
|
+
await execFileAsync$3(getDockerCmd(), [
|
|
16534
16568
|
"volume",
|
|
16535
16569
|
"rm",
|
|
16536
16570
|
v
|
|
@@ -16681,7 +16715,7 @@ async function runEcsTask(task, options, state) {
|
|
|
16681
16715
|
let id;
|
|
16682
16716
|
warnFinchArgvExposure(Object.keys(sensitiveEnv));
|
|
16683
16717
|
try {
|
|
16684
|
-
const { stdout } = await execFileAsync$
|
|
16718
|
+
const { stdout } = await execFileAsync$3(getDockerCmd(), args, {
|
|
16685
16719
|
maxBuffer: 10 * 1024 * 1024,
|
|
16686
16720
|
...execEnvForSecrets(sensitiveEnv)
|
|
16687
16721
|
});
|
|
@@ -16773,7 +16807,7 @@ async function waitForContainerHealthy(containerId, displayName) {
|
|
|
16773
16807
|
let lastStatus = "";
|
|
16774
16808
|
while (Date.now() < deadline) {
|
|
16775
16809
|
try {
|
|
16776
|
-
const { stdout } = await execFileAsync$
|
|
16810
|
+
const { stdout } = await execFileAsync$3(getDockerCmd(), [
|
|
16777
16811
|
"inspect",
|
|
16778
16812
|
"--format",
|
|
16779
16813
|
"{{.State.Health.Status}}",
|
|
@@ -16796,7 +16830,7 @@ async function waitForContainerHealthy(containerId, displayName) {
|
|
|
16796
16830
|
}
|
|
16797
16831
|
async function waitForContainerExit(containerId) {
|
|
16798
16832
|
try {
|
|
16799
|
-
const { stdout } = await execFileAsync$
|
|
16833
|
+
const { stdout } = await execFileAsync$3(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
|
|
16800
16834
|
const code = Number.parseInt(stdout.trim(), 10);
|
|
16801
16835
|
return Number.isFinite(code) ? code : 1;
|
|
16802
16836
|
} catch (err) {
|
|
@@ -16806,7 +16840,7 @@ async function waitForContainerExit(containerId) {
|
|
|
16806
16840
|
}
|
|
16807
16841
|
async function stopContainer(containerId, graceSeconds) {
|
|
16808
16842
|
try {
|
|
16809
|
-
await execFileAsync$
|
|
16843
|
+
await execFileAsync$3(getDockerCmd(), [
|
|
16810
16844
|
"stop",
|
|
16811
16845
|
"-t",
|
|
16812
16846
|
String(graceSeconds),
|
|
@@ -16901,7 +16935,7 @@ async function realizeDockerVolumes(volumes, state) {
|
|
|
16901
16935
|
const dockerVolumeName = `${getEmbedConfig().resourceNamePrefix}-${v.name}-${randHex(4)}`;
|
|
16902
16936
|
args.push(dockerVolumeName);
|
|
16903
16937
|
try {
|
|
16904
|
-
await execFileAsync$
|
|
16938
|
+
await execFileAsync$3(getDockerCmd(), args);
|
|
16905
16939
|
state.dockerVolumeNames.push(dockerVolumeName);
|
|
16906
16940
|
logger.debug(`Created docker volume ${displayIdent(dockerVolumeName)} for task volume ${displayIdent(v.name)}`);
|
|
16907
16941
|
} catch (err) {
|
|
@@ -17095,23 +17129,23 @@ function shellJoin(parts) {
|
|
|
17095
17129
|
function resolveEcsServiceTarget(target, stacks, context, options) {
|
|
17096
17130
|
if (stacks.length === 0) throw new EcsTaskResolutionError("No stacks found in the synthesized assembly.");
|
|
17097
17131
|
const parsed = parseEcsTarget(target);
|
|
17098
|
-
const stack = pickStack$
|
|
17132
|
+
const stack = pickStack$3(parsed, stacks, target);
|
|
17099
17133
|
const resources = stack.template.Resources ?? {};
|
|
17100
17134
|
let serviceLogicalId;
|
|
17101
17135
|
let serviceResource;
|
|
17102
17136
|
if (parsed.isPath) {
|
|
17103
17137
|
const index = buildCdkPathIndex(stack.template);
|
|
17104
17138
|
const services = resolveCdkPathToLogicalIds(parsed.pathOrId, index).filter(({ logicalId: l }) => resources[l]?.Type === "AWS::ECS::Service");
|
|
17105
|
-
if (services.length === 0) throw notFoundError(target, stack, resources, parsed);
|
|
17139
|
+
if (services.length === 0) throw notFoundError$1(target, stack, resources, parsed);
|
|
17106
17140
|
if (services.length > 1) throw new EcsTaskResolutionError(`Target '${target}' matches ${services.length} ECS services in ${stack.stackName}: ` + services.map((s) => s.logicalId).join(", ") + ". Refine the path or use the stack:LogicalId form.");
|
|
17107
17141
|
serviceLogicalId = services[0].logicalId;
|
|
17108
17142
|
serviceResource = resources[serviceLogicalId];
|
|
17109
17143
|
} else {
|
|
17110
17144
|
serviceResource = resources[parsed.pathOrId];
|
|
17111
|
-
if (!serviceResource) throw notFoundError(target, stack, resources, parsed);
|
|
17145
|
+
if (!serviceResource) throw notFoundError$1(target, stack, resources, parsed);
|
|
17112
17146
|
serviceLogicalId = parsed.pathOrId;
|
|
17113
17147
|
}
|
|
17114
|
-
if (!serviceLogicalId || !serviceResource) throw notFoundError(target, stack, resources, parsed);
|
|
17148
|
+
if (!serviceLogicalId || !serviceResource) throw notFoundError$1(target, stack, resources, parsed);
|
|
17115
17149
|
if (serviceResource.Type === "AWS::ECS::TaskDefinition") throw new EcsTaskResolutionError(`Resource ${displayIdent(serviceLogicalId)} in ${stack.stackName} is an ECS TaskDefinition, not a Service. Use \`${getEmbedConfig().cliName} run-task\` for one-shot tasks; \`${getEmbedConfig().cliName} start-service\` is Service-only.`);
|
|
17116
17150
|
if (serviceResource.Type !== "AWS::ECS::Service") throw new EcsTaskResolutionError(`Resource ${displayIdent(serviceLogicalId)} in ${stack.stackName} is ${displayIdent(serviceResource.Type)}, not an AWS::ECS::Service.`);
|
|
17117
17151
|
return extractServiceProperties(stack, serviceLogicalId, serviceResource, stacks, context, options);
|
|
@@ -17267,7 +17301,7 @@ function deriveServiceDisplayName(rawServiceName, serviceLogicalId, metadata) {
|
|
|
17267
17301
|
}
|
|
17268
17302
|
return serviceLogicalId;
|
|
17269
17303
|
}
|
|
17270
|
-
function pickStack$
|
|
17304
|
+
function pickStack$3(parsed, stacks, target) {
|
|
17271
17305
|
const selection = selectTargetStack(parsed, target, stacks);
|
|
17272
17306
|
switch (selection.kind) {
|
|
17273
17307
|
case "found": return selection.stack;
|
|
@@ -17276,7 +17310,7 @@ function pickStack$2(parsed, stacks, target) {
|
|
|
17276
17310
|
case "ambiguous": throw new EcsTaskResolutionError(`Multiple stacks match '${selection.pattern}': ${describeStacks(selection.matched)}. Refine the pattern, or use the stack's display path (path form).`);
|
|
17277
17311
|
}
|
|
17278
17312
|
}
|
|
17279
|
-
function notFoundError(target, stack, resources, parsed) {
|
|
17313
|
+
function notFoundError$1(target, stack, resources, parsed) {
|
|
17280
17314
|
const services = [];
|
|
17281
17315
|
for (const [logicalId, r] of Object.entries(resources)) {
|
|
17282
17316
|
if (r.Type !== "AWS::ECS::Service") continue;
|
|
@@ -17301,11 +17335,11 @@ function notFoundError(target, stack, resources, parsed) {
|
|
|
17301
17335
|
|
|
17302
17336
|
//#endregion
|
|
17303
17337
|
//#region src/local/docker-inspect.ts
|
|
17304
|
-
const execFileAsync$
|
|
17338
|
+
const execFileAsync$2 = promisify(execFile);
|
|
17305
17339
|
async function getContainerNetworkIp(containerId, networkName) {
|
|
17306
17340
|
const format = `{{with index .NetworkSettings.Networks "${networkName}"}}{{.IPAddress}}{{end}}`;
|
|
17307
17341
|
try {
|
|
17308
|
-
const { stdout } = await execFileAsync$
|
|
17342
|
+
const { stdout } = await execFileAsync$2(getDockerCmd(), [
|
|
17309
17343
|
"inspect",
|
|
17310
17344
|
"--format",
|
|
17311
17345
|
format,
|
|
@@ -17321,7 +17355,7 @@ async function getContainerNetworkIp(containerId, networkName) {
|
|
|
17321
17355
|
async function getPublishedHostPort(containerId, containerPort, protocol = "tcp") {
|
|
17322
17356
|
const format = `{{with index .NetworkSettings.Ports "${`${containerPort}/${protocol}`}"}}{{with index . 0}}{{.HostPort}}{{end}}{{end}}`;
|
|
17323
17357
|
try {
|
|
17324
|
-
const { stdout } = await execFileAsync$
|
|
17358
|
+
const { stdout } = await execFileAsync$2(getDockerCmd(), [
|
|
17325
17359
|
"inspect",
|
|
17326
17360
|
"--format",
|
|
17327
17361
|
format,
|
|
@@ -19516,7 +19550,7 @@ function matchBitPrefix(a, b, prefixLength) {
|
|
|
19516
19550
|
|
|
19517
19551
|
//#endregion
|
|
19518
19552
|
//#region src/local/front-door-tls.ts
|
|
19519
|
-
const execFileAsync = promisify(execFile);
|
|
19553
|
+
const execFileAsync$1 = promisify(execFile);
|
|
19520
19554
|
async function resolveFrontDoorTlsMaterials(opts) {
|
|
19521
19555
|
const hasCert = opts.certPath !== void 0 && opts.certPath !== "";
|
|
19522
19556
|
const hasKey = opts.keyPath !== void 0 && opts.keyPath !== "";
|
|
@@ -19606,7 +19640,7 @@ function readCertNotAfter(certPath) {
|
|
|
19606
19640
|
}
|
|
19607
19641
|
}
|
|
19608
19642
|
async function runOpenssl(args) {
|
|
19609
|
-
await execFileAsync("openssl", args, { timeout: 3e4 });
|
|
19643
|
+
await execFileAsync$1("openssl", args, { timeout: 3e4 });
|
|
19610
19644
|
}
|
|
19611
19645
|
function readPemOrThrow(path, flagName) {
|
|
19612
19646
|
try {
|
|
@@ -21809,7 +21843,7 @@ function resolveAlbFrontDoor(stack, albLogicalId) {
|
|
|
21809
21843
|
if (resource.Type !== LISTENER_TYPE) continue;
|
|
21810
21844
|
const props = resource.Properties ?? {};
|
|
21811
21845
|
if (refOf(props["LoadBalancerArn"]) !== albLogicalId) continue;
|
|
21812
|
-
const port = parsePort$
|
|
21846
|
+
const port = parsePort$2(props["Port"]);
|
|
21813
21847
|
if (port === void 0) continue;
|
|
21814
21848
|
const protocol = typeof props["Protocol"] === "string" ? props["Protocol"] : "HTTP";
|
|
21815
21849
|
if (protocol !== "HTTP" && protocol !== "HTTPS") {
|
|
@@ -22174,7 +22208,7 @@ function refOf(raw) {
|
|
|
22174
22208
|
if (typeof ref === "string" && ref.length > 0) return ref;
|
|
22175
22209
|
}
|
|
22176
22210
|
}
|
|
22177
|
-
function parsePort$
|
|
22211
|
+
function parsePort$2(raw) {
|
|
22178
22212
|
if (typeof raw === "number" && Number.isInteger(raw) && raw >= 1 && raw <= 65535) return raw;
|
|
22179
22213
|
if (typeof raw === "string" && /^\d+$/.test(raw)) {
|
|
22180
22214
|
const n = parseInt(raw, 10);
|
|
@@ -22182,7 +22216,7 @@ function parsePort$1(raw) {
|
|
|
22182
22216
|
}
|
|
22183
22217
|
}
|
|
22184
22218
|
function parseContainerPort(raw) {
|
|
22185
|
-
return parsePort$
|
|
22219
|
+
return parsePort$2(raw);
|
|
22186
22220
|
}
|
|
22187
22221
|
function parseWeight(raw) {
|
|
22188
22222
|
if (typeof raw === "number" && Number.isFinite(raw)) return raw < 0 ? 0 : raw;
|
|
@@ -22276,7 +22310,7 @@ function parseLbPortOverrides(values) {
|
|
|
22276
22310
|
function resolveAlbTarget(target, stacks) {
|
|
22277
22311
|
if (stacks.length === 0) throw new LocalStartServiceError("No stacks found in the synthesized assembly.");
|
|
22278
22312
|
const parsed = parseEcsTarget(target);
|
|
22279
|
-
const stack = pickStack$
|
|
22313
|
+
const stack = pickStack$2(parsed, stacks, target);
|
|
22280
22314
|
const resources = stack.template.Resources ?? {};
|
|
22281
22315
|
if (parsed.isPath) {
|
|
22282
22316
|
const index = buildCdkPathIndex(stack.template);
|
|
@@ -22298,7 +22332,7 @@ function resolveAlbTarget(target, stacks) {
|
|
|
22298
22332
|
albLogicalId: parsed.pathOrId
|
|
22299
22333
|
};
|
|
22300
22334
|
}
|
|
22301
|
-
function pickStack$
|
|
22335
|
+
function pickStack$2(parsed, stacks, target) {
|
|
22302
22336
|
const selection = selectTargetStack(parsed, target, stacks);
|
|
22303
22337
|
switch (selection.kind) {
|
|
22304
22338
|
case "found": return selection.stack;
|
|
@@ -24213,7 +24247,7 @@ async function attachKvsModules(distribution, stacks, options, profileCredential
|
|
|
24213
24247
|
function resolveCloudFrontTarget(target, stacks) {
|
|
24214
24248
|
if (stacks.length === 0) throw new LocalStartCloudFrontError("No stacks found in the synthesized assembly.");
|
|
24215
24249
|
const parsed = parseEcsTarget(target);
|
|
24216
|
-
const stack = pickStack(parsed, stacks, target);
|
|
24250
|
+
const stack = pickStack$1(parsed, stacks, target);
|
|
24217
24251
|
const resources = stack.template.Resources ?? {};
|
|
24218
24252
|
if (parsed.isPath) {
|
|
24219
24253
|
const index = buildCdkPathIndex(stack.template);
|
|
@@ -24235,7 +24269,7 @@ function resolveCloudFrontTarget(target, stacks) {
|
|
|
24235
24269
|
logicalId: parsed.pathOrId
|
|
24236
24270
|
};
|
|
24237
24271
|
}
|
|
24238
|
-
function pickStack(parsed, stacks, target) {
|
|
24272
|
+
function pickStack$1(parsed, stacks, target) {
|
|
24239
24273
|
const selection = selectTargetStack(parsed, target, stacks);
|
|
24240
24274
|
switch (selection.kind) {
|
|
24241
24275
|
case "found": return selection.stack;
|
|
@@ -24858,7 +24892,7 @@ function readAuthorizationHeader(headers) {
|
|
|
24858
24892
|
|
|
24859
24893
|
//#endregion
|
|
24860
24894
|
//#region src/cli/commands/local-start-agentcore.ts
|
|
24861
|
-
function parsePort(raw) {
|
|
24895
|
+
function parsePort$1(raw) {
|
|
24862
24896
|
const n = Number(raw);
|
|
24863
24897
|
if (!Number.isInteger(n) || n < 0 || n > 65535) throw new InvalidArgumentError(`--port must be an integer 0-65535, got '${raw}'.`);
|
|
24864
24898
|
return n;
|
|
@@ -25186,7 +25220,761 @@ function createLocalStartAgentCoreCommand(opts = {}) {
|
|
|
25186
25220
|
return cmd;
|
|
25187
25221
|
}
|
|
25188
25222
|
function addStartAgentCoreSpecificOptions(cmd) {
|
|
25189
|
-
return cmd.addOption(new Option("--port <n>", "Serve bind port the client connects to (HTTP contract + /ws on the same port). Default 0 (OS-assigned).").default(0).argParser(parsePort)).addOption(new Option("--host <ip>", "Serve bind host. Default 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--session-id <id>", "Pin one AgentCore runtime session id header value for every forwarded request / /ws connection (default: a fresh random UUID each, so each is its own session).")).addOption(new Option("--bearer-token <jwt>", "Bearer JWT to present when the runtime declares a customJwtAuthorizer. Verified against the runtime's OIDC discovery URL before the container starts, then injected as Authorization: Bearer <jwt> on every forwarded request and the container /ws upgrade.")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--sigv4", "Sign each forwarded request with AWS SigV4 (service bedrock-agentcore) when the runtime declares NO customJwtAuthorizer, so the warm container sees the same Authorization / X-Amz-* headers the cloud receives. Mutually exclusive with --bearer-token; ignored (with a warning) when a customJwtAuthorizer is declared.")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64). Defaults to linux/arm64 because the cloud AgentCore Runtime requires arm64.").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--watch", "Re-synth + reload the warm container in place on a CDK source change, keeping the serve up. A per-firing classifier picks rebuild (boot a fresh container, re-point the serve) vs soft-reload (docker cp + docker restart the same container) — the same pattern as start-service / invoke-agentcore --ws --watch.")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host IP used to bind the agent container port. Must be a numeric IP. Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--timeout <ms>", "Maximum time in milliseconds to wait for the container to become ready (the GET /ping readiness deadline). Default 120000.").default(12e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container. (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's literal RoleArn; (3) `--no-assume-role` opts out. Off by default.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack and substitute Ref / Fn::ImportValue in env vars / image URIs with the deployed physical IDs / exports. Bare form uses the resolved stack name.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
|
|
25223
|
+
return cmd.addOption(new Option("--port <n>", "Serve bind port the client connects to (HTTP contract + /ws on the same port). Default 0 (OS-assigned).").default(0).argParser(parsePort$1)).addOption(new Option("--host <ip>", "Serve bind host. Default 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--session-id <id>", "Pin one AgentCore runtime session id header value for every forwarded request / /ws connection (default: a fresh random UUID each, so each is its own session).")).addOption(new Option("--bearer-token <jwt>", "Bearer JWT to present when the runtime declares a customJwtAuthorizer. Verified against the runtime's OIDC discovery URL before the container starts, then injected as Authorization: Bearer <jwt> on every forwarded request and the container /ws upgrade.")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--sigv4", "Sign each forwarded request with AWS SigV4 (service bedrock-agentcore) when the runtime declares NO customJwtAuthorizer, so the warm container sees the same Authorization / X-Amz-* headers the cloud receives. Mutually exclusive with --bearer-token; ignored (with a warning) when a customJwtAuthorizer is declared.")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64). Defaults to linux/arm64 because the cloud AgentCore Runtime requires arm64.").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--watch", "Re-synth + reload the warm container in place on a CDK source change, keeping the serve up. A per-firing classifier picks rebuild (boot a fresh container, re-point the serve) vs soft-reload (docker cp + docker restart the same container) — the same pattern as start-service / invoke-agentcore --ws --watch.")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host IP used to bind the agent container port. Must be a numeric IP. Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--timeout <ms>", "Maximum time in milliseconds to wait for the container to become ready (the GET /ping readiness deadline). Default 120000.").default(12e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container. (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's literal RoleArn; (3) `--no-assume-role` opts out. Off by default.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack and substitute Ref / Fn::ImportValue in env vars / image URIs with the deployed physical IDs / exports. Bare form uses the resolved stack name.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
|
|
25224
|
+
}
|
|
25225
|
+
|
|
25226
|
+
//#endregion
|
|
25227
|
+
//#region src/local/web-function-resolver.ts
|
|
25228
|
+
const WEB_FUNCTION_TYPE = "AWS::Lambda::WebFunction";
|
|
25229
|
+
const WEB_FUNCTION_REVISION_TYPE = "AWS::Lambda::WebFunctionRevision";
|
|
25230
|
+
const WEB_FUNCTION_ENDPOINT_TYPE = "AWS::Lambda::WebFunctionEndpoint";
|
|
25231
|
+
const WEB_TYPES = [
|
|
25232
|
+
WEB_FUNCTION_ENDPOINT_TYPE,
|
|
25233
|
+
WEB_FUNCTION_TYPE,
|
|
25234
|
+
WEB_FUNCTION_REVISION_TYPE
|
|
25235
|
+
];
|
|
25236
|
+
var WebFunctionResolutionError = class WebFunctionResolutionError extends Error {
|
|
25237
|
+
constructor(message) {
|
|
25238
|
+
super(message);
|
|
25239
|
+
this.name = "WebFunctionResolutionError";
|
|
25240
|
+
Object.setPrototypeOf(this, WebFunctionResolutionError.prototype);
|
|
25241
|
+
}
|
|
25242
|
+
};
|
|
25243
|
+
function resolveWebFunctionTarget(target, stacks, revisionFlag) {
|
|
25244
|
+
if (stacks.length === 0) throw new WebFunctionResolutionError("No stacks found in the synthesized assembly.");
|
|
25245
|
+
const parsed = parseTarget(target);
|
|
25246
|
+
const stack = pickStack(parsed, stacks, target);
|
|
25247
|
+
const resources = stack.template.Resources ?? {};
|
|
25248
|
+
const { logicalId, resource } = matchWebResource(parsed, target, stack, resources);
|
|
25249
|
+
const functions = logicalIdsOfType(resources, WEB_FUNCTION_TYPE);
|
|
25250
|
+
const linked = (value) => linkedFunctionLogicalId(value, resources, functions);
|
|
25251
|
+
let functionLogicalId;
|
|
25252
|
+
let endpoint;
|
|
25253
|
+
let revisionLogicalId;
|
|
25254
|
+
let selection;
|
|
25255
|
+
if (resource.Type === "AWS::Lambda::WebFunctionRevision") {
|
|
25256
|
+
functionLogicalId = linked(resource.Properties?.["FunctionName"]);
|
|
25257
|
+
revisionLogicalId = logicalId;
|
|
25258
|
+
selection = "target-revision";
|
|
25259
|
+
} else if (resource.Type === "AWS::Lambda::WebFunctionEndpoint") {
|
|
25260
|
+
functionLogicalId = linked(resource.Properties?.["FunctionName"]);
|
|
25261
|
+
endpoint = readEndpoint(logicalId, resource, resources);
|
|
25262
|
+
} else functionLogicalId = logicalId;
|
|
25263
|
+
const revisionsOfFunction = () => functionLogicalId === void 0 ? [] : logicalIdsOfType(resources, WEB_FUNCTION_REVISION_TYPE).filter((id) => linked(resources[id]?.Properties?.["FunctionName"]) === functionLogicalId);
|
|
25264
|
+
const endpointsOfFunction = () => functionLogicalId === void 0 ? [] : logicalIdsOfType(resources, WEB_FUNCTION_ENDPOINT_TYPE).filter((id) => linked(resources[id]?.Properties?.["FunctionName"]) === functionLogicalId);
|
|
25265
|
+
if (revisionFlag !== void 0) {
|
|
25266
|
+
const flagged = resources[revisionFlag];
|
|
25267
|
+
if (!flagged || flagged.Type !== "AWS::Lambda::WebFunctionRevision") throw new WebFunctionResolutionError(`--revision ${displayIdent(revisionFlag)} is not an ${WEB_FUNCTION_REVISION_TYPE} logical id in ${displayStackName(stack.stackName)}. ${describeRevisions(revisionsOfFunction(), stack)}`);
|
|
25268
|
+
const owner = linked(flagged.Properties?.["FunctionName"]);
|
|
25269
|
+
if (functionLogicalId !== void 0 && owner !== functionLogicalId) throw new WebFunctionResolutionError(`--revision ${displayIdent(revisionFlag)} belongs to a different web function than ${displayIdent(logicalId)}. ${describeRevisions(revisionsOfFunction(), stack)}`);
|
|
25270
|
+
functionLogicalId ??= owner;
|
|
25271
|
+
revisionLogicalId = revisionFlag;
|
|
25272
|
+
selection = "revision-flag";
|
|
25273
|
+
}
|
|
25274
|
+
if (revisionLogicalId === void 0 && endpoint !== void 0) {
|
|
25275
|
+
revisionLogicalId = pickHighestWeight(endpoint);
|
|
25276
|
+
if (revisionLogicalId !== void 0) selection = "endpoint-weight";
|
|
25277
|
+
}
|
|
25278
|
+
if (revisionLogicalId === void 0) {
|
|
25279
|
+
const revisions = revisionsOfFunction();
|
|
25280
|
+
if (revisions.length === 1) {
|
|
25281
|
+
revisionLogicalId = revisions[0];
|
|
25282
|
+
selection = "only-revision";
|
|
25283
|
+
} else if (endpoint === void 0 && revisions.length > 1) {
|
|
25284
|
+
const endpoints = endpointsOfFunction();
|
|
25285
|
+
if (endpoints.length === 1) {
|
|
25286
|
+
endpoint = readEndpoint(endpoints[0], resources[endpoints[0]], resources);
|
|
25287
|
+
revisionLogicalId = pickHighestWeight(endpoint);
|
|
25288
|
+
if (revisionLogicalId !== void 0) selection = "endpoint-weight";
|
|
25289
|
+
}
|
|
25290
|
+
}
|
|
25291
|
+
if (revisionLogicalId === void 0) throw new WebFunctionResolutionError(revisions.length === 0 ? `${displayIdent(logicalId)} in ${displayStackName(stack.stackName)} resolves to no ${WEB_FUNCTION_REVISION_TYPE} in this template, so there is no code to serve. Target the revision itself, or pass --revision <logicalId>.` : `${displayIdent(logicalId)} has ${revisions.length} revisions and no single endpoint that picks one. Pass --revision <logicalId>, or target one of the function's endpoints. ${describeRevisions(revisions, stack)}`);
|
|
25292
|
+
}
|
|
25293
|
+
if (endpoint === void 0) {
|
|
25294
|
+
const routing = endpointsOfFunction().map((id) => readEndpoint(id, resources[id], resources)).filter((e) => e.weights.some((w) => w.revisionLogicalId === revisionLogicalId));
|
|
25295
|
+
if (routing.length === 1) endpoint = routing[0];
|
|
25296
|
+
}
|
|
25297
|
+
const fnName = (functionLogicalId !== void 0 ? resources[functionLogicalId] : void 0)?.Properties?.["FunctionName"];
|
|
25298
|
+
return {
|
|
25299
|
+
stack,
|
|
25300
|
+
functionLogicalId,
|
|
25301
|
+
functionName: typeof fnName === "string" && fnName.length > 0 ? fnName : functionLogicalId ?? revisionLogicalId,
|
|
25302
|
+
revisionLogicalId,
|
|
25303
|
+
revision: resources[revisionLogicalId],
|
|
25304
|
+
endpoint,
|
|
25305
|
+
selection: selection ?? "only-revision"
|
|
25306
|
+
};
|
|
25307
|
+
}
|
|
25308
|
+
function pickStack(parsed, stacks, target) {
|
|
25309
|
+
const selection = selectTargetStack(parsed, target, stacks);
|
|
25310
|
+
switch (selection.kind) {
|
|
25311
|
+
case "found": return selection.stack;
|
|
25312
|
+
case "no-prefix": throw new WebFunctionResolutionError(`Multiple stacks in app, target ${displayIdent(parsed.pathOrId)} is missing a stack prefix. Use StackName:<logicalId> or StackName/... (path form). Available stacks: ${describeStacks(stacks)}.`);
|
|
25313
|
+
case "not-found": throw new WebFunctionResolutionError(`Stack ${displayStackName(selection.pattern)} not found. Available stacks: ${describeStacks(stacks)}.`);
|
|
25314
|
+
case "ambiguous": throw new WebFunctionResolutionError(`Stack pattern ${displayStackName(selection.pattern)} matched ${selection.matched.length} stacks: ${describeStacks(selection.matched)}. Use a more specific pattern, or the stack's display path.`);
|
|
25315
|
+
}
|
|
25316
|
+
}
|
|
25317
|
+
function matchWebResource(parsed, target, stack, resources) {
|
|
25318
|
+
if (parsed.isPath) {
|
|
25319
|
+
const matches = resolveCdkPathToLogicalIds(parsed.pathOrId, buildCdkPathIndex(stack.template)).filter(({ logicalId }) => WEB_TYPES.includes(resources[logicalId]?.Type ?? ""));
|
|
25320
|
+
for (const type of WEB_TYPES) {
|
|
25321
|
+
const ofType = matches.filter(({ logicalId }) => resources[logicalId].Type === type);
|
|
25322
|
+
if (ofType.length === 1) {
|
|
25323
|
+
const id = ofType[0].logicalId;
|
|
25324
|
+
return {
|
|
25325
|
+
logicalId: id,
|
|
25326
|
+
resource: resources[id]
|
|
25327
|
+
};
|
|
25328
|
+
}
|
|
25329
|
+
if (ofType.length > 1) throw new WebFunctionResolutionError(`Target ${displayStackName(target)} matches ${ofType.length} ${type} resources: ${ofType.map((m) => displayIdent(m.logicalId)).join(", ")}. Refine the path or use the StackName:<logicalId> form.`);
|
|
25330
|
+
}
|
|
25331
|
+
throw notFoundError(target, stack, resources);
|
|
25332
|
+
}
|
|
25333
|
+
const resource = resources[parsed.pathOrId];
|
|
25334
|
+
if (!resource) throw notFoundError(target, stack, resources);
|
|
25335
|
+
if (!WEB_TYPES.includes(resource.Type)) throw new WebFunctionResolutionError(`Resource ${displayIdent(parsed.pathOrId)} in ${displayStackName(stack.stackName)} is ${displayIdent(resource.Type)}, not a Lambda web function. ${getEmbedConfig().cliName} start-web-function serves ${WEB_TYPES.join(" / ")} targets.`);
|
|
25336
|
+
return {
|
|
25337
|
+
logicalId: parsed.pathOrId,
|
|
25338
|
+
resource
|
|
25339
|
+
};
|
|
25340
|
+
}
|
|
25341
|
+
function notFoundError(target, stack, resources) {
|
|
25342
|
+
const available = WEB_TYPES.flatMap((t) => logicalIdsOfType(resources, t));
|
|
25343
|
+
const hint = available.length > 0 ? `Web function resources in ${displayStackName(stack.stackName)}: ${available.map((id) => displayIdent(id)).join(", ")}.` : `No ${WEB_FUNCTION_TYPE} resources found in ${displayStackName(stack.stackName)}.`;
|
|
25344
|
+
return new WebFunctionResolutionError(`Target ${displayStackName(target)} not found. ${hint}`);
|
|
25345
|
+
}
|
|
25346
|
+
function logicalIdsOfType(resources, type) {
|
|
25347
|
+
return Object.keys(resources).filter((id) => resources[id]?.Type === type);
|
|
25348
|
+
}
|
|
25349
|
+
function linkedFunctionLogicalId(value, resources, functions) {
|
|
25350
|
+
const ref = referencedLogicalId(value);
|
|
25351
|
+
if (ref !== void 0) return functions.includes(ref) ? ref : void 0;
|
|
25352
|
+
if (typeof value !== "string") return void 0;
|
|
25353
|
+
const byName = functions.filter((id) => resources[id]?.Properties?.["FunctionName"] === value);
|
|
25354
|
+
return byName.length === 1 ? byName[0] : void 0;
|
|
25355
|
+
}
|
|
25356
|
+
function referencedLogicalId(value) {
|
|
25357
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
25358
|
+
const obj = value;
|
|
25359
|
+
if (typeof obj["Ref"] === "string") return obj["Ref"];
|
|
25360
|
+
const getAtt = obj["Fn::GetAtt"];
|
|
25361
|
+
if (Array.isArray(getAtt) && typeof getAtt[0] === "string") return getAtt[0];
|
|
25362
|
+
if (typeof getAtt === "string") return getAtt.split(".")[0];
|
|
25363
|
+
}
|
|
25364
|
+
function readEndpoint(logicalId, resource, resources) {
|
|
25365
|
+
const props = resource.Properties ?? {};
|
|
25366
|
+
const rawWeights = props["RevisionWeights"];
|
|
25367
|
+
const weights = [];
|
|
25368
|
+
if (Array.isArray(rawWeights)) for (const entry of rawWeights) {
|
|
25369
|
+
if (!entry || typeof entry !== "object") continue;
|
|
25370
|
+
const e = entry;
|
|
25371
|
+
const ref = referencedLogicalId(e["RevisionId"]);
|
|
25372
|
+
weights.push({
|
|
25373
|
+
revisionLogicalId: ref !== void 0 && resources[ref]?.Type === "AWS::Lambda::WebFunctionRevision" ? ref : void 0,
|
|
25374
|
+
weight: typeof e["Weight"] === "number" ? e["Weight"] : 0
|
|
25375
|
+
});
|
|
25376
|
+
}
|
|
25377
|
+
const str = (v) => typeof v === "string" ? v : void 0;
|
|
25378
|
+
return {
|
|
25379
|
+
logicalId,
|
|
25380
|
+
endpointType: str(props["EndpointType"]),
|
|
25381
|
+
authType: str(props["AuthType"]),
|
|
25382
|
+
weights
|
|
25383
|
+
};
|
|
25384
|
+
}
|
|
25385
|
+
function pickHighestWeight(endpoint) {
|
|
25386
|
+
let best;
|
|
25387
|
+
for (const w of endpoint.weights) {
|
|
25388
|
+
if (w.revisionLogicalId === void 0) continue;
|
|
25389
|
+
if (best === void 0 || w.weight > best.weight) best = w;
|
|
25390
|
+
}
|
|
25391
|
+
return best?.revisionLogicalId;
|
|
25392
|
+
}
|
|
25393
|
+
function describeRevisions(revisions, stack) {
|
|
25394
|
+
return revisions.length > 0 ? `Revisions: ${revisions.map((id) => displayIdent(id)).join(", ")}.` : `No ${WEB_FUNCTION_REVISION_TYPE} linked to it in ${displayStackName(stack.stackName)}.`;
|
|
25395
|
+
}
|
|
25396
|
+
|
|
25397
|
+
//#endregion
|
|
25398
|
+
//#region src/local/web-function-artifact.ts
|
|
25399
|
+
const SUPPORTED_CODE_CONFIG_KEYS = ["S3Object"];
|
|
25400
|
+
function parseWebFunctionBuildConfig(revisionLogicalId, buildConfig) {
|
|
25401
|
+
const subject = `Web function revision ${displayIdent(revisionLogicalId)}`;
|
|
25402
|
+
const build = asObject$1(buildConfig);
|
|
25403
|
+
const runtime = asObject$1(build?.["RuntimeConfig"])?.["Runtime"];
|
|
25404
|
+
if (typeof runtime !== "string" || runtime.length === 0) throw new CdkLocalError(`${subject} has no literal BuildConfig.RuntimeConfig.Runtime.`, "LOCAL_START_WEB_FUNCTION_NO_RUNTIME");
|
|
25405
|
+
const codeConfig = asObject$1(build?.["CodeConfig"]);
|
|
25406
|
+
if (!codeConfig) throw new CdkLocalError(`${subject} has no BuildConfig.CodeConfig object.`, "LOCAL_START_WEB_FUNCTION_NO_CODE_CONFIG");
|
|
25407
|
+
const unknownKeys = Object.keys(codeConfig).filter((k) => !SUPPORTED_CODE_CONFIG_KEYS.includes(k));
|
|
25408
|
+
if (unknownKeys.length > 0) throw new CdkLocalError(`${subject} uses BuildConfig.CodeConfig.${unknownKeys.map((k) => displayIdent(k)).join(", ")}, which ${getEmbedConfig().cliName} start-web-function does not support yet. Supported: ${SUPPORTED_CODE_CONFIG_KEYS.join(", ")}.`, "LOCAL_START_WEB_FUNCTION_UNSUPPORTED_CODE_CONFIG");
|
|
25409
|
+
const s3 = asObject$1(codeConfig["S3Object"]);
|
|
25410
|
+
if (!s3) throw new CdkLocalError(`${subject} has no BuildConfig.CodeConfig.S3Object.`, "LOCAL_START_WEB_FUNCTION_NO_CODE_CONFIG");
|
|
25411
|
+
const key = s3["Key"];
|
|
25412
|
+
if (typeof key !== "string" || key.length === 0) throw new CdkLocalError(`${subject} has a CodeConfig.S3Object.Key that is not a literal string (${describeValue(key)}). The code must come from a CDK asset in this app (for example an s3assets.Asset passing asset.s3BucketName / asset.s3ObjectKey), whose key synthesizes as a literal.`, "LOCAL_START_WEB_FUNCTION_CODE_KEY_NOT_LITERAL");
|
|
25413
|
+
const versionId = s3["VersionId"];
|
|
25414
|
+
return {
|
|
25415
|
+
runtime,
|
|
25416
|
+
s3Object: {
|
|
25417
|
+
bucket: s3["Bucket"],
|
|
25418
|
+
key,
|
|
25419
|
+
...typeof versionId === "string" && { versionId }
|
|
25420
|
+
}
|
|
25421
|
+
};
|
|
25422
|
+
}
|
|
25423
|
+
function findFileAssetForObjectKey(manifest, key) {
|
|
25424
|
+
for (const [hash, asset] of Object.entries(manifest.files ?? {})) for (const dest of Object.values(asset.destinations ?? {})) if (dest.objectKey === key || dest.objectKey.endsWith(`/${key}`)) return {
|
|
25425
|
+
hash,
|
|
25426
|
+
asset
|
|
25427
|
+
};
|
|
25428
|
+
const hash = key.replace(/^.*\//, "").replace(/\.zip$/, "");
|
|
25429
|
+
const byHash = Object.hasOwn(manifest.files ?? {}, hash) ? manifest.files[hash] : void 0;
|
|
25430
|
+
return byHash ? {
|
|
25431
|
+
hash,
|
|
25432
|
+
asset: byHash
|
|
25433
|
+
} : void 0;
|
|
25434
|
+
}
|
|
25435
|
+
async function resolveWebFunctionArtifact(stack, revisionLogicalId, code, loader = new AssetManifestLoader()) {
|
|
25436
|
+
const subject = `Web function revision ${displayUntrustedValue(revisionLogicalId)} code bundle`;
|
|
25437
|
+
const notFound = () => new CdkLocalError(`${subject} (S3Object bucket ${describeValue(code.s3Object.bucket)}, key ${displayUntrustedValue(code.s3Object.key)}) matches no file asset in this app's cdk.out. ${getEmbedConfig().cliName} start-web-function runs code that comes from a CDK asset in this app (for example an s3assets.Asset of a directory); it does not download deployed code. Re-synthesize the app, or point the revision at an asset.`, "LOCAL_START_WEB_FUNCTION_CODE_ASSET_NOT_FOUND");
|
|
25438
|
+
const manifestPath = stack.assetManifestPath;
|
|
25439
|
+
if (!manifestPath) throw notFound();
|
|
25440
|
+
const manifestDir = dirname$1(manifestPath);
|
|
25441
|
+
const manifest = await loader.loadStackManifest(stack, manifestDir);
|
|
25442
|
+
const match = manifest ? findFileAssetForObjectKey(manifest, code.s3Object.key) : void 0;
|
|
25443
|
+
if (!match) throw notFound();
|
|
25444
|
+
if (typeof match.asset.source.path !== "string" || match.asset.source.path.length === 0) throw new CdkLocalError(`${subject} matches file asset ${displayIdent(match.hash)}, which has no source.path (it is produced by source.executable at publish time), so there is no staged bundle in cdk.out to mount. Give the revision an asset of a directory or a .zip file (for example s3assets.Asset with path: '<dir>').`, "LOCAL_START_WEB_FUNCTION_CODE_ASSET_NO_PATH");
|
|
25445
|
+
const sourcePath = resolveAssetSourcePath({
|
|
25446
|
+
manifestDir,
|
|
25447
|
+
value: match.asset.source.path,
|
|
25448
|
+
assetOutdir: assetPathDirs(stack).assetOutdir,
|
|
25449
|
+
absolute: "honour-warn",
|
|
25450
|
+
field: "source.path",
|
|
25451
|
+
subject,
|
|
25452
|
+
action: "mount it",
|
|
25453
|
+
sink: "bind-mount that directory into the web function container",
|
|
25454
|
+
wrapError: (message) => new CdkLocalError(message, "LOCAL_START_WEB_FUNCTION_CODE_SOURCE_ESCAPES_ASSEMBLY")
|
|
25455
|
+
});
|
|
25456
|
+
if (!existsSync$1(sourcePath)) throw new CdkLocalError(`${subject} source ${displayUntrustedValue(sourcePath)} does not exist. Re-synthesize the app and retry.`, "LOCAL_START_WEB_FUNCTION_CODE_SOURCE_MISSING");
|
|
25457
|
+
if (!statSync$1(sourcePath).isDirectory() && !sourcePath.endsWith(".zip")) throw new CdkLocalError(`${subject} source ${displayUntrustedValue(sourcePath)} is neither a directory nor a .zip archive, so it is not a code bundle.`, "LOCAL_START_WEB_FUNCTION_CODE_SOURCE_NOT_BUNDLE");
|
|
25458
|
+
const materialized = materializeAssetCodeDir(sourcePath);
|
|
25459
|
+
return {
|
|
25460
|
+
kind: "zip",
|
|
25461
|
+
runtime: code.runtime,
|
|
25462
|
+
codeDir: materialized.dir,
|
|
25463
|
+
...materialized.tmpDir !== void 0 && { tmpDir: materialized.tmpDir },
|
|
25464
|
+
assetHash: match.hash
|
|
25465
|
+
};
|
|
25466
|
+
}
|
|
25467
|
+
function disposeWebFunctionArtifact(artifact) {
|
|
25468
|
+
if (artifact?.kind !== "zip" || artifact.tmpDir === void 0) return;
|
|
25469
|
+
try {
|
|
25470
|
+
if (existsSync$1(artifact.tmpDir)) rmSync$1(artifact.tmpDir, {
|
|
25471
|
+
recursive: true,
|
|
25472
|
+
force: true
|
|
25473
|
+
});
|
|
25474
|
+
} catch {}
|
|
25475
|
+
}
|
|
25476
|
+
function asObject$1(value) {
|
|
25477
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
25478
|
+
}
|
|
25479
|
+
function describeValue(value) {
|
|
25480
|
+
if (typeof value === "string") return displayUntrustedValue(value);
|
|
25481
|
+
let json;
|
|
25482
|
+
try {
|
|
25483
|
+
json = JSON.stringify(value);
|
|
25484
|
+
} catch {
|
|
25485
|
+
json = void 0;
|
|
25486
|
+
}
|
|
25487
|
+
return displayUntrustedValue(json ?? String(value));
|
|
25488
|
+
}
|
|
25489
|
+
|
|
25490
|
+
//#endregion
|
|
25491
|
+
//#region src/local/web-function-runtime.ts
|
|
25492
|
+
const NODE_CODE_MOUNT = "/var/task";
|
|
25493
|
+
const NODE_ENTRYPOINT_ENV = "AWS_LAMBDA_NODEJS_ENTRYPOINT";
|
|
25494
|
+
const NODE_DEFAULT_ENTRY = "index.js";
|
|
25495
|
+
function buildNodeEntryFileStart(runtime, env, codeDir, fileExists = existsSync$1) {
|
|
25496
|
+
const configured = env[NODE_ENTRYPOINT_ENV];
|
|
25497
|
+
const entryFile = configured !== void 0 && configured.length > 0 ? configured : NODE_DEFAULT_ENTRY;
|
|
25498
|
+
const hostPath = resolve$1(codeDir, entryFile);
|
|
25499
|
+
const rel = relative$1(codeDir, hostPath);
|
|
25500
|
+
if (isAbsolute$1(entryFile) || rel === "" || rel === ".." || rel.startsWith(`..${sep$1}`) || isAbsolute$1(rel)) throw new CdkLocalError(`${NODE_ENTRYPOINT_ENV}=${displayUntrustedValue(entryFile)} must name a file inside the code bundle, relative to its root.`, "LOCAL_START_WEB_FUNCTION_ENTRYPOINT_OUTSIDE_BUNDLE");
|
|
25501
|
+
if (!fileExists(hostPath)) throw new CdkLocalError(`The ${runtime} web function entry file ${displayUntrustedValue(entryFile)} was not found in the code bundle ${displayUntrustedValue(codeDir)}. The runtime loads ${NODE_DEFAULT_ENTRY} from the package root unless ${NODE_ENTRYPOINT_ENV} names another file.`, "LOCAL_START_WEB_FUNCTION_ENTRYPOINT_MISSING");
|
|
25502
|
+
const posixRel = sep$1 === "\\" ? rel.split("\\").join("/") : rel;
|
|
25503
|
+
return {
|
|
25504
|
+
entryPoint: ["/var/lang/bin/node"],
|
|
25505
|
+
cmd: [posix.join(NODE_CODE_MOUNT, posixRel)],
|
|
25506
|
+
label: entryFile
|
|
25507
|
+
};
|
|
25508
|
+
}
|
|
25509
|
+
const WEB_FUNCTION_RUNTIMES = { "nodejs24.x": {
|
|
25510
|
+
runtime: "nodejs24.x",
|
|
25511
|
+
baseImage: "public.ecr.aws/lambda/nodejs:24",
|
|
25512
|
+
codeMountPath: NODE_CODE_MOUNT,
|
|
25513
|
+
architectures: ["arm64"],
|
|
25514
|
+
buildStart: (env, codeDir, deps) => buildNodeEntryFileStart("nodejs24.x", env, codeDir, deps?.fileExists)
|
|
25515
|
+
} };
|
|
25516
|
+
function supportedWebFunctionRuntimes(table = WEB_FUNCTION_RUNTIMES) {
|
|
25517
|
+
return Object.keys(table).sort();
|
|
25518
|
+
}
|
|
25519
|
+
function resolveWebFunctionRuntime(runtime, table = WEB_FUNCTION_RUNTIMES) {
|
|
25520
|
+
const spec = Object.hasOwn(table, runtime) ? table[runtime] : void 0;
|
|
25521
|
+
if (!spec) throw new CdkLocalError(`Web function runtime ${displayIdent(runtime)} is not supported by ${getEmbedConfig().cliName} start-web-function yet. Supported: ${supportedWebFunctionRuntimes(table).join(", ")}.`, "LOCAL_START_WEB_FUNCTION_UNSUPPORTED_RUNTIME");
|
|
25522
|
+
return spec;
|
|
25523
|
+
}
|
|
25524
|
+
function defaultWebFunctionPlatform(spec) {
|
|
25525
|
+
return spec.architectures[0] === "x86_64" ? "linux/amd64" : "linux/arm64";
|
|
25526
|
+
}
|
|
25527
|
+
|
|
25528
|
+
//#endregion
|
|
25529
|
+
//#region src/local/web-function-service-config.ts
|
|
25530
|
+
const WEB_FUNCTION_HTTP_ENDPOINT_ENV = "AWS_LAMBDA_HTTP_ENDPOINT";
|
|
25531
|
+
const APPLICATION_MANAGED_AUTH = "ApplicationManaged";
|
|
25532
|
+
const HOME_REGION_ENDPOINT = "HomeRegion";
|
|
25533
|
+
function readWebFunctionServiceConfig(revision) {
|
|
25534
|
+
const sc = asObject(revision.Properties?.["ServiceConfig"]) ?? {};
|
|
25535
|
+
const envRaw = sc["EnvironmentVariables"];
|
|
25536
|
+
const envObj = asObject(envRaw);
|
|
25537
|
+
const envKeys = envObj ? Object.keys(envObj) : [];
|
|
25538
|
+
const env = envKeys.length === 1 && (envKeys[0] === "Ref" || envKeys[0].startsWith("Fn::")) ? void 0 : envObj;
|
|
25539
|
+
const logGroup = asObject(asObject(sc["TelemetryConfig"])?.["LoggingConfig"])?.["LogGroup"];
|
|
25540
|
+
return {
|
|
25541
|
+
environmentVariables: env,
|
|
25542
|
+
environmentUnreadable: envRaw !== void 0 && env === void 0,
|
|
25543
|
+
executionRoleArn: sc["ExecutionRoleArn"],
|
|
25544
|
+
egressNetworkConnectorArn: sc["EgressNetworkConnectorArn"],
|
|
25545
|
+
timeoutSeconds: typeof sc["TimeoutSeconds"] === "number" ? sc["TimeoutSeconds"] : void 0,
|
|
25546
|
+
logGroup: typeof logGroup === "string" && logGroup.length > 0 ? logGroup : void 0
|
|
25547
|
+
};
|
|
25548
|
+
}
|
|
25549
|
+
function buildWebFunctionLambdaView(resolved, config, runtime) {
|
|
25550
|
+
return {
|
|
25551
|
+
kind: "zip",
|
|
25552
|
+
stack: resolved.stack,
|
|
25553
|
+
logicalId: resolved.revisionLogicalId,
|
|
25554
|
+
resource: {
|
|
25555
|
+
Type: resolved.revision.Type,
|
|
25556
|
+
Properties: {
|
|
25557
|
+
...config.environmentVariables !== void 0 && { Environment: { Variables: config.environmentVariables } },
|
|
25558
|
+
...config.executionRoleArn !== void 0 && { Role: config.executionRoleArn }
|
|
25559
|
+
},
|
|
25560
|
+
...resolved.revision.Metadata !== void 0 && { Metadata: resolved.revision.Metadata }
|
|
25561
|
+
},
|
|
25562
|
+
memoryMb: 128,
|
|
25563
|
+
timeoutSec: config.timeoutSeconds ?? 0,
|
|
25564
|
+
layers: [],
|
|
25565
|
+
runtime,
|
|
25566
|
+
handler: "",
|
|
25567
|
+
codePath: null,
|
|
25568
|
+
architecture: "arm64"
|
|
25569
|
+
};
|
|
25570
|
+
}
|
|
25571
|
+
function webFunctionAssumeRole(assumeRole, config) {
|
|
25572
|
+
if (assumeRole === true && isIamRoleArn(config.executionRoleArn)) return config.executionRoleArn;
|
|
25573
|
+
return assumeRole;
|
|
25574
|
+
}
|
|
25575
|
+
function finalizeWebFunctionEnv(lambdaEnv, opts) {
|
|
25576
|
+
const env = { ...lambdaEnv };
|
|
25577
|
+
delete env["AWS_LAMBDA_FUNCTION_MEMORY_SIZE"];
|
|
25578
|
+
delete env["AWS_LAMBDA_FUNCTION_VERSION"];
|
|
25579
|
+
delete env["AWS_LAMBDA_FUNCTION_TIMEOUT"];
|
|
25580
|
+
env["AWS_LAMBDA_FUNCTION_NAME"] = opts.functionName;
|
|
25581
|
+
env["AWS_LAMBDA_LOG_GROUP_NAME"] = opts.logGroup ?? `/aws/lambda/${opts.functionName}`;
|
|
25582
|
+
if (opts.timeoutSeconds !== void 0) env["AWS_LAMBDA_FUNCTION_TIMEOUT"] = String(opts.timeoutSeconds);
|
|
25583
|
+
const replacedHttpEndpoint = Object.hasOwn(lambdaEnv, WEB_FUNCTION_HTTP_ENDPOINT_ENV);
|
|
25584
|
+
env[WEB_FUNCTION_HTTP_ENDPOINT_ENV] = `0.0.0.0:${opts.containerPort}`;
|
|
25585
|
+
return {
|
|
25586
|
+
env,
|
|
25587
|
+
replacedHttpEndpoint
|
|
25588
|
+
};
|
|
25589
|
+
}
|
|
25590
|
+
function webFunctionFidelityWarnings(resolved, config) {
|
|
25591
|
+
const out = [];
|
|
25592
|
+
const rev = displayIdent(resolved.revisionLogicalId);
|
|
25593
|
+
if (config.egressNetworkConnectorArn !== void 0) out.push(`Revision ${rev} sets ServiceConfig.EgressNetworkConnectorArn; the network connector is not emulated, so the container reaches the network through Docker's default bridge.`);
|
|
25594
|
+
if (config.environmentUnreadable) out.push(`Revision ${rev} declares ServiceConfig.EnvironmentVariables as an intrinsic rather than a map; none of its variables reach the container. Supply them with --env-vars.`);
|
|
25595
|
+
const endpoint = resolved.endpoint;
|
|
25596
|
+
if (endpoint) {
|
|
25597
|
+
const ep = displayIdent(endpoint.logicalId);
|
|
25598
|
+
if (endpoint.endpointType !== void 0 && endpoint.endpointType !== "HomeRegion") out.push(`Endpoint ${ep} has EndpointType ${displayIdent(endpoint.endpointType)}; only a single ${HOME_REGION_ENDPOINT} endpoint is reproduced, on one local port.`);
|
|
25599
|
+
if (endpoint.authType !== void 0 && endpoint.authType !== "ApplicationManaged") out.push(`Endpoint ${ep} has AuthType ${displayIdent(endpoint.authType)}; it is not enforced locally — every request reaches the server unauthenticated.`);
|
|
25600
|
+
const routed = endpoint.weights.filter((w) => w.weight > 0);
|
|
25601
|
+
if (routed.length > 1) out.push(`Endpoint ${ep} splits traffic across ${routed.length} revisions; weighted routing is not emulated — every request goes to revision ${rev}.`);
|
|
25602
|
+
}
|
|
25603
|
+
return out;
|
|
25604
|
+
}
|
|
25605
|
+
function asObject(value) {
|
|
25606
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
25607
|
+
}
|
|
25608
|
+
|
|
25609
|
+
//#endregion
|
|
25610
|
+
//#region src/local/web-function-runner.ts
|
|
25611
|
+
const execFileAsync = promisify$1(execFile$1);
|
|
25612
|
+
const WEB_FUNCTION_CONTAINER_PORT = 8080;
|
|
25613
|
+
const READY_FAILURE_LOG_LINES = 20;
|
|
25614
|
+
const MAX_PROBE_TIMEOUT_MS = 1e4;
|
|
25615
|
+
function planWebFunctionContainer(artifact, spec, env, deps) {
|
|
25616
|
+
if (artifact.kind !== "zip") throw new CdkLocalError("A container-image web function source is not supported yet; only a zip bundle from CodeConfig.S3Object runs locally.", "LOCAL_START_WEB_FUNCTION_UNSUPPORTED_ARTIFACT");
|
|
25617
|
+
const start = spec.buildStart(env, artifact.codeDir, deps);
|
|
25618
|
+
return {
|
|
25619
|
+
image: spec.baseImage,
|
|
25620
|
+
mounts: [{
|
|
25621
|
+
hostPath: artifact.codeDir,
|
|
25622
|
+
containerPath: spec.codeMountPath,
|
|
25623
|
+
readOnly: true
|
|
25624
|
+
}],
|
|
25625
|
+
entryPoint: start.entryPoint,
|
|
25626
|
+
cmd: start.cmd,
|
|
25627
|
+
workingDir: spec.codeMountPath,
|
|
25628
|
+
label: start.label
|
|
25629
|
+
};
|
|
25630
|
+
}
|
|
25631
|
+
async function startWebFunctionContainer(opts) {
|
|
25632
|
+
const { plan } = opts;
|
|
25633
|
+
return runDetached({
|
|
25634
|
+
image: plan.image,
|
|
25635
|
+
mounts: plan.mounts,
|
|
25636
|
+
env: opts.env,
|
|
25637
|
+
...opts.sensitiveEnvKeys.size > 0 && { sensitiveEnvKeys: opts.sensitiveEnvKeys },
|
|
25638
|
+
entryPoint: plan.entryPoint,
|
|
25639
|
+
cmd: plan.cmd,
|
|
25640
|
+
...plan.workingDir !== void 0 && { workingDir: plan.workingDir },
|
|
25641
|
+
hostPort: opts.hostPort,
|
|
25642
|
+
containerPort: WEB_FUNCTION_CONTAINER_PORT,
|
|
25643
|
+
host: opts.host,
|
|
25644
|
+
platform: opts.platform,
|
|
25645
|
+
name: opts.name,
|
|
25646
|
+
autoRemove: false
|
|
25647
|
+
});
|
|
25648
|
+
}
|
|
25649
|
+
var RecentOutput = class {
|
|
25650
|
+
lines = [];
|
|
25651
|
+
partial = "";
|
|
25652
|
+
max;
|
|
25653
|
+
constructor(max = 20) {
|
|
25654
|
+
this.max = max;
|
|
25655
|
+
}
|
|
25656
|
+
push(chunk) {
|
|
25657
|
+
const parts = (this.partial + chunk.toString()).split("\n");
|
|
25658
|
+
this.partial = parts.pop() ?? "";
|
|
25659
|
+
for (const line of parts) this.add(line);
|
|
25660
|
+
if (this.partial.length > 4096) {
|
|
25661
|
+
this.add(this.partial);
|
|
25662
|
+
this.partial = "";
|
|
25663
|
+
}
|
|
25664
|
+
}
|
|
25665
|
+
tail() {
|
|
25666
|
+
return this.partial.length > 0 ? [...this.lines, this.partial].slice(-this.max) : this.lines;
|
|
25667
|
+
}
|
|
25668
|
+
add(line) {
|
|
25669
|
+
this.lines.push(line.replace(/\r$/, ""));
|
|
25670
|
+
if (this.lines.length > this.max) this.lines.shift();
|
|
25671
|
+
}
|
|
25672
|
+
};
|
|
25673
|
+
async function waitForWebFunctionReady(args, deps = defaultReadyDeps) {
|
|
25674
|
+
const deadline = deps.now() + args.timeoutMs;
|
|
25675
|
+
let attempt = 0;
|
|
25676
|
+
let last = "refused";
|
|
25677
|
+
while (deps.now() < deadline) {
|
|
25678
|
+
const remaining = Math.max(1, deadline - deps.now());
|
|
25679
|
+
last = await deps.probe(args.host, args.port, Math.min(remaining, MAX_PROBE_TIMEOUT_MS));
|
|
25680
|
+
if (last === "answered") return;
|
|
25681
|
+
attempt++;
|
|
25682
|
+
if (attempt % 4 === 0 && !await deps.isRunning(args.containerId)) throw await containerFailure(`The web function container exited before its server listened on AWS_LAMBDA_HTTP_ENDPOINT (started ${args.label}).`, args.containerId, args.recent, deps.fetchLogs);
|
|
25683
|
+
if (last === "refused") await deps.sleep(250);
|
|
25684
|
+
}
|
|
25685
|
+
const authority = formatAuthority(args.host, args.port);
|
|
25686
|
+
throw await containerFailure(last === "timeout" ? `The web function server on ${authority} accepted the connection but did not answer GET / within ${args.timeoutMs}ms — it is listening but slow to respond. Raise --timeout, or make / answer sooner (started ${args.label}).` : `The web function server never accepted an HTTP connection on ${authority} within ${args.timeoutMs}ms. It must listen on the host:port given in AWS_LAMBDA_HTTP_ENDPOINT (started ${args.label}).`, args.containerId, args.recent, deps.fetchLogs);
|
|
25687
|
+
}
|
|
25688
|
+
async function containerFailure(message, containerId, recent, fetchLogs = readContainerLogTail, code = "LOCAL_START_WEB_FUNCTION_NOT_READY") {
|
|
25689
|
+
let lines = [];
|
|
25690
|
+
try {
|
|
25691
|
+
lines = await fetchLogs(containerId, 20);
|
|
25692
|
+
} catch {
|
|
25693
|
+
lines = [];
|
|
25694
|
+
}
|
|
25695
|
+
if (lines.length === 0) lines = recent.tail();
|
|
25696
|
+
return new CdkLocalError(`${message}${lines.length > 0 ? ` Last ${lines.length} line(s) of container output:\n${lines.map((l) => ` ${displayToolOutput(l)}`).join("\n")}` : " The container printed nothing."}`, code);
|
|
25697
|
+
}
|
|
25698
|
+
function watchContainerExit(containerId) {
|
|
25699
|
+
let stopped = false;
|
|
25700
|
+
const proc = spawn$1(getDockerCmd(), ["wait", containerId], { stdio: [
|
|
25701
|
+
"ignore",
|
|
25702
|
+
"pipe",
|
|
25703
|
+
"ignore"
|
|
25704
|
+
] });
|
|
25705
|
+
let out = "";
|
|
25706
|
+
proc.stdout?.on("data", (c) => out += c.toString());
|
|
25707
|
+
return {
|
|
25708
|
+
exited: new Promise((resolveExit) => {
|
|
25709
|
+
const done = () => {
|
|
25710
|
+
if (stopped) return;
|
|
25711
|
+
const code = Number.parseInt(out.trim(), 10);
|
|
25712
|
+
resolveExit(Number.isNaN(code) ? void 0 : code);
|
|
25713
|
+
};
|
|
25714
|
+
proc.on("close", done);
|
|
25715
|
+
proc.on("error", done);
|
|
25716
|
+
}),
|
|
25717
|
+
stop: () => {
|
|
25718
|
+
stopped = true;
|
|
25719
|
+
if (!proc.killed) proc.kill("SIGTERM");
|
|
25720
|
+
}
|
|
25721
|
+
};
|
|
25722
|
+
}
|
|
25723
|
+
function probeHttp(host, port, timeoutMs) {
|
|
25724
|
+
return new Promise((resolveProbe) => {
|
|
25725
|
+
let timedOut = false;
|
|
25726
|
+
let connected = false;
|
|
25727
|
+
const req = request$2({
|
|
25728
|
+
host,
|
|
25729
|
+
port,
|
|
25730
|
+
path: "/",
|
|
25731
|
+
method: "GET",
|
|
25732
|
+
timeout: timeoutMs,
|
|
25733
|
+
headers: { connection: "close" }
|
|
25734
|
+
}, (res) => {
|
|
25735
|
+
res.resume();
|
|
25736
|
+
resolveProbe("answered");
|
|
25737
|
+
});
|
|
25738
|
+
req.on("socket", (socket) => {
|
|
25739
|
+
socket.once("connect", () => {
|
|
25740
|
+
connected = true;
|
|
25741
|
+
});
|
|
25742
|
+
});
|
|
25743
|
+
req.on("timeout", () => {
|
|
25744
|
+
timedOut = true;
|
|
25745
|
+
req.destroy();
|
|
25746
|
+
});
|
|
25747
|
+
req.on("error", () => resolveProbe(timedOut && connected ? "timeout" : "refused"));
|
|
25748
|
+
req.end();
|
|
25749
|
+
});
|
|
25750
|
+
}
|
|
25751
|
+
async function containerIsRunning(containerId) {
|
|
25752
|
+
try {
|
|
25753
|
+
const { stdout } = await execFileAsync(getDockerCmd(), [
|
|
25754
|
+
"inspect",
|
|
25755
|
+
"-f",
|
|
25756
|
+
"{{.State.Running}}",
|
|
25757
|
+
containerId
|
|
25758
|
+
]);
|
|
25759
|
+
return stdout.trim() === "true";
|
|
25760
|
+
} catch {
|
|
25761
|
+
return false;
|
|
25762
|
+
}
|
|
25763
|
+
}
|
|
25764
|
+
function readContainerLogTail(containerId, lines, spawnFn = spawn$1) {
|
|
25765
|
+
return new Promise((resolveLogs, rejectLogs) => {
|
|
25766
|
+
const proc = spawnFn(getDockerCmd(), [
|
|
25767
|
+
"logs",
|
|
25768
|
+
"--tail",
|
|
25769
|
+
String(lines),
|
|
25770
|
+
containerId
|
|
25771
|
+
], { stdio: [
|
|
25772
|
+
"ignore",
|
|
25773
|
+
"pipe",
|
|
25774
|
+
"pipe"
|
|
25775
|
+
] });
|
|
25776
|
+
const chunks = [];
|
|
25777
|
+
let size = 0;
|
|
25778
|
+
const take = (c) => {
|
|
25779
|
+
if (size > 4 * 1024 * 1024) return;
|
|
25780
|
+
chunks.push(c);
|
|
25781
|
+
size += c.length;
|
|
25782
|
+
};
|
|
25783
|
+
proc.stdout?.on("data", take);
|
|
25784
|
+
proc.stderr?.on("data", take);
|
|
25785
|
+
proc.on("error", rejectLogs);
|
|
25786
|
+
proc.on("close", (code) => {
|
|
25787
|
+
if (code !== 0) {
|
|
25788
|
+
rejectLogs(/* @__PURE__ */ new Error(`docker logs exited ${code}`));
|
|
25789
|
+
return;
|
|
25790
|
+
}
|
|
25791
|
+
resolveLogs(Buffer.concat(chunks).toString().split("\n").map((l) => l.replace(/\r$/, "")).filter((l) => l.length > 0).slice(-lines));
|
|
25792
|
+
});
|
|
25793
|
+
});
|
|
25794
|
+
}
|
|
25795
|
+
const defaultReadyDeps = {
|
|
25796
|
+
probe: probeHttp,
|
|
25797
|
+
isRunning: containerIsRunning,
|
|
25798
|
+
fetchLogs: readContainerLogTail,
|
|
25799
|
+
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
25800
|
+
now: () => Date.now()
|
|
25801
|
+
};
|
|
25802
|
+
|
|
25803
|
+
//#endregion
|
|
25804
|
+
//#region src/cli/commands/local-start-web-function.ts
|
|
25805
|
+
function parsePort(raw) {
|
|
25806
|
+
const n = Number(raw);
|
|
25807
|
+
if (!Number.isInteger(n) || n < 0 || n > 65535) throw new InvalidArgumentError(`--port must be an integer 0-65535, got '${raw}'.`);
|
|
25808
|
+
return n;
|
|
25809
|
+
}
|
|
25810
|
+
function connectHost(host) {
|
|
25811
|
+
if (host === "0.0.0.0") return "127.0.0.1";
|
|
25812
|
+
if (host === "::" || host === "[::]") return "::1";
|
|
25813
|
+
return host;
|
|
25814
|
+
}
|
|
25815
|
+
async function localStartWebFunctionCommand(target, options, extraStateProviders, hostSynthesizer) {
|
|
25816
|
+
const logger = getLogger();
|
|
25817
|
+
if (options.verbose) logger.setLevel("debug");
|
|
25818
|
+
let containerId;
|
|
25819
|
+
let stopLogs;
|
|
25820
|
+
let exitWatch;
|
|
25821
|
+
let artifact;
|
|
25822
|
+
let runInFlight;
|
|
25823
|
+
let teardownPromise;
|
|
25824
|
+
let shuttingDown = false;
|
|
25825
|
+
let waitingOnRun = false;
|
|
25826
|
+
let containerName;
|
|
25827
|
+
const forever = () => new Promise(() => void 0);
|
|
25828
|
+
const doTeardown = async () => {
|
|
25829
|
+
exitWatch?.stop();
|
|
25830
|
+
if (containerId === void 0 && runInFlight !== void 0) {
|
|
25831
|
+
waitingOnRun = true;
|
|
25832
|
+
try {
|
|
25833
|
+
containerId = await runInFlight;
|
|
25834
|
+
} catch {} finally {
|
|
25835
|
+
waitingOnRun = false;
|
|
25836
|
+
}
|
|
25837
|
+
}
|
|
25838
|
+
if (stopLogs) try {
|
|
25839
|
+
stopLogs();
|
|
25840
|
+
} catch (err) {
|
|
25841
|
+
logger.debug(`streamLogs stop failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25842
|
+
}
|
|
25843
|
+
if (containerId) await removeContainer(containerId);
|
|
25844
|
+
disposeWebFunctionArtifact(artifact);
|
|
25845
|
+
};
|
|
25846
|
+
const teardown = () => teardownPromise ??= doTeardown();
|
|
25847
|
+
await applyRoleArnIfSet({
|
|
25848
|
+
roleArn: options.roleArn,
|
|
25849
|
+
region: options.region,
|
|
25850
|
+
profile: options.profile
|
|
25851
|
+
});
|
|
25852
|
+
await ensureDockerAvailable();
|
|
25853
|
+
const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
|
|
25854
|
+
const appCmd = resolveApp(options.app);
|
|
25855
|
+
if (!appCmd) throw new Error(`No CDK app specified. Pass --app, set ${getEmbedConfig().envPrefix}_APP, or add "app" to cdk.json.`);
|
|
25856
|
+
logger.info("Synthesizing CDK app...");
|
|
25857
|
+
const synthesizer = hostSynthesizer ?? new Synthesizer();
|
|
25858
|
+
const context = parseContextOptions(options.context);
|
|
25859
|
+
const synthOpts = {
|
|
25860
|
+
app: appCmd,
|
|
25861
|
+
output: options.output,
|
|
25862
|
+
...options.region && { region: options.region },
|
|
25863
|
+
...options.profile && { profile: options.profile },
|
|
25864
|
+
...Object.keys(context).length > 0 && { context }
|
|
25865
|
+
};
|
|
25866
|
+
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
25867
|
+
const resolved = resolveWebFunctionTarget(await resolveSingleTarget(target, {
|
|
25868
|
+
entries: listTargets(stacks).webFunctions,
|
|
25869
|
+
message: "Select a Lambda web function to serve",
|
|
25870
|
+
noun: "Lambda web functions",
|
|
25871
|
+
onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} start-web-function requires a <target> (a WebFunction, WebFunctionEndpoint or WebFunctionRevision display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or run it in a TTY to pick interactively.`, "LOCAL_START_WEB_FUNCTION_TARGET_REQUIRED")
|
|
25872
|
+
}), stacks, options.revision);
|
|
25873
|
+
const code = parseWebFunctionBuildConfig(resolved.revisionLogicalId, resolved.revision.Properties?.["BuildConfig"]);
|
|
25874
|
+
const spec = resolveWebFunctionRuntime(code.runtime);
|
|
25875
|
+
const selectionNote = {
|
|
25876
|
+
"target-revision": "the target revision",
|
|
25877
|
+
"revision-flag": "--revision",
|
|
25878
|
+
"endpoint-weight": `highest weight on endpoint ${displayIdent(resolved.endpoint?.logicalId ?? "")}`,
|
|
25879
|
+
"only-revision": "the function's only revision"
|
|
25880
|
+
};
|
|
25881
|
+
logger.info(`Target: ${displayStackName(`${resolved.stack.stackName}/${resolved.revisionLogicalId}`)} (${spec.runtime}; revision chosen by ${selectionNote[resolved.selection]})`);
|
|
25882
|
+
const serviceConfig = readWebFunctionServiceConfig(resolved.revision);
|
|
25883
|
+
for (const line of webFunctionFidelityWarnings(resolved, serviceConfig)) logger.warn(line);
|
|
25884
|
+
artifact = await resolveWebFunctionArtifact(resolved.stack, resolved.revisionLogicalId, code);
|
|
25885
|
+
const shutdown = async (signal, exitCode) => {
|
|
25886
|
+
if (shuttingDown) {
|
|
25887
|
+
if (!waitingOnRun) {
|
|
25888
|
+
logger.info(`Received ${signal} again; still removing the container, please wait...`);
|
|
25889
|
+
return;
|
|
25890
|
+
}
|
|
25891
|
+
disposeWebFunctionArtifact(artifact);
|
|
25892
|
+
logger.warn(`Received ${signal} again; exiting without waiting for docker run to return. The container may still be starting, and its environment holds the forwarded AWS credentials. Remove it by its name (this works even if it is created after this exit): docker rm -f ${containerName ?? "<name>"}`);
|
|
25893
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
25894
|
+
return;
|
|
25895
|
+
}
|
|
25896
|
+
shuttingDown = true;
|
|
25897
|
+
logger.info(`Received ${signal}, shutting down...`);
|
|
25898
|
+
await teardown();
|
|
25899
|
+
process.exit(exitCode);
|
|
25900
|
+
};
|
|
25901
|
+
process.on("SIGINT", () => void shutdown("SIGINT", 130));
|
|
25902
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM", 0));
|
|
25903
|
+
const recent = new RecentOutput();
|
|
25904
|
+
try {
|
|
25905
|
+
const assumeRole = webFunctionAssumeRole(options.assumeRole, serviceConfig);
|
|
25906
|
+
const containerEnv = await resolveLambdaContainerEnv(buildWebFunctionLambdaView(resolved, serviceConfig, spec.runtime), {
|
|
25907
|
+
...options,
|
|
25908
|
+
...assumeRole !== void 0 && { assumeRole },
|
|
25909
|
+
deployedFunctionLookups: false
|
|
25910
|
+
}, profileCredentials, extraStateProviders);
|
|
25911
|
+
const { env, replacedHttpEndpoint } = finalizeWebFunctionEnv(containerEnv.env, {
|
|
25912
|
+
functionName: resolved.functionName,
|
|
25913
|
+
containerPort: WEB_FUNCTION_CONTAINER_PORT,
|
|
25914
|
+
timeoutSeconds: serviceConfig.timeoutSeconds,
|
|
25915
|
+
logGroup: serviceConfig.logGroup
|
|
25916
|
+
});
|
|
25917
|
+
if (replacedHttpEndpoint) logger.warn(`The revision's ${WEB_FUNCTION_HTTP_ENDPOINT_ENV} is replaced with 0.0.0.0:${WEB_FUNCTION_CONTAINER_PORT}: the runtime owns that variable, and the local port is published to it.`);
|
|
25918
|
+
const plan = planWebFunctionContainer(artifact, spec, env);
|
|
25919
|
+
const platform = options.platform ?? defaultWebFunctionPlatform(spec);
|
|
25920
|
+
await pullImage(plan.image, options.pull === false, platform);
|
|
25921
|
+
if (teardownPromise) return await forever();
|
|
25922
|
+
const hostPort = options.port === 0 ? await pickFreePort() : options.port;
|
|
25923
|
+
const name = containerName = `${getEmbedConfig().resourceNamePrefix}-webfn-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
25924
|
+
logger.info(`Starting web function container (image=${plan.image}, start=${plan.label}, port=${hostPort} -> ${WEB_FUNCTION_CONTAINER_PORT})...`);
|
|
25925
|
+
runInFlight = startWebFunctionContainer({
|
|
25926
|
+
plan,
|
|
25927
|
+
env,
|
|
25928
|
+
sensitiveEnvKeys: new Set(containerEnv.sensitiveEnvKeys),
|
|
25929
|
+
host: options.host,
|
|
25930
|
+
hostPort,
|
|
25931
|
+
platform,
|
|
25932
|
+
name
|
|
25933
|
+
});
|
|
25934
|
+
const id = await runInFlight;
|
|
25935
|
+
if (teardownPromise) return await forever();
|
|
25936
|
+
containerId = id;
|
|
25937
|
+
stopLogs = streamLogs(id, { onOutput: (chunk) => recent.push(chunk) });
|
|
25938
|
+
exitWatch = watchContainerExit(id);
|
|
25939
|
+
const probeHost = connectHost(options.host);
|
|
25940
|
+
await waitForWebFunctionReady({
|
|
25941
|
+
containerId: id,
|
|
25942
|
+
host: probeHost,
|
|
25943
|
+
port: hostPort,
|
|
25944
|
+
timeoutMs: options.timeout,
|
|
25945
|
+
recent,
|
|
25946
|
+
label: plan.label
|
|
25947
|
+
});
|
|
25948
|
+
logger.info(`Server listening on http://${formatAuthority(probeHost, hostPort)} (${displayIdent(resolved.functionName)} (Lambda web function))`);
|
|
25949
|
+
logger.info("Press ^C to shut down.");
|
|
25950
|
+
} catch (err) {
|
|
25951
|
+
if (shuttingDown) return await forever();
|
|
25952
|
+
await teardown();
|
|
25953
|
+
throw err;
|
|
25954
|
+
}
|
|
25955
|
+
if (!exitWatch || !containerId) return await forever();
|
|
25956
|
+
const exitCode = await exitWatch.exited;
|
|
25957
|
+
if (shuttingDown || teardownPromise) return await forever();
|
|
25958
|
+
const failure = await containerFailure(`The web function container exited (exit code ${exitCode ?? "unknown"}) while serving.`, containerId, recent, void 0, "LOCAL_START_WEB_FUNCTION_EXITED");
|
|
25959
|
+
await teardown();
|
|
25960
|
+
throw failure;
|
|
25961
|
+
}
|
|
25962
|
+
function createLocalStartWebFunctionCommand(opts = {}) {
|
|
25963
|
+
setEmbedConfig(opts.embedConfig);
|
|
25964
|
+
const cmd = new Command("start-web-function").description("Serve an AWS Lambda Web Function locally. Resolves a WebFunction, WebFunctionEndpoint or WebFunctionRevision target to one revision (an endpoint serves its highest-weight revision; --revision overrides), runs its code bundle from cdk.out in a container whose server listens on AWS_LAMBDA_HTTP_ENDPOINT, and publishes it on a local port with the revision's ServiceConfig environment. Target accepts a CDK display path or stack-qualified logical ID; single-stack apps may omit the prefix. Omit <target> in a TTY to pick from a list. Runs until ^C.").argument("[target]", "CDK display path or stack-qualified logical ID of the WebFunction / WebFunctionEndpoint / WebFunctionRevision (omit to pick interactively in a TTY)").action(withErrorHandling(async (target, options) => {
|
|
25965
|
+
await localStartWebFunctionCommand(target, options, opts.extraStateProviders, opts.synthesizer);
|
|
25966
|
+
}));
|
|
25967
|
+
addStartWebFunctionSpecificOptions(cmd);
|
|
25968
|
+
[
|
|
25969
|
+
...commonOptions(),
|
|
25970
|
+
...appOptions(),
|
|
25971
|
+
...contextOptions
|
|
25972
|
+
].forEach((opt) => cmd.addOption(opt));
|
|
25973
|
+
cmd.addOption(regionOption);
|
|
25974
|
+
return cmd;
|
|
25975
|
+
}
|
|
25976
|
+
function addStartWebFunctionSpecificOptions(cmd) {
|
|
25977
|
+
return cmd.addOption(new Option("--revision <logicalId>", "Serve this WebFunctionRevision (logical ID) instead of the one the endpoint weights pick.")).addOption(new Option("--port <n>", "Local port to serve on. Default 0 (OS-assigned).").default(0).argParser(parsePort)).addOption(new Option("--host <ip>", "Address to publish the port on.").default("127.0.0.1")).addOption(new Option("--platform <platform>", "docker --platform for the server container. Defaults to the runtime's cloud architecture (linux/arm64 for nodejs24.x).").choices(["linux/amd64", "linux/arm64"])).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"RevisionLogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--no-pull", "Skip docker pull of the runtime base image (use the cached image)")).addOption(new Option("--timeout <ms>", "Maximum time in milliseconds to wait for the server to answer HTTP. Default 60000.").default(6e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the revision's execution role and forward STS-issued temp credentials to the container. (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the revision's ServiceConfig.ExecutionRoleArn: a literal ARN as written, or the Fn::GetAtt / Ref CDK synthesizes resolved against --from-cfn-stack deployed state; (3) `--no-assume-role` opts out. Off by default.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Bare form uses the resolved stack name.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
|
|
25190
25978
|
}
|
|
25191
25979
|
|
|
25192
25980
|
//#endregion
|
|
@@ -25215,7 +26003,7 @@ async function localListCommand(options) {
|
|
|
25215
26003
|
process.stdout.write(`${formatTargetListing(listing, getEmbedConfig().cliName, { long: options.long })}\n`);
|
|
25216
26004
|
}
|
|
25217
26005
|
function formatTargetListing(listing, cliName, options = {}) {
|
|
25218
|
-
if (countTargets(listing) === 0) return `No runnable targets (Lambda functions, APIs, ECS services / tasks, AgentCore Runtimes, load balancers, CloudFront distributions) found in this CDK app.`;
|
|
26006
|
+
if (countTargets(listing) === 0) return `No runnable targets (Lambda functions, APIs, ECS services / tasks, AgentCore Runtimes, load balancers, CloudFront distributions, Lambda web functions) found in this CDK app.`;
|
|
25219
26007
|
const long = options.long ?? false;
|
|
25220
26008
|
return "\n" + [
|
|
25221
26009
|
formatSection("Lambda Functions", `${cliName} invoke <target>`, listing.lambdas, long),
|
|
@@ -25224,7 +26012,8 @@ function formatTargetListing(listing, cliName, options = {}) {
|
|
|
25224
26012
|
formatSection("ECS Task Definitions", `${cliName} run-task <target>`, listing.ecsTaskDefinitions, long),
|
|
25225
26013
|
formatSection("AgentCore Runtimes", `${cliName} invoke-agentcore <target>`, listing.agentCoreRuntimes, long),
|
|
25226
26014
|
formatSection("Application Load Balancers", `${cliName} start-alb <target...>`, listing.loadBalancers, long),
|
|
25227
|
-
formatSection("CloudFront Distributions", `${cliName} start-cloudfront <target>`, listing.cloudFrontDistributions, long)
|
|
26015
|
+
formatSection("CloudFront Distributions", `${cliName} start-cloudfront <target>`, listing.cloudFrontDistributions, long),
|
|
26016
|
+
formatSection("Lambda Web Functions", `${cliName} start-web-function <target>`, listing.webFunctions, long)
|
|
25228
26017
|
].filter((lines) => lines.length > 0).map((lines) => lines.join("\n")).join("\n\n");
|
|
25229
26018
|
}
|
|
25230
26019
|
function formatSection(title, command, entries, long) {
|
|
@@ -30500,5 +31289,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
30500
31289
|
}
|
|
30501
31290
|
|
|
30502
31291
|
//#endregion
|
|
30503
|
-
export {
|
|
30504
|
-
//# sourceMappingURL=local-studio-
|
|
31292
|
+
export { WEB_FUNCTION_TYPE as $, AgentCoreResolutionError as $i, invokeAgentCore as $n, pickResponseTemplate as $r, parseLbPortOverrides as $t, containerFailure as A, resolveCfnRegion as Ai, listPinnedTargets as An, buildCognitoJwksUrl as Ar, buildEdgeRequestEvent as At, webFunctionAssumeRole as B, discoverWebSocketApis as Bi, bridgeAgentCoreWs as Bn, invokeTokenAuthorizer as Br, pickLambdaEdgeFunctionLogicalId as Bt, addListSpecificOptions as C, workloadClientConfig as Ca, substituteEnvVarsFromState as Ci, mergeForService as Cn, filterRoutesByApiIdentifiers as Cr, matchBehavior as Ct, createLocalStartWebFunctionCommand as D, buildProxyClientConfig as Da, isCfnFlagPresent as Di, describePinnedImageUri as Dn, resolveSelectionExpression as Dr, serveLambdaUrlOrigin as Dt, addStartWebFunctionSpecificOptions as E, resolveProfileCredentials as Ea, createLocalStateProvider as Ei, runImageOverrideBuilds as En, startApiServer as Er, serveFromStaticOrigin as Et, watchContainerExit as F, resolveWatchConfig as Fi, setShadowReadyTimeoutMs as Fn, verifyJwtViaDiscovery as Fr, describeS3OriginDomain as Ft, resolveWebFunctionRuntime as G, discoverRoutes as Gi, MCP_CONTAINER_PORT as Gn, isFunctionUrlOacFronted as Gr, runViewerResponse as Gt, WEB_FUNCTION_RUNTIMES as H, filterWebSocketApisByIdentifiers as Hi, A2A_CONTAINER_PORT as Hn, applyCorsResponseHeaders as Hr, resolveCloudFrontDistribution as Ht, WEB_FUNCTION_HTTP_ENDPOINT_ENV as I, resolveSingleTarget as Ii, getContainerNetworkIp as In, buildMethodArn as Ir, extractKvsAssociations as It, findFileAssetForObjectKey as J, AGENTCORE_A2A_PROTOCOL as Ji, mcpInvokeOnce as Jn, translateLambdaResponse as Jr, createLocalFileKvsDataSource as Jt, supportedWebFunctionRuntimes as K, pickRefLogicalId as Ki, MCP_PATH as Kn, matchPreflight as Kr, stripCloudFrontImport as Kt, buildWebFunctionLambdaView as L, countTargets as Li, attachContainerLogStreamer as Ln, computeRequestIdentityHash as Lr, isCloudFrontDistribution as Lt, readContainerLogTail as M, CfnLocalStateProvider as Mi, CloudMapRegistry as Mn, createJwksCache as Mr, edgeHeadersToHttp as Mt, startWebFunctionContainer as N, collectSsmParameterRefs as Ni, DEFAULT_SHADOW_READY_TIMEOUT_MS as Nn, verifyCognitoJwt as Nr, httpHeadersToEdge as Nt, RecentOutput as O, isProxyEnvConfigured as Oa, rejectExplicitCfnStackWithMultipleStacks as Oi, imageOverrideKeyAliases as On, resolveServiceIntegrationParameters as Or, applyEdgeRequestResult as Ot, waitForWebFunctionReady as P, resolveSsmParameters as Pi, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Pn, verifyJwtAuthorizer as Pr, CLOUDFRONT_DISTRIBUTION_TYPE as Pt, WEB_FUNCTION_REVISION_TYPE as Q, AGENTCORE_RUNTIME_TYPE as Qi, AGENTCORE_SESSION_ID_HEADER as Qn, evaluateResponseParameters as Qr, createLocalStartAlbCommand as Qt, finalizeWebFunctionEnv as R, listTargets as Ri, addInvokeAgentCoreSpecificOptions as Rn, evaluateCachedLambdaPolicy as Rr, pickFunctionUrlLogicalIdFromOrigin as Rt, StudioEventBus as S, resetWorkloadIdentity as Sa, substituteAgainstStateAsync as Si, enforceImageOverrideOrphans as Sn, filterRoutesByApiIdentifier as Sr, createS3OriginReader as St, formatTargetListing as T, buildStsClientConfig as Ta, LocalStateSourceError as Ti, resolveImageOverrides as Tn, readMtlsMaterialsFromDisk as Tr, resolveErrorResponseCandidates as Tt, buildNodeEntryFileStart as U, parseSelectionExpressionPath as Ui, A2A_PATH as Un, buildCorsConfigByApiId as Ur, compileCloudFrontFunction as Ut, webFunctionFidelityWarnings as V, discoverWebSocketApisOrThrow as Vi, invokeAgentCoreWs as Vn, attachAuthorizers as Vr, pickTargetFunctionLogicalId as Vt, defaultWebFunctionPlatform as W, webSocketApiMatchesIdentifier as Wi, a2aInvokeOnce as Wn, buildCorsConfigFromCloudFrontChain as Wr, runViewerRequest as Wt, resolveWebFunctionArtifact as X, AGENTCORE_HTTP_PROTOCOL as Xi, AGENTCORE_SIGV4_SERVICE as Xn, buildHttpApiV2Event as Xr, addAlbSpecificOptions as Xt, parseWebFunctionBuildConfig as Y, AGENTCORE_AGUI_PROTOCOL as Yi, parseSseForJsonRpc as Yn, applyAuthorizerOverlay as Yr, createUnboundCloudFrontModule as Yt, WEB_FUNCTION_ENDPOINT_TYPE as Z, AGENTCORE_MCP_PROTOCOL as Zi, signAgentCoreInvocation as Zn, buildRestV1Event as Zr, albStrategy as Zt, filterStudioTargetGroups as _, SECOND_ASSUME_MESSAGE as _a, resolveRuntimeCodeMountPath as _i, resolveSharedSidecarCredentials as _n, attachStageContext as _r, resolveKvsModulesForDistribution as _t, createLocalStudioCommand as a, tryResolveImageFnJoin as aa, probeHostGatewaySupport as ai, serviceStrategy as an, computeCodeImageTag as ar, selectServeInboundAuth as at, renderStudioHtml as b, readEnvCallerCredentials as ba, EcsTaskResolutionError as bi, buildImageOverrideTag as bn, resolveEnvVars$1 as br, resolveDeployedOriginBucket as bt, startStudioProxy as c, DynamicReferenceResolver as ca, ConnectionRegistry as ci, MAX_TASKS_SUBNET_RANGE_CAP as cn, classifySourceChange as cr, startAgentCoreWsBridge as ct, createStudioDispatcher as d, firstUsableRegion as da, parseConnectionsPath as di, addImageOverrideOptions as dn, addStartApiSpecificOptions as dr, createLocalStartCloudFrontCommand as dt, pickAgentCoreCandidateStack as ea, selectIntegrationResponse as ei, resolveAlbTarget as en, waitForAgentCoreHttpReady as er, WebFunctionResolutionError as et, filterStudioCustomResources as f, keysNotFromTemplate as fa, buildConnectEvent as fi, buildEcsImageResolutionContext$1 as fn, createLocalStartApiCommand as fr, normalizeKvsFileKeys as ft, annotatePinnedEcsTargets as g, withoutKeys as ga, buildContainerImage as gi, resolveEcsAssumeRoleOption as gn, createFileWatcher as gr, idFromArn as gt, annotateEcsTaskPinnedTargets as h, resolveDynamicReferencesInEnv as ha, architectureToPlatform as hi, parseRestartPolicy as hn, createAuthorizerCache as hr, resolveCloudFrontTarget as ht, coerceStopRequest as i, substituteImagePlaceholders as ia, HOST_GATEWAY_MIN_VERSION as ii, createLocalStartServiceCommand as in, buildAgentCoreCodeImage as ir, buildAgentCoreServeAuthCheck as it, planWebFunctionContainer as j, resolveCfnStackName as ji, buildCloudMapIndex as jn, buildJwksUrlFromIssuer as jr, buildEdgeResponseEvent as jt, WEB_FUNCTION_CONTAINER_PORT as k, resolveCfnFallbackRegion as ki, isLocalCdkAssetImage as kn, defaultCredentialsLoader as kr, applyEdgeResponseResult as kt, relayServeRequest as l, containsDynamicReference as la, buildMgmtEndpointEnvUrl as li, addCommonEcsServiceOptions as ln, addInvokeSpecificOptions as lr, LocalStartCloudFrontError as lt, annotateAlbPinnedBackingServices as m, parseDynamicReference as ma, buildMessageEvent as mi, parseMaxTasks as mn, resolveApiTargetSubset as mr, parseOriginOverrides as mt, coerceRunRequest as n, derivePseudoParametersFromRegion as na, VtlEvaluationError as ni, resolveAlbFrontDoor as nn, downloadAndExtractS3Bundle as nr, addStartAgentCoreSpecificOptions as nt, resolveServeBaseUrl as o, LocalInvokeBuildError as oa, resolveHostGatewayExtraHosts as oi, addRunTaskSpecificOptions as on, renderCodeDockerfile as or, startAgentCoreHttpServer as ot, isCustomResourceLambdaTarget as p, keysOverriddenBy as pa, buildDisconnectEvent as pi, ecsClusterOption as pn, createWatchPredicates as pr, parseKvsFileOverrides as pt, disposeWebFunctionArtifact as q, resolveLambdaArnIntrinsic as qi, MCP_PROTOCOL_VERSION as qn, matchRoute as qr, createCloudFrontModule as qt, coerceServeRequest as r, formatStateRemedy as ra, HOST_DOCKER_INTERNAL_GATEWAY as ri, addStartServiceSpecificOptions as rn, SUPPORTED_CODE_RUNTIMES as rr, createLocalStartAgentCoreCommand as rt, createStudioServeManager as s, DynamicReferenceResolutionError as sa, bufferToBody as si, createLocalRunTaskCommand as sn, toCmdArgv as sr, attachAgentCoreWsBridge as st, addStudioSpecificOptions as t, resolveAgentCoreTarget as ta, tryParseStatus as ti, isApplicationLoadBalancer as tn, waitForAgentCorePing as tr, resolveWebFunctionTarget as tt, reinvoke as u, deployedFillMayBeSecret as ua, handleConnectionsRequest as ui, addEcsAssumeRoleOptions as un, createLocalInvokeCommand as ur, addStartCloudFrontSpecificOptions as ut, startStudioServer as v, assumedRoleRecorded as va, resolveRuntimeFileExtension as vi, runEcsServiceEmulator as vn, buildStageMap as vr, createDeployedKvsDataSource as vt, createLocalListCommand as w, workloadStsClientConfig as wa, substituteEnvVarsFromStateAsync as wi, parseImageOverrideFlags as wn, groupRoutesByServer as wr, startCloudFrontServer as wt, createStudioStore as x, recordAssumedRole as xa, substituteAgainstState as xi, canonicalizeImageOverrideKeys as xn, availableApiIdentifiers as xr, classifyS3Error as xt, toStudioTargetGroups as y, deployAccountStsClientConfig as ya, resolveRuntimeImage as yi, ImageOverrideError as yn, materializeLayerFromArn as yr, resolveDeployedKvsArnByName as yt, readWebFunctionServiceConfig as z, availableWebSocketApiIdentifiers as zi, createLocalInvokeAgentCoreCommand as zn, invokeRequestAuthorizer as zr, pickKvsLogicalIdFromArn as zt };
|
|
31293
|
+
//# sourceMappingURL=local-studio-CsftJJ1r.js.map
|