@kvell007/embed-labs-cli 0.1.0-alpha.22 → 0.1.0-alpha.23
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/index.js +107 -11
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1392,19 +1392,34 @@ function isApiResponse(value) {
|
|
|
1392
1392
|
return isJsonObject(error) && typeof error.code === "string" && typeof error.message === "string";
|
|
1393
1393
|
}
|
|
1394
1394
|
async function bridgeGet(path) {
|
|
1395
|
-
|
|
1396
|
-
headers: bridgeHeaders("GET", path, "")
|
|
1397
|
-
});
|
|
1398
|
-
return await response.json();
|
|
1395
|
+
return await bridgeRequest("GET", path);
|
|
1399
1396
|
}
|
|
1400
1397
|
async function bridgePost(path, body) {
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1398
|
+
return await bridgeRequest("POST", path, body);
|
|
1399
|
+
}
|
|
1400
|
+
async function bridgeRequest(method, path, body) {
|
|
1401
|
+
const bodyText = body === undefined ? "" : JSON.stringify(body);
|
|
1402
|
+
const makeRequest = async () => {
|
|
1403
|
+
const response = await fetch(`${DEFAULT_BRIDGE_URL}${path}`, {
|
|
1404
|
+
method,
|
|
1405
|
+
headers: bridgeHeaders(method, path, method === "POST" ? bodyText : "", method === "POST" ? { "content-type": "application/json" } : {}),
|
|
1406
|
+
body: method === "POST" ? bodyText : undefined
|
|
1407
|
+
});
|
|
1408
|
+
return await response.json();
|
|
1409
|
+
};
|
|
1410
|
+
try {
|
|
1411
|
+
return await makeRequest();
|
|
1412
|
+
}
|
|
1413
|
+
catch (error) {
|
|
1414
|
+
if (!isBridgeConnectionFailure(error)) {
|
|
1415
|
+
throw error;
|
|
1416
|
+
}
|
|
1417
|
+
const started = await ensureBridgeStartedForRequest();
|
|
1418
|
+
if (!started.ok) {
|
|
1419
|
+
return started;
|
|
1420
|
+
}
|
|
1421
|
+
return await makeRequest();
|
|
1422
|
+
}
|
|
1408
1423
|
}
|
|
1409
1424
|
function bridgeHeaders(method, path, bodyText, base = {}) {
|
|
1410
1425
|
const token = process.env.EMBED_BRIDGE_TOKEN?.trim();
|
|
@@ -1433,6 +1448,87 @@ function addBridgeRequestSignature(headers, method, pathWithQuery, bodyText, tok
|
|
|
1433
1448
|
headers["x-embed-body-sha256"] = bodySha256;
|
|
1434
1449
|
headers["x-embed-signature"] = createHmac("sha256", token).update(canonical).digest("hex");
|
|
1435
1450
|
}
|
|
1451
|
+
function isBridgeConnectionFailure(error) {
|
|
1452
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1453
|
+
return message.includes("fetch failed") ||
|
|
1454
|
+
message.includes("ECONNREFUSED") ||
|
|
1455
|
+
message.includes("ECONNRESET") ||
|
|
1456
|
+
message.includes("UND_ERR_SOCKET");
|
|
1457
|
+
}
|
|
1458
|
+
async function ensureBridgeStartedForRequest() {
|
|
1459
|
+
if (process.env.EMBED_BRIDGE_AUTO_START === "0") {
|
|
1460
|
+
return fail("bridge_unavailable", `embed-local-bridge is not running at ${DEFAULT_BRIDGE_URL}.`, {
|
|
1461
|
+
remediation: `Start it with: embed bridge start`
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
let bridgeURL;
|
|
1465
|
+
try {
|
|
1466
|
+
bridgeURL = new URL(DEFAULT_BRIDGE_URL);
|
|
1467
|
+
}
|
|
1468
|
+
catch {
|
|
1469
|
+
return fail("bridge_url_invalid", `EMBED_BRIDGE_URL is not a valid URL: ${DEFAULT_BRIDGE_URL}`);
|
|
1470
|
+
}
|
|
1471
|
+
if (!isLocalBridgeURL(bridgeURL)) {
|
|
1472
|
+
return fail("bridge_unavailable", `embed-local-bridge is not reachable at ${DEFAULT_BRIDGE_URL}.`, {
|
|
1473
|
+
remediation: `Start the bridge for that host, or set EMBED_BRIDGE_URL to a local bridge URL.`
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
const launcher = await resolveBridgeLauncher();
|
|
1477
|
+
const host = bridgeURL.hostname === "::1" ? "::1" : bridgeURL.hostname || "127.0.0.1";
|
|
1478
|
+
const port = bridgeURL.port || "18083";
|
|
1479
|
+
const env = {
|
|
1480
|
+
...process.env,
|
|
1481
|
+
EMBED_BRIDGE_HOST: host,
|
|
1482
|
+
EMBED_BRIDGE_PORT: port
|
|
1483
|
+
};
|
|
1484
|
+
const child = spawn(launcher.command, [...launcher.args, "--host", host, "--port", port], {
|
|
1485
|
+
cwd: process.cwd(),
|
|
1486
|
+
detached: true,
|
|
1487
|
+
stdio: "ignore",
|
|
1488
|
+
env
|
|
1489
|
+
});
|
|
1490
|
+
child.unref();
|
|
1491
|
+
const ready = await waitForBridgeHealth(bridgeURL, 8000);
|
|
1492
|
+
if (!ready.ok) {
|
|
1493
|
+
return ready;
|
|
1494
|
+
}
|
|
1495
|
+
return ok({
|
|
1496
|
+
started: true,
|
|
1497
|
+
bridge_url: DEFAULT_BRIDGE_URL,
|
|
1498
|
+
command: launcher.command
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
function isLocalBridgeURL(url) {
|
|
1502
|
+
const host = url.hostname.toLowerCase();
|
|
1503
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
1504
|
+
}
|
|
1505
|
+
async function waitForBridgeHealth(bridgeURL, timeoutMs) {
|
|
1506
|
+
const deadline = Date.now() + timeoutMs;
|
|
1507
|
+
let lastError = "";
|
|
1508
|
+
while (Date.now() < deadline) {
|
|
1509
|
+
try {
|
|
1510
|
+
const response = await fetch(new URL("/healthz", bridgeURL), {
|
|
1511
|
+
headers: bridgeHeaders("GET", "/healthz", "")
|
|
1512
|
+
});
|
|
1513
|
+
const parsed = await response.json();
|
|
1514
|
+
if (parsed.ok) {
|
|
1515
|
+
return parsed;
|
|
1516
|
+
}
|
|
1517
|
+
lastError = parsed.error?.message ?? `HTTP ${response.status}`;
|
|
1518
|
+
}
|
|
1519
|
+
catch (error) {
|
|
1520
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
1521
|
+
}
|
|
1522
|
+
await delay(100);
|
|
1523
|
+
}
|
|
1524
|
+
return fail("bridge_start_failed", `embed-local-bridge did not become healthy at ${DEFAULT_BRIDGE_URL}.`, {
|
|
1525
|
+
remediation: `Run embed bridge start in a separate terminal and retry.`,
|
|
1526
|
+
details: { last_error: lastError }
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
function delay(ms) {
|
|
1530
|
+
return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
1531
|
+
}
|
|
1436
1532
|
async function cloudGet(path) {
|
|
1437
1533
|
return await cloudRequest("GET", path);
|
|
1438
1534
|
}
|