cdk-local 0.159.0 → 0.160.1

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.
@@ -1,8 +1,8 @@
1
1
  import { C as sanitizeServiceExceptionMessage, S as isAwsServiceException, _ as resolveAssemblyPath, a as isDockerClientEnvKey, b as describeCredentialLoadFailure, c as runDockerStreaming, d as absoluteAssemblyPathEscape, f as assemblyPathEscape, g as renderAssemblyPathEscape, h as namesTheSameDirectory, i as getDockerCmd, l as spawnStreaming, m as isPasteableCommandArg, n as finchSecretArgvRefusal, o as isMalformedEnvKey, p as displayUntrustedValue, r as formatDockerLoginError, s as runDockerForeground, u as warnFinchArgvExposure, v as clampErrorName, w as stringifyThrown, x as flattenToOneLine, y as describeAwsFailureForWarn } from "./docker-cmd-CoZdbeos.js";
2
2
  import { a as displayIdent, c as getEmbedConfig, i as STACK_REF_MAX_CODE_POINTS, o as displayStackName, s as displayToolOutput, t as getLogger, u as setEmbedConfig } from "./logger-Co5XVwco.js";
3
- import { chmodSync, cpSync, createWriteStream, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { chmodSync, cpSync, createWriteStream, existsSync, lstatSync, mkdirSync, mkdtempSync, promises, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { homedir, hostname, tmpdir } from "node:os";
5
- import * as path$1 from "node:path";
5
+ import * as nodePath from "node:path";
6
6
  import path, { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
7
7
  import { Command, InvalidArgumentError, Option } from "commander";
8
8
  import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
@@ -6850,6 +6850,10 @@ function extractHashFromImageUri(imageUri) {
6850
6850
  //#endregion
6851
6851
  //#region src/local/rie-client.ts
6852
6852
  const INVOKE_PATH = "/2015-03-31/functions/function/invocations";
6853
+ const NOT_AN_RIE_STATUS = /* @__PURE__ */ new Set([404, 405]);
6854
+ function notAnRieError(url, status) {
6855
+ return /* @__PURE__ */ new Error(`The container answered the invoke at ${url} with HTTP ${status}, which the Lambda Runtime Interface Emulator never sends for that path: something else is listening on the container's port 8080 (the function's own server?). Check the container logs.`);
6856
+ }
6853
6857
  async function waitForRieReady(host, port, timeoutMs = 5e3) {
6854
6858
  const deadline = Date.now() + timeoutMs;
6855
6859
  let lastError;
@@ -6910,6 +6914,7 @@ async function invokeRie(host, port, event, timeoutMs) {
6910
6914
  clearTimeout(timer);
6911
6915
  }
6912
6916
  const raw = await response.text();
6917
+ if (NOT_AN_RIE_STATUS.has(response.status)) throw notAnRieError(url, response.status);
6913
6918
  let payload = raw;
6914
6919
  try {
6915
6920
  payload = JSON.parse(raw);
@@ -6965,6 +6970,11 @@ async function invokeRieStreaming(host, port, event, timeoutMs) {
6965
6970
  if (err.name === "AbortError") throw new Error(`RIE streaming invoke at ${url} timed out after ${timeoutMs}ms. The handler may be hung; check container logs.`);
6966
6971
  throw err;
6967
6972
  }
6973
+ if (NOT_AN_RIE_STATUS.has(response.status)) {
6974
+ clearTimeout(timer);
6975
+ await response.body?.cancel().catch(() => void 0);
6976
+ throw notAnRieError(url, response.status);
6977
+ }
6968
6978
  if (!response.body) {
6969
6979
  clearTimeout(timer);
6970
6980
  throw new Error(`RIE streaming invoke at ${url} returned no response body.`);
@@ -8856,11 +8866,11 @@ function createContainerPool(specs, options) {
8856
8866
  } else containerId = await runDetached({
8857
8867
  image: spec.image,
8858
8868
  mounts: [],
8859
- ...spec.profileCredentialsFile && { extraMounts: [{
8869
+ extraMounts: [...spec.rieMount ? [spec.rieMount] : [], ...spec.profileCredentialsFile ? [{
8860
8870
  hostPath: spec.profileCredentialsFile.hostPath,
8861
8871
  containerPath: spec.profileCredentialsFile.containerPath,
8862
8872
  readOnly: true
8863
- }] },
8873
+ }] : []],
8864
8874
  env: spec.env,
8865
8875
  ...spec.sensitiveEnvKeys !== void 0 && { sensitiveEnvKeys: spec.sensitiveEnvKeys },
8866
8876
  cmd: spec.command,
@@ -9077,6 +9087,209 @@ function clampConcurrency(input) {
9077
9087
  return Math.min(MAX_PER_LAMBDA_CONCURRENCY, Math.max(MIN_PER_LAMBDA_CONCURRENCY, Math.trunc(input)));
9078
9088
  }
9079
9089
 
9090
+ //#endregion
9091
+ //#region src/utils/cache-home.ts
9092
+ function userCacheHome(env = process.env, home = homedir) {
9093
+ const product = getEmbedConfig().productName.replace(/[^A-Za-z0-9._-]/g, "-").replace(/^\.*$/, "-");
9094
+ const xdg = env["XDG_CACHE_HOME"];
9095
+ if (xdg !== void 0 && isAbsolute(xdg)) return join(xdg, product);
9096
+ let dir;
9097
+ try {
9098
+ dir = home();
9099
+ } catch {
9100
+ return;
9101
+ }
9102
+ return isAbsolute(dir) ? join(dir, ".cache", product) : void 0;
9103
+ }
9104
+
9105
+ //#endregion
9106
+ //#region src/local/rie-mount.ts
9107
+ const RIE_CONTAINER_PATH = "/var/rapid/aws-lambda-rie";
9108
+ const RIE_SOURCE_IMAGE = "public.ecr.aws/lambda/provided:al2023";
9109
+ const RIE_SOURCE_PATH = "/usr/local/bin/aws-lambda-rie";
9110
+ const RIE_BASENAME = "aws-lambda-rie";
9111
+ const ELF_MACHINE_BY_PLATFORM = {
9112
+ "linux/amd64": 62,
9113
+ "linux/arm64": 183
9114
+ };
9115
+ function rieCacheDirectory(env = process.env) {
9116
+ const root = userCacheHome(env);
9117
+ return root === void 0 ? void 0 : join(root, "lambda-rie");
9118
+ }
9119
+ const inFlight = /* @__PURE__ */ new Map();
9120
+ const warnedNoBinary = /* @__PURE__ */ new Set();
9121
+ async function resolveRieWrap(input) {
9122
+ const logger = getLogger().child("rie");
9123
+ let program;
9124
+ try {
9125
+ const own = nonEmpty(input.entryPoint) && nonEmpty(input.command) ? {
9126
+ entrypoint: [],
9127
+ cmd: []
9128
+ } : await inspectImageEntrypointCmd(input.image);
9129
+ const entryPoint = nonEmpty(input.entryPoint) ? [...input.entryPoint] : own.entrypoint;
9130
+ const cmd = nonEmpty(input.command) ? [...input.command] : own.cmd;
9131
+ program = [...entryPoint, ...cmd];
9132
+ } catch (err) {
9133
+ logger.warn(`Could not read the ENTRYPOINT / CMD of image ${displayUntrustedValue(input.image)} (${messageOf(err)}), so no Lambda Runtime Interface Emulator is mounted into it; it runs as built.`);
9134
+ return;
9135
+ }
9136
+ const ownRie = program.find(isRieExecutable);
9137
+ if (ownRie !== void 0) {
9138
+ logger.debug(`Image ${displayUntrustedValue(input.image)} already runs ${displayUntrustedValue(ownRie)}; not mounting another RIE`);
9139
+ return;
9140
+ }
9141
+ let hostPath;
9142
+ try {
9143
+ hostPath = await ensureRieBinary(input.platform, input.skipPull === true);
9144
+ } catch (err) {
9145
+ if (!warnedNoBinary.has(input.platform)) {
9146
+ warnedNoBinary.add(input.platform);
9147
+ logger.warn(`Could not mount the Lambda Runtime Interface Emulator into ${displayUntrustedValue(input.platform)} container-image functions (${messageOf(err)}). They run as built, so only images that ship their own emulator (the AWS Lambda base images do) can be invoked.`);
9148
+ } else logger.debug(`RIE mount skipped for ${displayUntrustedValue(input.image)}: ${messageOf(err)}`);
9149
+ return;
9150
+ }
9151
+ return {
9152
+ mount: {
9153
+ hostPath,
9154
+ containerPath: RIE_CONTAINER_PATH,
9155
+ readOnly: true
9156
+ },
9157
+ entryPoint: [RIE_CONTAINER_PATH],
9158
+ cmd: program
9159
+ };
9160
+ }
9161
+ function isRieExecutable(path) {
9162
+ return basename(path).startsWith(RIE_BASENAME);
9163
+ }
9164
+ function messageOf(err) {
9165
+ return displayToolOutput(err instanceof Error ? err.message : String(err));
9166
+ }
9167
+ function nonEmpty(v) {
9168
+ return v !== void 0 && v.length > 0;
9169
+ }
9170
+ async function inspectImageEntrypointCmd(image) {
9171
+ let stdout;
9172
+ try {
9173
+ ({stdout} = await runDockerStreaming([
9174
+ "image",
9175
+ "inspect",
9176
+ "--format",
9177
+ "{{json .Config}}",
9178
+ image
9179
+ ], { streamLive: false }));
9180
+ } catch (err) {
9181
+ throw new Error(`docker image inspect failed: ${messageOf(err)}`);
9182
+ }
9183
+ const config = JSON.parse(stdout.trim());
9184
+ return {
9185
+ entrypoint: stringArray(config?.Entrypoint),
9186
+ cmd: stringArray(config?.Cmd)
9187
+ };
9188
+ }
9189
+ function stringArray(v) {
9190
+ return Array.isArray(v) && v.every((s) => typeof s === "string") ? v : [];
9191
+ }
9192
+ async function ensureRieBinary(platform, skipPull) {
9193
+ const machine = ELF_MACHINE_BY_PLATFORM[platform];
9194
+ if (machine === void 0) throw new Error(`unsupported platform '${platform}'`);
9195
+ const root = rieCacheDirectory();
9196
+ if (root === void 0) throw new Error("no cache directory (HOME is not set)");
9197
+ const target = join(root, platform.replace("/", "-"), RIE_BASENAME);
9198
+ if (!isMountableHostPath(target)) throw new Error(`the cache path ${displayUntrustedValue(target)} contains ':'`);
9199
+ let run = inFlight.get(target);
9200
+ if (run === void 0) {
9201
+ run = (async () => {
9202
+ if (await isRegularFile(target) && await isElfFor(target, machine)) return target;
9203
+ await extractRie(platform, target, machine, skipPull);
9204
+ return target;
9205
+ })();
9206
+ inFlight.set(target, run);
9207
+ run.catch(() => inFlight.delete(target));
9208
+ }
9209
+ return run;
9210
+ }
9211
+ function isMountableHostPath(path, pathApi = nodePath) {
9212
+ return !path.slice(pathApi.parse(path).root.length).includes(":");
9213
+ }
9214
+ async function isRegularFile(path) {
9215
+ try {
9216
+ return (await promises.lstat(path)).isFile();
9217
+ } catch {
9218
+ return false;
9219
+ }
9220
+ }
9221
+ async function isElfFor(path, machine) {
9222
+ let handle;
9223
+ try {
9224
+ handle = await promises.open(path, "r");
9225
+ const header = Buffer.alloc(20);
9226
+ const { bytesRead } = await handle.read(header, 0, 20, 0);
9227
+ return bytesRead === 20 && header.readUInt32BE(0) === 2135247942 && header.readUInt16LE(18) === machine;
9228
+ } catch {
9229
+ return false;
9230
+ } finally {
9231
+ await handle?.close().catch(() => void 0);
9232
+ }
9233
+ }
9234
+ async function extractRie(platform, target, machine, skipPull) {
9235
+ getLogger().child("rie").info(skipPull ? `Copying the Lambda Runtime Interface Emulator for ${platform} out of the local ${RIE_SOURCE_IMAGE} image (one time)...` : `Fetching the Lambda Runtime Interface Emulator for ${platform} from ${RIE_SOURCE_IMAGE} (one time)...`);
9236
+ const dir = dirname(target);
9237
+ await promises.mkdir(dir, {
9238
+ recursive: true,
9239
+ mode: 448
9240
+ });
9241
+ if (!skipPull) try {
9242
+ await runDockerStreaming([
9243
+ "pull",
9244
+ "--platform",
9245
+ platform,
9246
+ RIE_SOURCE_IMAGE
9247
+ ], { streamLive: false });
9248
+ } catch (err) {
9249
+ throw new Error(`docker pull failed: ${messageOf(err)}`);
9250
+ }
9251
+ const createArgs = [
9252
+ "create",
9253
+ "--name",
9254
+ `${getEmbedConfig().resourceNamePrefix}-rie-extract-${process.pid}-${randomBytes(4).toString("hex")}`,
9255
+ ...skipPull ? ["--pull", "never"] : [],
9256
+ "--platform",
9257
+ platform,
9258
+ RIE_SOURCE_IMAGE
9259
+ ];
9260
+ let containerId;
9261
+ try {
9262
+ containerId = (await runDockerStreaming(createArgs, { streamLive: false })).stdout.trim();
9263
+ } catch (err) {
9264
+ throw new Error(`docker create failed: ${messageOf(err)}` + (skipPull ? ` (--no-pull: pull ${RIE_SOURCE_IMAGE} once, or run ${getEmbedConfig().binaryName} without --no-pull)` : ""));
9265
+ }
9266
+ const tmp = join(dir, `.${RIE_BASENAME}.${process.pid}.${randomBytes(4).toString("hex")}`);
9267
+ try {
9268
+ try {
9269
+ await runDockerStreaming([
9270
+ "cp",
9271
+ `${containerId}:${RIE_SOURCE_PATH}`,
9272
+ tmp
9273
+ ], { streamLive: false });
9274
+ } catch (err) {
9275
+ throw new Error(`docker cp failed: ${messageOf(err)}`);
9276
+ }
9277
+ if (!await isRegularFile(tmp) || !await isElfFor(tmp, machine)) throw new Error(`the copied ${RIE_SOURCE_PATH} is not a ${platform} executable`);
9278
+ await promises.chmod(tmp, 493);
9279
+ await promises.rename(tmp, target);
9280
+ } finally {
9281
+ await promises.rm(tmp, {
9282
+ force: true,
9283
+ recursive: true
9284
+ }).catch(() => void 0);
9285
+ await runDockerStreaming([
9286
+ "rm",
9287
+ "-f",
9288
+ containerId
9289
+ ], { streamLive: false }).catch(() => void 0);
9290
+ }
9291
+ }
9292
+
9080
9293
  //#endregion
9081
9294
  //#region src/local/api-gateway-event.ts
9082
9295
  const MOCK_ACCOUNT_ID = "123456789012";
@@ -12337,8 +12550,8 @@ function getContainerAwsCredentialsPath() {
12337
12550
  async function writeProfileCredentialsFile(profileName, creds) {
12338
12551
  if (profileName === "") throw new Error("writeProfileCredentialsFile: profile name must not be empty.");
12339
12552
  if (/[\r\n[\]]/.test(profileName)) throw new Error(`writeProfileCredentialsFile: profile name ${displayUntrustedValue(profileName)} contains a forbidden character (any of CR, LF, '[', ']' would corrupt the INI file or the docker -e env var).`);
12340
- const dir = await mkdtemp(path$1.join(tmpdir(), `${getEmbedConfig().productName}-profile-creds-`));
12341
- const hostPath = path$1.join(dir, "credentials");
12553
+ const dir = await mkdtemp(nodePath.join(tmpdir(), `${getEmbedConfig().productName}-profile-creds-`));
12554
+ const hostPath = nodePath.join(dir, "credentials");
12342
12555
  const lines = [
12343
12556
  `[${profileName}]`,
12344
12557
  `aws_access_key_id = ${creds.accessKeyId}`,
@@ -12791,8 +13004,8 @@ async function localStartApiCommand(targets, options, extraStateProviders) {
12791
13004
  }
12792
13005
  function createWatchPredicates(args) {
12793
13006
  const { watchRoot, output, watchConfig } = args;
12794
- const toRel = (abs) => path$1.relative(watchRoot, abs).split(path$1.sep).join("/");
12795
- const outputRel = toRel(path$1.resolve(watchRoot, output));
13007
+ const toRel = (abs) => nodePath.relative(watchRoot, abs).split(nodePath.sep).join("/");
13008
+ const outputRel = toRel(nodePath.resolve(watchRoot, output));
12796
13009
  const excludePatterns = [
12797
13010
  ...outputRel !== "" && !outputRel.startsWith("..") ? [outputRel] : [],
12798
13011
  "node_modules",
@@ -13159,13 +13372,24 @@ async function buildContainerSpec(args) {
13159
13372
  containerPath: profileCredsFile.containerPath
13160
13373
  } }
13161
13374
  };
13375
+ const rie = await resolveRieWrap({
13376
+ image: imageRef,
13377
+ platform,
13378
+ entryPoint: lambda.imageConfig.entryPoint,
13379
+ command: lambda.imageConfig.command,
13380
+ skipPull
13381
+ });
13162
13382
  return {
13163
13383
  kind: "image",
13164
13384
  lambda,
13165
13385
  image: imageRef,
13166
13386
  platform,
13167
- command: lambda.imageConfig.command ?? [],
13168
- ...lambda.imageConfig.entryPoint !== void 0 && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
13387
+ command: rie ? rie.cmd : lambda.imageConfig.command ?? [],
13388
+ ...rie && {
13389
+ entryPoint: rie.entryPoint,
13390
+ rieMount: rie.mount
13391
+ },
13392
+ ...!rie && lambda.imageConfig.entryPoint !== void 0 && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
13169
13393
  ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
13170
13394
  env: dockerEnv,
13171
13395
  ...sensitiveEnvKeys && { sensitiveEnvKeys },
@@ -13198,7 +13422,7 @@ async function resolveContainerImageForStartApi(lambda, skipPull, profile, optio
13198
13422
  async function resolveLocalBuildPlan$1(lambda) {
13199
13423
  const manifestPath = lambda.stack.assetManifestPath;
13200
13424
  if (!manifestPath) return void 0;
13201
- const cdkOutDir = path$1.dirname(manifestPath);
13425
+ const cdkOutDir = nodePath.dirname(manifestPath);
13202
13426
  const manifest = await new AssetManifestLoader().loadStackManifest(lambda.stack, cdkOutDir);
13203
13427
  if (!manifest) return void 0;
13204
13428
  const entry = getDockerImageBySourceHash(manifest, lambda.imageUri);
@@ -13228,7 +13452,7 @@ async function materializeLambdaLayers$1(layers, layerTmpDirs, layerRoleArn) {
13228
13452
  });
13229
13453
  }
13230
13454
  if (flat.length === 1) return flat[0].assetPath;
13231
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-start-api-layers-`));
13455
+ const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-start-api-layers-`));
13232
13456
  try {
13233
13457
  for (const layer of flat) copyLayerTreeLastWins(layer.assetPath, dir);
13234
13458
  } catch (error) {
@@ -13369,10 +13593,10 @@ function materializeInlineCode$2(handler, source, fileExtension, tmpDirsOut) {
13369
13593
  const lastDot = handler.lastIndexOf(".");
13370
13594
  if (lastDot <= 0) throw new Error(`Handler ${displayUntrustedValue(handler)} is malformed: expected '<modulePath>.<exportName>'.`);
13371
13595
  const modulePath = handler.substring(0, lastDot);
13372
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-start-api-`));
13596
+ const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-start-api-`));
13373
13597
  tmpDirsOut.add(dir);
13374
- const filePath = path$1.join(dir, `${modulePath}${fileExtension}`);
13375
- mkdirSync(path$1.dirname(filePath), { recursive: true });
13598
+ const filePath = nodePath.join(dir, `${modulePath}${fileExtension}`);
13599
+ mkdirSync(nodePath.dirname(filePath), { recursive: true });
13376
13600
  writeFileSync(filePath, source, "utf-8");
13377
13601
  return dir;
13378
13602
  }
@@ -13896,7 +14120,7 @@ function materializeLambdaLayers(layers) {
13896
14120
  containerPath: "/opt",
13897
14121
  readOnly: true
13898
14122
  } };
13899
- const tmpDir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-invoke-layers-`));
14123
+ const tmpDir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-invoke-layers-`));
13900
14124
  try {
13901
14125
  for (const layer of layers) copyLayerTreeLastWins(layer.assetPath, tmpDir);
13902
14126
  } catch (error) {
@@ -13936,13 +14160,21 @@ async function resolveContainerImagePlan$1(lambda, options) {
13936
14160
  });
13937
14161
  }
13938
14162
  const tmpfs = resolveTmpfsForLambda(lambda);
14163
+ const rie = await resolveRieWrap({
14164
+ image: imageRef,
14165
+ platform,
14166
+ entryPoint: lambda.imageConfig.entryPoint,
14167
+ command: lambda.imageConfig.command,
14168
+ skipPull: options.pull === false
14169
+ });
13939
14170
  return {
13940
14171
  image: imageRef,
13941
14172
  mounts: [],
13942
- extraMounts: [],
13943
- cmd: lambda.imageConfig.command ?? [],
14173
+ extraMounts: rie ? [rie.mount] : [],
14174
+ cmd: rie ? rie.cmd : lambda.imageConfig.command ?? [],
13944
14175
  platform,
13945
- ...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
14176
+ ...rie && { entryPoint: rie.entryPoint },
14177
+ ...!rie && lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
13946
14178
  ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
13947
14179
  ...tmpfs !== void 0 && { tmpfs }
13948
14180
  };
@@ -14233,9 +14465,9 @@ function materializeInlineCode$1(handler, source, fileExtension) {
14233
14465
  const lastDot = handler.lastIndexOf(".");
14234
14466
  if (lastDot <= 0) throw new Error(`Handler ${displayUntrustedValue(handler)} is malformed: expected '<modulePath>.<exportName>'.`);
14235
14467
  const modulePath = handler.substring(0, lastDot);
14236
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-invoke-`));
14237
- const filePath = path$1.join(dir, `${modulePath}${fileExtension}`);
14238
- mkdirSync(path$1.dirname(filePath), { recursive: true });
14468
+ const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-invoke-`));
14469
+ const filePath = nodePath.join(dir, `${modulePath}${fileExtension}`);
14470
+ mkdirSync(nodePath.dirname(filePath), { recursive: true });
14239
14471
  writeFileSync(filePath, source, "utf-8");
14240
14472
  return dir;
14241
14473
  }
@@ -18923,6 +19155,7 @@ const DEFAULT_UPSTREAM_TIMEOUT_MS = 3e4;
18923
19155
  async function startFrontDoorServer(opts) {
18924
19156
  const logger = getLogger().child("front-door");
18925
19157
  const host = opts.host ?? "127.0.0.1";
19158
+ if (opts.assumeHost !== void 0 && !/^[\x21-\x7e]+$/.test(opts.assumeHost)) throw new Error(`assumeHost must be a non-empty host name without blanks or control characters (got ${JSON.stringify(opts.assumeHost)}).`);
18926
19159
  const forwardedProto = opts.forwardedProto ?? (opts.tls ? "https" : "http");
18927
19160
  const effectiveOpts = {
18928
19161
  ...opts,
@@ -18988,7 +19221,7 @@ function handleProxyRequest(req, res, opts) {
18988
19221
  if (opts.route) {
18989
19222
  const action = opts.route({
18990
19223
  path: url,
18991
- ...hostHeader(req),
19224
+ ...routeHost(req, opts),
18992
19225
  headers: req.headers,
18993
19226
  ...req.method !== void 0 && { method: req.method },
18994
19227
  ...req.socket.remoteAddress !== void 0 && { sourceIp: req.socket.remoteAddress }
@@ -19052,7 +19285,8 @@ function buildNoRuleMatched404Body(req, opts) {
19052
19285
  const summary = opts.rulesSummary;
19053
19286
  if (!summary) return `No listener rule matched '${requestPath}' on ${opts.label}, and the listener has no default action forwarding to a local target.`;
19054
19287
  const rawHost = req.headers.host;
19055
- const hostValue = Array.isArray(rawHost) ? rawHost[0] : rawHost;
19288
+ const requestHost = Array.isArray(rawHost) ? rawHost[0] : rawHost;
19289
+ const hostValue = opts.assumeHost !== void 0 ? `${opts.assumeHost} (--assume-host; the request sent ${requestHost ?? "no Host header"})` : requestHost;
19056
19290
  const lines = [];
19057
19291
  lines.push(`No listener rule matched the request on ${opts.label}, and the listener has no default action forwarding to a local target.`);
19058
19292
  lines.push("");
@@ -19091,7 +19325,7 @@ function handlePoolRequest(req, res, pool, opts) {
19091
19325
  };
19092
19326
  const headers = { ...req.headers };
19093
19327
  stripHopByHopHeaders(headers);
19094
- appendForwardedHeaders(headers, req, opts.listenerPort, resolveForwardedProto(opts));
19328
+ appendForwardedHeaders(headers, req, opts);
19095
19329
  const proxyReq = request({
19096
19330
  host: endpoint.host,
19097
19331
  port: endpoint.port,
@@ -19126,7 +19360,8 @@ function handlePoolRequest(req, res, pool, opts) {
19126
19360
  req.pipe(proxyReq);
19127
19361
  });
19128
19362
  }
19129
- function hostHeader(req) {
19363
+ function routeHost(req, opts) {
19364
+ if (opts.assumeHost !== void 0) return { host: opts.assumeHost };
19130
19365
  const raw = req.headers.host;
19131
19366
  const host = Array.isArray(raw) ? raw[0] : raw;
19132
19367
  return host ? { host } : {};
@@ -19219,7 +19454,7 @@ function handleLambdaRequest(req, res, lambda, opts) {
19219
19454
  const body = Buffer.concat(chunks);
19220
19455
  const forwardHeaders = { ...req.headers };
19221
19456
  stripHopByHopHeaders(forwardHeaders);
19222
- appendForwardedHeaders(forwardHeaders, req, opts.listenerPort, resolveForwardedProto(opts));
19457
+ appendForwardedHeaders(forwardHeaders, req, opts);
19223
19458
  const snapshot = snapshotFromIncoming(req, body);
19224
19459
  for (const [name, value] of Object.entries(forwardHeaders)) {
19225
19460
  if (value === void 0) continue;
@@ -19273,13 +19508,14 @@ function stripHopByHopHeaders(headers) {
19273
19508
  function resolveForwardedProto(opts) {
19274
19509
  return opts.forwardedProto ?? (opts.tls ? "https" : "http");
19275
19510
  }
19276
- function appendForwardedHeaders(headers, req, listenerPort, scheme) {
19511
+ function appendForwardedHeaders(headers, req, opts) {
19277
19512
  const clientIp = req.socket.remoteAddress ?? "";
19278
19513
  const existing = headers["x-forwarded-for"];
19279
19514
  const chain = Array.isArray(existing) ? existing.join(", ") : existing;
19280
19515
  headers["x-forwarded-for"] = chain ? `${chain}, ${clientIp}` : clientIp;
19281
- headers["x-forwarded-proto"] = scheme;
19282
- headers["x-forwarded-port"] = String(listenerPort);
19516
+ headers["x-forwarded-proto"] = resolveForwardedProto(opts);
19517
+ headers["x-forwarded-port"] = String(opts.listenerPort);
19518
+ if (opts.assumeHost !== void 0) headers["host"] = opts.assumeHost;
19283
19519
  }
19284
19520
  function writeError(res, statusCode, message) {
19285
19521
  res.writeHead(statusCode, { "content-type": "text/plain; charset=utf-8" });
@@ -19293,7 +19529,7 @@ function handleUpgrade$1(req, clientSocket, head, opts) {
19293
19529
  }
19294
19530
  const action = opts.route({
19295
19531
  path: req.url ?? "/",
19296
- ...hostHeader(req),
19532
+ ...routeHost(req, opts),
19297
19533
  headers: req.headers,
19298
19534
  ...req.method !== void 0 && { method: req.method },
19299
19535
  ...req.socket.remoteAddress !== void 0 && { sourceIp: req.socket.remoteAddress }
@@ -19361,7 +19597,7 @@ function bridgeWebSocket(req, clientSocket, head, pool, opts) {
19361
19597
  upstream.on("connect", () => {
19362
19598
  upstreamConnected = true;
19363
19599
  const headers = { ...req.headers };
19364
- appendForwardedHeaders(headers, req, opts.listenerPort, resolveForwardedProto(opts));
19600
+ appendForwardedHeaders(headers, req, opts);
19365
19601
  const lines = [`${req.method ?? "GET"} ${req.url ?? "/"} HTTP/${req.httpVersion}`];
19366
19602
  for (const [name, value] of Object.entries(headers)) {
19367
19603
  if (value === void 0) continue;
@@ -19850,9 +20086,9 @@ function materializeInlineCode(handler, source, fileExtension) {
19850
20086
  const lastDot = handler.lastIndexOf(".");
19851
20087
  if (lastDot <= 0) throw new Error(`Handler ${displayIdent(handler)} is malformed: expected '<modulePath>.<exportName>'.`);
19852
20088
  const modulePath = handler.substring(0, lastDot);
19853
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-alb-lambda-`));
19854
- const filePath = path$1.join(dir, `${modulePath}${fileExtension}`);
19855
- mkdirSync(path$1.dirname(filePath), { recursive: true });
20089
+ const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-alb-lambda-`));
20090
+ const filePath = nodePath.join(dir, `${modulePath}${fileExtension}`);
20091
+ mkdirSync(nodePath.dirname(filePath), { recursive: true });
19856
20092
  writeFileSync(filePath, source, "utf-8");
19857
20093
  return dir;
19858
20094
  }
@@ -19892,7 +20128,7 @@ async function resolveContainerImagePlan(lambda, opts) {
19892
20128
  let imageRef;
19893
20129
  let localBuilt = false;
19894
20130
  if (manifestPath) {
19895
- const cdkOutDir = path$1.dirname(manifestPath);
20131
+ const cdkOutDir = nodePath.dirname(manifestPath);
19896
20132
  const manifest = await new AssetManifestLoader().loadStackManifest(lambda.stack, cdkOutDir);
19897
20133
  const entry = manifest ? getDockerImageBySourceHash(manifest, lambda.imageUri) : void 0;
19898
20134
  if (entry) {
@@ -19912,12 +20148,20 @@ async function resolveContainerImagePlan(lambda, opts) {
19912
20148
  ...opts.ecrRoleArn !== void 0 && { ecrRoleArn: opts.ecrRoleArn }
19913
20149
  });
19914
20150
  }
20151
+ const rie = await resolveRieWrap({
20152
+ image: imageRef,
20153
+ platform,
20154
+ entryPoint: lambda.imageConfig.entryPoint,
20155
+ command: lambda.imageConfig.command,
20156
+ skipPull: opts.skipPull === true
20157
+ });
19915
20158
  return {
19916
20159
  image: imageRef,
19917
- mounts: [],
19918
- cmd: lambda.imageConfig.command ?? [],
20160
+ mounts: rie ? [rie.mount] : [],
20161
+ cmd: rie ? rie.cmd : lambda.imageConfig.command ?? [],
19919
20162
  platform,
19920
- ...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
20163
+ ...rie && { entryPoint: rie.entryPoint },
20164
+ ...!rie && lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
19921
20165
  ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory }
19922
20166
  };
19923
20167
  }
@@ -21293,7 +21537,8 @@ async function buildFrontDoor(plan, options, logger, extraStateProviders) {
21293
21537
  label: `listener port ${listener.listenerPort}`,
21294
21538
  forwardedProto,
21295
21539
  rulesSummary,
21296
- ...tls ? { tls } : {}
21540
+ ...tls ? { tls } : {},
21541
+ ...listener.assumeHost !== void 0 && { assumeHost: listener.assumeHost }
21297
21542
  };
21298
21543
  let server;
21299
21544
  try {
@@ -21312,6 +21557,7 @@ async function buildFrontDoor(plan, options, logger, extraStateProviders) {
21312
21557
  }
21313
21558
  servers.push(server);
21314
21559
  logger.info(`ALB front-door: ${server.scheme}://${formatAuthority(server.host, server.port)} (listener port ${listener.listenerPort})`);
21560
+ if (listener.assumeHost !== void 0) logger.info(` assumed host: ${displayUntrustedValue(listener.assumeHost)} (--assume-host; host-header rules see it and the target receives it as Host)`);
21315
21561
  if (degradedHttps) logger.warn(`listener port ${listener.listenerPort} is HTTPS in the cloud but serving HTTP locally (X-Forwarded-Proto: https preserved). Pass --tls to terminate TLS locally with a self-signed or user-supplied cert.`);
21316
21562
  if (listener.defaultAction) logger.info(` default -> ${describeAction(listener.defaultAction)}`);
21317
21563
  for (const r of [...listener.rules].sort((a, b) => a.priority - b.priority)) logger.info(` ${describeConditions(r)} (priority ${r.priority}) -> ${describeAction(r.action)}`);
@@ -22612,6 +22858,31 @@ function parseLbPortOverrides(values) {
22612
22858
  }
22613
22859
  return out;
22614
22860
  }
22861
+ const ASSUME_HOST_PATTERN = /^(?:[A-Za-z0-9_](?:[A-Za-z0-9_.-]*[A-Za-z0-9_])?|\[[0-9A-Fa-f:.]+\])(?::\d{1,5})?$/;
22862
+ function parseAssumeHostOverrides(values) {
22863
+ const out = { byListenerPort: {} };
22864
+ const usage = "Expected <host> or <listenerPort>=<host> (e.g. api.example.com or 443=api.example.com).";
22865
+ for (const raw of values ?? []) {
22866
+ const value = raw.trim();
22867
+ const eq = value.indexOf("=");
22868
+ const portPart = eq === -1 ? void 0 : value.slice(0, eq);
22869
+ const host = eq === -1 ? value : value.slice(eq + 1);
22870
+ const hostPort = /:(\d+)$/.exec(host)?.[1];
22871
+ if (!ASSUME_HOST_PATTERN.test(host) || hostPort !== void 0 && !(Number(hostPort) >= 1 && Number(hostPort) <= 65535)) throw new LocalStartServiceError(`Invalid --assume-host ${JSON.stringify(raw)}: ${host === "" ? "the host is empty" : `${JSON.stringify(host)} is not a host name`}. ${usage}`);
22872
+ if (portPart === void 0) {
22873
+ if (/^\d+$/.test(host)) throw new LocalStartServiceError(`Invalid --assume-host ${JSON.stringify(raw)}: a bare number is not a host name (did you mean ${host}=<host>?). ${usage}`);
22874
+ if (out.all !== void 0) throw new LocalStartServiceError(`--assume-host was given two hosts for every listener (${out.all} and ${host}). Pass one, or name each listener as <listenerPort>=<host>.`);
22875
+ out.all = host;
22876
+ continue;
22877
+ }
22878
+ const port = /^\d+$/.test(portPart) ? Number(portPart) : NaN;
22879
+ if (!(port >= 1 && port <= 65535)) throw new LocalStartServiceError(`Invalid --assume-host ${JSON.stringify(raw)}: the listener port must be 1-65535. ${usage}`);
22880
+ const prior = out.byListenerPort[port];
22881
+ if (prior !== void 0) throw new LocalStartServiceError(`--assume-host was given two hosts for listener port ${port} (${prior} and ${host}).`);
22882
+ out.byListenerPort[port] = host;
22883
+ }
22884
+ return out;
22885
+ }
22615
22886
  function resolveAlbTarget(target, stacks) {
22616
22887
  if (stacks.length === 0) throw new LocalStartServiceError("No stacks found in the synthesized assembly.");
22617
22888
  const parsed = parseEcsTarget(target);
@@ -22653,6 +22924,7 @@ function notFound$1(target, stack, resources) {
22653
22924
  }
22654
22925
  function albStrategy(options) {
22655
22926
  const lbPortOverrides = parseLbPortOverrides(options.lbPort);
22927
+ const assumeHosts = parseAssumeHostOverrides(options.assumeHost);
22656
22928
  return {
22657
22929
  pickEntries: (stacks) => listTargets(stacks).loadBalancers,
22658
22930
  pickerMessage: "Select one or more Application Load Balancers to run",
@@ -22714,10 +22986,12 @@ function albStrategy(options) {
22714
22986
  continue;
22715
22987
  }
22716
22988
  claimedHostPorts.set(hostPort, listener.listenerPort);
22989
+ const assumeHost = assumeHosts.byListenerPort[listener.listenerPort] ?? assumeHosts.all;
22717
22990
  listeners.push({
22718
22991
  listenerPort: listener.listenerPort,
22719
22992
  hostPort,
22720
22993
  protocol: listener.listenerProtocol,
22994
+ ...assumeHost !== void 0 && { assumeHost },
22721
22995
  ...listener.defaultAction ? { defaultAction: qualify(listener.defaultAction) } : {},
22722
22996
  ...listener.defaultAuthGuard ? { defaultAuthGuard: listener.defaultAuthGuard } : {},
22723
22997
  rules: listener.rules.map((r) => ({
@@ -22740,6 +23014,10 @@ function albStrategy(options) {
22740
23014
  const port = Number(portStr);
22741
23015
  if (!resolvedPorts.has(port)) warnings.push(`--lb-port override for listener port ${port} matched no ALB listener resolved for the named target(s); it was ignored.`);
22742
23016
  }
23017
+ for (const portStr of Object.keys(assumeHosts.byListenerPort)) {
23018
+ const port = Number(portStr);
23019
+ if (!resolvedPorts.has(port)) warnings.push(`--assume-host for listener port ${port} matched no ALB listener resolved for the named target(s); it was ignored.`);
23020
+ }
22743
23021
  return {
22744
23022
  boots,
22745
23023
  ...listeners.length > 0 ? { frontDoor: { listeners } } : {},
@@ -22761,7 +23039,7 @@ function createLocalStartAlbCommand(opts = {}) {
22761
23039
  }
22762
23040
  function addAlbSpecificOptions(cmd) {
22763
23041
  addImageOverrideOptions(cmd);
22764
- return cmd.addOption(new Option("--lb-port <listenerPort=hostPort...>", "Bind the local front-door on a specific host port (e.g. 80=8080); repeatable. Default: host port == ALB listener port. Use this on macOS to remap a privileged listener port (< 1024) to a non-privileged host port.")).addOption(new Option("--tls", "Terminate TLS locally for cloud-HTTPS listeners. Default: a cloud-HTTPS listener is served over plain HTTP locally (X-Forwarded-Proto: https is preserved so the upstream app still sees the deployed listener protocol). Implied by --tls-cert / --tls-key. Use this when local-dev cookies need Secure / SameSite=None, when the upstream app inspects TLS metadata, or for mTLS / SNI testing — otherwise plain HTTP is friendlier (no self-signed cert warnings in curl / browser).")).addOption(new Option("--tls-cert <path>", "PEM-encoded server certificate for HTTPS front-door listeners. Implies --tls. Must be set together with --tls-key. Pass --tls alone (without --tls-cert / --tls-key) to auto-generate a self-signed cert (cached under $XDG_CACHE_HOME/cdk-local/alb-https/, default ~/.cache/cdk-local/alb-https/); requires openssl on PATH. The deployed Listener Certificates[] are NOT fetched (ACM private keys are not retrievable by design). The auto-generated cert lists DNS:localhost,IP:127.0.0.1 as SubjectAltName, so a client validating a non-loopback --container-host will fail the SAN check — pass --tls-cert / --tls-key with a SAN covering that host instead.")).addOption(new Option("--tls-key <path>", "PEM-encoded server private key matching --tls-cert. Implies --tls. Must be set together with --tls-cert.")).addOption(new Option("--no-verify-auth", "Disable local enforcement of authenticate-cognito / authenticate-oidc actions. Every request is served as if the auth check passed. Useful for local dev where you do not want to mint a Bearer token at all.")).addOption(new Option("--bearer-token <jwt>", "Default Bearer JWT this command INJECTS only when an inbound request has none (the default-when-missing role) — `cdkl start-alb` is the local ALB front-door RECEIVING outside-in requests, so this token is the fallback the front-door slots in as Authorization: Bearer <jwt> if the caller did not already supply one. Verified against the same JWKS / OIDC discovery URL the deployed ALB would (signature + iss + aud + exp). Cookie pass-through (AWSELBAuthSessionCookie-*) also bypasses the guard. Contrast with `cdkl invoke-agentcore --bearer-token`, where the role is reversed — that command is the outbound client and ALWAYS presents this token (the supplier).")).addOption(new Option("--watch", "Hot-reload: re-synth + per-replica reload of every ECS service behind the ALB when the CDK source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). A per-firing classifier picks the per-replica primitive: source-only edits on interpreted-language handlers (Node/Python/Ruby/shell) take a bind-mount FAST PATH (`docker cp` the new source into each replica + restart it; no rebuild, its front-door pool entry is drained and re-published once it listens again). Dockerfile / dependency manifest / compiled-language source / ambiguous edits fall through to the rebuild rolling primitive — boot a shadow under a bumped generation suffix, wait for its container port to accept a TCP connection, atomically register it in the front-door pool, then drop the old entry and retire the old container. Either path rolls one replica at a time, so a continuous external request stream against the listener port sees zero connection refusals across the reload. The host front-door (TLS, JWKS cache, Lambda-target containers, listener sockets) stays up across the reload. Lambda target groups behind the ALB are a no-op on reload (the warm RIE container keeps its boot-time image). Off by default; existing replica(s) keep serving when synth fails mid-reload.").default(false));
23042
+ return cmd.addOption(new Option("--lb-port <listenerPort=hostPort...>", "Bind the local front-door on a specific host port (e.g. 80=8080); repeatable. Default: host port == ALB listener port. Use this on macOS to remap a privileged listener port (< 1024) to a non-privileged host port.")).addOption(new Option("--assume-host <host>", "Treat every inbound request as if it carried this Host: host-header rule conditions see <host>, and the target (ECS replica or Lambda) receives it as the Host header, as behind the deployed ALB on its own domain name. Use it to reach a listener rule that matches only a production host name (host-header: api.example.com) from a browser or a client that sends Host: localhost. <listenerPort>=<host> (e.g. 443=api.example.com) applies to one listener and wins over a bare <host>; repeatable. Other rule conditions are unaffected, and a redirect action keeps the request Host so the browser stays on the local front-door. Default: the request Host is used as sent.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate TLS locally for cloud-HTTPS listeners. Default: a cloud-HTTPS listener is served over plain HTTP locally (X-Forwarded-Proto: https is preserved so the upstream app still sees the deployed listener protocol). Implied by --tls-cert / --tls-key. Use this when local-dev cookies need Secure / SameSite=None, when the upstream app inspects TLS metadata, or for mTLS / SNI testing — otherwise plain HTTP is friendlier (no self-signed cert warnings in curl / browser).")).addOption(new Option("--tls-cert <path>", "PEM-encoded server certificate for HTTPS front-door listeners. Implies --tls. Must be set together with --tls-key. Pass --tls alone (without --tls-cert / --tls-key) to auto-generate a self-signed cert (cached under $XDG_CACHE_HOME/cdk-local/alb-https/, default ~/.cache/cdk-local/alb-https/); requires openssl on PATH. The deployed Listener Certificates[] are NOT fetched (ACM private keys are not retrievable by design). The auto-generated cert lists DNS:localhost,IP:127.0.0.1 as SubjectAltName, so a client validating a non-loopback --container-host will fail the SAN check — pass --tls-cert / --tls-key with a SAN covering that host instead.")).addOption(new Option("--tls-key <path>", "PEM-encoded server private key matching --tls-cert. Implies --tls. Must be set together with --tls-cert.")).addOption(new Option("--no-verify-auth", "Disable local enforcement of authenticate-cognito / authenticate-oidc actions. Every request is served as if the auth check passed. Useful for local dev where you do not want to mint a Bearer token at all.")).addOption(new Option("--bearer-token <jwt>", "Default Bearer JWT this command INJECTS only when an inbound request has none (the default-when-missing role) — `cdkl start-alb` is the local ALB front-door RECEIVING outside-in requests, so this token is the fallback the front-door slots in as Authorization: Bearer <jwt> if the caller did not already supply one. Verified against the same JWKS / OIDC discovery URL the deployed ALB would (signature + iss + aud + exp). Cookie pass-through (AWSELBAuthSessionCookie-*) also bypasses the guard. Contrast with `cdkl invoke-agentcore --bearer-token`, where the role is reversed — that command is the outbound client and ALWAYS presents this token (the supplier).")).addOption(new Option("--watch", "Hot-reload: re-synth + per-replica reload of every ECS service behind the ALB when the CDK source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). A per-firing classifier picks the per-replica primitive: source-only edits on interpreted-language handlers (Node/Python/Ruby/shell) take a bind-mount FAST PATH (`docker cp` the new source into each replica + restart it; no rebuild, its front-door pool entry is drained and re-published once it listens again). Dockerfile / dependency manifest / compiled-language source / ambiguous edits fall through to the rebuild rolling primitive — boot a shadow under a bumped generation suffix, wait for its container port to accept a TCP connection, atomically register it in the front-door pool, then drop the old entry and retire the old container. Either path rolls one replica at a time, so a continuous external request stream against the listener port sees zero connection refusals across the reload. The host front-door (TLS, JWKS cache, Lambda-target containers, listener sockets) stays up across the reload. Lambda target groups behind the ALB are a no-op on reload (the warm RIE container keeps its boot-time image). Off by default; existing replica(s) keep serving when synth fails mid-reload.").default(false));
22765
23043
  }
22766
23044
 
22767
23045
  //#endregion
@@ -25755,7 +26033,7 @@ async function bootLambdaEdgeFunctions(distribution, stacks, opts) {
25755
26033
  }
25756
26034
  for (const functionLogicalId of functionLogicalIds) try {
25757
26035
  const lambda = resolveLambdaTarget(`${distribution.stackName}:${functionLogicalId}`, stacks);
25758
- const containerEnv = await resolveLambdaContainerEnv(lambda, opts.envOptions, opts.profileCredentials, opts.extraStateProviders);
26036
+ const containerEnv = await resolveLambdaContainerEnv(lambda, lambdaEdgeEnvOptions(opts.envOptions), opts.profileCredentials, opts.extraStateProviders);
25759
26037
  const runner = createFrontDoorLambdaRunner(lambda, {
25760
26038
  containerHost: opts.containerHost,
25761
26039
  skipPull: opts.skipPull,
@@ -25782,9 +26060,15 @@ function buildLambdaEnvOptions(options, extraStateProviders) {
25782
26060
  ...options.assumeRole !== void 0 && { assumeRole: options.assumeRole },
25783
26061
  ...options.region !== void 0 && { region: options.region },
25784
26062
  ...options.profile !== void 0 && { profile: options.profile },
25785
- ...options.stackRegion !== void 0 && { stackRegion: options.stackRegion }
26063
+ ...options.stackRegion !== void 0 && { stackRegion: options.stackRegion },
26064
+ ...options.envVars !== void 0 && { envVars: options.envVars }
25786
26065
  };
25787
26066
  }
26067
+ function lambdaEdgeEnvOptions(envOptions) {
26068
+ const out = { ...envOptions };
26069
+ delete out.envVars;
26070
+ return out;
26071
+ }
25788
26072
  function buildLambdaBootOptions(options, profileCredentials, extraStateProviders) {
25789
26073
  return {
25790
26074
  containerHost: options.host,
@@ -25805,6 +26089,10 @@ function warnUnusedCacheOrigin(options, extraStateProviders) {
25805
26089
  getLogger().warn(`--cache-origin has no effect without ${flags}: it caches a deployed-S3 read-through origin, which is only built under a state source. A local BucketDeployment / --origin <id>=<dir> origin serves from disk and is not cached. Pass ${flags} to enable the deployed-S3 origin (then --cache-origin applies), or drop --cache-origin.`);
25806
26090
  }
25807
26091
  }
26092
+ function warnUnusedEnvVars(distribution, options) {
26093
+ if (options.envVars === void 0) return;
26094
+ if (![...distribution.origins.values()].some((o) => o.kind === "lambda-url" || o.kind === "web-function")) getLogger().warn("--env-vars has no effect: the distribution has no Lambda Function URL or Lambda Web Function endpoint origin (CloudFront Functions and Lambda@Edge take no environment variables).");
26095
+ }
25808
26096
  async function resolveDeployedS3Origins(distribution, stacks, options, profileCredentials, logger, extraStateProviders) {
25809
26097
  const readers = /* @__PURE__ */ new Map();
25810
26098
  const buckets = /* @__PURE__ */ new Map();
@@ -25919,6 +26207,7 @@ async function localStartCloudFrontCommand(target, options, extraStateProviders,
25919
26207
  const deployedS3 = await resolveDeployedS3Origins(initial.distribution, initial.stacks, options, profileCredentials, logger, extraStateProviders);
25920
26208
  warnUnsupported(initial.distribution, extraStateProviders);
25921
26209
  warnUnusedCacheOrigin(options, extraStateProviders);
26210
+ warnUnusedEnvVars(initial.distribution, options);
25922
26211
  await attachKvsModules(initial.distribution, initial.stacks, options, profileCredentials, logger, extraStateProviders);
25923
26212
  const bootOpts = buildLambdaBootOptions(options, profileCredentials, extraStateProviders);
25924
26213
  const webFunctionServes = [];
@@ -26042,7 +26331,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
26042
26331
  return cmd;
26043
26332
  }
26044
26333
  function addStartCloudFrontSpecificOptions(cmd) {
26045
- return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <key=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is a KeyValueStore handle — its AWS::CloudFront::KeyValueStore resource logical id, its construct path, or its bare construct id; the file is a flat { \"key\": \"value\" } object. The AWS-free alternative to --from-cfn-stack, which instead reads the deployed store via the GetKey API.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL / Web Function origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind to a deployed CloudFormation stack (ListStackResources). Resolves an S3 origin that has no local BucketDeployment source to its deployed bucket and serves it from real S3 on demand (the front/back-split case: files uploaded out of band), and resolves a Lambda Function URL / Lambda@Edge function's or a Web Function origin revision's env vars to the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs.")).addOption(new Option("--cache-origin", "For a deployed-S3 origin (served from real S3 under --from-cfn-stack): keep fetched objects in memory for the session instead of re-reading on every request. Faster repeat reads / fewer S3 GETs, but an out-of-band S3 content change is not reflected until a --watch reload (which clears the cache) or a restart. Off by default (every request re-reads, always current). Not CloudFront CDN caching.").default(false)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's (or a Web Function origin revision's) execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
26334
+ return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <key=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is a KeyValueStore handle — its AWS::CloudFront::KeyValueStore resource logical id, its construct path, or its bare construct id; the file is a flat { \"key\": \"value\" } object. The AWS-free alternative to --from-cfn-stack, which instead reads the deployed store via the GetKey API.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL / Web Function origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind to a deployed CloudFormation stack (ListStackResources). Resolves an S3 origin that has no local BucketDeployment source to its deployed bucket and serves it from real S3 on demand (the front/back-split case: files uploaded out of band), and resolves a Lambda Function URL / Lambda@Edge function's or a Web Function origin revision's env vars to the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs.")).addOption(new Option("--cache-origin", "For a deployed-S3 origin (served from real S3 under --from-cfn-stack): keep fetched objects in memory for the session instead of re-reading on every request. Faster repeat reads / fewer S3 GETs, but an out-of-band S3 content change is not reflected until a --watch reload (which clears the cache) or a restart. Off by default (every request re-reads, always current). Not CloudFront CDN caching.").default(false)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's (or a Web Function origin revision's) execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--env-vars <file>", "JSON env-var overrides for the Lambda Function URL and Lambda Web Function endpoint origins (SAM-compatible, the same file as the other commands: {\"Parameters\": {...}} for every origin, {\"<LogicalId or construct path>\": {\"KEY\": \"VALUE\"}} for one — the backing function, or the Web Function revision the endpoint serves; a null value removes the variable). Not applied to Lambda@Edge functions, which cannot carry environment variables in AWS.")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
26046
26335
  }
26047
26336
 
26048
26337
  //#endregion
@@ -28172,6 +28461,13 @@ const OPTION_SPECS = {
28172
28461
  leftPlaceholder: "listenerPort",
28173
28462
  rightPlaceholder: "hostPort"
28174
28463
  },
28464
+ {
28465
+ flag: "--assume-host",
28466
+ kind: "scalar",
28467
+ label: "Assume host",
28468
+ placeholder: "api.example.com",
28469
+ help: "Route and forward every request as if it carried this Host (host-header rules see it; the target receives it). <listenerPort>=<host> limits it to one listener. One value per run here; the CLI flag is repeatable."
28470
+ },
28175
28471
  {
28176
28472
  flag: "--bearer-token",
28177
28473
  kind: "scalar",
@@ -28332,6 +28628,15 @@ const OPTION_SPECS = {
28332
28628
  leftPlaceholder: "originId",
28333
28629
  rightPlaceholder: "./dist",
28334
28630
  help: "Point a distribution origin at a local directory when cdk-local can't resolve its BucketDeployment source."
28631
+ },
28632
+ {
28633
+ flag: "--env-vars",
28634
+ kind: "env-kv",
28635
+ label: "Env vars",
28636
+ sep: "=",
28637
+ leftPlaceholder: "KEY",
28638
+ rightPlaceholder: "value",
28639
+ help: "Overlay the Lambda Function URL / Web Function endpoint origin container env vars — add KEY=VALUE rows or paste a JSON object."
28335
28640
  }
28336
28641
  ]
28337
28642
  };
@@ -33295,4 +33600,4 @@ function addStudioSpecificOptions(cmd) {
33295
33600
 
33296
33601
  //#endregion
33297
33602
  export { postHook as $, deployedFillMayBeSecret as $a, parseConnectionsPath as $i, addImageOverrideOptions as $n, addStartApiSpecificOptions as $r, classifyS3Error as $t, microvmFidelityWarnings as A, discoverWebSocketApisOrThrow as Aa, applyCorsResponseHeaders as Ai, stripCloudFrontImport as An, A2A_CONTAINER_PORT as Ar, readContainerLogTail as At, MICROVM_WS_BASE_PROTOCOL as B, AGENTCORE_MCP_PROTOCOL as Ba, evaluateResponseParameters as Bi, createLocalStartAlbCommand as Bn, AGENTCORE_SESSION_ID_HEADER as Br, parseWebFunctionBuildConfig as Bt, addListSpecificOptions as C, resolveSsmParameters as Ca, verifyJwtViaDiscovery as Ci, WEB_FUNCTION_REVISION_TYPE as Cn, setShadowReadyTimeoutMs as Cr, parseKvsFileOverrides as Ct, buildMicrovmLambdaView as D, listTargets as Da, invokeRequestAuthorizer as Di, compileCloudFrontFunction as Dn, createLocalInvokeAgentCoreCommand as Dr, WEB_FUNCTION_CONTAINER_PORT as Dt, addStartMicrovmSpecificOptions as E, countTargets as Ea, evaluateCachedLambdaPolicy as Ei, resolveWebFunctionTarget as En, addInvokeAgentCoreSpecificOptions as Er, RecentOutput as Et, microvmImageTag as F, pickRefLogicalId as Fa, matchRoute as Fi, findFileAssetForObjectKey as Fn, MCP_PROTOCOL_VERSION as Fr, buildNodeEntryFileStart as Ft, startMicrovmFrontDoor as G, derivePseudoParametersFromRegion as Ga, HOST_DOCKER_INTERNAL_GATEWAY as Gi, addStartServiceSpecificOptions as Gn, SUPPORTED_CODE_RUNTIMES as Gr, readWebFunctionServiceConfig as Gt, PROXY_PORT_HEADER as H, AgentCoreResolutionError as Ha, selectIntegrationResponse as Hi, resolveAlbTarget as Hn, waitForAgentCoreHttpReady as Hr, WEB_FUNCTION_HTTP_ENDPOINT_ENV as Ht, planMicrovmPorts as I, resolveLambdaArnIntrinsic as Ia, translateLambdaResponse as Ii, isBucketDeploymentResource as In, mcpInvokeOnce as Ir, defaultWebFunctionPlatform as It, MICROVM_HOOK_PATH_PREFIX as J, tryResolveImageFnJoin as Ja, resolveHostGatewayExtraHosts as Ji, addRunTaskSpecificOptions as Jn, renderCodeDockerfile as Jr, idFromArn as Jt, stripMicrovmProxyHeaders as K, formatStateRemedy as Ka, HOST_GATEWAY_MIN_VERSION as Ki, createLocalStartServiceCommand as Kn, buildAgentCoreCodeImage as Kr, webFunctionAssumeRole as Kt, readExposedPorts as L, AGENTCORE_A2A_PROTOCOL as La, applyAuthorizerOverlay as Li, resolveBucketDeploymentObjectKey as Ln, parseSseForJsonRpc as Lr, resolveWebFunctionRuntime as Lt, DEFAULT_TERMINATE_HOOK_TIMEOUT_MS as M, parseSelectionExpressionPath as Ma, buildCorsConfigFromCloudFrontChain as Mi, createLocalFileKvsDataSource as Mn, a2aInvokeOnce as Mr, waitForWebFunctionReady as Mt, LocalMicrovm as N, webSocketApiMatchesIdentifier as Na, isFunctionUrlOacFronted as Ni, createUnboundCloudFrontModule as Nn, MCP_CONTAINER_PORT as Nr, watchContainerExit as Nt, createLocalStartMicrovmCommand as O, availableWebSocketApiIdentifiers as Oa, invokeTokenAuthorizer as Oi, runViewerRequest as On, bridgeAgentCoreWs as Or, containerFailure as Ot, buildMicrovmImage as P, discoverRoutes as Pa, matchPreflight as Pi, bucketDeploymentSourceObjectKeys as Pn, MCP_PATH as Pr, WEB_FUNCTION_RUNTIMES as Pt, pollBuildHook as Q, containsDynamicReference as Qa, handleConnectionsRequest as Qi, addEcsAssumeRoleOptions as Qn, createLocalInvokeCommand as Qr, resolveDeployedOriginBucket as Qt, setContainerPaused as R, AGENTCORE_AGUI_PROTOCOL as Ra, buildHttpApiV2Event as Ri, addAlbSpecificOptions as Rn, AGENTCORE_SIGV4_SERVICE as Rr, supportedWebFunctionRuntimes as Rt, StudioEventBus as S, collectSsmParameterRefs as Sa, verifyJwtAuthorizer as Si, WEB_FUNCTION_ENDPOINT_TYPE as Sn, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Sr, normalizeKvsFileKeys as St, formatTargetListing as T, resolveSingleTarget as Ta, computeRequestIdentityHash as Ti, WebFunctionResolutionError as Tn, attachContainerLogStreamer as Tr, resolveCloudFrontTarget as Tt, rewriteUpgradeResponseHead as U, pickAgentCoreCandidateStack as Ua, tryParseStatus as Ui, isApplicationLoadBalancer as Un, waitForAgentCorePing as Ur, buildWebFunctionLambdaView as Ut, MicrovmStateError as V, AGENTCORE_RUNTIME_TYPE as Va, pickResponseTemplate as Vi, parseLbPortOverrides as Vn, invokeAgentCore as Vr, resolveWebFunctionArtifact as Vt, selectTargetPort as W, resolveAgentCoreTarget as Wa, VtlEvaluationError as Wi, resolveAlbFrontDoor as Wn, downloadAndExtractS3Bundle as Wr, finalizeWebFunctionEnv as Wt, callRuntimeHook as X, DynamicReferenceResolutionError as Xa, ConnectionRegistry as Xi, MAX_TASKS_SUBNET_RANGE_CAP as Xn, classifySourceChange as Xr, createDeployedKvsDataSource as Xt, MicrovmHookError as Y, LocalInvokeBuildError as Ya, bufferToBody as Yi, createLocalRunTaskCommand as Yn, toCmdArgv as Yr, resolveKvsModulesForDistribution as Yt, generateMicrovmId as Z, DynamicReferenceResolver as Za, buildMgmtEndpointEnvUrl as Zi, addCommonEcsServiceOptions as Zn, addInvokeSpecificOptions as Zr, resolveDeployedKvsArnByName as Zt, filterStudioTargetGroups as _, rejectExplicitCfnStackWithMultipleStacks as _a, defaultCredentialsLoader as _i, pickKvsLogicalIdFromArn as _n, isProxyEnvConfigured as _o, isLocalCdkAssetImage as _r, attachAgentCoreWsBridge as _t, createLocalStudioCommand as a, resolveRuntimeCodeMountPath as aa, attachStageContext as ai, serveLambdaUrlOrigin as an, withoutKeys as ao, resolveSharedSidecarCredentials as ar, disposeMicrovmCodeArtifact as at, renderStudioHtml as b, resolveCfnStackName as ba, createJwksCache as bi, pickWebFunctionEndpointLogicalIdFromOrigin as bn, CloudMapRegistry as br, addStartCloudFrontSpecificOptions as bt, startStudioProxy as c, EcsTaskResolutionError as ca, resolveEnvVars$1 as ci, buildEdgeRequestEvent as cn, deployAccountStsClientConfig as co, buildImageOverrideTag as cr, resolveMicrovmImageTarget as ct, createStudioDispatcher as d, substituteAgainstStateAsync as da, filterRoutesByApiIdentifiers as di, httpHeadersToEdge as dn, resetWorkloadIdentity as do, mergeForService as dr, createLocalStartWebFunctionCommand as dt, buildConnectEvent as ea, createLocalStartApiCommand as ei, createS3OriginReader as en, firstUsableRegion as eo, buildEcsImageResolutionContext$1 as er, runHookBody as et, filterStudioCustomResources as f, substituteEnvVarsFromState as fa, groupRoutesByServer as fi, CLOUDFRONT_DISTRIBUTION_TYPE as fn, workloadClientConfig as fo, parseImageOverrideFlags as fr, addStartAgentCoreSpecificOptions as ft, annotatePinnedEcsTargets as g, isCfnFlagPresent as ga, resolveServiceIntegrationParameters as gi, pickFunctionUrlLogicalIdFromOrigin as gn, buildProxyClientConfig as go, imageOverrideKeyAliases as gr, startAgentCoreHttpServer as gt, annotateEcsTaskPinnedTargets as h, createLocalStateProvider as ha, resolveSelectionExpression as hi, isCloudFrontDistribution as hn, resolveProfileCredentials as ho, describePinnedImageUri as hr, selectServeInboundAuth as ht, coerceStopRequest as i, buildContainerImage as ia, createFileWatcher as ii, serveFromStaticOrigin as in, resolveDynamicReferencesInEnv as io, resolveEcsAssumeRoleOption as ir, MicrovmResolutionError as it, readRunHookPayload as j, filterWebSocketApisByIdentifiers as ja, buildCorsConfigByApiId as ji, createCloudFrontModule as jn, A2A_PATH as jr, startWebFunctionContainer as jt, finalizeMicrovmEnv as k, discoverWebSocketApis as ka, attachAuthorizers as ki, runViewerResponse as kn, invokeAgentCoreWs as kr, planWebFunctionContainer as kt, relayServeRequest as l, assertEcsTaskImagesResolvable as la, availableApiIdentifiers as li, buildEdgeResponseEvent as ln, readEnvCallerCredentials as lo, canonicalizeImageOverrideKeys as lr, s3KeyOfUri as lt, annotateAlbPinnedBackingServices as m, LocalStateSourceError as ma, startApiServer as mi, extractKvsAssociations as mn, buildStsClientConfig as mo, runImageOverrideBuilds as mr, buildAgentCoreServeAuthCheck as mt, coerceRunRequest as n, buildMessageEvent as na, resolveApiTargetSubset as ni, startCloudFrontServer as nn, keysOverriddenBy as no, parseMaxTasks as nr, MICROVM_DEFAULT_INGRESS_PORT as nt, resolveServeBaseUrl as o, resolveRuntimeFileExtension as oa, buildStageMap as oi, applyEdgeRequestResult as on, SECOND_ASSUME_MESSAGE as oo, runEcsServiceEmulator as or, readMicrovmImageConfig as ot, isCustomResourceLambdaTarget as p, substituteEnvVarsFromStateAsync as pa, readMtlsMaterialsFromDisk as pi, describeS3OriginDomain as pn, workloadStsClientConfig as po, resolveImageOverrides as pr, createLocalStartAgentCoreCommand as pt, MAX_RUN_HOOK_PAYLOAD_BYTES as q, substituteImagePlaceholders as qa, probeHostGatewaySupport as qi, serviceStrategy as qn, computeCodeImageTag as qr, webFunctionFidelityWarnings as qt, coerceServeRequest as r, architectureToPlatform as ra, createAuthorizerCache as ri, resolveErrorResponseCandidates as rn, parseDynamicReference as ro, parseRestartPolicy as rr, MICROVM_IMAGE_TYPE as rt, createStudioServeManager as s, resolveRuntimeImage as sa, materializeLayerFromArn as si, applyEdgeResponseResult as sn, assumedRoleRecorded as so, ImageOverrideError as sr, resolveMicrovmCodeArtifact as st, addStudioSpecificOptions as t, buildDisconnectEvent as ta, createWatchPredicates as ti, matchBehavior as tn, keysNotFromTemplate as to, ecsClusterOption as tr, waitForAppAnswer as tt, reinvoke as u, substituteAgainstState as ua, filterRoutesByApiIdentifier as ui, edgeHeadersToHttp as un, recordAssumedRole as uo, enforceImageOverrideOrphans as ur, addStartWebFunctionSpecificOptions as ut, startStudioServer as v, resolveCfnFallbackRegion as va, buildCognitoJwksUrl as vi, pickLambdaEdgeFunctionLogicalId as vn, listPinnedTargets as vr, startAgentCoreWsBridge as vt, createLocalListCommand as w, resolveWatchConfig as wa, buildMethodArn as wi, WEB_FUNCTION_TYPE as wn, getContainerNetworkIp as wr, parseOriginOverrides as wt, createStudioStore as x, CfnLocalStateProvider as xa, verifyCognitoJwt as xi, resolveCloudFrontDistribution as xn, DEFAULT_SHADOW_READY_TIMEOUT_MS as xr, createLocalStartCloudFrontCommand as xt, toStudioTargetGroups as y, resolveCfnRegion as ya, buildJwksUrlFromIssuer as yi, pickTargetFunctionLogicalId as yn, buildCloudMapIndex as yr, LocalStartCloudFrontError as yt, MICROVM_CONTROL_PATH as z, AGENTCORE_HTTP_PROTOCOL as za, buildRestV1Event as zi, albStrategy as zn, signAgentCoreInvocation as zr, disposeWebFunctionArtifact as zt };
33298
- //# sourceMappingURL=local-studio-D2McUMmL.js.map
33603
+ //# sourceMappingURL=local-studio-Ur6enHho.js.map