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.
@@ -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$5(parsed, stacks, target);
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$3(target, stack, resources);
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$3(target, stack, resources);
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$5(parsed, stacks, target) {
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$3(target, stack, resources) {
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$4(parsed, stacks, target);
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$4(parsed, stacks, target) {
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$2(target, stack, resources);
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$2(target, stack, resources);
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$2(target, stack, resources) {
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$3(parsed, stacks, target);
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$1(target, stack, resources);
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$1(target, stack, resources);
5116
+ if (!resource) throw notFoundError$2(target, stack, resources);
5112
5117
  logicalId = parsed.pathOrId;
5113
5118
  }
5114
- if (!logicalId || !resource) throw notFoundError$1(target, stack, resources);
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$3(parsed, stacks, target) {
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$1(target, stack, resources) {
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$5 = promisify(execFile);
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$5(getDockerCmd(), args, {
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$5(getDockerCmd(), [
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$5(cmd, [
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
- resolvedAssumeRoleArn = await resolveAssumeRoleArnForLambda(options.assumeRole, stateForRoleHint, stateProvider, lambda.logicalId);
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$4 = promisify(execFile);
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$4(dockerCmd, [
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$4(dockerCmd, [
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$4(dockerCmd, ["restart", containerId]);
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$3 = promisify(execFile);
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$3(getDockerCmd(), [
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$3(getDockerCmd(), [
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$3(getDockerCmd(), [
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$3(getDockerCmd(), sidecarArgs, {
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$3(getDockerCmd(), [
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$2 = promisify(execFile);
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$2(getDockerCmd(), [
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$2(getDockerCmd(), args, {
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$2(getDockerCmd(), [
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$2(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
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$2(getDockerCmd(), [
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$2(getDockerCmd(), args);
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$2(parsed, stacks, target);
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$2(parsed, stacks, target) {
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$1 = promisify(execFile);
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$1(getDockerCmd(), [
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$1(getDockerCmd(), [
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$1(props["Port"]);
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$1(raw) {
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$1(raw);
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$1(parsed, stacks, target);
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$1(parsed, stacks, target) {
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 { applyEdgeResponseResult as $, defaultCredentialsLoader as $n, resolveCfnFallbackRegion as $r, isLocalCdkAssetImage as $t, startAgentCoreHttpServer as A, LocalInvokeBuildError as Ai, renderCodeDockerfile as An, resolveHostGatewayExtraHosts as Ar, addRunTaskSpecificOptions as At, idFromArn as B, withoutKeys as Bi, createFileWatcher as Bn, buildContainerImage as Br, resolveEcsAssumeRoleOption as Bt, addListSpecificOptions as C, AgentCoreResolutionError as Ci, invokeAgentCore as Cn, pickResponseTemplate as Cr, parseLbPortOverrides as Ct, createLocalStartAgentCoreCommand as D, formatStateRemedy as Di, SUPPORTED_CODE_RUNTIMES as Dn, HOST_DOCKER_INTERNAL_GATEWAY as Dr, addStartServiceSpecificOptions as Dt, addStartAgentCoreSpecificOptions as E, derivePseudoParametersFromRegion as Ei, downloadAndExtractS3Bundle as En, VtlEvaluationError as Er, resolveAlbFrontDoor as Et, createLocalStartCloudFrontCommand as F, firstUsableRegion as Fi, addStartApiSpecificOptions as Fn, parseConnectionsPath as Fr, addImageOverrideOptions as Ft, classifyS3Error as G, recordAssumedRole as Gi, availableApiIdentifiers as Gn, substituteAgainstState as Gr, canonicalizeImageOverrideKeys as Gt, createDeployedKvsDataSource as H, assumedRoleRecorded as Hi, buildStageMap as Hn, resolveRuntimeFileExtension as Hr, runEcsServiceEmulator as Ht, normalizeKvsFileKeys as I, keysNotFromTemplate as Ii, createLocalStartApiCommand as In, buildConnectEvent as Ir, buildEcsImageResolutionContext$1 as It, startCloudFrontServer as J, workloadStsClientConfig as Ji, groupRoutesByServer as Jn, substituteEnvVarsFromStateAsync as Jr, parseImageOverrideFlags as Jt, createS3OriginReader as K, resetWorkloadIdentity as Ki, filterRoutesByApiIdentifier as Kn, substituteAgainstStateAsync as Kr, enforceImageOverrideOrphans as Kt, parseKvsFileOverrides as L, keysOverriddenBy as Li, createWatchPredicates as Ln, buildDisconnectEvent as Lr, ecsClusterOption as Lt, startAgentCoreWsBridge as M, DynamicReferenceResolver as Mi, classifySourceChange as Mn, ConnectionRegistry as Mr, MAX_TASKS_SUBNET_RANGE_CAP as Mt, LocalStartCloudFrontError as N, containsDynamicReference as Ni, addInvokeSpecificOptions as Nn, buildMgmtEndpointEnvUrl as Nr, addCommonEcsServiceOptions as Nt, buildAgentCoreServeAuthCheck as O, substituteImagePlaceholders as Oi, buildAgentCoreCodeImage as On, HOST_GATEWAY_MIN_VERSION as Or, createLocalStartServiceCommand as Ot, addStartCloudFrontSpecificOptions as P, deployedFillMayBeSecret as Pi, createLocalInvokeCommand as Pn, handleConnectionsRequest as Pr, addEcsAssumeRoleOptions as Pt, applyEdgeRequestResult as Q, isProxyEnvConfigured as Qi, resolveServiceIntegrationParameters as Qn, rejectExplicitCfnStackWithMultipleStacks as Qr, imageOverrideKeyAliases as Qt, parseOriginOverrides as R, parseDynamicReference as Ri, resolveApiTargetSubset as Rn, buildMessageEvent as Rr, parseMaxTasks as Rt, StudioEventBus as S, AGENTCORE_RUNTIME_TYPE as Si, AGENTCORE_SESSION_ID_HEADER as Sn, evaluateResponseParameters as Sr, createLocalStartAlbCommand as St, formatTargetListing as T, resolveAgentCoreTarget as Ti, waitForAgentCorePing as Tn, tryParseStatus as Tr, isApplicationLoadBalancer as Tt, resolveDeployedKvsArnByName as U, deployAccountStsClientConfig as Ui, materializeLayerFromArn as Un, resolveRuntimeImage as Ur, ImageOverrideError as Ut, resolveKvsModulesForDistribution as V, SECOND_ASSUME_MESSAGE as Vi, attachStageContext as Vn, resolveRuntimeCodeMountPath as Vr, resolveSharedSidecarCredentials as Vt, resolveDeployedOriginBucket as W, readEnvCallerCredentials as Wi, resolveEnvVars$1 as Wn, EcsTaskResolutionError as Wr, buildImageOverrideTag as Wt, serveFromStaticOrigin as X, resolveProfileCredentials as Xi, startApiServer as Xn, createLocalStateProvider as Xr, runImageOverrideBuilds as Xt, resolveErrorResponseCandidates as Y, buildStsClientConfig as Yi, readMtlsMaterialsFromDisk as Yn, LocalStateSourceError as Yr, resolveImageOverrides as Yt, serveLambdaUrlOrigin as Z, buildProxyClientConfig as Zi, resolveSelectionExpression as Zn, isCfnFlagPresent as Zr, describePinnedImageUri as Zt, filterStudioTargetGroups as _, resolveLambdaArnIntrinsic as _i, MCP_PROTOCOL_VERSION as _n, matchRoute as _r, createCloudFrontModule as _t, createLocalStudioCommand as a, resolveWatchConfig as ai, setShadowReadyTimeoutMs as an, verifyJwtViaDiscovery as ar, describeS3OriginDomain as at, renderStudioHtml as b, AGENTCORE_HTTP_PROTOCOL as bi, AGENTCORE_SIGV4_SERVICE as bn, buildHttpApiV2Event as br, addAlbSpecificOptions as bt, startStudioProxy as c, listTargets as ci, addInvokeAgentCoreSpecificOptions as cn, evaluateCachedLambdaPolicy as cr, pickFunctionUrlLogicalIdFromOrigin as ct, createStudioDispatcher as d, discoverWebSocketApisOrThrow as di, invokeAgentCoreWs as dn, attachAuthorizers as dr, pickTargetFunctionLogicalId as dt, resolveCfnRegion as ei, listPinnedTargets as en, buildCognitoJwksUrl as er, buildEdgeRequestEvent as et, filterStudioCustomResources as f, filterWebSocketApisByIdentifiers as fi, A2A_CONTAINER_PORT as fn, applyCorsResponseHeaders as fr, resolveCloudFrontDistribution as ft, annotatePinnedEcsTargets as g, pickRefLogicalId as gi, MCP_PATH as gn, matchPreflight as gr, stripCloudFrontImport as gt, annotateEcsTaskPinnedTargets as h, discoverRoutes as hi, MCP_CONTAINER_PORT as hn, isFunctionUrlOacFronted as hr, runViewerResponse as ht, coerceStopRequest as i, resolveSsmParameters as ii, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as in, verifyJwtAuthorizer as ir, CLOUDFRONT_DISTRIBUTION_TYPE as it, attachAgentCoreWsBridge as j, DynamicReferenceResolutionError as ji, toCmdArgv as jn, bufferToBody as jr, createLocalRunTaskCommand as jt, selectServeInboundAuth as k, tryResolveImageFnJoin as ki, computeCodeImageTag as kn, probeHostGatewaySupport as kr, serviceStrategy as kt, relayServeRequest as l, availableWebSocketApiIdentifiers as li, createLocalInvokeAgentCoreCommand as ln, invokeRequestAuthorizer as lr, pickKvsLogicalIdFromArn as lt, annotateAlbPinnedBackingServices as m, webSocketApiMatchesIdentifier as mi, a2aInvokeOnce as mn, buildCorsConfigFromCloudFrontChain as mr, runViewerRequest as mt, coerceRunRequest as n, CfnLocalStateProvider as ni, CloudMapRegistry as nn, createJwksCache as nr, edgeHeadersToHttp as nt, resolveServeBaseUrl as o, resolveSingleTarget as oi, getContainerNetworkIp as on, buildMethodArn as or, extractKvsAssociations as ot, isCustomResourceLambdaTarget as p, parseSelectionExpressionPath as pi, A2A_PATH as pn, buildCorsConfigByApiId as pr, compileCloudFrontFunction as pt, matchBehavior as q, workloadClientConfig as qi, filterRoutesByApiIdentifiers as qn, substituteEnvVarsFromState as qr, mergeForService as qt, coerceServeRequest as r, collectSsmParameterRefs as ri, DEFAULT_SHADOW_READY_TIMEOUT_MS as rn, verifyCognitoJwt as rr, httpHeadersToEdge as rt, createStudioServeManager as s, countTargets as si, attachContainerLogStreamer as sn, computeRequestIdentityHash as sr, isCloudFrontDistribution as st, addStudioSpecificOptions as t, resolveCfnStackName as ti, buildCloudMapIndex as tn, buildJwksUrlFromIssuer as tr, buildEdgeResponseEvent as tt, reinvoke as u, discoverWebSocketApis as ui, bridgeAgentCoreWs as un, invokeTokenAuthorizer as ur, pickLambdaEdgeFunctionLogicalId as ut, startStudioServer as v, AGENTCORE_A2A_PROTOCOL as vi, mcpInvokeOnce as vn, translateLambdaResponse as vr, createLocalFileKvsDataSource as vt, createLocalListCommand as w, pickAgentCoreCandidateStack as wi, waitForAgentCoreHttpReady as wn, selectIntegrationResponse as wr, resolveAlbTarget as wt, createStudioStore as x, AGENTCORE_MCP_PROTOCOL as xi, signAgentCoreInvocation as xn, buildRestV1Event as xr, albStrategy as xt, toStudioTargetGroups as y, AGENTCORE_AGUI_PROTOCOL as yi, parseSseForJsonRpc as yn, applyAuthorizerOverlay as yr, createUnboundCloudFrontModule as yt, resolveCloudFrontTarget as z, resolveDynamicReferencesInEnv as zi, createAuthorizerCache as zn, architectureToPlatform as zr, parseRestartPolicy as zt };
30504
- //# sourceMappingURL=local-studio-CJfNARFz.js.map
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