opencode-copilot-account-switcher 0.14.14 → 0.14.15
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createBrokerSocket } from "./broker-endpoint.js";
|
|
2
2
|
import { parseEnvelopeLine, serializeEnvelope, } from "./protocol.js";
|
|
3
3
|
function isNonEmptyString(value) {
|
|
4
4
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -23,7 +23,7 @@ export async function connect(endpoint, options = {}) {
|
|
|
23
23
|
if (options.bridge && options.onCollectStatus) {
|
|
24
24
|
throw new Error("broker client options are ambiguous: provide either bridge or onCollectStatus");
|
|
25
25
|
}
|
|
26
|
-
const socket =
|
|
26
|
+
const socket = createBrokerSocket(endpoint);
|
|
27
27
|
let sequence = 0;
|
|
28
28
|
let pendingResolve = null;
|
|
29
29
|
let pendingReject = null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
type BrokerEndpointOptions = {
|
|
3
|
+
platform?: NodeJS.Platform;
|
|
4
|
+
stateRoot?: string;
|
|
5
|
+
now?: () => number;
|
|
6
|
+
random?: () => number;
|
|
7
|
+
};
|
|
8
|
+
type ParsedBrokerEndpoint = {
|
|
9
|
+
kind: "tcp";
|
|
10
|
+
host: string;
|
|
11
|
+
port: number;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "path";
|
|
14
|
+
path: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function isTcpBrokerEndpoint(endpoint: string): boolean;
|
|
17
|
+
export declare function createDefaultBrokerEndpoint(options?: BrokerEndpointOptions): string;
|
|
18
|
+
export declare function parseBrokerEndpoint(endpoint: string): ParsedBrokerEndpoint;
|
|
19
|
+
export declare function createBrokerSocket(endpoint: string): net.Socket;
|
|
20
|
+
export declare function listenOnBrokerEndpoint(server: net.Server, endpoint: string): Promise<string>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function isNonEmptyString(value) {
|
|
4
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
5
|
+
}
|
|
6
|
+
export function isTcpBrokerEndpoint(endpoint) {
|
|
7
|
+
return endpoint.startsWith("tcp://");
|
|
8
|
+
}
|
|
9
|
+
export function createDefaultBrokerEndpoint(options = {}) {
|
|
10
|
+
const platform = options.platform ?? process.platform;
|
|
11
|
+
const stateRoot = options.stateRoot ?? ".";
|
|
12
|
+
const now = options.now ?? Date.now;
|
|
13
|
+
const random = options.random ?? Math.random;
|
|
14
|
+
const suffix = `${now()}-${random().toString(16).slice(2)}`;
|
|
15
|
+
if (platform === "win32") {
|
|
16
|
+
return "tcp://127.0.0.1:0";
|
|
17
|
+
}
|
|
18
|
+
return path.join(stateRoot, `broker-${suffix}.sock`);
|
|
19
|
+
}
|
|
20
|
+
export function parseBrokerEndpoint(endpoint) {
|
|
21
|
+
if (!isTcpBrokerEndpoint(endpoint)) {
|
|
22
|
+
return {
|
|
23
|
+
kind: "path",
|
|
24
|
+
path: endpoint,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const parsed = new URL(endpoint);
|
|
28
|
+
if (parsed.protocol !== "tcp:") {
|
|
29
|
+
throw new Error(`unsupported broker endpoint protocol: ${parsed.protocol}`);
|
|
30
|
+
}
|
|
31
|
+
if (!isNonEmptyString(parsed.hostname)) {
|
|
32
|
+
throw new Error("tcp broker endpoint host is required");
|
|
33
|
+
}
|
|
34
|
+
const port = Number(parsed.port);
|
|
35
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
36
|
+
throw new Error("tcp broker endpoint port is invalid");
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
kind: "tcp",
|
|
40
|
+
host: parsed.hostname,
|
|
41
|
+
port,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function createBrokerSocket(endpoint) {
|
|
45
|
+
const parsed = parseBrokerEndpoint(endpoint);
|
|
46
|
+
if (parsed.kind === "tcp") {
|
|
47
|
+
return net.createConnection({
|
|
48
|
+
host: parsed.host,
|
|
49
|
+
port: parsed.port,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return net.createConnection(parsed.path);
|
|
53
|
+
}
|
|
54
|
+
export async function listenOnBrokerEndpoint(server, endpoint) {
|
|
55
|
+
const parsed = parseBrokerEndpoint(endpoint);
|
|
56
|
+
await new Promise((resolve, reject) => {
|
|
57
|
+
server.once("error", reject);
|
|
58
|
+
if (parsed.kind === "tcp") {
|
|
59
|
+
server.listen({ host: parsed.host, port: parsed.port }, () => {
|
|
60
|
+
server.off("error", reject);
|
|
61
|
+
resolve();
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
server.listen(parsed.path, () => {
|
|
66
|
+
server.off("error", reject);
|
|
67
|
+
resolve();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
if (parsed.kind === "path") {
|
|
71
|
+
return parsed.path;
|
|
72
|
+
}
|
|
73
|
+
const address = server.address();
|
|
74
|
+
if (!address || typeof address === "string") {
|
|
75
|
+
throw new Error("tcp broker endpoint failed to resolve bound address");
|
|
76
|
+
}
|
|
77
|
+
return `tcp://${address.address}:${address.port}`;
|
|
78
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createDefaultBrokerEndpoint } from "./broker-endpoint.js";
|
|
1
2
|
type BrokerMetadata = {
|
|
2
3
|
pid: number;
|
|
3
4
|
endpoint: string;
|
|
@@ -24,5 +25,5 @@ type LaunchOptions = {
|
|
|
24
25
|
pingImpl?: (endpoint: string) => Promise<boolean>;
|
|
25
26
|
onLockAcquired?: (lock: LaunchLockContent) => void;
|
|
26
27
|
};
|
|
28
|
+
export { createDefaultBrokerEndpoint };
|
|
27
29
|
export declare function connectOrSpawnBroker(options?: LaunchOptions): Promise<BrokerMetadata>;
|
|
28
|
-
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import net from "node:net";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { randomUUID } from "node:crypto";
|
|
4
3
|
import { mkdir, open, readFile, rm } from "node:fs/promises";
|
|
5
4
|
import { spawn } from "node:child_process";
|
|
6
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createBrokerSocket, createDefaultBrokerEndpoint } from "./broker-endpoint.js";
|
|
7
7
|
import { wechatStateRoot } from "./state-paths.js";
|
|
8
8
|
import { parseEnvelopeLine, serializeEnvelope } from "./protocol.js";
|
|
9
9
|
const DEFAULT_BACKOFF_MS = 250;
|
|
@@ -17,6 +17,7 @@ function isFiniteNumber(value) {
|
|
|
17
17
|
function delay(ms) {
|
|
18
18
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
19
19
|
}
|
|
20
|
+
export { createDefaultBrokerEndpoint };
|
|
20
21
|
async function readCurrentPackageVersion() {
|
|
21
22
|
try {
|
|
22
23
|
const packageJsonPath = new URL("../../package.json", import.meta.url);
|
|
@@ -57,7 +58,7 @@ async function readBrokerMetadata(filePath) {
|
|
|
57
58
|
}
|
|
58
59
|
async function defaultPingImpl(endpoint) {
|
|
59
60
|
return new Promise((resolve) => {
|
|
60
|
-
const socket =
|
|
61
|
+
const socket = createBrokerSocket(endpoint);
|
|
61
62
|
let buffer = "";
|
|
62
63
|
const timer = setTimeout(() => {
|
|
63
64
|
socket.destroy();
|
|
@@ -162,13 +163,7 @@ export async function connectOrSpawnBroker(options = {}) {
|
|
|
162
163
|
const expectedVersion = options.expectedVersion ?? await readCurrentPackageVersion();
|
|
163
164
|
const pingImpl = options.pingImpl ?? defaultPingImpl;
|
|
164
165
|
const spawnImpl = options.spawnImpl ?? defaultSpawnImpl;
|
|
165
|
-
const endpointFactory = options.endpointFactory ?? (() => {
|
|
166
|
-
const suffix = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
167
|
-
if (process.platform === "win32") {
|
|
168
|
-
return `\\\\.\\pipe\\wechat-broker-${process.pid}-${suffix}`;
|
|
169
|
-
}
|
|
170
|
-
return path.join(stateRoot, `broker-${suffix}.sock`);
|
|
171
|
-
});
|
|
166
|
+
const endpointFactory = options.endpointFactory ?? (() => createDefaultBrokerEndpoint({ stateRoot }));
|
|
172
167
|
await mkdir(stateRoot, { recursive: true, mode: 0o700 });
|
|
173
168
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
174
169
|
const running = await isBrokerAlive(brokerJsonFile, pingImpl, expectedVersion);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { chmod, mkdir, rm, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { createBrokerSocket, isTcpBrokerEndpoint, listenOnBrokerEndpoint } from "./broker-endpoint.js";
|
|
4
5
|
import { registerConnection, revokeSessionToken, validateSessionToken } from "./ipc-auth.js";
|
|
5
6
|
import { createErrorEnvelope, parseEnvelopeLine, serializeEnvelope, } from "./protocol.js";
|
|
6
7
|
import { WECHAT_DIR_MODE, WECHAT_FILE_MODE, instanceStatePath, instancesDir } from "./state-paths.js";
|
|
@@ -378,7 +379,7 @@ async function handleMessage(envelope, socket) {
|
|
|
378
379
|
writeError(socket, "notImplemented", `${envelope.type} is not implemented`, requestId);
|
|
379
380
|
}
|
|
380
381
|
async function tightenEndpointPermission(endpoint) {
|
|
381
|
-
if (process.platform === "win32") {
|
|
382
|
+
if (process.platform === "win32" || isTcpBrokerEndpoint(endpoint)) {
|
|
382
383
|
return;
|
|
383
384
|
}
|
|
384
385
|
await chmod(endpoint, WECHAT_FILE_MODE);
|
|
@@ -389,7 +390,7 @@ async function tightenEndpointPermission(endpoint) {
|
|
|
389
390
|
}
|
|
390
391
|
async function ensureCurrentUserCanAccess(endpoint) {
|
|
391
392
|
await new Promise((resolve, reject) => {
|
|
392
|
-
const probe =
|
|
393
|
+
const probe = createBrokerSocket(endpoint);
|
|
393
394
|
probe.once("connect", () => {
|
|
394
395
|
probe.end();
|
|
395
396
|
resolve();
|
|
@@ -398,7 +399,7 @@ async function ensureCurrentUserCanAccess(endpoint) {
|
|
|
398
399
|
});
|
|
399
400
|
}
|
|
400
401
|
async function prepareEndpoint(endpoint) {
|
|
401
|
-
if (process.platform === "win32") {
|
|
402
|
+
if (process.platform === "win32" || isTcpBrokerEndpoint(endpoint)) {
|
|
402
403
|
return;
|
|
403
404
|
}
|
|
404
405
|
await mkdir(path.dirname(endpoint), { recursive: true, mode: WECHAT_DIR_MODE });
|
|
@@ -438,16 +439,10 @@ export async function startBrokerServer(endpoint) {
|
|
|
438
439
|
}
|
|
439
440
|
});
|
|
440
441
|
});
|
|
441
|
-
await
|
|
442
|
-
server.once("error", reject);
|
|
443
|
-
server.listen(endpoint, () => {
|
|
444
|
-
server.off("error", reject);
|
|
445
|
-
resolve();
|
|
446
|
-
});
|
|
447
|
-
});
|
|
442
|
+
const boundEndpoint = await listenOnBrokerEndpoint(server, endpoint);
|
|
448
443
|
try {
|
|
449
|
-
await tightenEndpointPermission(
|
|
450
|
-
await ensureCurrentUserCanAccess(
|
|
444
|
+
await tightenEndpointPermission(boundEndpoint);
|
|
445
|
+
await ensureCurrentUserCanAccess(boundEndpoint);
|
|
451
446
|
}
|
|
452
447
|
catch (error) {
|
|
453
448
|
await new Promise((resolve) => {
|
|
@@ -528,13 +523,13 @@ export async function startBrokerServer(endpoint) {
|
|
|
528
523
|
await new Promise((resolve) => {
|
|
529
524
|
server.close(() => resolve());
|
|
530
525
|
});
|
|
531
|
-
if (process.platform !== "win32") {
|
|
526
|
+
if (process.platform !== "win32" && !isTcpBrokerEndpoint(endpoint)) {
|
|
532
527
|
await rm(endpoint, { force: true });
|
|
533
528
|
}
|
|
534
529
|
clearRuntimeState();
|
|
535
530
|
};
|
|
536
531
|
return {
|
|
537
|
-
endpoint,
|
|
532
|
+
endpoint: boundEndpoint,
|
|
538
533
|
startedAt: Date.now(),
|
|
539
534
|
collectStatus,
|
|
540
535
|
handleWechatSlashCommand,
|