@moxxy/cli 0.8.2 → 0.9.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/bin.js +80 -6
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -134374,13 +134374,14 @@ async function createWebSocketTransportServer(opts) {
|
|
|
134374
134374
|
const host = opts.host ?? "127.0.0.1";
|
|
134375
134375
|
const maxConnections = opts.maxConnections ?? DEFAULT_MAX_CONNECTIONS;
|
|
134376
134376
|
let currentToken = opts.authToken;
|
|
134377
|
+
let currentAllowedOrigins = opts.allowedOrigins ?? [];
|
|
134377
134378
|
let connections = 0;
|
|
134378
134379
|
const wss = new import_websocket_server.default({
|
|
134379
134380
|
host,
|
|
134380
134381
|
port: opts.port,
|
|
134381
134382
|
maxPayload: opts.maxPayloadBytes ?? 64 * 1024 * 1024,
|
|
134382
134383
|
verifyClient: (info) => {
|
|
134383
|
-
if (!checkWsOrigin(info.req,
|
|
134384
|
+
if (!checkWsOrigin(info.req, currentAllowedOrigins)) {
|
|
134384
134385
|
console.warn(`[moxxy] ws bridge: rejected browser-origin upgrade (Origin: ${String(info.req.headers.origin)})`);
|
|
134385
134386
|
return false;
|
|
134386
134387
|
}
|
|
@@ -134420,6 +134421,9 @@ async function createWebSocketTransportServer(opts) {
|
|
|
134420
134421
|
for (const client of wss.clients)
|
|
134421
134422
|
client.terminate();
|
|
134422
134423
|
},
|
|
134424
|
+
setAllowedOrigins(origins) {
|
|
134425
|
+
currentAllowedOrigins = [...origins];
|
|
134426
|
+
},
|
|
134423
134427
|
clientCount() {
|
|
134424
134428
|
return connections;
|
|
134425
134429
|
},
|
|
@@ -135994,6 +135998,17 @@ var REMOTE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
135994
135998
|
"session.setMode",
|
|
135995
135999
|
"session.newSession",
|
|
135996
136000
|
"session.runCommand",
|
|
136001
|
+
// Multi-session conversations: list/create/switch/rename are conversation-
|
|
136002
|
+
// scoped — the same trust class as `session.newSession` (already allowed),
|
|
136003
|
+
// and what a paired phone needs to mirror the desktop's session list.
|
|
136004
|
+
// `sessions.remove` is deliberately NOT here: it deletes on-disk state
|
|
136005
|
+
// (the runner's session JSONL + the chat NDJSON transcript), a destructive
|
|
136006
|
+
// host mutation in the same class as `desks.remove`, which is also
|
|
136007
|
+
// host-only.
|
|
136008
|
+
"sessions.list",
|
|
136009
|
+
"sessions.create",
|
|
136010
|
+
"sessions.setActive",
|
|
136011
|
+
"sessions.rename",
|
|
135997
136012
|
// Voice input (capability-probed; transcribe fails coded without a transcriber).
|
|
135998
136013
|
"session.hasTranscriber",
|
|
135999
136014
|
"session.transcribe",
|
|
@@ -136129,6 +136144,20 @@ var ipcInputSchemas = {
|
|
|
136129
136144
|
id: z.string().min(1).max(256),
|
|
136130
136145
|
name: z.string().min(1).max(200)
|
|
136131
136146
|
}),
|
|
136147
|
+
// Sessions: create/rename persist the name into the desks JSON (bound it
|
|
136148
|
+
// like desks.create/rename); setActive spawns a runner and remove deletes
|
|
136149
|
+
// the session's on-disk logs, so their ids are bounded too. These commands
|
|
136150
|
+
// are also served to remote (WS) clients, so the bounds are load-bearing.
|
|
136151
|
+
"sessions.create": z.object({
|
|
136152
|
+
deskId: z.string().min(1).max(256).optional(),
|
|
136153
|
+
name: z.string().min(1).max(200).optional()
|
|
136154
|
+
}).optional(),
|
|
136155
|
+
"sessions.setActive": z.object({ id: z.string().min(1).max(256) }),
|
|
136156
|
+
"sessions.remove": z.object({ id: z.string().min(1).max(256) }),
|
|
136157
|
+
"sessions.rename": z.object({
|
|
136158
|
+
id: z.string().min(1).max(256),
|
|
136159
|
+
name: z.string().min(1).max(200)
|
|
136160
|
+
}),
|
|
136132
136161
|
// Whitelist the fields a renderer may write — `version` is managed by
|
|
136133
136162
|
// the main process; unknown keys are rejected (.strict()).
|
|
136134
136163
|
"prefs.update": z.object({
|
|
@@ -136136,7 +136165,8 @@ var ipcInputSchemas = {
|
|
|
136136
136165
|
clerkUserId: z.string().max(256).nullable().optional(),
|
|
136137
136166
|
clerkDisplayName: z.string().max(256).nullable().optional(),
|
|
136138
136167
|
signedInAt: z.number().nullable().optional(),
|
|
136139
|
-
mobileGatewayEnabled: z.boolean().optional()
|
|
136168
|
+
mobileGatewayEnabled: z.boolean().optional(),
|
|
136169
|
+
theme: z.enum(["light", "dark", "system"]).optional()
|
|
136140
136170
|
}).strict(),
|
|
136141
136171
|
// Mobile-gateway control. Both no-arg variants pin the payload to "nothing"
|
|
136142
136172
|
// so a hostile caller can't smuggle args; setEnabled is a strict boolean.
|
|
@@ -136524,14 +136554,41 @@ function isWildcardHost(host) {
|
|
|
136524
136554
|
const h3 = host.trim().toLowerCase();
|
|
136525
136555
|
return h3 === "0.0.0.0" || h3 === "::" || h3 === "[::]";
|
|
136526
136556
|
}
|
|
136557
|
+
var VIRTUAL_IFACE = /^(?:utun|tun|tap|ppp|ipsec|wg|zt|ts|tailscale|vmnet|vnic|bridge|docker|veth|awdl|llw|ap|anpi)\d*$/i;
|
|
136558
|
+
function isLinkLocalV4(ip) {
|
|
136559
|
+
return ip.startsWith("169.254.");
|
|
136560
|
+
}
|
|
136561
|
+
function isRfc1918(ip) {
|
|
136562
|
+
if (ip.startsWith("10.") || ip.startsWith("192.168."))
|
|
136563
|
+
return true;
|
|
136564
|
+
const m3 = /^172\.(\d{1,3})\./.exec(ip);
|
|
136565
|
+
return m3 !== null && Number(m3[1]) >= 16 && Number(m3[1]) <= 31;
|
|
136566
|
+
}
|
|
136567
|
+
function isCgnat(ip) {
|
|
136568
|
+
const m3 = /^100\.(\d{1,3})\./.exec(ip);
|
|
136569
|
+
return m3 !== null && Number(m3[1]) >= 64 && Number(m3[1]) <= 127;
|
|
136570
|
+
}
|
|
136527
136571
|
function lanHost(fallback) {
|
|
136528
|
-
|
|
136572
|
+
let best = null;
|
|
136573
|
+
for (const [name, list] of Object.entries(os5__default.networkInterfaces())) {
|
|
136529
136574
|
for (const ni of list ?? []) {
|
|
136530
|
-
if (ni.family
|
|
136531
|
-
|
|
136575
|
+
if (ni.family !== "IPv4" || ni.internal)
|
|
136576
|
+
continue;
|
|
136577
|
+
const virtual = VIRTUAL_IFACE.test(name);
|
|
136578
|
+
let rank;
|
|
136579
|
+
if (isLinkLocalV4(ni.address))
|
|
136580
|
+
rank = 5;
|
|
136581
|
+
else if (isRfc1918(ni.address))
|
|
136582
|
+
rank = virtual ? 3 : 1;
|
|
136583
|
+
else if (isCgnat(ni.address))
|
|
136584
|
+
rank = 4;
|
|
136585
|
+
else
|
|
136586
|
+
rank = virtual ? 4 : 2;
|
|
136587
|
+
if (!best || rank < best.rank)
|
|
136588
|
+
best = { address: ni.address, rank };
|
|
136532
136589
|
}
|
|
136533
136590
|
}
|
|
136534
|
-
return fallback;
|
|
136591
|
+
return best?.address ?? fallback;
|
|
136535
136592
|
}
|
|
136536
136593
|
function advertisedHost(bindHost) {
|
|
136537
136594
|
if (isWildcardHost(bindHost))
|
|
@@ -136547,6 +136604,20 @@ function buildConnectUrl(opts) {
|
|
|
136547
136604
|
}
|
|
136548
136605
|
return `ws://${opts.localHost}:${opts.port}/?t=${t2}`;
|
|
136549
136606
|
}
|
|
136607
|
+
function connectUrlOrigin(url2) {
|
|
136608
|
+
const u2 = new URL(url2);
|
|
136609
|
+
const secure = u2.protocol === "wss:" || u2.protocol === "https:";
|
|
136610
|
+
return `${secure ? "https" : "http"}://${u2.host}`;
|
|
136611
|
+
}
|
|
136612
|
+
function advertisedOrigins(bindHost, port) {
|
|
136613
|
+
return [
|
|
136614
|
+
.../* @__PURE__ */ new Set([
|
|
136615
|
+
connectUrlOrigin(`ws://${advertisedHost(bindHost)}:${port}`),
|
|
136616
|
+
`http://127.0.0.1:${port}`,
|
|
136617
|
+
`http://localhost:${port}`
|
|
136618
|
+
])
|
|
136619
|
+
];
|
|
136620
|
+
}
|
|
136550
136621
|
|
|
136551
136622
|
// ../plugin-channel-mobile/dist/tunnel.js
|
|
136552
136623
|
function normalizeTunnelChoice(raw) {
|
|
@@ -136631,10 +136702,12 @@ var MobileChannel = class {
|
|
|
136631
136702
|
this.host = host;
|
|
136632
136703
|
host.register();
|
|
136633
136704
|
host.wire();
|
|
136705
|
+
const localOrigins = advertisedOrigins(this.bindHost, this.port);
|
|
136634
136706
|
const server = await startWsBridge(bus, {
|
|
136635
136707
|
port: this.port,
|
|
136636
136708
|
host: this.bindHost,
|
|
136637
136709
|
authToken: this.token,
|
|
136710
|
+
allowedOrigins: localOrigins,
|
|
136638
136711
|
// Back-compat ONLY: the QR this channel prints embeds the token as `?t=`
|
|
136639
136712
|
// (pairing payload); current apps strip it and authenticate via the
|
|
136640
136713
|
// Sec-WebSocket-Protocol bearer entry, but older installed builds still
|
|
@@ -136649,6 +136722,7 @@ var MobileChannel = class {
|
|
|
136649
136722
|
try {
|
|
136650
136723
|
this.tunnel = await provider.open({ port: this.port, host: this.bindHost });
|
|
136651
136724
|
tunnelUrl = this.tunnel.url;
|
|
136725
|
+
server.setAllowedOrigins([...localOrigins, connectUrlOrigin(tunnelUrl)]);
|
|
136652
136726
|
this.logger?.info?.("mobile tunnel open", { provider: provider.name, url: tunnelUrl });
|
|
136653
136727
|
} catch (err) {
|
|
136654
136728
|
this.logger?.warn?.("mobile tunnel failed; using the local URL", {
|