cdk-local 0.110.0 → 0.112.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/dist/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +1 -73
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/{local-studio-CmriwG6o.d.ts → local-studio-BXe9E0Q0.d.ts} +75 -2
- package/dist/local-studio-BXe9E0Q0.d.ts.map +1 -0
- package/dist/{local-studio-8hdH7a_R.js → local-studio-D6yNtSFF.js} +206 -52
- package/dist/{local-studio-8hdH7a_R.js.map → local-studio-D6yNtSFF.js.map} +1 -1
- package/package.json +1 -1
- package/dist/local-studio-CmriwG6o.d.ts.map +0 -1
|
@@ -25578,7 +25578,7 @@ async function runEcsServiceEmulator(targets, options, strategy, extraStateProvi
|
|
|
25578
25578
|
sharedNetwork
|
|
25579
25579
|
};
|
|
25580
25580
|
if (frontDoor && frontDoor.listeners.length > 0) {
|
|
25581
|
-
const built = await buildFrontDoor(frontDoor, options, logger);
|
|
25581
|
+
const built = await buildFrontDoor(frontDoor, options, logger, extraStateProviders);
|
|
25582
25582
|
frontDoorServers = built.servers;
|
|
25583
25583
|
frontDoorByService = built.frontDoorByService;
|
|
25584
25584
|
frontDoorLambdaRunners = built.lambdaRunners;
|
|
@@ -26052,6 +26052,52 @@ async function resolveServiceAndRunnerOpts(boot, stacks, options, discovery, ski
|
|
|
26052
26052
|
};
|
|
26053
26053
|
}
|
|
26054
26054
|
/**
|
|
26055
|
+
* Collect the unique backing Lambdas across every forward action in the plan
|
|
26056
|
+
* (default actions + listener rules), keyed by logical id. start-service plans
|
|
26057
|
+
* have no Lambda targets so this is empty.
|
|
26058
|
+
*/
|
|
26059
|
+
function collectAlbLambdaTargets(plan) {
|
|
26060
|
+
const out = /* @__PURE__ */ new Map();
|
|
26061
|
+
const fromAction = (action) => {
|
|
26062
|
+
if (!action || action.kind !== "forward") return;
|
|
26063
|
+
for (const t of action.targets) if (t.kind === "lambda" && !out.has(t.lambda.logicalId)) out.set(t.lambda.logicalId, t.lambda);
|
|
26064
|
+
};
|
|
26065
|
+
for (const listener of plan.listeners) {
|
|
26066
|
+
fromAction(listener.defaultAction);
|
|
26067
|
+
for (const rule of listener.rules) fromAction(rule.action);
|
|
26068
|
+
}
|
|
26069
|
+
return out;
|
|
26070
|
+
}
|
|
26071
|
+
/**
|
|
26072
|
+
* Issue #380 — resolve the container env for every ALB `TargetType: lambda`
|
|
26073
|
+
* target group's backing Lambda, the SAME way `cdkl invoke` /
|
|
26074
|
+
* `cdkl start-cloudfront` do, via the shared {@link resolveLambdaContainerEnv}.
|
|
26075
|
+
* Returns a `logicalId -> LambdaContainerEnvResult` map the front-door threads
|
|
26076
|
+
* into each Lambda runner so the function's declared `Environment.Variables` +
|
|
26077
|
+
* `--from-cfn-stack` intrinsic substitution + `--assume-role` / `--profile`
|
|
26078
|
+
* creds all reach the locally-invoked Lambda. `--assume-role` collapses the
|
|
26079
|
+
* legacy `--assume-task-role` alias via {@link resolveEcsAssumeRoleOption}, and
|
|
26080
|
+
* `--env-vars` overlays the same SAM-shape `Parameters` it overlays onto the
|
|
26081
|
+
* ECS task containers. Empty when the plan carries no Lambda targets.
|
|
26082
|
+
*/
|
|
26083
|
+
async function resolveAlbLambdaTargetEnv(plan, options, extraStateProviders) {
|
|
26084
|
+
const lambdas = collectAlbLambdaTargets(plan);
|
|
26085
|
+
const out = /* @__PURE__ */ new Map();
|
|
26086
|
+
if (lambdas.size === 0) return out;
|
|
26087
|
+
const effectiveAssumeRole = resolveEcsAssumeRoleOption(options);
|
|
26088
|
+
const envOptions = {
|
|
26089
|
+
...options.fromCfnStack !== void 0 && { fromCfnStack: options.fromCfnStack },
|
|
26090
|
+
...effectiveAssumeRole !== void 0 && { assumeRole: effectiveAssumeRole },
|
|
26091
|
+
...options.region !== void 0 && { region: options.region },
|
|
26092
|
+
...options.profile !== void 0 && { profile: options.profile },
|
|
26093
|
+
...options.stackRegion !== void 0 && { stackRegion: options.stackRegion },
|
|
26094
|
+
...options.envVars !== void 0 && { envVars: options.envVars }
|
|
26095
|
+
};
|
|
26096
|
+
const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
|
|
26097
|
+
for (const [logicalId, lambda] of lambdas) out.set(logicalId, await resolveLambdaContainerEnv(lambda, envOptions, profileCredentials, extraStateProviders));
|
|
26098
|
+
return out;
|
|
26099
|
+
}
|
|
26100
|
+
/**
|
|
26055
26101
|
* Stand up one host-side reverse-proxy server PER LISTENER PORT from the
|
|
26056
26102
|
* resolved {@link FrontDoorPlan}, path-routing each request across the services
|
|
26057
26103
|
* the listener fronts, and return the started servers (for teardown) plus a
|
|
@@ -26067,21 +26113,25 @@ async function resolveServiceAndRunnerOpts(boot, stacks, options, discovery, ski
|
|
|
26067
26113
|
* already in use) every server started so far is closed and the error is
|
|
26068
26114
|
* re-thrown with a `--lb-port` hint.
|
|
26069
26115
|
*/
|
|
26070
|
-
async function buildFrontDoor(plan, options, logger) {
|
|
26116
|
+
async function buildFrontDoor(plan, options, logger, extraStateProviders) {
|
|
26071
26117
|
const containerHost = options.containerHost;
|
|
26072
26118
|
const servers = [];
|
|
26073
26119
|
const poolRegistry = /* @__PURE__ */ new Map();
|
|
26074
26120
|
const lambdaRegistry = /* @__PURE__ */ new Map();
|
|
26121
|
+
const lambdaEnvByLogicalId = await resolveAlbLambdaTargetEnv(plan, options, extraStateProviders);
|
|
26075
26122
|
const dispatchFor = (t) => {
|
|
26076
26123
|
if (t.kind === "lambda") {
|
|
26077
26124
|
let runner = lambdaRegistry.get(t.lambda.logicalId);
|
|
26078
26125
|
if (!runner) {
|
|
26126
|
+
const containerEnv = lambdaEnvByLogicalId.get(t.lambda.logicalId);
|
|
26079
26127
|
runner = createFrontDoorLambdaRunner(t.lambda, {
|
|
26080
26128
|
containerHost,
|
|
26081
26129
|
skipPull: options.pull === false,
|
|
26082
26130
|
...options.platform !== void 0 && { platformOverride: options.platform },
|
|
26083
26131
|
...options.ecrRoleArn !== void 0 && { ecrRoleArn: options.ecrRoleArn },
|
|
26084
|
-
...options.region !== void 0 && { region: options.region }
|
|
26132
|
+
...options.region !== void 0 && { region: options.region },
|
|
26133
|
+
...containerEnv !== void 0 && { containerEnv: containerEnv.env },
|
|
26134
|
+
...containerEnv !== void 0 && containerEnv.sensitiveEnvKeys.length > 0 && { sensitiveEnvKeys: new Set(containerEnv.sensitiveEnvKeys) }
|
|
26085
26135
|
});
|
|
26086
26136
|
lambdaRegistry.set(t.lambda.logicalId, runner);
|
|
26087
26137
|
}
|
|
@@ -30155,6 +30205,7 @@ const STUDIO_SCRIPT = `
|
|
|
30155
30205
|
let shownDetailId = null; // captured request whose read-only detail is shown
|
|
30156
30206
|
let pendingReqPrefill = null; // {method,path,headers,body} to seed the next serve request composer (re-invoke)
|
|
30157
30207
|
let studioDockerfiles = []; // Dockerfiles scanned at boot (pinned-ecs image-override picker)
|
|
30208
|
+
let lastAppliedCfn = null; // last-applied --from-cfn-stack (null | true | name) — a change re-loads targets (issue #385)
|
|
30158
30209
|
|
|
30159
30210
|
function el(tag, cls, text) {
|
|
30160
30211
|
const e = document.createElement(tag);
|
|
@@ -30401,7 +30452,7 @@ const STUDIO_SCRIPT = `
|
|
|
30401
30452
|
};
|
|
30402
30453
|
}
|
|
30403
30454
|
|
|
30404
|
-
// Per-backing-service image-override pickers for a pinned ALB (issue #
|
|
30455
|
+
// Per-backing-service image-override pickers for a pinned ALB (issue #384):
|
|
30405
30456
|
// one Dockerfile select per deployed-registry-pinned service the ALB fronts.
|
|
30406
30457
|
// collect() returns a { [serviceId]: dockerfile } map threaded as
|
|
30407
30458
|
// imageOverrides (one --image-override service=df per entry).
|
|
@@ -30659,7 +30710,7 @@ const STUDIO_SCRIPT = `
|
|
|
30659
30710
|
lines.push('--image-override ' + applied.imageOverride);
|
|
30660
30711
|
}
|
|
30661
30712
|
// An alb serve threads a per-backing-service imageOverrides map (issue
|
|
30662
|
-
// #
|
|
30713
|
+
// #384); surface one --image-override line each so the picks do not
|
|
30663
30714
|
// silently vanish from the running view (the issue #356 contract).
|
|
30664
30715
|
if (applied && applied.imageOverrides) {
|
|
30665
30716
|
Object.keys(applied.imageOverrides).forEach(function (svc) {
|
|
@@ -30801,7 +30852,7 @@ const STUDIO_SCRIPT = `
|
|
|
30801
30852
|
ws.appendChild(io.node);
|
|
30802
30853
|
collectImageOverride = io.collect;
|
|
30803
30854
|
}
|
|
30804
|
-
// An ALB boots its backing ECS services (issue #
|
|
30855
|
+
// An ALB boots its backing ECS services (issue #384); a pinned backing
|
|
30805
30856
|
// service has the same "local edits do not take effect" problem, so offer
|
|
30806
30857
|
// a per-service Dockerfile picker that threads
|
|
30807
30858
|
// --image-override service=dockerfile to start-alb.
|
|
@@ -31754,6 +31805,9 @@ const STUDIO_SCRIPT = `
|
|
|
31754
31805
|
cfn.checked = on;
|
|
31755
31806
|
cfnName.value = typeof c.fromCfnStack === 'string' ? c.fromCfnStack : '';
|
|
31756
31807
|
cfnName.style.display = on ? '' : 'none';
|
|
31808
|
+
// Seed the last-applied from-cfn-stack signature so the first Session-bar
|
|
31809
|
+
// edit only re-loads targets if it actually changes the binding (#385).
|
|
31810
|
+
lastAppliedCfn = on ? (typeof c.fromCfnStack === 'string' && c.fromCfnStack ? c.fromCfnStack : true) : null;
|
|
31757
31811
|
// assume-role is now checkbox-gated, symmetric with from-cfn-stack
|
|
31758
31812
|
// (issue #343): the ARN input appears only when the box is checked.
|
|
31759
31813
|
const roleOn = document.getElementById('sess-role-on');
|
|
@@ -31782,8 +31836,9 @@ const STUDIO_SCRIPT = `
|
|
|
31782
31836
|
const role = document.getElementById('sess-role');
|
|
31783
31837
|
const roleOn = document.getElementById('sess-role-on');
|
|
31784
31838
|
const msg = document.getElementById('sess-msg');
|
|
31839
|
+
const nextCfn = cfn.checked ? cfnName.value.trim() || true : null;
|
|
31785
31840
|
const body = {
|
|
31786
|
-
fromCfnStack:
|
|
31841
|
+
fromCfnStack: nextCfn,
|
|
31787
31842
|
// assume-role is explicit-ARN-only: checked + empty is simply not bound.
|
|
31788
31843
|
assumeRole: roleOn.checked ? role.value.trim() || null : null,
|
|
31789
31844
|
watch: document.getElementById('sess-watch').checked,
|
|
@@ -31801,17 +31856,32 @@ const STUDIO_SCRIPT = `
|
|
|
31801
31856
|
}
|
|
31802
31857
|
msg.textContent = '✓ applied';
|
|
31803
31858
|
setTimeout(function () { msg.textContent = ''; }, 1200);
|
|
31804
|
-
// Do NOT re-load from the server here (issue #349):
|
|
31805
|
-
// exactly what was just PATCHed, and re-loading
|
|
31806
|
-
// assume-role has no bare server form, so a
|
|
31807
|
-
// PATCHes null; re-loading would read that
|
|
31808
|
-
//
|
|
31809
|
-
//
|
|
31859
|
+
// Do NOT re-load the SESSION CONTROLS from the server here (issue #349):
|
|
31860
|
+
// the UI already shows exactly what was just PATCHed, and re-loading
|
|
31861
|
+
// CLOBBERS the controls. assume-role has no bare server form, so a
|
|
31862
|
+
// checked-but-empty assume-role PATCHes null; re-loading would read that
|
|
31863
|
+
// back and immediately UN-check the box. loadConfig() runs once on init.
|
|
31864
|
+
//
|
|
31865
|
+
// But a --from-cfn-stack change DID re-classify the targets server-side
|
|
31866
|
+
// (issue #385) — the PATCH response already reflects the new binding, and
|
|
31867
|
+
// the server swapped its target list. Re-fetch /api/targets so the
|
|
31868
|
+
// image-override pickers appear / disappear without restarting studio.
|
|
31869
|
+
// Only when the binding actually changed, so a watch / role toggle does
|
|
31870
|
+
// not needlessly rebuild the target pane. Running-serve rows are
|
|
31871
|
+
// preserved on re-render (serveState + updateServeRow drive them).
|
|
31872
|
+
if (!sameCfn(nextCfn, lastAppliedCfn)) {
|
|
31873
|
+
lastAppliedCfn = nextCfn;
|
|
31874
|
+
await loadTargets();
|
|
31875
|
+
}
|
|
31810
31876
|
} catch (err) {
|
|
31811
31877
|
msg.textContent = 'Failed: ' + err;
|
|
31812
31878
|
}
|
|
31813
31879
|
}
|
|
31814
31880
|
|
|
31881
|
+
// Two --from-cfn-stack values are the same binding when both clear (null),
|
|
31882
|
+
// both bare (true), or the same stack name.
|
|
31883
|
+
function sameCfn(a, b) { return a === b; }
|
|
31884
|
+
|
|
31815
31885
|
function wireSession() {
|
|
31816
31886
|
const cfn = document.getElementById('sess-cfn');
|
|
31817
31887
|
const cfnName = document.getElementById('sess-cfn-name');
|
|
@@ -31995,7 +32065,7 @@ function annotatePinnedEcsTargets(groups, classify) {
|
|
|
31995
32065
|
}
|
|
31996
32066
|
/**
|
|
31997
32067
|
* Annotate each `alb` entry of `groups` with the deployed-registry-pinned ECS
|
|
31998
|
-
* services that ALB fronts (issue #
|
|
32068
|
+
* services that ALB fronts (issue #384), so the alb composer can offer a
|
|
31999
32069
|
* per-service image-override Dockerfile picker. `resolveBackingPinned` maps one
|
|
32000
32070
|
* ALB entry to its pinned backing services (`{ id, label }`, where `id` is the
|
|
32001
32071
|
* `--image-override` key — `start-alb`'s `Stack:LogicalId` service-boot
|
|
@@ -32054,11 +32124,11 @@ async function startStudioServer(options) {
|
|
|
32054
32124
|
const host = options.host ?? "127.0.0.1";
|
|
32055
32125
|
const maxBump = options.maxPortBump ?? 20;
|
|
32056
32126
|
const html = renderStudioHtml(options.appLabel, options.cliName);
|
|
32057
|
-
|
|
32127
|
+
let targetsJson = JSON.stringify({
|
|
32058
32128
|
groups: options.targetGroups,
|
|
32059
32129
|
dockerfiles: options.dockerfiles ?? []
|
|
32060
32130
|
});
|
|
32061
|
-
const server = createServer$1((req, res) => handleRequest(req, res, options.bus, html, targetsJson, options));
|
|
32131
|
+
const server = createServer$1((req, res) => handleRequest(req, res, options.bus, html, () => targetsJson, options));
|
|
32062
32132
|
const boundPort = await listenWithBump(server, host, options.port, maxBump);
|
|
32063
32133
|
return {
|
|
32064
32134
|
url: `http://${host}:${boundPort}`,
|
|
@@ -32066,10 +32136,16 @@ async function startStudioServer(options) {
|
|
|
32066
32136
|
close: () => new Promise((resolveClose, reject) => {
|
|
32067
32137
|
server.close((err) => err ? reject(err) : resolveClose());
|
|
32068
32138
|
server.closeAllConnections?.();
|
|
32069
|
-
})
|
|
32139
|
+
}),
|
|
32140
|
+
setTargets: (groups, dockerfiles) => {
|
|
32141
|
+
targetsJson = JSON.stringify({
|
|
32142
|
+
groups,
|
|
32143
|
+
dockerfiles: dockerfiles ?? []
|
|
32144
|
+
});
|
|
32145
|
+
}
|
|
32070
32146
|
};
|
|
32071
32147
|
}
|
|
32072
|
-
function handleRequest(req, res, bus, html,
|
|
32148
|
+
function handleRequest(req, res, bus, html, getTargetsJson, options) {
|
|
32073
32149
|
const url = req.url ?? "/";
|
|
32074
32150
|
const path = url.split("?")[0];
|
|
32075
32151
|
if (req.method === "GET" && (path === "/" || path === "/index.html")) {
|
|
@@ -32079,7 +32155,7 @@ function handleRequest(req, res, bus, html, targetsJson, options) {
|
|
|
32079
32155
|
}
|
|
32080
32156
|
if (req.method === "GET" && path === "/api/targets") {
|
|
32081
32157
|
res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
32082
|
-
res.end(
|
|
32158
|
+
res.end(getTargetsJson());
|
|
32083
32159
|
return;
|
|
32084
32160
|
}
|
|
32085
32161
|
if (req.method === "GET" && path === "/api/running") {
|
|
@@ -33122,15 +33198,11 @@ function createStudioServeManager(config) {
|
|
|
33122
33198
|
}
|
|
33123
33199
|
function buildArgs(req, spec, envFile) {
|
|
33124
33200
|
const preferAssembly = config.watch !== true;
|
|
33125
|
-
const omitStateBindings = req.kind === "cloudfront";
|
|
33126
33201
|
return [
|
|
33127
33202
|
spec.command,
|
|
33128
33203
|
req.targetId,
|
|
33129
33204
|
...spec.portArgs,
|
|
33130
|
-
...buildSharedChildArgs(config, {
|
|
33131
|
-
preferAssembly,
|
|
33132
|
-
omitStateBindings
|
|
33133
|
-
}),
|
|
33205
|
+
...buildSharedChildArgs(config, { preferAssembly }),
|
|
33134
33206
|
...buildPerRunArgs(req.kind, req.options),
|
|
33135
33207
|
...envFile ? ["--env-vars", envFile] : [],
|
|
33136
33208
|
...req.imageOverride && req.imageOverride.trim() !== "" ? ["--image-override", req.targetId + "=" + req.imageOverride.trim()] : [],
|
|
@@ -33680,9 +33752,10 @@ async function prepareEcsImageContexts(args) {
|
|
|
33680
33752
|
* the pin resolves, and surfaces a WARN (not a silent DEBUG swallow) when a
|
|
33681
33753
|
* service still cannot be classified.
|
|
33682
33754
|
*
|
|
33683
|
-
*
|
|
33684
|
-
*
|
|
33685
|
-
*
|
|
33755
|
+
* The classifier is re-run whenever the Session-bar `--from-cfn-stack` binding
|
|
33756
|
+
* changes (`PATCH /api/config`), so the pickers appear / disappear under the
|
|
33757
|
+
* new binding without restarting studio (issue #385) — `classifyTargets`
|
|
33758
|
+
* re-invokes this against a fresh clone of the un-annotated target groups.
|
|
33686
33759
|
*
|
|
33687
33760
|
* Returns a `(id) => boolean` callback (true = pinned). Exported for testing.
|
|
33688
33761
|
*/
|
|
@@ -33700,7 +33773,7 @@ function makePinClassifier(args) {
|
|
|
33700
33773
|
}
|
|
33701
33774
|
/**
|
|
33702
33775
|
* Build the boot-time resolver `annotateAlbPinnedBackingServices` calls per
|
|
33703
|
-
* `alb` entry (issue #
|
|
33776
|
+
* `alb` entry (issue #384). It resolves the ALB to its backing ECS services
|
|
33704
33777
|
* (`resolveAlbFrontDoor`, template-only) and returns the subset that is in
|
|
33705
33778
|
* `pinnedEcsByQualifiedId` — the `ecs` services already classified as a
|
|
33706
33779
|
* deployed-registry pin by {@link makePinClassifier}. Each returned `id` is the
|
|
@@ -33740,6 +33813,86 @@ function makeAlbBackingPinnedResolver(args) {
|
|
|
33740
33813
|
}
|
|
33741
33814
|
};
|
|
33742
33815
|
}
|
|
33816
|
+
/**
|
|
33817
|
+
* Classify the studio target list for a given `--from-cfn-stack` binding
|
|
33818
|
+
* (issue #385): annotate a FRESH clone of the un-annotated base groups with the
|
|
33819
|
+
* `pinned` (ecs services) + `backingPinnedServices` (alb entries) image-override
|
|
33820
|
+
* hints, and scan the app dir for Dockerfiles when at least one target is
|
|
33821
|
+
* pinned. Returns the annotated groups + dockerfiles; the un-annotated
|
|
33822
|
+
* `baseGroups` argument is left untouched so it can be re-classified under a
|
|
33823
|
+
* different binding (the Session-bar `--from-cfn-stack` change path —
|
|
33824
|
+
* `PATCH /api/config` — re-runs this and swaps the served target list, so the
|
|
33825
|
+
* pickers appear without restarting studio). Runs once at boot and again per
|
|
33826
|
+
* binding change.
|
|
33827
|
+
*
|
|
33828
|
+
* The clone means a re-classify never inherits stale pins; the `fromCfnStack`
|
|
33829
|
+
* override is threaded into the state-source options so the pin classifier
|
|
33830
|
+
* resolves INTRINSIC-ECR images against the right (or no) deployed stack
|
|
33831
|
+
* (issue #354). Exported for unit testing.
|
|
33832
|
+
*/
|
|
33833
|
+
async function classifyStudioTargets(args) {
|
|
33834
|
+
const { baseGroups, stacks, servableEcs, options, fromCfnStack, logger } = args;
|
|
33835
|
+
const groups = structuredClone(baseGroups);
|
|
33836
|
+
const classifyOptions = {
|
|
33837
|
+
...options,
|
|
33838
|
+
fromCfnStack
|
|
33839
|
+
};
|
|
33840
|
+
const anyPinned = annotatePinnedEcsTargets(groups, makePinClassifier({
|
|
33841
|
+
stacks,
|
|
33842
|
+
contextByStack: await prepareEcsImageContexts({
|
|
33843
|
+
serviceIds: [...servableEcs],
|
|
33844
|
+
stacks,
|
|
33845
|
+
options: classifyOptions,
|
|
33846
|
+
logger
|
|
33847
|
+
}),
|
|
33848
|
+
logger
|
|
33849
|
+
}));
|
|
33850
|
+
const pinnedEcsByQualifiedId = /* @__PURE__ */ new Map();
|
|
33851
|
+
for (const g of groups) {
|
|
33852
|
+
if (g.kind !== "ecs") continue;
|
|
33853
|
+
for (const e of g.entries) if (e.pinned) pinnedEcsByQualifiedId.set(e.qualifiedId, e.id);
|
|
33854
|
+
}
|
|
33855
|
+
const anyAlbBackingPinned = annotateAlbPinnedBackingServices(groups, makeAlbBackingPinnedResolver({
|
|
33856
|
+
stacks,
|
|
33857
|
+
pinnedEcsByQualifiedId,
|
|
33858
|
+
logger
|
|
33859
|
+
}));
|
|
33860
|
+
return {
|
|
33861
|
+
groups,
|
|
33862
|
+
dockerfiles: anyPinned || anyAlbBackingPinned ? discoverDockerfiles(process.cwd()) : []
|
|
33863
|
+
};
|
|
33864
|
+
}
|
|
33865
|
+
/**
|
|
33866
|
+
* Re-classify the studio target list when the Session-bar `--from-cfn-stack`
|
|
33867
|
+
* binding changes (issue #385), and swap the served list via `applyTargets`.
|
|
33868
|
+
* The orchestration the `PATCH /api/config` handler runs, extracted so its
|
|
33869
|
+
* branches are unit-testable without booting the studio server:
|
|
33870
|
+
*
|
|
33871
|
+
* - **change gate**: returns immediately when `after === before` (a watch /
|
|
33872
|
+
* assume-role toggle does not change the pin classification);
|
|
33873
|
+
* - **latest-wins**: bumps `tokenRef.current` before the async `classify` and
|
|
33874
|
+
* applies the result ONLY if its token is still current — so a slow earlier
|
|
33875
|
+
* re-classify cannot clobber a newer binding's result when patches arrive in
|
|
33876
|
+
* quick succession;
|
|
33877
|
+
* - **fail-soft**: a `classify` rejection is WARN-logged and the previous
|
|
33878
|
+
* target list is kept (never throws — the PATCH still returns the config).
|
|
33879
|
+
*
|
|
33880
|
+
* `after` (the post-patch binding) is threaded into `classify`, never the boot
|
|
33881
|
+
* value, so the pin classifier resolves against the new stack. Exported for
|
|
33882
|
+
* unit testing.
|
|
33883
|
+
*/
|
|
33884
|
+
async function reclassifyTargetsOnBindingChange(args) {
|
|
33885
|
+
const { before, after, classify, applyTargets, tokenRef, logger } = args;
|
|
33886
|
+
if (after === before) return;
|
|
33887
|
+
logger.info("--from-cfn-stack binding changed; re-classifying targets...");
|
|
33888
|
+
const myToken = ++tokenRef.current;
|
|
33889
|
+
try {
|
|
33890
|
+
const { groups, dockerfiles } = await classify(after);
|
|
33891
|
+
if (myToken === tokenRef.current) applyTargets(groups, dockerfiles);
|
|
33892
|
+
} catch (err) {
|
|
33893
|
+
logger.warn(`studio: could not re-classify targets after a --from-cfn-stack change; the target list keeps its previous pins (restart studio to retry). ${err instanceof Error ? err.message : String(err)}`);
|
|
33894
|
+
}
|
|
33895
|
+
}
|
|
33743
33896
|
async function localStudioCommand(options) {
|
|
33744
33897
|
const logger = getLogger();
|
|
33745
33898
|
if (options.verbose) logger.setLevel("debug");
|
|
@@ -33776,27 +33929,16 @@ async function localStudioCommand(options) {
|
|
|
33776
33929
|
}
|
|
33777
33930
|
const appLabel = stacks.map((s) => s.stackName).join(", ") || appCmd;
|
|
33778
33931
|
const servableEcs = new Set(targetGroups.filter((g) => g.kind === "ecs").flatMap((g) => g.entries.filter((e) => e.servable).map((e) => e.id)));
|
|
33779
|
-
const
|
|
33780
|
-
|
|
33781
|
-
|
|
33782
|
-
serviceIds: [...servableEcs],
|
|
33783
|
-
stacks,
|
|
33784
|
-
options,
|
|
33785
|
-
logger
|
|
33786
|
-
}),
|
|
33787
|
-
logger
|
|
33788
|
-
}));
|
|
33789
|
-
const pinnedEcsByQualifiedId = /* @__PURE__ */ new Map();
|
|
33790
|
-
for (const g of targetGroups) {
|
|
33791
|
-
if (g.kind !== "ecs") continue;
|
|
33792
|
-
for (const e of g.entries) if (e.pinned) pinnedEcsByQualifiedId.set(e.qualifiedId, e.id);
|
|
33793
|
-
}
|
|
33794
|
-
const anyAlbBackingPinned = annotateAlbPinnedBackingServices(targetGroups, makeAlbBackingPinnedResolver({
|
|
33932
|
+
const baseTargetGroups = targetGroups;
|
|
33933
|
+
const classifyTargets = (fromCfnStack) => classifyStudioTargets({
|
|
33934
|
+
baseGroups: baseTargetGroups,
|
|
33795
33935
|
stacks,
|
|
33796
|
-
|
|
33936
|
+
servableEcs,
|
|
33937
|
+
options,
|
|
33938
|
+
fromCfnStack,
|
|
33797
33939
|
logger
|
|
33798
|
-
})
|
|
33799
|
-
const dockerfiles
|
|
33940
|
+
});
|
|
33941
|
+
const { groups: initialGroups, dockerfiles: initialDockerfiles } = await classifyTargets(options.fromCfnStack);
|
|
33800
33942
|
const bus = new StudioEventBus();
|
|
33801
33943
|
const childConfig = {
|
|
33802
33944
|
cliEntry: process.argv[1] ?? "",
|
|
@@ -33824,11 +33966,13 @@ async function localStudioCommand(options) {
|
|
|
33824
33966
|
watch: childConfig.watch
|
|
33825
33967
|
});
|
|
33826
33968
|
const store = createStudioStore(bus);
|
|
33969
|
+
let serverRef;
|
|
33970
|
+
const reclassifyToken = { current: 0 };
|
|
33827
33971
|
const server = await startStudioServer({
|
|
33828
33972
|
port,
|
|
33829
33973
|
bus,
|
|
33830
|
-
targetGroups,
|
|
33831
|
-
dockerfiles,
|
|
33974
|
+
targetGroups: initialGroups,
|
|
33975
|
+
dockerfiles: initialDockerfiles,
|
|
33832
33976
|
appLabel,
|
|
33833
33977
|
cliName: getEmbedConfig().cliName,
|
|
33834
33978
|
store,
|
|
@@ -33868,11 +34012,21 @@ async function localStudioCommand(options) {
|
|
|
33868
34012
|
},
|
|
33869
34013
|
getRunning: () => ({ running: serveManager.list() }),
|
|
33870
34014
|
getConfig: () => sessionConfigSnapshot(),
|
|
33871
|
-
patchConfig: (body) => {
|
|
34015
|
+
patchConfig: async (body) => {
|
|
34016
|
+
const beforeFromCfn = childConfig.fromCfnStack;
|
|
33872
34017
|
applyConfigPatch(body, childConfig);
|
|
33873
|
-
|
|
34018
|
+
await reclassifyTargetsOnBindingChange({
|
|
34019
|
+
before: beforeFromCfn,
|
|
34020
|
+
after: childConfig.fromCfnStack,
|
|
34021
|
+
classify: classifyTargets,
|
|
34022
|
+
applyTargets: (groups, dockerfiles) => serverRef?.setTargets(groups, dockerfiles),
|
|
34023
|
+
tokenRef: reclassifyToken,
|
|
34024
|
+
logger
|
|
34025
|
+
});
|
|
34026
|
+
return sessionConfigSnapshot();
|
|
33874
34027
|
}
|
|
33875
34028
|
});
|
|
34029
|
+
serverRef = server;
|
|
33876
34030
|
const cliName = getEmbedConfig().cliName;
|
|
33877
34031
|
logger.info(`${cliName} studio is running at ${server.url}`);
|
|
33878
34032
|
if (childConfig.watch) logger.info("Watch mode: ON — serves started from the UI hot-reload on CDK source changes.");
|
|
@@ -33979,4 +34133,4 @@ function addStudioSpecificOptions(cmd) {
|
|
|
33979
34133
|
|
|
33980
34134
|
//#endregion
|
|
33981
34135
|
export { createLocalRunTaskCommand as $, buildDisconnectEvent as $n, addStartApiSpecificOptions as $t, matchBehavior as A, applyCorsResponseHeaders as An, webSocketApiMatchesIdentifier as Ar, invokeAgentCoreWs as At, runViewerRequest as B, evaluateResponseParameters as Bn, pickAgentCoreCandidateStack as Br, signAgentCoreInvocation as Bt, createLocalListCommand as C, verifyJwtViaDiscovery as Cn, countTargets as Cr, DEFAULT_SHADOW_READY_TIMEOUT_MS as Ct, createLocalStartCloudFrontCommand as D, invokeRequestAuthorizer as Dn, discoverWebSocketApisOrThrow as Dr, attachContainerLogStreamer as Dt, addStartCloudFrontSpecificOptions as E, evaluateCachedLambdaPolicy as En, discoverWebSocketApis as Er, getContainerNetworkIp as Et, isCloudFrontDistribution as F, matchRoute as Fn, AGENTCORE_AGUI_PROTOCOL as Fr, MCP_PATH as Ft, parseLbPortOverrides as G, HOST_GATEWAY_MIN_VERSION as Gn, tryResolveImageFnJoin as Gr, SUPPORTED_CODE_RUNTIMES as Gt, addAlbSpecificOptions as H, selectIntegrationResponse as Hn, derivePseudoParametersFromRegion as Hr, invokeAgentCore as Ht, pickFunctionUrlLogicalIdFromOrigin as I, translateLambdaResponse as In, AGENTCORE_HTTP_PROTOCOL as Ir, MCP_PROTOCOL_VERSION as It, resolveAlbFrontDoor as J, ConnectionRegistry as Jn, resolveProfileCredentials as Jr, renderCodeDockerfile as Jt, resolveAlbTarget as K, probeHostGatewaySupport as Kn, LocalInvokeBuildError as Kr, buildAgentCoreCodeImage as Kt, pickTargetFunctionLogicalId as L, applyAuthorizerOverlay as Ln, AGENTCORE_MCP_PROTOCOL as Lr, mcpInvokeOnce as Lt, serveFromStaticOrigin as M, buildCorsConfigFromCloudFrontChain as Mn, pickRefLogicalId as Mr, A2A_PATH as Mt, serveLambdaUrlOrigin as N, isFunctionUrlOacFronted as Nn, resolveLambdaArnIntrinsic as Nr, a2aInvokeOnce as Nt, parseOriginOverrides as O, invokeTokenAuthorizer as On, filterWebSocketApisByIdentifiers as Or, addInvokeAgentCoreSpecificOptions as Ot, CLOUDFRONT_DISTRIBUTION_TYPE as P, matchPreflight as Pn, AGENTCORE_A2A_PROTOCOL as Pr, MCP_CONTAINER_PORT as Pt, addRunTaskSpecificOptions as Q, buildConnectEvent as Qn, createLocalInvokeCommand as Qt, resolveCloudFrontDistribution as R, buildHttpApiV2Event as Rn, AGENTCORE_RUNTIME_TYPE as Rr, parseSseForJsonRpc as Rt, addListSpecificOptions as S, verifyJwtAuthorizer as Sn, resolveSingleTarget as Sr, CloudMapRegistry as St, LocalStartCloudFrontError as T, computeRequestIdentityHash as Tn, availableWebSocketApiIdentifiers as Tr, setShadowReadyTimeoutMs as Tt, albStrategy as U, tryParseStatus as Un, formatStateRemedy as Ur, waitForAgentCorePing as Ut, runViewerResponse as V, pickResponseTemplate as Vn, resolveAgentCoreTarget as Vr, AGENTCORE_SESSION_ID_HEADER as Vt, createLocalStartAlbCommand as W, VtlEvaluationError as Wn, substituteImagePlaceholders as Wr, downloadAndExtractS3Bundle as Wt, createLocalStartServiceCommand as X, handleConnectionsRequest as Xn, classifySourceChange as Xt, addStartServiceSpecificOptions as Y, buildMgmtEndpointEnvUrl as Yn, toCmdArgv as Yt, serviceStrategy as Z, parseConnectionsPath as Zn, addInvokeSpecificOptions as Zt, startStudioServer as _, defaultCredentialsLoader as _n, resolveCfnStackName as _r, runImageOverrideBuilds as _t, createLocalStudioCommand as a, attachStageContext as an, resolveRuntimeImage as ar, ecsClusterOption as at, createStudioStore as b, createJwksCache as bn, resolveSsmParameters as br, listPinnedTargets as bt, startStudioProxy as c, resolveEnvVars$1 as cn, substituteAgainstStateAsync as cr, resolveEcsAssumeRoleOption as ct, createStudioDispatcher as d, filterRoutesByApiIdentifiers as dn, LocalStateSourceError as dr, ImageOverrideError as dt, createLocalStartApiCommand as en, buildMessageEvent as er, MAX_TASKS_SUBNET_RANGE_CAP as et, filterStudioCustomResources as f, groupRoutesByServer as fn, createLocalStateProvider as fr, buildImageOverrideTag as ft, filterStudioTargetGroups as g, resolveServiceIntegrationParameters as gn, resolveCfnRegion as gr, resolveImageOverrides as gt, annotatePinnedEcsTargets as h, resolveSelectionExpression as hn, resolveCfnFallbackRegion as hr, parseImageOverrideFlags as ht, coerceStopRequest as i, createFileWatcher as in, resolveRuntimeFileExtension as ir, buildEcsImageResolutionContext$1 as it, startCloudFrontServer as j, buildCorsConfigByApiId as jn, discoverRoutes as jr, A2A_CONTAINER_PORT as jt, resolveCloudFrontTarget as k, attachAuthorizers as kn, parseSelectionExpressionPath as kr, createLocalInvokeAgentCoreCommand as kt, relayServeRequest as l, availableApiIdentifiers as ln, substituteEnvVarsFromState as lr, resolveSharedSidecarCredentials as lt, annotateAlbPinnedBackingServices as m, startApiServer as mn, rejectExplicitCfnStackWithMultipleStacks as mr, mergeForService as mt, coerceRunRequest as n, resolveApiTargetSubset as nn, buildContainerImage as nr, addEcsAssumeRoleOptions as nt, resolveServeBaseUrl as o, buildStageMap as on, EcsTaskResolutionError as or, parseMaxTasks as ot, isCustomResourceLambdaTarget as p, readMtlsMaterialsFromDisk as pn, isCfnFlagPresent as pr, enforceImageOverrideOrphans as pt, isApplicationLoadBalancer as q, bufferToBody as qn, buildStsClientConfig as qr, computeCodeImageTag as qt, coerceServeRequest as r, createAuthorizerCache as rn, resolveRuntimeCodeMountPath as rr, addImageOverrideOptions as rt, createStudioServeManager as s, materializeLayerFromArn as sn, substituteAgainstState as sr, parseRestartPolicy as st, addStudioSpecificOptions as t, createWatchPredicates as tn, architectureToPlatform as tr, addCommonEcsServiceOptions as tt, reinvoke as u, filterRoutesByApiIdentifier as un, substituteEnvVarsFromStateAsync as ur, runEcsServiceEmulator as ut, toStudioTargetGroups as v, buildCognitoJwksUrl as vn, CfnLocalStateProvider as vr, describePinnedImageUri as vt, formatTargetListing as w, buildMethodArn as wn, listTargets as wr, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as wt, StudioEventBus as x, verifyCognitoJwt as xn, resolveWatchConfig as xr, buildCloudMapIndex as xt, renderStudioHtml as y, buildJwksUrlFromIssuer as yn, collectSsmParameterRefs as yr, isLocalCdkAssetImage as yt, compileCloudFrontFunction as z, buildRestV1Event as zn, AgentCoreResolutionError as zr, AGENTCORE_SIGV4_SERVICE as zt };
|
|
33982
|
-
//# sourceMappingURL=local-studio-
|
|
34136
|
+
//# sourceMappingURL=local-studio-D6yNtSFF.js.map
|