opentray 0.0.0 → 0.2.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/README.md +45 -0
- package/dist/cli.d.mts +18 -0
- package/dist/cli.d.mts.map +1 -0
- package/dist/cli.mjs +474 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/client-BfXT-Zz9.mjs +86 -0
- package/dist/client-BfXT-Zz9.mjs.map +1 -0
- package/dist/client-COyxXT9C.d.mts +29 -0
- package/dist/client-COyxXT9C.d.mts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +3 -0
- package/dist/local-broker-CXOpd9Z8.mjs +502 -0
- package/dist/local-broker-CXOpd9Z8.mjs.map +1 -0
- package/dist/node.d.mts +45 -0
- package/dist/node.d.mts.map +1 -0
- package/dist/node.mjs +2 -0
- package/package.json +33 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-BfXT-Zz9.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n PROTOCOL_VERSION,\n type ClientFrame,\n type ClientRequestFrame,\n type RequestId,\n type ServerFrame,\n type SurfaceOptions,\n type SurfaceRef,\n type TrayId,\n type TrayOptions,\n} from \"@opentray/spec\";\n\nexport interface OpenTrayTransport {\n request(frame: ClientRequestFrame): Promise<ServerFrame>;\n}\n\nexport interface OpenTrayClient {\n createSurface(options: SurfaceOptions): Promise<SurfaceHandle>;\n}\n\nexport interface SurfaceHandle {\n surface: SurfaceRef;\n createTray(options: TrayOptions): Promise<TrayHandle>;\n}\n\nexport interface TrayHandle {\n surface: SurfaceRef;\n trayId: TrayId;\n commandExtension(ext: string, data: unknown): Promise<void>;\n destroy(): Promise<void>;\n}\n\nexport const createInitFrame = (clientVersion: string): ClientFrame => ({\n type: \"init\",\n protocolVersion: PROTOCOL_VERSION,\n clientVersion,\n});\n\nexport interface CreateClientOptions {\n requestIdPrefix?: string;\n}\n\nexport const createClient = (\n transport: OpenTrayTransport,\n options: CreateClientOptions = {},\n): OpenTrayClient => {\n const nextRequestId = createRequestIdFactory(options.requestIdPrefix ?? \"opentray\");\n\n return {\n async createSurface(surfaceOptions): Promise<SurfaceHandle> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"create-surface\",\n requestId,\n ...surfaceOptions,\n });\n const surface = expectResponse(response, requestId, \"surface-created\").surface;\n return createSurfaceHandle(transport, surface, nextRequestId);\n },\n };\n};\n\nexport const createSurfaceHandle = (\n transport: OpenTrayTransport,\n surface: SurfaceRef,\n nextRequestId: () => RequestId = createRequestIdFactory(\"opentray\"),\n): SurfaceHandle => ({\n surface,\n async createTray(options: TrayOptions): Promise<TrayHandle> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"create-tray\",\n requestId,\n surface,\n tray: options,\n });\n const frame = expectResponse(response, requestId, \"tray-created\");\n return createTrayHandle(transport, surface, frame.trayId, nextRequestId);\n },\n});\n\nexport const createTrayHandle = (\n transport: OpenTrayTransport,\n surface: SurfaceRef,\n trayId: TrayId,\n nextRequestId: () => RequestId = createRequestIdFactory(\"opentray\"),\n): TrayHandle => ({\n surface,\n trayId,\n async commandExtension(ext: string, data: unknown): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"ext-command\",\n requestId,\n surfaceId: surface.surfaceId,\n trayId,\n ext,\n data,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async destroy(): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"destroy-tray\",\n requestId,\n surfaceId: surface.surfaceId,\n trayId,\n });\n expectResponse(response, requestId, \"ack\");\n },\n});\n\nconst createRequestIdFactory = (prefix: string): (() => RequestId) => {\n let next = 1;\n return () => {\n const requestId = `${prefix}-${next}`;\n next += 1;\n return requestId;\n };\n};\n\nconst expectResponse = <TType extends ServerFrame[\"type\"]>(\n frame: ServerFrame,\n requestId: RequestId,\n type: TType,\n): Extract<ServerFrame, { type: TType }> => {\n if (frame.type === \"error\") {\n throw new Error(`${frame.code}: ${frame.message}`);\n }\n if (frame.type !== type) {\n throw new Error(`expected ${type} for ${requestId}, received ${frame.type}`);\n }\n if (requestIdOf(frame) !== requestId) {\n throw new Error(`expected response for ${requestId}, received ${requestIdOf(frame) ?? \"none\"}`);\n }\n return frame as Extract<ServerFrame, { type: TType }>;\n};\n\nconst requestIdOf = (frame: ServerFrame): RequestId | undefined => {\n switch (frame.type) {\n case \"surface-created\":\n case \"default-surface\":\n case \"tray-created\":\n case \"ack\":\n case \"daemon-health\":\n return frame.requestId;\n case \"error\":\n return frame.requestId;\n case \"ready\":\n case \"event\":\n case \"ext-event\":\n return undefined;\n }\n};\n"],"mappings":";;AAgCA,MAAa,mBAAmB,mBAAwC;CACtE,MAAM;CACN,iBAAiB;CACjB;AACF;AAMA,MAAa,gBACX,WACA,UAA+B,CAAC,MACb;CACnB,MAAM,gBAAgB,uBAAuB,QAAQ,mBAAmB,UAAU;CAElF,OAAO,EACL,MAAM,cAAc,gBAAwC;EAC1D,MAAM,YAAY,cAAc;EAMhC,MAAM,UAAU,eAAe,MALR,UAAU,QAAQ;GACvC,MAAM;GACN;GACA,GAAG;EACL,CAAC,GACwC,WAAW,iBAAiB,EAAE;EACvE,OAAO,oBAAoB,WAAW,SAAS,aAAa;CAC9D,EACF;AACF;AAEA,MAAa,uBACX,WACA,SACA,gBAAiC,uBAAuB,UAAU,OAC/C;CACnB;CACA,MAAM,WAAW,SAA2C;EAC1D,MAAM,YAAY,cAAc;EAQhC,OAAO,iBAAiB,WAAW,SADrB,eAAe,MANN,UAAU,QAAQ;GACvC,MAAM;GACN;GACA;GACA,MAAM;EACR,CAAC,GACsC,WAAW,cACF,EAAE,QAAQ,aAAa;CACzE;AACF;AAEA,MAAa,oBACX,WACA,SACA,QACA,gBAAiC,uBAAuB,UAAU,OAClD;CAChB;CACA;CACA,MAAM,iBAAiB,KAAa,MAA8B;EAChE,MAAM,YAAY,cAAc;EAShC,eAAe,MARQ,UAAU,QAAQ;GACvC,MAAM;GACN;GACA,WAAW,QAAQ;GACnB;GACA;GACA;EACF,CAAC,GACwB,WAAW,KAAK;CAC3C;CACA,MAAM,UAAyB;EAC7B,MAAM,YAAY,cAAc;EAOhC,eAAe,MANQ,UAAU,QAAQ;GACvC,MAAM;GACN;GACA,WAAW,QAAQ;GACnB;EACF,CAAC,GACwB,WAAW,KAAK;CAC3C;AACF;AAEA,MAAM,0BAA0B,WAAsC;CACpE,IAAI,OAAO;CACX,aAAa;EACX,MAAM,YAAY,GAAG,OAAO,GAAG;EAC/B,QAAQ;EACR,OAAO;CACT;AACF;AAEA,MAAM,kBACJ,OACA,WACA,SAC0C;CAC1C,IAAI,MAAM,SAAS,SACjB,MAAM,IAAI,MAAM,GAAG,MAAM,KAAK,IAAI,MAAM,SAAS;CAEnD,IAAI,MAAM,SAAS,MACjB,MAAM,IAAI,MAAM,YAAY,KAAK,OAAO,UAAU,aAAa,MAAM,MAAM;CAE7E,IAAI,YAAY,KAAK,MAAM,WACzB,MAAM,IAAI,MAAM,yBAAyB,UAAU,aAAa,YAAY,KAAK,KAAK,QAAQ;CAEhG,OAAO;AACT;AAEA,MAAM,eAAe,UAA8C;CACjE,QAAQ,MAAM,MAAd;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,iBACH,OAAO,MAAM;EACf,KAAK,SACH,OAAO,MAAM;EACf,KAAK;EACL,KAAK;EACL,KAAK,aACH;CACJ;AACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ClientFrame, ClientRequestFrame, RequestId, ServerFrame, SurfaceOptions, SurfaceRef, TrayId, TrayOptions } from "@opentray/spec";
|
|
2
|
+
|
|
3
|
+
//#region src/client.d.ts
|
|
4
|
+
interface OpenTrayTransport {
|
|
5
|
+
request(frame: ClientRequestFrame): Promise<ServerFrame>;
|
|
6
|
+
}
|
|
7
|
+
interface OpenTrayClient {
|
|
8
|
+
createSurface(options: SurfaceOptions): Promise<SurfaceHandle>;
|
|
9
|
+
}
|
|
10
|
+
interface SurfaceHandle {
|
|
11
|
+
surface: SurfaceRef;
|
|
12
|
+
createTray(options: TrayOptions): Promise<TrayHandle>;
|
|
13
|
+
}
|
|
14
|
+
interface TrayHandle {
|
|
15
|
+
surface: SurfaceRef;
|
|
16
|
+
trayId: TrayId;
|
|
17
|
+
commandExtension(ext: string, data: unknown): Promise<void>;
|
|
18
|
+
destroy(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
declare const createInitFrame: (clientVersion: string) => ClientFrame;
|
|
21
|
+
interface CreateClientOptions {
|
|
22
|
+
requestIdPrefix?: string;
|
|
23
|
+
}
|
|
24
|
+
declare const createClient: (transport: OpenTrayTransport, options?: CreateClientOptions) => OpenTrayClient;
|
|
25
|
+
declare const createSurfaceHandle: (transport: OpenTrayTransport, surface: SurfaceRef, nextRequestId?: () => RequestId) => SurfaceHandle;
|
|
26
|
+
declare const createTrayHandle: (transport: OpenTrayTransport, surface: SurfaceRef, trayId: TrayId, nextRequestId?: () => RequestId) => TrayHandle;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { TrayHandle as a, createSurfaceHandle as c, SurfaceHandle as i, createTrayHandle as l, OpenTrayClient as n, createClient as o, OpenTrayTransport as r, createInitFrame as s, CreateClientOptions as t };
|
|
29
|
+
//# sourceMappingURL=client-COyxXT9C.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-COyxXT9C.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;UAYiB,iBAAA;EACf,OAAA,CAAQ,KAAA,EAAO,kBAAA,GAAqB,OAAA,CAAQ,WAAA;AAAA;AAAA,UAG7B,cAAA;EACf,aAAA,CAAc,OAAA,EAAS,cAAA,GAAiB,OAAA,CAAQ,aAAA;AAAA;AAAA,UAGjC,aAAA;EACf,OAAA,EAAS,UAAA;EACT,UAAA,CAAW,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,UAAA;AAAA;AAAA,UAG3B,UAAA;EACf,OAAA,EAAS,UAAA;EACT,MAAA,EAAQ,MAAA;EACR,gBAAA,CAAiB,GAAA,UAAa,IAAA,YAAgB,OAAA;EAC9C,OAAA,IAAW,OAAA;AAAA;AAAA,cAGA,eAAA,GAAmB,aAAA,aAAwB,WAItD;AAAA,UAEe,mBAAA;EACf,eAAe;AAAA;AAAA,cAGJ,YAAA,GACX,SAAA,EAAW,iBAAA,EACX,OAAA,GAAS,mBAAA,KACR,cAAA;AAAA,cAiBU,mBAAA,GACX,SAAA,EAAW,iBAAA,EACX,OAAA,EAAS,UAAA,EACT,aAAA,SAAqB,SAAA,KACpB,aAAA;AAAA,cAeU,gBAAA,GACX,SAAA,EAAW,iBAAA,EACX,OAAA,EAAS,UAAA,EACT,MAAA,EAAQ,MAAA,EACR,aAAA,SAAqB,SAAA,KACpB,UAAA"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as TrayHandle, c as createSurfaceHandle, i as SurfaceHandle, l as createTrayHandle, n as OpenTrayClient, o as createClient, r as OpenTrayTransport, s as createInitFrame, t as CreateClientOptions } from "./client-COyxXT9C.mjs";
|
|
2
|
+
import { BrokerEndpointIdentity, BrokerEndpointIdentityOptions, PROTOCOL_VERSION, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion } from "@opentray/spec";
|
|
3
|
+
export { type BrokerEndpointIdentity, type BrokerEndpointIdentityOptions, type CreateClientOptions, type OpenTrayClient, type OpenTrayTransport, PROTOCOL_VERSION, type SurfaceHandle, type TrayHandle, createBrokerEndpointIdentity, createClient, createInitFrame, createSurfaceHandle, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { i as createTrayHandle, n as createInitFrame, r as createSurfaceHandle, t as createClient } from "./client-BfXT-Zz9.mjs";
|
|
2
|
+
import { PROTOCOL_VERSION, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion } from "@opentray/spec";
|
|
3
|
+
export { PROTOCOL_VERSION, createBrokerEndpointIdentity, createClient, createInitFrame, createSurfaceHandle, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion };
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { PROTOCOL_VERSION, createBrokerEndpointIdentity, formatUnixSocketPath, formatWindowsPipeName, parseServerFrame } from "@opentray/spec";
|
|
3
|
+
import { createConnection } from "node:net";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { constants } from "node:fs";
|
|
7
|
+
import { access, mkdir, open, readFile, rm, unlink, writeFile } from "node:fs/promises";
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
//#region src/daemon/native-target.ts
|
|
11
|
+
const resolveBrokerNativeTarget = (platform = process.platform, arch = process.arch) => {
|
|
12
|
+
const packageOs = platformToPackageOs(platform);
|
|
13
|
+
return {
|
|
14
|
+
packageName: `@opentray/${packageOs}-${normalizeArch(arch)}`,
|
|
15
|
+
binaryRelativePath: `bin/${packageOs === "windows" ? "opentray.exe" : "opentray"}`
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const platformToPackageOs = (platform) => {
|
|
19
|
+
switch (platform) {
|
|
20
|
+
case "darwin":
|
|
21
|
+
case "linux": return platform;
|
|
22
|
+
case "win32": return "windows";
|
|
23
|
+
default: throw new MissingPlatformBrokerBinaryError(`unsupported OpenTray broker platform: ${platform}`, platform, process.arch);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const normalizeArch = (arch) => {
|
|
27
|
+
switch (arch) {
|
|
28
|
+
case "arm64":
|
|
29
|
+
case "x64": return arch;
|
|
30
|
+
default: throw new MissingPlatformBrokerBinaryError(`unsupported OpenTray broker architecture: ${arch}`, process.platform, arch);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var MissingPlatformBrokerBinaryError = class extends Error {
|
|
34
|
+
code = "OPENTRAY_MISSING_PLATFORM_BROKER_BINARY";
|
|
35
|
+
platform;
|
|
36
|
+
arch;
|
|
37
|
+
packageName;
|
|
38
|
+
binaryPath;
|
|
39
|
+
constructor(message, platform, arch, options = {}) {
|
|
40
|
+
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
41
|
+
this.name = "MissingPlatformBrokerBinaryError";
|
|
42
|
+
this.platform = platform;
|
|
43
|
+
this.arch = arch;
|
|
44
|
+
this.packageName = options.packageName;
|
|
45
|
+
this.binaryPath = options.binaryPath;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/daemon/broker-command.ts
|
|
50
|
+
const sourceUrl = import.meta.url;
|
|
51
|
+
const requireFromSource = createRequire(sourceUrl);
|
|
52
|
+
const resolveBrokerCommand = async (paths, options = {}) => {
|
|
53
|
+
const explicit = (options.env ?? process.env).OPENTRAY_BROKER_BIN;
|
|
54
|
+
if (explicit !== void 0 && explicit.length > 0) return commandForBinary(explicit, paths);
|
|
55
|
+
const platform = options.platform ?? process.platform;
|
|
56
|
+
const arch = options.arch ?? process.arch;
|
|
57
|
+
let installedBinaryError;
|
|
58
|
+
try {
|
|
59
|
+
const installedBinary = await resolveInstalledBrokerBinary({
|
|
60
|
+
platform,
|
|
61
|
+
arch,
|
|
62
|
+
resolvePackageJson: options.resolvePackageJson ?? resolvePackageJson
|
|
63
|
+
});
|
|
64
|
+
if (installedBinary !== void 0) return commandForBinary(installedBinary, paths);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (!(error instanceof MissingPlatformBrokerBinaryError)) throw error;
|
|
67
|
+
installedBinaryError = error;
|
|
68
|
+
}
|
|
69
|
+
const sourceDir = options.sourceDir ?? dirname(fileURLToPath(sourceUrl));
|
|
70
|
+
const workspaceRoot = await (options.findWorkspaceRoot ?? findWorkspaceRoot)(sourceDir);
|
|
71
|
+
if (workspaceRoot !== void 0) return commandForBinary(await (options.ensureDevBrokerBinary ?? ensureDevBrokerBinary)(workspaceRoot), paths, workspaceRoot);
|
|
72
|
+
if (installedBinaryError !== void 0) throw installedBinaryError;
|
|
73
|
+
const target = resolveBrokerNativeTarget(platform, arch);
|
|
74
|
+
throw new MissingPlatformBrokerBinaryError(`unable to resolve OpenTray broker binary for ${platform}/${arch}; install ${target.packageName} or set OPENTRAY_BROKER_BIN`, platform, arch, { packageName: target.packageName });
|
|
75
|
+
};
|
|
76
|
+
const commandForBinary = (binary, paths, cwd) => {
|
|
77
|
+
const command = {
|
|
78
|
+
command: binary,
|
|
79
|
+
args: [
|
|
80
|
+
"broker",
|
|
81
|
+
"--endpoint",
|
|
82
|
+
paths.endpoint,
|
|
83
|
+
"--ready-file",
|
|
84
|
+
paths.readyFile,
|
|
85
|
+
"--package-version",
|
|
86
|
+
paths.packageVersion,
|
|
87
|
+
"--protocol-version",
|
|
88
|
+
`${paths.protocolVersion}`
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
if (cwd !== void 0) command.cwd = cwd;
|
|
92
|
+
return command;
|
|
93
|
+
};
|
|
94
|
+
const resolveInstalledBrokerBinary = async ({ platform, arch, resolvePackageJson }) => {
|
|
95
|
+
const target = resolveBrokerNativeTarget(platform, arch);
|
|
96
|
+
const packageJsonPath = resolvePackageJson(target.packageName);
|
|
97
|
+
if (packageJsonPath === void 0) return;
|
|
98
|
+
const binary = join(dirname(packageJsonPath), target.binaryRelativePath);
|
|
99
|
+
if (!await exists(binary)) throw new MissingPlatformBrokerBinaryError(`OpenTray broker package ${target.packageName} is installed but missing ${target.binaryRelativePath}`, platform, arch, {
|
|
100
|
+
packageName: target.packageName,
|
|
101
|
+
binaryPath: binary
|
|
102
|
+
});
|
|
103
|
+
return binary;
|
|
104
|
+
};
|
|
105
|
+
const resolvePackageJson = (packageName) => {
|
|
106
|
+
try {
|
|
107
|
+
return requireFromSource.resolve(`${packageName}/package.json`);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (isNodeError$1(error) && error.code === "MODULE_NOT_FOUND") return;
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const findWorkspaceRoot = async (start) => {
|
|
114
|
+
let current = start;
|
|
115
|
+
while (true) {
|
|
116
|
+
if (await exists(join(current, "Cargo.toml"))) {
|
|
117
|
+
if (await exists(join(current, "crates", "opentray-bin", "Cargo.toml"))) return current;
|
|
118
|
+
}
|
|
119
|
+
const parent = dirname(current);
|
|
120
|
+
if (parent === current) return;
|
|
121
|
+
current = parent;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const ensureDevBrokerBinary = async (workspaceRoot) => {
|
|
125
|
+
const binary = join(workspaceRoot, "target", "debug", process.platform === "win32" ? "opentray.exe" : "opentray");
|
|
126
|
+
await runCargoBuild(workspaceRoot);
|
|
127
|
+
return binary;
|
|
128
|
+
};
|
|
129
|
+
const runCargoBuild = (workspaceRoot) => new Promise((resolve, reject) => {
|
|
130
|
+
const child = spawn("cargo", [
|
|
131
|
+
"build",
|
|
132
|
+
"-p",
|
|
133
|
+
"opentray-bin"
|
|
134
|
+
], {
|
|
135
|
+
cwd: workspaceRoot,
|
|
136
|
+
stdio: process.env.OPENTRAY_BROKER_BUILD_LOGS === "1" ? "inherit" : "ignore"
|
|
137
|
+
});
|
|
138
|
+
child.once("error", reject);
|
|
139
|
+
child.once("exit", (code) => {
|
|
140
|
+
if (code === 0) {
|
|
141
|
+
resolve();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
reject(/* @__PURE__ */ new Error(`cargo build -p opentray-bin failed with code ${code ?? "unknown"}`));
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
const exists = async (path) => {
|
|
148
|
+
try {
|
|
149
|
+
await access(path, constants.F_OK);
|
|
150
|
+
return true;
|
|
151
|
+
} catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const isNodeError$1 = (error) => error instanceof Error && "code" in error;
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/daemon/lifecycle.ts
|
|
158
|
+
const createNodeDaemonDriver = (cliEntrypoint) => ({
|
|
159
|
+
async isAlive(pid) {
|
|
160
|
+
return isProcessAlive(pid);
|
|
161
|
+
},
|
|
162
|
+
async spawnBroker(paths) {
|
|
163
|
+
const broker = await resolveBrokerCommand(paths);
|
|
164
|
+
const child = spawn(broker.command, broker.args, {
|
|
165
|
+
cwd: broker.cwd,
|
|
166
|
+
detached: true,
|
|
167
|
+
env: {
|
|
168
|
+
...process.env,
|
|
169
|
+
OPENTRAY_DAEMON_HOME: paths.homeDir,
|
|
170
|
+
OPENTRAY_DAEMON_PACKAGE_VERSION: paths.packageVersion,
|
|
171
|
+
OPENTRAY_DAEMON_CLI_ENTRYPOINT: cliEntrypoint
|
|
172
|
+
},
|
|
173
|
+
stdio: "ignore"
|
|
174
|
+
});
|
|
175
|
+
child.unref();
|
|
176
|
+
return child.pid ?? 0;
|
|
177
|
+
},
|
|
178
|
+
async stop(pid) {
|
|
179
|
+
process.kill(pid, "SIGTERM");
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const startDaemon = async ({ paths, driver, lockTimeoutMs = 1e3 }) => {
|
|
183
|
+
await mkdir(paths.runtimeDir, { recursive: true });
|
|
184
|
+
const lock = await acquireLock(paths.lockFile, lockTimeoutMs);
|
|
185
|
+
try {
|
|
186
|
+
const existingPid = await readPid(paths.pidFile);
|
|
187
|
+
if (existingPid !== void 0 && await driver.isAlive(existingPid)) return {
|
|
188
|
+
status: "already-running",
|
|
189
|
+
pid: existingPid,
|
|
190
|
+
paths
|
|
191
|
+
};
|
|
192
|
+
await cleanupRuntimeFiles(paths);
|
|
193
|
+
const pid = await driver.spawnBroker(paths);
|
|
194
|
+
if (!Number.isInteger(pid) || pid <= 0) throw new Error("daemon broker process did not expose a valid pid");
|
|
195
|
+
await writeFile(paths.pidFile, `${pid}\n`, "utf8");
|
|
196
|
+
await waitForReadyFile(paths.readyFile);
|
|
197
|
+
return {
|
|
198
|
+
status: "started",
|
|
199
|
+
pid,
|
|
200
|
+
paths
|
|
201
|
+
};
|
|
202
|
+
} finally {
|
|
203
|
+
await lock.release();
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const stopDaemon = async ({ paths, driver }) => {
|
|
207
|
+
const pid = await readPid(paths.pidFile);
|
|
208
|
+
if (pid === void 0 || !await driver.isAlive(pid)) {
|
|
209
|
+
await cleanupRuntimeFiles(paths);
|
|
210
|
+
return {
|
|
211
|
+
status: "not-running",
|
|
212
|
+
paths
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
await driver.stop(pid);
|
|
216
|
+
await waitUntilStopped(driver, pid);
|
|
217
|
+
await cleanupRuntimeFiles(paths);
|
|
218
|
+
return {
|
|
219
|
+
status: "stopped",
|
|
220
|
+
pid,
|
|
221
|
+
paths
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
const restartDaemon = async (options) => {
|
|
225
|
+
await stopDaemon({
|
|
226
|
+
paths: options.paths,
|
|
227
|
+
driver: options.driver
|
|
228
|
+
});
|
|
229
|
+
return startDaemon(options);
|
|
230
|
+
};
|
|
231
|
+
const inspectDaemon = async ({ paths, driver }) => {
|
|
232
|
+
const pid = await readPid(paths.pidFile);
|
|
233
|
+
if (pid !== void 0 && await driver.isAlive(pid)) return {
|
|
234
|
+
status: "running",
|
|
235
|
+
pid,
|
|
236
|
+
paths
|
|
237
|
+
};
|
|
238
|
+
await cleanupRuntimeFiles(paths);
|
|
239
|
+
return pid === void 0 ? {
|
|
240
|
+
status: "not-running",
|
|
241
|
+
paths
|
|
242
|
+
} : {
|
|
243
|
+
status: "not-running",
|
|
244
|
+
paths,
|
|
245
|
+
stalePid: pid
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
const readPid = async (pidFile) => {
|
|
249
|
+
try {
|
|
250
|
+
const content = await readFile(pidFile, "utf8");
|
|
251
|
+
const pid = Number.parseInt(content.trim(), 10);
|
|
252
|
+
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (isNodeError(error) && error.code === "ENOENT") return;
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
const cleanupRuntimeFiles = async (paths) => {
|
|
259
|
+
await rm(paths.readyFile, { force: true });
|
|
260
|
+
await rm(paths.pidFile, { force: true });
|
|
261
|
+
if (process.platform !== "win32") await rm(paths.endpoint, { force: true });
|
|
262
|
+
};
|
|
263
|
+
const waitUntilStopped = async (driver, pid) => {
|
|
264
|
+
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
265
|
+
if (!await driver.isAlive(pid)) return;
|
|
266
|
+
await sleep(50);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
const waitForReadyFile = async (readyFile) => {
|
|
270
|
+
for (let attempt = 0; attempt < 40; attempt += 1) try {
|
|
271
|
+
await readFile(readyFile, "utf8");
|
|
272
|
+
return;
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if (!isNodeError(error) || error.code !== "ENOENT") throw error;
|
|
275
|
+
await sleep(50);
|
|
276
|
+
}
|
|
277
|
+
throw new Error(`timed out waiting for daemon readiness: ${readyFile}`);
|
|
278
|
+
};
|
|
279
|
+
const acquireLock = async (lockFile, timeoutMs) => {
|
|
280
|
+
const deadline = Date.now() + timeoutMs;
|
|
281
|
+
while (Date.now() <= deadline) try {
|
|
282
|
+
const handle = await open(lockFile, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);
|
|
283
|
+
await handle.writeFile(`${process.pid}\n`, "utf8");
|
|
284
|
+
return { async release() {
|
|
285
|
+
await handle.close();
|
|
286
|
+
await unlink(lockFile).catch((error) => {
|
|
287
|
+
if (!isNodeError(error) || error.code !== "ENOENT") throw error;
|
|
288
|
+
});
|
|
289
|
+
} };
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (isNodeError(error) && error.code === "EEXIST") {
|
|
292
|
+
await sleep(25);
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
throw new Error(`timed out acquiring daemon lock: ${lockFile}`);
|
|
298
|
+
};
|
|
299
|
+
const isProcessAlive = (pid) => {
|
|
300
|
+
try {
|
|
301
|
+
process.kill(pid, 0);
|
|
302
|
+
return true;
|
|
303
|
+
} catch {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
308
|
+
const isNodeError = (error) => error instanceof Error && "code" in error;
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region src/daemon/package-version.ts
|
|
311
|
+
const readPackageVersion = async (packageJsonUrl) => {
|
|
312
|
+
const value = JSON.parse(await readFile(packageJsonUrl, "utf8"));
|
|
313
|
+
if (!isPackageJsonWithVersion(value)) throw new Error(`package.json is missing a string version: ${packageJsonUrl.href}`);
|
|
314
|
+
return value.version;
|
|
315
|
+
};
|
|
316
|
+
const isPackageJsonWithVersion = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && "version" in value && typeof value.version === "string";
|
|
317
|
+
//#endregion
|
|
318
|
+
//#region src/daemon/paths.ts
|
|
319
|
+
const resolveDaemonPaths = ({ homeDir, packageVersion, platform = process.platform }) => {
|
|
320
|
+
const identity = createBrokerEndpointIdentity({ packageVersion });
|
|
321
|
+
const normalizedHome = homeDir.replace(/[\\/]+$/u, "");
|
|
322
|
+
const stateRoot = `${normalizedHome}/.opentray/${identity.packageVersion}`;
|
|
323
|
+
const runtimeDir = `${stateRoot}/runtime`;
|
|
324
|
+
const endpoint = platform === "win32" ? formatWindowsPipeName(identity) : formatUnixSocketPath(normalizedHome, identity);
|
|
325
|
+
return {
|
|
326
|
+
homeDir: normalizedHome,
|
|
327
|
+
packageVersion: identity.packageVersion,
|
|
328
|
+
protocolVersion: identity.protocolVersion,
|
|
329
|
+
stateRoot,
|
|
330
|
+
runtimeDir,
|
|
331
|
+
endpoint,
|
|
332
|
+
pidFile: `${runtimeDir}/broker.pid`,
|
|
333
|
+
lockFile: `${runtimeDir}/broker.lock`,
|
|
334
|
+
readyFile: `${runtimeDir}/ready.json`
|
|
335
|
+
};
|
|
336
|
+
};
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/local-broker.ts
|
|
339
|
+
const packageJsonUrl = new URL("../package.json", import.meta.url);
|
|
340
|
+
const connectLocalBroker = async (options = {}) => {
|
|
341
|
+
const packageVersion = options.packageVersion ?? await readPackageVersion(packageJsonUrl);
|
|
342
|
+
const clientVersion = options.clientVersion ?? packageVersion;
|
|
343
|
+
const paths = resolveDaemonPaths({
|
|
344
|
+
homeDir: options.homeDir ?? process.env.OPENTRAY_HOME ?? homedir(),
|
|
345
|
+
packageVersion
|
|
346
|
+
});
|
|
347
|
+
const endpoint = options.endpoint ?? paths.endpoint;
|
|
348
|
+
const autoStart = options.autoStart ?? endpoint === paths.endpoint;
|
|
349
|
+
if (autoStart && endpoint !== paths.endpoint) throw new Error("local broker autoStart requires the derived same-version endpoint");
|
|
350
|
+
if (autoStart) {
|
|
351
|
+
const cliEntrypoint = options.cliEntrypoint ?? resolveCliEntrypoint();
|
|
352
|
+
await startDaemon({
|
|
353
|
+
paths,
|
|
354
|
+
driver: options.daemonDriver ?? createNodeDaemonDriver(cliEntrypoint)
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
const connection = new LocalBrokerConnection(await connectSocket(endpoint), endpoint);
|
|
358
|
+
await connection.init(clientVersion, options.protocolVersion ?? PROTOCOL_VERSION);
|
|
359
|
+
return connection;
|
|
360
|
+
};
|
|
361
|
+
var LocalBrokerConnection = class {
|
|
362
|
+
socket;
|
|
363
|
+
endpoint;
|
|
364
|
+
leaseId = "";
|
|
365
|
+
buffer = "";
|
|
366
|
+
listeners = /* @__PURE__ */ new Set();
|
|
367
|
+
pending = /* @__PURE__ */ new Map();
|
|
368
|
+
ready;
|
|
369
|
+
constructor(socket, endpoint) {
|
|
370
|
+
this.socket = socket;
|
|
371
|
+
this.endpoint = endpoint;
|
|
372
|
+
socket.setEncoding("utf8");
|
|
373
|
+
socket.on("data", (chunk) => {
|
|
374
|
+
this.consume(String(chunk));
|
|
375
|
+
});
|
|
376
|
+
socket.on("error", (error) => {
|
|
377
|
+
this.rejectAll(error);
|
|
378
|
+
});
|
|
379
|
+
socket.on("close", () => {
|
|
380
|
+
this.rejectAll(/* @__PURE__ */ new Error("broker connection closed"));
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
async init(clientVersion, protocolVersion) {
|
|
384
|
+
const ready = new Promise((resolve, reject) => {
|
|
385
|
+
this.ready = {
|
|
386
|
+
resolve,
|
|
387
|
+
reject
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
this.write({
|
|
391
|
+
type: "init",
|
|
392
|
+
protocolVersion,
|
|
393
|
+
clientVersion
|
|
394
|
+
});
|
|
395
|
+
const frame = await ready;
|
|
396
|
+
this.leaseId = frame.leaseId;
|
|
397
|
+
}
|
|
398
|
+
async request(frame) {
|
|
399
|
+
if (this.pending.has(frame.requestId)) throw new Error(`duplicate requestId: ${frame.requestId}`);
|
|
400
|
+
const response = new Promise((resolve, reject) => {
|
|
401
|
+
this.pending.set(frame.requestId, {
|
|
402
|
+
resolve,
|
|
403
|
+
reject
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
this.write(frame);
|
|
407
|
+
return response;
|
|
408
|
+
}
|
|
409
|
+
onEvent(listener) {
|
|
410
|
+
this.listeners.add(listener);
|
|
411
|
+
return () => {
|
|
412
|
+
this.listeners.delete(listener);
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
async close() {
|
|
416
|
+
this.write({ type: "exit" });
|
|
417
|
+
await new Promise((resolve) => {
|
|
418
|
+
this.socket.end(resolve);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
consume(chunk) {
|
|
422
|
+
this.buffer += chunk;
|
|
423
|
+
while (true) {
|
|
424
|
+
const newline = this.buffer.indexOf("\n");
|
|
425
|
+
if (newline < 0) return;
|
|
426
|
+
const line = this.buffer.slice(0, newline).trim();
|
|
427
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
428
|
+
if (line.length > 0) this.dispatchLine(line);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
dispatchLine(line) {
|
|
432
|
+
const parsed = parseServerFrame(line);
|
|
433
|
+
if (!parsed.ok || parsed.frame === void 0) {
|
|
434
|
+
this.rejectAll(new Error(parsed.error ?? "invalid server frame"));
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
this.dispatchFrame(parsed.frame);
|
|
438
|
+
}
|
|
439
|
+
dispatchFrame(frame) {
|
|
440
|
+
if (frame.type === "ready") {
|
|
441
|
+
this.ready?.resolve(frame);
|
|
442
|
+
this.ready = void 0;
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (frame.type === "error") {
|
|
446
|
+
const error = /* @__PURE__ */ new Error(`${frame.code}: ${frame.message}`);
|
|
447
|
+
if (frame.requestId !== void 0) {
|
|
448
|
+
this.pending.get(frame.requestId)?.reject(error);
|
|
449
|
+
this.pending.delete(frame.requestId);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
this.ready?.reject(error);
|
|
453
|
+
this.ready = void 0;
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const requestId = responseRequestId(frame);
|
|
457
|
+
if (requestId !== void 0) {
|
|
458
|
+
this.pending.get(requestId)?.resolve(frame);
|
|
459
|
+
this.pending.delete(requestId);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (frame.type === "event" || frame.type === "ext-event") for (const listener of this.listeners) listener(frame);
|
|
463
|
+
}
|
|
464
|
+
write(frame) {
|
|
465
|
+
this.socket.write(`${JSON.stringify(frame)}\n`);
|
|
466
|
+
}
|
|
467
|
+
rejectAll(error) {
|
|
468
|
+
this.ready?.reject(error);
|
|
469
|
+
this.ready = void 0;
|
|
470
|
+
for (const pending of this.pending.values()) pending.reject(error);
|
|
471
|
+
this.pending.clear();
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
const connectSocket = (endpoint) => new Promise((resolve, reject) => {
|
|
475
|
+
const socket = createConnection(endpoint);
|
|
476
|
+
socket.once("connect", () => {
|
|
477
|
+
socket.off("error", reject);
|
|
478
|
+
resolve(socket);
|
|
479
|
+
});
|
|
480
|
+
socket.once("error", reject);
|
|
481
|
+
});
|
|
482
|
+
const responseRequestId = (frame) => {
|
|
483
|
+
switch (frame.type) {
|
|
484
|
+
case "surface-created":
|
|
485
|
+
case "default-surface":
|
|
486
|
+
case "tray-created":
|
|
487
|
+
case "ack":
|
|
488
|
+
case "daemon-health": return frame.requestId;
|
|
489
|
+
case "ready":
|
|
490
|
+
case "event":
|
|
491
|
+
case "ext-event":
|
|
492
|
+
case "error": return;
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const resolveCliEntrypoint = () => {
|
|
496
|
+
const suffix = fileURLToPath(import.meta.url).endsWith(".ts") ? "cli.ts" : "cli.mjs";
|
|
497
|
+
return fileURLToPath(new URL(`./${suffix}`, import.meta.url));
|
|
498
|
+
};
|
|
499
|
+
//#endregion
|
|
500
|
+
export { inspectDaemon as a, stopDaemon as c, createNodeDaemonDriver as i, resolveDaemonPaths as n, restartDaemon as o, readPackageVersion as r, startDaemon as s, connectLocalBroker as t };
|
|
501
|
+
|
|
502
|
+
//# sourceMappingURL=local-broker-CXOpd9Z8.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-broker-CXOpd9Z8.mjs","names":["isNodeError"],"sources":["../src/daemon/native-target.ts","../src/daemon/broker-command.ts","../src/daemon/lifecycle.ts","../src/daemon/package-version.ts","../src/daemon/paths.ts","../src/local-broker.ts"],"sourcesContent":["export type BrokerPackageOs = \"darwin\" | \"linux\" | \"windows\";\nexport type BrokerArch = \"arm64\" | \"x64\";\n\nexport interface BrokerNativeTarget {\n packageName: string;\n binaryRelativePath: string;\n}\n\nexport const resolveBrokerNativeTarget = (\n platform: string = process.platform,\n arch: string = process.arch,\n): BrokerNativeTarget => {\n const packageOs = platformToPackageOs(platform);\n const nativeArch = normalizeArch(arch);\n return {\n packageName: `@opentray/${packageOs}-${nativeArch}`,\n binaryRelativePath: `bin/${packageOs === \"windows\" ? \"opentray.exe\" : \"opentray\"}`,\n };\n};\n\nconst platformToPackageOs = (platform: string): BrokerPackageOs => {\n switch (platform) {\n case \"darwin\":\n case \"linux\":\n return platform;\n case \"win32\":\n return \"windows\";\n default:\n throw new MissingPlatformBrokerBinaryError(\n `unsupported OpenTray broker platform: ${platform}`,\n platform,\n process.arch,\n );\n }\n};\n\nconst normalizeArch = (arch: string): BrokerArch => {\n switch (arch) {\n case \"arm64\":\n case \"x64\":\n return arch;\n default:\n throw new MissingPlatformBrokerBinaryError(\n `unsupported OpenTray broker architecture: ${arch}`,\n process.platform,\n arch,\n );\n }\n};\n\nexport class MissingPlatformBrokerBinaryError extends Error {\n readonly code = \"OPENTRAY_MISSING_PLATFORM_BROKER_BINARY\";\n readonly platform: string;\n readonly arch: string;\n readonly packageName: string | undefined;\n readonly binaryPath: string | undefined;\n\n constructor(\n message: string,\n platform: string,\n arch: string,\n options: {\n packageName?: string;\n binaryPath?: string;\n cause?: unknown;\n } = {},\n ) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = \"MissingPlatformBrokerBinaryError\";\n this.platform = platform;\n this.arch = arch;\n this.packageName = options.packageName;\n this.binaryPath = options.binaryPath;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn } from \"node:child_process\";\n\nimport type { DaemonPaths } from \"./paths\";\nimport { MissingPlatformBrokerBinaryError, resolveBrokerNativeTarget } from \"./native-target\";\n\nexport interface BrokerCommand {\n command: string;\n args: string[];\n cwd?: string;\n}\n\nconst sourceUrl = import.meta.url;\nconst requireFromSource = createRequire(sourceUrl);\n\nexport interface ResolveBrokerCommandOptions {\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n arch?: string;\n sourceDir?: string;\n resolvePackageJson?: (packageName: string) => string | undefined;\n findWorkspaceRoot?: (start: string) => Promise<string | undefined>;\n ensureDevBrokerBinary?: (workspaceRoot: string) => Promise<string>;\n}\n\nexport const resolveBrokerCommand = async (\n paths: DaemonPaths,\n options: ResolveBrokerCommandOptions = {},\n): Promise<BrokerCommand> => {\n const env = options.env ?? process.env;\n const explicit = env.OPENTRAY_BROKER_BIN;\n if (explicit !== undefined && explicit.length > 0) {\n return commandForBinary(explicit, paths);\n }\n\n const platform = options.platform ?? process.platform;\n const arch = options.arch ?? process.arch;\n let installedBinaryError: MissingPlatformBrokerBinaryError | undefined;\n try {\n const installedBinary = await resolveInstalledBrokerBinary({\n platform,\n arch,\n resolvePackageJson: options.resolvePackageJson ?? resolvePackageJson,\n });\n if (installedBinary !== undefined) {\n return commandForBinary(installedBinary, paths);\n }\n } catch (error) {\n if (!(error instanceof MissingPlatformBrokerBinaryError)) {\n throw error;\n }\n installedBinaryError = error;\n }\n\n const sourceDir = options.sourceDir ?? dirname(fileURLToPath(sourceUrl));\n const workspaceRoot = await (options.findWorkspaceRoot ?? findWorkspaceRoot)(sourceDir);\n if (workspaceRoot !== undefined) {\n const binary = await (options.ensureDevBrokerBinary ?? ensureDevBrokerBinary)(workspaceRoot);\n return commandForBinary(binary, paths, workspaceRoot);\n }\n\n if (installedBinaryError !== undefined) {\n throw installedBinaryError;\n }\n\n const target = resolveBrokerNativeTarget(platform, arch);\n throw new MissingPlatformBrokerBinaryError(\n `unable to resolve OpenTray broker binary for ${platform}/${arch}; install ${target.packageName} or set OPENTRAY_BROKER_BIN`,\n platform,\n arch,\n { packageName: target.packageName },\n );\n};\n\nconst commandForBinary = (binary: string, paths: DaemonPaths, cwd?: string): BrokerCommand => {\n const command: BrokerCommand = {\n command: binary,\n args: [\n \"broker\",\n \"--endpoint\",\n paths.endpoint,\n \"--ready-file\",\n paths.readyFile,\n \"--package-version\",\n paths.packageVersion,\n \"--protocol-version\",\n `${paths.protocolVersion}`,\n ],\n };\n if (cwd !== undefined) {\n command.cwd = cwd;\n }\n return command;\n};\n\ninterface ResolveInstalledBrokerBinaryOptions {\n platform: NodeJS.Platform;\n arch: string;\n resolvePackageJson: (packageName: string) => string | undefined;\n}\n\nexport const resolveInstalledBrokerBinary = async ({\n platform,\n arch,\n resolvePackageJson,\n}: ResolveInstalledBrokerBinaryOptions): Promise<string | undefined> => {\n const target = resolveBrokerNativeTarget(platform, arch);\n const packageJsonPath = resolvePackageJson(target.packageName);\n if (packageJsonPath === undefined) {\n return undefined;\n }\n\n const binary = join(dirname(packageJsonPath), target.binaryRelativePath);\n if (!(await exists(binary))) {\n throw new MissingPlatformBrokerBinaryError(\n `OpenTray broker package ${target.packageName} is installed but missing ${target.binaryRelativePath}`,\n platform,\n arch,\n {\n packageName: target.packageName,\n binaryPath: binary,\n },\n );\n }\n\n return binary;\n};\n\nconst resolvePackageJson = (packageName: string): string | undefined => {\n try {\n return requireFromSource.resolve(`${packageName}/package.json`);\n } catch (error) {\n if (isNodeError(error) && error.code === \"MODULE_NOT_FOUND\") {\n return undefined;\n }\n throw error;\n }\n};\n\nconst findWorkspaceRoot = async (start: string): Promise<string | undefined> => {\n let current = start;\n while (true) {\n if (await exists(join(current, \"Cargo.toml\"))) {\n if (await exists(join(current, \"crates\", \"opentray-bin\", \"Cargo.toml\"))) {\n return current;\n }\n }\n\n const parent = dirname(current);\n if (parent === current) {\n return undefined;\n }\n current = parent;\n }\n};\n\nconst ensureDevBrokerBinary = async (workspaceRoot: string): Promise<string> => {\n const binary = join(\n workspaceRoot,\n \"target\",\n \"debug\",\n process.platform === \"win32\" ? \"opentray.exe\" : \"opentray\",\n );\n await runCargoBuild(workspaceRoot);\n return binary;\n};\n\nconst runCargoBuild = (workspaceRoot: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const child = spawn(\"cargo\", [\"build\", \"-p\", \"opentray-bin\"], {\n cwd: workspaceRoot,\n stdio: process.env.OPENTRAY_BROKER_BUILD_LOGS === \"1\" ? \"inherit\" : \"ignore\",\n });\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(new Error(`cargo build -p opentray-bin failed with code ${code ?? \"unknown\"}`));\n });\n });\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nconst isNodeError = (error: unknown): error is NodeJS.ErrnoException =>\n error instanceof Error && \"code\" in error;\n","import { constants } from \"node:fs\";\nimport { mkdir, open, readFile, rm, unlink, writeFile } from \"node:fs/promises\";\nimport { spawn } from \"node:child_process\";\n\nimport { resolveBrokerCommand } from \"./broker-command\";\nimport type { DaemonPaths } from \"./paths\";\n\nexport type DaemonStartResult =\n | { status: \"started\"; pid: number; paths: DaemonPaths }\n | { status: \"already-running\"; pid: number; paths: DaemonPaths };\n\nexport type DaemonStopResult =\n | { status: \"stopped\"; pid: number; paths: DaemonPaths }\n | { status: \"not-running\"; paths: DaemonPaths };\n\nexport type DaemonInspectResult =\n | { status: \"running\"; pid: number; paths: DaemonPaths }\n | { status: \"not-running\"; paths: DaemonPaths; stalePid?: number };\n\nexport interface DaemonDriver {\n isAlive(pid: number): Promise<boolean>;\n spawnBroker(paths: DaemonPaths): Promise<number>;\n stop(pid: number): Promise<void>;\n}\n\nexport interface StartDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n lockTimeoutMs?: number;\n}\n\nexport interface StopDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n}\n\nexport interface InspectDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n}\n\nexport const createNodeDaemonDriver = (cliEntrypoint: string): DaemonDriver => ({\n async isAlive(pid) {\n return isProcessAlive(pid);\n },\n async spawnBroker(paths) {\n const broker = await resolveBrokerCommand(paths);\n const child = spawn(broker.command, broker.args, {\n cwd: broker.cwd,\n detached: true,\n env: {\n ...process.env,\n OPENTRAY_DAEMON_HOME: paths.homeDir,\n OPENTRAY_DAEMON_PACKAGE_VERSION: paths.packageVersion,\n OPENTRAY_DAEMON_CLI_ENTRYPOINT: cliEntrypoint,\n },\n stdio: \"ignore\",\n });\n\n child.unref();\n return child.pid ?? 0;\n },\n async stop(pid) {\n process.kill(pid, \"SIGTERM\");\n },\n});\n\nexport const startDaemon = async ({\n paths,\n driver,\n lockTimeoutMs = 1_000,\n}: StartDaemonOptions): Promise<DaemonStartResult> => {\n await mkdir(paths.runtimeDir, { recursive: true });\n\n const lock = await acquireLock(paths.lockFile, lockTimeoutMs);\n try {\n const existingPid = await readPid(paths.pidFile);\n if (existingPid !== undefined && (await driver.isAlive(existingPid))) {\n return { status: \"already-running\", pid: existingPid, paths };\n }\n\n await cleanupRuntimeFiles(paths);\n const pid = await driver.spawnBroker(paths);\n if (!Number.isInteger(pid) || pid <= 0) {\n throw new Error(\"daemon broker process did not expose a valid pid\");\n }\n await writeFile(paths.pidFile, `${pid}\\n`, \"utf8\");\n await waitForReadyFile(paths.readyFile);\n return { status: \"started\", pid, paths };\n } finally {\n await lock.release();\n }\n};\n\nexport const stopDaemon = async ({ paths, driver }: StopDaemonOptions): Promise<DaemonStopResult> => {\n const pid = await readPid(paths.pidFile);\n if (pid === undefined || !(await driver.isAlive(pid))) {\n await cleanupRuntimeFiles(paths);\n return { status: \"not-running\", paths };\n }\n\n await driver.stop(pid);\n await waitUntilStopped(driver, pid);\n await cleanupRuntimeFiles(paths);\n return { status: \"stopped\", pid, paths };\n};\n\nexport const restartDaemon = async (options: StartDaemonOptions): Promise<DaemonStartResult> => {\n await stopDaemon({ paths: options.paths, driver: options.driver });\n return startDaemon(options);\n};\n\nexport const inspectDaemon = async ({ paths, driver }: InspectDaemonOptions): Promise<DaemonInspectResult> => {\n const pid = await readPid(paths.pidFile);\n if (pid !== undefined && (await driver.isAlive(pid))) {\n return { status: \"running\", pid, paths };\n }\n\n await cleanupRuntimeFiles(paths);\n return pid === undefined\n ? { status: \"not-running\", paths }\n : { status: \"not-running\", paths, stalePid: pid };\n};\n\nconst readPid = async (pidFile: string): Promise<number | undefined> => {\n try {\n const content = await readFile(pidFile, \"utf8\");\n const pid = Number.parseInt(content.trim(), 10);\n return Number.isInteger(pid) && pid > 0 ? pid : undefined;\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n};\n\nconst cleanupRuntimeFiles = async (paths: DaemonPaths): Promise<void> => {\n await rm(paths.readyFile, { force: true });\n await rm(paths.pidFile, { force: true });\n if (process.platform !== \"win32\") {\n await rm(paths.endpoint, { force: true });\n }\n};\n\nconst waitUntilStopped = async (driver: DaemonDriver, pid: number): Promise<void> => {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (!(await driver.isAlive(pid))) {\n return;\n }\n await sleep(50);\n }\n};\n\nconst waitForReadyFile = async (readyFile: string): Promise<void> => {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n try {\n await readFile(readyFile, \"utf8\");\n return;\n } catch (error) {\n if (!isNodeError(error) || error.code !== \"ENOENT\") {\n throw error;\n }\n await sleep(50);\n }\n }\n\n throw new Error(`timed out waiting for daemon readiness: ${readyFile}`);\n};\n\nconst acquireLock = async (\n lockFile: string,\n timeoutMs: number,\n): Promise<{\n release(): Promise<void>;\n}> => {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() <= deadline) {\n try {\n const handle = await open(lockFile, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);\n await handle.writeFile(`${process.pid}\\n`, \"utf8\");\n return {\n async release() {\n await handle.close();\n await unlink(lockFile).catch((error: unknown) => {\n if (!isNodeError(error) || error.code !== \"ENOENT\") {\n throw error;\n }\n });\n },\n };\n } catch (error) {\n if (isNodeError(error) && error.code === \"EEXIST\") {\n await sleep(25);\n continue;\n }\n throw error;\n }\n }\n\n throw new Error(`timed out acquiring daemon lock: ${lockFile}`);\n};\n\nconst isProcessAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst isNodeError = (error: unknown): error is NodeJS.ErrnoException =>\n error instanceof Error && \"code\" in error;\n","import { readFile } from \"node:fs/promises\";\n\nexport const readPackageVersion = async (packageJsonUrl: URL): Promise<string> => {\n const value: unknown = JSON.parse(await readFile(packageJsonUrl, \"utf8\"));\n if (!isPackageJsonWithVersion(value)) {\n throw new Error(`package.json is missing a string version: ${packageJsonUrl.href}`);\n }\n\n return value.version;\n};\n\nconst isPackageJsonWithVersion = (value: unknown): value is { version: string } =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"version\" in value &&\n typeof value.version === \"string\";\n","import { createBrokerEndpointIdentity, formatUnixSocketPath, formatWindowsPipeName } from \"@opentray/spec\";\n\nexport interface DaemonPathOptions {\n homeDir: string;\n packageVersion: string;\n platform?: NodeJS.Platform;\n}\n\nexport interface DaemonPaths {\n homeDir: string;\n packageVersion: string;\n protocolVersion: number;\n stateRoot: string;\n runtimeDir: string;\n endpoint: string;\n pidFile: string;\n lockFile: string;\n readyFile: string;\n}\n\nexport const resolveDaemonPaths = ({\n homeDir,\n packageVersion,\n platform = process.platform,\n}: DaemonPathOptions): DaemonPaths => {\n const identity = createBrokerEndpointIdentity({ packageVersion });\n const normalizedHome = homeDir.replace(/[\\\\/]+$/u, \"\");\n const stateRoot = `${normalizedHome}/.opentray/${identity.packageVersion}`;\n const runtimeDir = `${stateRoot}/runtime`;\n const endpoint =\n platform === \"win32\" ? formatWindowsPipeName(identity) : formatUnixSocketPath(normalizedHome, identity);\n\n return {\n homeDir: normalizedHome,\n packageVersion: identity.packageVersion,\n protocolVersion: identity.protocolVersion,\n stateRoot,\n runtimeDir,\n endpoint,\n pidFile: `${runtimeDir}/broker.pid`,\n lockFile: `${runtimeDir}/broker.lock`,\n readyFile: `${runtimeDir}/ready.json`,\n };\n};\n","import { createConnection, type Socket } from \"node:net\";\nimport { homedir } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\n\nimport {\n PROTOCOL_VERSION,\n parseServerFrame,\n type BrokerEndpointIdentityOptions,\n type ClientRequestFrame,\n type RequestId,\n type ServerFrame,\n} from \"@opentray/spec\";\n\nimport type { OpenTrayTransport } from \"./client\";\nimport { createNodeDaemonDriver, startDaemon, type DaemonDriver } from \"./daemon/lifecycle\";\nimport { readPackageVersion } from \"./daemon/package-version\";\nimport { resolveDaemonPaths } from \"./daemon/paths\";\n\nconst packageJsonUrl = new URL(\"../package.json\", import.meta.url);\n\nexport type BrokerEventFrame = Extract<ServerFrame, { type: \"event\" | \"ext-event\" }>;\n\nexport interface LocalBrokerClient extends OpenTrayTransport {\n readonly endpoint: string;\n readonly leaseId: string;\n onEvent(listener: (frame: BrokerEventFrame) => void): () => void;\n close(): Promise<void>;\n}\n\nexport interface ConnectLocalBrokerOptions extends Partial<BrokerEndpointIdentityOptions> {\n endpoint?: string;\n homeDir?: string;\n clientVersion?: string;\n autoStart?: boolean;\n daemonDriver?: DaemonDriver;\n cliEntrypoint?: string;\n}\n\ninterface PendingRequest {\n resolve(frame: ServerFrame): void;\n reject(error: Error): void;\n}\n\ninterface BrokerSocket {\n setEncoding(encoding: BufferEncoding): void;\n on(event: \"data\", listener: (chunk: Buffer | string) => void): void;\n on(event: \"error\", listener: (error: Error) => void): void;\n on(event: \"close\", listener: () => void): void;\n once(event: \"connect\", listener: () => void): void;\n once(event: \"error\", listener: (error: Error) => void): void;\n off(event: \"error\", listener: (error: Error) => void): void;\n write(data: string): void;\n end(callback: () => void): void;\n}\n\nexport const connectLocalBroker = async (\n options: ConnectLocalBrokerOptions = {},\n): Promise<LocalBrokerClient> => {\n const packageVersion = options.packageVersion ?? (await readPackageVersion(packageJsonUrl));\n const clientVersion = options.clientVersion ?? packageVersion;\n const paths = resolveDaemonPaths({\n homeDir: options.homeDir ?? process.env.OPENTRAY_HOME ?? homedir(),\n packageVersion,\n });\n const endpoint = options.endpoint ?? paths.endpoint;\n const autoStart = options.autoStart ?? endpoint === paths.endpoint;\n if (autoStart && endpoint !== paths.endpoint) {\n throw new Error(\"local broker autoStart requires the derived same-version endpoint\");\n }\n if (autoStart) {\n const cliEntrypoint = options.cliEntrypoint ?? resolveCliEntrypoint();\n const driver = options.daemonDriver ?? createNodeDaemonDriver(cliEntrypoint);\n await startDaemon({ paths, driver });\n }\n const socket = await connectSocket(endpoint);\n const connection = new LocalBrokerConnection(socket, endpoint);\n\n await connection.init(clientVersion, options.protocolVersion ?? PROTOCOL_VERSION);\n return connection;\n};\n\nclass LocalBrokerConnection implements LocalBrokerClient {\n readonly endpoint: string;\n leaseId = \"\";\n\n private buffer = \"\";\n private readonly listeners = new Set<(frame: BrokerEventFrame) => void>();\n private readonly pending = new Map<RequestId, PendingRequest>();\n private ready:\n | {\n resolve(frame: Extract<ServerFrame, { type: \"ready\" }>): void;\n reject(error: Error): void;\n }\n | undefined;\n\n constructor(\n private readonly socket: BrokerSocket,\n endpoint: string,\n ) {\n this.endpoint = endpoint;\n socket.setEncoding(\"utf8\");\n socket.on(\"data\", (chunk: Buffer | string) => {\n this.consume(String(chunk));\n });\n socket.on(\"error\", (error) => {\n this.rejectAll(error);\n });\n socket.on(\"close\", () => {\n this.rejectAll(new Error(\"broker connection closed\"));\n });\n }\n\n async init(clientVersion: string, protocolVersion: number): Promise<void> {\n const ready = new Promise<Extract<ServerFrame, { type: \"ready\" }>>((resolve, reject) => {\n this.ready = { resolve, reject };\n });\n this.write({\n type: \"init\",\n protocolVersion,\n clientVersion,\n });\n const frame = await ready;\n this.leaseId = frame.leaseId;\n }\n\n async request(frame: ClientRequestFrame): Promise<ServerFrame> {\n if (this.pending.has(frame.requestId)) {\n throw new Error(`duplicate requestId: ${frame.requestId}`);\n }\n\n const response = new Promise<ServerFrame>((resolve, reject) => {\n this.pending.set(frame.requestId, { resolve, reject });\n });\n this.write(frame);\n return response;\n }\n\n onEvent(listener: (frame: BrokerEventFrame) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n async close(): Promise<void> {\n this.write({ type: \"exit\" });\n await new Promise<void>((resolve) => {\n this.socket.end(resolve);\n });\n }\n\n private consume(chunk: string): void {\n this.buffer += chunk;\n while (true) {\n const newline = this.buffer.indexOf(\"\\n\");\n if (newline < 0) {\n return;\n }\n\n const line = this.buffer.slice(0, newline).trim();\n this.buffer = this.buffer.slice(newline + 1);\n if (line.length > 0) {\n this.dispatchLine(line);\n }\n }\n }\n\n private dispatchLine(line: string): void {\n const parsed = parseServerFrame(line);\n if (!parsed.ok || parsed.frame === undefined) {\n this.rejectAll(new Error(parsed.error ?? \"invalid server frame\"));\n return;\n }\n\n this.dispatchFrame(parsed.frame);\n }\n\n private dispatchFrame(frame: ServerFrame): void {\n if (frame.type === \"ready\") {\n this.ready?.resolve(frame);\n this.ready = undefined;\n return;\n }\n\n if (frame.type === \"error\") {\n const error = new Error(`${frame.code}: ${frame.message}`);\n if (frame.requestId !== undefined) {\n this.pending.get(frame.requestId)?.reject(error);\n this.pending.delete(frame.requestId);\n return;\n }\n this.ready?.reject(error);\n this.ready = undefined;\n return;\n }\n\n const requestId = responseRequestId(frame);\n if (requestId !== undefined) {\n // Request responses and broker events are separate streams even on one socket.\n this.pending.get(requestId)?.resolve(frame);\n this.pending.delete(requestId);\n return;\n }\n\n if (frame.type === \"event\" || frame.type === \"ext-event\") {\n for (const listener of this.listeners) {\n listener(frame);\n }\n }\n }\n\n private write(frame: unknown): void {\n this.socket.write(`${JSON.stringify(frame)}\\n`);\n }\n\n private rejectAll(error: Error): void {\n this.ready?.reject(error);\n this.ready = undefined;\n for (const pending of this.pending.values()) {\n pending.reject(error);\n }\n this.pending.clear();\n }\n}\n\nconst connectSocket = (endpoint: string): Promise<BrokerSocket> =>\n new Promise((resolve, reject) => {\n const socket = createConnection(endpoint);\n socket.once(\"connect\", () => {\n socket.off(\"error\", reject);\n resolve(socket);\n });\n socket.once(\"error\", reject);\n });\n\nconst responseRequestId = (frame: ServerFrame): RequestId | undefined => {\n switch (frame.type) {\n case \"surface-created\":\n case \"default-surface\":\n case \"tray-created\":\n case \"ack\":\n case \"daemon-health\":\n return frame.requestId;\n case \"ready\":\n case \"event\":\n case \"ext-event\":\n case \"error\":\n return undefined;\n }\n};\n\nconst resolveCliEntrypoint = (): string => {\n const suffix = fileURLToPath(import.meta.url).endsWith(\".ts\") ? \"cli.ts\" : \"cli.mjs\";\n return fileURLToPath(new URL(`./${suffix}`, import.meta.url));\n};\n"],"mappings":"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"}
|