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.
- package/README.md +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +89 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-BQt4qgdp.d.ts → local-studio-8dQLtWxH.d.ts} +56 -3
- package/dist/local-studio-8dQLtWxH.d.ts.map +1 -0
- package/dist/{local-studio-DPEUB-rH.js → local-studio-D7SkLbCO.js} +739 -60
- package/dist/local-studio-D7SkLbCO.js.map +1 -0
- package/package.json +1 -1
- package/dist/local-studio-BQt4qgdp.d.ts.map +0 -1
- package/dist/local-studio-DPEUB-rH.js.map +0 -1
|
@@ -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
|
-
|
|
28570
|
-
|
|
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
|
|
28873
|
-
|
|
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:
|
|
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:
|
|
29384
|
+
ip: clientIp,
|
|
29047
29385
|
distributionId: distribution.logicalId,
|
|
29048
29386
|
domainName: req.headers.host ?? "localhost",
|
|
29049
|
-
requestId:
|
|
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,
|
|
29066
|
-
uri:
|
|
29067
|
-
querystring,
|
|
29068
|
-
method:
|
|
29069
|
-
headers:
|
|
29070
|
-
readBody: () => readRequestBody(req),
|
|
29071
|
-
sourceIp:
|
|
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:
|
|
29082
|
-
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,
|
|
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(
|
|
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,
|
|
29142
|
-
const { distribution
|
|
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).
|
|
29526
|
-
|
|
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
|
|
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
|
-
|
|
29589
|
-
|
|
29590
|
-
|
|
29591
|
-
|
|
29592
|
-
|
|
29593
|
-
|
|
29594
|
-
|
|
29595
|
-
|
|
29596
|
-
|
|
29597
|
-
|
|
29598
|
-
|
|
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
|
|
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
|
|
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 {
|
|
34711
|
-
//# sourceMappingURL=local-studio-
|
|
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
|