@ganglion/xacpx-relay 0.5.2 → 0.8.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-update.d.ts +9 -0
- package/dist/cli.js +237 -15
- package/dist/http/app.d.ts +4 -0
- package/dist/proc.d.ts +8 -0
- package/dist/relay-web/assets/{BrandLogo.vue_vue_type_script_setup_true_lang-DJP2AXeI.js → BrandLogo.vue_vue_type_script_setup_true_lang-BtzVQiX-.js} +1 -1
- package/dist/relay-web/assets/{DashboardView-Di-qpvLF.css → DashboardView-YomyNeqU.css} +1 -1
- package/dist/relay-web/assets/DashboardView-qq0Rv5HT.js +287 -0
- package/dist/relay-web/assets/{LoginView-Cc1pyK2H.js → LoginView-VO7V-HuK.js} +1 -1
- package/dist/relay-web/assets/SettingsView-DChr5KoZ.js +6 -0
- package/dist/relay-web/assets/{index-CwYMuvhS.css → index-DLj88NJ6.css} +1 -1
- package/dist/relay-web/assets/{index-B_zwxZen.js → index-DcwLeItv.js} +17 -17
- package/dist/relay-web/assets/{theme-CxgdBqbU.js → theme-yXKfObZ9.js} +1 -1
- package/dist/relay-web/index.html +2 -2
- package/dist/relay-web/sw.js +1 -1
- package/dist/stores/messages.d.ts +2 -2
- package/dist/version.d.ts +27 -0
- package/package.json +19 -6
- package/dist/relay-web/assets/DashboardView-CBYGWHdu.js +0 -271
- package/dist/relay-web/assets/SettingsView-Cl3pdwq8.js +0 -6
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface RelayUpdateDeps {
|
|
2
|
+
readCurrentVersion: () => string;
|
|
3
|
+
getLatestVersion: () => Promise<string | null>;
|
|
4
|
+
updateSelf: () => Promise<void>;
|
|
5
|
+
print: (line: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/** `xacpx-relay update [--check]` — self-update the hub package. `--check` only
|
|
8
|
+
* reports current vs latest. Returns the process exit code. */
|
|
9
|
+
export declare function handleRelayUpdate(args: string[], deps?: Partial<RelayUpdateDeps>): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -6,8 +6,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
6
6
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
|
-
import { dirname as
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { dirname as dirname3, join as join2, resolve } from "node:path";
|
|
10
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
11
11
|
|
|
12
12
|
// packages/relay/src/server.ts
|
|
13
13
|
import { serve } from "@hono/node-server";
|
|
@@ -101,10 +101,15 @@ function initSchema(db) {
|
|
|
101
101
|
direction TEXT NOT NULL CHECK (direction IN ('in','out')),
|
|
102
102
|
text TEXT NOT NULL,
|
|
103
103
|
created_at TEXT NOT NULL,
|
|
104
|
-
structured TEXT
|
|
104
|
+
structured TEXT,
|
|
105
|
+
attachments TEXT
|
|
105
106
|
);
|
|
106
107
|
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages (instance_id, session_alias, id);
|
|
107
108
|
`);
|
|
109
|
+
const messageCols = db.all("PRAGMA table_info(messages)");
|
|
110
|
+
if (!messageCols.some((c) => c.name === "attachments")) {
|
|
111
|
+
db.exec("ALTER TABLE messages ADD COLUMN attachments TEXT");
|
|
112
|
+
}
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
// packages/relay/src/stores/accounts.ts
|
|
@@ -363,13 +368,21 @@ class MessageStore {
|
|
|
363
368
|
this.db = db;
|
|
364
369
|
this.now = now;
|
|
365
370
|
}
|
|
366
|
-
append(instanceId, sessionAlias, direction, text, structured) {
|
|
367
|
-
this.db.run("INSERT INTO messages (instance_id, session_alias, direction, text, created_at, structured) VALUES (
|
|
371
|
+
append(instanceId, sessionAlias, direction, text, structured, attachments) {
|
|
372
|
+
this.db.run("INSERT INTO messages (instance_id, session_alias, direction, text, created_at, structured, attachments) VALUES (?,?,?,?,?,?,?)", [
|
|
373
|
+
instanceId,
|
|
374
|
+
sessionAlias,
|
|
375
|
+
direction,
|
|
376
|
+
text,
|
|
377
|
+
this.now().toISOString(),
|
|
378
|
+
structured ? JSON.stringify(structured) : null,
|
|
379
|
+
attachments && attachments.length > 0 ? JSON.stringify(attachments) : null
|
|
380
|
+
]);
|
|
368
381
|
}
|
|
369
382
|
listBySession(accountId, instanceId, sessionAlias, opts = {}) {
|
|
370
383
|
const limit = opts.limit ?? 100;
|
|
371
384
|
const before = opts.before ?? null;
|
|
372
|
-
const rows = this.db.all(`SELECT m.id, m.instance_id, m.session_alias, m.direction, m.text, m.created_at, m.structured
|
|
385
|
+
const rows = this.db.all(`SELECT m.id, m.instance_id, m.session_alias, m.direction, m.text, m.created_at, m.structured, m.attachments
|
|
373
386
|
FROM messages m JOIN instances i ON i.id = m.instance_id
|
|
374
387
|
WHERE i.account_id = ? AND m.instance_id = ? AND m.session_alias = ?
|
|
375
388
|
AND (? IS NULL OR m.id < ?)
|
|
@@ -385,7 +398,8 @@ class MessageStore {
|
|
|
385
398
|
direction: r.direction,
|
|
386
399
|
text: r.text,
|
|
387
400
|
createdAt: r.created_at,
|
|
388
|
-
...r.structured ? { structured: JSON.parse(r.structured) } : {}
|
|
401
|
+
...r.structured ? { structured: JSON.parse(r.structured) } : {},
|
|
402
|
+
...r.attachments ? { attachments: JSON.parse(r.attachments) } : {}
|
|
389
403
|
}))
|
|
390
404
|
};
|
|
391
405
|
}
|
|
@@ -602,6 +616,124 @@ function clientIp(c, trustProxy) {
|
|
|
602
616
|
}
|
|
603
617
|
}
|
|
604
618
|
|
|
619
|
+
// packages/relay/src/version.ts
|
|
620
|
+
import { readFileSync } from "node:fs";
|
|
621
|
+
import { dirname as dirname2, join } from "node:path";
|
|
622
|
+
import { fileURLToPath } from "node:url";
|
|
623
|
+
|
|
624
|
+
// packages/relay/src/proc.ts
|
|
625
|
+
import { spawn } from "node:child_process";
|
|
626
|
+
var spawnUsesShell = () => process.platform === "win32";
|
|
627
|
+
async function runCapture(command, args, opts = {}) {
|
|
628
|
+
return await new Promise((resolve, reject) => {
|
|
629
|
+
const child = spawn(command, args, {
|
|
630
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
631
|
+
shell: spawnUsesShell(),
|
|
632
|
+
timeout: opts.timeoutMs
|
|
633
|
+
});
|
|
634
|
+
let stdout = "";
|
|
635
|
+
let stderr = "";
|
|
636
|
+
child.stdout.setEncoding("utf8");
|
|
637
|
+
child.stderr.setEncoding("utf8");
|
|
638
|
+
child.stdout.on("data", (chunk) => {
|
|
639
|
+
stdout += chunk;
|
|
640
|
+
});
|
|
641
|
+
child.stderr.on("data", (chunk) => {
|
|
642
|
+
stderr += chunk;
|
|
643
|
+
});
|
|
644
|
+
child.on("error", reject);
|
|
645
|
+
child.on("close", (code) => resolve({ code: code ?? 1, stdout, stderr }));
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
async function runInherit(command, args) {
|
|
649
|
+
await new Promise((resolve, reject) => {
|
|
650
|
+
const child = spawn(command, args, { stdio: "inherit", shell: spawnUsesShell() });
|
|
651
|
+
child.on("error", reject);
|
|
652
|
+
child.on("exit", (code) => {
|
|
653
|
+
if (code === 0)
|
|
654
|
+
resolve();
|
|
655
|
+
else
|
|
656
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// packages/relay/src/version.ts
|
|
662
|
+
var RELAY_PACKAGE_NAME = "@ganglion/xacpx-relay";
|
|
663
|
+
function readRelayVersion(moduleUrl = import.meta.url) {
|
|
664
|
+
const here = dirname2(fileURLToPath(moduleUrl));
|
|
665
|
+
for (const candidate of [
|
|
666
|
+
join(here, "package.json"),
|
|
667
|
+
join(here, "..", "package.json"),
|
|
668
|
+
join(here, "..", "..", "package.json")
|
|
669
|
+
]) {
|
|
670
|
+
try {
|
|
671
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf8"));
|
|
672
|
+
if (parsed.name === RELAY_PACKAGE_NAME && typeof parsed.version === "string")
|
|
673
|
+
return parsed.version;
|
|
674
|
+
} catch {}
|
|
675
|
+
}
|
|
676
|
+
return "unknown";
|
|
677
|
+
}
|
|
678
|
+
async function getLatestNpmVersion(packageName) {
|
|
679
|
+
let result;
|
|
680
|
+
try {
|
|
681
|
+
result = await runCapture("npm", ["view", packageName, "version", "--json"], { timeoutMs: 8000 });
|
|
682
|
+
} catch {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
if (result.code !== 0)
|
|
686
|
+
return null;
|
|
687
|
+
const raw = result.stdout.trim();
|
|
688
|
+
if (!raw)
|
|
689
|
+
return null;
|
|
690
|
+
try {
|
|
691
|
+
const parsed = JSON.parse(raw);
|
|
692
|
+
return typeof parsed === "string" ? parsed : null;
|
|
693
|
+
} catch {
|
|
694
|
+
return raw.replace(/^"|"$/g, "") || null;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
function isNewer(candidate, current) {
|
|
698
|
+
if (!parseSemver(candidate) || !parseSemver(current))
|
|
699
|
+
return false;
|
|
700
|
+
return compareSemver(candidate, current) > 0;
|
|
701
|
+
}
|
|
702
|
+
function parseSemver(value) {
|
|
703
|
+
const match = /^\s*v?(\d+)\.(\d+)\.(\d+)(-[^\s]*)?/.exec(value);
|
|
704
|
+
if (!match)
|
|
705
|
+
return null;
|
|
706
|
+
return { nums: [Number(match[1]), Number(match[2]), Number(match[3])], prerelease: Boolean(match[4]) };
|
|
707
|
+
}
|
|
708
|
+
function compareSemver(a, b) {
|
|
709
|
+
const left = parseSemver(a) ?? { nums: [0, 0, 0], prerelease: false };
|
|
710
|
+
const right = parseSemver(b) ?? { nums: [0, 0, 0], prerelease: false };
|
|
711
|
+
for (let i = 0;i < 3; i += 1) {
|
|
712
|
+
if (left.nums[i] !== right.nums[i])
|
|
713
|
+
return left.nums[i] < right.nums[i] ? -1 : 1;
|
|
714
|
+
}
|
|
715
|
+
if (left.prerelease === right.prerelease)
|
|
716
|
+
return 0;
|
|
717
|
+
return left.prerelease ? -1 : 1;
|
|
718
|
+
}
|
|
719
|
+
function createRelayUpdateChecker(opts) {
|
|
720
|
+
const getLatest = opts.getLatest ?? (() => getLatestNpmVersion(RELAY_PACKAGE_NAME));
|
|
721
|
+
const now = opts.now ?? (() => Date.now());
|
|
722
|
+
const ttlMs = opts.ttlMs ?? 60 * 60 * 1000;
|
|
723
|
+
let cache = null;
|
|
724
|
+
return async () => {
|
|
725
|
+
if (!cache || now() - cache.at >= ttlMs) {
|
|
726
|
+
try {
|
|
727
|
+
const latest2 = await getLatest();
|
|
728
|
+
if (latest2 != null)
|
|
729
|
+
cache = { latest: latest2, at: now() };
|
|
730
|
+
} catch {}
|
|
731
|
+
}
|
|
732
|
+
const latest = cache?.latest ?? null;
|
|
733
|
+
return { current: opts.current, latest, updateAvailable: latest != null && isNewer(latest, opts.current) };
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
|
|
605
737
|
// packages/relay/src/http/app.ts
|
|
606
738
|
var SESSION_COOKIE = "xrelay_session";
|
|
607
739
|
var LOGIN_WINDOW_MS = 10 * 60 * 1000;
|
|
@@ -620,12 +752,26 @@ var CHAT_SCOPED_TYPES = new Set([
|
|
|
620
752
|
MSG2.sessionsCreate,
|
|
621
753
|
MSG2.sessionsNativeList,
|
|
622
754
|
MSG2.sessionsRemove,
|
|
755
|
+
MSG2.sessionsArchive,
|
|
756
|
+
MSG2.sessionsUnarchive,
|
|
623
757
|
MSG2.sessionModelGet,
|
|
624
758
|
MSG2.sessionModelSet
|
|
625
759
|
]);
|
|
626
760
|
function requireJson(contentType) {
|
|
627
761
|
return (contentType ?? "").toLowerCase().includes("application/json");
|
|
628
762
|
}
|
|
763
|
+
function safePreviewUrl(v) {
|
|
764
|
+
if (typeof v === "string" && v.startsWith("data:image/") && v.length <= 256 * 1024) {
|
|
765
|
+
return v;
|
|
766
|
+
}
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
var RPC_MAX_BODY_BYTES = 16 * 1024 * 1024;
|
|
770
|
+
var MAX_PERSISTED_ATTACHMENTS = 5;
|
|
771
|
+
var MAX_ATTACHMENT_FIELD_LEN = 256;
|
|
772
|
+
function boundField(v) {
|
|
773
|
+
return typeof v === "string" ? v.slice(0, MAX_ATTACHMENT_FIELD_LEN) : v;
|
|
774
|
+
}
|
|
629
775
|
function createApp(deps) {
|
|
630
776
|
const sessionTtlMs = deps.sessionTtlMs ?? 7 * 24 * 60 * 60 * 1000;
|
|
631
777
|
const pairingTtlMs = deps.pairingTtlMs ?? 10 * 60 * 1000;
|
|
@@ -722,6 +868,10 @@ function createApp(deps) {
|
|
|
722
868
|
}
|
|
723
869
|
});
|
|
724
870
|
});
|
|
871
|
+
app.get("/api/version", async (c) => {
|
|
872
|
+
const check = deps.checkUpdate ?? (async () => ({ current: readRelayVersion(), latest: null, updateAvailable: false }));
|
|
873
|
+
return c.json(await check());
|
|
874
|
+
});
|
|
725
875
|
app.get("/api/instances", (c) => {
|
|
726
876
|
const account = c.get("account");
|
|
727
877
|
const rows = deps.instances.listByAccount(account.id).map((row) => ({
|
|
@@ -785,6 +935,10 @@ function createApp(deps) {
|
|
|
785
935
|
const instance = deps.instances.getOwned(c.req.param("id"), account.id);
|
|
786
936
|
if (!instance)
|
|
787
937
|
return c.json({ error: "not-found" }, 404);
|
|
938
|
+
const contentLength = Number(c.req.header("content-length"));
|
|
939
|
+
if (Number.isFinite(contentLength) && contentLength > RPC_MAX_BODY_BYTES) {
|
|
940
|
+
return c.json({ error: "payload-too-large" }, 413);
|
|
941
|
+
}
|
|
788
942
|
const body = await c.req.json().catch(() => ({}));
|
|
789
943
|
if (!body.type || !body.type.startsWith("control."))
|
|
790
944
|
return c.json({ error: "invalid-rpc-type" }, 400);
|
|
@@ -798,10 +952,28 @@ function createApp(deps) {
|
|
|
798
952
|
};
|
|
799
953
|
}
|
|
800
954
|
try {
|
|
955
|
+
if (body.type === MSG2.upload) {
|
|
956
|
+
const up = payload;
|
|
957
|
+
const approxBytes = up.content ? Math.floor(up.content.length * 3 / 4) : 0;
|
|
958
|
+
if (approxBytes > 10 * 1024 * 1024)
|
|
959
|
+
return c.json({ error: "file-too-large" }, 413);
|
|
960
|
+
}
|
|
801
961
|
if (body.type === MSG2.prompt || body.type === MSG2.commandExecute) {
|
|
802
962
|
const p = payload;
|
|
803
|
-
if (p.sessionAlias && p.text)
|
|
804
|
-
|
|
963
|
+
if (p.sessionAlias && p.text !== undefined) {
|
|
964
|
+
const attachments = (p.media ?? []).slice(0, MAX_PERSISTED_ATTACHMENTS).map((m) => {
|
|
965
|
+
const previewUrl = safePreviewUrl(m.previewUrl);
|
|
966
|
+
return {
|
|
967
|
+
id: m.id,
|
|
968
|
+
filename: boundField(m.fileName),
|
|
969
|
+
mimeType: boundField(m.mimeType),
|
|
970
|
+
size: m.size,
|
|
971
|
+
kind: m.kind,
|
|
972
|
+
...previewUrl ? { previewUrl } : {}
|
|
973
|
+
};
|
|
974
|
+
});
|
|
975
|
+
deps.messages.append(instance.id, p.sessionAlias, "in", p.text, undefined, attachments);
|
|
976
|
+
}
|
|
805
977
|
}
|
|
806
978
|
const result = await deps.gateway.sendRequest(instance.id, body.type, payload);
|
|
807
979
|
if (body.type === MSG2.commandExecute) {
|
|
@@ -976,7 +1148,8 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
976
1148
|
historyRetentionDays: options.historyRetentionDays ?? 30,
|
|
977
1149
|
maxMessagesPerSession: MAX_MESSAGES_PER_SESSION,
|
|
978
1150
|
activeTurns: listActiveTurns,
|
|
979
|
-
trustProxy: options.trustProxy
|
|
1151
|
+
trustProxy: options.trustProxy,
|
|
1152
|
+
checkUpdate: createRelayUpdateChecker({ current: readRelayVersion() })
|
|
980
1153
|
});
|
|
981
1154
|
return { db, accounts, instances, messages, gateway, webGateway, app, close: () => db.close() };
|
|
982
1155
|
}
|
|
@@ -1056,17 +1229,62 @@ function parseCookie(header) {
|
|
|
1056
1229
|
return out;
|
|
1057
1230
|
}
|
|
1058
1231
|
|
|
1232
|
+
// packages/relay/src/cli-update.ts
|
|
1233
|
+
async function handleRelayUpdate(args, deps = {}) {
|
|
1234
|
+
const readCurrent = deps.readCurrentVersion ?? (() => readRelayVersion());
|
|
1235
|
+
const getLatest = deps.getLatestVersion ?? (() => getLatestNpmVersion(RELAY_PACKAGE_NAME));
|
|
1236
|
+
const updateSelf = deps.updateSelf ?? defaultUpdateSelf;
|
|
1237
|
+
const print = deps.print ?? ((l) => console.log(l));
|
|
1238
|
+
const checkOnly = args.includes("--check");
|
|
1239
|
+
const current = readCurrent();
|
|
1240
|
+
const latest = await getLatest();
|
|
1241
|
+
if (latest == null) {
|
|
1242
|
+
if (checkOnly) {
|
|
1243
|
+
print(`current: v${current}; latest: unknown (could not reach npm)`);
|
|
1244
|
+
return 0;
|
|
1245
|
+
}
|
|
1246
|
+
print(`update failed: could not determine the latest ${RELAY_PACKAGE_NAME} version (is npm reachable?)`);
|
|
1247
|
+
return 1;
|
|
1248
|
+
}
|
|
1249
|
+
if (!isNewer(latest, current)) {
|
|
1250
|
+
print(`already up to date (v${current})`);
|
|
1251
|
+
return 0;
|
|
1252
|
+
}
|
|
1253
|
+
if (checkOnly) {
|
|
1254
|
+
print(`update available: v${current} → v${latest} (run: xacpx-relay update)`);
|
|
1255
|
+
return 0;
|
|
1256
|
+
}
|
|
1257
|
+
print(`updating ${RELAY_PACKAGE_NAME}: v${current} → v${latest} …`);
|
|
1258
|
+
try {
|
|
1259
|
+
await updateSelf();
|
|
1260
|
+
} catch (error) {
|
|
1261
|
+
print(`update failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1262
|
+
return 1;
|
|
1263
|
+
}
|
|
1264
|
+
print(`updated to v${latest}`);
|
|
1265
|
+
return 0;
|
|
1266
|
+
}
|
|
1267
|
+
async function defaultUpdateSelf() {
|
|
1268
|
+
const spec = `${RELAY_PACKAGE_NAME}@latest`;
|
|
1269
|
+
const useBun = (process.env.PACKAGE_MANAGER ?? "").trim().toLowerCase() === "bun";
|
|
1270
|
+
if (useBun) {
|
|
1271
|
+
await runInherit("bun", ["add", "-g", spec]);
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
await runInherit("npm", ["install", "-g", spec]);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1059
1277
|
// packages/relay/src/cli.ts
|
|
1060
1278
|
function defaultDbPath() {
|
|
1061
|
-
return
|
|
1279
|
+
return join2(homedir(), ".xacpx-relay", "relay.db");
|
|
1062
1280
|
}
|
|
1063
|
-
function resolveBundledWebRoot(cliJsPath =
|
|
1064
|
-
const here =
|
|
1281
|
+
function resolveBundledWebRoot(cliJsPath = fileURLToPath2(import.meta.url)) {
|
|
1282
|
+
const here = dirname3(cliJsPath);
|
|
1065
1283
|
const embedded = resolve(here, "relay-web");
|
|
1066
|
-
if (existsSync(
|
|
1284
|
+
if (existsSync(join2(embedded, "index.html")))
|
|
1067
1285
|
return embedded;
|
|
1068
1286
|
const sibling = resolve(here, "../../relay-web/dist");
|
|
1069
|
-
if (existsSync(
|
|
1287
|
+
if (existsSync(join2(sibling, "index.html")))
|
|
1070
1288
|
return sibling;
|
|
1071
1289
|
return;
|
|
1072
1290
|
}
|
|
@@ -1077,6 +1295,7 @@ var USAGE = [
|
|
|
1077
1295
|
" add token [--label <note>] [--db <path>]",
|
|
1078
1296
|
" ls [--db <path>]",
|
|
1079
1297
|
" rm token <value-or-id> [--db <path>]",
|
|
1298
|
+
" update [--check] (self-update @ganglion/xacpx-relay; --check only reports)",
|
|
1080
1299
|
"",
|
|
1081
1300
|
" Defaults: --db ~/.xacpx-relay/relay.db --web-root auto-detects the bundled dashboard"
|
|
1082
1301
|
].join(`
|
|
@@ -1180,6 +1399,9 @@ async function runRelayCli(args, io) {
|
|
|
1180
1399
|
runtime.close();
|
|
1181
1400
|
}
|
|
1182
1401
|
}
|
|
1402
|
+
if (args[0] === "update") {
|
|
1403
|
+
return await handleRelayUpdate(args.slice(1), { print: io.print });
|
|
1404
|
+
}
|
|
1183
1405
|
io.print(USAGE);
|
|
1184
1406
|
return 1;
|
|
1185
1407
|
}
|
package/dist/http/app.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type LiveTurnSnapshotDto } from "@ganglion/xacpx-relay-protocol";
|
|
|
3
3
|
import type { AccountRow, AccountStore } from "../stores/accounts.js";
|
|
4
4
|
import type { InstanceStore } from "../stores/instances.js";
|
|
5
5
|
import type { MessageStore } from "../stores/messages.js";
|
|
6
|
+
import { type UpdateCheck } from "../version.js";
|
|
6
7
|
export interface GatewayForApp {
|
|
7
8
|
isOnline(instanceId: string): boolean;
|
|
8
9
|
sendRequest(instanceId: string, type: string, payload: unknown): Promise<unknown>;
|
|
@@ -19,6 +20,9 @@ export interface AppDeps {
|
|
|
19
20
|
pairingTtlMs?: number;
|
|
20
21
|
historyRetentionDays?: number;
|
|
21
22
|
maxMessagesPerSession?: number;
|
|
23
|
+
/** Returns the hub's current version + whether a newer one is published. Injected
|
|
24
|
+
* by server.ts (cached). When omitted, /api/version reports current-only. */
|
|
25
|
+
checkUpdate?: () => Promise<UpdateCheck>;
|
|
22
26
|
trustProxy?: boolean;
|
|
23
27
|
now?: () => Date;
|
|
24
28
|
}
|
package/dist/proc.d.ts
ADDED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as e,c as s,
|
|
1
|
+
import{d as e,c as s,S as a,o as n}from"./index-DcwLeItv.js";const o={class:"flex items-center gap-2 select-none"},d=e({__name:"BrandLogo",setup(r){return(p,t)=>(n(),s("div",o,[...t[0]||(t[0]=[a('<svg data-test="brand-x" width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true"><defs><linearGradient id="xacpxBrand" x1="3" y1="3" x2="21" y2="21" gradientUnits="userSpaceOnUse"><stop stop-color="#4F9BF5"></stop><stop offset="1" stop-color="#69D689"></stop></linearGradient></defs><path d="M5 5 L19 19 M19 5 L5 19" stroke="url(#xacpxBrand)" stroke-width="3.2" stroke-linecap="round"></path></svg><span class="text-[15px] font-semibold tracking-tight text-fg">xacpx</span><span class="text-fg-muted text-xs">· relay</span>',3)])]))}});export{d as _};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.stream-md>:first-child{margin-top:0}.stream-md>:last-child{margin-bottom:0}.stream-md p{margin:.5em 0;line-height:1.5}.stream-md h1,.stream-md h2,.stream-md h3,.stream-md h4{margin:.8em 0 .4em;font-weight:600;line-height:1.3}.stream-md h1{font-size:1.3em}.stream-md h2{font-size:1.2em}.stream-md h3{font-size:1.1em}.stream-md ul,.stream-md ol{margin:.5em 0;padding-left:1.4em}.stream-md ul{list-style:disc}.stream-md ol{list-style:decimal}.stream-md li{margin:.2em 0}.stream-md a{color:rgb(var(--c-accent));text-decoration:underline}.stream-md code{background:rgb(var(--c-surface));color:rgb(var(--c-fg));border-radius:4px;padding:.1em .3em;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px}.stream-md pre{background:rgb(var(--c-bg));color:rgb(var(--c-fg));border:1px solid rgb(var(--c-border));border-radius:8px;padding:.65em .85em;overflow-x:auto;margin:.6em 0;box-shadow:var(--shadow-e1)}.stream-md pre::-webkit-scrollbar{height:8px}.stream-md pre::-webkit-scrollbar-thumb{background:rgb(var(--c-fg-muted) / .28);border-radius:8px}.stream-md pre::-webkit-scrollbar-track{background:transparent}.stream-md pre code{background:transparent;padding:0;color:inherit;font-size:13px;line-height:1.6}.stream-md .hljs-keyword,.stream-md .hljs-built_in,.stream-md .hljs-name,.stream-md .hljs-tag{color:rgb(var(--c-accent))}.stream-md .hljs-string,.stream-md .hljs-attr,.stream-md .hljs-symbol{color:rgb(var(--c-run))}.stream-md .hljs-comment,.stream-md .hljs-quote{color:rgb(var(--c-fg-muted))}.stream-md .hljs-number,.stream-md .hljs-literal{color:rgb(var(--c-info))}.stream-md blockquote{border-left:3px solid rgb(var(--c-border));margin:.6em 0;padding-left:.8em;color:rgb(var(--c-fg-muted))}.stream-md .md-table-wrap{max-width:100%;overflow-x:auto;margin:.6em 0}.stream-md .md-table-wrap::-webkit-scrollbar{height:8px}.stream-md .md-table-wrap::-webkit-scrollbar-thumb{background:rgb(var(--c-fg-muted) / .28);border-radius:8px}.stream-md .md-table-wrap::-webkit-scrollbar-track{background:transparent}.stream-md table{border-collapse:collapse}.stream-md img{max-width:100%;height:auto}.stream-md th,.stream-md td{border:1px solid rgb(var(--c-border));padding:.3em .6em}.stream-md hr{border:none;border-top:1px solid rgb(var(--c-border));margin:.8em 0}.cv-row[data-v-
|
|
1
|
+
.stream-md>:first-child{margin-top:0}.stream-md>:last-child{margin-bottom:0}.stream-md p{margin:.5em 0;line-height:1.5}.stream-md h1,.stream-md h2,.stream-md h3,.stream-md h4{margin:.8em 0 .4em;font-weight:600;line-height:1.3}.stream-md h1{font-size:1.3em}.stream-md h2{font-size:1.2em}.stream-md h3{font-size:1.1em}.stream-md ul,.stream-md ol{margin:.5em 0;padding-left:1.4em}.stream-md ul{list-style:disc}.stream-md ol{list-style:decimal}.stream-md li{margin:.2em 0}.stream-md a{color:rgb(var(--c-accent));text-decoration:underline}.stream-md code{background:rgb(var(--c-surface));color:rgb(var(--c-fg));border-radius:4px;padding:.1em .3em;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px}.stream-md pre{background:rgb(var(--c-bg));color:rgb(var(--c-fg));border:1px solid rgb(var(--c-border));border-radius:8px;padding:.65em .85em;overflow-x:auto;margin:.6em 0;box-shadow:var(--shadow-e1)}.stream-md pre::-webkit-scrollbar{height:8px}.stream-md pre::-webkit-scrollbar-thumb{background:rgb(var(--c-fg-muted) / .28);border-radius:8px}.stream-md pre::-webkit-scrollbar-track{background:transparent}.stream-md pre code{background:transparent;padding:0;color:inherit;font-size:13px;line-height:1.6}.stream-md .hljs-keyword,.stream-md .hljs-built_in,.stream-md .hljs-name,.stream-md .hljs-tag{color:rgb(var(--c-accent))}.stream-md .hljs-string,.stream-md .hljs-attr,.stream-md .hljs-symbol{color:rgb(var(--c-run))}.stream-md .hljs-comment,.stream-md .hljs-quote{color:rgb(var(--c-fg-muted))}.stream-md .hljs-number,.stream-md .hljs-literal{color:rgb(var(--c-info))}.stream-md blockquote{border-left:3px solid rgb(var(--c-border));margin:.6em 0;padding-left:.8em;color:rgb(var(--c-fg-muted))}.stream-md .md-table-wrap{max-width:100%;overflow-x:auto;margin:.6em 0}.stream-md .md-table-wrap::-webkit-scrollbar{height:8px}.stream-md .md-table-wrap::-webkit-scrollbar-thumb{background:rgb(var(--c-fg-muted) / .28);border-radius:8px}.stream-md .md-table-wrap::-webkit-scrollbar-track{background:transparent}.stream-md table{border-collapse:collapse}.stream-md img{max-width:100%;height:auto}.stream-md th,.stream-md td{border:1px solid rgb(var(--c-border));padding:.3em .6em}.stream-md hr{border:none;border-top:1px solid rgb(var(--c-border));margin:.8em 0}.cv-row[data-v-c68894eb]{content-visibility:auto;contain-intrinsic-size:auto 88px}
|