cdk-local 0.155.0 → 0.156.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.
@@ -46,10 +46,11 @@ 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";
49
+ import { existsSync as existsSync$1, readFileSync as readFileSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
50
50
  import { request as request$2 } from "http";
51
51
  import { execFile as execFile$1, spawn as spawn$1 } from "child_process";
52
52
  import { promisify as promisify$1 } from "util";
53
+ import { randomUUID as randomUUID$1 } from "crypto";
53
54
  import { EventEmitter } from "node:events";
54
55
 
55
56
  //#region src/utils/url-authority.ts
@@ -3536,7 +3537,8 @@ function listTargets(stacks) {
3536
3537
  agentCoreRuntimes: sortEntries(scanAgentCoreRuntimes(stacks)),
3537
3538
  loadBalancers: sortEntries(scanApplicationLoadBalancers(stacks)),
3538
3539
  cloudFrontDistributions: sortEntries(scanByType(stacks, "AWS::CloudFront::Distribution")),
3539
- webFunctions: sortEntries(scanByType(stacks, "AWS::Lambda::WebFunction"))
3540
+ webFunctions: sortEntries(scanByType(stacks, "AWS::Lambda::WebFunction")),
3541
+ microvmImages: sortEntries(scanByType(stacks, "AWS::Lambda::MicrovmImage"))
3540
3542
  };
3541
3543
  }
3542
3544
  const pathOf$1 = (e) => e.displayPath ?? e.qualifiedId;
@@ -3559,7 +3561,7 @@ function sortApiEntries(entries) {
3559
3561
  });
3560
3562
  }
3561
3563
  function countTargets(listing) {
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;
3564
+ 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 + listing.microvmImages.length;
3563
3565
  }
3564
3566
 
3565
3567
  //#endregion
@@ -6493,7 +6495,7 @@ function pushMap(hash, name, value) {
6493
6495
 
6494
6496
  //#endregion
6495
6497
  //#region src/local/docker-runner.ts
6496
- const execFileAsync$6 = promisify(execFile);
6498
+ const execFileAsync$7 = promisify(execFile);
6497
6499
  var DockerRunnerError = class DockerRunnerError extends Error {
6498
6500
  constructor(message) {
6499
6501
  super(message);
@@ -6555,6 +6557,7 @@ async function runDetached(opts) {
6555
6557
  const host = opts.host ?? "127.0.0.1";
6556
6558
  args.push("-p", `${host}:${opts.hostPort}:${opts.containerPort ?? 8080}`);
6557
6559
  if (opts.debugPort !== void 0) args.push("-p", `${host}:${opts.debugPort}:${opts.debugPort}`);
6560
+ for (const extra of opts.extraPorts ?? []) args.push("-p", `${host}:${extra.hostPort}:${extra.containerPort}`);
6558
6561
  for (const mount of opts.mounts) {
6559
6562
  const ro = mount.readOnly ? ":ro" : "";
6560
6563
  args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
@@ -6584,7 +6587,7 @@ async function runDetached(opts) {
6584
6587
  if (refusal !== void 0) throw new DockerRunnerError(refusal);
6585
6588
  warnFinchArgvExposure(forwardedKeys);
6586
6589
  try {
6587
- const { stdout } = await execFileAsync$6(getDockerCmd(), args, {
6590
+ const { stdout } = await execFileAsync$7(getDockerCmd(), args, {
6588
6591
  maxBuffer: 10 * 1024 * 1024,
6589
6592
  ...execEnvForSecrets(passthroughEnv)
6590
6593
  });
@@ -6641,8 +6644,8 @@ function streamLogs(containerId, opts = {}) {
6641
6644
  proc.stderr?.on("data", (chunk) => tap(chunk));
6642
6645
  }
6643
6646
  let flush = () => void 0;
6644
- if (process.env["CDKL_PREFIX_CONTAINER_OUTPUT"] === "1") {
6645
- const tag = `[${flattenToOneLine(containerId.slice(0, 12)).replace(/[\]\s]/g, "_")}] `;
6647
+ if (opts.prefix !== void 0 || process.env["CDKL_PREFIX_CONTAINER_OUTPUT"] === "1") {
6648
+ const tag = opts.prefix ?? `[${flattenToOneLine(containerId.slice(0, 12)).replace(/[\]\s]/g, "_")}] `;
6646
6649
  const stdoutRelay = createPrefixedLineRelay(tag, process.stdout);
6647
6650
  const stderrRelay = createPrefixedLineRelay(tag, process.stderr);
6648
6651
  proc.stdout?.on("data", (chunk) => stdoutRelay.push(chunk));
@@ -6666,7 +6669,7 @@ async function removeContainer(containerId) {
6666
6669
  if (!containerId) return;
6667
6670
  const logger = getLogger().child("docker");
6668
6671
  try {
6669
- await execFileAsync$6(getDockerCmd(), [
6672
+ await execFileAsync$7(getDockerCmd(), [
6670
6673
  "rm",
6671
6674
  "-f",
6672
6675
  containerId
@@ -6680,7 +6683,7 @@ async function removeContainer(containerId) {
6680
6683
  async function ensureDockerAvailable() {
6681
6684
  const cmd = getDockerCmd();
6682
6685
  try {
6683
- await execFileAsync$6(cmd, [
6686
+ await execFileAsync$7(cmd, [
6684
6687
  "version",
6685
6688
  "--format",
6686
6689
  "{{.Server.Version}}"
@@ -7213,14 +7216,14 @@ async function handleConnectionsRequest(opts) {
7213
7216
  const { req, res, registry } = opts;
7214
7217
  const parsed = parseConnectionsPath(req.url ?? "");
7215
7218
  if (!parsed) {
7216
- writeJson(res, 404, { message: "Not Found" });
7219
+ writeJson$1(res, 404, { message: "Not Found" });
7217
7220
  return;
7218
7221
  }
7219
7222
  const { connectionId } = parsed;
7220
7223
  const entry = registry.get(connectionId);
7221
7224
  const method = (req.method ?? "").toUpperCase();
7222
7225
  if (!entry) {
7223
- writeJson(res, 410, { message: "GoneException" });
7226
+ writeJson$1(res, 410, { message: "GoneException" });
7224
7227
  return;
7225
7228
  }
7226
7229
  if (method === "POST") {
@@ -7228,17 +7231,17 @@ async function handleConnectionsRequest(opts) {
7228
7231
  try {
7229
7232
  body = await readRequestBody$1(req);
7230
7233
  } catch (err) {
7231
- writeJson(res, 500, { message: `Failed to read request body: ${err instanceof Error ? err.message : String(err)}` });
7234
+ writeJson$1(res, 500, { message: `Failed to read request body: ${err instanceof Error ? err.message : String(err)}` });
7232
7235
  return;
7233
7236
  }
7234
7237
  if (entry.socket.readyState !== entry.socket.OPEN) {
7235
- writeJson(res, 410, { message: "GoneException" });
7238
+ writeJson$1(res, 410, { message: "GoneException" });
7236
7239
  return;
7237
7240
  }
7238
7241
  try {
7239
7242
  entry.socket.send(body);
7240
7243
  } catch (err) {
7241
- writeJson(res, 500, { message: `Failed to deliver to socket: ${err instanceof Error ? err.message : String(err)}` });
7244
+ writeJson$1(res, 500, { message: `Failed to deliver to socket: ${err instanceof Error ? err.message : String(err)}` });
7242
7245
  return;
7243
7246
  }
7244
7247
  res.writeHead(200);
@@ -7249,7 +7252,7 @@ async function handleConnectionsRequest(opts) {
7249
7252
  try {
7250
7253
  entry.socket.close(1e3, "DeleteConnection");
7251
7254
  } catch (err) {
7252
- writeJson(res, 500, { message: `Failed to close socket: ${err instanceof Error ? err.message : String(err)}` });
7255
+ writeJson$1(res, 500, { message: `Failed to close socket: ${err instanceof Error ? err.message : String(err)}` });
7253
7256
  return;
7254
7257
  }
7255
7258
  res.writeHead(204);
@@ -7257,7 +7260,7 @@ async function handleConnectionsRequest(opts) {
7257
7260
  return;
7258
7261
  }
7259
7262
  if (method === "GET") {
7260
- writeJson(res, 200, {
7263
+ writeJson$1(res, 200, {
7261
7264
  ConnectedAt: new Date(entry.connectedAt).toISOString(),
7262
7265
  Identity: { SourceIp: "127.0.0.1" },
7263
7266
  LastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -7265,9 +7268,9 @@ async function handleConnectionsRequest(opts) {
7265
7268
  return;
7266
7269
  }
7267
7270
  res.setHeader("Allow", "POST, GET, DELETE");
7268
- writeJson(res, 405, { message: "MethodNotAllowedException" });
7271
+ writeJson$1(res, 405, { message: "MethodNotAllowedException" });
7269
7272
  }
7270
- function writeJson(res, status, body) {
7273
+ function writeJson$1(res, status, body) {
7271
7274
  const json = JSON.stringify(body);
7272
7275
  res.writeHead(status, {
7273
7276
  "Content-Type": "application/json",
@@ -11049,7 +11052,7 @@ async function startApiServer(opts) {
11049
11052
  const logger = getLogger().child("start-api");
11050
11053
  let currentState = opts.state;
11051
11054
  const requestHandler = (req, res) => {
11052
- handleRequest$2(req, res, currentState, opts).catch((err) => {
11055
+ handleRequest$3(req, res, currentState, opts).catch((err) => {
11053
11056
  logger.error(`Unhandled request error: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
11054
11057
  if (!res.headersSent) writeError$1(res, 502);
11055
11058
  });
@@ -11101,7 +11104,7 @@ async function startApiServer(opts) {
11101
11104
  getServerState: () => currentState
11102
11105
  };
11103
11106
  }
11104
- async function handleRequest$2(req, res, state, opts) {
11107
+ async function handleRequest$3(req, res, state, opts) {
11105
11108
  const logger = getLogger().child("start-api");
11106
11109
  if (opts.preDispatch) try {
11107
11110
  if (await opts.preDispatch(req, res)) return;
@@ -16030,7 +16033,7 @@ async function runAgentCoreWatchLoop(args) {
16030
16033
  }
16031
16034
  }
16032
16035
  }
16033
- const execFileAsync$5 = promisify(execFile);
16036
+ const execFileAsync$6 = promisify(execFile);
16034
16037
  function describeExecError(err) {
16035
16038
  if (!(err instanceof Error)) return String(err);
16036
16039
  const stderr = err.stderr;
@@ -16042,7 +16045,7 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
16042
16045
  const dockerCmd = getDockerCmd();
16043
16046
  let workdir;
16044
16047
  try {
16045
- const { stdout } = await execFileAsync$5(dockerCmd, [
16048
+ const { stdout } = await execFileAsync$6(dockerCmd, [
16046
16049
  "inspect",
16047
16050
  "--format",
16048
16051
  "{{.Config.WorkingDir}}",
@@ -16055,7 +16058,7 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
16055
16058
  const workdirDest = workdir.endsWith("/") ? workdir : `${workdir}/`;
16056
16059
  logger.info(`Soft-reload: docker cp ${flattenToOneLine(newAssetSourceDir)} -> ${containerId}:${workdirDest}; restart.`);
16057
16060
  try {
16058
- await execFileAsync$5(dockerCmd, [
16061
+ await execFileAsync$6(dockerCmd, [
16059
16062
  "cp",
16060
16063
  `${newAssetSourceDir}/.`,
16061
16064
  `${containerId}:${workdirDest}`
@@ -16064,7 +16067,7 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
16064
16067
  throw new CdkLocalError(`softReloadAgentContainer: docker cp into '${containerId}:${workdir}' failed: ${describeExecError(err)}.`, "LOCAL_INVOKE_AGENTCORE_WATCH_SOFT_RELOAD_CP_FAILED");
16065
16068
  }
16066
16069
  try {
16067
- await execFileAsync$5(dockerCmd, ["restart", containerId]);
16070
+ await execFileAsync$6(dockerCmd, ["restart", containerId]);
16068
16071
  } catch (err) {
16069
16072
  throw new CdkLocalError(`softReloadAgentContainer: docker restart of '${containerId}' failed: ${describeExecError(err)}.`, "LOCAL_INVOKE_AGENTCORE_WATCH_SOFT_RELOAD_RESTART_FAILED");
16070
16073
  }
@@ -16240,7 +16243,7 @@ function writePrefixedLines(prefix, buffer, out) {
16240
16243
 
16241
16244
  //#endregion
16242
16245
  //#region src/local/ecs-network.ts
16243
- const execFileAsync$4 = promisify(execFile);
16246
+ const execFileAsync$5 = promisify(execFile);
16244
16247
  const METADATA_ENDPOINT_IMAGE = "amazon/amazon-ecs-local-container-endpoints:latest-amd64";
16245
16248
  const METADATA_ENDPOINT_IP = "169.254.170.2";
16246
16249
  const DEFAULT_METADATA_ENDPOINT_SUBNET = "169.254.170.0/24";
@@ -16276,7 +16279,7 @@ async function sweepOrphanedSvcNetworks(prefix) {
16276
16279
  const filter = `${prefix}-svc-`;
16277
16280
  let names;
16278
16281
  try {
16279
- const { stdout } = await execFileAsync$4(getDockerCmd(), [
16282
+ const { stdout } = await execFileAsync$5(getDockerCmd(), [
16280
16283
  "network",
16281
16284
  "ls",
16282
16285
  "--filter",
@@ -16294,7 +16297,7 @@ async function sweepOrphanedSvcNetworks(prefix) {
16294
16297
  for (const name of names) {
16295
16298
  let attached;
16296
16299
  try {
16297
- const { stdout } = await execFileAsync$4(getDockerCmd(), [
16300
+ const { stdout } = await execFileAsync$5(getDockerCmd(), [
16298
16301
  "network",
16299
16302
  "inspect",
16300
16303
  name,
@@ -16322,7 +16325,7 @@ async function createNetworkAndSidecar(args) {
16322
16325
  await pullImage(METADATA_ENDPOINT_IMAGE, skipPull);
16323
16326
  logger.info(`Creating docker network ${networkName} (subnet ${cidr})...`);
16324
16327
  try {
16325
- await execFileAsync$4(getDockerCmd(), [
16328
+ await execFileAsync$5(getDockerCmd(), [
16326
16329
  "network",
16327
16330
  "create",
16328
16331
  "--driver",
@@ -16359,7 +16362,7 @@ async function createNetworkAndSidecar(args) {
16359
16362
  warnFinchArgvExposure(Object.keys(sidecarPassthroughEnv));
16360
16363
  logger.info(`Starting ECS local-container-endpoints sidecar at ${sidecarIp}...`);
16361
16364
  try {
16362
- const { stdout } = await execFileAsync$4(getDockerCmd(), sidecarArgs, {
16365
+ const { stdout } = await execFileAsync$5(getDockerCmd(), sidecarArgs, {
16363
16366
  maxBuffer: 10 * 1024 * 1024,
16364
16367
  ...execEnvForSecrets(sidecarPassthroughEnv)
16365
16368
  });
@@ -16407,7 +16410,7 @@ async function destroyNetworkOnly(networkName) {
16407
16410
  if (!networkName) return;
16408
16411
  const logger = getLogger().child("ecs-network");
16409
16412
  try {
16410
- await execFileAsync$4(getDockerCmd(), [
16413
+ await execFileAsync$5(getDockerCmd(), [
16411
16414
  "network",
16412
16415
  "rm",
16413
16416
  networkName
@@ -16521,7 +16524,7 @@ async function resolveSsm(entry, shape, client) {
16521
16524
 
16522
16525
  //#endregion
16523
16526
  //#region src/local/ecs-task-runner.ts
16524
- const execFileAsync$3 = promisify(execFile);
16527
+ const execFileAsync$4 = promisify(execFile);
16525
16528
  var EcsTaskRunnerError = class EcsTaskRunnerError extends Error {
16526
16529
  constructor(message) {
16527
16530
  super(message);
@@ -16564,7 +16567,7 @@ async function cleanupEcsRun(state, options) {
16564
16567
  if (state.network && !state.network.ownedByCaller) await destroyTaskNetwork(state.network);
16565
16568
  state.network = void 0;
16566
16569
  for (const v of state.dockerVolumeNames) try {
16567
- await execFileAsync$3(getDockerCmd(), [
16570
+ await execFileAsync$4(getDockerCmd(), [
16568
16571
  "volume",
16569
16572
  "rm",
16570
16573
  v
@@ -16715,7 +16718,7 @@ async function runEcsTask(task, options, state) {
16715
16718
  let id;
16716
16719
  warnFinchArgvExposure(Object.keys(sensitiveEnv));
16717
16720
  try {
16718
- const { stdout } = await execFileAsync$3(getDockerCmd(), args, {
16721
+ const { stdout } = await execFileAsync$4(getDockerCmd(), args, {
16719
16722
  maxBuffer: 10 * 1024 * 1024,
16720
16723
  ...execEnvForSecrets(sensitiveEnv)
16721
16724
  });
@@ -16807,7 +16810,7 @@ async function waitForContainerHealthy(containerId, displayName) {
16807
16810
  let lastStatus = "";
16808
16811
  while (Date.now() < deadline) {
16809
16812
  try {
16810
- const { stdout } = await execFileAsync$3(getDockerCmd(), [
16813
+ const { stdout } = await execFileAsync$4(getDockerCmd(), [
16811
16814
  "inspect",
16812
16815
  "--format",
16813
16816
  "{{.State.Health.Status}}",
@@ -16830,7 +16833,7 @@ async function waitForContainerHealthy(containerId, displayName) {
16830
16833
  }
16831
16834
  async function waitForContainerExit(containerId) {
16832
16835
  try {
16833
- const { stdout } = await execFileAsync$3(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
16836
+ const { stdout } = await execFileAsync$4(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
16834
16837
  const code = Number.parseInt(stdout.trim(), 10);
16835
16838
  return Number.isFinite(code) ? code : 1;
16836
16839
  } catch (err) {
@@ -16840,7 +16843,7 @@ async function waitForContainerExit(containerId) {
16840
16843
  }
16841
16844
  async function stopContainer(containerId, graceSeconds) {
16842
16845
  try {
16843
- await execFileAsync$3(getDockerCmd(), [
16846
+ await execFileAsync$4(getDockerCmd(), [
16844
16847
  "stop",
16845
16848
  "-t",
16846
16849
  String(graceSeconds),
@@ -16935,7 +16938,7 @@ async function realizeDockerVolumes(volumes, state) {
16935
16938
  const dockerVolumeName = `${getEmbedConfig().resourceNamePrefix}-${v.name}-${randHex(4)}`;
16936
16939
  args.push(dockerVolumeName);
16937
16940
  try {
16938
- await execFileAsync$3(getDockerCmd(), args);
16941
+ await execFileAsync$4(getDockerCmd(), args);
16939
16942
  state.dockerVolumeNames.push(dockerVolumeName);
16940
16943
  logger.debug(`Created docker volume ${displayIdent(dockerVolumeName)} for task volume ${displayIdent(v.name)}`);
16941
16944
  } catch (err) {
@@ -17335,11 +17338,11 @@ function notFoundError$1(target, stack, resources, parsed) {
17335
17338
 
17336
17339
  //#endregion
17337
17340
  //#region src/local/docker-inspect.ts
17338
- const execFileAsync$2 = promisify(execFile);
17341
+ const execFileAsync$3 = promisify(execFile);
17339
17342
  async function getContainerNetworkIp(containerId, networkName) {
17340
17343
  const format = `{{with index .NetworkSettings.Networks "${networkName}"}}{{.IPAddress}}{{end}}`;
17341
17344
  try {
17342
- const { stdout } = await execFileAsync$2(getDockerCmd(), [
17345
+ const { stdout } = await execFileAsync$3(getDockerCmd(), [
17343
17346
  "inspect",
17344
17347
  "--format",
17345
17348
  format,
@@ -17355,7 +17358,7 @@ async function getContainerNetworkIp(containerId, networkName) {
17355
17358
  async function getPublishedHostPort(containerId, containerPort, protocol = "tcp") {
17356
17359
  const format = `{{with index .NetworkSettings.Ports "${`${containerPort}/${protocol}`}"}}{{with index . 0}}{{.HostPort}}{{end}}{{end}}`;
17357
17360
  try {
17358
- const { stdout } = await execFileAsync$2(getDockerCmd(), [
17361
+ const { stdout } = await execFileAsync$3(getDockerCmd(), [
17359
17362
  "inspect",
17360
17363
  "--format",
17361
17364
  format,
@@ -18653,7 +18656,7 @@ function buildHeaderMaps(headers) {
18653
18656
  multi
18654
18657
  };
18655
18658
  }
18656
- function firstHeader(headers, name) {
18659
+ function firstHeader$1(headers, name) {
18657
18660
  const lower = name.toLowerCase();
18658
18661
  for (const [k, v] of Object.entries(headers)) if (k.toLowerCase() === lower) return v[0];
18659
18662
  }
@@ -18661,8 +18664,8 @@ function buildAlbLambdaEvent(req, opts) {
18661
18664
  const { path, rawQuery } = splitRawUrl(req.rawUrl);
18662
18665
  const query = parseQuery(rawQuery);
18663
18666
  const headerMaps = buildHeaderMaps(req.headers);
18664
- const contentEncoding = firstHeader(req.headers, "content-encoding");
18665
- const contentType = firstHeader(req.headers, "content-type") ?? "";
18667
+ const contentEncoding = firstHeader$1(req.headers, "content-encoding");
18668
+ const contentType = firstHeader$1(req.headers, "content-type") ?? "";
18666
18669
  const isBase64Encoded = req.body.length > 0 && (contentEncoding !== void 0 ? true : !isTextualContentType(contentType));
18667
18670
  const body = isBase64Encoded ? req.body.toString("base64") : req.body.toString("utf-8");
18668
18671
  const event = {
@@ -18765,7 +18768,7 @@ async function startFrontDoorServer(opts) {
18765
18768
  const scheme = opts.tls ? "https" : "http";
18766
18769
  server.on("connection", (socket) => socket.setNoDelay(true));
18767
18770
  server.on("upgrade", (req, clientSocket, head) => {
18768
- handleUpgrade(req, clientSocket, head, effectiveOpts).catch((err) => {
18771
+ handleUpgrade$1(req, clientSocket, head, effectiveOpts).catch((err) => {
18769
18772
  logger.debug(`front-door upgrade error: ${err instanceof Error ? err.message : String(err)}`);
18770
18773
  if (!clientSocket.destroyed) clientSocket.destroy();
18771
18774
  });
@@ -19109,7 +19112,7 @@ function writeError(res, statusCode, message) {
19109
19112
  res.writeHead(statusCode, { "content-type": "text/plain; charset=utf-8" });
19110
19113
  res.end(`${message}\n`);
19111
19114
  }
19112
- function handleUpgrade(req, clientSocket, head, opts) {
19115
+ function handleUpgrade$1(req, clientSocket, head, opts) {
19113
19116
  clientSocket.setNoDelay?.(true);
19114
19117
  if (!opts.route) {
19115
19118
  writeRawHttpError(clientSocket, 404, "Not Found");
@@ -19296,7 +19299,9 @@ function sanitizeRawHeaderValue(value) {
19296
19299
  const STATUS_TEXT$1 = {
19297
19300
  301: "Moved Permanently",
19298
19301
  302: "Found",
19302
+ 400: "Bad Request",
19299
19303
  401: "Unauthorized",
19304
+ 403: "Forbidden",
19300
19305
  404: "Not Found",
19301
19306
  502: "Bad Gateway",
19302
19307
  503: "Service Unavailable"
@@ -19550,7 +19555,7 @@ function matchBitPrefix(a, b, prefixLength) {
19550
19555
 
19551
19556
  //#endregion
19552
19557
  //#region src/local/front-door-tls.ts
19553
- const execFileAsync$1 = promisify(execFile);
19558
+ const execFileAsync$2 = promisify(execFile);
19554
19559
  async function resolveFrontDoorTlsMaterials(opts) {
19555
19560
  const hasCert = opts.certPath !== void 0 && opts.certPath !== "";
19556
19561
  const hasKey = opts.keyPath !== void 0 && opts.keyPath !== "";
@@ -19640,7 +19645,7 @@ function readCertNotAfter(certPath) {
19640
19645
  }
19641
19646
  }
19642
19647
  async function runOpenssl(args) {
19643
- await execFileAsync$1("openssl", args, { timeout: 3e4 });
19648
+ await execFileAsync$2("openssl", args, { timeout: 3e4 });
19644
19649
  }
19645
19650
  function readPemOrThrow(path, flagName) {
19646
19651
  try {
@@ -21843,7 +21848,7 @@ function resolveAlbFrontDoor(stack, albLogicalId) {
21843
21848
  if (resource.Type !== LISTENER_TYPE) continue;
21844
21849
  const props = resource.Properties ?? {};
21845
21850
  if (refOf(props["LoadBalancerArn"]) !== albLogicalId) continue;
21846
- const port = parsePort$2(props["Port"]);
21851
+ const port = parsePort$3(props["Port"]);
21847
21852
  if (port === void 0) continue;
21848
21853
  const protocol = typeof props["Protocol"] === "string" ? props["Protocol"] : "HTTP";
21849
21854
  if (protocol !== "HTTP" && protocol !== "HTTPS") {
@@ -22208,7 +22213,7 @@ function refOf(raw) {
22208
22213
  if (typeof ref === "string" && ref.length > 0) return ref;
22209
22214
  }
22210
22215
  }
22211
- function parsePort$2(raw) {
22216
+ function parsePort$3(raw) {
22212
22217
  if (typeof raw === "number" && Number.isInteger(raw) && raw >= 1 && raw <= 65535) return raw;
22213
22218
  if (typeof raw === "string" && /^\d+$/.test(raw)) {
22214
22219
  const n = parseInt(raw, 10);
@@ -22216,7 +22221,7 @@ function parsePort$2(raw) {
22216
22221
  }
22217
22222
  }
22218
22223
  function parseContainerPort(raw) {
22219
- return parsePort$2(raw);
22224
+ return parsePort$3(raw);
22220
22225
  }
22221
22226
  function parseWeight(raw) {
22222
22227
  if (typeof raw === "number" && Number.isFinite(raw)) return raw < 0 ? 0 : raw;
@@ -23554,7 +23559,7 @@ async function startCloudFrontServer(options) {
23554
23559
  const s3OriginReaders = options.s3OriginReaders ?? /* @__PURE__ */ new Map();
23555
23560
  const state = { distribution: options.distribution };
23556
23561
  const handler = (req, res) => {
23557
- handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger).catch((err) => {
23562
+ handleRequest$2(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger).catch((err) => {
23558
23563
  logger.warn(`Request handling failed: ${err instanceof Error ? err.message : String(err)}`);
23559
23564
  if (!res.headersSent) {
23560
23565
  res.statusCode = 500;
@@ -23583,7 +23588,7 @@ async function startCloudFrontServer(options) {
23583
23588
  }
23584
23589
  };
23585
23590
  }
23586
- async function handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger) {
23591
+ async function handleRequest$2(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger) {
23587
23592
  const distribution = state.distribution;
23588
23593
  const rawUrl = req.url ?? "/";
23589
23594
  const queryIdx = rawUrl.indexOf("?");
@@ -24892,7 +24897,7 @@ function readAuthorizationHeader(headers) {
24892
24897
 
24893
24898
  //#endregion
24894
24899
  //#region src/cli/commands/local-start-agentcore.ts
24895
- function parsePort$1(raw) {
24900
+ function parsePort$2(raw) {
24896
24901
  const n = Number(raw);
24897
24902
  if (!Number.isInteger(n) || n < 0 || n > 65535) throw new InvalidArgumentError(`--port must be an integer 0-65535, got '${raw}'.`);
24898
24903
  return n;
@@ -25220,7 +25225,7 @@ function createLocalStartAgentCoreCommand(opts = {}) {
25220
25225
  return cmd;
25221
25226
  }
25222
25227
  function addStartAgentCoreSpecificOptions(cmd) {
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."));
25228
+ 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$2)).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
25229
  }
25225
25230
 
25226
25231
  //#endregion
@@ -25399,17 +25404,17 @@ function describeRevisions(revisions, stack) {
25399
25404
  const SUPPORTED_CODE_CONFIG_KEYS = ["S3Object"];
25400
25405
  function parseWebFunctionBuildConfig(revisionLogicalId, buildConfig) {
25401
25406
  const subject = `Web function revision ${displayIdent(revisionLogicalId)}`;
25402
- const build = asObject$1(buildConfig);
25403
- const runtime = asObject$1(build?.["RuntimeConfig"])?.["Runtime"];
25407
+ const build = asObject$2(buildConfig);
25408
+ const runtime = asObject$2(build?.["RuntimeConfig"])?.["Runtime"];
25404
25409
  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"]);
25410
+ const codeConfig = asObject$2(build?.["CodeConfig"]);
25406
25411
  if (!codeConfig) throw new CdkLocalError(`${subject} has no BuildConfig.CodeConfig object.`, "LOCAL_START_WEB_FUNCTION_NO_CODE_CONFIG");
25407
25412
  const unknownKeys = Object.keys(codeConfig).filter((k) => !SUPPORTED_CODE_CONFIG_KEYS.includes(k));
25408
25413
  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"]);
25414
+ const s3 = asObject$2(codeConfig["S3Object"]);
25410
25415
  if (!s3) throw new CdkLocalError(`${subject} has no BuildConfig.CodeConfig.S3Object.`, "LOCAL_START_WEB_FUNCTION_NO_CODE_CONFIG");
25411
25416
  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");
25417
+ if (typeof key !== "string" || key.length === 0) throw new CdkLocalError(`${subject} has a CodeConfig.S3Object.Key that is not a literal string (${describeValue$1(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
25418
  const versionId = s3["VersionId"];
25414
25419
  return {
25415
25420
  runtime,
@@ -25434,7 +25439,7 @@ function findFileAssetForObjectKey(manifest, key) {
25434
25439
  }
25435
25440
  async function resolveWebFunctionArtifact(stack, revisionLogicalId, code, loader = new AssetManifestLoader()) {
25436
25441
  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");
25442
+ const notFound = () => new CdkLocalError(`${subject} (S3Object bucket ${describeValue$1(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
25443
  const manifestPath = stack.assetManifestPath;
25439
25444
  if (!manifestPath) throw notFound();
25440
25445
  const manifestDir = dirname$1(manifestPath);
@@ -25473,10 +25478,10 @@ function disposeWebFunctionArtifact(artifact) {
25473
25478
  });
25474
25479
  } catch {}
25475
25480
  }
25476
- function asObject$1(value) {
25481
+ function asObject$2(value) {
25477
25482
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
25478
25483
  }
25479
- function describeValue(value) {
25484
+ function describeValue$1(value) {
25480
25485
  if (typeof value === "string") return displayUntrustedValue(value);
25481
25486
  let json;
25482
25487
  try {
@@ -25531,12 +25536,12 @@ const WEB_FUNCTION_HTTP_ENDPOINT_ENV = "AWS_LAMBDA_HTTP_ENDPOINT";
25531
25536
  const APPLICATION_MANAGED_AUTH = "ApplicationManaged";
25532
25537
  const HOME_REGION_ENDPOINT = "HomeRegion";
25533
25538
  function readWebFunctionServiceConfig(revision) {
25534
- const sc = asObject(revision.Properties?.["ServiceConfig"]) ?? {};
25539
+ const sc = asObject$1(revision.Properties?.["ServiceConfig"]) ?? {};
25535
25540
  const envRaw = sc["EnvironmentVariables"];
25536
- const envObj = asObject(envRaw);
25541
+ const envObj = asObject$1(envRaw);
25537
25542
  const envKeys = envObj ? Object.keys(envObj) : [];
25538
25543
  const env = envKeys.length === 1 && (envKeys[0] === "Ref" || envKeys[0].startsWith("Fn::")) ? void 0 : envObj;
25539
- const logGroup = asObject(asObject(sc["TelemetryConfig"])?.["LoggingConfig"])?.["LogGroup"];
25544
+ const logGroup = asObject$1(asObject$1(sc["TelemetryConfig"])?.["LoggingConfig"])?.["LogGroup"];
25540
25545
  return {
25541
25546
  environmentVariables: env,
25542
25547
  environmentUnreadable: envRaw !== void 0 && env === void 0,
@@ -25602,13 +25607,13 @@ function webFunctionFidelityWarnings(resolved, config) {
25602
25607
  }
25603
25608
  return out;
25604
25609
  }
25605
- function asObject(value) {
25610
+ function asObject$1(value) {
25606
25611
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
25607
25612
  }
25608
25613
 
25609
25614
  //#endregion
25610
25615
  //#region src/local/web-function-runner.ts
25611
- const execFileAsync = promisify$1(execFile$1);
25616
+ const execFileAsync$1 = promisify$1(execFile$1);
25612
25617
  const WEB_FUNCTION_CONTAINER_PORT = 8080;
25613
25618
  const READY_FAILURE_LOG_LINES = 20;
25614
25619
  const MAX_PROBE_TIMEOUT_MS = 1e4;
@@ -25750,7 +25755,7 @@ function probeHttp(host, port, timeoutMs) {
25750
25755
  }
25751
25756
  async function containerIsRunning(containerId) {
25752
25757
  try {
25753
- const { stdout } = await execFileAsync(getDockerCmd(), [
25758
+ const { stdout } = await execFileAsync$1(getDockerCmd(), [
25754
25759
  "inspect",
25755
25760
  "-f",
25756
25761
  "{{.State.Running}}",
@@ -25802,12 +25807,12 @@ const defaultReadyDeps = {
25802
25807
 
25803
25808
  //#endregion
25804
25809
  //#region src/cli/commands/local-start-web-function.ts
25805
- function parsePort(raw) {
25810
+ function parsePort$1(raw) {
25806
25811
  const n = Number(raw);
25807
25812
  if (!Number.isInteger(n) || n < 0 || n > 65535) throw new InvalidArgumentError(`--port must be an integer 0-65535, got '${raw}'.`);
25808
25813
  return n;
25809
25814
  }
25810
- function connectHost(host) {
25815
+ function connectHost$1(host) {
25811
25816
  if (host === "0.0.0.0") return "127.0.0.1";
25812
25817
  if (host === "::" || host === "[::]") return "::1";
25813
25818
  return host;
@@ -25936,7 +25941,7 @@ async function localStartWebFunctionCommand(target, options, extraStateProviders
25936
25941
  containerId = id;
25937
25942
  stopLogs = streamLogs(id, { onOutput: (chunk) => recent.push(chunk) });
25938
25943
  exitWatch = watchContainerExit(id);
25939
- const probeHost = connectHost(options.host);
25944
+ const probeHost = connectHost$1(options.host);
25940
25945
  await waitForWebFunctionReady({
25941
25946
  containerId: id,
25942
25947
  host: probeHost,
@@ -25974,7 +25979,1195 @@ function createLocalStartWebFunctionCommand(opts = {}) {
25974
25979
  return cmd;
25975
25980
  }
25976
25981
  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."));
25982
+ 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$1)).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."));
25983
+ }
25984
+
25985
+ //#endregion
25986
+ //#region src/local/microvm-image.ts
25987
+ const MICROVM_IMAGE_TYPE = "AWS::Lambda::MicrovmImage";
25988
+ const MICROVM_DEFAULT_INGRESS_PORT = 8080;
25989
+ var MicrovmResolutionError = class MicrovmResolutionError extends Error {
25990
+ constructor(message) {
25991
+ super(message);
25992
+ this.name = "MicrovmResolutionError";
25993
+ Object.setPrototypeOf(this, MicrovmResolutionError.prototype);
25994
+ }
25995
+ };
25996
+ function resolveMicrovmImageTarget(target, stacks) {
25997
+ if (stacks.length === 0) throw new MicrovmResolutionError("No stacks found in the synthesized assembly.");
25998
+ const parsed = parseTarget(target);
25999
+ const selection = selectTargetStack(parsed, target, stacks);
26000
+ let stack;
26001
+ switch (selection.kind) {
26002
+ case "found":
26003
+ stack = selection.stack;
26004
+ break;
26005
+ case "no-prefix": throw new MicrovmResolutionError(`Multiple stacks in app, target ${displayIdent(parsed.pathOrId)} is missing a stack prefix. Use StackName:<logicalId> or StackName/... (path form). Available stacks: ${describeStacks(stacks)}.`);
26006
+ case "not-found": throw new MicrovmResolutionError(`Stack ${displayStackName(selection.pattern)} not found. Available stacks: ${describeStacks(stacks)}.`);
26007
+ case "ambiguous": throw new MicrovmResolutionError(`Stack pattern ${displayStackName(selection.pattern)} matched ${selection.matched.length} stacks: ${describeStacks(selection.matched)}. Use a more specific pattern, or the stack's display path.`);
26008
+ }
26009
+ const resources = stack.template.Resources ?? {};
26010
+ const images = Object.keys(resources).filter((id) => resources[id]?.Type === MICROVM_IMAGE_TYPE);
26011
+ const notFound = () => new MicrovmResolutionError(`Target ${displayStackName(target)} not found. ` + (images.length > 0 ? `MicroVM images in ${displayStackName(stack.stackName)}: ${images.map((id) => displayIdent(id)).join(", ")}.` : `No ${MICROVM_IMAGE_TYPE} resources found in ${displayStackName(stack.stackName)}.`));
26012
+ if (parsed.isPath) {
26013
+ const matches = resolveCdkPathToLogicalIds(parsed.pathOrId, buildCdkPathIndex(stack.template)).filter(({ logicalId }) => resources[logicalId]?.Type === MICROVM_IMAGE_TYPE);
26014
+ if (matches.length === 1) {
26015
+ const id = matches[0].logicalId;
26016
+ return {
26017
+ stack,
26018
+ logicalId: id,
26019
+ resource: resources[id]
26020
+ };
26021
+ }
26022
+ if (matches.length > 1) throw new MicrovmResolutionError(`Target ${displayStackName(target)} matches ${matches.length} ${MICROVM_IMAGE_TYPE} resources: ${matches.map((m) => displayIdent(m.logicalId)).join(", ")}. Refine the path or use the StackName:<logicalId> form.`);
26023
+ throw notFound();
26024
+ }
26025
+ const resource = resources[parsed.pathOrId];
26026
+ if (!resource) throw notFound();
26027
+ if (resource.Type !== "AWS::Lambda::MicrovmImage") throw new MicrovmResolutionError(`Resource ${displayIdent(parsed.pathOrId)} in ${displayStackName(stack.stackName)} is ${displayIdent(resource.Type)}, not a MicroVM image. ${getEmbedConfig().cliName} start-microvm runs ${MICROVM_IMAGE_TYPE} targets.`);
26028
+ return {
26029
+ stack,
26030
+ logicalId: parsed.pathOrId,
26031
+ resource
26032
+ };
26033
+ }
26034
+ const HOOK_KEYS = {
26035
+ ready: {
26036
+ group: "MicrovmImageHooks",
26037
+ key: "Ready"
26038
+ },
26039
+ validate: {
26040
+ group: "MicrovmImageHooks",
26041
+ key: "Validate"
26042
+ },
26043
+ run: {
26044
+ group: "MicrovmHooks",
26045
+ key: "Run"
26046
+ },
26047
+ suspend: {
26048
+ group: "MicrovmHooks",
26049
+ key: "Suspend"
26050
+ },
26051
+ resume: {
26052
+ group: "MicrovmHooks",
26053
+ key: "Resume"
26054
+ },
26055
+ terminate: {
26056
+ group: "MicrovmHooks",
26057
+ key: "Terminate"
26058
+ }
26059
+ };
26060
+ function readMicrovmImageConfig(logicalId, resource) {
26061
+ const subject = `MicroVM image ${displayIdent(logicalId)}`;
26062
+ const props = resource.Properties ?? {};
26063
+ const name = typeof props["Name"] === "string" && props["Name"].length > 0 ? props["Name"] : logicalId;
26064
+ const uri = asObject(props["CodeArtifact"])?.["Uri"];
26065
+ const codeKey = s3KeyOfUri(uri);
26066
+ if (codeKey === void 0) throw new CdkLocalError(`${subject} has a CodeArtifact.Uri whose object key is not a literal (${describeValue(uri)}). The code must come from a CDK asset in this app (for example an s3assets.Asset of a directory holding the Dockerfile, passing asset.s3ObjectUrl), whose key synthesizes as a literal.`, "LOCAL_START_MICROVM_CODE_URI_NOT_LITERAL");
26067
+ const cpu = props["CpuConfigurations"];
26068
+ const archRaw = Array.isArray(cpu) ? asObject(cpu[0])?.["Architecture"] : void 0;
26069
+ const architecture = typeof archRaw === "string" ? normalizeArchitecture(archRaw) : void 0;
26070
+ const environment = {};
26071
+ const envRaw = props["EnvironmentVariables"];
26072
+ const unemulated = [];
26073
+ if (Array.isArray(envRaw)) for (const entry of envRaw) {
26074
+ const e = asObject(entry);
26075
+ if (e && typeof e["Key"] === "string") environment[e["Key"]] = e["Value"];
26076
+ }
26077
+ else if (envRaw !== void 0) unemulated.push("EnvironmentVariables is an intrinsic rather than a list, so none of its variables reach the container (supply them with --env-vars)");
26078
+ const hooksObj = asObject(props["Hooks"]);
26079
+ const hooks = {};
26080
+ for (const [hook, where] of Object.entries(HOOK_KEYS)) {
26081
+ const group = asObject(hooksObj?.[where.group]);
26082
+ const value = group?.[where.key];
26083
+ if (value === void 0 || value === "DISABLED") continue;
26084
+ if (value !== "ENABLED") throw new CdkLocalError(`${subject} has Hooks.${where.group}.${where.key} ${describeValue(value)}; only the literal ENABLED or DISABLED can run locally.`, "LOCAL_START_MICROVM_HOOK_VALUE");
26085
+ const timeout = group?.[`${where.key}TimeoutInSeconds`];
26086
+ hooks[hook] = { timeoutSeconds: typeof timeout === "number" && timeout > 0 ? timeout : void 0 };
26087
+ }
26088
+ const port = hooksObj?.["Port"];
26089
+ const hooksPort = typeof port === "number" && Number.isInteger(port) && port > 0 && port < 65536 ? port : void 0;
26090
+ if (Object.keys(hooks).length > 0 && hooksPort === void 0) throw new CdkLocalError(`${subject} enables lifecycle hooks (${Object.keys(hooks).join(", ")}) but has no literal Hooks.Port. Lambda requires the hooks port whenever a hook is configured; set Hooks.Port to the port the application serves /aws/lambda-microvms/runtime/v1/ on.`, "LOCAL_START_MICROVM_NO_HOOKS_PORT");
26091
+ const present = (key) => {
26092
+ const v = props[key];
26093
+ if (v === void 0 || v === null) return false;
26094
+ if (Array.isArray(v)) return v.length > 0;
26095
+ if (typeof v === "object") return Object.keys(v).length > 0;
26096
+ return true;
26097
+ };
26098
+ if (present("EgressNetworkConnectors")) unemulated.push("EgressNetworkConnectors (the container uses Docker's default network egress)");
26099
+ if (present("AdditionalOsCapabilities")) unemulated.push("AdditionalOsCapabilities (the container runs with Docker's default capabilities)");
26100
+ if (present("Resources")) unemulated.push("Resources sizing (the container gets no memory limit)");
26101
+ if (present("BaseImageVersion")) unemulated.push("BaseImageVersion (the local build uses whatever the Dockerfile names)");
26102
+ if (present("Logging")) unemulated.push("Logging (container output is printed here instead of sent to CloudWatch Logs)");
26103
+ return {
26104
+ logicalId,
26105
+ name,
26106
+ codeKey,
26107
+ architecture,
26108
+ environment,
26109
+ hooksPort,
26110
+ hooks,
26111
+ unemulated
26112
+ };
26113
+ }
26114
+ function normalizeArchitecture(raw) {
26115
+ const s = raw.toLowerCase().replace(/_/g, "");
26116
+ if (s === "arm64") return "arm64";
26117
+ if (s === "x8664") return "x86_64";
26118
+ }
26119
+ function s3KeyOfUri(value) {
26120
+ const flat = flattenTemplateString(value);
26121
+ if (flat === void 0) return void 0;
26122
+ const m = /^s3:\/\/[^/]*\/(.+)$/.exec(flat);
26123
+ if (!m) return void 0;
26124
+ const key = m[1];
26125
+ return key.includes("\0") || key.includes("${") ? void 0 : key;
26126
+ }
26127
+ function flattenTemplateString(value) {
26128
+ if (typeof value === "string") return value;
26129
+ const obj = asObject(value);
26130
+ if (!obj) return void 0;
26131
+ const join = obj["Fn::Join"];
26132
+ if (Array.isArray(join) && typeof join[0] === "string" && Array.isArray(join[1])) return join[1].map((p) => flattenTemplateString(p) ?? "\0").join(join[0]);
26133
+ const sub = obj["Fn::Sub"];
26134
+ if (typeof sub === "string") return sub.replace(/\$\{[^}]*\}/g, "\0");
26135
+ if (Array.isArray(sub) && typeof sub[0] === "string") return sub[0].replace(/\$\{[^}]*\}/g, "\0");
26136
+ return "\0";
26137
+ }
26138
+ async function resolveMicrovmCodeArtifact(stack, config, loader = new AssetManifestLoader()) {
26139
+ const subject = `MicroVM image ${displayUntrustedValue(config.logicalId)} code artifact`;
26140
+ const notFound = () => new CdkLocalError(`${subject} (key ${displayUntrustedValue(config.codeKey)}) matches no file asset in this app's cdk.out. ${getEmbedConfig().cliName} start-microvm builds code that comes from a CDK asset in this app (for example an s3assets.Asset of a directory holding the Dockerfile); it does not download deployed code. Re-synthesize the app, or point CodeArtifact.Uri at an asset.`, "LOCAL_START_MICROVM_CODE_ASSET_NOT_FOUND");
26141
+ const manifestPath = stack.assetManifestPath;
26142
+ if (!manifestPath) throw notFound();
26143
+ const manifestDir = dirname$1(manifestPath);
26144
+ const manifest = await loader.loadStackManifest(stack, manifestDir);
26145
+ const match = manifest ? findFileAssetForObjectKey(manifest, config.codeKey) : void 0;
26146
+ if (!match) throw notFound();
26147
+ 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 build. Give the image an asset of a directory or a .zip file.`, "LOCAL_START_MICROVM_CODE_ASSET_NO_PATH");
26148
+ const sourcePath = resolveAssetSourcePath({
26149
+ manifestDir,
26150
+ value: match.asset.source.path,
26151
+ assetOutdir: assetPathDirs(stack).assetOutdir,
26152
+ absolute: "honour-warn",
26153
+ field: "source.path",
26154
+ subject,
26155
+ action: "build it",
26156
+ sink: "send that directory to docker build as the MicroVM image context",
26157
+ wrapError: (message) => new CdkLocalError(message, "LOCAL_START_MICROVM_CODE_SOURCE_ESCAPES_ASSEMBLY")
26158
+ });
26159
+ if (!existsSync$1(sourcePath)) throw new CdkLocalError(`${subject} source ${displayUntrustedValue(sourcePath)} does not exist. Re-synthesize the app and retry.`, "LOCAL_START_MICROVM_CODE_SOURCE_MISSING");
26160
+ 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_MICROVM_CODE_SOURCE_NOT_BUNDLE");
26161
+ const materialized = materializeAssetCodeDir(sourcePath);
26162
+ const artifact = {
26163
+ contextDir: materialized.dir,
26164
+ ...materialized.tmpDir !== void 0 && { tmpDir: materialized.tmpDir },
26165
+ assetHash: match.hash
26166
+ };
26167
+ if (!existsSync$1(join$1(materialized.dir, "Dockerfile"))) {
26168
+ disposeMicrovmCodeArtifact(artifact);
26169
+ throw new CdkLocalError(`${subject} has no Dockerfile at its root. A MicroVM image's code artifact is a zip with a Dockerfile at the root plus the application files.`, "LOCAL_START_MICROVM_NO_DOCKERFILE");
26170
+ }
26171
+ return artifact;
26172
+ }
26173
+ function disposeMicrovmCodeArtifact(artifact) {
26174
+ if (artifact?.tmpDir === void 0) return;
26175
+ try {
26176
+ if (existsSync$1(artifact.tmpDir)) rmSync$1(artifact.tmpDir, {
26177
+ recursive: true,
26178
+ force: true
26179
+ });
26180
+ } catch {}
26181
+ }
26182
+ function asObject(value) {
26183
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
26184
+ }
26185
+ function describeValue(value) {
26186
+ if (typeof value === "string") return displayUntrustedValue(value);
26187
+ let json;
26188
+ try {
26189
+ json = JSON.stringify(value);
26190
+ } catch {
26191
+ json = void 0;
26192
+ }
26193
+ return displayUntrustedValue(json ?? String(value));
26194
+ }
26195
+
26196
+ //#endregion
26197
+ //#region src/local/microvm-hooks.ts
26198
+ const MICROVM_HOOK_PATH_PREFIX = "/aws/lambda-microvms/runtime/v1/";
26199
+ const MAX_RUN_HOOK_PAYLOAD_BYTES = 16 * 1024;
26200
+ const HOOK_RETRY_INTERVAL_MS = 250;
26201
+ var MicrovmHookError = class MicrovmHookError extends CdkLocalError {
26202
+ constructor(message, code = "LOCAL_START_MICROVM_HOOK_FAILED") {
26203
+ super(message, code);
26204
+ this.name = "MicrovmHookError";
26205
+ Object.setPrototypeOf(this, MicrovmHookError.prototype);
26206
+ }
26207
+ };
26208
+ function generateMicrovmId() {
26209
+ return `mvm-${randomUUID$1()}`;
26210
+ }
26211
+ function runHookBody(microvmId, runHookPayload) {
26212
+ return JSON.stringify({
26213
+ microvmId,
26214
+ ...runHookPayload !== void 0 && { runHookPayload }
26215
+ });
26216
+ }
26217
+ async function pollBuildHook(hook, endpoint, timeoutMs, deps = defaultHookDeps) {
26218
+ const path = `${MICROVM_HOOK_PATH_PREFIX}${hook}`;
26219
+ const deadline = deps.now() + timeoutMs;
26220
+ let attempts = 0;
26221
+ let last = { kind: "refused" };
26222
+ while (deps.now() < deadline) {
26223
+ const remaining = Math.max(1, deadline - deps.now());
26224
+ last = await deps.post(endpoint.host, endpoint.port, path, void 0, remaining);
26225
+ attempts++;
26226
+ if (last.kind === "status" && last.status === 200) return attempts;
26227
+ if (last.kind === "timeout") throw new MicrovmHookError(`The /${hook} hook held the request open for ${timeoutMs}ms without answering. Answer 503 immediately while not ready (the cloud ends the image build when a held request reaches the timeout), or raise ${timeoutField(hook)}.`, "LOCAL_START_MICROVM_HOOK_TIMEOUT");
26228
+ if (last.kind === "status" && last.status !== 503) throw new MicrovmHookError(`The /${hook} hook answered HTTP ${last.status}; it must answer 200 when done or 503 to be retried.${bodySuffix(last.body)}`);
26229
+ if (deps.isAlive && attempts % 4 === 0 && !await deps.isAlive()) throw new MicrovmHookError(`The MicroVM container exited while cdk-local polled its /${hook} hook.`, "LOCAL_START_MICROVM_EXITED");
26230
+ await deps.sleep(250);
26231
+ }
26232
+ const lastSeen = last.kind === "status" ? `its last answer was HTTP ${last.status}` : `nothing answered on ${formatAuthority(endpoint.host, endpoint.port)} (the hooks port)`;
26233
+ throw new MicrovmHookError(`The /${hook} hook did not answer 200 within ${timeoutMs}ms (${timeoutField(hook)}); ${lastSeen}.`, "LOCAL_START_MICROVM_HOOK_TIMEOUT");
26234
+ }
26235
+ async function callRuntimeHook(hook, endpoint, timeoutMs, body, deps = defaultHookDeps) {
26236
+ const path = `${MICROVM_HOOK_PATH_PREFIX}${hook}`;
26237
+ const result = await deps.post(endpoint.host, endpoint.port, path, body, timeoutMs);
26238
+ if (result.kind === "status" && result.status === 200) return;
26239
+ if (result.kind === "timeout") throw new MicrovmHookError(`The /${hook} hook did not answer within ${timeoutMs}ms (${timeoutField(hook)}).`, "LOCAL_START_MICROVM_HOOK_TIMEOUT");
26240
+ if (result.kind === "refused") throw new MicrovmHookError(`The /${hook} hook could not be reached: nothing answered on the hooks port (${formatAuthority(endpoint.host, endpoint.port)}).`);
26241
+ throw new MicrovmHookError(`The /${hook} hook answered HTTP ${result.status}; it must answer 200.${bodySuffix(result.body)}`);
26242
+ }
26243
+ async function waitForAppAnswer(endpoint, timeoutMs, deps = {
26244
+ probe: probeHttp,
26245
+ sleep: defaultHookDeps.sleep,
26246
+ now: defaultHookDeps.now
26247
+ }) {
26248
+ const deadline = deps.now() + timeoutMs;
26249
+ let attempt = 0;
26250
+ while (deps.now() < deadline) {
26251
+ const remaining = Math.max(1, deadline - deps.now());
26252
+ const outcome = await deps.probe(endpoint.host, endpoint.port, Math.min(remaining, 1e4));
26253
+ if (outcome === "answered") return;
26254
+ attempt++;
26255
+ if (deps.isAlive && attempt % 4 === 0 && !await deps.isAlive()) throw new MicrovmHookError("The MicroVM container exited before its application answered HTTP.", "LOCAL_START_MICROVM_EXITED");
26256
+ if (outcome === "refused") await deps.sleep(250);
26257
+ }
26258
+ throw new MicrovmHookError(`The MicroVM application never answered HTTP on ${formatAuthority(endpoint.host, endpoint.port)} within ${timeoutMs}ms. With no /ready hook, cdk-local waits for the app to answer before driving the next hook; raise --timeout, or enable the /ready hook.`, "LOCAL_START_MICROVM_NOT_READY");
26259
+ }
26260
+ function timeoutField(hook) {
26261
+ return `${hook.charAt(0).toUpperCase() + hook.slice(1)}TimeoutInSeconds, or --timeout when it is unset`;
26262
+ }
26263
+ function bodySuffix(body) {
26264
+ const trimmed = body.trim();
26265
+ if (trimmed.length === 0) return "";
26266
+ return ` Body: ${displayToolOutput(trimmed.length > 500 ? `${trimmed.slice(0, 500)}...` : trimmed)}`;
26267
+ }
26268
+ function postHook(host, port, path, body, timeoutMs) {
26269
+ return new Promise((resolvePost) => {
26270
+ let settled = false;
26271
+ const settle = (r) => {
26272
+ if (settled) return;
26273
+ settled = true;
26274
+ clearTimeout(timer);
26275
+ resolvePost(r);
26276
+ };
26277
+ const payload = body ?? "";
26278
+ const req = request$2({
26279
+ host,
26280
+ port,
26281
+ path,
26282
+ method: "POST",
26283
+ headers: {
26284
+ connection: "close",
26285
+ "content-length": Buffer.byteLength(payload),
26286
+ ...body !== void 0 && { "content-type": "application/json" }
26287
+ }
26288
+ }, (res) => {
26289
+ const chunks = [];
26290
+ let size = 0;
26291
+ res.on("data", (c) => {
26292
+ if (size < 64 * 1024) chunks.push(c);
26293
+ size += c.length;
26294
+ });
26295
+ res.on("end", () => settle({
26296
+ kind: "status",
26297
+ status: res.statusCode ?? 0,
26298
+ body: Buffer.concat(chunks).toString("utf-8")
26299
+ }));
26300
+ res.on("error", () => settle({
26301
+ kind: "status",
26302
+ status: res.statusCode ?? 0,
26303
+ body: ""
26304
+ }));
26305
+ });
26306
+ const timer = setTimeout(() => {
26307
+ settle({ kind: "timeout" });
26308
+ req.destroy();
26309
+ }, timeoutMs);
26310
+ req.on("error", () => settle({ kind: "refused" }));
26311
+ req.end(payload);
26312
+ });
26313
+ }
26314
+ const defaultHookDeps = {
26315
+ post: postHook,
26316
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
26317
+ now: () => Date.now()
26318
+ };
26319
+
26320
+ //#endregion
26321
+ //#region src/local/microvm-front-door.ts
26322
+ const MICROVM_CONTROL_PATH = "/_cdkl/microvm";
26323
+ const PROXY_PORT_HEADER = "x-aws-proxy-port";
26324
+ const MICROVM_WS_BASE_PROTOCOL = "lambda-microvms";
26325
+ const CLOSE_GRACE_MS = 1e3;
26326
+ function selectTargetPort(headers) {
26327
+ const fromHeader = firstHeader(headers[PROXY_PORT_HEADER]);
26328
+ const fromProtocol = fromHeader === void 0 ? subprotocols(headers).find((p) => p.startsWith(`${MICROVM_WS_BASE_PROTOCOL}.port.`)) : void 0;
26329
+ const raw = fromHeader ?? (fromProtocol !== void 0 ? fromProtocol.slice(`${"lambda-microvms"}.port.`.length) : void 0);
26330
+ if (raw === void 0) return {
26331
+ ok: true,
26332
+ port: MICROVM_DEFAULT_INGRESS_PORT
26333
+ };
26334
+ const trimmed = raw.trim();
26335
+ const n = /^\d{1,5}$/.test(trimmed) ? Number(trimmed) : NaN;
26336
+ if (!Number.isInteger(n) || n < 1 || n > 65535) return {
26337
+ ok: false,
26338
+ status: 400,
26339
+ message: `Invalid ${fromHeader === void 0 ? "WebSocket subprotocol lambda-microvms.port." : "X-aws-proxy-port"} value '${trimmed.slice(0, 32)}': it must be a port number 1-65535.`
26340
+ };
26341
+ return {
26342
+ ok: true,
26343
+ port: n
26344
+ };
26345
+ }
26346
+ function stripMicrovmProxyHeaders(headers) {
26347
+ for (const name of Object.keys(headers)) if (name.toLowerCase().startsWith("x-aws-proxy-")) delete headers[name];
26348
+ const offered = subprotocols(headers);
26349
+ if (offered.length === 0) return false;
26350
+ const kept = offered.filter((p) => !isMicrovmProtocol(p));
26351
+ if (kept.length > 0) headers["sec-websocket-protocol"] = kept.join(", ");
26352
+ else delete headers["sec-websocket-protocol"];
26353
+ return offered.includes(MICROVM_WS_BASE_PROTOCOL);
26354
+ }
26355
+ function isMicrovmProtocol(p) {
26356
+ return p === "lambda-microvms" || p.startsWith(`${"lambda-microvms"}.`);
26357
+ }
26358
+ function subprotocols(headers) {
26359
+ const raw = headers["sec-websocket-protocol"];
26360
+ const joined = Array.isArray(raw) ? raw.join(",") : raw;
26361
+ if (!joined) return [];
26362
+ return joined.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
26363
+ }
26364
+ function firstHeader(value) {
26365
+ if (Array.isArray(value)) return value[0];
26366
+ if (typeof value === "string") return value.split(",")[0];
26367
+ }
26368
+ function startMicrovmFrontDoor(opts) {
26369
+ const logger = getLogger().child("microvm");
26370
+ const bound = { port: opts.port };
26371
+ const server = createServer((req, res) => {
26372
+ handleRequest$1(req, res, opts, bound.port).catch((err) => {
26373
+ logger.debug(`microvm front door error: ${err instanceof Error ? err.message : String(err)}`);
26374
+ if (!res.headersSent) writeText(res, 502, "The MicroVM front door failed to forward the request.");
26375
+ else res.destroy();
26376
+ });
26377
+ });
26378
+ const upgraded = /* @__PURE__ */ new Set();
26379
+ const track = (sock) => {
26380
+ upgraded.add(sock);
26381
+ sock.once("close", () => upgraded.delete(sock));
26382
+ };
26383
+ server.on("upgrade", (req, socket, head) => {
26384
+ track(socket);
26385
+ handleUpgrade(req, socket, head, opts, track).catch((err) => {
26386
+ logger.debug(`microvm upgrade error: ${err instanceof Error ? err.message : String(err)}`);
26387
+ writeRawHttpError(socket, 502, "The MicroVM front door failed to forward the upgrade.");
26388
+ });
26389
+ });
26390
+ return new Promise((resolveStart, rejectStart) => {
26391
+ server.once("error", rejectStart);
26392
+ server.listen(opts.port, opts.host, () => {
26393
+ server.off("error", rejectStart);
26394
+ const address = server.address();
26395
+ const port = typeof address === "object" && address !== null ? address.port : opts.port;
26396
+ bound.port = port;
26397
+ resolveStart({
26398
+ port,
26399
+ close: () => new Promise((resolveClose) => {
26400
+ server.close(() => resolveClose());
26401
+ server.closeIdleConnections();
26402
+ for (const sock of upgraded) sock.end();
26403
+ setTimeout(() => {
26404
+ server.closeAllConnections();
26405
+ for (const sock of upgraded) sock.destroy();
26406
+ }, CLOSE_GRACE_MS).unref();
26407
+ })
26408
+ });
26409
+ });
26410
+ });
26411
+ }
26412
+ async function admit(opts) {
26413
+ const id = opts.target.microvmId;
26414
+ let state = opts.target.state();
26415
+ if ((state === "suspended" || state === "suspending" || state === "resuming") && opts.autoResume) {
26416
+ try {
26417
+ await opts.target.resume();
26418
+ } catch (err) {
26419
+ const now = opts.target.state();
26420
+ if (err instanceof MicrovmStateError && (now === "terminating" || now === "terminated")) return {
26421
+ status: 503,
26422
+ message: `MicroVM ${id} is ${now}.`
26423
+ };
26424
+ return {
26425
+ status: 502,
26426
+ message: `MicroVM ${id} could not be resumed for this request: ${err instanceof Error ? err.message : String(err)}`
26427
+ };
26428
+ }
26429
+ state = opts.target.state();
26430
+ }
26431
+ if (state === "running") return void 0;
26432
+ if (state === "terminating" || state === "terminated") return {
26433
+ status: 503,
26434
+ message: `MicroVM ${id} is ${state}.`
26435
+ };
26436
+ return {
26437
+ status: 503,
26438
+ message: `MicroVM ${id} is ${state}. Resume it with POST ${MICROVM_CONTROL_PATH}/resume (or start with --auto-resume to resume on the first request).`
26439
+ };
26440
+ }
26441
+ async function handleRequest$1(req, res, opts, boundPort) {
26442
+ const path = (req.url ?? "/").split("?")[0];
26443
+ if (path === "/_cdkl/microvm" || path.startsWith(`${"/_cdkl/microvm"}/`)) {
26444
+ const refusal = controlRequestRefusal(req.headers, opts.host, boundPort);
26445
+ if (refusal !== void 0) {
26446
+ req.resume();
26447
+ writeText(res, 403, refusal);
26448
+ return;
26449
+ }
26450
+ await handleControl(req, res, path, opts);
26451
+ return;
26452
+ }
26453
+ const selection = selectTargetPort(req.headers);
26454
+ if (!selection.ok) {
26455
+ req.resume();
26456
+ writeText(res, selection.status, selection.message);
26457
+ return;
26458
+ }
26459
+ const upstream = opts.target.upstreamFor(selection.port);
26460
+ if (!upstream) {
26461
+ req.resume();
26462
+ writeText(res, 403, notRoutableMessage(selection.port, opts.target));
26463
+ return;
26464
+ }
26465
+ const refusal = await admit(opts);
26466
+ if (refusal) {
26467
+ req.resume();
26468
+ writeText(res, refusal.status, refusal.message);
26469
+ return;
26470
+ }
26471
+ const headers = { ...req.headers };
26472
+ stripHopByHopHeaders(headers);
26473
+ stripMicrovmProxyHeaders(headers);
26474
+ await new Promise((resolveForward) => {
26475
+ const proxyReq = request({
26476
+ host: upstream.host,
26477
+ port: upstream.port,
26478
+ method: req.method,
26479
+ path: req.url,
26480
+ headers
26481
+ }, (proxyRes) => {
26482
+ const resHeaders = { ...proxyRes.headers };
26483
+ stripHopByHopHeaders(resHeaders);
26484
+ res.writeHead(proxyRes.statusCode ?? 502, resHeaders);
26485
+ proxyRes.pipe(res);
26486
+ proxyRes.on("end", resolveForward);
26487
+ proxyRes.on("error", () => {
26488
+ if (!res.writableEnded) res.destroy();
26489
+ resolveForward();
26490
+ });
26491
+ });
26492
+ proxyReq.on("error", () => {
26493
+ if (!res.headersSent) writeText(res, 502, `The application in MicroVM ${opts.target.microvmId} is not responding on port ${selection.port}.`);
26494
+ else if (!res.writableEnded) res.destroy();
26495
+ resolveForward();
26496
+ });
26497
+ res.on("close", () => {
26498
+ if (!res.writableEnded) proxyReq.destroy();
26499
+ resolveForward();
26500
+ });
26501
+ req.pipe(proxyReq);
26502
+ });
26503
+ }
26504
+ async function handleControl(req, res, path, opts) {
26505
+ req.resume();
26506
+ const target = opts.target;
26507
+ const action = path.slice(14).replace(/^\//, "");
26508
+ if (action === "") {
26509
+ if (req.method !== "GET" && req.method !== "HEAD") {
26510
+ writeText(res, 405, `Use GET ${MICROVM_CONTROL_PATH}.`);
26511
+ return;
26512
+ }
26513
+ writeJson(res, 200, {
26514
+ microvmId: target.microvmId,
26515
+ state: target.state(),
26516
+ ports: target.routablePorts()
26517
+ });
26518
+ return;
26519
+ }
26520
+ if (action !== "suspend" && action !== "resume" && action !== "terminate") {
26521
+ writeText(res, 404, `Unknown control action '${action.slice(0, 32)}'. Use POST ${MICROVM_CONTROL_PATH}/suspend, /resume or /terminate.`);
26522
+ return;
26523
+ }
26524
+ if (req.method !== "POST") {
26525
+ writeText(res, 405, `Use POST ${MICROVM_CONTROL_PATH}/${action}.`);
26526
+ return;
26527
+ }
26528
+ try {
26529
+ await (action === "suspend" ? target.suspend() : action === "resume" ? target.resume() : target.terminate());
26530
+ } catch (err) {
26531
+ const message = err instanceof Error ? err.message : String(err);
26532
+ writeText(res, err instanceof MicrovmStateError ? 409 : 502, message);
26533
+ return;
26534
+ }
26535
+ writeJson(res, 200, {
26536
+ microvmId: target.microvmId,
26537
+ state: target.state()
26538
+ });
26539
+ }
26540
+ const LOOPBACK_NAMES = [
26541
+ "localhost",
26542
+ "127.0.0.1",
26543
+ "[::1]"
26544
+ ];
26545
+ function isWildcard(host) {
26546
+ return host === "0.0.0.0" || host === "::" || host === "[::]";
26547
+ }
26548
+ function isIpLiteral(name) {
26549
+ return /^\d{1,3}(\.\d{1,3}){3}$/.test(name) || /^\[[0-9a-f:.]+\]$/i.test(name);
26550
+ }
26551
+ function controlRequestRefusal(headers, boundHost, boundPort) {
26552
+ const fetchSite = firstHeader(headers["sec-fetch-site"])?.trim().toLowerCase();
26553
+ if (fetchSite !== void 0 && fetchSite !== "same-origin" && fetchSite !== "none") return `Refusing a ${fetchSite} request to the MicroVM control endpoint: it accepts requests from this origin only (curl, or a page this front door served).`;
26554
+ const host = (Array.isArray(headers.host) ? headers.host[0] : headers.host)?.trim().toLowerCase();
26555
+ const m = host === void 0 ? null : /^(\[[^\]]+\]|[^:]+)(?::(\d+))?$/.exec(host);
26556
+ const name = m?.[1];
26557
+ const port = m ? m[2] !== void 0 ? Number(m[2]) : 80 : NaN;
26558
+ const bindName = boundHost.includes(":") && !boundHost.startsWith("[") ? `[${boundHost}]` : boundHost;
26559
+ const loopbackBind = isWildcard(boundHost) || LOOPBACK_NAMES.includes(bindName.toLowerCase());
26560
+ if (!(name !== void 0 && (name === bindName.toLowerCase() || loopbackBind && LOOPBACK_NAMES.includes(name) || isWildcard(boundHost) && isIpLiteral(name))) || port !== boundPort) return `Refusing a MicroVM control request whose Host header (${(host ?? "<none>").slice(0, 64)}) is not this front door's address.`;
26561
+ const origin = firstHeader(headers.origin)?.trim().toLowerCase();
26562
+ if (origin !== void 0 && origin !== `http://${host}`) return `Refusing a MicroVM control request from origin ${origin.slice(0, 64)}: it accepts requests from this origin only.`;
26563
+ }
26564
+ var MicrovmStateError = class MicrovmStateError extends Error {
26565
+ constructor(message) {
26566
+ super(message);
26567
+ this.name = "MicrovmStateError";
26568
+ Object.setPrototypeOf(this, MicrovmStateError.prototype);
26569
+ }
26570
+ };
26571
+ async function handleUpgrade(req, clientSocket, head, opts, track) {
26572
+ const selection = selectTargetPort(req.headers);
26573
+ if (!selection.ok) {
26574
+ writeRawHttpError(clientSocket, selection.status, selection.message);
26575
+ return;
26576
+ }
26577
+ const upstream = opts.target.upstreamFor(selection.port);
26578
+ if (!upstream) {
26579
+ writeRawHttpError(clientSocket, 403, notRoutableMessage(selection.port, opts.target));
26580
+ return;
26581
+ }
26582
+ const refusal = await admit(opts);
26583
+ if (refusal) {
26584
+ writeRawHttpError(clientSocket, refusal.status, refusal.message);
26585
+ return;
26586
+ }
26587
+ const headers = { ...req.headers };
26588
+ const offeredBase = stripMicrovmProxyHeaders(headers);
26589
+ const appProtocolsLeft = headers["sec-websocket-protocol"] !== void 0;
26590
+ const upstreamSocket = connect({
26591
+ host: upstream.host,
26592
+ port: upstream.port
26593
+ });
26594
+ track(upstreamSocket);
26595
+ upstreamSocket.setNoDelay(true);
26596
+ let connected = false;
26597
+ let responseHead = Buffer.alloc(0);
26598
+ upstreamSocket.on("connect", () => {
26599
+ connected = true;
26600
+ const lines = [`${req.method ?? "GET"} ${req.url ?? "/"} HTTP/${req.httpVersion}`];
26601
+ for (const [name, value] of Object.entries(headers)) {
26602
+ if (value === void 0) continue;
26603
+ for (const v of Array.isArray(value) ? value : [value]) lines.push(`${name}: ${v}`);
26604
+ }
26605
+ upstreamSocket.write(`${lines.join("\r\n")}\r\n\r\n`);
26606
+ if (head.length > 0) upstreamSocket.write(head);
26607
+ clientSocket.pipe(upstreamSocket, { end: false });
26608
+ });
26609
+ const onHead = (chunk) => {
26610
+ responseHead = Buffer.concat([responseHead, chunk]);
26611
+ const end = responseHead.indexOf("\r\n\r\n");
26612
+ if (end === -1 && responseHead.length < 64 * 1024) return;
26613
+ upstreamSocket.pause();
26614
+ upstreamSocket.off("data", onHead);
26615
+ const out = end === -1 ? responseHead : Buffer.concat([Buffer.from(rewriteUpgradeResponseHead(responseHead.subarray(0, end).toString("latin1"), offeredBase && !appProtocolsLeft) + "\r\n\r\n", "latin1"), responseHead.subarray(end + 4)]);
26616
+ responseHead = void 0;
26617
+ clientSocket.write(out);
26618
+ upstreamSocket.pipe(clientSocket);
26619
+ };
26620
+ upstreamSocket.on("data", onHead);
26621
+ const closeBoth = () => {
26622
+ if (!clientSocket.destroyed) clientSocket.destroy();
26623
+ if (!upstreamSocket.destroyed) upstreamSocket.destroy();
26624
+ };
26625
+ let answered = false;
26626
+ const answer502 = (why) => {
26627
+ if (answered || clientSocket.destroyed) return;
26628
+ answered = true;
26629
+ writeRawHttpError(clientSocket, 502, `The application in MicroVM ${opts.target.microvmId} ${why} on port ${selection.port}.`);
26630
+ };
26631
+ upstreamSocket.on("end", () => clientSocket.unpipe(upstreamSocket));
26632
+ upstreamSocket.on("error", () => {
26633
+ if (!connected) return answer502("is not responding");
26634
+ if (responseHead === void 0) closeBoth();
26635
+ });
26636
+ upstreamSocket.on("close", (hadError) => {
26637
+ if (responseHead !== void 0) return answer502("closed the connection before answering the upgrade");
26638
+ if (hadError) closeBoth();
26639
+ else if (!clientSocket.writableEnded) clientSocket.end();
26640
+ });
26641
+ clientSocket.on("error", closeBoth);
26642
+ clientSocket.on("end", () => {
26643
+ if (!upstreamSocket.destroyed && !upstreamSocket.writableEnded) upstreamSocket.end();
26644
+ });
26645
+ clientSocket.on("close", () => {
26646
+ if (!upstreamSocket.destroyed) upstreamSocket.destroy();
26647
+ });
26648
+ }
26649
+ function rewriteUpgradeResponseHead(head, addBase) {
26650
+ if (!addBase) return head;
26651
+ const lines = head.split("\r\n");
26652
+ if (!/^HTTP\/1\.[01] 101\b/.test(lines[0] ?? "")) return head;
26653
+ if (lines.some((l) => /^sec-websocket-protocol\s*:/i.test(l))) return head;
26654
+ return [...lines, `Sec-WebSocket-Protocol: ${MICROVM_WS_BASE_PROTOCOL}`].join("\r\n");
26655
+ }
26656
+ function notRoutableMessage(port, target) {
26657
+ return `Port ${port} of MicroVM ${target.microvmId} is not reachable locally. cdk-local publishes 8080, Hooks.Port, the image's EXPOSE ports and every --proxy-port; published: ${target.routablePorts().join(", ")}.`;
26658
+ }
26659
+ function writeText(res, status, message) {
26660
+ res.writeHead(status, { "content-type": "text/plain; charset=utf-8" });
26661
+ res.end(`${message}\n`);
26662
+ }
26663
+ function writeJson(res, status, body) {
26664
+ res.writeHead(status, { "content-type": "application/json" });
26665
+ res.end(JSON.stringify(body));
26666
+ }
26667
+
26668
+ //#endregion
26669
+ //#region src/local/microvm-runner.ts
26670
+ const execFileAsync = promisify$1(execFile$1);
26671
+ const DEFAULT_TERMINATE_HOOK_TIMEOUT_MS = 1e4;
26672
+ function microvmImageTag(artifact) {
26673
+ return `${getEmbedConfig().resourceNamePrefix}-microvm-${artifact.assetHash.slice(0, 16).toLowerCase()}`;
26674
+ }
26675
+ async function buildMicrovmImage(opts) {
26676
+ const tag = microvmImageTag(opts.artifact);
26677
+ const parent = dirname$1(opts.artifact.contextDir);
26678
+ getLogger().info(`Building MicroVM image ${tag}${opts.platform ? ` (platform=${opts.platform})` : ""}...`);
26679
+ await buildDockerImage({ source: {
26680
+ directory: basename$1(opts.artifact.contextDir),
26681
+ ...opts.noCache && { cacheDisabled: true }
26682
+ } }, parent, {
26683
+ tag,
26684
+ ...opts.platform !== void 0 && { platform: opts.platform },
26685
+ assetOutdir: parent,
26686
+ progressLabel: "Building MicroVM image",
26687
+ wrapError: (stderr) => new LocalInvokeBuildError(`docker build failed for the MicroVM image's Dockerfile: ${stderr}`)
26688
+ });
26689
+ return tag;
26690
+ }
26691
+ async function readExposedPorts(image) {
26692
+ try {
26693
+ const { stdout } = await execFileAsync(getDockerCmd(), [
26694
+ "image",
26695
+ "inspect",
26696
+ "-f",
26697
+ "{{json .Config.ExposedPorts}}",
26698
+ image
26699
+ ]);
26700
+ const parsed = JSON.parse(stdout.trim() || "null");
26701
+ if (!parsed) return [];
26702
+ return Object.keys(parsed).filter((k) => k.endsWith("/tcp") || !k.includes("/")).map((k) => Number(k.split("/")[0])).filter((n) => Number.isInteger(n) && n > 0 && n < 65536);
26703
+ } catch {
26704
+ return [];
26705
+ }
26706
+ }
26707
+ function planMicrovmPorts(hooksPort, exposed, extra) {
26708
+ const out = [MICROVM_DEFAULT_INGRESS_PORT];
26709
+ for (const p of [
26710
+ ...hooksPort !== void 0 ? [hooksPort] : [],
26711
+ ...exposed,
26712
+ ...extra
26713
+ ]) if (!out.includes(p)) out.push(p);
26714
+ return out;
26715
+ }
26716
+ async function setContainerPaused(containerId, paused) {
26717
+ try {
26718
+ await execFileAsync(getDockerCmd(), [paused ? "pause" : "unpause", containerId]);
26719
+ } catch (error) {
26720
+ const err = error;
26721
+ throw new CdkLocalError(`docker ${paused ? "pause" : "unpause"} failed: ${displayToolOutput(err.stderr?.trim() || err.message || String(error))}`, "LOCAL_START_MICROVM_PAUSE_FAILED");
26722
+ }
26723
+ }
26724
+ const defaultDeps = {
26725
+ setPaused: setContainerPaused,
26726
+ remove: removeContainer
26727
+ };
26728
+ var LocalMicrovm = class {
26729
+ microvmId;
26730
+ containerId;
26731
+ current = "booting";
26732
+ resuming;
26733
+ suspending;
26734
+ paused = false;
26735
+ terminating;
26736
+ opts;
26737
+ deps;
26738
+ constructor(opts, deps = {}) {
26739
+ this.opts = opts;
26740
+ this.deps = {
26741
+ ...defaultDeps,
26742
+ ...deps
26743
+ };
26744
+ this.microvmId = opts.microvmId;
26745
+ this.containerId = opts.containerId;
26746
+ }
26747
+ state() {
26748
+ return this.current === "booting" ? "resuming" : this.current;
26749
+ }
26750
+ upstreamFor(containerPort) {
26751
+ return this.opts.ports.get(containerPort);
26752
+ }
26753
+ routablePorts() {
26754
+ return [...this.opts.ports.keys()];
26755
+ }
26756
+ log(message) {
26757
+ getLogger().info(`MicroVM ${this.microvmId}: ${message}`);
26758
+ }
26759
+ hookEndpoint() {
26760
+ const port = this.opts.config.hooksPort;
26761
+ const endpoint = port !== void 0 ? this.opts.ports.get(port) : void 0;
26762
+ if (!endpoint) throw new CdkLocalError("The hooks port is not published.", "LOCAL_START_MICROVM_HOOK_FAILED");
26763
+ return endpoint;
26764
+ }
26765
+ hookTimeoutMs(hook) {
26766
+ const seconds = this.opts.config.hooks[hook]?.timeoutSeconds;
26767
+ if (seconds !== void 0) return seconds * 1e3;
26768
+ return hook === "terminate" ? DEFAULT_TERMINATE_HOOK_TIMEOUT_MS : this.opts.timeoutMs;
26769
+ }
26770
+ hookDeps() {
26771
+ return {
26772
+ ...this.deps.hooks ?? defaultHookDeps,
26773
+ ...this.deps.isAlive && { isAlive: this.deps.isAlive }
26774
+ };
26775
+ }
26776
+ async runtimeHook(hook, body) {
26777
+ if (!this.opts.config.hooks[hook]) return false;
26778
+ await callRuntimeHook(hook, this.hookEndpoint(), this.hookTimeoutMs(hook), body, this.hookDeps());
26779
+ this.log(`/${hook} hook answered 200`);
26780
+ return true;
26781
+ }
26782
+ async boot(runHookPayload) {
26783
+ const { hooks } = this.opts.config;
26784
+ const deps = this.hookDeps();
26785
+ if (hooks.ready) {
26786
+ const attempts = await pollBuildHook("ready", this.hookEndpoint(), this.hookTimeoutMs("ready"), deps);
26787
+ this.log(`/ready hook answered 200 after ${attempts} attempt(s)`);
26788
+ } else {
26789
+ const port = this.opts.config.hooksPort ?? 8080;
26790
+ const endpoint = this.opts.ports.get(port);
26791
+ await (this.deps.waitForAnswer ?? waitForAppAnswer)(endpoint, this.opts.timeoutMs, {
26792
+ probe: probeHttp,
26793
+ sleep: deps.sleep,
26794
+ now: deps.now,
26795
+ ...this.deps.isAlive && { isAlive: this.deps.isAlive }
26796
+ });
26797
+ this.log("application answered HTTP (no /ready hook)");
26798
+ }
26799
+ if (hooks.validate) {
26800
+ const attempts = await pollBuildHook("validate", this.hookEndpoint(), this.hookTimeoutMs("validate"), deps);
26801
+ this.log(`/validate hook answered 200 after ${attempts} attempt(s)`);
26802
+ }
26803
+ await this.runtimeHook("run", runHookBody(this.microvmId, runHookPayload));
26804
+ if (this.current === "booting") this.current = "running";
26805
+ }
26806
+ async setPaused(paused) {
26807
+ await this.deps.setPaused(this.containerId, paused);
26808
+ this.paused = paused;
26809
+ }
26810
+ suspend() {
26811
+ if (this.current !== "running") return Promise.reject(new MicrovmStateError(`MicroVM ${this.microvmId} is ${this.state()}; only a running MicroVM can be suspended.`));
26812
+ this.current = "suspending";
26813
+ this.suspending = (async () => {
26814
+ try {
26815
+ await this.runtimeHook("suspend");
26816
+ await this.setPaused(true);
26817
+ } catch (err) {
26818
+ if (this.current === "suspending") this.current = "running";
26819
+ throw err;
26820
+ } finally {
26821
+ this.suspending = void 0;
26822
+ }
26823
+ if (this.current === "suspending") {
26824
+ this.current = "suspended";
26825
+ this.log("suspended (container paused)");
26826
+ }
26827
+ })();
26828
+ return this.suspending;
26829
+ }
26830
+ resume() {
26831
+ if (this.current === "resuming" && this.resuming) return this.resuming;
26832
+ if (this.current === "suspending" && this.suspending) return this.suspending.then(() => this.resume(), () => void 0);
26833
+ if (this.current !== "suspended") return Promise.reject(new MicrovmStateError(`MicroVM ${this.microvmId} is ${this.state()}; only a suspended MicroVM can be resumed.`));
26834
+ this.current = "resuming";
26835
+ this.resuming = (async () => {
26836
+ try {
26837
+ await this.setPaused(false);
26838
+ try {
26839
+ await this.runtimeHook("resume");
26840
+ } catch (err) {
26841
+ if (this.current === "resuming") await this.setPaused(true).catch(() => void 0);
26842
+ throw err;
26843
+ }
26844
+ } catch (err) {
26845
+ if (this.current === "resuming") this.current = "suspended";
26846
+ throw err;
26847
+ } finally {
26848
+ this.resuming = void 0;
26849
+ }
26850
+ if (this.current === "resuming") {
26851
+ this.current = "running";
26852
+ this.log("resumed");
26853
+ }
26854
+ })();
26855
+ return this.resuming;
26856
+ }
26857
+ terminate() {
26858
+ this.terminating ??= (async () => {
26859
+ const wasBooting = this.current === "booting";
26860
+ this.current = "terminating";
26861
+ await Promise.allSettled([this.suspending, this.resuming].filter((p) => p !== void 0));
26862
+ try {
26863
+ if (this.paused) await this.setPaused(false).catch(() => void 0);
26864
+ if (!wasBooting) await this.runtimeHook("terminate");
26865
+ } catch (err) {
26866
+ getLogger().warn(`MicroVM ${this.microvmId}: ${err instanceof Error ? err.message : String(err)} Removing its container anyway.`);
26867
+ }
26868
+ await this.deps.remove(this.containerId);
26869
+ this.current = "terminated";
26870
+ this.log("terminated (container removed)");
26871
+ this.opts.onTerminated?.(this);
26872
+ })();
26873
+ return this.terminating;
26874
+ }
26875
+ };
26876
+
26877
+ //#endregion
26878
+ //#region src/cli/commands/local-start-microvm.ts
26879
+ function parsePort(raw) {
26880
+ const n = Number(raw);
26881
+ if (!Number.isInteger(n) || n < 0 || n > 65535) throw new InvalidArgumentError(`--port must be an integer 0-65535, got '${raw}'.`);
26882
+ return n;
26883
+ }
26884
+ function parseCount(raw) {
26885
+ const n = Number(raw);
26886
+ if (!Number.isInteger(n) || n < 1 || n > 64) throw new InvalidArgumentError(`--count must be an integer 1-64, got '${raw}'.`);
26887
+ return n;
26888
+ }
26889
+ function parseProxyPort(raw, previous) {
26890
+ const n = Number(raw);
26891
+ if (!Number.isInteger(n) || n < 1 || n > 65535) throw new InvalidArgumentError(`--proxy-port must be an integer 1-65535, got '${raw}'.`);
26892
+ return [...previous ?? [], n];
26893
+ }
26894
+ function connectHost(host) {
26895
+ if (host === "0.0.0.0") return "127.0.0.1";
26896
+ if (host === "::" || host === "[::]") return "::1";
26897
+ return host;
26898
+ }
26899
+ function readRunHookPayload(options, readFile = (p) => readFileSync$1(p, "utf-8")) {
26900
+ if (options.runHookPayload !== void 0 && options.runHookPayloadFile !== void 0) throw new CdkLocalError("--run-hook-payload and --run-hook-payload-file are mutually exclusive.", "LOCAL_START_MICROVM_PAYLOAD_CONFLICT");
26901
+ let payload = options.runHookPayload;
26902
+ if (options.runHookPayloadFile !== void 0) try {
26903
+ payload = readFile(options.runHookPayloadFile);
26904
+ } catch (err) {
26905
+ throw new CdkLocalError(`Cannot read --run-hook-payload-file ${displayUntrustedValue(options.runHookPayloadFile)}: ${err instanceof Error ? err.message : String(err)}`, "LOCAL_START_MICROVM_PAYLOAD_UNREADABLE");
26906
+ }
26907
+ if (payload !== void 0 && Buffer.byteLength(payload) > 16384) throw new CdkLocalError(`The run hook payload is ${Buffer.byteLength(payload)} bytes; run-microvm accepts at most ${MAX_RUN_HOOK_PAYLOAD_BYTES} (16 KB).`, "LOCAL_START_MICROVM_PAYLOAD_TOO_LARGE");
26908
+ return payload;
26909
+ }
26910
+ function buildMicrovmLambdaView(resolved, config) {
26911
+ return {
26912
+ kind: "zip",
26913
+ stack: resolved.stack,
26914
+ logicalId: resolved.logicalId,
26915
+ resource: {
26916
+ Type: resolved.resource.Type,
26917
+ Properties: { Environment: { Variables: config.environment } },
26918
+ ...resolved.resource.Metadata !== void 0 && { Metadata: resolved.resource.Metadata }
26919
+ },
26920
+ memoryMb: 128,
26921
+ timeoutSec: 0,
26922
+ layers: [],
26923
+ runtime: "",
26924
+ handler: "",
26925
+ codePath: null,
26926
+ architecture: config.architecture ?? "arm64"
26927
+ };
26928
+ }
26929
+ const LAMBDA_RUNTIME_ENV_KEYS = [
26930
+ "AWS_LAMBDA_FUNCTION_NAME",
26931
+ "AWS_LAMBDA_FUNCTION_MEMORY_SIZE",
26932
+ "AWS_LAMBDA_FUNCTION_TIMEOUT",
26933
+ "AWS_LAMBDA_FUNCTION_VERSION",
26934
+ "AWS_LAMBDA_LOG_GROUP_NAME",
26935
+ "AWS_LAMBDA_LOG_STREAM_NAME"
26936
+ ];
26937
+ function finalizeMicrovmEnv(lambdaEnv, declared) {
26938
+ const env = { ...lambdaEnv };
26939
+ for (const key of LAMBDA_RUNTIME_ENV_KEYS) if (!Object.hasOwn(declared, key)) delete env[key];
26940
+ return env;
26941
+ }
26942
+ function microvmFidelityWarnings(config) {
26943
+ const image = displayIdent(config.logicalId);
26944
+ const out = [
26945
+ `MicroVM image ${image}: each MicroVM is a Docker container started fresh from the built image, not a MicroVM restored from a snapshot — state the app initializes before /ready answers 200 is NOT shared across MicroVMs (each one runs its own startup), and there is no VM isolation or memory checkpoint (suspend is docker pause).`,
26946
+ `MicroVM image ${image}: requests are accepted without X-aws-proxy-auth — the JWE token the cloud endpoint requires is not checked locally (the header is still stripped).`,
26947
+ `MicroVM image ${image}: the idle policy is not emulated — a MicroVM suspends, resumes and terminates only through ${MICROVM_CONTROL_PATH}/suspend|resume|terminate (and --auto-resume).`,
26948
+ `MicroVM image ${image}: the Dockerfile is built by the local Docker engine, not on the Lambda-managed MicroVM base OS (BaseImageArn).`
26949
+ ];
26950
+ if (config.hooks.validate) out.push(`MicroVM image ${image}: /validate is called on the same container as /ready (the cloud calls it on a fresh MicroVM started from the built snapshot).`);
26951
+ for (const what of config.unemulated) out.push(`MicroVM image ${image}: ${what} is not emulated.`);
26952
+ return out;
26953
+ }
26954
+ async function localStartMicrovmCommand(target, options, extraStateProviders, hostSynthesizer) {
26955
+ const logger = getLogger();
26956
+ if (options.verbose) logger.setLevel("debug");
26957
+ const runHookPayload = readRunHookPayload(options);
26958
+ const vms = [];
26959
+ const frontDoors = /* @__PURE__ */ new Map();
26960
+ const logStops = [];
26961
+ const exitWatches = [];
26962
+ const bareContainers = /* @__PURE__ */ new Set();
26963
+ let runInFlight;
26964
+ let containerName;
26965
+ let artifact;
26966
+ let teardownPromise;
26967
+ let shuttingDown = false;
26968
+ let waitingOnRun = false;
26969
+ const forever = () => new Promise(() => void 0);
26970
+ const doTeardown = async () => {
26971
+ for (const w of exitWatches) w.stop();
26972
+ if (runInFlight !== void 0) {
26973
+ waitingOnRun = true;
26974
+ try {
26975
+ bareContainers.add(await runInFlight);
26976
+ } catch {} finally {
26977
+ waitingOnRun = false;
26978
+ }
26979
+ }
26980
+ await Promise.allSettled(vms.map((vm) => vm.terminate()));
26981
+ for (const vm of vms) bareContainers.delete(vm.containerId);
26982
+ await Promise.allSettled([...bareContainers].map((id) => removeContainer(id)));
26983
+ await Promise.allSettled([...frontDoors.values()].map((fd) => fd.close()));
26984
+ for (const stop of logStops) try {
26985
+ stop();
26986
+ } catch (err) {
26987
+ logger.debug(`streamLogs stop failed: ${err instanceof Error ? err.message : String(err)}`);
26988
+ }
26989
+ disposeMicrovmCodeArtifact(artifact);
26990
+ };
26991
+ const teardown = () => teardownPromise ??= doTeardown();
26992
+ await applyRoleArnIfSet({
26993
+ roleArn: options.roleArn,
26994
+ region: options.region,
26995
+ profile: options.profile
26996
+ });
26997
+ await ensureDockerAvailable();
26998
+ const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
26999
+ const appCmd = resolveApp(options.app);
27000
+ if (!appCmd) throw new Error(`No CDK app specified. Pass --app, set ${getEmbedConfig().envPrefix}_APP, or add "app" to cdk.json.`);
27001
+ logger.info("Synthesizing CDK app...");
27002
+ const synthesizer = hostSynthesizer ?? new Synthesizer();
27003
+ const context = parseContextOptions(options.context);
27004
+ const synthOpts = {
27005
+ app: appCmd,
27006
+ output: options.output,
27007
+ ...options.region && { region: options.region },
27008
+ ...options.profile && { profile: options.profile },
27009
+ ...Object.keys(context).length > 0 && { context }
27010
+ };
27011
+ const { stacks } = await synthesizer.synthesize(synthOpts);
27012
+ const resolved = resolveMicrovmImageTarget(await resolveSingleTarget(target, {
27013
+ entries: listTargets(stacks).microvmImages,
27014
+ message: "Select a Lambda MicroVM image to run",
27015
+ noun: "Lambda MicroVM images",
27016
+ onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} start-microvm requires a <target> (a MicrovmImage display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or run it in a TTY to pick interactively.`, "LOCAL_START_MICROVM_TARGET_REQUIRED")
27017
+ }), stacks);
27018
+ const config = readMicrovmImageConfig(resolved.logicalId, resolved.resource);
27019
+ const platform = options.platform ?? (config.architecture !== void 0 ? architectureToPlatform(config.architecture) : void 0);
27020
+ logger.info(`Target: ${displayStackName(`${resolved.stack.stackName}/${resolved.logicalId}`)} (MicroVM image ${displayIdent(config.name)}; hooks: ${Object.keys(config.hooks).join(", ") || "none"}${platform ? `; ${platform}` : ""})`);
27021
+ for (const line of microvmFidelityWarnings(config)) logger.warn(line);
27022
+ artifact = await resolveMicrovmCodeArtifact(resolved.stack, config);
27023
+ const shutdown = async (signal, exitCode) => {
27024
+ if (shuttingDown) {
27025
+ if (!waitingOnRun) {
27026
+ logger.info(`Received ${signal} again; still terminating the MicroVMs, please wait...`);
27027
+ return;
27028
+ }
27029
+ disposeMicrovmCodeArtifact(artifact);
27030
+ 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>"}`);
27031
+ process.exit(signal === "SIGINT" ? 130 : 143);
27032
+ return;
27033
+ }
27034
+ shuttingDown = true;
27035
+ logger.info(`Received ${signal}, terminating ${vms.length} MicroVM(s)...`);
27036
+ await teardown();
27037
+ process.exit(exitCode);
27038
+ };
27039
+ process.on("SIGINT", () => void shutdown("SIGINT", 130));
27040
+ process.on("SIGTERM", () => void shutdown("SIGTERM", 0));
27041
+ const recents = /* @__PURE__ */ new Map();
27042
+ let allTerminated;
27043
+ const everyVmTerminated = new Promise((r) => allTerminated = r);
27044
+ const checkAllTerminated = () => {
27045
+ if (vms.length === options.count && vms.every((v) => v.state() === "terminated")) allTerminated();
27046
+ };
27047
+ let unexpectedExit;
27048
+ const anyUnexpectedExit = new Promise((r) => unexpectedExit = r);
27049
+ const probeHost = connectHost(options.host);
27050
+ try {
27051
+ const containerEnv = await resolveLambdaContainerEnv(buildMicrovmLambdaView(resolved, config), {
27052
+ ...options,
27053
+ deployedFunctionLookups: false
27054
+ }, profileCredentials, extraStateProviders);
27055
+ const env = finalizeMicrovmEnv(containerEnv.env, config.environment);
27056
+ const image = await buildMicrovmImage({
27057
+ artifact,
27058
+ platform,
27059
+ noCache: options.buildCache === false
27060
+ });
27061
+ if (teardownPromise) return await forever();
27062
+ const containerPorts = planMicrovmPorts(config.hooksPort, await readExposedPorts(image), options.proxyPort ?? []);
27063
+ logger.info(`Publishing container ports ${containerPorts.join(", ")} to the front door(s).`);
27064
+ for (let i = 0; i < options.count; i++) {
27065
+ const microvmId = generateMicrovmId();
27066
+ const hostPorts = /* @__PURE__ */ new Map();
27067
+ for (const cp of containerPorts) hostPorts.set(cp, {
27068
+ host: "127.0.0.1",
27069
+ port: await pickFreePort()
27070
+ });
27071
+ const [first, ...rest] = containerPorts;
27072
+ const name = containerName = `${getEmbedConfig().resourceNamePrefix}-microvm-${process.pid}-${i}-${Math.random().toString(36).slice(2, 8)}`;
27073
+ logger.info(`Starting MicroVM ${microvmId} (container ${name})...`);
27074
+ runInFlight = runDetached({
27075
+ image,
27076
+ mounts: [],
27077
+ env,
27078
+ ...containerEnv.sensitiveEnvKeys.length > 0 && { sensitiveEnvKeys: new Set(containerEnv.sensitiveEnvKeys) },
27079
+ cmd: [],
27080
+ hostPort: hostPorts.get(first).port,
27081
+ containerPort: first,
27082
+ extraPorts: rest.map((cp) => ({
27083
+ hostPort: hostPorts.get(cp).port,
27084
+ containerPort: cp
27085
+ })),
27086
+ host: "127.0.0.1",
27087
+ ...platform !== void 0 && { platform },
27088
+ name,
27089
+ autoRemove: false
27090
+ });
27091
+ const containerId = await runInFlight;
27092
+ runInFlight = void 0;
27093
+ bareContainers.add(containerId);
27094
+ if (teardownPromise) return await forever();
27095
+ const recent = new RecentOutput();
27096
+ recents.set(containerId, recent);
27097
+ logStops.push(streamLogs(containerId, {
27098
+ onOutput: (chunk) => recent.push(chunk),
27099
+ ...options.count > 1 && { prefix: `[${microvmId.slice(0, 12)}] ` }
27100
+ }));
27101
+ const watch = watchContainerExit(containerId);
27102
+ exitWatches.push(watch);
27103
+ let exited = false;
27104
+ const vm = new LocalMicrovm({
27105
+ microvmId,
27106
+ containerId,
27107
+ ports: hostPorts,
27108
+ config,
27109
+ timeoutMs: options.timeout,
27110
+ onTerminated: checkAllTerminated
27111
+ }, { isAlive: async () => !exited });
27112
+ vms.push(vm);
27113
+ bareContainers.delete(containerId);
27114
+ watch.exited.then((code) => {
27115
+ exited = true;
27116
+ const s = vm.state();
27117
+ if (s !== "terminating" && s !== "terminated") unexpectedExit({
27118
+ vm,
27119
+ code
27120
+ });
27121
+ });
27122
+ await vm.boot(runHookPayload);
27123
+ if (teardownPromise) return await forever();
27124
+ const fd = await startMicrovmFrontDoor({
27125
+ host: options.host,
27126
+ port: options.port === 0 ? 0 : options.port + i,
27127
+ target: vm,
27128
+ autoResume: options.autoResume === true
27129
+ });
27130
+ frontDoors.set(vm, fd);
27131
+ const base = `http://${formatAuthority(probeHost, fd.port)}`;
27132
+ logger.info(`MicroVM ${microvmId} listening on ${base} (control: ${base}${MICROVM_CONTROL_PATH})`);
27133
+ }
27134
+ logger.info("Press ^C to terminate the MicroVM(s).");
27135
+ checkAllTerminated();
27136
+ } catch (err) {
27137
+ if (shuttingDown) return await forever();
27138
+ const failed = vms.at(-1);
27139
+ const wrapped = err instanceof MicrovmHookError && failed ? await containerFailure(err.message, failed.containerId, recents.get(failed.containerId) ?? new RecentOutput()).then((f) => new CdkLocalError(f.message, err.code)) : err;
27140
+ await teardown();
27141
+ throw wrapped;
27142
+ }
27143
+ const outcome = await Promise.race([everyVmTerminated.then(() => void 0), anyUnexpectedExit]);
27144
+ if (shuttingDown) return await forever();
27145
+ if (outcome === void 0) {
27146
+ logger.info("Every MicroVM is terminated; shutting down.");
27147
+ await teardown();
27148
+ return;
27149
+ }
27150
+ if (teardownPromise) return await forever();
27151
+ const failure = await containerFailure(`MicroVM ${outcome.vm.microvmId}'s container exited (exit code ${outcome.code ?? "unknown"}) while running.`, outcome.vm.containerId, recents.get(outcome.vm.containerId) ?? new RecentOutput());
27152
+ await teardown();
27153
+ throw new CdkLocalError(failure.message, "LOCAL_START_MICROVM_EXITED");
27154
+ }
27155
+ function createLocalStartMicrovmCommand(opts = {}) {
27156
+ setEmbedConfig(opts.embedConfig);
27157
+ const cmd = new Command("start-microvm").description("Run AWS Lambda MicroVMs locally. Builds a MicrovmImage code artifact (a Dockerfile plus the app, from cdk.out) once, starts --count containers with its EnvironmentVariables, drives the /ready, /validate and /run lifecycle hooks in the cloud order, and serves each MicroVM on its own local URL: X-aws-proxy-port / lambda-microvms.port.N routing (default 8080), X-aws-proxy-* stripping, and a control endpoint for suspend / resume / terminate. 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, which calls /terminate.").argument("[target]", "CDK display path or stack-qualified logical ID of the MicrovmImage (omit to pick interactively in a TTY)").action(withErrorHandling(async (target, options) => {
27158
+ await localStartMicrovmCommand(target, options, opts.extraStateProviders, opts.synthesizer);
27159
+ }));
27160
+ addStartMicrovmSpecificOptions(cmd);
27161
+ [
27162
+ ...commonOptions(),
27163
+ ...appOptions(),
27164
+ ...contextOptions
27165
+ ].forEach((opt) => cmd.addOption(opt));
27166
+ cmd.addOption(regionOption);
27167
+ return cmd;
27168
+ }
27169
+ function addStartMicrovmSpecificOptions(cmd) {
27170
+ return cmd.addOption(new Option("--count <n>", "Number of independent MicroVMs to run, each with its own URL.").default(1).argParser(parseCount)).addOption(new Option("--run-hook-payload <string>", "The runHookPayload string delivered to each MicroVM's /run hook (max 16 KB).")).addOption(new Option("--run-hook-payload-file <path>", "Read the runHookPayload from a file (mutually exclusive with --run-hook-payload).")).addOption(new Option("--port <n>", "Local port of the first MicroVM; MicroVM i listens on <n>+i. Default 0 (OS-assigned).").default(0).argParser(parsePort)).addOption(new Option("--host <ip>", "Address the MicroVM URLs listen on.").default("127.0.0.1")).addOption(new Option("--platform <platform>", "docker --platform for the build and the containers. Defaults to the image's CpuConfigurations architecture.").choices(["linux/amd64", "linux/arm64"])).addOption(new Option("--proxy-port <port>", "An extra container port X-aws-proxy-port may route to (repeatable). 8080, Hooks.Port and the image's EXPOSE ports are always routable.").argParser(parseProxyPort)).addOption(new Option("--auto-resume", "Resume a suspended MicroVM on its next request instead of answering 503 (autoResumeEnabled).")).addOption(new Option("--no-build-cache", "Build the image with docker build --no-cache.")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"MicrovmImageLogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--timeout <ms>", "Default deadline in milliseconds for each hook without its own <Hook>TimeoutInSeconds (/terminate defaults to 10000), and for the app to answer HTTP when there is no /ready hook. Default 60000.").default(6e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role <arn>", "Assume this role (the MicroVM's execution role, a run-microvm parameter rather than part of the template) and forward STS-issued temp credentials to the containers. Off by default: the shell credentials are forwarded.")).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."));
25978
27171
  }
25979
27172
 
25980
27173
  //#endregion
@@ -26003,7 +27196,7 @@ async function localListCommand(options) {
26003
27196
  process.stdout.write(`${formatTargetListing(listing, getEmbedConfig().cliName, { long: options.long })}\n`);
26004
27197
  }
26005
27198
  function formatTargetListing(listing, cliName, options = {}) {
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.`;
27199
+ if (countTargets(listing) === 0) return `No runnable targets (Lambda functions, APIs, ECS services / tasks, AgentCore Runtimes, load balancers, CloudFront distributions, Lambda web functions, Lambda MicroVM images) found in this CDK app.`;
26007
27200
  const long = options.long ?? false;
26008
27201
  return "\n" + [
26009
27202
  formatSection("Lambda Functions", `${cliName} invoke <target>`, listing.lambdas, long),
@@ -26013,7 +27206,8 @@ function formatTargetListing(listing, cliName, options = {}) {
26013
27206
  formatSection("AgentCore Runtimes", `${cliName} invoke-agentcore <target>`, listing.agentCoreRuntimes, long),
26014
27207
  formatSection("Application Load Balancers", `${cliName} start-alb <target...>`, listing.loadBalancers, long),
26015
27208
  formatSection("CloudFront Distributions", `${cliName} start-cloudfront <target>`, listing.cloudFrontDistributions, long),
26016
- formatSection("Lambda Web Functions", `${cliName} start-web-function <target>`, listing.webFunctions, long)
27209
+ formatSection("Lambda Web Functions", `${cliName} start-web-function <target>`, listing.webFunctions, long),
27210
+ formatSection("Lambda MicroVM Images", `${cliName} start-microvm <target>`, listing.microvmImages, long)
26017
27211
  ].filter((lines) => lines.length > 0).map((lines) => lines.join("\n")).join("\n\n");
26018
27212
  }
26019
27213
  function formatSection(title, command, entries, long) {
@@ -31289,5 +32483,5 @@ function addStudioSpecificOptions(cmd) {
31289
32483
  }
31290
32484
 
31291
32485
  //#endregion
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
32486
+ export { postHook as $, resolveDynamicReferencesInEnv as $a, architectureToPlatform as $i, parseRestartPolicy as $n, createAuthorizerCache as $r, resolveCloudFrontTarget as $t, microvmFidelityWarnings as A, pickRefLogicalId as Aa, matchPreflight as Ai, stripCloudFrontImport as An, MCP_PATH as Ar, supportedWebFunctionRuntimes as At, MICROVM_WS_BASE_PROTOCOL as B, derivePseudoParametersFromRegion as Ba, VtlEvaluationError as Bi, resolveAlbFrontDoor as Bn, downloadAndExtractS3Bundle as Br, addStartAgentCoreSpecificOptions as Bt, addListSpecificOptions as C, availableWebSocketApiIdentifiers as Ca, invokeRequestAuthorizer as Ci, pickKvsLogicalIdFromArn as Cn, createLocalInvokeAgentCoreCommand as Cr, readWebFunctionServiceConfig as Ct, buildMicrovmLambdaView as D, parseSelectionExpressionPath as Da, buildCorsConfigByApiId as Di, compileCloudFrontFunction as Dn, A2A_PATH as Dr, buildNodeEntryFileStart as Dt, addStartMicrovmSpecificOptions as E, filterWebSocketApisByIdentifiers as Ea, applyCorsResponseHeaders as Ei, resolveCloudFrontDistribution as En, A2A_CONTAINER_PORT as Er, WEB_FUNCTION_RUNTIMES as Et, microvmImageTag as F, AGENTCORE_MCP_PROTOCOL as Fa, buildRestV1Event as Fi, albStrategy as Fn, signAgentCoreInvocation as Fr, WEB_FUNCTION_ENDPOINT_TYPE as Ft, startMicrovmFrontDoor as G, DynamicReferenceResolutionError as Ga, bufferToBody as Gi, createLocalRunTaskCommand as Gn, toCmdArgv as Gr, attachAgentCoreWsBridge as Gt, PROXY_PORT_HEADER as H, substituteImagePlaceholders as Ha, HOST_GATEWAY_MIN_VERSION as Hi, createLocalStartServiceCommand as Hn, buildAgentCoreCodeImage as Hr, buildAgentCoreServeAuthCheck as Ht, planMicrovmPorts as I, AGENTCORE_RUNTIME_TYPE as Ia, evaluateResponseParameters as Ii, createLocalStartAlbCommand as In, AGENTCORE_SESSION_ID_HEADER as Ir, WEB_FUNCTION_REVISION_TYPE as It, MICROVM_HOOK_PATH_PREFIX as J, deployedFillMayBeSecret as Ja, handleConnectionsRequest as Ji, addEcsAssumeRoleOptions as Jn, createLocalInvokeCommand as Jr, addStartCloudFrontSpecificOptions as Jt, stripMicrovmProxyHeaders as K, DynamicReferenceResolver as Ka, ConnectionRegistry as Ki, MAX_TASKS_SUBNET_RANGE_CAP as Kn, classifySourceChange as Kr, startAgentCoreWsBridge as Kt, readExposedPorts as L, AgentCoreResolutionError as La, pickResponseTemplate as Li, parseLbPortOverrides as Ln, invokeAgentCore as Lr, WEB_FUNCTION_TYPE as Lt, DEFAULT_TERMINATE_HOOK_TIMEOUT_MS as M, AGENTCORE_A2A_PROTOCOL as Ma, translateLambdaResponse as Mi, createLocalFileKvsDataSource as Mn, mcpInvokeOnce as Mr, findFileAssetForObjectKey as Mt, LocalMicrovm as N, AGENTCORE_AGUI_PROTOCOL as Na, applyAuthorizerOverlay as Ni, createUnboundCloudFrontModule as Nn, parseSseForJsonRpc as Nr, parseWebFunctionBuildConfig as Nt, createLocalStartMicrovmCommand as O, webSocketApiMatchesIdentifier as Oa, buildCorsConfigFromCloudFrontChain as Oi, runViewerRequest as On, a2aInvokeOnce as Or, defaultWebFunctionPlatform as Ot, buildMicrovmImage as P, AGENTCORE_HTTP_PROTOCOL as Pa, buildHttpApiV2Event as Pi, addAlbSpecificOptions as Pn, AGENTCORE_SIGV4_SERVICE as Pr, resolveWebFunctionArtifact as Pt, pollBuildHook as Q, parseDynamicReference as Qa, buildMessageEvent as Qi, parseMaxTasks as Qn, resolveApiTargetSubset as Qr, parseOriginOverrides as Qt, setContainerPaused as R, pickAgentCoreCandidateStack as Ra, selectIntegrationResponse as Ri, resolveAlbTarget as Rn, waitForAgentCoreHttpReady as Rr, WebFunctionResolutionError as Rt, StudioEventBus as S, listTargets as Sa, evaluateCachedLambdaPolicy as Si, pickFunctionUrlLogicalIdFromOrigin as Sn, addInvokeAgentCoreSpecificOptions as Sr, finalizeWebFunctionEnv as St, formatTargetListing as T, discoverWebSocketApisOrThrow as Ta, attachAuthorizers as Ti, pickTargetFunctionLogicalId as Tn, invokeAgentCoreWs as Tr, webFunctionFidelityWarnings as Tt, rewriteUpgradeResponseHead as U, tryResolveImageFnJoin as Ua, probeHostGatewaySupport as Ui, serviceStrategy as Un, computeCodeImageTag as Ur, selectServeInboundAuth as Ut, MicrovmStateError as V, formatStateRemedy as Va, HOST_DOCKER_INTERNAL_GATEWAY as Vi, addStartServiceSpecificOptions as Vn, SUPPORTED_CODE_RUNTIMES as Vr, createLocalStartAgentCoreCommand as Vt, selectTargetPort as W, LocalInvokeBuildError as Wa, resolveHostGatewayExtraHosts as Wi, addRunTaskSpecificOptions as Wn, renderCodeDockerfile as Wr, startAgentCoreHttpServer as Wt, callRuntimeHook as X, keysNotFromTemplate as Xa, buildConnectEvent as Xi, buildEcsImageResolutionContext$1 as Xn, createLocalStartApiCommand as Xr, normalizeKvsFileKeys as Xt, MicrovmHookError as Y, firstUsableRegion as Ya, parseConnectionsPath as Yi, addImageOverrideOptions as Yn, addStartApiSpecificOptions as Yr, createLocalStartCloudFrontCommand as Yt, generateMicrovmId as Z, keysOverriddenBy as Za, buildDisconnectEvent as Zi, ecsClusterOption as Zn, createWatchPredicates as Zr, parseKvsFileOverrides as Zt, filterStudioTargetGroups as _, collectSsmParameterRefs as _a, verifyCognitoJwt as _i, httpHeadersToEdge as _n, DEFAULT_SHADOW_READY_TIMEOUT_MS as _r, startWebFunctionContainer as _t, createLocalStudioCommand as a, substituteAgainstState as aa, availableApiIdentifiers as ai, classifyS3Error as an, recordAssumedRole as ao, canonicalizeImageOverrideKeys as ar, disposeMicrovmCodeArtifact as at, renderStudioHtml as b, resolveSingleTarget as ba, buildMethodArn as bi, extractKvsAssociations as bn, getContainerNetworkIp as br, WEB_FUNCTION_HTTP_ENDPOINT_ENV as bt, startStudioProxy as c, substituteEnvVarsFromStateAsync as ca, groupRoutesByServer as ci, startCloudFrontServer as cn, workloadStsClientConfig as co, parseImageOverrideFlags as cr, resolveMicrovmImageTarget as ct, createStudioDispatcher as d, isCfnFlagPresent as da, resolveSelectionExpression as di, serveLambdaUrlOrigin as dn, buildProxyClientConfig as do, describePinnedImageUri as dr, createLocalStartWebFunctionCommand as dt, buildContainerImage as ea, createFileWatcher as ei, idFromArn as en, withoutKeys as eo, resolveEcsAssumeRoleOption as er, runHookBody as et, filterStudioCustomResources as f, rejectExplicitCfnStackWithMultipleStacks as fa, resolveServiceIntegrationParameters as fi, applyEdgeRequestResult as fn, isProxyEnvConfigured as fo, imageOverrideKeyAliases as fr, RecentOutput as ft, annotatePinnedEcsTargets as g, CfnLocalStateProvider as ga, createJwksCache as gi, edgeHeadersToHttp as gn, CloudMapRegistry as gr, readContainerLogTail as gt, annotateEcsTaskPinnedTargets as h, resolveCfnStackName as ha, buildJwksUrlFromIssuer as hi, buildEdgeResponseEvent as hn, buildCloudMapIndex as hr, planWebFunctionContainer as ht, coerceStopRequest as i, EcsTaskResolutionError as ia, resolveEnvVars$1 as ii, resolveDeployedOriginBucket as in, readEnvCallerCredentials as io, buildImageOverrideTag as ir, MicrovmResolutionError as it, readRunHookPayload as j, resolveLambdaArnIntrinsic as ja, matchRoute as ji, createCloudFrontModule as jn, MCP_PROTOCOL_VERSION as jr, disposeWebFunctionArtifact as jt, finalizeMicrovmEnv as k, discoverRoutes as ka, isFunctionUrlOacFronted as ki, runViewerResponse as kn, MCP_CONTAINER_PORT as kr, resolveWebFunctionRuntime as kt, relayServeRequest as l, LocalStateSourceError as la, readMtlsMaterialsFromDisk as li, resolveErrorResponseCandidates as ln, buildStsClientConfig as lo, resolveImageOverrides as lr, s3KeyOfUri as lt, annotateAlbPinnedBackingServices as m, resolveCfnRegion as ma, buildCognitoJwksUrl as mi, buildEdgeRequestEvent as mn, listPinnedTargets as mr, containerFailure as mt, coerceRunRequest as n, resolveRuntimeFileExtension as na, buildStageMap as ni, createDeployedKvsDataSource as nn, assumedRoleRecorded as no, runEcsServiceEmulator as nr, MICROVM_DEFAULT_INGRESS_PORT as nt, resolveServeBaseUrl as o, substituteAgainstStateAsync as oa, filterRoutesByApiIdentifier as oi, createS3OriginReader as on, resetWorkloadIdentity as oo, enforceImageOverrideOrphans as or, readMicrovmImageConfig as ot, isCustomResourceLambdaTarget as p, resolveCfnFallbackRegion as pa, defaultCredentialsLoader as pi, applyEdgeResponseResult as pn, isLocalCdkAssetImage as pr, WEB_FUNCTION_CONTAINER_PORT as pt, MAX_RUN_HOOK_PAYLOAD_BYTES as q, containsDynamicReference as qa, buildMgmtEndpointEnvUrl as qi, addCommonEcsServiceOptions as qn, addInvokeSpecificOptions as qr, LocalStartCloudFrontError as qt, coerceServeRequest as r, resolveRuntimeImage as ra, materializeLayerFromArn as ri, resolveDeployedKvsArnByName as rn, deployAccountStsClientConfig as ro, ImageOverrideError as rr, MICROVM_IMAGE_TYPE as rt, createStudioServeManager as s, substituteEnvVarsFromState as sa, filterRoutesByApiIdentifiers as si, matchBehavior as sn, workloadClientConfig as so, mergeForService as sr, resolveMicrovmCodeArtifact as st, addStudioSpecificOptions as t, resolveRuntimeCodeMountPath as ta, attachStageContext as ti, resolveKvsModulesForDistribution as tn, SECOND_ASSUME_MESSAGE as to, resolveSharedSidecarCredentials as tr, waitForAppAnswer as tt, reinvoke as u, createLocalStateProvider as ua, startApiServer as ui, serveFromStaticOrigin as un, resolveProfileCredentials as uo, runImageOverrideBuilds as ur, addStartWebFunctionSpecificOptions as ut, startStudioServer as v, resolveSsmParameters as va, verifyJwtAuthorizer as vi, CLOUDFRONT_DISTRIBUTION_TYPE as vn, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as vr, waitForWebFunctionReady as vt, createLocalListCommand as w, discoverWebSocketApis as wa, invokeTokenAuthorizer as wi, pickLambdaEdgeFunctionLogicalId as wn, bridgeAgentCoreWs as wr, webFunctionAssumeRole as wt, createStudioStore as x, countTargets as xa, computeRequestIdentityHash as xi, isCloudFrontDistribution as xn, attachContainerLogStreamer as xr, buildWebFunctionLambdaView as xt, toStudioTargetGroups as y, resolveWatchConfig as ya, verifyJwtViaDiscovery as yi, describeS3OriginDomain as yn, setShadowReadyTimeoutMs as yr, watchContainerExit as yt, MICROVM_CONTROL_PATH as z, resolveAgentCoreTarget as za, tryParseStatus as zi, isApplicationLoadBalancer as zn, waitForAgentCorePing as zr, resolveWebFunctionTarget as zt };
32487
+ //# sourceMappingURL=local-studio-BhFxp-jM.js.map