@go-to-k/cdkd 0.79.0 → 0.81.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 +24 -11
- package/dist/cli.js +320 -182
- package/dist/cli.js.map +4 -4
- package/dist/go-to-k-cdkd-0.81.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.79.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -44850,8 +44850,8 @@ var ApiGatewayV2Provider = class {
|
|
|
44850
44850
|
async createRoute(logicalId, resourceType, properties) {
|
|
44851
44851
|
this.logger.debug(`Creating API Gateway V2 Route ${logicalId}`);
|
|
44852
44852
|
const apiId = properties["ApiId"];
|
|
44853
|
-
const
|
|
44854
|
-
if (!apiId || !
|
|
44853
|
+
const routeKey = properties["RouteKey"];
|
|
44854
|
+
if (!apiId || !routeKey) {
|
|
44855
44855
|
throw new ProvisioningError(
|
|
44856
44856
|
`ApiId and RouteKey are required for API Gateway V2 Route ${logicalId}`,
|
|
44857
44857
|
resourceType,
|
|
@@ -44862,7 +44862,7 @@ var ApiGatewayV2Provider = class {
|
|
|
44862
44862
|
const response = await this.getClient().send(
|
|
44863
44863
|
new CreateRouteCommand2({
|
|
44864
44864
|
ApiId: apiId,
|
|
44865
|
-
RouteKey:
|
|
44865
|
+
RouteKey: routeKey,
|
|
44866
44866
|
Target: properties["Target"],
|
|
44867
44867
|
AuthorizationType: properties["AuthorizationType"],
|
|
44868
44868
|
AuthorizerId: properties["AuthorizerId"]
|
|
@@ -70579,7 +70579,9 @@ var SUPPORTED_RUNTIMES = {
|
|
|
70579
70579
|
java17: { image: "public.ecr.aws/lambda/java:17", fileExtension: null },
|
|
70580
70580
|
java21: { image: "public.ecr.aws/lambda/java:21", fileExtension: null },
|
|
70581
70581
|
dotnet6: { image: "public.ecr.aws/lambda/dotnet:6", fileExtension: null },
|
|
70582
|
-
dotnet8: { image: "public.ecr.aws/lambda/dotnet:8", fileExtension: null }
|
|
70582
|
+
dotnet8: { image: "public.ecr.aws/lambda/dotnet:8", fileExtension: null },
|
|
70583
|
+
"provided.al2": { image: "public.ecr.aws/lambda/provided:al2", fileExtension: null },
|
|
70584
|
+
"provided.al2023": { image: "public.ecr.aws/lambda/provided:al2023", fileExtension: null }
|
|
70583
70585
|
};
|
|
70584
70586
|
var UnsupportedRuntimeError = class _UnsupportedRuntimeError extends Error {
|
|
70585
70587
|
constructor(runtime, message) {
|
|
@@ -70597,7 +70599,7 @@ function resolveRuntimeFileExtension(runtime) {
|
|
|
70597
70599
|
if (spec.fileExtension === null) {
|
|
70598
70600
|
throw new UnsupportedRuntimeError(
|
|
70599
70601
|
runtime,
|
|
70600
|
-
`Inline 'Code.ZipFile' is not supported for runtime '${runtime}'. The Lambda Handler shape for this runtime names a compiled artifact (a JVM class, a .NET assembly, or
|
|
70602
|
+
`Inline 'Code.ZipFile' is not supported for runtime '${runtime}'. The Lambda Handler shape for this runtime names a compiled artifact (a JVM class, a .NET assembly, or \u2014 for the OS-only \`provided.*\` runtimes \u2014 an arbitrary \`bootstrap\` binary) that cannot be expressed as a single inline source file. Use \`lambda.Code.fromAsset(<dir>)\` with a directory containing the compiled output (.class hierarchy / JAR / DLL / native binary).`
|
|
70601
70603
|
);
|
|
70602
70604
|
}
|
|
70603
70605
|
return spec.fileExtension;
|
|
@@ -70612,17 +70614,24 @@ function resolveRuntimeSpec(runtime) {
|
|
|
70612
70614
|
const spec = SUPPORTED_RUNTIMES[runtime];
|
|
70613
70615
|
if (spec)
|
|
70614
70616
|
return spec;
|
|
70615
|
-
if (runtime
|
|
70617
|
+
if (runtime === "go1.x") {
|
|
70616
70618
|
throw new UnsupportedRuntimeError(
|
|
70617
70619
|
runtime,
|
|
70618
|
-
`Runtime '
|
|
70620
|
+
`Runtime 'go1.x' was deprecated by AWS Lambda on 2024-01-08 and is no longer available. Migrate to the OS-only runtime: build your Go program as a \`bootstrap\` binary and set the CDK runtime to \`lambda.Runtime.PROVIDED_AL2023\` (or \`lambda.Runtime.PROVIDED_AL2\`). See https://docs.aws.amazon.com/lambda/latest/dg/lambda-golang.html`
|
|
70619
70621
|
);
|
|
70620
70622
|
}
|
|
70621
70623
|
throw new UnsupportedRuntimeError(
|
|
70622
70624
|
runtime,
|
|
70623
|
-
`Unknown runtime '${runtime}'. cdkd local invoke supports nodejs18.x / nodejs20.x / nodejs22.x / nodejs24.x / python3.11 / python3.12 / python3.13 / python3.14 / ruby3.2 / ruby3.3 / java8.al2 / java11 / java17 / java21 / dotnet6 / dotnet8.`
|
|
70625
|
+
`Unknown runtime '${runtime}'. cdkd local invoke supports nodejs18.x / nodejs20.x / nodejs22.x / nodejs24.x / python3.11 / python3.12 / python3.13 / python3.14 / ruby3.2 / ruby3.3 / java8.al2 / java11 / java17 / java21 / dotnet6 / dotnet8 / provided.al2 / provided.al2023.`
|
|
70624
70626
|
);
|
|
70625
70627
|
}
|
|
70628
|
+
function resolveRuntimeCodeMountPath(runtime) {
|
|
70629
|
+
resolveRuntimeSpec(runtime);
|
|
70630
|
+
if (runtime === "provided.al2" || runtime === "provided.al2023") {
|
|
70631
|
+
return "/var/runtime";
|
|
70632
|
+
}
|
|
70633
|
+
return "/var/task";
|
|
70634
|
+
}
|
|
70626
70635
|
|
|
70627
70636
|
// src/local/docker-runner.ts
|
|
70628
70637
|
import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
|
|
@@ -70642,8 +70651,38 @@ async function pullImage(image, skipPull) {
|
|
|
70642
70651
|
logger.debug(`Skipping docker pull for ${image} (--no-pull)`);
|
|
70643
70652
|
return;
|
|
70644
70653
|
}
|
|
70645
|
-
|
|
70646
|
-
|
|
70654
|
+
if (getLogger().getLevel() === "debug") {
|
|
70655
|
+
logger.info(`Pulling ${image}...`);
|
|
70656
|
+
await runForeground("docker", ["pull", image]);
|
|
70657
|
+
return;
|
|
70658
|
+
}
|
|
70659
|
+
logger.debug(`Pulling ${image} (silent \u2014 pass --verbose to stream progress)`);
|
|
70660
|
+
await runCaptured("docker", ["pull", image], image);
|
|
70661
|
+
}
|
|
70662
|
+
function runCaptured(cmd, args, image) {
|
|
70663
|
+
return new Promise((resolveProc, rejectProc) => {
|
|
70664
|
+
const proc = spawn3(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
70665
|
+
let stdout = "";
|
|
70666
|
+
let stderr = "";
|
|
70667
|
+
proc.stdout?.on("data", (chunk) => {
|
|
70668
|
+
stdout += chunk.toString("utf-8");
|
|
70669
|
+
});
|
|
70670
|
+
proc.stderr?.on("data", (chunk) => {
|
|
70671
|
+
stderr += chunk.toString("utf-8");
|
|
70672
|
+
});
|
|
70673
|
+
proc.on(
|
|
70674
|
+
"error",
|
|
70675
|
+
(err) => rejectProc(new DockerRunnerError(`${cmd} pull ${image} failed: ${err.message}`))
|
|
70676
|
+
);
|
|
70677
|
+
proc.on("close", (code) => {
|
|
70678
|
+
if (code === 0) {
|
|
70679
|
+
resolveProc();
|
|
70680
|
+
return;
|
|
70681
|
+
}
|
|
70682
|
+
const detail = stderr.trim() || stdout.trim() || "(no output)";
|
|
70683
|
+
rejectProc(new DockerRunnerError(`docker pull ${image} exited with code ${code}: ${detail}`));
|
|
70684
|
+
});
|
|
70685
|
+
});
|
|
70647
70686
|
}
|
|
70648
70687
|
async function runDetached(opts) {
|
|
70649
70688
|
const args = ["run", "-d", "--rm"];
|
|
@@ -71358,8 +71397,8 @@ function discoverHttpApiRoute(logicalId, resource, template, stackName) {
|
|
|
71358
71397
|
);
|
|
71359
71398
|
}
|
|
71360
71399
|
}
|
|
71361
|
-
const
|
|
71362
|
-
if (typeof
|
|
71400
|
+
const routeKey = props["RouteKey"];
|
|
71401
|
+
if (typeof routeKey !== "string" || routeKey.length === 0) {
|
|
71363
71402
|
throw new Error(
|
|
71364
71403
|
`${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): RouteKey must be a string`
|
|
71365
71404
|
);
|
|
@@ -71395,7 +71434,7 @@ function discoverHttpApiRoute(logicalId, resource, template, stackName) {
|
|
|
71395
71434
|
integrationProps["IntegrationUri"],
|
|
71396
71435
|
`${stackName}/${integrationLogicalId}.IntegrationUri`
|
|
71397
71436
|
);
|
|
71398
|
-
const { method, pathPattern } = parseRouteKey(
|
|
71437
|
+
const { method, pathPattern } = parseRouteKey(routeKey);
|
|
71399
71438
|
return [
|
|
71400
71439
|
{
|
|
71401
71440
|
method,
|
|
@@ -71510,14 +71549,14 @@ function parseHttpApiTargetIntegration(target, location) {
|
|
|
71510
71549
|
)}).`
|
|
71511
71550
|
);
|
|
71512
71551
|
}
|
|
71513
|
-
function parseRouteKey(
|
|
71514
|
-
if (
|
|
71552
|
+
function parseRouteKey(routeKey) {
|
|
71553
|
+
if (routeKey === "$default") {
|
|
71515
71554
|
return { method: "ANY", pathPattern: "$default" };
|
|
71516
71555
|
}
|
|
71517
|
-
const m = /^([A-Za-z]+)\s+(\S+)$/.exec(
|
|
71556
|
+
const m = /^([A-Za-z]+)\s+(\S+)$/.exec(routeKey);
|
|
71518
71557
|
if (!m) {
|
|
71519
71558
|
throw new Error(
|
|
71520
|
-
`RouteKey '${
|
|
71559
|
+
`RouteKey '${routeKey}' is malformed: expected '<METHOD> <path>' (e.g. 'GET /items/{id}') or '$default'.`
|
|
71521
71560
|
);
|
|
71522
71561
|
}
|
|
71523
71562
|
return { method: m[1].toUpperCase(), pathPattern: m[2] };
|
|
@@ -71575,9 +71614,10 @@ function createContainerPool(specs, options) {
|
|
|
71575
71614
|
`Starting container ${name} for ${spec.lambda.logicalId} on ${spec.containerHost}:${hostPort}`
|
|
71576
71615
|
);
|
|
71577
71616
|
const optMount = spec.optDir ? [{ hostPath: spec.optDir, containerPath: "/opt", readOnly: true }] : [];
|
|
71617
|
+
const containerCodePath = resolveRuntimeCodeMountPath(spec.lambda.runtime);
|
|
71578
71618
|
const containerId = await runDetached({
|
|
71579
71619
|
image,
|
|
71580
|
-
mounts: [{ hostPath: spec.codeDir, containerPath:
|
|
71620
|
+
mounts: [{ hostPath: spec.codeDir, containerPath: containerCodePath, readOnly: true }],
|
|
71581
71621
|
extraMounts: optMount,
|
|
71582
71622
|
env: spec.env,
|
|
71583
71623
|
cmd: [spec.lambda.handler],
|
|
@@ -71857,10 +71897,10 @@ function buildHttpApiV2Event(req, ctx, opts = {}) {
|
|
|
71857
71897
|
const contentType = headers["content-type"] ?? "";
|
|
71858
71898
|
const { body, isBase64Encoded } = encodeBody(req.body, contentType);
|
|
71859
71899
|
const now = opts.now ? opts.now() : /* @__PURE__ */ new Date();
|
|
71860
|
-
const
|
|
71900
|
+
const routeKey = ctx.route.pathPattern === "$default" ? "$default" : `${ctx.route.method} ${ctx.route.pathPattern}`;
|
|
71861
71901
|
const event = {
|
|
71862
71902
|
version: "2.0",
|
|
71863
|
-
routeKey
|
|
71903
|
+
routeKey,
|
|
71864
71904
|
rawPath,
|
|
71865
71905
|
rawQueryString,
|
|
71866
71906
|
cookies,
|
|
@@ -71884,7 +71924,7 @@ function buildHttpApiV2Event(req, ctx, opts = {}) {
|
|
|
71884
71924
|
userAgent
|
|
71885
71925
|
},
|
|
71886
71926
|
requestId: randomUUID(),
|
|
71887
|
-
routeKey
|
|
71927
|
+
routeKey,
|
|
71888
71928
|
stage: ctx.route.stage,
|
|
71889
71929
|
time: formatRequestTime(now),
|
|
71890
71930
|
timeEpoch: now.getTime(),
|
|
@@ -73788,6 +73828,74 @@ function writeError(res, statusCode, body = '{"message":"Internal server error"}
|
|
|
73788
73828
|
res.end(body);
|
|
73789
73829
|
}
|
|
73790
73830
|
|
|
73831
|
+
// src/local/api-server-grouping.ts
|
|
73832
|
+
function groupRoutesByServer(routes) {
|
|
73833
|
+
const order = [];
|
|
73834
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
73835
|
+
for (const rwa of routes) {
|
|
73836
|
+
const r = rwa.route;
|
|
73837
|
+
let serverKey;
|
|
73838
|
+
let kind;
|
|
73839
|
+
let identifier;
|
|
73840
|
+
let displayName;
|
|
73841
|
+
if (r.source === "function-url") {
|
|
73842
|
+
identifier = r.lambdaLogicalId;
|
|
73843
|
+
serverKey = `function-url:${identifier}`;
|
|
73844
|
+
kind = "function-url";
|
|
73845
|
+
displayName = `${identifier} (Function URL)`;
|
|
73846
|
+
} else if (r.source === "http-api") {
|
|
73847
|
+
identifier = r.apiLogicalId ?? "<unknown>";
|
|
73848
|
+
serverKey = `http-api:${identifier}`;
|
|
73849
|
+
kind = "http-api";
|
|
73850
|
+
displayName = `${identifier} (HTTP API v2)`;
|
|
73851
|
+
} else {
|
|
73852
|
+
identifier = r.apiLogicalId ?? "<unknown>";
|
|
73853
|
+
serverKey = `rest-v1:${identifier}`;
|
|
73854
|
+
kind = "rest-v1";
|
|
73855
|
+
displayName = `${identifier} (REST API v1)`;
|
|
73856
|
+
}
|
|
73857
|
+
const existing = byKey.get(serverKey);
|
|
73858
|
+
if (existing) {
|
|
73859
|
+
existing.routes.push(rwa);
|
|
73860
|
+
} else {
|
|
73861
|
+
byKey.set(serverKey, { displayName, kind, identifier, routes: [rwa] });
|
|
73862
|
+
order.push(serverKey);
|
|
73863
|
+
}
|
|
73864
|
+
}
|
|
73865
|
+
return order.map((key) => {
|
|
73866
|
+
const entry = byKey.get(key);
|
|
73867
|
+
return {
|
|
73868
|
+
serverKey: key,
|
|
73869
|
+
displayName: entry.displayName,
|
|
73870
|
+
kind: entry.kind,
|
|
73871
|
+
identifier: entry.identifier,
|
|
73872
|
+
routes: entry.routes
|
|
73873
|
+
};
|
|
73874
|
+
});
|
|
73875
|
+
}
|
|
73876
|
+
function filterRoutesByApiIdentifier(routes, identifier) {
|
|
73877
|
+
return routes.filter((rwa) => {
|
|
73878
|
+
const r = rwa.route;
|
|
73879
|
+
if (r.source === "function-url") {
|
|
73880
|
+
return r.lambdaLogicalId === identifier;
|
|
73881
|
+
}
|
|
73882
|
+
return r.apiLogicalId === identifier;
|
|
73883
|
+
});
|
|
73884
|
+
}
|
|
73885
|
+
function availableApiIdentifiers(routes) {
|
|
73886
|
+
const seen = /* @__PURE__ */ new Set();
|
|
73887
|
+
const out = [];
|
|
73888
|
+
for (const rwa of routes) {
|
|
73889
|
+
const r = rwa.route;
|
|
73890
|
+
const id = r.source === "function-url" ? r.lambdaLogicalId : r.apiLogicalId ?? "<unknown>";
|
|
73891
|
+
if (!seen.has(id)) {
|
|
73892
|
+
seen.add(id);
|
|
73893
|
+
out.push(id);
|
|
73894
|
+
}
|
|
73895
|
+
}
|
|
73896
|
+
return out;
|
|
73897
|
+
}
|
|
73898
|
+
|
|
73791
73899
|
// src/local/stage-resolver.ts
|
|
73792
73900
|
function buildStageMap(template, stageOverride) {
|
|
73793
73901
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -75679,92 +75787,6 @@ function createFileWatcher(options) {
|
|
|
75679
75787
|
};
|
|
75680
75788
|
}
|
|
75681
75789
|
|
|
75682
|
-
// src/local/reload-orchestrator.ts
|
|
75683
|
-
function createReloadOrchestrator(deps) {
|
|
75684
|
-
const logger = getLogger().child("start-api-reload");
|
|
75685
|
-
let chain = Promise.resolve();
|
|
75686
|
-
return {
|
|
75687
|
-
reload() {
|
|
75688
|
-
const next = chain.then(() => runOneReload(deps, logger));
|
|
75689
|
-
chain = next.catch(() => void 0);
|
|
75690
|
-
return next;
|
|
75691
|
-
}
|
|
75692
|
-
};
|
|
75693
|
-
}
|
|
75694
|
-
async function runOneReload(deps, logger) {
|
|
75695
|
-
const previousState = deps.getServerState();
|
|
75696
|
-
const start = Date.now();
|
|
75697
|
-
let material;
|
|
75698
|
-
try {
|
|
75699
|
-
material = await deps.synthesizeAndBuild();
|
|
75700
|
-
} catch (err) {
|
|
75701
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
75702
|
-
logger.warn(`cdk synth failed during reload; keeping previous version. (${reason})`);
|
|
75703
|
-
return { ok: false, reason, added: [], removed: [], rebuiltLambdas: [] };
|
|
75704
|
-
}
|
|
75705
|
-
const oldRoutes = previousState.routes;
|
|
75706
|
-
const newRoutes = material.routes;
|
|
75707
|
-
const oldKeys = new Set(oldRoutes.map((r) => routeKey(r.route)));
|
|
75708
|
-
const newKeys = new Set(newRoutes.map((r) => routeKey(r.route)));
|
|
75709
|
-
const added = newRoutes.filter((r) => !oldKeys.has(routeKey(r.route)));
|
|
75710
|
-
const removed = oldRoutes.filter((r) => !newKeys.has(routeKey(r.route)));
|
|
75711
|
-
const previousSpecs = pickSpecsFromState(previousState);
|
|
75712
|
-
const rebuiltLambdas = [];
|
|
75713
|
-
for (const [logicalId, newSpec] of material.specs) {
|
|
75714
|
-
const oldSpec = previousSpecs.get(logicalId);
|
|
75715
|
-
if (!oldSpec)
|
|
75716
|
-
continue;
|
|
75717
|
-
if (specSignature(oldSpec) !== specSignature(newSpec)) {
|
|
75718
|
-
rebuiltLambdas.push(logicalId);
|
|
75719
|
-
}
|
|
75720
|
-
}
|
|
75721
|
-
const newPool = deps.buildPool(material.specs);
|
|
75722
|
-
Object.defineProperty(newPool, "__cdkdSpecs", {
|
|
75723
|
-
value: material.specs,
|
|
75724
|
-
enumerable: false,
|
|
75725
|
-
configurable: true
|
|
75726
|
-
});
|
|
75727
|
-
const newState = {
|
|
75728
|
-
routes: material.routes,
|
|
75729
|
-
pool: newPool,
|
|
75730
|
-
corsConfigByApiId: material.corsConfigByApiId
|
|
75731
|
-
};
|
|
75732
|
-
deps.setServerState(newState);
|
|
75733
|
-
void previousState.pool.dispose().catch(
|
|
75734
|
-
(err) => logger.debug(
|
|
75735
|
-
`Previous pool dispose() failed: ${err instanceof Error ? err.message : String(err)}`
|
|
75736
|
-
)
|
|
75737
|
-
);
|
|
75738
|
-
const elapsed = Date.now() - start;
|
|
75739
|
-
logger.info(
|
|
75740
|
-
`Reloaded in ${elapsed}ms: +${added.length} route(s), -${removed.length} route(s), ${rebuiltLambdas.length} Lambda(s) rebuilt.`
|
|
75741
|
-
);
|
|
75742
|
-
return {
|
|
75743
|
-
ok: true,
|
|
75744
|
-
added,
|
|
75745
|
-
removed,
|
|
75746
|
-
rebuiltLambdas,
|
|
75747
|
-
newState
|
|
75748
|
-
};
|
|
75749
|
-
}
|
|
75750
|
-
function routeKey(route) {
|
|
75751
|
-
return [route.method, route.pathPattern, route.lambdaLogicalId, route.source, route.apiVersion].map((s) => String(s)).join("|");
|
|
75752
|
-
}
|
|
75753
|
-
function specSignature(spec) {
|
|
75754
|
-
return JSON.stringify({
|
|
75755
|
-
codeDir: spec.codeDir,
|
|
75756
|
-
env: spec.env,
|
|
75757
|
-
handler: spec.lambda.handler,
|
|
75758
|
-
runtime: spec.lambda.runtime,
|
|
75759
|
-
containerHost: spec.containerHost,
|
|
75760
|
-
debugPort: spec.debugPort ?? null
|
|
75761
|
-
});
|
|
75762
|
-
}
|
|
75763
|
-
function pickSpecsFromState(state) {
|
|
75764
|
-
const tagged = state.pool.__cdkdSpecs;
|
|
75765
|
-
return tagged ?? /* @__PURE__ */ new Map();
|
|
75766
|
-
}
|
|
75767
|
-
|
|
75768
75790
|
// src/local/authorizer-cache.ts
|
|
75769
75791
|
function createAuthorizerCache(opts = {}) {
|
|
75770
75792
|
const now = opts.now ?? (() => Date.now());
|
|
@@ -75870,7 +75892,17 @@ async function localStartApiCommand(options) {
|
|
|
75870
75892
|
}
|
|
75871
75893
|
}
|
|
75872
75894
|
attachStageContext(routes, stageMap);
|
|
75873
|
-
|
|
75895
|
+
let routesWithAuth = attachAuthorizers(targetStacks, routes);
|
|
75896
|
+
if (options.api) {
|
|
75897
|
+
const filtered = filterRoutesByApiIdentifier(routesWithAuth, options.api);
|
|
75898
|
+
if (filtered.length === 0) {
|
|
75899
|
+
const available = availableApiIdentifiers(routesWithAuth).join(", ") || "(none)";
|
|
75900
|
+
throw new Error(
|
|
75901
|
+
`--api '${options.api}' did not match any discovered API. Available identifiers: ${available}.`
|
|
75902
|
+
);
|
|
75903
|
+
}
|
|
75904
|
+
routesWithAuth = filtered;
|
|
75905
|
+
}
|
|
75874
75906
|
const corsConfigByApiId = /* @__PURE__ */ new Map();
|
|
75875
75907
|
for (const stack of targetStacks) {
|
|
75876
75908
|
const m = buildCorsConfigByApiId(stack.template);
|
|
@@ -75923,88 +75955,91 @@ async function localStartApiCommand(options) {
|
|
|
75923
75955
|
return [...assetPaths];
|
|
75924
75956
|
};
|
|
75925
75957
|
const initialMaterial = await synthesizeAndBuild();
|
|
75926
|
-
const initialPool = buildPool(initialMaterial.specs);
|
|
75927
75958
|
lastAssetPaths.value = computeAssetPaths(initialMaterial.specs);
|
|
75928
75959
|
await prewarmJwks(initialMaterial.routes, jwksCache);
|
|
75929
75960
|
warnVpcConfigLambdas(initialMaterial.routes, initialMaterial.stacks ?? []);
|
|
75930
|
-
if (options.warm) {
|
|
75931
|
-
logger.info(`Pre-warming ${initialMaterial.specs.size} container(s)...`);
|
|
75932
|
-
const handles = await Promise.allSettled(
|
|
75933
|
-
[...initialMaterial.specs.keys()].map((id) => initialPool.acquire(id))
|
|
75934
|
-
);
|
|
75935
|
-
for (const result of handles) {
|
|
75936
|
-
if (result.status === "fulfilled") {
|
|
75937
|
-
initialPool.release(result.value);
|
|
75938
|
-
} else {
|
|
75939
|
-
logger.warn(
|
|
75940
|
-
`Pre-warm failed for one Lambda (cold start cost will apply on first request): ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`
|
|
75941
|
-
);
|
|
75942
|
-
}
|
|
75943
|
-
}
|
|
75944
|
-
}
|
|
75945
75961
|
let maxTimeoutSec = 0;
|
|
75946
75962
|
for (const spec of initialMaterial.specs.values()) {
|
|
75947
75963
|
if (spec.lambda.timeoutSec > maxTimeoutSec)
|
|
75948
75964
|
maxTimeoutSec = spec.lambda.timeoutSec;
|
|
75949
75965
|
}
|
|
75950
75966
|
const rieTimeoutMs = Math.max(3e4, maxTimeoutSec * 2 * 1e3);
|
|
75951
|
-
const
|
|
75952
|
-
if (!Number.isFinite(
|
|
75967
|
+
const basePort = parseInt(options.port, 10);
|
|
75968
|
+
if (!Number.isFinite(basePort) || basePort < 0 || basePort > 65535) {
|
|
75953
75969
|
throw new Error(`--port must be 0..65535 (got ${options.port}).`);
|
|
75954
75970
|
}
|
|
75955
|
-
const
|
|
75956
|
-
|
|
75957
|
-
|
|
75958
|
-
|
|
75959
|
-
|
|
75960
|
-
|
|
75961
|
-
|
|
75962
|
-
|
|
75963
|
-
|
|
75964
|
-
|
|
75965
|
-
|
|
75966
|
-
|
|
75967
|
-
|
|
75968
|
-
|
|
75969
|
-
|
|
75971
|
+
const initialGroups = groupRoutesByServer(initialMaterial.routes);
|
|
75972
|
+
const servers = [];
|
|
75973
|
+
let nextPort = basePort;
|
|
75974
|
+
for (const group of initialGroups) {
|
|
75975
|
+
const groupSpecs = filterSpecsForGroup(group, initialMaterial.specs);
|
|
75976
|
+
const groupPool = buildPool(groupSpecs);
|
|
75977
|
+
const groupState = {
|
|
75978
|
+
routes: group.routes,
|
|
75979
|
+
pool: groupPool,
|
|
75980
|
+
corsConfigByApiId: initialMaterial.corsConfigByApiId
|
|
75981
|
+
};
|
|
75982
|
+
if (options.warm) {
|
|
75983
|
+
logger.info(`Pre-warming ${groupSpecs.size} container(s) for ${group.displayName}...`);
|
|
75984
|
+
const handles = await Promise.allSettled(
|
|
75985
|
+
[...groupSpecs.keys()].map((id) => groupPool.acquire(id))
|
|
75986
|
+
);
|
|
75987
|
+
for (const result of handles) {
|
|
75988
|
+
if (result.status === "fulfilled") {
|
|
75989
|
+
groupPool.release(result.value);
|
|
75990
|
+
} else {
|
|
75991
|
+
logger.warn(
|
|
75992
|
+
`Pre-warm failed for one Lambda in ${group.displayName} (cold start cost will apply on first request): ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`
|
|
75993
|
+
);
|
|
75994
|
+
}
|
|
75995
|
+
}
|
|
75996
|
+
}
|
|
75997
|
+
const started = await startApiServer({
|
|
75998
|
+
state: groupState,
|
|
75999
|
+
rieTimeoutMs,
|
|
76000
|
+
host: options.host,
|
|
76001
|
+
// Increment per server; basePort=0 leaves every server on auto-alloc.
|
|
76002
|
+
port: basePort === 0 ? 0 : nextPort,
|
|
76003
|
+
authorizerCache,
|
|
76004
|
+
jwksCache,
|
|
76005
|
+
jwksWarnedUrls
|
|
76006
|
+
});
|
|
76007
|
+
servers.push({ group, server: started });
|
|
76008
|
+
if (basePort !== 0)
|
|
76009
|
+
nextPort += 1;
|
|
76010
|
+
}
|
|
76011
|
+
printPerServerRouteTables(servers);
|
|
75970
76012
|
logger.info(
|
|
75971
76013
|
`Per-Lambda concurrency: ${perLambdaConcurrency} (override with --per-lambda-concurrency)`
|
|
75972
76014
|
);
|
|
75973
|
-
|
|
75974
|
-
|
|
76015
|
+
for (const { group, server } of servers) {
|
|
76016
|
+
process.stdout.write(
|
|
76017
|
+
`Server listening on http://${server.host}:${server.port} (${group.displayName})
|
|
76018
|
+
`
|
|
76019
|
+
);
|
|
76020
|
+
}
|
|
75975
76021
|
process.stdout.write("^C to stop and clean up containers.\n");
|
|
75976
76022
|
let watcher;
|
|
75977
|
-
let
|
|
76023
|
+
let reloadChain = Promise.resolve();
|
|
75978
76024
|
if (options.watch) {
|
|
75979
|
-
orchestrator = createReloadOrchestrator({
|
|
75980
|
-
synthesizeAndBuild,
|
|
75981
|
-
buildPool,
|
|
75982
|
-
setServerState: server.setServerState,
|
|
75983
|
-
getServerState: server.getServerState
|
|
75984
|
-
});
|
|
75985
76025
|
const initialWatchPaths = [options.output, ...lastAssetPaths.value];
|
|
75986
76026
|
watcher = createFileWatcher({
|
|
75987
76027
|
paths: initialWatchPaths,
|
|
75988
76028
|
onChange: () => {
|
|
75989
|
-
if (!orchestrator)
|
|
75990
|
-
return;
|
|
75991
76029
|
logger.info("Detected file change; reloading...");
|
|
75992
|
-
|
|
75993
|
-
|
|
75994
|
-
|
|
75995
|
-
|
|
75996
|
-
|
|
75997
|
-
|
|
75998
|
-
|
|
75999
|
-
|
|
76000
|
-
|
|
76001
|
-
|
|
76002
|
-
}
|
|
76003
|
-
|
|
76004
|
-
|
|
76005
|
-
`Reload failed: ${err instanceof Error ? err.message : String(err)}. Keeping previous version.`
|
|
76006
|
-
);
|
|
76007
|
-
});
|
|
76030
|
+
const next = reloadChain.then(
|
|
76031
|
+
() => reloadAllServers({
|
|
76032
|
+
synthesizeAndBuild,
|
|
76033
|
+
servers,
|
|
76034
|
+
buildPool,
|
|
76035
|
+
computeAssetPaths,
|
|
76036
|
+
lastAssetPaths,
|
|
76037
|
+
watcher,
|
|
76038
|
+
output: options.output,
|
|
76039
|
+
logger
|
|
76040
|
+
})
|
|
76041
|
+
);
|
|
76042
|
+
reloadChain = next.catch(() => void 0);
|
|
76008
76043
|
}
|
|
76009
76044
|
});
|
|
76010
76045
|
logger.info(`Watching ${options.output} (and ${lastAssetPaths.value.length} asset dir(s))`);
|
|
@@ -76031,16 +76066,28 @@ async function localStartApiCommand(options) {
|
|
|
76031
76066
|
logger.warn(`watcher.close() failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
76032
76067
|
}
|
|
76033
76068
|
}
|
|
76034
|
-
|
|
76035
|
-
|
|
76036
|
-
|
|
76037
|
-
|
|
76038
|
-
|
|
76039
|
-
|
|
76040
|
-
|
|
76041
|
-
|
|
76042
|
-
|
|
76043
|
-
|
|
76069
|
+
await Promise.allSettled(
|
|
76070
|
+
servers.map(async ({ server, group }) => {
|
|
76071
|
+
try {
|
|
76072
|
+
await server.close();
|
|
76073
|
+
} catch (err) {
|
|
76074
|
+
logger.warn(
|
|
76075
|
+
`server.close() failed for ${group.displayName}: ${err instanceof Error ? err.message : String(err)}`
|
|
76076
|
+
);
|
|
76077
|
+
}
|
|
76078
|
+
})
|
|
76079
|
+
);
|
|
76080
|
+
await Promise.allSettled(
|
|
76081
|
+
servers.map(async ({ server, group }) => {
|
|
76082
|
+
try {
|
|
76083
|
+
await server.getServerState().pool.dispose();
|
|
76084
|
+
} catch (err) {
|
|
76085
|
+
logger.warn(
|
|
76086
|
+
`pool.dispose() failed for ${group.displayName}: ${err instanceof Error ? err.message : String(err)}`
|
|
76087
|
+
);
|
|
76088
|
+
}
|
|
76089
|
+
})
|
|
76090
|
+
);
|
|
76044
76091
|
for (const dir of inlineTmpDirs) {
|
|
76045
76092
|
try {
|
|
76046
76093
|
rmSync2(dir, { recursive: true, force: true });
|
|
@@ -76412,6 +76459,91 @@ function parsePerLambdaConcurrency(raw) {
|
|
|
76412
76459
|
}
|
|
76413
76460
|
return parsed;
|
|
76414
76461
|
}
|
|
76462
|
+
function filterSpecsForGroup(group, allSpecs) {
|
|
76463
|
+
const ids = /* @__PURE__ */ new Set();
|
|
76464
|
+
for (const rwa of group.routes) {
|
|
76465
|
+
ids.add(rwa.route.lambdaLogicalId);
|
|
76466
|
+
const auth = rwa.authorizer;
|
|
76467
|
+
if (auth && (auth.kind === "lambda-token" || auth.kind === "lambda-request")) {
|
|
76468
|
+
ids.add(auth.lambdaLogicalId);
|
|
76469
|
+
}
|
|
76470
|
+
}
|
|
76471
|
+
const out = /* @__PURE__ */ new Map();
|
|
76472
|
+
for (const id of ids) {
|
|
76473
|
+
const spec = allSpecs.get(id);
|
|
76474
|
+
if (spec)
|
|
76475
|
+
out.set(id, spec);
|
|
76476
|
+
}
|
|
76477
|
+
return out;
|
|
76478
|
+
}
|
|
76479
|
+
function printPerServerRouteTables(servers) {
|
|
76480
|
+
for (const { group, server } of servers) {
|
|
76481
|
+
process.stdout.write(`
|
|
76482
|
+
${group.displayName} (http://${server.host}:${server.port})
|
|
76483
|
+
`);
|
|
76484
|
+
printRouteTable(group.routes);
|
|
76485
|
+
}
|
|
76486
|
+
}
|
|
76487
|
+
async function reloadAllServers(args) {
|
|
76488
|
+
const {
|
|
76489
|
+
synthesizeAndBuild,
|
|
76490
|
+
servers,
|
|
76491
|
+
buildPool,
|
|
76492
|
+
computeAssetPaths,
|
|
76493
|
+
lastAssetPaths,
|
|
76494
|
+
watcher,
|
|
76495
|
+
output,
|
|
76496
|
+
logger
|
|
76497
|
+
} = args;
|
|
76498
|
+
let material;
|
|
76499
|
+
try {
|
|
76500
|
+
material = await synthesizeAndBuild();
|
|
76501
|
+
} catch (err) {
|
|
76502
|
+
logger.warn(
|
|
76503
|
+
`cdk synth failed during reload; keeping previous version. (${err instanceof Error ? err.message : String(err)})`
|
|
76504
|
+
);
|
|
76505
|
+
return;
|
|
76506
|
+
}
|
|
76507
|
+
const newGroups = groupRoutesByServer(material.routes);
|
|
76508
|
+
const newByKey = new Map(newGroups.map((g) => [g.serverKey, g]));
|
|
76509
|
+
const oldKeys = new Set(servers.map((s) => s.group.serverKey));
|
|
76510
|
+
const newKeys = new Set(newByKey.keys());
|
|
76511
|
+
const added = [...newKeys].filter((k) => !oldKeys.has(k));
|
|
76512
|
+
const removed = [...oldKeys].filter((k) => !newKeys.has(k));
|
|
76513
|
+
if (added.length > 0) {
|
|
76514
|
+
logger.warn(
|
|
76515
|
+
`Reload detected new API surface(s): ${added.join(", ")}. Restart 'cdkd local start-api' to serve them.`
|
|
76516
|
+
);
|
|
76517
|
+
}
|
|
76518
|
+
if (removed.length > 0) {
|
|
76519
|
+
logger.warn(
|
|
76520
|
+
`Reload detected removed API surface(s): ${removed.join(", ")}. Their servers will keep serving stale routes until restart.`
|
|
76521
|
+
);
|
|
76522
|
+
}
|
|
76523
|
+
for (const booted of servers) {
|
|
76524
|
+
const group = newByKey.get(booted.group.serverKey);
|
|
76525
|
+
if (!group)
|
|
76526
|
+
continue;
|
|
76527
|
+
const groupSpecs = filterSpecsForGroup(group, material.specs);
|
|
76528
|
+
const newPool = buildPool(groupSpecs);
|
|
76529
|
+
const newState = {
|
|
76530
|
+
routes: group.routes,
|
|
76531
|
+
pool: newPool,
|
|
76532
|
+
corsConfigByApiId: material.corsConfigByApiId
|
|
76533
|
+
};
|
|
76534
|
+
const previousState = booted.server.setServerState(newState);
|
|
76535
|
+
void previousState.pool.dispose().catch((err) => {
|
|
76536
|
+
logger.debug(
|
|
76537
|
+
`Previous pool dispose() failed for ${group.displayName}: ${err instanceof Error ? err.message : String(err)}`
|
|
76538
|
+
);
|
|
76539
|
+
});
|
|
76540
|
+
}
|
|
76541
|
+
lastAssetPaths.value = computeAssetPaths(material.specs);
|
|
76542
|
+
if (watcher) {
|
|
76543
|
+
watcher.update([output, ...lastAssetPaths.value]);
|
|
76544
|
+
}
|
|
76545
|
+
printPerServerRouteTables(servers);
|
|
76546
|
+
}
|
|
76415
76547
|
function parseDebugPort(raw) {
|
|
76416
76548
|
const parsed = parseInt(raw, 10);
|
|
76417
76549
|
if (!Number.isFinite(parsed) || parsed < 1 || parsed > 65535) {
|
|
@@ -76434,8 +76566,8 @@ function createLocalStartApiCommand() {
|
|
|
76434
76566
|
).addOption(new Option7("--no-pull", "Skip docker pull (cached image)")).addOption(
|
|
76435
76567
|
new Option7(
|
|
76436
76568
|
"--container-host <host>",
|
|
76437
|
-
"
|
|
76438
|
-
).default("
|
|
76569
|
+
"IP the host uses to bind/probe the RIE port (must be a numeric IP \u2014 `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1."
|
|
76570
|
+
).default("127.0.0.1")
|
|
76439
76571
|
).addOption(
|
|
76440
76572
|
new Option7(
|
|
76441
76573
|
"--debug-port-base <port>",
|
|
@@ -76461,6 +76593,11 @@ function createLocalStartApiCommand() {
|
|
|
76461
76593
|
"--stage <name>",
|
|
76462
76594
|
"Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation \u2014 HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage."
|
|
76463
76595
|
)
|
|
76596
|
+
).addOption(
|
|
76597
|
+
new Option7(
|
|
76598
|
+
"--api <id>",
|
|
76599
|
+
"Restrict to a single API surface by its logical id (HTTP API / REST API logical id, or the backing Lambda's logical id for Function URLs). When unset, every discovered API gets its own server on its own port (basePort, basePort+1, ... when --port is set; auto-allocated otherwise)."
|
|
76600
|
+
)
|
|
76464
76601
|
).action(withErrorHandling(localStartApiCommand));
|
|
76465
76602
|
[...commonOptions, ...appOptions, ...contextOptions].forEach((opt) => startApi.addOption(opt));
|
|
76466
76603
|
startApi.addOption(deprecatedRegionOption);
|
|
@@ -76670,9 +76807,10 @@ async function resolveZipImagePlan(lambda, options) {
|
|
|
76670
76807
|
const image = resolveRuntimeImage(lambda.runtime);
|
|
76671
76808
|
await pullImage(image, options.pull === false);
|
|
76672
76809
|
const layerPlan = materializeLambdaLayers2(lambda.layers);
|
|
76810
|
+
const containerCodePath = resolveRuntimeCodeMountPath(lambda.runtime);
|
|
76673
76811
|
return {
|
|
76674
76812
|
image,
|
|
76675
|
-
mounts: [{ hostPath: codeDir, containerPath:
|
|
76813
|
+
mounts: [{ hostPath: codeDir, containerPath: containerCodePath, readOnly: true }],
|
|
76676
76814
|
extraMounts: layerPlan.mount ? [layerPlan.mount] : [],
|
|
76677
76815
|
cmd: [lambda.handler],
|
|
76678
76816
|
...inlineTmpDir !== void 0 && { inlineTmpDir },
|
|
@@ -77045,7 +77183,7 @@ function reorderArgs(argv) {
|
|
|
77045
77183
|
}
|
|
77046
77184
|
async function main() {
|
|
77047
77185
|
const program = new Command16();
|
|
77048
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
77186
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.81.0");
|
|
77049
77187
|
program.addCommand(createBootstrapCommand());
|
|
77050
77188
|
program.addCommand(createSynthCommand());
|
|
77051
77189
|
program.addCommand(createListCommand());
|