cdk-local 0.97.0 → 0.98.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 +22 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-BOLwXNkK.d.ts → local-studio-BGHLCa1m.d.ts} +14 -2
- package/dist/{local-studio-BOLwXNkK.d.ts.map → local-studio-BGHLCa1m.d.ts.map} +1 -1
- package/dist/{local-studio-BUAWok_f.js → local-studio-C_vsDHsf.js} +323 -7
- package/dist/local-studio-C_vsDHsf.js.map +1 -0
- package/package.json +1 -1
- package/dist/local-studio-BUAWok_f.js.map +0 -1
|
@@ -28525,6 +28525,21 @@ const STUDIO_CSS = `
|
|
|
28525
28525
|
border: 0; border-radius: 3px; cursor: pointer; font: inherit; font-weight: 700;
|
|
28526
28526
|
}
|
|
28527
28527
|
.composer button:hover { background: #339152; }
|
|
28528
|
+
.req-composer .req-row { display: flex; gap: 6px; margin-bottom: 6px; }
|
|
28529
|
+
.req-composer .req-method { background: #111; color: #ddd; border: 1px solid #333; border-radius: 3px;
|
|
28530
|
+
padding: 4px 6px; font: 12px ui-monospace, Menlo, monospace; }
|
|
28531
|
+
.req-composer .req-path { flex: 1; min-width: 0; background: #111; color: #ddd; border: 1px solid #333;
|
|
28532
|
+
border-radius: 3px; padding: 4px 6px; font: 12px ui-monospace, Menlo, monospace; }
|
|
28533
|
+
.req-composer textarea { width: 100%; box-sizing: border-box; min-height: 48px; resize: vertical;
|
|
28534
|
+
background: #111; color: #ddd; border: 1px solid #333; border-radius: 3px; padding: 5px;
|
|
28535
|
+
font: 12px/1.5 ui-monospace, Menlo, monospace; margin-bottom: 6px; }
|
|
28536
|
+
.req-composer .req-body { min-height: 70px; }
|
|
28537
|
+
.req-composer select:focus, .req-composer input:focus, .req-composer textarea:focus {
|
|
28538
|
+
outline: none; border-color: #4ec97a; }
|
|
28539
|
+
.req-composer .req-send { display: flex; align-items: center; gap: 10px; }
|
|
28540
|
+
.req-composer .req-send button { margin-top: 0; padding: 4px 16px; }
|
|
28541
|
+
.req-composer .req-status { margin-top: 8px; font: 12px ui-monospace, Menlo, monospace; }
|
|
28542
|
+
.req-composer .req-result pre { background: #0e0e0e; }
|
|
28528
28543
|
.composer button:disabled { background: #333; color: #888; cursor: default; }
|
|
28529
28544
|
.composer .err { color: #e0707a; margin-top: 6px; min-height: 18px; }
|
|
28530
28545
|
.section { padding: 8px 12px; border-bottom: 1px solid #222; }
|
|
@@ -29143,6 +29158,12 @@ const STUDIO_SCRIPT = `
|
|
|
29143
29158
|
const link = href(url);
|
|
29144
29159
|
epSec.appendChild(link);
|
|
29145
29160
|
}
|
|
29161
|
+
} else if (running && isEcs && st.hostUrl) {
|
|
29162
|
+
// An ecs service published via --host-port IS reachable on the host
|
|
29163
|
+
// (issue #322); show its host URL. No proxy fronts it, so requests are
|
|
29164
|
+
// not captured on the timeline.
|
|
29165
|
+
epSec.appendChild(href(st.hostUrl));
|
|
29166
|
+
epSec.appendChild(el('div', 'opt-hint', '(direct host port — not captured on the timeline)'));
|
|
29146
29167
|
} else if (running && isEcs) {
|
|
29147
29168
|
// A pure-compute ECS service has no host endpoint — it just runs the
|
|
29148
29169
|
// replicas (reach them container-to-container via Cloud Map).
|
|
@@ -29152,6 +29173,18 @@ const STUDIO_SCRIPT = `
|
|
|
29152
29173
|
}
|
|
29153
29174
|
ws.appendChild(epSec);
|
|
29154
29175
|
|
|
29176
|
+
// In-workspace HTTP request composer for a running api / alb (or ecs with
|
|
29177
|
+
// --host-port) serve (issue #322): compose a request and Send it; studio
|
|
29178
|
+
// relays it server-side (same-origin) so it works cross-port and, for
|
|
29179
|
+
// api / alb, lands on the timeline via the capture proxy.
|
|
29180
|
+
const httpBase = running
|
|
29181
|
+
? (st.endpoints || []).find((u) => /^https?:/.test(u)) || (isEcs ? st.hostUrl : null)
|
|
29182
|
+
: null;
|
|
29183
|
+
if (httpBase) {
|
|
29184
|
+
const captured = (st.endpoints || []).indexOf(httpBase) >= 0;
|
|
29185
|
+
ws.appendChild(renderRequestComposer(id, httpBase, captured));
|
|
29186
|
+
}
|
|
29187
|
+
|
|
29155
29188
|
// A served WebSocket API exposes a ws:// endpoint — attach a WebSocket
|
|
29156
29189
|
// console so the browser can connect + exchange frames (issue #303).
|
|
29157
29190
|
const wsEndpoint = running ? (st.endpoints || []).find((u) => /^wss?:/.test(u)) : null;
|
|
@@ -29166,6 +29199,111 @@ const STUDIO_SCRIPT = `
|
|
|
29166
29199
|
ws.appendChild(logSec);
|
|
29167
29200
|
}
|
|
29168
29201
|
|
|
29202
|
+
// In-workspace HTTP request composer for a running serve (issue #322):
|
|
29203
|
+
// Method + Path + Headers + Body -> Send. The request is relayed by studio's
|
|
29204
|
+
// OWN server (POST /api/request) so it reaches the served port without a
|
|
29205
|
+
// cross-origin fetch; for an api / alb serve it flows through the capture
|
|
29206
|
+
// proxy and lands on the timeline.
|
|
29207
|
+
const REQ_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
|
|
29208
|
+
|
|
29209
|
+
function parseHeaderLines(text) {
|
|
29210
|
+
const out = {};
|
|
29211
|
+
String(text || '').split('\\n').forEach(function (line) {
|
|
29212
|
+
const i = line.indexOf(':');
|
|
29213
|
+
if (i <= 0) return;
|
|
29214
|
+
const k = line.slice(0, i).trim();
|
|
29215
|
+
if (k) out[k] = line.slice(i + 1).trim();
|
|
29216
|
+
});
|
|
29217
|
+
return out;
|
|
29218
|
+
}
|
|
29219
|
+
|
|
29220
|
+
function renderRequestComposer(id, baseUrl, captured) {
|
|
29221
|
+
const sec = el('div', 'section req-composer');
|
|
29222
|
+
sec.appendChild(el('h3', null, 'Request'));
|
|
29223
|
+
const row = el('div', 'req-row');
|
|
29224
|
+
const method = el('select', 'req-method');
|
|
29225
|
+
REQ_METHODS.forEach(function (m) {
|
|
29226
|
+
const o = el('option', null, m);
|
|
29227
|
+
o.value = m;
|
|
29228
|
+
method.appendChild(o);
|
|
29229
|
+
});
|
|
29230
|
+
row.appendChild(method);
|
|
29231
|
+
const path = el('input', 'req-path');
|
|
29232
|
+
path.value = '/';
|
|
29233
|
+
path.placeholder = '/path?query';
|
|
29234
|
+
row.appendChild(path);
|
|
29235
|
+
sec.appendChild(row);
|
|
29236
|
+
|
|
29237
|
+
sec.appendChild(el('div', 'opt-label', 'Headers (one per line: Name: value)'));
|
|
29238
|
+
const headers = el('textarea', 'req-headers');
|
|
29239
|
+
headers.placeholder = 'Authorization: Bearer demo';
|
|
29240
|
+
headers.spellcheck = false;
|
|
29241
|
+
sec.appendChild(headers);
|
|
29242
|
+
|
|
29243
|
+
sec.appendChild(el('div', 'opt-label', 'Body'));
|
|
29244
|
+
const bodyTa = el('textarea', 'req-body');
|
|
29245
|
+
bodyTa.placeholder = '{ }';
|
|
29246
|
+
bodyTa.spellcheck = false;
|
|
29247
|
+
sec.appendChild(bodyTa);
|
|
29248
|
+
|
|
29249
|
+
const sendRow = el('div', 'req-send');
|
|
29250
|
+
const btn = el('button', null, 'Send');
|
|
29251
|
+
sendRow.appendChild(btn);
|
|
29252
|
+
sendRow.appendChild(
|
|
29253
|
+
el('span', 'opt-hint', captured
|
|
29254
|
+
? 'Relayed via studio to ' + baseUrl + ' — captured on the timeline.'
|
|
29255
|
+
: 'Relayed direct to ' + baseUrl + ' (ecs host port) — not captured.')
|
|
29256
|
+
);
|
|
29257
|
+
sec.appendChild(sendRow);
|
|
29258
|
+
const msg = el('div', 'err');
|
|
29259
|
+
sec.appendChild(msg);
|
|
29260
|
+
const result = el('div', 'req-result');
|
|
29261
|
+
sec.appendChild(result);
|
|
29262
|
+
|
|
29263
|
+
btn.onclick = async function () {
|
|
29264
|
+
msg.textContent = '';
|
|
29265
|
+
btn.disabled = true;
|
|
29266
|
+
btn.textContent = 'Sending…';
|
|
29267
|
+
result.innerHTML = '';
|
|
29268
|
+
try {
|
|
29269
|
+
const payload = {
|
|
29270
|
+
targetId: id,
|
|
29271
|
+
method: method.value,
|
|
29272
|
+
path: path.value || '/',
|
|
29273
|
+
headers: parseHeaderLines(headers.value),
|
|
29274
|
+
};
|
|
29275
|
+
if (bodyTa.value !== '') payload.body = bodyTa.value;
|
|
29276
|
+
const res = await fetch('/api/request', {
|
|
29277
|
+
method: 'POST',
|
|
29278
|
+
headers: { 'content-type': 'application/json' },
|
|
29279
|
+
body: JSON.stringify(payload),
|
|
29280
|
+
});
|
|
29281
|
+
const data = await res.json();
|
|
29282
|
+
if (!res.ok) {
|
|
29283
|
+
msg.textContent = 'Request failed: ' + (data.error || ('HTTP ' + res.status));
|
|
29284
|
+
return;
|
|
29285
|
+
}
|
|
29286
|
+
const statusLine = el('div', 'req-status');
|
|
29287
|
+
const cls = data.status >= 200 && data.status < 300 ? 'ok' : 'bad';
|
|
29288
|
+
statusLine.appendChild(
|
|
29289
|
+
el('span', cls, data.status + (data.durationMs != null ? ' · ' + data.durationMs + 'ms' : ''))
|
|
29290
|
+
);
|
|
29291
|
+
result.appendChild(statusLine);
|
|
29292
|
+
const hdrs = Object.keys(data.headers || {})
|
|
29293
|
+
.map(function (k) { return k + ': ' + data.headers[k]; })
|
|
29294
|
+
.join('\\n');
|
|
29295
|
+
if (hdrs) result.appendChild(el('pre', 'req-resp-headers', hdrs));
|
|
29296
|
+
result.appendChild(el('pre', null, data.body != null ? data.body : ''));
|
|
29297
|
+
} catch (err) {
|
|
29298
|
+
msg.textContent = 'Request failed: ' + err;
|
|
29299
|
+
} finally {
|
|
29300
|
+
btn.disabled = false;
|
|
29301
|
+
btn.textContent = 'Send';
|
|
29302
|
+
}
|
|
29303
|
+
};
|
|
29304
|
+
return sec;
|
|
29305
|
+
}
|
|
29306
|
+
|
|
29169
29307
|
// Build an <a> that opens an http(s) endpoint in a new tab; ws:// URLs
|
|
29170
29308
|
// are shown as plain text (not navigable in a browser tab — the WebSocket
|
|
29171
29309
|
// console below connects to them instead).
|
|
@@ -29601,7 +29739,7 @@ const STUDIO_SCRIPT = `
|
|
|
29601
29739
|
if (ev.status === 'stopped' || ev.status === 'error') {
|
|
29602
29740
|
serveState.set(ev.target, { status: ev.status, endpoints: [] });
|
|
29603
29741
|
} else {
|
|
29604
|
-
serveState.set(ev.target, { status: ev.status, endpoints: ev.endpoints || [] });
|
|
29742
|
+
serveState.set(ev.target, { status: ev.status, endpoints: ev.endpoints || [], hostUrl: ev.hostUrl });
|
|
29605
29743
|
}
|
|
29606
29744
|
updateServeRow(ev.target);
|
|
29607
29745
|
}
|
|
@@ -29969,6 +30107,10 @@ function handleRequest(req, res, bus, html, targetsJson, options) {
|
|
|
29969
30107
|
handleDispatch(req, res, options.onRun);
|
|
29970
30108
|
return;
|
|
29971
30109
|
}
|
|
30110
|
+
if (req.method === "POST" && path === "/api/request") {
|
|
30111
|
+
handleDispatch(req, res, options.onServeRequest);
|
|
30112
|
+
return;
|
|
30113
|
+
}
|
|
29972
30114
|
if (req.method === "POST" && path === "/api/stop") {
|
|
29973
30115
|
handleDispatch(req, res, options.onStop);
|
|
29974
30116
|
return;
|
|
@@ -30117,10 +30259,16 @@ function listenWithBump(server, host, port, maxBump) {
|
|
|
30117
30259
|
* Build the shared `--app` / `--profile` / `--region` / `-c` /
|
|
30118
30260
|
* `--from-cfn-stack` / `--assume-role` args for a studio child command.
|
|
30119
30261
|
* Returns a flat argv fragment to spread after the subcommand + target.
|
|
30262
|
+
*
|
|
30263
|
+
* When `opts.preferAssembly` is true and `config.assemblyDir` is set, the
|
|
30264
|
+
* `--app` value is the once-synthesized cloud-assembly directory so the
|
|
30265
|
+
* child reads it and skips a redundant synth (issue #324); otherwise it is
|
|
30266
|
+
* the app command (`config.app`).
|
|
30120
30267
|
*/
|
|
30121
|
-
function buildSharedChildArgs(config) {
|
|
30268
|
+
function buildSharedChildArgs(config, opts = {}) {
|
|
30122
30269
|
const args = [];
|
|
30123
|
-
|
|
30270
|
+
const appValue = opts.preferAssembly && config.assemblyDir ? config.assemblyDir : config.app;
|
|
30271
|
+
if (appValue) args.push("--app", appValue);
|
|
30124
30272
|
if (config.profile) args.push("--profile", config.profile);
|
|
30125
30273
|
if (config.region) args.push("--region", config.region);
|
|
30126
30274
|
for (const [k, v] of Object.entries(config.context ?? {})) args.push("-c", `${k}=${v}`);
|
|
@@ -30215,7 +30363,7 @@ function createStudioDispatcher(config) {
|
|
|
30215
30363
|
req.targetId,
|
|
30216
30364
|
"--event",
|
|
30217
30365
|
eventFile,
|
|
30218
|
-
...buildSharedChildArgs(config),
|
|
30366
|
+
...buildSharedChildArgs(config, { preferAssembly: true }),
|
|
30219
30367
|
...buildPerRunArgs(req.kind, req.options)
|
|
30220
30368
|
];
|
|
30221
30369
|
const envVars = resolveEnvVars(req.kind, req.options);
|
|
@@ -30411,6 +30559,62 @@ function tryParseJson(raw) {
|
|
|
30411
30559
|
}
|
|
30412
30560
|
}
|
|
30413
30561
|
|
|
30562
|
+
//#endregion
|
|
30563
|
+
//#region src/local/studio-request-relay.ts
|
|
30564
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
30565
|
+
const DEFAULT_MAX_BODY = 512 * 1024;
|
|
30566
|
+
const BODY_METHODS = new Set([
|
|
30567
|
+
"POST",
|
|
30568
|
+
"PUT",
|
|
30569
|
+
"PATCH",
|
|
30570
|
+
"DELETE"
|
|
30571
|
+
]);
|
|
30572
|
+
/** Join a base URL and a path without doubling or dropping the `/`. */
|
|
30573
|
+
function joinUrl(baseUrl, path) {
|
|
30574
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
30575
|
+
if (!path || path === "") return base + "/";
|
|
30576
|
+
return base + (path.startsWith("/") ? path : "/" + path);
|
|
30577
|
+
}
|
|
30578
|
+
/**
|
|
30579
|
+
* Perform one HTTP request against a running serve and return a bounded
|
|
30580
|
+
* response. `fetchFn` is injectable for tests (defaults to the global `fetch`).
|
|
30581
|
+
* Throws on a network / timeout error (the caller maps it to a 502/500); an
|
|
30582
|
+
* HTTP error status is a NORMAL result (returned, not thrown).
|
|
30583
|
+
*/
|
|
30584
|
+
async function relayServeRequest(input, fetchFn = fetch, clock = Date.now) {
|
|
30585
|
+
const method = input.method.toUpperCase();
|
|
30586
|
+
const url = joinUrl(input.baseUrl, input.path);
|
|
30587
|
+
const maxBody = input.maxBodyChars ?? DEFAULT_MAX_BODY;
|
|
30588
|
+
const controller = new AbortController();
|
|
30589
|
+
const timer = setTimeout(() => controller.abort(), input.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
30590
|
+
const startedAt = clock();
|
|
30591
|
+
try {
|
|
30592
|
+
const res = await fetchFn(url, {
|
|
30593
|
+
method,
|
|
30594
|
+
headers: input.headers ?? {},
|
|
30595
|
+
...BODY_METHODS.has(method) && input.body !== void 0 ? { body: input.body } : {},
|
|
30596
|
+
signal: controller.signal,
|
|
30597
|
+
redirect: "manual"
|
|
30598
|
+
});
|
|
30599
|
+
const headers = {};
|
|
30600
|
+
res.headers.forEach((value, key) => {
|
|
30601
|
+
headers[key] = value;
|
|
30602
|
+
});
|
|
30603
|
+
const full = await res.text();
|
|
30604
|
+
const truncated = full.length > maxBody;
|
|
30605
|
+
const body = truncated ? full.slice(0, maxBody) + "\n…[truncated]" : full;
|
|
30606
|
+
return {
|
|
30607
|
+
status: res.status,
|
|
30608
|
+
headers,
|
|
30609
|
+
body,
|
|
30610
|
+
truncated,
|
|
30611
|
+
durationMs: clock() - startedAt
|
|
30612
|
+
};
|
|
30613
|
+
} finally {
|
|
30614
|
+
clearTimeout(timer);
|
|
30615
|
+
}
|
|
30616
|
+
}
|
|
30617
|
+
|
|
30414
30618
|
//#endregion
|
|
30415
30619
|
//#region src/local/studio-proxy.ts
|
|
30416
30620
|
let proxyIdCounter = 0;
|
|
@@ -30689,6 +30893,7 @@ function createStudioServeManager(config) {
|
|
|
30689
30893
|
startedAt: e.startedAt
|
|
30690
30894
|
};
|
|
30691
30895
|
if (e.pid !== void 0) s.pid = e.pid;
|
|
30896
|
+
if (e.hostUrl !== void 0) s.hostUrl = e.hostUrl;
|
|
30692
30897
|
return s;
|
|
30693
30898
|
}
|
|
30694
30899
|
function emitServe(e, message) {
|
|
@@ -30700,15 +30905,17 @@ function createStudioServeManager(config) {
|
|
|
30700
30905
|
endpoints: [...e.endpoints]
|
|
30701
30906
|
};
|
|
30702
30907
|
if (e.pid !== void 0) ev.pid = e.pid;
|
|
30908
|
+
if (e.hostUrl !== void 0) ev.hostUrl = e.hostUrl;
|
|
30703
30909
|
if (message !== void 0) ev.message = message;
|
|
30704
30910
|
config.bus.emit("serve", ev);
|
|
30705
30911
|
}
|
|
30706
30912
|
function buildArgs(req, spec) {
|
|
30913
|
+
const preferAssembly = config.watch !== true;
|
|
30707
30914
|
return [
|
|
30708
30915
|
spec.command,
|
|
30709
30916
|
req.targetId,
|
|
30710
30917
|
...spec.portArgs,
|
|
30711
|
-
...buildSharedChildArgs(config),
|
|
30918
|
+
...buildSharedChildArgs(config, { preferAssembly }),
|
|
30712
30919
|
...buildPerRunArgs(req.kind, req.options),
|
|
30713
30920
|
...req.imageOverride && req.imageOverride.trim() !== "" ? ["--image-override", req.targetId + "=" + req.imageOverride.trim()] : [],
|
|
30714
30921
|
...config.watch === true ? ["--watch"] : [],
|
|
@@ -30737,6 +30944,13 @@ function createStudioServeManager(config) {
|
|
|
30737
30944
|
proxies: []
|
|
30738
30945
|
};
|
|
30739
30946
|
if (child.pid !== void 0) entry.pid = child.pid;
|
|
30947
|
+
if (req.kind === "ecs") {
|
|
30948
|
+
const hp = req.options?.["--host-port"];
|
|
30949
|
+
if (Array.isArray(hp)) {
|
|
30950
|
+
const first = hp.find((r) => r && typeof r === "object" && typeof r.right === "string" && r.right.trim() !== "");
|
|
30951
|
+
if (first) entry.hostUrl = "http://127.0.0.1:" + first.right.trim();
|
|
30952
|
+
}
|
|
30953
|
+
}
|
|
30740
30954
|
entries.set(req.targetId, entry);
|
|
30741
30955
|
emitServe(entry);
|
|
30742
30956
|
return new Promise((resolve, reject) => {
|
|
@@ -30974,6 +31188,60 @@ function coerceStopRequest(body) {
|
|
|
30974
31188
|
if (typeof targetId !== "string" || targetId.trim() === "") throw new Error("Request body must include a non-empty \"targetId\" string.");
|
|
30975
31189
|
return { targetId };
|
|
30976
31190
|
}
|
|
31191
|
+
const SERVE_REQUEST_METHODS = new Set([
|
|
31192
|
+
"GET",
|
|
31193
|
+
"POST",
|
|
31194
|
+
"PUT",
|
|
31195
|
+
"PATCH",
|
|
31196
|
+
"DELETE",
|
|
31197
|
+
"HEAD",
|
|
31198
|
+
"OPTIONS"
|
|
31199
|
+
]);
|
|
31200
|
+
/**
|
|
31201
|
+
* Pick the HTTP base URL the request composer relays to for a running serve
|
|
31202
|
+
* (issue #322): the first `http(s)://` endpoint (the api / alb capture-proxy
|
|
31203
|
+
* URL — a `ws://` WebSocket-API endpoint is NOT relayable, so it is skipped),
|
|
31204
|
+
* else the ecs `--host-port` host URL, else `undefined` (no reachable HTTP
|
|
31205
|
+
* endpoint). Exported so the relay base-URL choice is unit-testable.
|
|
31206
|
+
*/
|
|
31207
|
+
function resolveServeBaseUrl(state) {
|
|
31208
|
+
return (state.endpoints || []).find((u) => /^https?:/.test(u)) ?? state.hostUrl;
|
|
31209
|
+
}
|
|
31210
|
+
/**
|
|
31211
|
+
* Validate + narrow the untyped `POST /api/request` body (issue #322). Throws
|
|
31212
|
+
* on a malformed body; the studio server surfaces a thrown handler error as a
|
|
31213
|
+
* 500 (the same convention as {@link coerceRunRequest} / {@link
|
|
31214
|
+
* coerceStopRequest}) so a bad UI / curl payload fails loudly rather than
|
|
31215
|
+
* relaying a bogus request.
|
|
31216
|
+
*/
|
|
31217
|
+
function coerceServeRequest(body) {
|
|
31218
|
+
if (typeof body !== "object" || body === null) throw new Error("Request body must be a JSON object.");
|
|
31219
|
+
const { targetId, method, path, headers, body: reqBody } = body;
|
|
31220
|
+
if (typeof targetId !== "string" || targetId.trim() === "") throw new Error("Request body must include a non-empty \"targetId\" string.");
|
|
31221
|
+
if (typeof method !== "string" || !SERVE_REQUEST_METHODS.has(method.toUpperCase())) throw new Error(`Request body "method" must be one of: ${[...SERVE_REQUEST_METHODS].join(", ")}.`);
|
|
31222
|
+
const out = {
|
|
31223
|
+
targetId,
|
|
31224
|
+
method: method.toUpperCase()
|
|
31225
|
+
};
|
|
31226
|
+
if (path !== void 0) {
|
|
31227
|
+
if (typeof path !== "string") throw new Error("Request body \"path\" must be a string.");
|
|
31228
|
+
out.path = path;
|
|
31229
|
+
}
|
|
31230
|
+
if (headers !== void 0) {
|
|
31231
|
+
if (typeof headers !== "object" || headers === null || Array.isArray(headers)) throw new Error("Request body \"headers\" must be a JSON object of string values.");
|
|
31232
|
+
const h = {};
|
|
31233
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
31234
|
+
if (typeof v !== "string") throw new Error(`Request header "${k}" must be a string.`);
|
|
31235
|
+
if (k.trim() !== "") h[k] = v;
|
|
31236
|
+
}
|
|
31237
|
+
out.headers = h;
|
|
31238
|
+
}
|
|
31239
|
+
if (reqBody !== void 0) {
|
|
31240
|
+
if (typeof reqBody !== "string") throw new Error("Request body \"body\" must be a string.");
|
|
31241
|
+
out.body = reqBody;
|
|
31242
|
+
}
|
|
31243
|
+
return out;
|
|
31244
|
+
}
|
|
30977
31245
|
/**
|
|
30978
31246
|
* Validate a `PATCH /api/config` body and apply the editable run-time
|
|
30979
31247
|
* bindings (`fromCfnStack` / `assumeRole`) onto `target` in place. Only the
|
|
@@ -31017,6 +31285,38 @@ function parseStudioPort(raw) {
|
|
|
31017
31285
|
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(`--studio-port must be 0..65535 (got ${raw}).`);
|
|
31018
31286
|
return port;
|
|
31019
31287
|
}
|
|
31288
|
+
/**
|
|
31289
|
+
* Resolve the on-disk cloud-assembly directory the boot synth produced, so
|
|
31290
|
+
* studio can forward `--app <assemblyDir>` to NON-watch children and skip a
|
|
31291
|
+
* redundant re-synth (issue #324). Returns the absolute path when a
|
|
31292
|
+
* reusable assembly directory exists, else `undefined` (children then fall
|
|
31293
|
+
* back to forwarding the app command).
|
|
31294
|
+
*
|
|
31295
|
+
* Two cases yield a reusable dir:
|
|
31296
|
+
* 1. `--app` is itself a pre-synthesized assembly directory — `synthesize`
|
|
31297
|
+
* read it in place (no `--output` write), so we reuse that very dir.
|
|
31298
|
+
* 2. `--app` is a CDK app command — the synth wrote the assembly to
|
|
31299
|
+
* `--output` (default `cdk.out`), so we reuse that.
|
|
31300
|
+
*
|
|
31301
|
+
* The existence check is defensive: if neither path is a directory on disk
|
|
31302
|
+
* (an unusual synth setup), we return `undefined` rather than hand a child
|
|
31303
|
+
* a `--app` that points at nothing.
|
|
31304
|
+
*
|
|
31305
|
+
* Exported for unit testing.
|
|
31306
|
+
*/
|
|
31307
|
+
function resolveBootAssemblyDir(appCmd, output) {
|
|
31308
|
+
const isDir = (p) => {
|
|
31309
|
+
try {
|
|
31310
|
+
return existsSync(p) && statSync(p).isDirectory();
|
|
31311
|
+
} catch {
|
|
31312
|
+
return false;
|
|
31313
|
+
}
|
|
31314
|
+
};
|
|
31315
|
+
const appPath = resolve(appCmd);
|
|
31316
|
+
if (isDir(appPath)) return appPath;
|
|
31317
|
+
const outPath = resolve(output);
|
|
31318
|
+
if (isDir(outPath)) return outPath;
|
|
31319
|
+
}
|
|
31020
31320
|
async function localStudioCommand(options) {
|
|
31021
31321
|
const logger = getLogger();
|
|
31022
31322
|
if (options.verbose) logger.setLevel("debug");
|
|
@@ -31038,6 +31338,7 @@ async function localStudioCommand(options) {
|
|
|
31038
31338
|
...Object.keys(context).length > 0 && { context }
|
|
31039
31339
|
};
|
|
31040
31340
|
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
31341
|
+
const assemblyDir = resolveBootAssemblyDir(appCmd, options.output);
|
|
31041
31342
|
const targetGroups = filterStudioTargetGroups(toStudioTargetGroups(listTargets(stacks)), options.stack);
|
|
31042
31343
|
if (options.stack && options.stack.length > 0) {
|
|
31043
31344
|
const shown = targetGroups.reduce((n, g) => n + g.entries.length, 0);
|
|
@@ -31060,6 +31361,7 @@ async function localStudioCommand(options) {
|
|
|
31060
31361
|
bus,
|
|
31061
31362
|
cwd: process.cwd(),
|
|
31062
31363
|
...appCmd ? { app: appCmd } : {},
|
|
31364
|
+
...assemblyDir ? { assemblyDir } : {},
|
|
31063
31365
|
...options.profile ? { profile: options.profile } : {},
|
|
31064
31366
|
...options.region ? { region: options.region } : {},
|
|
31065
31367
|
...Object.keys(context).length > 0 ? { context } : {},
|
|
@@ -31099,6 +31401,20 @@ async function localStudioCommand(options) {
|
|
|
31099
31401
|
await serveManager.stop(req);
|
|
31100
31402
|
return { stopped: req.targetId };
|
|
31101
31403
|
},
|
|
31404
|
+
onServeRequest: async (body) => {
|
|
31405
|
+
const req = coerceServeRequest(body);
|
|
31406
|
+
const state = serveManager.list().find((s) => s.targetId === req.targetId);
|
|
31407
|
+
if (!state || state.status !== "running") throw new Error(`'${req.targetId}' is not a running serve target.`);
|
|
31408
|
+
const baseUrl = resolveServeBaseUrl(state);
|
|
31409
|
+
if (!baseUrl) throw new Error(`'${req.targetId}' has no reachable HTTP endpoint (an ecs service needs --host-port).`);
|
|
31410
|
+
return await relayServeRequest({
|
|
31411
|
+
baseUrl,
|
|
31412
|
+
method: req.method,
|
|
31413
|
+
...req.path !== void 0 ? { path: req.path } : {},
|
|
31414
|
+
...req.headers !== void 0 ? { headers: req.headers } : {},
|
|
31415
|
+
...req.body !== void 0 ? { body: req.body } : {}
|
|
31416
|
+
});
|
|
31417
|
+
},
|
|
31102
31418
|
getRunning: () => ({ running: serveManager.list() }),
|
|
31103
31419
|
getConfig: () => sessionConfigSnapshot(),
|
|
31104
31420
|
patchConfig: (body) => {
|
|
@@ -31180,5 +31496,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
31180
31496
|
}
|
|
31181
31497
|
|
|
31182
31498
|
//#endregion
|
|
31183
|
-
export {
|
|
31184
|
-
//# sourceMappingURL=local-studio-
|
|
31499
|
+
export { listPinnedTargets as $, resolveSsmParameters as $n, createJwksCache as $t, serviceStrategy as A, parseConnectionsPath as An, addInvokeSpecificOptions as At, parseRestartPolicy as B, substituteAgainstState as Bn, materializeLayerFromArn as Bt, createLocalStartAlbCommand as C, VtlEvaluationError as Cn, substituteImagePlaceholders as Cr, downloadAndExtractS3Bundle as Ct, resolveAlbFrontDoor as D, ConnectionRegistry as Dn, resolveProfileCredentials as Dr, renderCodeDockerfile as Dt, isApplicationLoadBalancer as E, bufferToBody as En, buildStsClientConfig as Er, computeCodeImageTag as Et, addEcsAssumeRoleOptions as F, buildContainerImage as Fn, resolveApiTargetSubset as Ft, buildImageOverrideTag as G, createLocalStateProvider as Gn, groupRoutesByServer as Gt, resolveSharedSidecarCredentials as H, substituteEnvVarsFromState as Hn, availableApiIdentifiers as Ht, addImageOverrideOptions as I, resolveRuntimeCodeMountPath as In, createAuthorizerCache as It, parseImageOverrideFlags as J, resolveCfnFallbackRegion as Jn, resolveSelectionExpression as Jt, enforceImageOverrideOrphans as K, isCfnFlagPresent as Kn, readMtlsMaterialsFromDisk as Kt, buildEcsImageResolutionContext$1 as L, resolveRuntimeFileExtension as Ln, createFileWatcher as Lt, createLocalRunTaskCommand as M, buildDisconnectEvent as Mn, addStartApiSpecificOptions as Mt, MAX_TASKS_SUBNET_RANGE_CAP as N, buildMessageEvent as Nn, createLocalStartApiCommand as Nt, addStartServiceSpecificOptions as O, buildMgmtEndpointEnvUrl as On, toCmdArgv as Ot, addCommonEcsServiceOptions as P, architectureToPlatform as Pn, createWatchPredicates as Pt, isLocalCdkAssetImage as Q, collectSsmParameterRefs as Qn, buildJwksUrlFromIssuer as Qt, ecsClusterOption as R, resolveRuntimeImage as Rn, attachStageContext as Rt, albStrategy as S, tryParseStatus as Sn, formatStateRemedy as Sr, waitForAgentCorePing as St, resolveAlbTarget as T, probeHostGatewaySupport as Tn, LocalInvokeBuildError as Tr, buildAgentCoreCodeImage as Tt, runEcsServiceEmulator as U, substituteEnvVarsFromStateAsync as Un, filterRoutesByApiIdentifier as Ut, resolveEcsAssumeRoleOption as V, substituteAgainstStateAsync as Vn, resolveEnvVars$1 as Vt, ImageOverrideError as W, LocalStateSourceError as Wn, filterRoutesByApiIdentifiers as Wt, runImageOverrideBuilds as X, resolveCfnStackName as Xn, defaultCredentialsLoader as Xt, resolveImageOverrides as Y, resolveCfnRegion as Yn, resolveServiceIntegrationParameters as Yt, describePinnedImageUri as Z, CfnLocalStateProvider as Zn, buildCognitoJwksUrl as Zt, StudioEventBus as _, buildHttpApiV2Event as _n, AGENTCORE_RUNTIME_TYPE as _r, parseSseForJsonRpc as _t, createLocalStudioCommand as a, evaluateCachedLambdaPolicy as an, discoverWebSocketApis as ar, getContainerNetworkIp as at, formatTargetListing as b, pickResponseTemplate as bn, resolveAgentCoreTarget as br, AGENTCORE_SESSION_ID_HEADER as bt, startStudioProxy as c, attachAuthorizers as cn, parseSelectionExpressionPath as cr, createLocalInvokeAgentCoreCommand as ct, annotatePinnedEcsTargets as d, buildCorsConfigFromCloudFrontChain as dn, pickRefLogicalId as dr, A2A_PATH as dt, verifyCognitoJwt as en, resolveWatchConfig as er, buildCloudMapIndex as et, filterStudioTargetGroups as f, isFunctionUrlOacFronted as fn, resolveLambdaArnIntrinsic as fr, a2aInvokeOnce as ft, createStudioStore as g, applyAuthorizerOverlay as gn, AGENTCORE_MCP_PROTOCOL as gr, mcpInvokeOnce as gt, renderStudioHtml as h, translateLambdaResponse as hn, AGENTCORE_HTTP_PROTOCOL as hr, MCP_PROTOCOL_VERSION as ht, coerceStopRequest as i, computeRequestIdentityHash as in, availableWebSocketApiIdentifiers as ir, setShadowReadyTimeoutMs as it, addRunTaskSpecificOptions as j, buildConnectEvent as jn, createLocalInvokeCommand as jt, createLocalStartServiceCommand as k, handleConnectionsRequest as kn, classifySourceChange as kt, relayServeRequest as l, applyCorsResponseHeaders as ln, webSocketApiMatchesIdentifier as lr, invokeAgentCoreWs as lt, toStudioTargetGroups as m, matchRoute as mn, AGENTCORE_AGUI_PROTOCOL as mr, MCP_PATH as mt, coerceRunRequest as n, verifyJwtViaDiscovery as nn, countTargets as nr, DEFAULT_SHADOW_READY_TIMEOUT_MS as nt, resolveServeBaseUrl as o, invokeRequestAuthorizer as on, discoverWebSocketApisOrThrow as or, attachContainerLogStreamer as ot, startStudioServer as p, matchPreflight as pn, AGENTCORE_A2A_PROTOCOL as pr, MCP_CONTAINER_PORT as pt, mergeForService as q, rejectExplicitCfnStackWithMultipleStacks as qn, startApiServer as qt, coerceServeRequest as r, buildMethodArn as rn, listTargets as rr, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as rt, createStudioServeManager as s, invokeTokenAuthorizer as sn, filterWebSocketApisByIdentifiers as sr, addInvokeAgentCoreSpecificOptions as st, addStudioSpecificOptions as t, verifyJwtAuthorizer as tn, resolveSingleTarget as tr, CloudMapRegistry as tt, createStudioDispatcher as u, buildCorsConfigByApiId as un, discoverRoutes as ur, A2A_CONTAINER_PORT as ut, addListSpecificOptions as v, buildRestV1Event as vn, AgentCoreResolutionError as vr, AGENTCORE_SIGV4_SERVICE as vt, parseLbPortOverrides as w, HOST_GATEWAY_MIN_VERSION as wn, tryResolveImageFnJoin as wr, SUPPORTED_CODE_RUNTIMES as wt, addAlbSpecificOptions as x, selectIntegrationResponse as xn, derivePseudoParametersFromRegion as xr, invokeAgentCore as xt, createLocalListCommand as y, evaluateResponseParameters as yn, pickAgentCoreCandidateStack as yr, signAgentCoreInvocation as yt, parseMaxTasks as z, EcsTaskResolutionError as zn, buildStageMap as zt };
|
|
31500
|
+
//# sourceMappingURL=local-studio-C_vsDHsf.js.map
|