cdk-local 0.119.0 → 0.121.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.
@@ -18100,7 +18100,7 @@ function computeCodeImageTag(sourceDir, runtime, entryPoint, dockerfile) {
18100
18100
  async function downloadAndExtractS3Bundle(location, options = {}) {
18101
18101
  const ref = formatRef(location);
18102
18102
  getLogger().info(`Downloading fromS3 code bundle ${ref}...`);
18103
- const bytes = await (options.fetchObject ?? defaultFetchObject(options))(location);
18103
+ const bytes = await (options.fetchObject ?? defaultFetchObject$1(options))(location);
18104
18104
  let files;
18105
18105
  try {
18106
18106
  files = unzipSync(bytes);
@@ -18147,7 +18147,7 @@ function resolveSafeEntryPath(root, entry) {
18147
18147
  if (dest !== root && !dest.startsWith(rootWithSep)) throw new CdkLocalError(`Refusing to extract a fromS3 bundle entry that escapes the target dir: '${entry}'.`, "LOCAL_INVOKE_AGENTCORE_S3_BUNDLE_ZIP_SLIP");
18148
18148
  return dest;
18149
18149
  }
18150
- function defaultFetchObject(options) {
18150
+ function defaultFetchObject$1(options) {
18151
18151
  return async (location) => {
18152
18152
  const { S3Client, GetObjectCommand } = await import("@aws-sdk/client-s3");
18153
18153
  const client = new S3Client({
@@ -23890,7 +23890,7 @@ function writeRawHttpError(socket, statusCode, message) {
23890
23890
  if (socket.destroyed) return;
23891
23891
  const body = `${message}\n`;
23892
23892
  const lines = [
23893
- `HTTP/1.1 ${statusCode} ${STATUS_TEXT[statusCode] ?? "Error"}`,
23893
+ `HTTP/1.1 ${statusCode} ${STATUS_TEXT$1[statusCode] ?? "Error"}`,
23894
23894
  "content-type: text/plain; charset=utf-8",
23895
23895
  `content-length: ${Buffer.byteLength(body)}`,
23896
23896
  "connection: close",
@@ -23943,7 +23943,7 @@ function writeRawHttpRedirect(socket, action, req, listenerPort, scheme) {
23943
23943
  function writeRawHttpFixedResponse(socket, action) {
23944
23944
  if (socket.destroyed) return;
23945
23945
  const body = action.messageBody ?? "";
23946
- const statusText = STATUS_TEXT[action.statusCode] ?? "";
23946
+ const statusText = STATUS_TEXT$1[action.statusCode] ?? "";
23947
23947
  const contentType = sanitizeRawHeaderValue(action.contentType ?? "text/plain; charset=utf-8");
23948
23948
  const lines = [
23949
23949
  `HTTP/1.1 ${action.statusCode} ${statusText}`,
@@ -23963,7 +23963,7 @@ function sanitizeRawHeaderValue(value) {
23963
23963
  return value.replace(/[\r\n]/g, " ");
23964
23964
  }
23965
23965
  /** Minimal HTTP/1.1 status text map for the codes the raw writers emit. */
23966
- const STATUS_TEXT = {
23966
+ const STATUS_TEXT$1 = {
23967
23967
  301: "Moved Permanently",
23968
23968
  302: "Found",
23969
23969
  401: "Unauthorized",
@@ -28402,6 +28402,15 @@ function buildViewerResponseEvent(requestEvent, response) {
28402
28402
  }
28403
28403
  };
28404
28404
  }
28405
+ /** Serialize a CloudFront request's `querystring` object back to a raw string. */
28406
+ function serializeCfQueryString(qs) {
28407
+ const parts = [];
28408
+ for (const [key, val] of Object.entries(qs)) {
28409
+ const values = val.multiValue && val.multiValue.length > 0 ? val.multiValue : [{ value: val.value }];
28410
+ for (const v of values) parts.push(v.value === "" ? encodeURIComponent(key) : `${encodeURIComponent(key)}=${encodeURIComponent(v.value)}`);
28411
+ }
28412
+ return parts.join("&");
28413
+ }
28405
28414
  function parseQueryStringToCf(raw) {
28406
28415
  const out = {};
28407
28416
  if (!raw) return out;
@@ -28460,6 +28469,7 @@ const CLOUDFRONT_FUNCTION_TYPE = "AWS::CloudFront::Function";
28460
28469
  const S3_BUCKET_TYPE = "AWS::S3::Bucket";
28461
28470
  const LAMBDA_URL_TYPE = "AWS::Lambda::Url";
28462
28471
  const LAMBDA_FUNCTION_TYPE = "AWS::Lambda::Function";
28472
+ const LAMBDA_VERSION_TYPE = "AWS::Lambda::Version";
28463
28473
  /**
28464
28474
  * Resolve a distribution logical id within a stack into its routing model.
28465
28475
  * `originOverrides` maps an origin id to a local directory (the `--origin`
@@ -28565,10 +28575,9 @@ function resolveBehaviors(dc, functions, distLogicalId, template) {
28565
28575
  return behaviors;
28566
28576
  }
28567
28577
  function resolveBehavior(behavior, pathPattern, functions, distLogicalId, template) {
28568
- const resolved = {
28569
- targetOriginId: typeof behavior["TargetOriginId"] === "string" ? behavior["TargetOriginId"] : "",
28570
- hasLambdaEdge: Array.isArray(behavior["LambdaFunctionAssociations"]) ? behavior["LambdaFunctionAssociations"].length > 0 : false
28571
- };
28578
+ const resolved = { targetOriginId: typeof behavior["TargetOriginId"] === "string" ? behavior["TargetOriginId"] : "" };
28579
+ const lambdaEdge = resolveLambdaEdgeAssociations(behavior, template, distLogicalId);
28580
+ if (lambdaEdge) resolved.lambdaEdge = lambdaEdge;
28572
28581
  if (pathPattern !== void 0) resolved.pathPattern = pathPattern;
28573
28582
  const cors = resolveResponseHeadersPolicyCors(template, behavior["ResponseHeadersPolicyId"]);
28574
28583
  if (cors) resolved.cors = cors;
@@ -28600,6 +28609,55 @@ function pickFunctionLogicalIdFromArn(value) {
28600
28609
  const getAtt = value["Fn::GetAtt"];
28601
28610
  if (Array.isArray(getAtt) && getAtt.length === 2 && typeof getAtt[0] === "string") return getAtt[0];
28602
28611
  }
28612
+ /**
28613
+ * Resolve a behavior's `LambdaFunctionAssociations[]` into the per-event-type
28614
+ * backing-function map (issue #400). Each association names a
28615
+ * `LambdaFunctionARN` (a versioned ARN) + an `EventType` + `IncludeBody`.
28616
+ */
28617
+ function resolveLambdaEdgeAssociations(behavior, template, distLogicalId) {
28618
+ const assocs = Array.isArray(behavior["LambdaFunctionAssociations"]) ? behavior["LambdaFunctionAssociations"] : [];
28619
+ const out = {};
28620
+ for (const a of assocs) {
28621
+ if (!a || typeof a !== "object") continue;
28622
+ const assoc = a;
28623
+ const eventType = assoc["EventType"];
28624
+ const functionLogicalId = pickLambdaEdgeFunctionLogicalId(assoc["LambdaFunctionARN"], template);
28625
+ if (!functionLogicalId) {
28626
+ getLogger().warn(`Distribution '${distLogicalId}': a Lambda@Edge association references a LambdaFunctionARN cdk-local could not resolve to a local AWS::Lambda::Function; it will not run.`);
28627
+ continue;
28628
+ }
28629
+ const entry = {
28630
+ functionLogicalId,
28631
+ includeBody: assoc["IncludeBody"] === true
28632
+ };
28633
+ if (eventType === "viewer-request") out.viewerRequest = entry;
28634
+ else if (eventType === "origin-request") out.originRequest = entry;
28635
+ else if (eventType === "origin-response") out.originResponse = entry;
28636
+ else if (eventType === "viewer-response") out.viewerResponse = entry;
28637
+ }
28638
+ return Object.keys(out).length > 0 ? out : void 0;
28639
+ }
28640
+ /**
28641
+ * Resolve a `LambdaFunctionARN` (a versioned function ARN) to the backing
28642
+ * `AWS::Lambda::Function` logical id. CDK wires the association to a
28643
+ * `lambda.Version` (`{Ref: <Version>}` returns the qualified ARN), whose
28644
+ * `FunctionName` references the function. A direct (unqualified) function ref
28645
+ * is also accepted. Returns `undefined` when it cannot reach an
28646
+ * `AWS::Lambda::Function` (e.g. an imported cross-region EdgeFunction ARN).
28647
+ */
28648
+ function pickLambdaEdgeFunctionLogicalId(value, template) {
28649
+ const candidate = refLogicalId(value) ?? getAttLogicalId(value);
28650
+ if (!candidate) return void 0;
28651
+ const resources = template.Resources ?? {};
28652
+ const resource = resources[candidate];
28653
+ if (!resource) return void 0;
28654
+ if (resource.Type === LAMBDA_FUNCTION_TYPE) return candidate;
28655
+ if (resource.Type === LAMBDA_VERSION_TYPE) {
28656
+ const fnName = (resource.Properties ?? {})["FunctionName"];
28657
+ const fnId = refLogicalId(fnName) ?? getAttLogicalId(fnName);
28658
+ if (fnId && resources[fnId]?.Type === LAMBDA_FUNCTION_TYPE) return fnId;
28659
+ }
28660
+ }
28603
28661
  function resolveOrigins(dc, template, stack, overrides) {
28604
28662
  const out = /* @__PURE__ */ new Map();
28605
28663
  const origins = Array.isArray(dc["Origins"]) ? dc["Origins"] : [];
@@ -28799,6 +28857,261 @@ function isCloudFrontDistribution(resource) {
28799
28857
  return resource.Type === CLOUDFRONT_DISTRIBUTION_TYPE;
28800
28858
  }
28801
28859
 
28860
+ //#endregion
28861
+ //#region src/local/cloudfront-edge-event.ts
28862
+ /** Convert a normalized HTTP header map into the Lambda@Edge multi-map. */
28863
+ function httpHeadersToEdge(headers) {
28864
+ const out = {};
28865
+ for (const [name, values] of Object.entries(headers)) {
28866
+ const lower = name.toLowerCase();
28867
+ out[lower] = values.map((value) => ({
28868
+ key: name,
28869
+ value
28870
+ }));
28871
+ }
28872
+ return out;
28873
+ }
28874
+ /**
28875
+ * Flatten a Lambda@Edge header multi-map into a single-valued `{ name: value }`
28876
+ * map (comma-joining duplicates), EXCEPT `set-cookie`, whose values are returned
28877
+ * separately so multiple cookies survive. Pseudo / read-only headers CloudFront
28878
+ * forbids a function from setting are dropped.
28879
+ */
28880
+ function edgeHeadersToHttp(headers) {
28881
+ const out = {};
28882
+ const setCookies = [];
28883
+ for (const [name, entries] of Object.entries(headers)) {
28884
+ if (!Array.isArray(entries)) continue;
28885
+ const lower = name.toLowerCase();
28886
+ if (READ_ONLY_RESPONSE_HEADERS.has(lower)) continue;
28887
+ if (lower === "set-cookie") {
28888
+ for (const e of entries) if (e && typeof e.value === "string") setCookies.push(e.value);
28889
+ continue;
28890
+ }
28891
+ const values = entries.filter((e) => e && typeof e.value === "string").map((e) => e.value);
28892
+ if (values.length > 0) out[lower] = values.join(", ");
28893
+ }
28894
+ return {
28895
+ headers: out,
28896
+ setCookies
28897
+ };
28898
+ }
28899
+ /**
28900
+ * Headers a Lambda@Edge function is not allowed to add/modify on a response (a
28901
+ * subset CloudFront blackholes). We drop them rather than fail the response.
28902
+ */
28903
+ const READ_ONLY_RESPONSE_HEADERS = new Set([
28904
+ "connection",
28905
+ "content-length",
28906
+ "keep-alive",
28907
+ "proxy-authenticate",
28908
+ "proxy-authorization",
28909
+ "te",
28910
+ "trailer",
28911
+ "transfer-encoding",
28912
+ "upgrade"
28913
+ ]);
28914
+ /** Build the request-stage event (`viewer-request` / `origin-request`). */
28915
+ function buildEdgeRequestEvent(args) {
28916
+ return { Records: [{ cf: {
28917
+ config: {
28918
+ ...args.config,
28919
+ eventType: args.eventType
28920
+ },
28921
+ request: toEdgeRequest(args.request, args.includeBody)
28922
+ } }] };
28923
+ }
28924
+ /** Build the response-stage event (`origin-response` / `viewer-response`). */
28925
+ function buildEdgeResponseEvent(args) {
28926
+ return { Records: [{ cf: {
28927
+ config: {
28928
+ ...args.config,
28929
+ eventType: args.eventType
28930
+ },
28931
+ request: toEdgeRequest(args.request, false),
28932
+ response: {
28933
+ status: String(args.response.statusCode),
28934
+ statusDescription: statusText(args.response.statusCode),
28935
+ headers: httpHeadersToEdge(toMultiMap(args.response.headers))
28936
+ }
28937
+ } }] };
28938
+ }
28939
+ function toEdgeRequest(input, includeBody) {
28940
+ const request = {
28941
+ clientIp: input.clientIp,
28942
+ method: input.method,
28943
+ uri: input.uri,
28944
+ querystring: input.querystring,
28945
+ headers: httpHeadersToEdge(input.headers)
28946
+ };
28947
+ if (includeBody) request.body = {
28948
+ action: "read-only",
28949
+ data: (input.body ?? Buffer.alloc(0)).toString("base64"),
28950
+ encoding: "base64",
28951
+ inputTruncated: false
28952
+ };
28953
+ return request;
28954
+ }
28955
+ function interpretEdgeRequestResult(result, fallback) {
28956
+ if (!result || typeof result !== "object") return {
28957
+ kind: "continue",
28958
+ request: fallback
28959
+ };
28960
+ const obj = result;
28961
+ if ("status" in obj) return {
28962
+ kind: "response",
28963
+ response: coerceEdgeResponse(obj)
28964
+ };
28965
+ return {
28966
+ kind: "continue",
28967
+ request: coerceEdgeRequest(obj, fallback)
28968
+ };
28969
+ }
28970
+ /** Interpret a response-stage handler's return value as the (modified) response. */
28971
+ function interpretEdgeResponseResult(result, fallback) {
28972
+ if (!result || typeof result !== "object") return fallback;
28973
+ return coerceEdgeResponse(result, fallback);
28974
+ }
28975
+ /** Collapse an {@link EdgeResponse} into the server's status / headers / body. */
28976
+ function edgeResponseToResult(response, fallbackBody) {
28977
+ const statusCode = Number.parseInt(response.status, 10);
28978
+ const { headers, setCookies } = edgeHeadersToHttp(response.headers ?? {});
28979
+ let body;
28980
+ if (response.body !== void 0) body = response.bodyEncoding === "base64" ? Buffer.from(response.body, "base64") : Buffer.from(response.body);
28981
+ else body = fallbackBody ?? Buffer.alloc(0);
28982
+ return {
28983
+ statusCode: Number.isFinite(statusCode) ? statusCode : 500,
28984
+ headers,
28985
+ setCookies,
28986
+ body
28987
+ };
28988
+ }
28989
+ /**
28990
+ * Server-facing request-stage orchestration: given a handler's raw return value
28991
+ * and the current request input, produce either the (modified) request to
28992
+ * continue with, or the generated response to short-circuit.
28993
+ */
28994
+ function applyEdgeRequestResult(result, base) {
28995
+ const outcome = interpretEdgeRequestResult(result, toEdgeRequest(base, false));
28996
+ if (outcome.kind === "response") return {
28997
+ kind: "response",
28998
+ response: edgeResponseToResult(outcome.response)
28999
+ };
29000
+ return {
29001
+ kind: "continue",
29002
+ request: applyEdgeRequest(base, outcome.request)
29003
+ };
29004
+ }
29005
+ /**
29006
+ * Server-facing response-stage orchestration: apply a handler's modified
29007
+ * response over the current status / headers, keeping the origin body unless the
29008
+ * function replaced it.
29009
+ */
29010
+ function applyEdgeResponseResult(result, base, originBody) {
29011
+ return edgeResponseToResult(interpretEdgeResponseResult(result, {
29012
+ status: String(base.statusCode),
29013
+ headers: httpHeadersToEdge(toMultiMap(base.headers))
29014
+ }), originBody);
29015
+ }
29016
+ /** Apply a request-stage function's modified request back onto the server's request input. */
29017
+ function applyEdgeRequest(base, request) {
29018
+ const out = {
29019
+ clientIp: base.clientIp,
29020
+ method: typeof request.method === "string" ? request.method : base.method,
29021
+ uri: typeof request.uri === "string" ? request.uri : base.uri,
29022
+ querystring: typeof request.querystring === "string" ? request.querystring : base.querystring,
29023
+ headers: edgeHeadersToRawMap(request.headers) ?? base.headers
29024
+ };
29025
+ if (request.body && request.body.action === "replace" && typeof request.body.data === "string") out.body = request.body.encoding === "base64" ? Buffer.from(request.body.data, "base64") : Buffer.from(request.body.data);
29026
+ else if (base.body !== void 0) out.body = base.body;
29027
+ return out;
29028
+ }
29029
+ function edgeHeadersToRawMap(headers) {
29030
+ if (!headers || typeof headers !== "object") return void 0;
29031
+ const out = {};
29032
+ for (const [name, entries] of Object.entries(headers)) {
29033
+ if (!Array.isArray(entries)) continue;
29034
+ out[name.toLowerCase()] = entries.filter((e) => e && typeof e.value === "string").map((e) => e.value);
29035
+ }
29036
+ return out;
29037
+ }
29038
+ function coerceEdgeRequest(obj, fallback) {
29039
+ const out = {
29040
+ clientIp: typeof obj["clientIp"] === "string" ? obj["clientIp"] : fallback.clientIp,
29041
+ method: typeof obj["method"] === "string" ? obj["method"] : fallback.method,
29042
+ uri: typeof obj["uri"] === "string" ? obj["uri"] : fallback.uri,
29043
+ querystring: typeof obj["querystring"] === "string" ? obj["querystring"] : fallback.querystring,
29044
+ headers: coerceEdgeHeaders(obj["headers"]) ?? fallback.headers
29045
+ };
29046
+ const body = obj["body"];
29047
+ if (body && typeof body === "object") {
29048
+ const b = body;
29049
+ out.body = {
29050
+ action: b["action"] === "replace" ? "replace" : "read-only",
29051
+ data: typeof b["data"] === "string" ? b["data"] : "",
29052
+ encoding: b["encoding"] === "text" ? "text" : "base64",
29053
+ inputTruncated: b["inputTruncated"] === true
29054
+ };
29055
+ }
29056
+ return out;
29057
+ }
29058
+ function coerceEdgeResponse(obj, fallback) {
29059
+ const out = {
29060
+ status: typeof obj["status"] === "string" ? obj["status"] : typeof obj["status"] === "number" ? String(obj["status"]) : fallback?.status ?? "200",
29061
+ headers: coerceEdgeHeaders(obj["headers"]) ?? fallback?.headers ?? {}
29062
+ };
29063
+ if (typeof obj["statusDescription"] === "string") out.statusDescription = obj["statusDescription"];
29064
+ else if (fallback?.statusDescription !== void 0) out.statusDescription = fallback.statusDescription;
29065
+ if (typeof obj["body"] === "string") {
29066
+ out.body = obj["body"];
29067
+ if (obj["bodyEncoding"] === "base64" || obj["bodyEncoding"] === "text") out.bodyEncoding = obj["bodyEncoding"];
29068
+ }
29069
+ return out;
29070
+ }
29071
+ /** Coerce an arbitrary value into the EdgeHeaders shape, tolerating a bare `{name: 'value'}` map. */
29072
+ function coerceEdgeHeaders(value) {
29073
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
29074
+ const out = {};
29075
+ for (const [name, raw] of Object.entries(value)) {
29076
+ const lower = name.toLowerCase();
29077
+ if (Array.isArray(raw)) out[lower] = raw.filter((e) => !!e && typeof e === "object").map((e) => ({
29078
+ key: typeof e["key"] === "string" ? e["key"] : name,
29079
+ value: typeof e["value"] === "string" ? e["value"] : String(e["value"] ?? "")
29080
+ }));
29081
+ else if (typeof raw === "string") out[lower] = [{
29082
+ key: name,
29083
+ value: raw
29084
+ }];
29085
+ }
29086
+ return out;
29087
+ }
29088
+ function toMultiMap(headers) {
29089
+ const out = {};
29090
+ for (const [name, value] of Object.entries(headers)) out[name] = [value];
29091
+ return out;
29092
+ }
29093
+ function statusText(code) {
29094
+ return STATUS_TEXT[code] ?? "";
29095
+ }
29096
+ const STATUS_TEXT = {
29097
+ 200: "OK",
29098
+ 201: "Created",
29099
+ 204: "No Content",
29100
+ 301: "Moved Permanently",
29101
+ 302: "Found",
29102
+ 303: "See Other",
29103
+ 304: "Not Modified",
29104
+ 307: "Temporary Redirect",
29105
+ 308: "Permanent Redirect",
29106
+ 400: "Bad Request",
29107
+ 401: "Unauthorized",
29108
+ 403: "Forbidden",
29109
+ 404: "Not Found",
29110
+ 500: "Internal Server Error",
29111
+ 502: "Bad Gateway",
29112
+ 503: "Service Unavailable"
29113
+ };
29114
+
28802
29115
  //#endregion
28803
29116
  //#region src/local/cloudfront-lambda-origin.ts
28804
29117
  /**
@@ -28869,15 +29182,11 @@ function serveFromStaticOrigin(input) {
28869
29182
  headers: { "content-type": contentTypeForKey(key) },
28870
29183
  body: direct
28871
29184
  };
28872
- const errorResponses = input.customErrorResponses ?? [];
28873
- for (const code of [403, 404]) {
28874
- const match = errorResponses.find((e) => e.errorCode === code);
28875
- if (!match || !match.responsePagePath) continue;
28876
- const errorKey = stripLeadingSlash(match.responsePagePath);
28877
- const body = readKey(input.localDirs, errorKey);
29185
+ for (const candidate of resolveErrorResponseCandidates(input.customErrorResponses)) {
29186
+ const body = readKey(input.localDirs, candidate.errorKey);
28878
29187
  if (body) return {
28879
- statusCode: match.responseCode ?? code,
28880
- headers: { "content-type": contentTypeForKey(errorKey) },
29188
+ statusCode: candidate.responseCode,
29189
+ headers: { "content-type": contentTypeForKey(candidate.errorKey) },
28881
29190
  body
28882
29191
  };
28883
29192
  }
@@ -28888,6 +29197,27 @@ function serveFromStaticOrigin(input) {
28888
29197
  };
28889
29198
  }
28890
29199
  /**
29200
+ * Resolve the ordered list of custom-error-page candidates to try when an
29201
+ * origin object is missing/forbidden, shared by the local-dir static origin and
29202
+ * the deployed-S3 read-through origin so the 403-then-404 priority + the
29203
+ * `ResponseCode` mapping live in ONE place. We try 403 first then 404 because a
29204
+ * missing key on an OAC-fronted private bucket returns 403 AccessDenied (the
29205
+ * common static-site setup), but an app that mapped 404 instead is also honored.
29206
+ */
29207
+ function resolveErrorResponseCandidates(customErrorResponses) {
29208
+ const errorResponses = customErrorResponses ?? [];
29209
+ const out = [];
29210
+ for (const code of [403, 404]) {
29211
+ const match = errorResponses.find((e) => e.errorCode === code);
29212
+ if (!match || !match.responsePagePath) continue;
29213
+ out.push({
29214
+ errorKey: stripLeadingSlash(match.responsePagePath),
29215
+ responseCode: match.responseCode ?? code
29216
+ });
29217
+ }
29218
+ return out;
29219
+ }
29220
+ /**
28891
29221
  * Map a request URI to an S3 object key. The query string / fragment is
28892
29222
  * dropped, the leading slash is removed, and the root path (`/` or empty)
28893
29223
  * resolves to the default root object. A URI ending in `/` is NOT auto-indexed
@@ -28983,9 +29313,11 @@ function contentTypeForKey(key) {
28983
29313
  async function startCloudFrontServer(options) {
28984
29314
  const logger = getLogger().child("cloudfront");
28985
29315
  const lambdaInvokers = options.lambdaInvokers ?? /* @__PURE__ */ new Map();
29316
+ const edgeInvokers = options.edgeInvokers ?? /* @__PURE__ */ new Map();
29317
+ const s3OriginReaders = options.s3OriginReaders ?? /* @__PURE__ */ new Map();
28986
29318
  const state = { distribution: options.distribution };
28987
29319
  const handler = (req, res) => {
28988
- handleRequest$1(req, res, state, lambdaInvokers, logger).catch((err) => {
29320
+ handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger).catch((err) => {
28989
29321
  logger.warn(`Request handling failed: ${err instanceof Error ? err.message : String(err)}`);
28990
29322
  if (!res.headersSent) {
28991
29323
  res.statusCode = 500;
@@ -29015,7 +29347,7 @@ async function startCloudFrontServer(options) {
29015
29347
  };
29016
29348
  }
29017
29349
  /** The per-request pipeline: behavior match -> viewer-request -> origin -> viewer-response. */
29018
- async function handleRequest$1(req, res, state, lambdaInvokers, logger) {
29350
+ async function handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger) {
29019
29351
  const distribution = state.distribution;
29020
29352
  const rawUrl = req.url ?? "/";
29021
29353
  const queryIdx = rawUrl.indexOf("?");
@@ -29038,54 +29370,121 @@ async function handleRequest$1(req, res, state, lambdaInvokers, logger) {
29038
29370
  return;
29039
29371
  }
29040
29372
  }
29373
+ const config = {
29374
+ distributionDomainName: req.headers.host ?? "localhost",
29375
+ distributionId: distribution.logicalId,
29376
+ requestId: `cdkl-${Date.now().toString(36)}-${Math.floor(performance.now()).toString(36)}`
29377
+ };
29378
+ const clientIp = req.socket.remoteAddress ?? "127.0.0.1";
29041
29379
  let requestEvent = buildViewerRequestEvent({
29042
29380
  method: req.method ?? "GET",
29043
29381
  uri,
29044
29382
  querystring,
29045
29383
  headers: req.headers,
29046
- ip: req.socket.remoteAddress ?? "127.0.0.1",
29384
+ ip: clientIp,
29047
29385
  distributionId: distribution.logicalId,
29048
29386
  domainName: req.headers.host ?? "localhost",
29049
- requestId: `cdkl-${Date.now().toString(36)}-${Math.floor(performance.now()).toString(36)}`
29387
+ requestId: config.requestId
29050
29388
  });
29051
- let effectiveUri = uri;
29052
29389
  if (behavior.viewerRequest) {
29053
29390
  const outcome = await runViewerRequest(behavior.viewerRequest, requestEvent);
29054
29391
  if (outcome.kind === "response") {
29055
29392
  writeCfResponse(res, outcome.response, logger);
29056
29393
  return;
29057
29394
  }
29058
- effectiveUri = outcome.request.uri;
29059
29395
  requestEvent = {
29060
29396
  ...requestEvent,
29061
29397
  request: outcome.request
29062
29398
  };
29063
29399
  }
29400
+ let edgeInput = {
29401
+ clientIp,
29402
+ method: requestEvent.request.method,
29403
+ uri: requestEvent.request.uri,
29404
+ querystring: serializeCfQueryString(requestEvent.request.querystring),
29405
+ headers: cfHeadersToRawMap(requestEvent.request.headers)
29406
+ };
29407
+ for (const eventType of ["viewer-request", "origin-request"]) {
29408
+ const assoc = eventType === "viewer-request" ? behavior.lambdaEdge?.viewerRequest : behavior.lambdaEdge?.originRequest;
29409
+ if (!assoc) continue;
29410
+ const invoke = edgeInvokers.get(assoc.functionLogicalId);
29411
+ if (!invoke) {
29412
+ logger.warn(`Lambda@Edge ${eventType} function '${assoc.functionLogicalId}' was not booted (added after start-up); skipping. Restart start-cloudfront.`);
29413
+ continue;
29414
+ }
29415
+ if (assoc.includeBody && edgeInput.body === void 0) edgeInput = {
29416
+ ...edgeInput,
29417
+ body: await readRequestBody(req)
29418
+ };
29419
+ const outcome = applyEdgeRequestResult(await invoke(buildEdgeRequestEvent({
29420
+ eventType,
29421
+ config,
29422
+ request: edgeInput,
29423
+ includeBody: assoc.includeBody
29424
+ })), edgeInput);
29425
+ if (outcome.kind === "response") {
29426
+ writeEdgeResponse(res, outcome.response, behavior, req, logger);
29427
+ return;
29428
+ }
29429
+ edgeInput = outcome.request;
29430
+ }
29064
29431
  const origin = distribution.origins.get(behavior.targetOriginId);
29065
- const originResult = await serveFromOrigin(origin, behavior, {
29066
- uri: effectiveUri,
29067
- querystring,
29068
- method: req.method ?? "GET",
29069
- headers: req.headers,
29070
- readBody: () => readRequestBody(req),
29071
- sourceIp: req.socket.remoteAddress ?? "127.0.0.1",
29432
+ const originResult = await serveFromOrigin(origin, {
29433
+ uri: edgeInput.uri,
29434
+ querystring: edgeInput.querystring,
29435
+ method: edgeInput.method,
29436
+ headers: rawMapToIncomingHeaders(edgeInput.headers),
29437
+ readBody: () => edgeInput.body !== void 0 ? Promise.resolve(edgeInput.body) : readRequestBody(req),
29438
+ sourceIp: clientIp,
29072
29439
  distribution,
29073
29440
  lambdaInvokers,
29441
+ s3OriginReaders,
29074
29442
  logger
29075
29443
  });
29076
29444
  if (!originResult) return writePlain(res, 502, originUnavailableMessage(origin, behavior));
29077
29445
  let finalStatus = originResult.statusCode;
29078
29446
  let finalHeaders = originResult.headers;
29447
+ let finalBody = originResult.body;
29448
+ const setCookies = [...originResult.setCookies ?? []];
29449
+ if (behavior.lambdaEdge?.originResponse) {
29450
+ const r = await runEdgeResponseStage(behavior.lambdaEdge.originResponse, "origin-response", {
29451
+ config,
29452
+ request: edgeInput,
29453
+ statusCode: finalStatus,
29454
+ headers: finalHeaders,
29455
+ body: finalBody
29456
+ }, edgeInvokers, logger);
29457
+ if (r) {
29458
+ finalStatus = r.statusCode;
29459
+ finalHeaders = r.headers;
29460
+ finalBody = r.body;
29461
+ setCookies.push(...r.setCookies);
29462
+ }
29463
+ }
29079
29464
  if (behavior.viewerResponse) {
29080
29465
  const responseEvent = buildViewerResponseEvent(requestEvent, {
29081
- statusCode: originResult.statusCode,
29082
- headers: originResult.headers
29466
+ statusCode: finalStatus,
29467
+ headers: finalHeaders
29083
29468
  });
29084
29469
  const mutated = await runViewerResponse(behavior.viewerResponse, responseEvent);
29085
29470
  finalStatus = mutated.statusCode;
29086
- finalHeaders = cfHeadersToPlain(mutated.headers, originResult.headers);
29471
+ finalHeaders = cfHeadersToPlain(mutated.headers, finalHeaders);
29472
+ }
29473
+ if (behavior.lambdaEdge?.viewerResponse) {
29474
+ const r = await runEdgeResponseStage(behavior.lambdaEdge.viewerResponse, "viewer-response", {
29475
+ config,
29476
+ request: edgeInput,
29477
+ statusCode: finalStatus,
29478
+ headers: finalHeaders,
29479
+ body: finalBody
29480
+ }, edgeInvokers, logger);
29481
+ if (r) {
29482
+ finalStatus = r.statusCode;
29483
+ finalHeaders = r.headers;
29484
+ finalBody = r.body;
29485
+ setCookies.push(...r.setCookies);
29486
+ }
29087
29487
  }
29088
- const setCookies = [...originResult.setCookies ?? []];
29089
29488
  for (const name of Object.keys(finalHeaders)) if (name.toLowerCase() === "set-cookie") {
29090
29489
  setCookies.push(finalHeaders[name]);
29091
29490
  delete finalHeaders[name];
@@ -29101,7 +29500,54 @@ async function handleRequest$1(req, res, state, lambdaInvokers, logger) {
29101
29500
  const origin = req.headers.origin;
29102
29501
  applyCorsResponseHeadersFromConfig(res, behavior.cors, typeof origin === "string" ? origin : void 0);
29103
29502
  }
29104
- res.end(originResult.body);
29503
+ res.end(finalBody);
29504
+ }
29505
+ /** Run a Lambda@Edge response-stage function, returning the modified response (or undefined when no invoker). */
29506
+ async function runEdgeResponseStage(assoc, eventType, ctx, edgeInvokers, logger) {
29507
+ const invoke = edgeInvokers.get(assoc.functionLogicalId);
29508
+ if (!invoke) {
29509
+ logger.warn(`Lambda@Edge ${eventType} function '${assoc.functionLogicalId}' was not booted (added after start-up); skipping. Restart start-cloudfront.`);
29510
+ return;
29511
+ }
29512
+ return applyEdgeResponseResult(await invoke(buildEdgeResponseEvent({
29513
+ eventType,
29514
+ config: ctx.config,
29515
+ request: ctx.request,
29516
+ response: {
29517
+ statusCode: ctx.statusCode,
29518
+ headers: ctx.headers
29519
+ }
29520
+ })), {
29521
+ statusCode: ctx.statusCode,
29522
+ headers: ctx.headers
29523
+ }, ctx.body);
29524
+ }
29525
+ /** Write a Lambda@Edge generated response (request-stage short-circuit), incl. CORS. */
29526
+ function writeEdgeResponse(res, result, behavior, req, logger) {
29527
+ if (!req.readableEnded) req.resume();
29528
+ res.statusCode = result.statusCode;
29529
+ setHeadersSafely(res, result.headers, logger);
29530
+ if (result.setCookies.length > 0) try {
29531
+ res.setHeader("set-cookie", result.setCookies);
29532
+ } catch {}
29533
+ if (behavior.cors) {
29534
+ const origin = req.headers.origin;
29535
+ applyCorsResponseHeadersFromConfig(res, behavior.cors, typeof origin === "string" ? origin : void 0);
29536
+ }
29537
+ res.end(result.body);
29538
+ }
29539
+ /** Convert a CloudFront-Function header map (`{name: CfValue}`) into the raw `{name: string[]}` form. */
29540
+ function cfHeadersToRawMap(cf) {
29541
+ const out = {};
29542
+ for (const [name, val] of Object.entries(cf)) if (val.multiValue && val.multiValue.length > 0) out[name] = val.multiValue.map((m) => m.value);
29543
+ else out[name] = [val.value];
29544
+ return out;
29545
+ }
29546
+ /** Convert a raw `{name: string[]}` header map into Node's `IncomingHttpHeaders` shape. */
29547
+ function rawMapToIncomingHeaders(headers) {
29548
+ const out = {};
29549
+ for (const [name, values] of Object.entries(headers)) out[name] = values.length === 1 ? values[0] : values;
29550
+ return out;
29105
29551
  }
29106
29552
  /**
29107
29553
  * Convert Node's `IncomingMessage.headers` (`Record<string, string | string[]>`)
@@ -29138,9 +29584,8 @@ function setHeadersSafely(res, headers, logger) {
29138
29584
  logger.warn(`Skipping invalid response header '${name}': ${err instanceof Error ? err.message : String(err)}`);
29139
29585
  }
29140
29586
  }
29141
- async function serveFromOrigin(origin, behavior, args) {
29142
- const { distribution, logger } = args;
29143
- if (behavior.hasLambdaEdge) logger.warn(`Behavior ${behavior.pathPattern ?? "(default)"} carries a Lambda@Edge association; cdk-local does not run Lambda@Edge — serving the origin only.`);
29587
+ async function serveFromOrigin(origin, args) {
29588
+ const { distribution } = args;
29144
29589
  if (!origin) return void 0;
29145
29590
  if (origin.kind === "lambda-url") {
29146
29591
  const invoke = args.lambdaInvokers.get(origin.functionLogicalId);
@@ -29165,6 +29610,20 @@ async function serveFromOrigin(origin, behavior, args) {
29165
29610
  ...result.cookies.length > 0 && { setCookies: result.cookies }
29166
29611
  };
29167
29612
  }
29613
+ if (origin.kind === "s3-deployed") {
29614
+ const reader = args.s3OriginReaders.get(origin.originId);
29615
+ if (!reader) return void 0;
29616
+ const result = await reader({
29617
+ uri: args.uri,
29618
+ ...distribution.defaultRootObject !== void 0 && { defaultRootObject: distribution.defaultRootObject },
29619
+ customErrorResponses: distribution.customErrorResponses
29620
+ });
29621
+ return {
29622
+ statusCode: result.statusCode,
29623
+ headers: result.headers,
29624
+ body: result.body
29625
+ };
29626
+ }
29168
29627
  if (origin.kind !== "s3") return void 0;
29169
29628
  const result = serveFromStaticOrigin({
29170
29629
  localDirs: origin.localDirs,
@@ -29182,6 +29641,8 @@ function originUnavailableMessage(origin, behavior) {
29182
29641
  if (!origin) return `Behavior ${behavior.pathPattern ?? "(default)"} targets unknown origin '${behavior.targetOriginId}'.\n`;
29183
29642
  if (origin.kind === "lambda-url") return `Origin '${origin.originId}' is a Lambda Function URL origin whose backing function '${origin.functionLogicalId}' was not booted (it was added after start-up). Restart start-cloudfront.\n`;
29184
29643
  if (origin.kind === "custom") return `Origin '${origin.originId}' is a custom (non-S3) origin (${origin.domainName}). cdkl start-cloudfront serves S3 origins and Lambda Function URL origins only.
29644
+ `;
29645
+ if (origin.kind === "s3-deployed") return `Origin '${origin.originId}' is a deployed-S3 origin (bucket '${origin.bucketName}') whose reader was not booted (it was promoted after start-up). Restart start-cloudfront.
29185
29646
  `;
29186
29647
  return `Origin '${origin.originId}' is an S3 origin with no resolvable local source. Point it at a directory with --origin ${origin.originId}=<dir>.\n`;
29187
29648
  }
@@ -29237,6 +29698,101 @@ function listen(server, host, port) {
29237
29698
  });
29238
29699
  }
29239
29700
 
29701
+ //#endregion
29702
+ //#region src/local/cloudfront-s3-origin.ts
29703
+ /**
29704
+ * Build a reader that serves a deployed S3 bucket on demand. The S3 client is
29705
+ * created lazily on first read (and reused) so an all-local distribution never
29706
+ * touches the SDK. Boot-time bound to one `bucketName`; one reader per origin.
29707
+ */
29708
+ function createS3OriginReader(bucketName, options = {}) {
29709
+ const fetchObject = options.fetchObject ?? defaultFetchObject(bucketName, options);
29710
+ let deniedWarned = false;
29711
+ return async (input) => {
29712
+ const key = uriToKey(input.uri, input.defaultRootObject);
29713
+ if (key !== "") {
29714
+ const direct = await fetchObject(key);
29715
+ if (direct.kind === "found") return {
29716
+ statusCode: 200,
29717
+ headers: { "content-type": contentTypeForKey(key) },
29718
+ body: direct.body
29719
+ };
29720
+ if (direct.kind === "denied" && !deniedWarned) {
29721
+ deniedWarned = true;
29722
+ getLogger().warn(`S3 denied reading '${key}' from bucket '${bucketName}'. If this is an OAC-locked / private bucket your credentials cannot read, point the origin at a local directory with --origin <originId>=<dir> (or use credentials with s3:GetObject on the bucket). ${getEmbedConfig().cliName} start-cloudfront reads the origin from real S3.`);
29723
+ }
29724
+ if (direct.kind === "error") getLogger().warn(`S3 read of '${key}' from bucket '${bucketName}' failed: ${direct.message}`);
29725
+ }
29726
+ for (const candidate of resolveErrorResponseCandidates(input.customErrorResponses)) {
29727
+ const page = await fetchObject(candidate.errorKey);
29728
+ if (page.kind === "found") return {
29729
+ statusCode: candidate.responseCode,
29730
+ headers: { "content-type": contentTypeForKey(candidate.errorKey) },
29731
+ body: page.body
29732
+ };
29733
+ }
29734
+ return {
29735
+ statusCode: 404,
29736
+ headers: { "content-type": "text/plain; charset=utf-8" },
29737
+ body: Buffer.from(`Not found: ${input.uri}\n`)
29738
+ };
29739
+ };
29740
+ }
29741
+ /** The default fetcher: a real S3 `GetObject`, classifying the SDK error into the outcome union. */
29742
+ function defaultFetchObject(bucketName, options) {
29743
+ let init = null;
29744
+ const getAccess = () => {
29745
+ if (!init) init = (async () => {
29746
+ const { S3Client, GetObjectCommand } = await import("@aws-sdk/client-s3");
29747
+ return {
29748
+ client: new S3Client({
29749
+ ...options.region && { region: options.region },
29750
+ ...options.credentials && { credentials: {
29751
+ accessKeyId: options.credentials.accessKeyId,
29752
+ secretAccessKey: options.credentials.secretAccessKey,
29753
+ ...options.credentials.sessionToken && { sessionToken: options.credentials.sessionToken }
29754
+ } }
29755
+ }),
29756
+ GetObjectCommand
29757
+ };
29758
+ })();
29759
+ return init;
29760
+ };
29761
+ return async (key) => {
29762
+ try {
29763
+ const { client, GetObjectCommand } = await getAccess();
29764
+ const res = await client.send(new GetObjectCommand({
29765
+ Bucket: bucketName,
29766
+ Key: key
29767
+ }));
29768
+ if (!res.Body) return { kind: "not-found" };
29769
+ const bytes = await res.Body.transformToByteArray();
29770
+ return {
29771
+ kind: "found",
29772
+ body: Buffer.from(bytes)
29773
+ };
29774
+ } catch (err) {
29775
+ return classifyS3Error(err);
29776
+ }
29777
+ };
29778
+ }
29779
+ /**
29780
+ * Classify an S3 SDK error: a missing key (`NoSuchKey` / 404) is `not-found`
29781
+ * (try the SPA fallback), an `AccessDenied` / 403 is `denied` (a credential /
29782
+ * OAC config problem), anything else is `error`.
29783
+ */
29784
+ function classifyS3Error(err) {
29785
+ const e = err;
29786
+ const status = e?.$metadata?.httpStatusCode;
29787
+ const name = e?.name;
29788
+ if (status === 404 || name === "NoSuchKey" || name === "NotFound") return { kind: "not-found" };
29789
+ if (status === 403 || name === "AccessDenied" || name === "Forbidden") return { kind: "denied" };
29790
+ return {
29791
+ kind: "error",
29792
+ message: err instanceof Error ? err.message : String(err)
29793
+ };
29794
+ }
29795
+
29240
29796
  //#endregion
29241
29797
  //#region src/local/cloudfront-kvs-client.ts
29242
29798
  /**
@@ -29518,12 +30074,123 @@ async function bootLambdaUrlOrigins(distribution, stacks, opts) {
29518
30074
  runners
29519
30075
  };
29520
30076
  }
30077
+ /**
30078
+ * Boot one warm RIE container per unique Lambda@Edge function across the
30079
+ * distribution's behaviors (issue #400), returning the runners + an invoker map
30080
+ * keyed by backing-function logical id for {@link startCloudFrontServer}. Each
30081
+ * function gets the SAME container env as a direct `cdkl invoke` (declared env
30082
+ * vars + `--from-cfn-stack` substitution + `--assume-role` creds) via the shared
30083
+ * {@link resolveLambdaContainerEnv}. A function that cannot be booted is
30084
+ * warn-and-skipped (its edge stage will not run); booted once at start-up, NOT
30085
+ * rebuilt on a `--watch` reload.
30086
+ */
30087
+ async function bootLambdaEdgeFunctions(distribution, stacks, opts) {
30088
+ const logger = getLogger();
30089
+ const invokers = /* @__PURE__ */ new Map();
30090
+ const runners = [];
30091
+ const functionLogicalIds = /* @__PURE__ */ new Set();
30092
+ for (const behavior of distribution.behaviors) {
30093
+ const edge = behavior.lambdaEdge;
30094
+ if (!edge) continue;
30095
+ for (const assoc of [
30096
+ edge.viewerRequest,
30097
+ edge.originRequest,
30098
+ edge.originResponse,
30099
+ edge.viewerResponse
30100
+ ]) if (assoc) functionLogicalIds.add(assoc.functionLogicalId);
30101
+ }
30102
+ for (const functionLogicalId of functionLogicalIds) try {
30103
+ const lambda = resolveLambdaTarget(functionLogicalId, stacks);
30104
+ const containerEnv = await resolveLambdaContainerEnv(lambda, opts.envOptions, opts.profileCredentials);
30105
+ const runner = createFrontDoorLambdaRunner(lambda, {
30106
+ containerHost: opts.containerHost,
30107
+ skipPull: opts.skipPull,
30108
+ ...opts.envOptions.region !== void 0 && { region: opts.envOptions.region },
30109
+ containerEnv: containerEnv.env,
30110
+ ...containerEnv.sensitiveEnvKeys.length > 0 && { sensitiveEnvKeys: new Set(containerEnv.sensitiveEnvKeys) }
30111
+ });
30112
+ logger.info(`Booting Lambda@Edge container for ${functionLogicalId} (the function runs locally via RIE)...`);
30113
+ await runner.start();
30114
+ runners.push(runner);
30115
+ invokers.set(functionLogicalId, (event) => runner.invoke(event));
30116
+ } catch (err) {
30117
+ logger.warn(`Could not boot Lambda@Edge function '${functionLogicalId}'; its stage will be skipped: ${err instanceof Error ? err.message : String(err)}`);
30118
+ }
30119
+ return {
30120
+ invokers,
30121
+ runners
30122
+ };
30123
+ }
29521
30124
  /** Emit boot-time WARNs for parts of the distribution cdk-local does not serve. */
29522
30125
  function warnUnsupported(distribution) {
29523
30126
  const logger = getLogger();
29524
30127
  for (const origin of distribution.origins.values()) if (origin.kind === "custom") logger.warn(`Origin '${origin.originId}' is a custom (non-S3, non-Lambda-Function-URL) origin (${origin.domainName}); ${getEmbedConfig().cliName} start-cloudfront serves S3 origins and Lambda Function URL origins only. Requests routed to it return 502.`);
29525
- else if (origin.kind === "s3-unresolved") logger.warn(`Origin '${origin.originId}' is an S3 origin with no resolvable local source (no BucketDeployment found, or its source could not be located in the cloud assembly). Point it at a directory with --origin ${origin.originId}=<dir>. Requests routed to it return 502.`);
29526
- if (distribution.behaviors.some((b) => b.hasLambdaEdge)) logger.warn("One or more cache behaviors carry a Lambda@Edge association; cdk-local does not run Lambda@Edge functions — only CloudFront Functions + the S3 origin are served.");
30128
+ else if (origin.kind === "s3-unresolved") logger.warn(`Origin '${origin.originId}' is an S3 origin with no resolvable local source (no BucketDeployment found, or its source could not be located in the cloud assembly). Pass --from-cfn-stack to serve the deployed bucket from real S3 on demand, or point it at a local directory with --origin ${origin.originId}=<dir>. Requests routed to it return 502.`);
30129
+ }
30130
+ /**
30131
+ * Promote each S3 origin with no local BucketDeployment source (`s3-unresolved`)
30132
+ * to a deployed-S3 read-through origin (issue #405), building one
30133
+ * {@link S3OriginReader} per origin. This is the front/back-split path: the CDK
30134
+ * repo defines the distribution + bucket but the static files were uploaded out
30135
+ * of band, so there is nothing in the cloud assembly to serve locally. Under
30136
+ * `--from-cfn-stack`, the bucket's physical NAME is resolved from deployed state
30137
+ * (`ListStackResources`) and the reader serves it from real S3 on demand.
30138
+ *
30139
+ * Returns the readers (keyed by origin id, handed to the server) + the
30140
+ * origin-id -> bucket-name map (re-applied on each `--watch` reload via
30141
+ * {@link annotateDeployedS3Origins}, since the pure resolver re-emits the origin
30142
+ * as `s3-unresolved`). A no-op without `--from-cfn-stack` or when the bucket's
30143
+ * physical id is not in state (the origin stays `s3-unresolved` -> the existing
30144
+ * boot WARN + 502, with `--origin <id>=<dir>` as the escape hatch).
30145
+ */
30146
+ async function resolveDeployedS3Origins(distribution, stacks, options, profileCredentials, logger) {
30147
+ const readers = /* @__PURE__ */ new Map();
30148
+ const buckets = /* @__PURE__ */ new Map();
30149
+ if (!isCfnFlagPresent(options)) return {
30150
+ readers,
30151
+ buckets
30152
+ };
30153
+ const synthRegion = stacks.find((s) => s.stackName === distribution.stackName)?.region;
30154
+ const region = options.stackRegion ?? options.region ?? synthRegion;
30155
+ const provider = createLocalStateProvider(options, distribution.stackName, synthRegion);
30156
+ const record = provider ? await provider.load(distribution.stackName, synthRegion) : void 0;
30157
+ for (const origin of [...distribution.origins.values()]) {
30158
+ if (origin.kind !== "s3-unresolved" || origin.bucketLogicalId === void 0) continue;
30159
+ const bucketName = record?.resources[origin.bucketLogicalId]?.physicalId;
30160
+ if (!bucketName) continue;
30161
+ readers.set(origin.originId, createS3OriginReader(bucketName, {
30162
+ ...region !== void 0 && { region },
30163
+ ...profileCredentials !== void 0 && { credentials: profileCredentials }
30164
+ }));
30165
+ buckets.set(origin.originId, bucketName);
30166
+ distribution.origins.set(origin.originId, {
30167
+ kind: "s3-deployed",
30168
+ originId: origin.originId,
30169
+ bucketName
30170
+ });
30171
+ logger.info(`Origin '${origin.originId}': no local BucketDeployment source; serving from deployed S3 (bucket=${bucketName}) on demand under --from-cfn-stack.`);
30172
+ }
30173
+ return {
30174
+ readers,
30175
+ buckets
30176
+ };
30177
+ }
30178
+ /**
30179
+ * Re-apply the boot-time deployed-S3 promotion to a freshly re-synthed
30180
+ * distribution on a `--watch` reload: the pure resolver re-emits the origin as
30181
+ * `s3-unresolved`, so rewrite it back to `s3-deployed` (same bucket name) so it
30182
+ * dispatches to the boot-time reader. The S3 readers themselves are boot-time
30183
+ * only (like the Function URL origin containers), so nothing is rebuilt here.
30184
+ */
30185
+ function annotateDeployedS3Origins(distribution, buckets) {
30186
+ for (const [originId, bucketName] of buckets) {
30187
+ const origin = distribution.origins.get(originId);
30188
+ if (origin && origin.kind === "s3-unresolved") distribution.origins.set(originId, {
30189
+ kind: "s3-deployed",
30190
+ originId,
30191
+ bucketName
30192
+ });
30193
+ }
29527
30194
  }
29528
30195
  async function localStartCloudFrontCommand(target, options) {
29529
30196
  const logger = getLogger();
@@ -29569,8 +30236,9 @@ async function localStartCloudFrontCommand(target, options) {
29569
30236
  };
29570
30237
  };
29571
30238
  const initial = await synthAndResolve();
29572
- warnUnsupported(initial.distribution);
29573
30239
  const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
30240
+ const deployedS3 = await resolveDeployedS3Origins(initial.distribution, initial.stacks, options, profileCredentials, logger);
30241
+ warnUnsupported(initial.distribution);
29574
30242
  const envOptions = {
29575
30243
  ...options.fromCfnStack !== void 0 && { fromCfnStack: options.fromCfnStack },
29576
30244
  ...options.assumeRole !== void 0 && { assumeRole: options.assumeRole },
@@ -29579,24 +30247,34 @@ async function localStartCloudFrontCommand(target, options) {
29579
30247
  ...options.stackRegion !== void 0 && { stackRegion: options.stackRegion }
29580
30248
  };
29581
30249
  await attachKvsModules(initial.distribution, initial.stacks, options, profileCredentials, logger);
29582
- const { invokers: lambdaInvokers, runners: lambdaRunners } = await bootLambdaUrlOrigins(initial.distribution, initial.stacks, {
30250
+ const bootOpts = {
29583
30251
  containerHost: options.host,
29584
30252
  skipPull: options.pull === false,
29585
30253
  envOptions,
29586
30254
  ...profileCredentials !== void 0 && { profileCredentials }
29587
- });
29588
- let tls;
29589
- if (tlsRequested) tls = await resolveFrontDoorTlsMaterials({
29590
- certPath: options.tlsCert,
29591
- keyPath: options.tlsKey
29592
- });
29593
- const server = await startCloudFrontServer({
29594
- distribution: initial.distribution,
29595
- host: options.host,
29596
- port: basePort,
29597
- ...tls && { tls },
29598
- ...lambdaInvokers.size > 0 && { lambdaInvokers }
29599
- });
30255
+ };
30256
+ const { invokers: lambdaInvokers, runners: lambdaRunners } = await bootLambdaUrlOrigins(initial.distribution, initial.stacks, bootOpts);
30257
+ const { invokers: edgeInvokers, runners: edgeRunners } = await bootLambdaEdgeFunctions(initial.distribution, initial.stacks, bootOpts);
30258
+ let server;
30259
+ try {
30260
+ let tls;
30261
+ if (tlsRequested) tls = await resolveFrontDoorTlsMaterials({
30262
+ certPath: options.tlsCert,
30263
+ keyPath: options.tlsKey
30264
+ });
30265
+ server = await startCloudFrontServer({
30266
+ distribution: initial.distribution,
30267
+ host: options.host,
30268
+ port: basePort,
30269
+ ...tls && { tls },
30270
+ ...lambdaInvokers.size > 0 && { lambdaInvokers },
30271
+ ...edgeInvokers.size > 0 && { edgeInvokers },
30272
+ ...deployedS3.readers.size > 0 && { s3OriginReaders: deployedS3.readers }
30273
+ });
30274
+ } catch (err) {
30275
+ await Promise.all([...lambdaRunners, ...edgeRunners].map((r) => r.stop().catch(() => void 0)));
30276
+ throw err;
30277
+ }
29600
30278
  process.stdout.write(`CloudFront distribution serving on ${server.url} (${initial.distribution.logicalId})\n`);
29601
30279
  process.stdout.write("^C to stop.\n");
29602
30280
  let watcher;
@@ -29617,6 +30295,7 @@ async function localStartCloudFrontCommand(target, options) {
29617
30295
  reloadChain = reloadChain.then(async () => {
29618
30296
  try {
29619
30297
  const reloaded = await synthAndResolve();
30298
+ annotateDeployedS3Origins(reloaded.distribution, deployedS3.buckets);
29620
30299
  warnUnsupported(reloaded.distribution);
29621
30300
  await attachKvsModules(reloaded.distribution, reloaded.stacks, options, profileCredentials, logger);
29622
30301
  server.update(reloaded.distribution);
@@ -29640,8 +30319,8 @@ async function localStartCloudFrontCommand(target, options) {
29640
30319
  try {
29641
30320
  await server.close();
29642
30321
  } catch {}
29643
- await Promise.all(lambdaRunners.map((r) => r.stop().catch((err) => {
29644
- logger.debug(`Lambda origin runner stop failed: ${err instanceof Error ? err.message : String(err)}`);
30322
+ await Promise.all([...lambdaRunners, ...edgeRunners].map((r) => r.stop().catch((err) => {
30323
+ logger.debug(`Lambda runner stop failed: ${err instanceof Error ? err.message : String(err)}`);
29645
30324
  })));
29646
30325
  process.exit(exitCode);
29647
30326
  };
@@ -29672,7 +30351,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
29672
30351
  * `cmd`.
29673
30352
  */
29674
30353
  function addStartCloudFrontSpecificOptions(cmd) {
29675
- 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 <kvsLogicalId=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is the AWS::CloudFront::KeyValueStore resource logical 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 origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind a Lambda Function URL origin's backing Lambda to a deployed CloudFormation stack so its env vars resolve to the deployed physical IDs / exports (ListStackResources). 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. No effect on a pure-S3 distribution.")).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 deployed 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));
30354
+ 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 <kvsLogicalId=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is the AWS::CloudFront::KeyValueStore resource logical 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 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 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("--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 deployed 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));
29676
30355
  }
29677
30356
 
29678
30357
  //#endregion
@@ -34707,5 +35386,5 @@ function addStudioSpecificOptions(cmd) {
34707
35386
  }
34708
35387
 
34709
35388
  //#endregion
34710
- export { createUnboundCloudFrontModule as $, pickResponseTemplate as $n, resolveAgentCoreTarget as $r, AGENTCORE_SESSION_ID_HEADER as $t, parseOriginOverrides as A, buildCognitoJwksUrl as An, CfnLocalStateProvider as Ar, describePinnedImageUri as At, CLOUDFRONT_DISTRIBUTION_TYPE as B, invokeTokenAuthorizer as Bn, filterWebSocketApisByIdentifiers as Br, addInvokeAgentCoreSpecificOptions as Bt, addListSpecificOptions as C, filterRoutesByApiIdentifiers as Cn, LocalStateSourceError as Cr, ImageOverrideError as Ct, addStartCloudFrontSpecificOptions as D, resolveSelectionExpression as Dn, resolveCfnFallbackRegion as Dr, parseImageOverrideFlags as Dt, LocalStartCloudFrontError as E, startApiServer as En, rejectExplicitCfnStackWithMultipleStacks as Er, mergeForService as Et, resolveDeployedKvsArnByName as F, verifyJwtViaDiscovery as Fn, countTargets as Fr, DEFAULT_SHADOW_READY_TIMEOUT_MS as Ft, pickTargetFunctionLogicalId as G, isFunctionUrlOacFronted as Gn, resolveLambdaArnIntrinsic as Gr, a2aInvokeOnce as Gt, isCloudFrontDistribution as H, applyCorsResponseHeaders as Hn, webSocketApiMatchesIdentifier as Hr, invokeAgentCoreWs as Ht, matchBehavior as I, buildMethodArn as In, listTargets as Ir, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as It, runViewerRequest as J, translateLambdaResponse as Jn, AGENTCORE_HTTP_PROTOCOL as Jr, MCP_PROTOCOL_VERSION as Jt, resolveCloudFrontDistribution as K, matchPreflight as Kn, AGENTCORE_A2A_PROTOCOL as Kr, MCP_CONTAINER_PORT as Kt, startCloudFrontServer as L, computeRequestIdentityHash as Ln, availableWebSocketApiIdentifiers as Lr, setShadowReadyTimeoutMs as Lt, idFromArn as M, createJwksCache as Mn, resolveSsmParameters as Mr, listPinnedTargets as Mt, resolveKvsModulesForDistribution as N, verifyCognitoJwt as Nn, resolveWatchConfig as Nr, buildCloudMapIndex as Nt, createLocalStartCloudFrontCommand as O, resolveServiceIntegrationParameters as On, resolveCfnRegion as Or, resolveImageOverrides as Ot, createDeployedKvsDataSource as P, verifyJwtAuthorizer as Pn, resolveSingleTarget as Pr, CloudMapRegistry as Pt, createLocalFileKvsDataSource as Q, evaluateResponseParameters as Qn, pickAgentCoreCandidateStack as Qr, signAgentCoreInvocation as Qt, serveFromStaticOrigin as R, evaluateCachedLambdaPolicy as Rn, discoverWebSocketApis as Rr, getContainerNetworkIp as Rt, StudioEventBus as S, filterRoutesByApiIdentifier as Sn, substituteEnvVarsFromStateAsync as Sr, runEcsServiceEmulator as St, formatTargetListing as T, readMtlsMaterialsFromDisk as Tn, isCfnFlagPresent as Tr, enforceImageOverrideOrphans as Tt, pickFunctionUrlLogicalIdFromOrigin as U, buildCorsConfigByApiId as Un, discoverRoutes as Ur, A2A_CONTAINER_PORT as Ut, extractKvsAssociations as V, attachAuthorizers as Vn, parseSelectionExpressionPath as Vr, createLocalInvokeAgentCoreCommand as Vt, pickKvsLogicalIdFromArn as W, buildCorsConfigFromCloudFrontChain as Wn, pickRefLogicalId as Wr, A2A_PATH as Wt, stripCloudFrontImport as X, buildHttpApiV2Event as Xn, AGENTCORE_RUNTIME_TYPE as Xr, parseSseForJsonRpc as Xt, runViewerResponse as Y, applyAuthorizerOverlay as Yn, AGENTCORE_MCP_PROTOCOL as Yr, mcpInvokeOnce as Yt, createCloudFrontModule as Z, buildRestV1Event as Zn, AgentCoreResolutionError as Zr, AGENTCORE_SIGV4_SERVICE as Zt, filterStudioTargetGroups as _, attachStageContext as _n, resolveRuntimeImage as _r, ecsClusterOption as _t, createLocalStudioCommand as a, buildStsClientConfig as ai, computeCodeImageTag as an, bufferToBody as ar, isApplicationLoadBalancer as at, renderStudioHtml as b, resolveEnvVars$1 as bn, substituteAgainstStateAsync as br, resolveEcsAssumeRoleOption as bt, startStudioProxy as c, classifySourceChange as cn, handleConnectionsRequest as cr, createLocalStartServiceCommand as ct, createStudioDispatcher as d, addStartApiSpecificOptions as dn, buildDisconnectEvent as dr, createLocalRunTaskCommand as dt, derivePseudoParametersFromRegion as ei, invokeAgentCore as en, selectIntegrationResponse as er, addAlbSpecificOptions as et, filterStudioCustomResources as f, createLocalStartApiCommand as fn, buildMessageEvent as fr, MAX_TASKS_SUBNET_RANGE_CAP as ft, annotatePinnedEcsTargets as g, createFileWatcher as gn, resolveRuntimeFileExtension as gr, buildEcsImageResolutionContext$1 as gt, annotateEcsTaskPinnedTargets as h, createAuthorizerCache as hn, resolveRuntimeCodeMountPath as hr, addImageOverrideOptions as ht, coerceStopRequest as i, LocalInvokeBuildError as ii, buildAgentCoreCodeImage as in, probeHostGatewaySupport as ir, resolveAlbTarget as it, resolveCloudFrontTarget as j, buildJwksUrlFromIssuer as jn, collectSsmParameterRefs as jr, isLocalCdkAssetImage as jt, parseKvsFileOverrides as k, defaultCredentialsLoader as kn, resolveCfnStackName as kr, runImageOverrideBuilds as kt, relayServeRequest as l, addInvokeSpecificOptions as ln, parseConnectionsPath as lr, serviceStrategy as lt, annotateAlbPinnedBackingServices as m, resolveApiTargetSubset as mn, buildContainerImage as mr, addEcsAssumeRoleOptions as mt, coerceRunRequest as n, substituteImagePlaceholders as ni, downloadAndExtractS3Bundle as nn, VtlEvaluationError as nr, createLocalStartAlbCommand as nt, resolveServeBaseUrl as o, resolveProfileCredentials as oi, renderCodeDockerfile as on, ConnectionRegistry as or, resolveAlbFrontDoor as ot, isCustomResourceLambdaTarget as p, createWatchPredicates as pn, architectureToPlatform as pr, addCommonEcsServiceOptions as pt, compileCloudFrontFunction as q, matchRoute as qn, AGENTCORE_AGUI_PROTOCOL as qr, MCP_PATH as qt, coerceServeRequest as r, tryResolveImageFnJoin as ri, SUPPORTED_CODE_RUNTIMES as rn, HOST_GATEWAY_MIN_VERSION as rr, parseLbPortOverrides as rt, createStudioServeManager as s, toCmdArgv as sn, buildMgmtEndpointEnvUrl as sr, addStartServiceSpecificOptions as st, addStudioSpecificOptions as t, formatStateRemedy as ti, waitForAgentCorePing as tn, tryParseStatus as tr, albStrategy as tt, reinvoke as u, createLocalInvokeCommand as un, buildConnectEvent as ur, addRunTaskSpecificOptions as ut, startStudioServer as v, buildStageMap as vn, EcsTaskResolutionError as vr, parseMaxTasks as vt, createLocalListCommand as w, groupRoutesByServer as wn, createLocalStateProvider as wr, buildImageOverrideTag as wt, createStudioStore as x, availableApiIdentifiers as xn, substituteEnvVarsFromState as xr, resolveSharedSidecarCredentials as xt, toStudioTargetGroups as y, materializeLayerFromArn as yn, substituteAgainstState as yr, parseRestartPolicy as yt, serveLambdaUrlOrigin as z, invokeRequestAuthorizer as zn, discoverWebSocketApisOrThrow as zr, attachContainerLogStreamer as zt };
34711
- //# sourceMappingURL=local-studio-DPEUB-rH.js.map
35389
+ export { pickKvsLogicalIdFromArn as $, buildCorsConfigByApiId as $n, discoverRoutes as $r, A2A_CONTAINER_PORT as $t, parseOriginOverrides as A, resolveEnvVars$1 as An, substituteAgainstStateAsync as Ar, resolveEcsAssumeRoleOption as At, resolveErrorResponseCandidates as B, buildCognitoJwksUrl as Bn, CfnLocalStateProvider as Br, describePinnedImageUri as Bt, addListSpecificOptions as C, createWatchPredicates as Cn, architectureToPlatform as Cr, addCommonEcsServiceOptions as Ct, addStartCloudFrontSpecificOptions as D, attachStageContext as Dn, resolveRuntimeImage as Dr, ecsClusterOption as Dt, LocalStartCloudFrontError as E, createFileWatcher as En, resolveRuntimeFileExtension as Er, buildEcsImageResolutionContext$1 as Et, resolveDeployedKvsArnByName as F, readMtlsMaterialsFromDisk as Fn, isCfnFlagPresent as Fr, enforceImageOverrideOrphans as Ft, buildEdgeRequestEvent as G, verifyJwtViaDiscovery as Gn, countTargets as Gr, DEFAULT_SHADOW_READY_TIMEOUT_MS as Gt, serveLambdaUrlOrigin as H, createJwksCache as Hn, resolveSsmParameters as Hr, listPinnedTargets as Ht, classifyS3Error as I, startApiServer as In, rejectExplicitCfnStackWithMultipleStacks as Ir, mergeForService as It, httpHeadersToEdge as J, evaluateCachedLambdaPolicy as Jn, discoverWebSocketApis as Jr, getContainerNetworkIp as Jt, buildEdgeResponseEvent as K, buildMethodArn as Kn, listTargets as Kr, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Kt, createS3OriginReader as L, resolveSelectionExpression as Ln, resolveCfnFallbackRegion as Lr, parseImageOverrideFlags as Lt, idFromArn as M, filterRoutesByApiIdentifier as Mn, substituteEnvVarsFromStateAsync as Mr, runEcsServiceEmulator as Mt, resolveKvsModulesForDistribution as N, filterRoutesByApiIdentifiers as Nn, LocalStateSourceError as Nr, ImageOverrideError as Nt, createLocalStartCloudFrontCommand as O, buildStageMap as On, EcsTaskResolutionError as Or, parseMaxTasks as Ot, createDeployedKvsDataSource as P, groupRoutesByServer as Pn, createLocalStateProvider as Pr, buildImageOverrideTag as Pt, pickFunctionUrlLogicalIdFromOrigin as Q, applyCorsResponseHeaders as Qn, webSocketApiMatchesIdentifier as Qr, invokeAgentCoreWs as Qt, matchBehavior as R, resolveServiceIntegrationParameters as Rn, resolveCfnRegion as Rr, resolveImageOverrides as Rt, StudioEventBus as S, createLocalStartApiCommand as Sn, buildMessageEvent as Sr, MAX_TASKS_SUBNET_RANGE_CAP as St, formatTargetListing as T, createAuthorizerCache as Tn, resolveRuntimeCodeMountPath as Tr, addImageOverrideOptions as Tt, applyEdgeRequestResult as U, verifyCognitoJwt as Un, resolveWatchConfig as Ur, buildCloudMapIndex as Ut, serveFromStaticOrigin as V, buildJwksUrlFromIssuer as Vn, collectSsmParameterRefs as Vr, isLocalCdkAssetImage as Vt, applyEdgeResponseResult as W, verifyJwtAuthorizer as Wn, resolveSingleTarget as Wr, CloudMapRegistry as Wt, extractKvsAssociations as X, invokeTokenAuthorizer as Xn, filterWebSocketApisByIdentifiers as Xr, addInvokeAgentCoreSpecificOptions as Xt, CLOUDFRONT_DISTRIBUTION_TYPE as Y, invokeRequestAuthorizer as Yn, discoverWebSocketApisOrThrow as Yr, attachContainerLogStreamer as Yt, isCloudFrontDistribution as Z, attachAuthorizers as Zn, parseSelectionExpressionPath as Zr, createLocalInvokeAgentCoreCommand as Zt, filterStudioTargetGroups as _, toCmdArgv as _n, buildMgmtEndpointEnvUrl as _r, addStartServiceSpecificOptions as _t, createLocalStudioCommand as a, AGENTCORE_MCP_PROTOCOL as ai, mcpInvokeOnce as an, applyAuthorizerOverlay as ar, runViewerResponse as at, renderStudioHtml as b, createLocalInvokeCommand as bn, buildConnectEvent as br, addRunTaskSpecificOptions as bt, startStudioProxy as c, pickAgentCoreCandidateStack as ci, signAgentCoreInvocation as cn, evaluateResponseParameters as cr, createLocalFileKvsDataSource as ct, createStudioDispatcher as d, formatStateRemedy as di, waitForAgentCorePing as dn, tryParseStatus as dr, albStrategy as dt, pickRefLogicalId as ei, A2A_PATH as en, buildCorsConfigFromCloudFrontChain as er, pickLambdaEdgeFunctionLogicalId as et, filterStudioCustomResources as f, substituteImagePlaceholders as fi, downloadAndExtractS3Bundle as fn, VtlEvaluationError as fr, createLocalStartAlbCommand as ft, annotatePinnedEcsTargets as g, resolveProfileCredentials as gi, renderCodeDockerfile as gn, ConnectionRegistry as gr, resolveAlbFrontDoor as gt, annotateEcsTaskPinnedTargets as h, buildStsClientConfig as hi, computeCodeImageTag as hn, bufferToBody as hr, isApplicationLoadBalancer as ht, coerceStopRequest as i, AGENTCORE_HTTP_PROTOCOL as ii, MCP_PROTOCOL_VERSION as in, translateLambdaResponse as ir, runViewerRequest as it, resolveCloudFrontTarget as j, availableApiIdentifiers as jn, substituteEnvVarsFromState as jr, resolveSharedSidecarCredentials as jt, parseKvsFileOverrides as k, materializeLayerFromArn as kn, substituteAgainstState as kr, parseRestartPolicy as kt, relayServeRequest as l, resolveAgentCoreTarget as li, AGENTCORE_SESSION_ID_HEADER as ln, pickResponseTemplate as lr, createUnboundCloudFrontModule as lt, annotateAlbPinnedBackingServices as m, LocalInvokeBuildError as mi, buildAgentCoreCodeImage as mn, probeHostGatewaySupport as mr, resolveAlbTarget as mt, coerceRunRequest as n, AGENTCORE_A2A_PROTOCOL as ni, MCP_CONTAINER_PORT as nn, matchPreflight as nr, resolveCloudFrontDistribution as nt, resolveServeBaseUrl as o, AGENTCORE_RUNTIME_TYPE as oi, parseSseForJsonRpc as on, buildHttpApiV2Event as or, stripCloudFrontImport as ot, isCustomResourceLambdaTarget as p, tryResolveImageFnJoin as pi, SUPPORTED_CODE_RUNTIMES as pn, HOST_GATEWAY_MIN_VERSION as pr, parseLbPortOverrides as pt, edgeHeadersToHttp as q, computeRequestIdentityHash as qn, availableWebSocketApiIdentifiers as qr, setShadowReadyTimeoutMs as qt, coerceServeRequest as r, AGENTCORE_AGUI_PROTOCOL as ri, MCP_PATH as rn, matchRoute as rr, compileCloudFrontFunction as rt, createStudioServeManager as s, AgentCoreResolutionError as si, AGENTCORE_SIGV4_SERVICE as sn, buildRestV1Event as sr, createCloudFrontModule as st, addStudioSpecificOptions as t, resolveLambdaArnIntrinsic as ti, a2aInvokeOnce as tn, isFunctionUrlOacFronted as tr, pickTargetFunctionLogicalId as tt, reinvoke as u, derivePseudoParametersFromRegion as ui, invokeAgentCore as un, selectIntegrationResponse as ur, addAlbSpecificOptions as ut, startStudioServer as v, classifySourceChange as vn, handleConnectionsRequest as vr, createLocalStartServiceCommand as vt, createLocalListCommand as w, resolveApiTargetSubset as wn, buildContainerImage as wr, addEcsAssumeRoleOptions as wt, createStudioStore as x, addStartApiSpecificOptions as xn, buildDisconnectEvent as xr, createLocalRunTaskCommand as xt, toStudioTargetGroups as y, addInvokeSpecificOptions as yn, parseConnectionsPath as yr, serviceStrategy as yt, startCloudFrontServer as z, defaultCredentialsLoader as zn, resolveCfnStackName as zr, runImageOverrideBuilds as zt };
35390
+ //# sourceMappingURL=local-studio-D7SkLbCO.js.map