@camstack/agent 1.1.18 → 1.1.20
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/{chunk-XEHYJVPH.mjs → chunk-BWAPSCEC.mjs} +143 -20
- package/dist/chunk-BWAPSCEC.mjs.map +1 -0
- package/dist/cli.js +145 -19
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +4 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +142 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-XEHYJVPH.mjs.map +0 -1
|
@@ -605,17 +605,108 @@ function createAgentService(deps) {
|
|
|
605
605
|
import * as fs4 from "fs";
|
|
606
606
|
import * as path4 from "path";
|
|
607
607
|
import Fastify from "fastify";
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
608
|
+
|
|
609
|
+
// src/derive-hub-url.ts
|
|
610
|
+
var HUB_API_PORT = 4443;
|
|
611
|
+
function deriveHubUrlFromHubAddress(hubAddress) {
|
|
612
|
+
const trimmed = hubAddress.trim();
|
|
613
|
+
if (trimmed.length === 0) return void 0;
|
|
614
|
+
const afterAt = trimmed.includes("@") ? trimmed.split("@")[1] ?? "" : trimmed;
|
|
615
|
+
const authority = afterAt.split("/")[0] ?? "";
|
|
616
|
+
const host = extractHostFromAuthority(authority);
|
|
617
|
+
if (host === void 0) return void 0;
|
|
618
|
+
return `https://${host}:${HUB_API_PORT}`;
|
|
619
|
+
}
|
|
620
|
+
function deriveHubUrlForExport(hubUrlWasExplicit, hubAddress) {
|
|
621
|
+
if (hubUrlWasExplicit) return void 0;
|
|
622
|
+
if (hubAddress === void 0) return void 0;
|
|
623
|
+
return deriveHubUrlFromHubAddress(hubAddress);
|
|
624
|
+
}
|
|
625
|
+
function extractHostFromAuthority(authority) {
|
|
626
|
+
const value = authority.trim();
|
|
627
|
+
if (value.length === 0) return void 0;
|
|
628
|
+
if (value.startsWith("[")) {
|
|
629
|
+
const end = value.indexOf("]");
|
|
630
|
+
if (end > 0) return value.slice(0, end + 1);
|
|
631
|
+
return void 0;
|
|
632
|
+
}
|
|
633
|
+
const host = value.split(":")[0] ?? "";
|
|
634
|
+
return host.length > 0 ? host : void 0;
|
|
635
|
+
}
|
|
636
|
+
var HUB_NODE_ID = "hub";
|
|
637
|
+
var IPV4_MAPPED_PREFIX = "::ffff:";
|
|
638
|
+
var IPV4_DOTTED_QUAD = /^\d{1,3}(?:\.\d{1,3}){3}$/;
|
|
639
|
+
function pickIpv4(ipList) {
|
|
640
|
+
if (!ipList) return null;
|
|
641
|
+
for (const ip of ipList) {
|
|
642
|
+
if (ip.includes(":")) continue;
|
|
643
|
+
if (ip.startsWith("127.")) continue;
|
|
644
|
+
return ip;
|
|
616
645
|
}
|
|
617
646
|
return null;
|
|
618
647
|
}
|
|
648
|
+
function normalizeObservedHost(raw) {
|
|
649
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
650
|
+
const trimmed = raw.trim();
|
|
651
|
+
if (trimmed.length === 0) return void 0;
|
|
652
|
+
if (trimmed.startsWith("[")) return trimmed;
|
|
653
|
+
if (trimmed.toLowerCase().startsWith(IPV4_MAPPED_PREFIX)) {
|
|
654
|
+
const mapped = trimmed.slice(IPV4_MAPPED_PREFIX.length);
|
|
655
|
+
if (IPV4_DOTTED_QUAD.test(mapped)) return mapped;
|
|
656
|
+
}
|
|
657
|
+
if (trimmed.includes(":")) return `[${trimmed}]`;
|
|
658
|
+
return trimmed;
|
|
659
|
+
}
|
|
660
|
+
function deriveHubUrlFromRegistry(nodes) {
|
|
661
|
+
const hub = nodes.find((node) => node.id === HUB_NODE_ID);
|
|
662
|
+
if (hub === void 0) return void 0;
|
|
663
|
+
const host = normalizeObservedHost(hub.udpAddress) ?? pickIpv4(hub.ipList) ?? hub.hostname;
|
|
664
|
+
if (host === void 0 || host.length === 0) return void 0;
|
|
665
|
+
return `https://${host}:${HUB_API_PORT}`;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/agent-http.ts
|
|
669
|
+
function compareVersions(a, b) {
|
|
670
|
+
if (a === null && b === null) return 0;
|
|
671
|
+
if (a === null) return -1;
|
|
672
|
+
if (b === null) return 1;
|
|
673
|
+
const pa = a.split(".").map((s) => Number.parseInt(s, 10) || 0);
|
|
674
|
+
const pb = b.split(".").map((s) => Number.parseInt(s, 10) || 0);
|
|
675
|
+
const len = Math.max(pa.length, pb.length);
|
|
676
|
+
for (let i = 0; i < len; i++) {
|
|
677
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
678
|
+
if (diff !== 0) return diff;
|
|
679
|
+
}
|
|
680
|
+
return 0;
|
|
681
|
+
}
|
|
682
|
+
function readUiDistCandidate(baseDir) {
|
|
683
|
+
const dir = path4.join(baseDir, "dist");
|
|
684
|
+
if (!fs4.existsSync(path4.join(dir, "index.html"))) return null;
|
|
685
|
+
let version = null;
|
|
686
|
+
try {
|
|
687
|
+
const parsed = JSON.parse(fs4.readFileSync(path4.join(baseDir, "package.json"), "utf-8"));
|
|
688
|
+
version = typeof parsed.version === "string" ? parsed.version : null;
|
|
689
|
+
} catch {
|
|
690
|
+
version = null;
|
|
691
|
+
}
|
|
692
|
+
return { dir, version };
|
|
693
|
+
}
|
|
694
|
+
function pickUiDist(installed, bundled) {
|
|
695
|
+
if (installed && bundled) {
|
|
696
|
+
return compareVersions(bundled.version, installed.version) > 0 ? bundled.dir : installed.dir;
|
|
697
|
+
}
|
|
698
|
+
return installed?.dir ?? bundled?.dir ?? null;
|
|
699
|
+
}
|
|
700
|
+
function resolveUiDistDir(dataDir, bundledAddonsDir, siblingDistDir = path4.resolve(__dirname, "../../addon-agent-ui/dist")) {
|
|
701
|
+
if (fs4.existsSync(path4.join(siblingDistDir, "index.html"))) return siblingDistDir;
|
|
702
|
+
const installed = readUiDistCandidate(path4.join(dataDir, "addons", "@camstack", "addon-agent-ui"));
|
|
703
|
+
const bundled = bundledAddonsDir ? readUiDistCandidate(path4.join(bundledAddonsDir, "addon-agent-ui")) : null;
|
|
704
|
+
const picked = pickUiDist(installed, bundled);
|
|
705
|
+
if (picked) return picked;
|
|
706
|
+
const legacy = path4.join(dataDir, "agent-ui");
|
|
707
|
+
if (fs4.existsSync(path4.join(legacy, "index.html"))) return legacy;
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
619
710
|
function readConfigFile(configPath) {
|
|
620
711
|
if (!fs4.existsSync(configPath)) return {};
|
|
621
712
|
try {
|
|
@@ -636,15 +727,6 @@ function getRegistryNodes(broker) {
|
|
|
636
727
|
return [];
|
|
637
728
|
}
|
|
638
729
|
}
|
|
639
|
-
function pickIpv4(ipList) {
|
|
640
|
-
if (!ipList) return null;
|
|
641
|
-
for (const ip of ipList) {
|
|
642
|
-
if (ip.includes(":")) continue;
|
|
643
|
-
if (ip.startsWith("127.")) continue;
|
|
644
|
-
return ip;
|
|
645
|
-
}
|
|
646
|
-
return null;
|
|
647
|
-
}
|
|
648
730
|
function resolveHubEndpoint(nodes) {
|
|
649
731
|
const hub = nodes.find((n) => n.id === "hub");
|
|
650
732
|
if (!hub) return null;
|
|
@@ -792,19 +874,26 @@ async function createAgentHttpServer(getBroker, config) {
|
|
|
792
874
|
const nodes = getRegistryNodes(b);
|
|
793
875
|
return mapDiscoveredNodes(nodes, b.nodeID);
|
|
794
876
|
});
|
|
795
|
-
const uiDir = resolveUiDistDir(config.dataDir);
|
|
877
|
+
const uiDir = resolveUiDistDir(config.dataDir, process.env["CAMSTACK_BUNDLED_ADDONS_DIR"]);
|
|
796
878
|
if (uiDir) {
|
|
797
879
|
const fastifyStatic = await import("@fastify/static");
|
|
798
880
|
await app.register(fastifyStatic.default, {
|
|
799
881
|
root: uiDir,
|
|
800
882
|
prefix: "/",
|
|
801
883
|
wildcard: false,
|
|
802
|
-
|
|
884
|
+
// MUST stay true: the SPA-fallback below uses `reply.sendFile`, which
|
|
885
|
+
// only exists when the plugin decorates Reply. With `false` every
|
|
886
|
+
// fallback request 500'd with "reply.sendFile is not a function".
|
|
887
|
+
decorateReply: true
|
|
803
888
|
});
|
|
804
889
|
app.setNotFoundHandler(async (req, reply) => {
|
|
805
890
|
if (req.url.startsWith("/api/") || req.url.startsWith("/health")) {
|
|
806
891
|
return reply.status(404).send({ error: "Not found" });
|
|
807
892
|
}
|
|
893
|
+
if (req.url.startsWith("/assets/")) {
|
|
894
|
+
console.warn(`[Agent] UI asset not found (stale index.html?): ${req.url}`);
|
|
895
|
+
return reply.status(404).send({ error: "Asset not found" });
|
|
896
|
+
}
|
|
808
897
|
return reply.type("text/html").sendFile("index.html");
|
|
809
898
|
});
|
|
810
899
|
console.log(`[Agent] UI served from: ${uiDir}`);
|
|
@@ -1026,6 +1115,14 @@ import { LogManager } from "@camstack/system";
|
|
|
1026
1115
|
var agentLogManager = new LogManager(5e3);
|
|
1027
1116
|
async function startAgent(configPath) {
|
|
1028
1117
|
const config = loadAgentConfig(configPath);
|
|
1118
|
+
const hubUrlWasExplicit = process.env["CAMSTACK_HUB_URL"] !== void 0;
|
|
1119
|
+
const derivedHubUrl = deriveHubUrlForExport(hubUrlWasExplicit, config.hubAddress);
|
|
1120
|
+
if (derivedHubUrl !== void 0) {
|
|
1121
|
+
process.env["CAMSTACK_HUB_URL"] = derivedHubUrl;
|
|
1122
|
+
console.log(
|
|
1123
|
+
`[Agent] Derived CAMSTACK_HUB_URL=${derivedHubUrl} from hub address "${config.hubAddress}"`
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1029
1126
|
if (config.hubAddress) {
|
|
1030
1127
|
console.log(
|
|
1031
1128
|
`[Agent] Starting node "${config.nodeId}" (name="${config.name}") connecting to ${config.hubAddress}`
|
|
@@ -1072,6 +1169,13 @@ async function startAgent(configPath) {
|
|
|
1072
1169
|
console.log(
|
|
1073
1170
|
`[Agent] New config: hub=${fresh.hubAddress ?? "discovery"}, secret=${fresh.secret ? "yes" : "none"}`
|
|
1074
1171
|
);
|
|
1172
|
+
const freshHubUrl = deriveHubUrlForExport(hubUrlWasExplicit, fresh.hubAddress);
|
|
1173
|
+
if (freshHubUrl !== void 0 && process.env["CAMSTACK_HUB_URL"] !== freshHubUrl) {
|
|
1174
|
+
process.env["CAMSTACK_HUB_URL"] = freshHubUrl;
|
|
1175
|
+
console.log(
|
|
1176
|
+
`[Agent] Derived CAMSTACK_HUB_URL=${freshHubUrl} from hub address "${fresh.hubAddress}"`
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1075
1179
|
broker = createBroker({
|
|
1076
1180
|
nodeID: config.nodeId,
|
|
1077
1181
|
mode: "agent",
|
|
@@ -1336,6 +1440,25 @@ async function startAgent(configPath) {
|
|
|
1336
1440
|
registerEventBusService(broker);
|
|
1337
1441
|
broker.createService(createHwAccelService(createKernelHwAccel()));
|
|
1338
1442
|
await broker.start();
|
|
1443
|
+
let hubUrlFromRegistry;
|
|
1444
|
+
const reconcileHubUrlFromRegistry = () => {
|
|
1445
|
+
if (hubUrlWasExplicit) return;
|
|
1446
|
+
const current = process.env["CAMSTACK_HUB_URL"];
|
|
1447
|
+
if (current !== void 0 && current !== hubUrlFromRegistry) return;
|
|
1448
|
+
const fromRegistry = deriveHubUrlFromRegistry(
|
|
1449
|
+
getRegistryNodes(broker)
|
|
1450
|
+
);
|
|
1451
|
+
if (fromRegistry === void 0 || fromRegistry === current) return;
|
|
1452
|
+
process.env["CAMSTACK_HUB_URL"] = fromRegistry;
|
|
1453
|
+
hubUrlFromRegistry = fromRegistry;
|
|
1454
|
+
console.log(`[Agent] Derived CAMSTACK_HUB_URL=${fromRegistry} from live hub connection`);
|
|
1455
|
+
};
|
|
1456
|
+
reconcileHubUrlFromRegistry();
|
|
1457
|
+
broker.localBus.on("$node.connected", (data) => {
|
|
1458
|
+
const node = data.node;
|
|
1459
|
+
if (node?.id !== "hub") return;
|
|
1460
|
+
reconcileHubUrlFromRegistry();
|
|
1461
|
+
});
|
|
1339
1462
|
let udsEventBridgeDispose = null;
|
|
1340
1463
|
if (agentUdsRegistry !== void 0) {
|
|
1341
1464
|
const agentBrokerEventBus = getBrokerEventBus(broker);
|
|
@@ -1745,4 +1868,4 @@ export {
|
|
|
1745
1868
|
startAgentHttpServer,
|
|
1746
1869
|
startAgent
|
|
1747
1870
|
};
|
|
1748
|
-
//# sourceMappingURL=chunk-
|
|
1871
|
+
//# sourceMappingURL=chunk-BWAPSCEC.mjs.map
|