opentray 0.15.0 → 0.16.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/index.d.mts +14 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +66 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
package/dist/index.d.mts
CHANGED
|
@@ -67,6 +67,7 @@ interface OpenTrayEventfulClient extends OpenTrayClient {
|
|
|
67
67
|
}
|
|
68
68
|
interface TrayHandle {
|
|
69
69
|
trayId: TrayId$1;
|
|
70
|
+
app: AppHandle;
|
|
70
71
|
getBounds(): Promise<TrayBoundsResult$1>;
|
|
71
72
|
setMenu(menu: Menu$1): Promise<void>;
|
|
72
73
|
setTooltip(tooltip: Tooltip$1): Promise<void>;
|
|
@@ -77,6 +78,13 @@ interface TrayHandle {
|
|
|
77
78
|
extend<TCapability extends object, TOptions = undefined>(extension: TrayExtension<TCapability, TOptions>, options?: TOptions): TrayHandle & TCapability;
|
|
78
79
|
destroy(): Promise<void>;
|
|
79
80
|
}
|
|
81
|
+
interface AppHandle {
|
|
82
|
+
readonly appId: string;
|
|
83
|
+
getName(): Promise<string>;
|
|
84
|
+
setName(name: string): Promise<string>;
|
|
85
|
+
getIcon(): Promise<Icon$1 | null>;
|
|
86
|
+
setIcon(icon: Icon$1 | null): Promise<Icon$1 | null>;
|
|
87
|
+
}
|
|
80
88
|
type TrayScopedEvent = Exclude<TrayEvent$1, {
|
|
81
89
|
type: "ready";
|
|
82
90
|
}>;
|
|
@@ -121,6 +129,10 @@ interface TrayExtension<TCapability extends object, TOptions = undefined> {
|
|
|
121
129
|
declare const createInitFrame: (clientVersion: string) => ClientFrame$1;
|
|
122
130
|
interface CreateClientOptions {
|
|
123
131
|
requestIdPrefix?: string;
|
|
132
|
+
appOptions?: {
|
|
133
|
+
name?: string;
|
|
134
|
+
icon?: Icon$1;
|
|
135
|
+
};
|
|
124
136
|
}
|
|
125
137
|
declare function createClient(transport: OpenTrayConnection, options?: CreateClientOptions): OpenTrayEventfulClient;
|
|
126
138
|
declare function createClient(transport: OpenTrayTransport, options?: CreateClientOptions): OpenTrayClient;
|
|
@@ -180,6 +192,7 @@ interface OpenTrayRuntimeOptions {
|
|
|
180
192
|
clientVersion?: string;
|
|
181
193
|
appId?: string;
|
|
182
194
|
appName?: string;
|
|
195
|
+
appIcon?: Icon$1;
|
|
183
196
|
autoStart?: boolean;
|
|
184
197
|
}
|
|
185
198
|
/** App-facing tray options accepted by top-level createTray. */
|
|
@@ -197,5 +210,5 @@ interface CreateTrayHandle extends Omit<EventfulTrayHandle, "setMenu" | "extend"
|
|
|
197
210
|
}
|
|
198
211
|
declare const createTray: (options: CreateTrayOptions, runtimeOptions?: OpenTrayRuntimeOptions) => Promise<CreateTrayHandle>;
|
|
199
212
|
//#endregion
|
|
200
|
-
export { type AppId, type AppIdentity, type AppOptions, type AppRef, type BrokerEndpointIdentity, type BrokerEndpointIdentityOptions, type ClientFrame, type ClientRequestFrame, type CreateClientOptions, type CreateTrayCheckItem, type CreateTrayHandle, type CreateTrayItem, type CreateTrayMenu, type CreateTrayMenu as TrayMenu, type CreateTrayMenuClickHandler, type CreateTrayMenuItem, type CreateTrayOptions, type CreateTrayRadioItem, type CreateTraySeparatorItem, type CreateTraySubmenuItem, type DarwinIcon, type DarwinIconText, type EventfulTrayHandle, type ExtensionEnvelope, type ExtensionLoadOptions, type Icon, type IconCandidates, type IconImage, type IconText, type LinuxIcon, type Menu, type MenuItem, type MenuItemId, type MouseButton, type NativeExtensionArch, type NativeExtensionArtifact, NativeExtensionArtifactResolutionError, type NativeExtensionExpectedIdentity, type NativeExtensionFileArtifact, type NativeExtensionIdentitySource, type NativeExtensionPackageArtifact, type NativeExtensionPackageTarget, type NativeExtensionTarget, type OpenTrayClient, type OpenTrayConnection, type OpenTrayEventFrame, type OpenTrayEventSource, type OpenTrayRuntimeOptions, type OpenTrayTransport, PROTOCOL_VERSION, type Rect, type ResolvedNativeExtensionArtifact, type ServerFrame, type SimpleIcon, type Tooltip, type TrayBoundsKind, type TrayBoundsResult, type TrayEvent, type TrayEventByType, type TrayEventType, type TrayExtension, type TrayExtensionContext, type TrayExtensionMountSpec, type TrayHandle, type TrayIcon, type TrayId, type TrayOptions, type TrayTooltip, type Win32Icon, createBrokerEndpointIdentity, createClient, createInitFrame, createTray, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion, resolveNativeExtensionArtifact };
|
|
213
|
+
export { type AppHandle, type AppId, type AppIdentity, type AppOptions, type AppRef, type BrokerEndpointIdentity, type BrokerEndpointIdentityOptions, type ClientFrame, type ClientRequestFrame, type CreateClientOptions, type CreateTrayCheckItem, type CreateTrayHandle, type CreateTrayItem, type CreateTrayMenu, type CreateTrayMenu as TrayMenu, type CreateTrayMenuClickHandler, type CreateTrayMenuItem, type CreateTrayOptions, type CreateTrayRadioItem, type CreateTraySeparatorItem, type CreateTraySubmenuItem, type DarwinIcon, type DarwinIconText, type EventfulTrayHandle, type ExtensionEnvelope, type ExtensionLoadOptions, type Icon, type IconCandidates, type IconImage, type IconText, type LinuxIcon, type Menu, type MenuItem, type MenuItemId, type MouseButton, type NativeExtensionArch, type NativeExtensionArtifact, NativeExtensionArtifactResolutionError, type NativeExtensionExpectedIdentity, type NativeExtensionFileArtifact, type NativeExtensionIdentitySource, type NativeExtensionPackageArtifact, type NativeExtensionPackageTarget, type NativeExtensionTarget, type OpenTrayClient, type OpenTrayConnection, type OpenTrayEventFrame, type OpenTrayEventSource, type OpenTrayRuntimeOptions, type OpenTrayTransport, PROTOCOL_VERSION, type Rect, type ResolvedNativeExtensionArtifact, type ServerFrame, type SimpleIcon, type Tooltip, type TrayBoundsKind, type TrayBoundsResult, type TrayEvent, type TrayEventByType, type TrayEventType, type TrayExtension, type TrayExtensionContext, type TrayExtensionMountSpec, type TrayHandle, type TrayIcon, type TrayId, type TrayOptions, type TrayTooltip, type Win32Icon, createBrokerEndpointIdentity, createClient, createInitFrame, createTray, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion, resolveNativeExtensionArtifact };
|
|
201
214
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/native-extension-artifact.ts","../src/client.ts","../src/menu-input.ts","../src/sdk.ts"],"mappings":";;;KAUY,mBAAA;AAAA,KACA,qBAAA,MAA2B,MAAA,CAAO,QAAA,IAAY,mBAAmB;AAAA,UAE5D,4BAAA;EACf,WAAA;EACA,WAAW;AAAA;AAAA,UAGI,6BAAA;EACf,cAAA;EACA,mBAAmB;AAAA;AAAA,UAGJ,8BAAA,SACP,6BAAA;EACR,IAAA;EACA,OAAA,EAAS,OAAA,CAAQ,MAAA,CAAO,qBAAA,EAAuB,4BAAA;AAAA;AAAA,UAGvC,+BAAA;EACR,IAAA;EACA,IAAI;AAAA;AAAA,KAGM,2BAAA,GAA8B,+BAAA;EAGlC,gBAAA,EAAkB,+BAAA;EAClB,cAAA;AAAA;EAGA,gBAAA;EACA,cAAA,EAAgB,6BAAA;AAAA;AAAA,KAIZ,uBAAA,GACR,8BAAA,GACA,2BAA2B;AAAA,KAEnB,+BAAA,GAAkC,yBAAyB;AAAA,UAEtD,+BAAA;EACf,IAAA;EACA,WAAA;EACA,cAAA;EACA,gBAAA,EAAkB,+BAAA;EAClB,MAAA,EAAQ,qBAAqB;AAAA;AAAA,cAGlB,sCAAA,SAA+C,KAAA;EAAA,SAO/C,MAAA,EAAQ,qBAAA;EAAA,SANV,IAAA;EAAA,SACA,WAAA;EAAA,SACA,oBAAA;cAGP,OAAA,UACS,MAAA,EAAQ,qBAAA,EACjB,OAAA,GAAS,YAAA;IACP,WAAA;IACA,oBAAA;EAAA;AAAA;AA5CuE;AAAA,cA2DhE,8BAAA,GACX,QAAA,EAAU,uBAAA,EACV,QAAA,GAAU,MAAA,CAAO,QAAA,EACjB,IAAA,cACC,OAAA,CAAQ,+BAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/native-extension-artifact.ts","../src/client.ts","../src/menu-input.ts","../src/sdk.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -129,8 +129,27 @@ const createInitFrame = (clientVersion) => ({
|
|
|
129
129
|
});
|
|
130
130
|
function createClient(transport, options = {}) {
|
|
131
131
|
const nextRequestId = createRequestIdFactory(options.requestIdPrefix ?? "opentray");
|
|
132
|
+
let appPromise;
|
|
133
|
+
const ensureApp = async (trayOptions) => {
|
|
134
|
+
appPromise ??= (async () => {
|
|
135
|
+
const app = await resolveDefaultAppRef(transport, nextRequestId);
|
|
136
|
+
const handle = createAppHandle(transport, app.appId, nextRequestId);
|
|
137
|
+
const configured = options.appOptions;
|
|
138
|
+
if (configured?.name !== void 0) await handle.setName(configured.name);
|
|
139
|
+
if (configured?.icon !== void 0) await handle.setIcon(configured.icon);
|
|
140
|
+
else if (trayOptions.icon !== void 0 && await handle.getIcon() === null) await handle.setIcon(trayOptions.icon);
|
|
141
|
+
return {
|
|
142
|
+
app,
|
|
143
|
+
handle
|
|
144
|
+
};
|
|
145
|
+
})().catch((error) => {
|
|
146
|
+
appPromise = void 0;
|
|
147
|
+
throw error;
|
|
148
|
+
});
|
|
149
|
+
return appPromise;
|
|
150
|
+
};
|
|
132
151
|
return { async createTray(options) {
|
|
133
|
-
const app = await
|
|
152
|
+
const { app } = await ensureApp(options);
|
|
134
153
|
const requestId = nextRequestId();
|
|
135
154
|
const frame = expectResponse(await transport.request({
|
|
136
155
|
type: "create-tray",
|
|
@@ -150,6 +169,7 @@ function createTrayHandle(transport, appId, trayId, nextRequestId = createReques
|
|
|
150
169
|
};
|
|
151
170
|
const handle = {
|
|
152
171
|
trayId,
|
|
172
|
+
app: createAppHandle(transport, appId, nextRequestId),
|
|
153
173
|
async getBounds() {
|
|
154
174
|
const requestId = nextRequestId();
|
|
155
175
|
return expectResponse(await transport.request({
|
|
@@ -288,6 +308,45 @@ const resolveDefaultAppRef = async (transport, nextRequestId) => {
|
|
|
288
308
|
requestId
|
|
289
309
|
}), requestId, "default-app").app;
|
|
290
310
|
};
|
|
311
|
+
const createAppHandle = (transport, appId, nextRequestId) => {
|
|
312
|
+
const requestIdentity = async () => {
|
|
313
|
+
const requestId = nextRequestId();
|
|
314
|
+
return expectResponse(await transport.request({
|
|
315
|
+
type: "get-app-identity",
|
|
316
|
+
requestId,
|
|
317
|
+
appId
|
|
318
|
+
}), requestId, "app-identity").identity;
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
appId,
|
|
322
|
+
async getName() {
|
|
323
|
+
return (await requestIdentity()).appName;
|
|
324
|
+
},
|
|
325
|
+
async setName(name) {
|
|
326
|
+
const requestId = nextRequestId();
|
|
327
|
+
expectResponse(await transport.request({
|
|
328
|
+
type: "set-app-name",
|
|
329
|
+
requestId,
|
|
330
|
+
appId,
|
|
331
|
+
name
|
|
332
|
+
}), requestId, "ack");
|
|
333
|
+
return (await requestIdentity()).appName;
|
|
334
|
+
},
|
|
335
|
+
async getIcon() {
|
|
336
|
+
return (await requestIdentity()).icon ?? null;
|
|
337
|
+
},
|
|
338
|
+
async setIcon(icon) {
|
|
339
|
+
const requestId = nextRequestId();
|
|
340
|
+
expectResponse(await transport.request({
|
|
341
|
+
type: "set-app-icon",
|
|
342
|
+
requestId,
|
|
343
|
+
appId,
|
|
344
|
+
icon
|
|
345
|
+
}), requestId, "ack");
|
|
346
|
+
return icon;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
};
|
|
291
350
|
const createTrayExtensionContext = (tray, appId, extension, options, nextMountId) => {
|
|
292
351
|
const mount = extension.resolveMount?.(options) ?? {};
|
|
293
352
|
const name = mount.name ?? extension.name;
|
|
@@ -344,6 +403,7 @@ const requestIdOf = (frame) => {
|
|
|
344
403
|
switch (frame.type) {
|
|
345
404
|
case "app-created":
|
|
346
405
|
case "default-app":
|
|
406
|
+
case "app-identity":
|
|
347
407
|
case "tray-created":
|
|
348
408
|
case "tray-bounds":
|
|
349
409
|
case "ack":
|
|
@@ -944,6 +1004,7 @@ const responseRequestId = (frame) => {
|
|
|
944
1004
|
switch (frame.type) {
|
|
945
1005
|
case "app-created":
|
|
946
1006
|
case "default-app":
|
|
1007
|
+
case "app-identity":
|
|
947
1008
|
case "tray-created":
|
|
948
1009
|
case "tray-bounds":
|
|
949
1010
|
case "ack":
|
|
@@ -1083,7 +1144,10 @@ const createTray = async (options, runtimeOptions = {}) => {
|
|
|
1083
1144
|
const normalized = normalizeCreateTrayOptions(options);
|
|
1084
1145
|
const connection = await connectLocalBroker(runtimeOptions);
|
|
1085
1146
|
try {
|
|
1086
|
-
const tray = await createClient(connection
|
|
1147
|
+
const tray = await createClient(connection, { appOptions: {
|
|
1148
|
+
...runtimeOptions.appName === void 0 ? {} : { name: runtimeOptions.appName },
|
|
1149
|
+
...runtimeOptions.appIcon === void 0 ? {} : { icon: runtimeOptions.appIcon }
|
|
1150
|
+
} }).createTray(normalized.options);
|
|
1087
1151
|
return wrapCreateTrayHandle(tray, {
|
|
1088
1152
|
closeConnection: () => connection.close(),
|
|
1089
1153
|
destroyPromise: void 0,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["PROTOCOL_VERSION","isNodeError","createBrokerEndpointIdentity","normalizeAppIdentityField","formatWindowsPipeName","formatUnixSocketPath","PROTOCOL_VERSION"],"sources":["../src/native-extension-artifact.ts","../src/client.ts","../src/daemon/caller-label.ts","../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","../src/menu-input.ts","../src/sdk.ts"],"sourcesContent":["// Orthogonal intents (2026-07-19; original user request: pnpm install must be sufficient):\n// 1. Describe package-owned and exact-file native extension artifacts without importing binaries.\n// 2. Resolve platform packages from the declaring facade's dependency closure.\n// 3. Reject missing targets, invalid package metadata, and inaccessible native libraries precisely.\n\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport type { ExpectedExtensionIdentity } from \"@opentray/spec\";\n\nexport type NativeExtensionArch = \"arm64\" | \"x64\";\nexport type NativeExtensionTarget = `${NodeJS.Platform}-${NativeExtensionArch}`;\n\nexport interface NativeExtensionPackageTarget {\n packageName: string;\n libraryPath: string;\n}\n\nexport interface NativeExtensionIdentitySource {\n packageJsonUrl: string;\n contractManifestUrl: string;\n}\n\nexport interface NativeExtensionPackageArtifact\n extends NativeExtensionIdentitySource {\n kind: \"package\";\n targets: Partial<Record<NativeExtensionTarget, NativeExtensionPackageTarget>>;\n}\n\ninterface NativeExtensionFileArtifactBase {\n kind: \"file\";\n path: string;\n}\n\nexport type NativeExtensionFileArtifact = NativeExtensionFileArtifactBase &\n (\n | {\n expectedIdentity: NativeExtensionExpectedIdentity;\n identitySource?: never;\n }\n | {\n expectedIdentity?: never;\n identitySource: NativeExtensionIdentitySource;\n }\n );\n\nexport type NativeExtensionArtifact =\n | NativeExtensionPackageArtifact\n | NativeExtensionFileArtifact;\n\nexport type NativeExtensionExpectedIdentity = ExpectedExtensionIdentity;\n\nexport interface ResolvedNativeExtensionArtifact {\n path: string;\n packageName?: string;\n packageVersion?: string;\n expectedIdentity: NativeExtensionExpectedIdentity;\n target: NativeExtensionTarget;\n}\n\nexport class NativeExtensionArtifactResolutionError extends Error {\n readonly code = \"OPENTRAY_NATIVE_EXTENSION_ARTIFACT_RESOLUTION_FAILED\";\n readonly packageName?: string;\n readonly facadePackageJsonUrl?: string;\n\n constructor(\n message: string,\n readonly target: NativeExtensionTarget,\n options: ErrorOptions & {\n packageName?: string;\n facadePackageJsonUrl?: string;\n } = {}\n ) {\n super(message, options);\n this.name = \"NativeExtensionArtifactResolutionError\";\n if (options.packageName !== undefined) {\n this.packageName = options.packageName;\n }\n if (options.facadePackageJsonUrl !== undefined) {\n this.facadePackageJsonUrl = options.facadePackageJsonUrl;\n }\n }\n}\n\n/** Resolve one exact native library from the dependency closure that owns the facade. */\nexport const resolveNativeExtensionArtifact = async (\n artifact: NativeExtensionArtifact,\n platform: NodeJS.Platform = process.platform,\n arch: string = process.arch\n): Promise<ResolvedNativeExtensionArtifact> => {\n const target = nativeExtensionTarget(platform, arch);\n if (artifact.kind === \"file\") {\n return {\n path: await resolveAccessibleLibrary(artifact.path, target),\n expectedIdentity:\n artifact.expectedIdentity ??\n (await resolveExpectedIdentity(artifact.identitySource, target)),\n target,\n };\n }\n\n const packageTarget = artifact.targets[target];\n if (packageTarget === undefined) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension does not support target ${target}`,\n target\n );\n }\n\n const expectedIdentity = await resolveExpectedIdentity(artifact, target);\n\n const resolveFromFacade = createRequire(artifact.packageJsonUrl);\n let platformPackageJsonPath: string;\n try {\n platformPackageJsonPath = resolveFromFacade.resolve(\n `${packageTarget.packageName}/package.json`\n );\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `unable to resolve native extension package \"${packageTarget.packageName}\" for ${target} from ${artifact.packageJsonUrl}`,\n target,\n {\n cause,\n packageName: packageTarget.packageName,\n facadePackageJsonUrl: artifact.packageJsonUrl,\n }\n );\n }\n\n const manifest = await readPlatformPackageManifest(\n platformPackageJsonPath,\n target,\n packageTarget.packageName\n );\n const libraryPath = join(dirname(platformPackageJsonPath), packageTarget.libraryPath);\n return {\n path: await resolveAccessibleLibrary(libraryPath, target, packageTarget.packageName),\n packageName: packageTarget.packageName,\n packageVersion: manifest.version,\n expectedIdentity,\n target,\n };\n};\n\nconst resolveExpectedIdentity = async (\n source: NativeExtensionIdentitySource,\n target: NativeExtensionTarget\n): Promise<NativeExtensionExpectedIdentity> => {\n const [facadeManifest, contractManifest] = await Promise.all([\n readFacadePackageManifest(source.packageJsonUrl, target),\n readExtensionContractManifest(source.contractManifestUrl, target),\n ]);\n const [os, arch] = splitTarget(target);\n return {\n extensionName: contractManifest.extensionName,\n artifactSetVersion: facadeManifest.version,\n contractFingerprint: contractManifest.contractFingerprint,\n target: { os, arch },\n };\n};\n\nconst nativeExtensionTarget = (\n platform: NodeJS.Platform,\n arch: string\n): NativeExtensionTarget => {\n if (arch !== \"arm64\" && arch !== \"x64\") {\n throw new Error(`unsupported native extension architecture: ${arch}`);\n }\n return `${platform}-${arch}`;\n};\n\ninterface PlatformPackageManifest {\n name: string;\n version: string;\n os?: string[];\n cpu?: string[];\n}\n\ninterface FacadePackageManifest {\n name: string;\n version: string;\n}\n\ninterface ExtensionContractManifest {\n extensionName: string;\n contractFingerprint: string;\n}\n\nconst readFacadePackageManifest = async (\n packageJsonUrl: string,\n target: NativeExtensionTarget\n): Promise<FacadePackageManifest> => {\n const parsed = await readJsonUrl(packageJsonUrl, target, \"facade package manifest\");\n if (!isFacadePackageManifest(parsed)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension facade manifest is invalid at ${packageJsonUrl}`,\n target,\n { facadePackageJsonUrl: packageJsonUrl }\n );\n }\n return parsed;\n};\n\nconst readExtensionContractManifest = async (\n contractManifestUrl: string,\n target: NativeExtensionTarget\n): Promise<ExtensionContractManifest> => {\n const parsed = await readJsonUrl(\n contractManifestUrl,\n target,\n \"extension contract manifest\"\n );\n if (!isExtensionContractManifest(parsed)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension contract manifest is invalid at ${contractManifestUrl}`,\n target\n );\n }\n return parsed;\n};\n\nconst readJsonUrl = async (\n url: string,\n target: NativeExtensionTarget,\n label: string\n): Promise<unknown> => {\n try {\n return JSON.parse(await readFile(new URL(url), \"utf8\"));\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `unable to read ${label} at ${url}`,\n target,\n { cause }\n );\n }\n};\n\nconst readPlatformPackageManifest = async (\n packageJsonPath: string,\n target: NativeExtensionTarget,\n packageName: string\n): Promise<PlatformPackageManifest> => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(await readFile(packageJsonPath, \"utf8\"));\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `unable to read native extension package manifest at ${packageJsonPath}`,\n target,\n { cause, packageName }\n );\n }\n if (!isPlatformPackageManifest(parsed) || parsed.name !== packageName) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension package manifest at ${packageJsonPath} does not identify ${packageName}`,\n target,\n { packageName }\n );\n }\n const [platform, arch] = splitTarget(target);\n if (parsed.os !== undefined && !parsed.os.includes(platform)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension package ${packageName} does not support os ${platform}`,\n target,\n { packageName }\n );\n }\n if (parsed.cpu !== undefined && !parsed.cpu.includes(arch)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension package ${packageName} does not support cpu ${arch}`,\n target,\n { packageName }\n );\n }\n return parsed;\n};\n\nconst isPlatformPackageManifest = (\n value: unknown\n): value is PlatformPackageManifest =>\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n typeof value.name === \"string\" &&\n \"version\" in value &&\n typeof value.version === \"string\" &&\n (!(\"os\" in value) ||\n (Array.isArray(value.os) && value.os.every((item) => typeof item === \"string\"))) &&\n (!(\"cpu\" in value) ||\n (Array.isArray(value.cpu) && value.cpu.every((item) => typeof item === \"string\")));\n\nconst isFacadePackageManifest = (value: unknown): value is FacadePackageManifest =>\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n typeof value.name === \"string\" &&\n \"version\" in value &&\n typeof value.version === \"string\";\n\nconst isExtensionContractManifest = (\n value: unknown\n): value is ExtensionContractManifest =>\n typeof value === \"object\" &&\n value !== null &&\n \"extensionName\" in value &&\n typeof value.extensionName === \"string\" &&\n \"contractFingerprint\" in value &&\n typeof value.contractFingerprint === \"string\";\n\nconst splitTarget = (\n target: NativeExtensionTarget\n): [NodeJS.Platform, NativeExtensionArch] => {\n const separator = target.lastIndexOf(\"-\");\n return [\n target.slice(0, separator) as NodeJS.Platform,\n target.slice(separator + 1) as NativeExtensionArch,\n ];\n};\n\nconst resolveAccessibleLibrary = async (\n path: string,\n target: NativeExtensionTarget,\n packageName?: string\n): Promise<string> => {\n try {\n return await realpath(path);\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension library is not accessible at ${path}`,\n target,\n {\n cause,\n ...(packageName === undefined ? {} : { packageName }),\n }\n );\n }\n};\n","import {\n PROTOCOL_VERSION,\n type ClientFrame,\n type ClientRequestFrame,\n type ExtensionEnvelope,\n type Icon,\n type Menu,\n type RequestId,\n type ServerFrame,\n type Tooltip,\n type TrayBoundsResult,\n type TrayEvent,\n type TrayId,\n type TrayOptions,\n} from \"@opentray/spec\";\n\nimport {\n resolveNativeExtensionArtifact,\n type NativeExtensionArtifact,\n} from \"./native-extension-artifact\";\n\nexport interface OpenTrayTransport {\n request(frame: ClientRequestFrame): Promise<ServerFrame>;\n}\n\nexport type OpenTrayEventFrame = Extract<\n ServerFrame,\n { type: \"event\" | \"ext-event\" }\n>;\n\nexport interface OpenTrayEventSource {\n onEvent(listener: (frame: OpenTrayEventFrame) => void): () => void;\n}\n\nexport interface OpenTrayConnection\n extends OpenTrayTransport,\n OpenTrayEventSource {}\n\nexport interface OpenTrayClient {\n createTray(options: TrayOptions): Promise<TrayHandle>;\n}\n\nexport interface OpenTrayEventfulClient extends OpenTrayClient {\n createTray(options: TrayOptions): Promise<EventfulTrayHandle>;\n}\n\nexport interface TrayHandle {\n trayId: TrayId;\n getBounds(): Promise<TrayBoundsResult>;\n setMenu(menu: Menu): Promise<void>;\n setTooltip(tooltip: Tooltip): Promise<void>;\n setIcon(icon: Icon): Promise<void>;\n loadExtension(options: ExtensionLoadOptions): Promise<void>;\n commandExtension(ext: string, data: unknown): Promise<void>;\n requestExtension(ext: string, data: unknown): Promise<ExtensionEnvelope[]>;\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): TrayHandle & TCapability;\n destroy(): Promise<void>;\n}\n\nexport type TrayScopedEvent = Exclude<TrayEvent, { type: \"ready\" }>;\nexport type TrayEventType = TrayScopedEvent[\"type\"];\nexport type TrayEventByType<TEvent extends TrayEventType> = Extract<\n TrayScopedEvent,\n { type: TEvent }\n>;\n\nexport interface EventfulTrayHandle extends TrayHandle {\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): EventfulTrayHandle & TCapability;\n listenExtension<TData = unknown>(\n ext: string,\n handler: (event: ExtensionEnvelope<TData>) => void\n ): () => void;\n listen<TEvent extends TrayEventType>(\n event: TEvent,\n handler: (event: TrayEventByType<TEvent>) => void\n ): () => void;\n onMenuClick(\n handler: (event: TrayEventByType<\"menuClick\">) => void\n ): () => void;\n onTrayClick(\n handler: (event: TrayEventByType<\"trayClick\">) => void\n ): () => void;\n onTrayDoubleClick(\n handler: (event: TrayEventByType<\"trayDoubleClick\">) => void\n ): () => void;\n}\n\nexport interface ExtensionLoadOptions {\n name: string;\n artifact: NativeExtensionArtifact;\n mountId?: string;\n}\n\nexport interface TrayExtensionMountSpec {\n name?: string;\n artifact?: NativeExtensionArtifact;\n mountId?: string;\n}\n\nexport interface TrayExtensionContext {\n readonly appId: string;\n readonly trayId: TrayId;\n readonly name: string;\n readonly artifact: NativeExtensionArtifact;\n readonly mountId: string;\n ensureLoaded(): Promise<void>;\n command(data: unknown): Promise<void>;\n request(data: unknown): Promise<ExtensionEnvelope[]>;\n}\n\nexport interface TrayExtension<\n TCapability extends object,\n TOptions = undefined\n> {\n readonly name: string;\n readonly artifact: NativeExtensionArtifact;\n resolveMount?(options: TOptions | undefined): TrayExtensionMountSpec;\n extend(\n tray: TrayHandle,\n context: TrayExtensionContext,\n options: TOptions | undefined\n ): TCapability;\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 function createClient(\n transport: OpenTrayConnection,\n options?: CreateClientOptions\n): OpenTrayEventfulClient;\nexport function createClient(\n transport: OpenTrayTransport,\n options?: CreateClientOptions\n): OpenTrayClient;\nexport function createClient(\n transport: OpenTrayTransport,\n options: CreateClientOptions = {}\n): OpenTrayClient | OpenTrayEventfulClient {\n const nextRequestId = createRequestIdFactory(\n options.requestIdPrefix ?? \"opentray\"\n );\n\n return {\n async createTray(options: TrayOptions): Promise<TrayHandle> {\n const app = await resolveDefaultAppRef(transport, nextRequestId);\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"create-tray\",\n requestId,\n app,\n tray: options,\n });\n const frame = expectResponse(response, requestId, \"tray-created\");\n return createTrayHandle(\n transport,\n app.appId,\n frame.trayId ?? options.id,\n nextRequestId\n );\n },\n };\n}\n\nexport function createTrayHandle(\n transport: OpenTrayConnection,\n appId: string,\n trayId: TrayId,\n nextRequestId?: () => RequestId\n): EventfulTrayHandle;\nexport function createTrayHandle(\n transport: OpenTrayTransport,\n appId: string,\n trayId: TrayId,\n nextRequestId?: () => RequestId\n): TrayHandle;\nexport function createTrayHandle(\n transport: OpenTrayTransport,\n appId: string,\n trayId: TrayId,\n nextRequestId: () => RequestId = createRequestIdFactory(\"opentray\")\n): TrayHandle | EventfulTrayHandle {\n let nextMountOrdinal = 1;\n const nextMountId = (extensionName: string): string => {\n const mountId = `${formatMountIdComponent(\n extensionName\n )}.${formatMountIdComponent(trayId)}.${nextMountOrdinal}`;\n nextMountOrdinal += 1;\n return mountId;\n };\n const handle: TrayHandle = {\n trayId,\n async getBounds(): Promise<TrayBoundsResult> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"get-tray-bounds\",\n requestId,\n appId,\n trayId,\n });\n return expectResponse(response, requestId, \"tray-bounds\").bounds;\n },\n async setMenu(menu: Menu): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-tray-menu\",\n requestId,\n appId,\n trayId,\n menu,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async setTooltip(tooltip: Tooltip): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-tray-tooltip\",\n requestId,\n appId,\n trayId,\n tooltip,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async setIcon(icon: Icon): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-tray-icon\",\n requestId,\n appId,\n trayId,\n icon,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async loadExtension(options): Promise<void> {\n const requestId = nextRequestId();\n const resolved = await resolveNativeExtensionArtifact(options.artifact);\n const response = await transport.request({\n type: \"load-ext\",\n requestId,\n appId,\n name: options.name,\n path: resolved.path,\n expectedIdentity: resolved.expectedIdentity,\n ...(options.mountId === undefined ? {} : { mountId: options.mountId }),\n });\n expectResponse(response, requestId, \"ack\");\n },\n async commandExtension(ext: string, data: unknown): Promise<void> {\n await this.requestExtension(ext, data);\n },\n async requestExtension(\n ext: string,\n data: unknown\n ): Promise<ExtensionEnvelope[]> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"ext-command\",\n requestId,\n appId,\n trayId,\n ext,\n data,\n });\n if (response.type === \"ack\") {\n expectResponse(response, requestId, \"ack\");\n return [];\n }\n return expectResponse(response, requestId, \"ext-command-result\").events;\n },\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): TrayHandle & TCapability {\n const context = createTrayExtensionContext(\n handle,\n appId,\n extension,\n options,\n nextMountId\n );\n const capability = extension.extend(handle, context, options);\n return Object.assign({}, handle, capability);\n },\n async destroy(): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"destroy-tray\",\n requestId,\n appId,\n trayId,\n });\n expectResponse(response, requestId, \"ack\");\n },\n };\n if (!isOpenTrayEventSource(transport)) {\n return handle;\n }\n return attachEventfulTrayHandle(handle, transport, appId, nextMountId);\n}\n\nconst attachEventfulTrayHandle = (\n handle: TrayHandle,\n source: OpenTrayEventSource,\n appId: string,\n nextMountId: (extensionName: string) => string\n): EventfulTrayHandle => {\n const listen: EventfulTrayHandle[\"listen\"] = (event, handler) =>\n source.onEvent((frame) => {\n if (frame.type !== \"event\" || frame.event.type !== event) {\n return;\n }\n if (!isOwnedTrayEvent(frame.event, appId, handle.trayId)) {\n return;\n }\n handler(frame.event as TrayEventByType<typeof event>);\n });\n\n const eventful: EventfulTrayHandle = {\n ...handle,\n listenExtension<TData = unknown>(\n ext: string,\n handler: (event: ExtensionEnvelope<TData>) => void\n ) {\n return source.onEvent((frame) => {\n if (frame.type !== \"ext-event\" || frame.ext !== ext) {\n return;\n }\n if (frame.appId !== appId || frame.trayId !== handle.trayId) {\n return;\n }\n handler({\n scope: { appId: frame.appId, trayId: frame.trayId, ext: frame.ext },\n data: frame.data as TData,\n });\n });\n },\n listen,\n onMenuClick(handler) {\n return listen(\"menuClick\", handler);\n },\n onTrayClick(handler) {\n return listen(\"trayClick\", handler);\n },\n onTrayDoubleClick(handler) {\n return listen(\"trayDoubleClick\", handler);\n },\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): EventfulTrayHandle & TCapability {\n const context = createTrayExtensionContext(\n eventful,\n appId,\n extension,\n options,\n nextMountId\n );\n const capability = extension.extend(eventful, context, options);\n return Object.assign({}, eventful, capability);\n },\n };\n return eventful;\n};\n\nconst isOwnedTrayEvent = (\n event: TrayEvent,\n appId: string,\n trayId: string\n): event is TrayScopedEvent =>\n event.type !== \"ready\" && event.appId === appId && event.trayId === trayId;\n\nconst isOpenTrayEventSource = (\n transport: OpenTrayTransport\n): transport is OpenTrayConnection =>\n \"onEvent\" in transport && typeof transport.onEvent === \"function\";\n\nconst resolveDefaultAppRef = async (\n transport: OpenTrayTransport,\n nextRequestId: () => RequestId\n): Promise<{ appId: string }> => {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"resolve-default-app\",\n requestId,\n });\n return expectResponse(response, requestId, \"default-app\").app;\n};\n\nconst createTrayExtensionContext = <TCapability extends object, TOptions>(\n tray: TrayHandle,\n appId: string,\n extension: TrayExtension<TCapability, TOptions>,\n options: TOptions | undefined,\n nextMountId: (extensionName: string) => string\n): TrayExtensionContext => {\n const mount = extension.resolveMount?.(options) ?? {};\n const name = mount.name ?? extension.name;\n const artifact = mount.artifact ?? extension.artifact;\n const mountId = mount.mountId ?? nextMountId(name);\n let loadPromise: Promise<void> | undefined;\n\n const ensureLoaded = async (): Promise<void> => {\n if (loadPromise === undefined) {\n // Package-manager resolution stays in Node; the broker receives one exact file.\n loadPromise = tray\n .loadExtension({ name, artifact, mountId })\n .catch((error: unknown) => {\n loadPromise = undefined;\n throw error;\n });\n }\n await loadPromise;\n };\n\n return {\n appId,\n trayId: tray.trayId,\n name,\n artifact,\n mountId,\n ensureLoaded,\n async command(data: unknown): Promise<void> {\n await ensureLoaded();\n await tray.commandExtension(mountId, data);\n },\n async request(data: unknown): Promise<ExtensionEnvelope[]> {\n await ensureLoaded();\n return tray.requestExtension(mountId, data);\n },\n };\n};\n\nconst formatMountIdComponent = (value: string): string => {\n const formatted = value.replaceAll(/[^a-zA-Z0-9._+-]/g, \"_\");\n return formatted.length > 0 ? formatted : \"ext\";\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(\n `expected ${type} for ${requestId}, received ${frame.type}`\n );\n }\n if (requestIdOf(frame) !== requestId) {\n throw new Error(\n `expected response for ${requestId}, received ${\n requestIdOf(frame) ?? \"none\"\n }`\n );\n }\n return frame as Extract<ServerFrame, { type: TType }>;\n};\n\nconst requestIdOf = (frame: ServerFrame): RequestId | undefined => {\n switch (frame.type) {\n case \"app-created\":\n case \"default-app\":\n case \"tray-created\":\n case \"tray-bounds\":\n case \"ack\":\n case \"ext-command-result\":\n case \"runtime-host-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","import { basename } from \"node:path\";\n\nimport { sanitizeCallerLabel } from \"@opentray/spec\";\n\nexport interface CallerLabelSources {\n /** Explicit developer-provided label, highest precedence. */\n readonly explicit?: string;\n /** `npm_package_name` environment value. */\n readonly npmPackageName?: string;\n /** Script path resolved from `process.argv[1]` or equivalent. */\n readonly scriptPath?: string;\n}\n\nexport interface ResolveCallerLabelOptions extends Partial<CallerLabelSources> {\n env?: NodeJS.ProcessEnv;\n argv?: readonly string[];\n}\n\n/**\n * Derives a caller label using the precedence: explicit > npm_package_name >\n * script basename > neutral default. The result is always sanitized to a\n * filesystem- and process-safe component, so callers can use it directly in\n * endpoint identity, runtime directories, and process titles.\n */\nexport const resolveCallerLabel = (options: ResolveCallerLabelOptions = {}): string => {\n const env = options.env ?? process.env;\n const argv = options.argv ?? process.argv;\n\n const candidates: string[] = [];\n if (options.explicit !== undefined && options.explicit.length > 0) {\n candidates.push(options.explicit);\n }\n const npmName = options.npmPackageName ?? env.npm_package_name;\n if (typeof npmName === \"string\" && npmName.length > 0) {\n candidates.push(npmName);\n }\n const scriptPath = options.scriptPath ?? argv[1];\n if (typeof scriptPath === \"string\" && scriptPath.length > 0) {\n candidates.push(basename(scriptPath));\n }\n\n for (const candidate of candidates) {\n const sanitized = sanitizeCallerLabel(candidate);\n if (sanitized.length > 0) {\n return sanitized;\n }\n }\n\n return sanitizeCallerLabel(undefined);\n};\n","import type { BrokerArtifactTarget } from \"@opentray/spec\";\n\nexport 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\nexport const resolveBrokerArtifactTarget = (\n platform: string = process.platform,\n arch: string = process.arch,\n): BrokerArtifactTarget => {\n const packageOs = platformToPackageOs(platform);\n return {\n os: packageOs === \"windows\" ? \"win32\" : packageOs,\n arch: normalizeArch(arch),\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 { createHash } from \"node:crypto\";\nimport { access, readFile, realpath } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn } from \"node:child_process\";\n\nimport type { BrokerArtifactIdentity } from \"@opentray/spec\";\n\nimport type { DaemonPaths } from \"./paths\";\nimport {\n type BrokerNativeTarget,\n MissingPlatformBrokerBinaryError,\n resolveBrokerArtifactTarget,\n resolveBrokerNativeTarget,\n} from \"./native-target\";\n\nexport interface BrokerCommand {\n command: string;\n args: string[];\n cwd?: string;\n}\n\nexport interface ResolvedBrokerArtifact extends BrokerCommand {\n executablePath: string;\n artifactIdentity: BrokerArtifactIdentity;\n}\n\nconst sourceUrl = import.meta.url;\nconst requireFromSource = createRequire(sourceUrl);\n\nexport interface InstalledBrokerBinaryResolution {\n binary?: string;\n binaryPath?: string;\n}\n\nexport interface ResolveInstalledBrokerBinaryOptions {\n platform?: NodeJS.Platform;\n resolvePackageJson?: (specifier: string) => string;\n assertBinaryAccessible?: (binaryPath: string, platform: NodeJS.Platform) => Promise<void>;\n}\n\nexport interface ResolveBrokerCommandOptions {\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n arch?: string;\n sourceDir?: string;\n resolveInstalledBrokerBinary?: (\n target: BrokerNativeTarget,\n options: ResolveInstalledBrokerBinaryOptions,\n ) => Promise<InstalledBrokerBinaryResolution>;\n findWorkspaceRoot?: (start: string) => Promise<string | undefined>;\n ensureDevBrokerBinary?: (\n workspaceRoot: string,\n paths: DaemonPaths,\n platform: NodeJS.Platform,\n ) => Promise<string>;\n}\n\nexport interface ResolveBrokerArtifactOptions extends ResolveBrokerCommandOptions {\n resolveExecutablePath?: (path: string) => Promise<string>;\n readExecutable?: (path: string) => Promise<Uint8Array>;\n}\n\nexport const resolveBrokerArtifact = async (\n paths: DaemonPaths,\n options: ResolveBrokerArtifactOptions = {},\n): Promise<ResolvedBrokerArtifact> => {\n const command = await resolveBrokerCommand(paths, options);\n const executablePath = await (options.resolveExecutablePath ?? realpath)(command.command);\n const bytes = await (options.readExecutable ?? readFile)(executablePath);\n const executableHash = createHash(\"sha256\").update(bytes).digest(\"hex\");\n const artifactIdentity: BrokerArtifactIdentity = {\n packageVersion: paths.packageVersion,\n target: resolveBrokerArtifactTarget(\n options.platform ?? process.platform,\n options.arch ?? process.arch,\n ),\n executableHash,\n buildIdentity: `sha256:${executableHash.slice(0, 16)}`,\n };\n return {\n ...command,\n command: executablePath,\n args: [\n ...command.args,\n \"--broker-executable-path\",\n executablePath,\n \"--broker-artifact-identity\",\n JSON.stringify(artifactIdentity),\n ],\n executablePath,\n artifactIdentity,\n };\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 const target = resolveBrokerNativeTarget(platform, arch);\n const installed = await (options.resolveInstalledBrokerBinary ?? resolveInstalledBrokerBinary)(\n target,\n { platform },\n );\n if (installed.binary !== undefined) {\n return commandForBinary(installed.binary, paths);\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)(\n workspaceRoot,\n paths,\n platform,\n );\n return commandForBinary(binary, paths);\n }\n\n throw new MissingPlatformBrokerBinaryError(\n installed.binaryPath === undefined\n ? `unable to resolve OpenTray broker binary for ${platform}/${arch}; install \"${target.packageName}\" for this platform or set OPENTRAY_BROKER_BIN`\n : `unable to resolve OpenTray broker binary for ${platform}/${arch}; package \"${target.packageName}\" was found but binary \"${installed.binaryPath}\" is not accessible; restage the runtime package or set OPENTRAY_BROKER_BIN`,\n platform,\n arch,\n {\n packageName: target.packageName,\n ...(installed.binaryPath === undefined ? {} : { binaryPath: installed.binaryPath }),\n },\n );\n};\n\nexport const resolveInstalledBrokerBinary = async (\n target: BrokerNativeTarget,\n options: ResolveInstalledBrokerBinaryOptions = {},\n): Promise<InstalledBrokerBinaryResolution> => {\n const platform = options.platform ?? process.platform;\n let packageJsonPath: string;\n try {\n packageJsonPath = (\n options.resolvePackageJson ?? requireFromSource.resolve.bind(requireFromSource)\n )(`${target.packageName}/package.json`);\n } catch (error) {\n if (isNodeError(error) && error.code === \"MODULE_NOT_FOUND\") {\n return {};\n }\n throw error;\n }\n\n const binaryPath = join(dirname(packageJsonPath), target.binaryRelativePath);\n try {\n await (options.assertBinaryAccessible ?? assertInstalledBrokerBinaryAccessible)(\n binaryPath,\n platform,\n );\n return { binary: binaryPath, binaryPath };\n } catch (error) {\n if (\n isNodeError(error) &&\n (error.code === \"ENOENT\" || error.code === \"EACCES\" || error.code === \"EPERM\")\n ) {\n return { binaryPath };\n }\n throw error;\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 \"--app-id\",\n paths.appId,\n \"--app-name\",\n paths.appName,\n \"--caller-label\",\n paths.callerLabel,\n ],\n };\n if (cwd !== undefined) {\n command.cwd = cwd;\n }\n return command;\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\nexport const resolveDevBrokerBinaryPath = (\n workspaceRoot: string,\n platform: NodeJS.Platform = process.platform,\n callerLabel = \"opentray\",\n): string =>\n join(\n resolveDevBrokerTargetDir(workspaceRoot, platform, callerLabel),\n \"debug\",\n platform === \"win32\" ? \"opentray.exe\" : \"opentray\",\n );\n\nconst resolveDevBrokerTargetDir = (\n workspaceRoot: string,\n platform: NodeJS.Platform,\n callerLabel: string,\n): string =>\n platform === \"win32\"\n ? join(workspaceRoot, \"target\", \"opentray-source\", callerLabel)\n : join(workspaceRoot, \"target\");\n\nconst ensureDevBrokerBinary = async (\n workspaceRoot: string,\n paths: DaemonPaths,\n platform: NodeJS.Platform,\n): Promise<string> => {\n const targetDir = resolveDevBrokerTargetDir(workspaceRoot, platform, paths.callerLabel);\n const binary = resolveDevBrokerBinaryPath(workspaceRoot, platform, paths.callerLabel);\n await runCargoBuild(workspaceRoot, platform === \"win32\" ? targetDir : undefined);\n return binary;\n};\n\nconst runCargoBuild = (workspaceRoot: string, targetDir?: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const child = spawn(\n \"cargo\",\n [\n \"build\",\n \"-p\",\n \"opentray-bin\",\n ...(targetDir === undefined ? [] : [\"--target-dir\", targetDir]),\n ],\n {\n cwd: workspaceRoot,\n stdio: process.env.OPENTRAY_BROKER_BUILD_LOGS === \"1\" ? \"inherit\" : \"ignore\",\n },\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 binaryAccessMode = (platform: NodeJS.Platform): number =>\n platform === \"win32\" ? constants.F_OK : constants.X_OK;\n\nconst assertInstalledBrokerBinaryAccessible = async (\n binaryPath: string,\n platform: NodeJS.Platform,\n): Promise<void> => {\n await access(binaryPath, binaryAccessMode(platform));\n};\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\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 {\n brokerArtifactIdentityEquals,\n isBrokerArtifactIdentity,\n type BrokerReadyMetadata,\n} from \"@opentray/spec\";\n\nimport { resolveBrokerArtifact, type ResolvedBrokerArtifact } from \"./broker-command\";\nimport type { DaemonPaths } from \"./paths\";\n\nconst DAEMON_STDIO_ENV = \"OPENTRAY_DAEMON_STDIO\";\nconst DEFAULT_DAEMON_LOCK_TIMEOUT_MS = 5_000;\n\nexport type DaemonStartResult =\n | {\n status: \"started\";\n pid: number;\n paths: DaemonPaths;\n broker: ResolvedBrokerArtifact;\n }\n | {\n status: \"already-running\";\n pid: number;\n paths: DaemonPaths;\n broker: ResolvedBrokerArtifact;\n };\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 resolveBroker(paths: DaemonPaths): Promise<ResolvedBrokerArtifact>;\n isAlive(pid: number): Promise<boolean>;\n spawnBroker(paths: DaemonPaths, broker: ResolvedBrokerArtifact): 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 resolveBroker(paths) {\n return resolveBrokerArtifact(paths);\n },\n async isAlive(pid) {\n return isProcessAlive(pid);\n },\n async spawnBroker(paths, broker) {\n // The caller label flows to the broker via both a CLI flag and an env var.\n // The broker uses it to bind the per-caller endpoint and to set its own\n // process title so task managers show the owning application.\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 OPENTRAY_DAEMON_APP_ID: paths.appId,\n OPENTRAY_DAEMON_APP_NAME: paths.appName,\n OPENTRAY_DAEMON_CALLER_LABEL: paths.callerLabel,\n },\n stdio: resolveBrokerStdio(process.env[DAEMON_STDIO_ENV]),\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 resolveBrokerStdio = (value: string | undefined): \"ignore\" | \"inherit\" => {\n return value === \"inherit\" ? \"inherit\" : \"ignore\";\n};\n\nexport const startDaemon = async ({\n paths,\n driver,\n lockTimeoutMs = DEFAULT_DAEMON_LOCK_TIMEOUT_MS,\n}: StartDaemonOptions): Promise<DaemonStartResult> => {\n const broker = await driver.resolveBroker(paths);\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 const ready = await readReadyMetadata(paths.readyFile);\n // Liveness is not compatibility: only the exact resolved executable may win reuse.\n if (readyMatchesBroker(ready, paths, existingPid, broker)) {\n return {\n status: \"already-running\",\n pid: existingPid,\n paths,\n broker,\n };\n }\n await driver.stop(existingPid);\n if (!(await waitUntilStopped(driver, existingPid))) {\n throw new Error(\n `incompatible daemon broker did not stop within the bounded shutdown window: pid=${existingPid}`,\n );\n }\n }\n\n await cleanupRuntimeFiles(paths);\n const pid = await driver.spawnBroker(paths, broker);\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 try {\n await waitForReadyFile(paths, driver, pid, broker);\n } catch (error) {\n if (await driver.isAlive(pid)) {\n await driver.stop(pid);\n await waitUntilStopped(driver, pid);\n }\n await cleanupRuntimeFiles(paths);\n throw error;\n }\n return { status: \"started\", pid, paths, broker };\n } finally {\n await lock.release();\n }\n};\n\nexport const stopDaemon = async ({\n paths,\n driver,\n}: 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 if (!(await waitUntilStopped(driver, pid))) {\n throw new Error(`daemon broker did not stop within the bounded shutdown window: pid=${pid}`);\n }\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 ({\n paths,\n driver,\n}: 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<boolean> => {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (!(await driver.isAlive(pid))) {\n return true;\n }\n await sleep(50);\n }\n return false;\n};\n\nconst waitForReadyFile = async (\n paths: DaemonPaths,\n driver: DaemonDriver,\n pid: number,\n broker: ResolvedBrokerArtifact,\n): Promise<void> => {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n const ready = await readReadyMetadata(paths.readyFile);\n if (readyMatchesBroker(ready, paths, pid, broker)) {\n return;\n }\n if (ready !== undefined) {\n throw new Error(\n `daemon readiness artifact identity mismatch: expected=${JSON.stringify(broker.artifactIdentity)} actual=${JSON.stringify(ready.brokerArtifactIdentity)}`,\n );\n }\n if (!(await driver.isAlive(pid))) {\n throw new Error(\n `daemon broker exited before readiness: pid=${pid}; readyFile=${paths.readyFile}; set ${DAEMON_STDIO_ENV}=inherit to inspect broker stderr`,\n );\n }\n await sleep(50);\n }\n\n throw new Error(`timed out waiting for daemon readiness: ${paths.readyFile}`);\n};\n\nconst readReadyMetadata = async (readyFile: string): Promise<BrokerReadyMetadata | undefined> => {\n let value: unknown;\n try {\n value = JSON.parse(await readFile(readyFile, \"utf8\"));\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return undefined;\n }\n if (error instanceof SyntaxError) {\n return undefined;\n }\n throw error;\n }\n if (\n !isRecord(value) ||\n !Number.isInteger(value.pid) ||\n typeof value.pid !== \"number\" ||\n typeof value.endpoint !== \"string\" ||\n typeof value.packageVersion !== \"string\" ||\n typeof value.protocolVersion !== \"number\" ||\n typeof value.appId !== \"string\" ||\n typeof value.appName !== \"string\" ||\n typeof value.callerLabel !== \"string\" ||\n typeof value.executablePath !== \"string\" ||\n !isBrokerArtifactIdentity(value.brokerArtifactIdentity)\n ) {\n return undefined;\n }\n return {\n pid: value.pid,\n endpoint: value.endpoint,\n packageVersion: value.packageVersion,\n protocolVersion: value.protocolVersion,\n appId: value.appId,\n appName: value.appName,\n callerLabel: value.callerLabel,\n executablePath: value.executablePath,\n brokerArtifactIdentity: value.brokerArtifactIdentity,\n };\n};\n\nconst readyMatchesBroker = (\n ready: BrokerReadyMetadata | undefined,\n paths: DaemonPaths,\n pid: number,\n broker: ResolvedBrokerArtifact,\n): boolean =>\n ready !== undefined &&\n ready.pid === pid &&\n ready.endpoint === paths.endpoint &&\n ready.packageVersion === paths.packageVersion &&\n ready.protocolVersion === paths.protocolVersion &&\n ready.appId === paths.appId &&\n ready.appName === paths.appName &&\n ready.callerLabel === paths.callerLabel &&\n executablePathsEqual(ready.executablePath, broker.executablePath) &&\n brokerArtifactIdentityEquals(ready.brokerArtifactIdentity, broker.artifactIdentity);\n\nexport const executablePathsEqual = (\n left: string,\n right: string,\n platform: NodeJS.Platform = process.platform,\n): boolean => {\n if (platform !== \"win32\") {\n return left === right;\n }\n\n const normalize = (value: string): string =>\n value\n .replaceAll(\"\\\\\", \"/\")\n .replace(/^\\/\\/?\\?\\//u, \"\")\n .toLowerCase();\n return normalize(left) === normalize(right);\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(\n lockFile,\n constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY,\n );\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\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\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 {\n createBrokerEndpointIdentity,\n formatUnixSocketPath,\n formatWindowsPipeName,\n} from \"@opentray/spec\";\n\nexport interface DaemonPathOptions {\n homeDir: string;\n packageVersion: string;\n callerLabel?: string;\n appId?: string;\n appName?: string;\n platform?: NodeJS.Platform;\n}\n\nexport interface DaemonPaths {\n homeDir: string;\n packageVersion: string;\n callerLabel: string;\n appId: string;\n appName: 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 callerLabel,\n appId,\n appName,\n platform = process.platform,\n}: DaemonPathOptions): DaemonPaths => {\n const identity = createBrokerEndpointIdentity(\n callerLabel === undefined\n ? { packageVersion }\n : { packageVersion, callerLabel }\n );\n const resolvedAppId = normalizeAppIdentityField(appId, identity.callerLabel);\n const resolvedAppName = normalizeAppIdentityField(\n appName,\n identity.callerLabel\n );\n const normalizedHome = homeDir.replace(/[\\\\/]+$/u, \"\");\n const stateRoot = `${normalizedHome}/.opentray/${identity.packageVersion}/${identity.callerLabel}`;\n const runtimeDir = `${stateRoot}/runtime`;\n const endpoint =\n platform === \"win32\"\n ? formatWindowsPipeName(identity)\n : formatUnixSocketPath(normalizedHome, identity);\n\n return {\n homeDir: normalizedHome,\n packageVersion: identity.packageVersion,\n callerLabel: identity.callerLabel,\n appId: resolvedAppId,\n appName: resolvedAppName,\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\nconst normalizeAppIdentityField = (\n value: string | undefined,\n fallback: string\n): string => {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? fallback : trimmed;\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 brokerArtifactIdentityEquals,\n parseServerFrame,\n type BrokerArtifactIdentity,\n type BrokerEndpointIdentityOptions,\n type ClientRequestFrame,\n type RequestId,\n type ServerFrame,\n} from \"@opentray/spec\";\n\nimport type { OpenTrayTransport } from \"./client\";\nimport { resolveCallerLabel } from \"./daemon/caller-label\";\nimport {\n createNodeDaemonDriver,\n startDaemon,\n type DaemonDriver,\n} 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 LocalRuntimeEventFrame = Extract<\n ServerFrame,\n { type: \"event\" | \"ext-event\" }\n>;\n\nexport interface LocalBrokerClient extends OpenTrayTransport {\n readonly endpoint: string;\n readonly callerLabel: string;\n readonly sessionId: string;\n onEvent(listener: (frame: LocalRuntimeEventFrame) => void): () => void;\n close(): Promise<void>;\n}\n\nexport interface ConnectLocalBrokerOptions\n extends Partial<BrokerEndpointIdentityOptions> {\n endpoint?: string;\n homeDir?: string;\n appId?: string;\n appName?: string;\n clientVersion?: string;\n autoStart?: boolean;\n daemonDriver?: DaemonDriver;\n cliEntrypoint?: string;\n callerLabel?: string;\n expectedBrokerArtifactIdentity?: BrokerArtifactIdentity;\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 =\n options.packageVersion ?? (await readPackageVersion(packageJsonUrl));\n const clientVersion = options.clientVersion ?? packageVersion;\n const appId = normalizeAppIdentityField(options.appId);\n const appName = normalizeAppIdentityField(options.appName);\n const callerLabel =\n options.callerLabel ?? appName ?? appId ?? resolveCallerLabel();\n const paths = resolveDaemonPaths({\n homeDir: options.homeDir ?? process.env.OPENTRAY_HOME ?? homedir(),\n packageVersion,\n callerLabel,\n ...(appId === undefined ? {} : { appId }),\n ...(appName === undefined ? {} : { appName }),\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(\n \"local broker autoStart requires the derived same-version endpoint\"\n );\n }\n const cliEntrypoint = options.cliEntrypoint ?? resolveCliEntrypoint();\n const driver = options.daemonDriver ?? createNodeDaemonDriver(cliEntrypoint);\n const expectedBrokerArtifactIdentity = autoStart\n ? (await startDaemon({ paths, driver })).broker.artifactIdentity\n : options.expectedBrokerArtifactIdentity ??\n (await driver.resolveBroker(paths)).artifactIdentity;\n const socket = await connectSocket(endpoint);\n const connection = new LocalBrokerConnection(socket, endpoint, callerLabel);\n\n try {\n await connection.init(\n clientVersion,\n options.protocolVersion ?? PROTOCOL_VERSION,\n expectedBrokerArtifactIdentity,\n );\n } catch (error) {\n await connection.close();\n throw error;\n }\n return connection;\n};\n\nconst normalizeAppIdentityField = (\n value: string | undefined\n): string | undefined => {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;\n};\n\nclass LocalBrokerConnection implements LocalBrokerClient {\n readonly endpoint: string;\n readonly callerLabel: string;\n sessionId = \"\";\n\n private buffer = \"\";\n private readonly listeners = new Set<\n (frame: LocalRuntimeEventFrame) => void\n >();\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 callerLabel: string\n ) {\n this.endpoint = endpoint;\n this.callerLabel = callerLabel;\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(\n clientVersion: string,\n protocolVersion: number,\n expectedBrokerArtifactIdentity: BrokerArtifactIdentity,\n ): Promise<void> {\n const ready = new Promise<Extract<ServerFrame, { type: \"ready\" }>>(\n (resolve, reject) => {\n this.ready = { resolve, reject };\n }\n );\n this.write({\n type: \"init\",\n protocolVersion,\n clientVersion,\n });\n const frame = await ready;\n if (\n !brokerArtifactIdentityEquals(\n frame.brokerArtifactIdentity,\n expectedBrokerArtifactIdentity,\n )\n ) {\n throw new Error(\n `broker artifact identity mismatch: expected=${JSON.stringify(expectedBrokerArtifactIdentity)} actual=${JSON.stringify(frame.brokerArtifactIdentity)}`,\n );\n }\n this.sessionId = frame.sessionId;\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: LocalRuntimeEventFrame) => 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(\n new Error(`${parsed.error ?? \"invalid server frame\"}: ${line}`)\n );\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 // An error with no requestId could not be correlated to a specific request.\n // If the handshake is still pending, reject it; otherwise reject every\n // pending request so callers fail loudly instead of hanging indefinitely.\n // (See issue #3: createTray never resolves on a malformed frame.)\n if (this.ready) {\n this.ready.reject(error);\n this.ready = undefined;\n return;\n }\n this.rejectAll(error);\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 \"app-created\":\n case \"default-app\":\n case \"tray-created\":\n case \"tray-bounds\":\n case \"ack\":\n case \"ext-command-result\":\n case \"runtime-host-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\")\n ? \"cli.ts\"\n : \"cli.mjs\";\n return fileURLToPath(new URL(`./${suffix}`, import.meta.url));\n};\n","import type { Menu, MenuItem, MenuItemId } from \"@opentray/spec\";\n\nimport type { TrayEventByType } from \"./client\";\n\nexport type CreateTrayMenuClickHandler = (\n event: TrayEventByType<\"menuClick\">\n) => void;\n\n/** App-facing menu input accepted by top-level createTray and setMenu. */\nexport type CreateTrayMenu = {\n items: CreateTrayMenuItem[];\n};\n\n/** Menu item shorthand normalized to protocol MenuItem before runtime transport. */\nexport type CreateTrayMenuItem =\n | string\n | readonly [title: string, items: readonly CreateTrayMenuItem[]]\n | CreateTrayItem\n | CreateTrayCheckItem\n | CreateTrayRadioItem\n | CreateTraySeparatorItem\n | CreateTraySubmenuItem;\n\nexport type CreateTrayItem = {\n type?: \"item\";\n id?: MenuItemId;\n title: string;\n primaryEvent?: boolean;\n enabled?: boolean;\n shortcut?: string;\n onMenuClick?: CreateTrayMenuClickHandler;\n};\n\nexport type CreateTrayCheckItem = {\n type: \"check\";\n id?: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n onMenuClick?: CreateTrayMenuClickHandler;\n};\n\nexport type CreateTrayRadioItem = {\n type: \"radio\";\n id?: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n group: number;\n onMenuClick?: CreateTrayMenuClickHandler;\n};\n\nexport type CreateTraySeparatorItem = {\n type: \"separator\";\n};\n\nexport type CreateTraySubmenuItem = {\n type: \"submenu\";\n title: string;\n enabled?: boolean;\n items: readonly CreateTrayMenuItem[];\n};\n\nexport interface NormalizedCreateTrayMenu {\n menu: Menu;\n handlers: Map<MenuItemId, CreateTrayMenuClickHandler[]>;\n}\n\nexport const normalizeCreateTrayMenu = (\n menu: CreateTrayMenu\n): NormalizedCreateTrayMenu => {\n const state: NormalizeState = {\n usedIds: collectExplicitMenuIds(menu.items),\n nextId: 1,\n handlers: new Map(),\n };\n return {\n menu: {\n items: menu.items.map((item) => normalizeCreateTrayMenuItem(item, state)),\n },\n handlers: state.handlers,\n };\n};\n\nconst normalizeCreateTrayMenuItem = (\n item: CreateTrayMenuItem,\n state: NormalizeState\n): MenuItem => {\n if (typeof item === \"string\") {\n if (isSeparatorShortcut(item)) {\n return { type: \"separator\" };\n }\n return normalizePlainItem({ title: item }, state);\n }\n if (isSubmenuTuple(item)) {\n const [title, items] = item;\n return {\n type: \"submenu\",\n title,\n items: items.map((child) => normalizeCreateTrayMenuItem(child, state)),\n };\n }\n switch (item.type) {\n case undefined:\n case \"item\":\n return normalizePlainItem(item, state);\n case \"check\":\n return normalizeCheckItem(item, state);\n case \"radio\":\n return normalizeRadioItem(item, state);\n case \"separator\":\n return item;\n case \"submenu\":\n return {\n type: \"submenu\",\n title: item.title,\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n items: item.items.map((child) =>\n normalizeCreateTrayMenuItem(child, state)\n ),\n };\n }\n throw new Error(\"unsupported menu item\");\n};\n\nconst normalizeClickableItem = (\n item: {\n id?: MenuItemId;\n onMenuClick?: CreateTrayMenuClickHandler;\n },\n state: NormalizeState\n): MenuItemId => {\n const id = item.id ?? allocateMenuItemId(state);\n registerClickId(state, id);\n if (item.onMenuClick !== undefined) {\n const handlers = state.handlers.get(id) ?? [];\n handlers.push(item.onMenuClick);\n state.handlers.set(id, handlers);\n }\n return id;\n};\n\nconst normalizePlainItem = (\n item: CreateTrayItem,\n state: NormalizeState\n): Extract<MenuItem, { type: \"item\" }> => {\n const id = normalizeClickableItem(item, state);\n return {\n type: \"item\",\n id,\n title: item.title,\n ...(item.primaryEvent === undefined\n ? {}\n : { primaryEvent: item.primaryEvent }),\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n ...(item.shortcut === undefined ? {} : { shortcut: item.shortcut }),\n };\n};\n\nconst normalizeCheckItem = (\n item: CreateTrayCheckItem,\n state: NormalizeState\n): Extract<MenuItem, { type: \"check\" }> => {\n const id = normalizeClickableItem(item, state);\n return {\n type: \"check\",\n id,\n title: item.title,\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n ...(item.checked === undefined ? {} : { checked: item.checked }),\n };\n};\n\nconst normalizeRadioItem = (\n item: CreateTrayRadioItem,\n state: NormalizeState\n): Extract<MenuItem, { type: \"radio\" }> => {\n const id = normalizeClickableItem(item, state);\n return {\n type: \"radio\",\n id,\n title: item.title,\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n ...(item.checked === undefined ? {} : { checked: item.checked }),\n group: item.group,\n };\n};\n\nconst allocateMenuItemId = (state: NormalizeState): MenuItemId => {\n while (state.usedIds.has(state.nextId)) {\n state.nextId += 1;\n }\n const id = state.nextId;\n state.usedIds.add(id);\n state.nextId += 1;\n return id;\n};\n\nconst collectExplicitMenuIds = (\n items: readonly CreateTrayMenuItem[]\n): Set<MenuItemId> => {\n const ids = new Set<MenuItemId>();\n for (const item of items) {\n if (typeof item === \"string\") {\n continue;\n }\n if (isSubmenuTuple(item)) {\n for (const id of collectExplicitMenuIds(item[1])) {\n ids.add(id);\n }\n continue;\n }\n switch (item.type) {\n case undefined:\n case \"item\":\n case \"check\":\n case \"radio\":\n if (item.id !== undefined) {\n ids.add(item.id);\n }\n break;\n case \"submenu\":\n for (const id of collectExplicitMenuIds(item.items)) {\n ids.add(id);\n }\n break;\n case \"separator\":\n break;\n }\n }\n return ids;\n};\n\nconst isSeparatorShortcut = (value: string): boolean => /^-+$/.test(value);\n\nconst isSubmenuTuple = (\n item: CreateTrayMenuItem\n): item is readonly [title: string, items: readonly CreateTrayMenuItem[]] =>\n Array.isArray(item);\n\nconst registerClickId = (state: NormalizeState, id: MenuItemId): void => {\n const seen = state.seenClickIds ?? new Set<MenuItemId>();\n if (seen.has(id)) {\n throw new Error(`duplicate menu item id: ${id}`);\n }\n seen.add(id);\n state.seenClickIds = seen;\n};\n\ninterface NormalizeState {\n usedIds: Set<MenuItemId>;\n nextId: MenuItemId;\n handlers: Map<MenuItemId, CreateTrayMenuClickHandler[]>;\n seenClickIds?: Set<MenuItemId>;\n}\n","// Orthogonal intents (2026-07-19; original user request: pnpm install must be sufficient):\n// 1. Expose one direct, ergonomic createTray entrypoint.\n// 2. Normalize app-facing menu shorthand into the protocol model.\n// 3. Make the returned handle own and deterministically close its broker session.\n\nimport type { Icon, Tooltip, TrayOptions } from \"@opentray/spec\";\n\nimport {\n createClient,\n type EventfulTrayHandle,\n type TrayExtension,\n} from \"./client\";\nimport { connectLocalBroker } from \"./local-broker\";\nimport {\n normalizeCreateTrayMenu,\n type CreateTrayMenu,\n type CreateTrayMenuClickHandler,\n} from \"./menu-input\";\n\nexport interface OpenTrayRuntimeOptions {\n endpoint?: string;\n homeDir?: string;\n packageVersion?: string;\n protocolVersion?: number;\n clientVersion?: string;\n appId?: string;\n appName?: string;\n autoStart?: boolean;\n}\n\n/** App-facing tray options accepted by top-level createTray. */\nexport interface CreateTrayOptions {\n id: string;\n tooltip?: Tooltip;\n icon?: Icon;\n menu?: CreateTrayMenu;\n}\n\n/** Tray handle returned by top-level createTray with ergonomic menu and session ownership. */\nexport interface CreateTrayHandle\n extends Omit<EventfulTrayHandle, \"setMenu\" | \"extend\" | \"destroy\"> {\n setMenu(menu: CreateTrayMenu): Promise<void>;\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): CreateTrayHandle & TCapability;\n destroy(): Promise<void>;\n}\n\nexport const createTray = async (\n options: CreateTrayOptions,\n runtimeOptions: OpenTrayRuntimeOptions = {}\n): Promise<CreateTrayHandle> => {\n const normalized = normalizeCreateTrayOptions(options);\n const connection = await connectLocalBroker(runtimeOptions);\n try {\n const tray = await createClient(connection).createTray(normalized.options);\n return wrapCreateTrayHandle(tray, {\n closeConnection: () => connection.close(),\n destroyPromise: undefined,\n menuUnsubscribe: bindMenuClickHandlers(tray, normalized.menuHandlers),\n });\n } catch (error) {\n await connection.close().catch(noop);\n throw error;\n }\n};\n\nconst normalizeCreateTrayOptions = (\n options: CreateTrayOptions\n): NormalizedCreateTrayOptions => {\n const protocolOptions: Omit<TrayOptions, \"menu\"> = {\n id: options.id,\n ...(options.tooltip === undefined ? {} : { tooltip: options.tooltip }),\n ...(options.icon === undefined ? {} : { icon: options.icon }),\n };\n if (options.menu === undefined) {\n return { options: protocolOptions, menuHandlers: new Map() };\n }\n const normalized = normalizeCreateTrayMenu(options.menu);\n return {\n options: {\n ...protocolOptions,\n menu: normalized.menu,\n },\n menuHandlers: normalized.handlers,\n };\n};\n\nconst wrapCreateTrayHandle = (\n tray: EventfulTrayHandle,\n state: CreateTrayHandleState\n): CreateTrayHandle => {\n const handle: CreateTrayHandle = {\n ...tray,\n async setMenu(menu: CreateTrayMenu): Promise<void> {\n const normalized = normalizeCreateTrayMenu(menu);\n await tray.setMenu(normalized.menu);\n state.menuUnsubscribe();\n state.menuUnsubscribe = bindMenuClickHandlers(tray, normalized.handlers);\n },\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): CreateTrayHandle & TCapability {\n const extended = tray.extend(extension, options);\n return wrapCreateTrayHandle(extended, state) as CreateTrayHandle &\n TCapability;\n },\n async destroy(): Promise<void> {\n state.destroyPromise ??= (async () => {\n state.menuUnsubscribe();\n state.menuUnsubscribe = noop;\n try {\n await tray.destroy();\n } finally {\n await state.closeConnection();\n }\n })();\n await state.destroyPromise;\n },\n };\n return handle;\n};\n\nconst bindMenuClickHandlers = (\n tray: EventfulTrayHandle,\n handlers: Map<number, CreateTrayMenuClickHandler[]>\n): (() => void) => {\n if (handlers.size === 0) {\n return noop;\n }\n return tray.onMenuClick((event) => {\n for (const handler of handlers.get(event.itemId) ?? []) {\n handler(event);\n }\n });\n};\n\nconst noop = (): void => {};\n\ninterface NormalizedCreateTrayOptions {\n options: TrayOptions;\n menuHandlers: Map<number, CreateTrayMenuClickHandler[]>;\n}\n\ninterface CreateTrayHandleState {\n closeConnection: () => Promise<void>;\n destroyPromise: Promise<void> | undefined;\n menuUnsubscribe: () => void;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["PROTOCOL_VERSION","isNodeError","createBrokerEndpointIdentity","normalizeAppIdentityField","formatWindowsPipeName","formatUnixSocketPath","PROTOCOL_VERSION"],"sources":["../src/native-extension-artifact.ts","../src/client.ts","../src/daemon/caller-label.ts","../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","../src/menu-input.ts","../src/sdk.ts"],"sourcesContent":["// Orthogonal intents (2026-07-19; original user request: pnpm install must be sufficient):\n// 1. Describe package-owned and exact-file native extension artifacts without importing binaries.\n// 2. Resolve platform packages from the declaring facade's dependency closure.\n// 3. Reject missing targets, invalid package metadata, and inaccessible native libraries precisely.\n\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport type { ExpectedExtensionIdentity } from \"@opentray/spec\";\n\nexport type NativeExtensionArch = \"arm64\" | \"x64\";\nexport type NativeExtensionTarget = `${NodeJS.Platform}-${NativeExtensionArch}`;\n\nexport interface NativeExtensionPackageTarget {\n packageName: string;\n libraryPath: string;\n}\n\nexport interface NativeExtensionIdentitySource {\n packageJsonUrl: string;\n contractManifestUrl: string;\n}\n\nexport interface NativeExtensionPackageArtifact\n extends NativeExtensionIdentitySource {\n kind: \"package\";\n targets: Partial<Record<NativeExtensionTarget, NativeExtensionPackageTarget>>;\n}\n\ninterface NativeExtensionFileArtifactBase {\n kind: \"file\";\n path: string;\n}\n\nexport type NativeExtensionFileArtifact = NativeExtensionFileArtifactBase &\n (\n | {\n expectedIdentity: NativeExtensionExpectedIdentity;\n identitySource?: never;\n }\n | {\n expectedIdentity?: never;\n identitySource: NativeExtensionIdentitySource;\n }\n );\n\nexport type NativeExtensionArtifact =\n | NativeExtensionPackageArtifact\n | NativeExtensionFileArtifact;\n\nexport type NativeExtensionExpectedIdentity = ExpectedExtensionIdentity;\n\nexport interface ResolvedNativeExtensionArtifact {\n path: string;\n packageName?: string;\n packageVersion?: string;\n expectedIdentity: NativeExtensionExpectedIdentity;\n target: NativeExtensionTarget;\n}\n\nexport class NativeExtensionArtifactResolutionError extends Error {\n readonly code = \"OPENTRAY_NATIVE_EXTENSION_ARTIFACT_RESOLUTION_FAILED\";\n readonly packageName?: string;\n readonly facadePackageJsonUrl?: string;\n\n constructor(\n message: string,\n readonly target: NativeExtensionTarget,\n options: ErrorOptions & {\n packageName?: string;\n facadePackageJsonUrl?: string;\n } = {}\n ) {\n super(message, options);\n this.name = \"NativeExtensionArtifactResolutionError\";\n if (options.packageName !== undefined) {\n this.packageName = options.packageName;\n }\n if (options.facadePackageJsonUrl !== undefined) {\n this.facadePackageJsonUrl = options.facadePackageJsonUrl;\n }\n }\n}\n\n/** Resolve one exact native library from the dependency closure that owns the facade. */\nexport const resolveNativeExtensionArtifact = async (\n artifact: NativeExtensionArtifact,\n platform: NodeJS.Platform = process.platform,\n arch: string = process.arch\n): Promise<ResolvedNativeExtensionArtifact> => {\n const target = nativeExtensionTarget(platform, arch);\n if (artifact.kind === \"file\") {\n return {\n path: await resolveAccessibleLibrary(artifact.path, target),\n expectedIdentity:\n artifact.expectedIdentity ??\n (await resolveExpectedIdentity(artifact.identitySource, target)),\n target,\n };\n }\n\n const packageTarget = artifact.targets[target];\n if (packageTarget === undefined) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension does not support target ${target}`,\n target\n );\n }\n\n const expectedIdentity = await resolveExpectedIdentity(artifact, target);\n\n const resolveFromFacade = createRequire(artifact.packageJsonUrl);\n let platformPackageJsonPath: string;\n try {\n platformPackageJsonPath = resolveFromFacade.resolve(\n `${packageTarget.packageName}/package.json`\n );\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `unable to resolve native extension package \"${packageTarget.packageName}\" for ${target} from ${artifact.packageJsonUrl}`,\n target,\n {\n cause,\n packageName: packageTarget.packageName,\n facadePackageJsonUrl: artifact.packageJsonUrl,\n }\n );\n }\n\n const manifest = await readPlatformPackageManifest(\n platformPackageJsonPath,\n target,\n packageTarget.packageName\n );\n const libraryPath = join(dirname(platformPackageJsonPath), packageTarget.libraryPath);\n return {\n path: await resolveAccessibleLibrary(libraryPath, target, packageTarget.packageName),\n packageName: packageTarget.packageName,\n packageVersion: manifest.version,\n expectedIdentity,\n target,\n };\n};\n\nconst resolveExpectedIdentity = async (\n source: NativeExtensionIdentitySource,\n target: NativeExtensionTarget\n): Promise<NativeExtensionExpectedIdentity> => {\n const [facadeManifest, contractManifest] = await Promise.all([\n readFacadePackageManifest(source.packageJsonUrl, target),\n readExtensionContractManifest(source.contractManifestUrl, target),\n ]);\n const [os, arch] = splitTarget(target);\n return {\n extensionName: contractManifest.extensionName,\n artifactSetVersion: facadeManifest.version,\n contractFingerprint: contractManifest.contractFingerprint,\n target: { os, arch },\n };\n};\n\nconst nativeExtensionTarget = (\n platform: NodeJS.Platform,\n arch: string\n): NativeExtensionTarget => {\n if (arch !== \"arm64\" && arch !== \"x64\") {\n throw new Error(`unsupported native extension architecture: ${arch}`);\n }\n return `${platform}-${arch}`;\n};\n\ninterface PlatformPackageManifest {\n name: string;\n version: string;\n os?: string[];\n cpu?: string[];\n}\n\ninterface FacadePackageManifest {\n name: string;\n version: string;\n}\n\ninterface ExtensionContractManifest {\n extensionName: string;\n contractFingerprint: string;\n}\n\nconst readFacadePackageManifest = async (\n packageJsonUrl: string,\n target: NativeExtensionTarget\n): Promise<FacadePackageManifest> => {\n const parsed = await readJsonUrl(packageJsonUrl, target, \"facade package manifest\");\n if (!isFacadePackageManifest(parsed)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension facade manifest is invalid at ${packageJsonUrl}`,\n target,\n { facadePackageJsonUrl: packageJsonUrl }\n );\n }\n return parsed;\n};\n\nconst readExtensionContractManifest = async (\n contractManifestUrl: string,\n target: NativeExtensionTarget\n): Promise<ExtensionContractManifest> => {\n const parsed = await readJsonUrl(\n contractManifestUrl,\n target,\n \"extension contract manifest\"\n );\n if (!isExtensionContractManifest(parsed)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension contract manifest is invalid at ${contractManifestUrl}`,\n target\n );\n }\n return parsed;\n};\n\nconst readJsonUrl = async (\n url: string,\n target: NativeExtensionTarget,\n label: string\n): Promise<unknown> => {\n try {\n return JSON.parse(await readFile(new URL(url), \"utf8\"));\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `unable to read ${label} at ${url}`,\n target,\n { cause }\n );\n }\n};\n\nconst readPlatformPackageManifest = async (\n packageJsonPath: string,\n target: NativeExtensionTarget,\n packageName: string\n): Promise<PlatformPackageManifest> => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(await readFile(packageJsonPath, \"utf8\"));\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `unable to read native extension package manifest at ${packageJsonPath}`,\n target,\n { cause, packageName }\n );\n }\n if (!isPlatformPackageManifest(parsed) || parsed.name !== packageName) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension package manifest at ${packageJsonPath} does not identify ${packageName}`,\n target,\n { packageName }\n );\n }\n const [platform, arch] = splitTarget(target);\n if (parsed.os !== undefined && !parsed.os.includes(platform)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension package ${packageName} does not support os ${platform}`,\n target,\n { packageName }\n );\n }\n if (parsed.cpu !== undefined && !parsed.cpu.includes(arch)) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension package ${packageName} does not support cpu ${arch}`,\n target,\n { packageName }\n );\n }\n return parsed;\n};\n\nconst isPlatformPackageManifest = (\n value: unknown\n): value is PlatformPackageManifest =>\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n typeof value.name === \"string\" &&\n \"version\" in value &&\n typeof value.version === \"string\" &&\n (!(\"os\" in value) ||\n (Array.isArray(value.os) && value.os.every((item) => typeof item === \"string\"))) &&\n (!(\"cpu\" in value) ||\n (Array.isArray(value.cpu) && value.cpu.every((item) => typeof item === \"string\")));\n\nconst isFacadePackageManifest = (value: unknown): value is FacadePackageManifest =>\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n typeof value.name === \"string\" &&\n \"version\" in value &&\n typeof value.version === \"string\";\n\nconst isExtensionContractManifest = (\n value: unknown\n): value is ExtensionContractManifest =>\n typeof value === \"object\" &&\n value !== null &&\n \"extensionName\" in value &&\n typeof value.extensionName === \"string\" &&\n \"contractFingerprint\" in value &&\n typeof value.contractFingerprint === \"string\";\n\nconst splitTarget = (\n target: NativeExtensionTarget\n): [NodeJS.Platform, NativeExtensionArch] => {\n const separator = target.lastIndexOf(\"-\");\n return [\n target.slice(0, separator) as NodeJS.Platform,\n target.slice(separator + 1) as NativeExtensionArch,\n ];\n};\n\nconst resolveAccessibleLibrary = async (\n path: string,\n target: NativeExtensionTarget,\n packageName?: string\n): Promise<string> => {\n try {\n return await realpath(path);\n } catch (cause) {\n throw new NativeExtensionArtifactResolutionError(\n `native extension library is not accessible at ${path}`,\n target,\n {\n cause,\n ...(packageName === undefined ? {} : { packageName }),\n }\n );\n }\n};\n","import {\n PROTOCOL_VERSION,\n type ClientFrame,\n type ClientRequestFrame,\n type AppIdentity,\n type ExtensionEnvelope,\n type Icon,\n type Menu,\n type RequestId,\n type ServerFrame,\n type Tooltip,\n type TrayBoundsResult,\n type TrayEvent,\n type TrayId,\n type TrayOptions,\n} from \"@opentray/spec\";\n\nimport {\n resolveNativeExtensionArtifact,\n type NativeExtensionArtifact,\n} from \"./native-extension-artifact\";\n\nexport interface OpenTrayTransport {\n request(frame: ClientRequestFrame): Promise<ServerFrame>;\n}\n\nexport type OpenTrayEventFrame = Extract<\n ServerFrame,\n { type: \"event\" | \"ext-event\" }\n>;\n\nexport interface OpenTrayEventSource {\n onEvent(listener: (frame: OpenTrayEventFrame) => void): () => void;\n}\n\nexport interface OpenTrayConnection\n extends OpenTrayTransport,\n OpenTrayEventSource {}\n\nexport interface OpenTrayClient {\n createTray(options: TrayOptions): Promise<TrayHandle>;\n}\n\nexport interface OpenTrayEventfulClient extends OpenTrayClient {\n createTray(options: TrayOptions): Promise<EventfulTrayHandle>;\n}\n\nexport interface TrayHandle {\n trayId: TrayId;\n app: AppHandle;\n getBounds(): Promise<TrayBoundsResult>;\n setMenu(menu: Menu): Promise<void>;\n setTooltip(tooltip: Tooltip): Promise<void>;\n setIcon(icon: Icon): Promise<void>;\n loadExtension(options: ExtensionLoadOptions): Promise<void>;\n commandExtension(ext: string, data: unknown): Promise<void>;\n requestExtension(ext: string, data: unknown): Promise<ExtensionEnvelope[]>;\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): TrayHandle & TCapability;\n destroy(): Promise<void>;\n}\n\nexport interface AppHandle {\n readonly appId: string;\n getName(): Promise<string>;\n setName(name: string): Promise<string>;\n getIcon(): Promise<Icon | null>;\n setIcon(icon: Icon | null): Promise<Icon | null>;\n}\n\nexport type TrayScopedEvent = Exclude<TrayEvent, { type: \"ready\" }>;\nexport type TrayEventType = TrayScopedEvent[\"type\"];\nexport type TrayEventByType<TEvent extends TrayEventType> = Extract<\n TrayScopedEvent,\n { type: TEvent }\n>;\n\nexport interface EventfulTrayHandle extends TrayHandle {\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): EventfulTrayHandle & TCapability;\n listenExtension<TData = unknown>(\n ext: string,\n handler: (event: ExtensionEnvelope<TData>) => void\n ): () => void;\n listen<TEvent extends TrayEventType>(\n event: TEvent,\n handler: (event: TrayEventByType<TEvent>) => void\n ): () => void;\n onMenuClick(\n handler: (event: TrayEventByType<\"menuClick\">) => void\n ): () => void;\n onTrayClick(\n handler: (event: TrayEventByType<\"trayClick\">) => void\n ): () => void;\n onTrayDoubleClick(\n handler: (event: TrayEventByType<\"trayDoubleClick\">) => void\n ): () => void;\n}\n\nexport interface ExtensionLoadOptions {\n name: string;\n artifact: NativeExtensionArtifact;\n mountId?: string;\n}\n\nexport interface TrayExtensionMountSpec {\n name?: string;\n artifact?: NativeExtensionArtifact;\n mountId?: string;\n}\n\nexport interface TrayExtensionContext {\n readonly appId: string;\n readonly trayId: TrayId;\n readonly name: string;\n readonly artifact: NativeExtensionArtifact;\n readonly mountId: string;\n ensureLoaded(): Promise<void>;\n command(data: unknown): Promise<void>;\n request(data: unknown): Promise<ExtensionEnvelope[]>;\n}\n\nexport interface TrayExtension<\n TCapability extends object,\n TOptions = undefined\n> {\n readonly name: string;\n readonly artifact: NativeExtensionArtifact;\n resolveMount?(options: TOptions | undefined): TrayExtensionMountSpec;\n extend(\n tray: TrayHandle,\n context: TrayExtensionContext,\n options: TOptions | undefined\n ): TCapability;\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 appOptions?: {\n name?: string;\n icon?: Icon;\n };\n}\n\nexport function createClient(\n transport: OpenTrayConnection,\n options?: CreateClientOptions\n): OpenTrayEventfulClient;\nexport function createClient(\n transport: OpenTrayTransport,\n options?: CreateClientOptions\n): OpenTrayClient;\nexport function createClient(\n transport: OpenTrayTransport,\n options: CreateClientOptions = {}\n): OpenTrayClient | OpenTrayEventfulClient {\n const nextRequestId = createRequestIdFactory(\n options.requestIdPrefix ?? \"opentray\"\n );\n let appPromise: Promise<{ app: { appId: string }; handle: AppHandle }> | undefined;\n\n const ensureApp = async (\n trayOptions: TrayOptions\n ): Promise<{ app: { appId: string }; handle: AppHandle }> => {\n appPromise ??= (async () => {\n const app = await resolveDefaultAppRef(transport, nextRequestId);\n const handle = createAppHandle(transport, app.appId, nextRequestId);\n const configured = options.appOptions;\n if (configured?.name !== undefined) {\n await handle.setName(configured.name);\n }\n if (configured?.icon !== undefined) {\n await handle.setIcon(configured.icon);\n } else if (\n trayOptions.icon !== undefined &&\n (await handle.getIcon()) === null\n ) {\n await handle.setIcon(trayOptions.icon);\n }\n return { app, handle };\n })().catch((error: unknown) => {\n appPromise = undefined;\n throw error;\n });\n return appPromise;\n };\n\n return {\n async createTray(options: TrayOptions): Promise<TrayHandle> {\n const { app } = await ensureApp(options);\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"create-tray\",\n requestId,\n app,\n tray: options,\n });\n const frame = expectResponse(response, requestId, \"tray-created\");\n return createTrayHandle(\n transport,\n app.appId,\n frame.trayId ?? options.id,\n nextRequestId\n );\n },\n };\n}\n\nexport function createTrayHandle(\n transport: OpenTrayConnection,\n appId: string,\n trayId: TrayId,\n nextRequestId?: () => RequestId\n): EventfulTrayHandle;\nexport function createTrayHandle(\n transport: OpenTrayTransport,\n appId: string,\n trayId: TrayId,\n nextRequestId?: () => RequestId\n): TrayHandle;\nexport function createTrayHandle(\n transport: OpenTrayTransport,\n appId: string,\n trayId: TrayId,\n nextRequestId: () => RequestId = createRequestIdFactory(\"opentray\")\n): TrayHandle | EventfulTrayHandle {\n let nextMountOrdinal = 1;\n const nextMountId = (extensionName: string): string => {\n const mountId = `${formatMountIdComponent(\n extensionName\n )}.${formatMountIdComponent(trayId)}.${nextMountOrdinal}`;\n nextMountOrdinal += 1;\n return mountId;\n };\n const handle: TrayHandle = {\n trayId,\n app: createAppHandle(transport, appId, nextRequestId),\n async getBounds(): Promise<TrayBoundsResult> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"get-tray-bounds\",\n requestId,\n appId,\n trayId,\n });\n return expectResponse(response, requestId, \"tray-bounds\").bounds;\n },\n async setMenu(menu: Menu): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-tray-menu\",\n requestId,\n appId,\n trayId,\n menu,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async setTooltip(tooltip: Tooltip): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-tray-tooltip\",\n requestId,\n appId,\n trayId,\n tooltip,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async setIcon(icon: Icon): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-tray-icon\",\n requestId,\n appId,\n trayId,\n icon,\n });\n expectResponse(response, requestId, \"ack\");\n },\n async loadExtension(options): Promise<void> {\n const requestId = nextRequestId();\n const resolved = await resolveNativeExtensionArtifact(options.artifact);\n const response = await transport.request({\n type: \"load-ext\",\n requestId,\n appId,\n name: options.name,\n path: resolved.path,\n expectedIdentity: resolved.expectedIdentity,\n ...(options.mountId === undefined ? {} : { mountId: options.mountId }),\n });\n expectResponse(response, requestId, \"ack\");\n },\n async commandExtension(ext: string, data: unknown): Promise<void> {\n await this.requestExtension(ext, data);\n },\n async requestExtension(\n ext: string,\n data: unknown\n ): Promise<ExtensionEnvelope[]> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"ext-command\",\n requestId,\n appId,\n trayId,\n ext,\n data,\n });\n if (response.type === \"ack\") {\n expectResponse(response, requestId, \"ack\");\n return [];\n }\n return expectResponse(response, requestId, \"ext-command-result\").events;\n },\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): TrayHandle & TCapability {\n const context = createTrayExtensionContext(\n handle,\n appId,\n extension,\n options,\n nextMountId\n );\n const capability = extension.extend(handle, context, options);\n return Object.assign({}, handle, capability);\n },\n async destroy(): Promise<void> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"destroy-tray\",\n requestId,\n appId,\n trayId,\n });\n expectResponse(response, requestId, \"ack\");\n },\n };\n if (!isOpenTrayEventSource(transport)) {\n return handle;\n }\n return attachEventfulTrayHandle(handle, transport, appId, nextMountId);\n}\n\nconst attachEventfulTrayHandle = (\n handle: TrayHandle,\n source: OpenTrayEventSource,\n appId: string,\n nextMountId: (extensionName: string) => string\n): EventfulTrayHandle => {\n const listen: EventfulTrayHandle[\"listen\"] = (event, handler) =>\n source.onEvent((frame) => {\n if (frame.type !== \"event\" || frame.event.type !== event) {\n return;\n }\n if (!isOwnedTrayEvent(frame.event, appId, handle.trayId)) {\n return;\n }\n handler(frame.event as TrayEventByType<typeof event>);\n });\n\n const eventful: EventfulTrayHandle = {\n ...handle,\n listenExtension<TData = unknown>(\n ext: string,\n handler: (event: ExtensionEnvelope<TData>) => void\n ) {\n return source.onEvent((frame) => {\n if (frame.type !== \"ext-event\" || frame.ext !== ext) {\n return;\n }\n if (frame.appId !== appId || frame.trayId !== handle.trayId) {\n return;\n }\n handler({\n scope: { appId: frame.appId, trayId: frame.trayId, ext: frame.ext },\n data: frame.data as TData,\n });\n });\n },\n listen,\n onMenuClick(handler) {\n return listen(\"menuClick\", handler);\n },\n onTrayClick(handler) {\n return listen(\"trayClick\", handler);\n },\n onTrayDoubleClick(handler) {\n return listen(\"trayDoubleClick\", handler);\n },\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): EventfulTrayHandle & TCapability {\n const context = createTrayExtensionContext(\n eventful,\n appId,\n extension,\n options,\n nextMountId\n );\n const capability = extension.extend(eventful, context, options);\n return Object.assign({}, eventful, capability);\n },\n };\n return eventful;\n};\n\nconst isOwnedTrayEvent = (\n event: TrayEvent,\n appId: string,\n trayId: string\n): event is TrayScopedEvent =>\n event.type !== \"ready\" && event.appId === appId && event.trayId === trayId;\n\nconst isOpenTrayEventSource = (\n transport: OpenTrayTransport\n): transport is OpenTrayConnection =>\n \"onEvent\" in transport && typeof transport.onEvent === \"function\";\n\nconst resolveDefaultAppRef = async (\n transport: OpenTrayTransport,\n nextRequestId: () => RequestId\n): Promise<{ appId: string }> => {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"resolve-default-app\",\n requestId,\n });\n return expectResponse(response, requestId, \"default-app\").app;\n};\n\nconst createAppHandle = (\n transport: OpenTrayTransport,\n appId: string,\n nextRequestId: () => RequestId,\n): AppHandle => {\n const requestIdentity = async (): Promise<AppIdentity> => {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"get-app-identity\",\n requestId,\n appId,\n });\n return expectResponse(response, requestId, \"app-identity\").identity;\n };\n return {\n appId,\n async getName(): Promise<string> {\n return (await requestIdentity()).appName;\n },\n async setName(name: string): Promise<string> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-app-name\",\n requestId,\n appId,\n name,\n });\n expectResponse(response, requestId, \"ack\");\n return (await requestIdentity()).appName;\n },\n async getIcon(): Promise<Icon | null> {\n return (await requestIdentity()).icon ?? null;\n },\n async setIcon(icon: Icon | null): Promise<Icon | null> {\n const requestId = nextRequestId();\n const response = await transport.request({\n type: \"set-app-icon\",\n requestId,\n appId,\n icon,\n });\n expectResponse(response, requestId, \"ack\");\n return icon;\n },\n };\n};\n\nconst createTrayExtensionContext = <TCapability extends object, TOptions>(\n tray: TrayHandle,\n appId: string,\n extension: TrayExtension<TCapability, TOptions>,\n options: TOptions | undefined,\n nextMountId: (extensionName: string) => string\n): TrayExtensionContext => {\n const mount = extension.resolveMount?.(options) ?? {};\n const name = mount.name ?? extension.name;\n const artifact = mount.artifact ?? extension.artifact;\n const mountId = mount.mountId ?? nextMountId(name);\n let loadPromise: Promise<void> | undefined;\n\n const ensureLoaded = async (): Promise<void> => {\n if (loadPromise === undefined) {\n // Package-manager resolution stays in Node; the broker receives one exact file.\n loadPromise = tray\n .loadExtension({ name, artifact, mountId })\n .catch((error: unknown) => {\n loadPromise = undefined;\n throw error;\n });\n }\n await loadPromise;\n };\n\n return {\n appId,\n trayId: tray.trayId,\n name,\n artifact,\n mountId,\n ensureLoaded,\n async command(data: unknown): Promise<void> {\n await ensureLoaded();\n await tray.commandExtension(mountId, data);\n },\n async request(data: unknown): Promise<ExtensionEnvelope[]> {\n await ensureLoaded();\n return tray.requestExtension(mountId, data);\n },\n };\n};\n\nconst formatMountIdComponent = (value: string): string => {\n const formatted = value.replaceAll(/[^a-zA-Z0-9._+-]/g, \"_\");\n return formatted.length > 0 ? formatted : \"ext\";\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(\n `expected ${type} for ${requestId}, received ${frame.type}`\n );\n }\n if (requestIdOf(frame) !== requestId) {\n throw new Error(\n `expected response for ${requestId}, received ${\n requestIdOf(frame) ?? \"none\"\n }`\n );\n }\n return frame as Extract<ServerFrame, { type: TType }>;\n};\n\nconst requestIdOf = (frame: ServerFrame): RequestId | undefined => {\n switch (frame.type) {\n case \"app-created\":\n case \"default-app\":\n case \"app-identity\":\n case \"tray-created\":\n case \"tray-bounds\":\n case \"ack\":\n case \"ext-command-result\":\n case \"runtime-host-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","import { basename } from \"node:path\";\n\nimport { sanitizeCallerLabel } from \"@opentray/spec\";\n\nexport interface CallerLabelSources {\n /** Explicit developer-provided label, highest precedence. */\n readonly explicit?: string;\n /** `npm_package_name` environment value. */\n readonly npmPackageName?: string;\n /** Script path resolved from `process.argv[1]` or equivalent. */\n readonly scriptPath?: string;\n}\n\nexport interface ResolveCallerLabelOptions extends Partial<CallerLabelSources> {\n env?: NodeJS.ProcessEnv;\n argv?: readonly string[];\n}\n\n/**\n * Derives a caller label using the precedence: explicit > npm_package_name >\n * script basename > neutral default. The result is always sanitized to a\n * filesystem- and process-safe component, so callers can use it directly in\n * endpoint identity, runtime directories, and process titles.\n */\nexport const resolveCallerLabel = (options: ResolveCallerLabelOptions = {}): string => {\n const env = options.env ?? process.env;\n const argv = options.argv ?? process.argv;\n\n const candidates: string[] = [];\n if (options.explicit !== undefined && options.explicit.length > 0) {\n candidates.push(options.explicit);\n }\n const npmName = options.npmPackageName ?? env.npm_package_name;\n if (typeof npmName === \"string\" && npmName.length > 0) {\n candidates.push(npmName);\n }\n const scriptPath = options.scriptPath ?? argv[1];\n if (typeof scriptPath === \"string\" && scriptPath.length > 0) {\n candidates.push(basename(scriptPath));\n }\n\n for (const candidate of candidates) {\n const sanitized = sanitizeCallerLabel(candidate);\n if (sanitized.length > 0) {\n return sanitized;\n }\n }\n\n return sanitizeCallerLabel(undefined);\n};\n","import type { BrokerArtifactTarget } from \"@opentray/spec\";\n\nexport 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\nexport const resolveBrokerArtifactTarget = (\n platform: string = process.platform,\n arch: string = process.arch,\n): BrokerArtifactTarget => {\n const packageOs = platformToPackageOs(platform);\n return {\n os: packageOs === \"windows\" ? \"win32\" : packageOs,\n arch: normalizeArch(arch),\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 { createHash } from \"node:crypto\";\nimport { access, readFile, realpath } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn } from \"node:child_process\";\n\nimport type { BrokerArtifactIdentity } from \"@opentray/spec\";\n\nimport type { DaemonPaths } from \"./paths\";\nimport {\n type BrokerNativeTarget,\n MissingPlatformBrokerBinaryError,\n resolveBrokerArtifactTarget,\n resolveBrokerNativeTarget,\n} from \"./native-target\";\n\nexport interface BrokerCommand {\n command: string;\n args: string[];\n cwd?: string;\n}\n\nexport interface ResolvedBrokerArtifact extends BrokerCommand {\n executablePath: string;\n artifactIdentity: BrokerArtifactIdentity;\n}\n\nconst sourceUrl = import.meta.url;\nconst requireFromSource = createRequire(sourceUrl);\n\nexport interface InstalledBrokerBinaryResolution {\n binary?: string;\n binaryPath?: string;\n}\n\nexport interface ResolveInstalledBrokerBinaryOptions {\n platform?: NodeJS.Platform;\n resolvePackageJson?: (specifier: string) => string;\n assertBinaryAccessible?: (binaryPath: string, platform: NodeJS.Platform) => Promise<void>;\n}\n\nexport interface ResolveBrokerCommandOptions {\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n arch?: string;\n sourceDir?: string;\n resolveInstalledBrokerBinary?: (\n target: BrokerNativeTarget,\n options: ResolveInstalledBrokerBinaryOptions,\n ) => Promise<InstalledBrokerBinaryResolution>;\n findWorkspaceRoot?: (start: string) => Promise<string | undefined>;\n ensureDevBrokerBinary?: (\n workspaceRoot: string,\n paths: DaemonPaths,\n platform: NodeJS.Platform,\n ) => Promise<string>;\n}\n\nexport interface ResolveBrokerArtifactOptions extends ResolveBrokerCommandOptions {\n resolveExecutablePath?: (path: string) => Promise<string>;\n readExecutable?: (path: string) => Promise<Uint8Array>;\n}\n\nexport const resolveBrokerArtifact = async (\n paths: DaemonPaths,\n options: ResolveBrokerArtifactOptions = {},\n): Promise<ResolvedBrokerArtifact> => {\n const command = await resolveBrokerCommand(paths, options);\n const executablePath = await (options.resolveExecutablePath ?? realpath)(command.command);\n const bytes = await (options.readExecutable ?? readFile)(executablePath);\n const executableHash = createHash(\"sha256\").update(bytes).digest(\"hex\");\n const artifactIdentity: BrokerArtifactIdentity = {\n packageVersion: paths.packageVersion,\n target: resolveBrokerArtifactTarget(\n options.platform ?? process.platform,\n options.arch ?? process.arch,\n ),\n executableHash,\n buildIdentity: `sha256:${executableHash.slice(0, 16)}`,\n };\n return {\n ...command,\n command: executablePath,\n args: [\n ...command.args,\n \"--broker-executable-path\",\n executablePath,\n \"--broker-artifact-identity\",\n JSON.stringify(artifactIdentity),\n ],\n executablePath,\n artifactIdentity,\n };\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 const target = resolveBrokerNativeTarget(platform, arch);\n const installed = await (options.resolveInstalledBrokerBinary ?? resolveInstalledBrokerBinary)(\n target,\n { platform },\n );\n if (installed.binary !== undefined) {\n return commandForBinary(installed.binary, paths);\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)(\n workspaceRoot,\n paths,\n platform,\n );\n return commandForBinary(binary, paths);\n }\n\n throw new MissingPlatformBrokerBinaryError(\n installed.binaryPath === undefined\n ? `unable to resolve OpenTray broker binary for ${platform}/${arch}; install \"${target.packageName}\" for this platform or set OPENTRAY_BROKER_BIN`\n : `unable to resolve OpenTray broker binary for ${platform}/${arch}; package \"${target.packageName}\" was found but binary \"${installed.binaryPath}\" is not accessible; restage the runtime package or set OPENTRAY_BROKER_BIN`,\n platform,\n arch,\n {\n packageName: target.packageName,\n ...(installed.binaryPath === undefined ? {} : { binaryPath: installed.binaryPath }),\n },\n );\n};\n\nexport const resolveInstalledBrokerBinary = async (\n target: BrokerNativeTarget,\n options: ResolveInstalledBrokerBinaryOptions = {},\n): Promise<InstalledBrokerBinaryResolution> => {\n const platform = options.platform ?? process.platform;\n let packageJsonPath: string;\n try {\n packageJsonPath = (\n options.resolvePackageJson ?? requireFromSource.resolve.bind(requireFromSource)\n )(`${target.packageName}/package.json`);\n } catch (error) {\n if (isNodeError(error) && error.code === \"MODULE_NOT_FOUND\") {\n return {};\n }\n throw error;\n }\n\n const binaryPath = join(dirname(packageJsonPath), target.binaryRelativePath);\n try {\n await (options.assertBinaryAccessible ?? assertInstalledBrokerBinaryAccessible)(\n binaryPath,\n platform,\n );\n return { binary: binaryPath, binaryPath };\n } catch (error) {\n if (\n isNodeError(error) &&\n (error.code === \"ENOENT\" || error.code === \"EACCES\" || error.code === \"EPERM\")\n ) {\n return { binaryPath };\n }\n throw error;\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 \"--app-id\",\n paths.appId,\n \"--app-name\",\n paths.appName,\n \"--caller-label\",\n paths.callerLabel,\n ],\n };\n if (cwd !== undefined) {\n command.cwd = cwd;\n }\n return command;\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\nexport const resolveDevBrokerBinaryPath = (\n workspaceRoot: string,\n platform: NodeJS.Platform = process.platform,\n callerLabel = \"opentray\",\n): string =>\n join(\n resolveDevBrokerTargetDir(workspaceRoot, platform, callerLabel),\n \"debug\",\n platform === \"win32\" ? \"opentray.exe\" : \"opentray\",\n );\n\nconst resolveDevBrokerTargetDir = (\n workspaceRoot: string,\n platform: NodeJS.Platform,\n callerLabel: string,\n): string =>\n platform === \"win32\"\n ? join(workspaceRoot, \"target\", \"opentray-source\", callerLabel)\n : join(workspaceRoot, \"target\");\n\nconst ensureDevBrokerBinary = async (\n workspaceRoot: string,\n paths: DaemonPaths,\n platform: NodeJS.Platform,\n): Promise<string> => {\n const targetDir = resolveDevBrokerTargetDir(workspaceRoot, platform, paths.callerLabel);\n const binary = resolveDevBrokerBinaryPath(workspaceRoot, platform, paths.callerLabel);\n await runCargoBuild(workspaceRoot, platform === \"win32\" ? targetDir : undefined);\n return binary;\n};\n\nconst runCargoBuild = (workspaceRoot: string, targetDir?: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const child = spawn(\n \"cargo\",\n [\n \"build\",\n \"-p\",\n \"opentray-bin\",\n ...(targetDir === undefined ? [] : [\"--target-dir\", targetDir]),\n ],\n {\n cwd: workspaceRoot,\n stdio: process.env.OPENTRAY_BROKER_BUILD_LOGS === \"1\" ? \"inherit\" : \"ignore\",\n },\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 binaryAccessMode = (platform: NodeJS.Platform): number =>\n platform === \"win32\" ? constants.F_OK : constants.X_OK;\n\nconst assertInstalledBrokerBinaryAccessible = async (\n binaryPath: string,\n platform: NodeJS.Platform,\n): Promise<void> => {\n await access(binaryPath, binaryAccessMode(platform));\n};\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\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 {\n brokerArtifactIdentityEquals,\n isBrokerArtifactIdentity,\n type BrokerReadyMetadata,\n} from \"@opentray/spec\";\n\nimport { resolveBrokerArtifact, type ResolvedBrokerArtifact } from \"./broker-command\";\nimport type { DaemonPaths } from \"./paths\";\n\nconst DAEMON_STDIO_ENV = \"OPENTRAY_DAEMON_STDIO\";\nconst DEFAULT_DAEMON_LOCK_TIMEOUT_MS = 5_000;\n\nexport type DaemonStartResult =\n | {\n status: \"started\";\n pid: number;\n paths: DaemonPaths;\n broker: ResolvedBrokerArtifact;\n }\n | {\n status: \"already-running\";\n pid: number;\n paths: DaemonPaths;\n broker: ResolvedBrokerArtifact;\n };\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 resolveBroker(paths: DaemonPaths): Promise<ResolvedBrokerArtifact>;\n isAlive(pid: number): Promise<boolean>;\n spawnBroker(paths: DaemonPaths, broker: ResolvedBrokerArtifact): 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 resolveBroker(paths) {\n return resolveBrokerArtifact(paths);\n },\n async isAlive(pid) {\n return isProcessAlive(pid);\n },\n async spawnBroker(paths, broker) {\n // The caller label flows to the broker via both a CLI flag and an env var.\n // The broker uses it to bind the per-caller endpoint and to set its own\n // process title so task managers show the owning application.\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 OPENTRAY_DAEMON_APP_ID: paths.appId,\n OPENTRAY_DAEMON_APP_NAME: paths.appName,\n OPENTRAY_DAEMON_CALLER_LABEL: paths.callerLabel,\n },\n stdio: resolveBrokerStdio(process.env[DAEMON_STDIO_ENV]),\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 resolveBrokerStdio = (value: string | undefined): \"ignore\" | \"inherit\" => {\n return value === \"inherit\" ? \"inherit\" : \"ignore\";\n};\n\nexport const startDaemon = async ({\n paths,\n driver,\n lockTimeoutMs = DEFAULT_DAEMON_LOCK_TIMEOUT_MS,\n}: StartDaemonOptions): Promise<DaemonStartResult> => {\n const broker = await driver.resolveBroker(paths);\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 const ready = await readReadyMetadata(paths.readyFile);\n // Liveness is not compatibility: only the exact resolved executable may win reuse.\n if (readyMatchesBroker(ready, paths, existingPid, broker)) {\n return {\n status: \"already-running\",\n pid: existingPid,\n paths,\n broker,\n };\n }\n await driver.stop(existingPid);\n if (!(await waitUntilStopped(driver, existingPid))) {\n throw new Error(\n `incompatible daemon broker did not stop within the bounded shutdown window: pid=${existingPid}`,\n );\n }\n }\n\n await cleanupRuntimeFiles(paths);\n const pid = await driver.spawnBroker(paths, broker);\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 try {\n await waitForReadyFile(paths, driver, pid, broker);\n } catch (error) {\n if (await driver.isAlive(pid)) {\n await driver.stop(pid);\n await waitUntilStopped(driver, pid);\n }\n await cleanupRuntimeFiles(paths);\n throw error;\n }\n return { status: \"started\", pid, paths, broker };\n } finally {\n await lock.release();\n }\n};\n\nexport const stopDaemon = async ({\n paths,\n driver,\n}: 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 if (!(await waitUntilStopped(driver, pid))) {\n throw new Error(`daemon broker did not stop within the bounded shutdown window: pid=${pid}`);\n }\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 ({\n paths,\n driver,\n}: 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<boolean> => {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (!(await driver.isAlive(pid))) {\n return true;\n }\n await sleep(50);\n }\n return false;\n};\n\nconst waitForReadyFile = async (\n paths: DaemonPaths,\n driver: DaemonDriver,\n pid: number,\n broker: ResolvedBrokerArtifact,\n): Promise<void> => {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n const ready = await readReadyMetadata(paths.readyFile);\n if (readyMatchesBroker(ready, paths, pid, broker)) {\n return;\n }\n if (ready !== undefined) {\n throw new Error(\n `daemon readiness artifact identity mismatch: expected=${JSON.stringify(broker.artifactIdentity)} actual=${JSON.stringify(ready.brokerArtifactIdentity)}`,\n );\n }\n if (!(await driver.isAlive(pid))) {\n throw new Error(\n `daemon broker exited before readiness: pid=${pid}; readyFile=${paths.readyFile}; set ${DAEMON_STDIO_ENV}=inherit to inspect broker stderr`,\n );\n }\n await sleep(50);\n }\n\n throw new Error(`timed out waiting for daemon readiness: ${paths.readyFile}`);\n};\n\nconst readReadyMetadata = async (readyFile: string): Promise<BrokerReadyMetadata | undefined> => {\n let value: unknown;\n try {\n value = JSON.parse(await readFile(readyFile, \"utf8\"));\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return undefined;\n }\n if (error instanceof SyntaxError) {\n return undefined;\n }\n throw error;\n }\n if (\n !isRecord(value) ||\n !Number.isInteger(value.pid) ||\n typeof value.pid !== \"number\" ||\n typeof value.endpoint !== \"string\" ||\n typeof value.packageVersion !== \"string\" ||\n typeof value.protocolVersion !== \"number\" ||\n typeof value.appId !== \"string\" ||\n typeof value.appName !== \"string\" ||\n typeof value.callerLabel !== \"string\" ||\n typeof value.executablePath !== \"string\" ||\n !isBrokerArtifactIdentity(value.brokerArtifactIdentity)\n ) {\n return undefined;\n }\n return {\n pid: value.pid,\n endpoint: value.endpoint,\n packageVersion: value.packageVersion,\n protocolVersion: value.protocolVersion,\n appId: value.appId,\n appName: value.appName,\n callerLabel: value.callerLabel,\n executablePath: value.executablePath,\n brokerArtifactIdentity: value.brokerArtifactIdentity,\n };\n};\n\nconst readyMatchesBroker = (\n ready: BrokerReadyMetadata | undefined,\n paths: DaemonPaths,\n pid: number,\n broker: ResolvedBrokerArtifact,\n): boolean =>\n ready !== undefined &&\n ready.pid === pid &&\n ready.endpoint === paths.endpoint &&\n ready.packageVersion === paths.packageVersion &&\n ready.protocolVersion === paths.protocolVersion &&\n ready.appId === paths.appId &&\n ready.appName === paths.appName &&\n ready.callerLabel === paths.callerLabel &&\n executablePathsEqual(ready.executablePath, broker.executablePath) &&\n brokerArtifactIdentityEquals(ready.brokerArtifactIdentity, broker.artifactIdentity);\n\nexport const executablePathsEqual = (\n left: string,\n right: string,\n platform: NodeJS.Platform = process.platform,\n): boolean => {\n if (platform !== \"win32\") {\n return left === right;\n }\n\n const normalize = (value: string): string =>\n value\n .replaceAll(\"\\\\\", \"/\")\n .replace(/^\\/\\/?\\?\\//u, \"\")\n .toLowerCase();\n return normalize(left) === normalize(right);\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(\n lockFile,\n constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY,\n );\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\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\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 {\n createBrokerEndpointIdentity,\n formatUnixSocketPath,\n formatWindowsPipeName,\n} from \"@opentray/spec\";\n\nexport interface DaemonPathOptions {\n homeDir: string;\n packageVersion: string;\n callerLabel?: string;\n appId?: string;\n appName?: string;\n platform?: NodeJS.Platform;\n}\n\nexport interface DaemonPaths {\n homeDir: string;\n packageVersion: string;\n callerLabel: string;\n appId: string;\n appName: 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 callerLabel,\n appId,\n appName,\n platform = process.platform,\n}: DaemonPathOptions): DaemonPaths => {\n const identity = createBrokerEndpointIdentity(\n callerLabel === undefined\n ? { packageVersion }\n : { packageVersion, callerLabel }\n );\n const resolvedAppId = normalizeAppIdentityField(appId, identity.callerLabel);\n const resolvedAppName = normalizeAppIdentityField(\n appName,\n identity.callerLabel\n );\n const normalizedHome = homeDir.replace(/[\\\\/]+$/u, \"\");\n const stateRoot = `${normalizedHome}/.opentray/${identity.packageVersion}/${identity.callerLabel}`;\n const runtimeDir = `${stateRoot}/runtime`;\n const endpoint =\n platform === \"win32\"\n ? formatWindowsPipeName(identity)\n : formatUnixSocketPath(normalizedHome, identity);\n\n return {\n homeDir: normalizedHome,\n packageVersion: identity.packageVersion,\n callerLabel: identity.callerLabel,\n appId: resolvedAppId,\n appName: resolvedAppName,\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\nconst normalizeAppIdentityField = (\n value: string | undefined,\n fallback: string\n): string => {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? fallback : trimmed;\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 brokerArtifactIdentityEquals,\n parseServerFrame,\n type BrokerArtifactIdentity,\n type BrokerEndpointIdentityOptions,\n type ClientRequestFrame,\n type RequestId,\n type ServerFrame,\n} from \"@opentray/spec\";\n\nimport type { OpenTrayTransport } from \"./client\";\nimport { resolveCallerLabel } from \"./daemon/caller-label\";\nimport {\n createNodeDaemonDriver,\n startDaemon,\n type DaemonDriver,\n} 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 LocalRuntimeEventFrame = Extract<\n ServerFrame,\n { type: \"event\" | \"ext-event\" }\n>;\n\nexport interface LocalBrokerClient extends OpenTrayTransport {\n readonly endpoint: string;\n readonly callerLabel: string;\n readonly sessionId: string;\n onEvent(listener: (frame: LocalRuntimeEventFrame) => void): () => void;\n close(): Promise<void>;\n}\n\nexport interface ConnectLocalBrokerOptions\n extends Partial<BrokerEndpointIdentityOptions> {\n endpoint?: string;\n homeDir?: string;\n appId?: string;\n appName?: string;\n clientVersion?: string;\n autoStart?: boolean;\n daemonDriver?: DaemonDriver;\n cliEntrypoint?: string;\n callerLabel?: string;\n expectedBrokerArtifactIdentity?: BrokerArtifactIdentity;\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 =\n options.packageVersion ?? (await readPackageVersion(packageJsonUrl));\n const clientVersion = options.clientVersion ?? packageVersion;\n const appId = normalizeAppIdentityField(options.appId);\n const appName = normalizeAppIdentityField(options.appName);\n const callerLabel =\n options.callerLabel ?? appName ?? appId ?? resolveCallerLabel();\n const paths = resolveDaemonPaths({\n homeDir: options.homeDir ?? process.env.OPENTRAY_HOME ?? homedir(),\n packageVersion,\n callerLabel,\n ...(appId === undefined ? {} : { appId }),\n ...(appName === undefined ? {} : { appName }),\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(\n \"local broker autoStart requires the derived same-version endpoint\"\n );\n }\n const cliEntrypoint = options.cliEntrypoint ?? resolveCliEntrypoint();\n const driver = options.daemonDriver ?? createNodeDaemonDriver(cliEntrypoint);\n const expectedBrokerArtifactIdentity = autoStart\n ? (await startDaemon({ paths, driver })).broker.artifactIdentity\n : options.expectedBrokerArtifactIdentity ??\n (await driver.resolveBroker(paths)).artifactIdentity;\n const socket = await connectSocket(endpoint);\n const connection = new LocalBrokerConnection(socket, endpoint, callerLabel);\n\n try {\n await connection.init(\n clientVersion,\n options.protocolVersion ?? PROTOCOL_VERSION,\n expectedBrokerArtifactIdentity,\n );\n } catch (error) {\n await connection.close();\n throw error;\n }\n return connection;\n};\n\nconst normalizeAppIdentityField = (\n value: string | undefined\n): string | undefined => {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;\n};\n\nclass LocalBrokerConnection implements LocalBrokerClient {\n readonly endpoint: string;\n readonly callerLabel: string;\n sessionId = \"\";\n\n private buffer = \"\";\n private readonly listeners = new Set<\n (frame: LocalRuntimeEventFrame) => void\n >();\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 callerLabel: string\n ) {\n this.endpoint = endpoint;\n this.callerLabel = callerLabel;\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(\n clientVersion: string,\n protocolVersion: number,\n expectedBrokerArtifactIdentity: BrokerArtifactIdentity,\n ): Promise<void> {\n const ready = new Promise<Extract<ServerFrame, { type: \"ready\" }>>(\n (resolve, reject) => {\n this.ready = { resolve, reject };\n }\n );\n this.write({\n type: \"init\",\n protocolVersion,\n clientVersion,\n });\n const frame = await ready;\n if (\n !brokerArtifactIdentityEquals(\n frame.brokerArtifactIdentity,\n expectedBrokerArtifactIdentity,\n )\n ) {\n throw new Error(\n `broker artifact identity mismatch: expected=${JSON.stringify(expectedBrokerArtifactIdentity)} actual=${JSON.stringify(frame.brokerArtifactIdentity)}`,\n );\n }\n this.sessionId = frame.sessionId;\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: LocalRuntimeEventFrame) => 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(\n new Error(`${parsed.error ?? \"invalid server frame\"}: ${line}`)\n );\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 // An error with no requestId could not be correlated to a specific request.\n // If the handshake is still pending, reject it; otherwise reject every\n // pending request so callers fail loudly instead of hanging indefinitely.\n // (See issue #3: createTray never resolves on a malformed frame.)\n if (this.ready) {\n this.ready.reject(error);\n this.ready = undefined;\n return;\n }\n this.rejectAll(error);\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 \"app-created\":\n case \"default-app\":\n case \"app-identity\":\n case \"tray-created\":\n case \"tray-bounds\":\n case \"ack\":\n case \"ext-command-result\":\n case \"runtime-host-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\")\n ? \"cli.ts\"\n : \"cli.mjs\";\n return fileURLToPath(new URL(`./${suffix}`, import.meta.url));\n};\n","import type { Menu, MenuItem, MenuItemId } from \"@opentray/spec\";\n\nimport type { TrayEventByType } from \"./client\";\n\nexport type CreateTrayMenuClickHandler = (\n event: TrayEventByType<\"menuClick\">\n) => void;\n\n/** App-facing menu input accepted by top-level createTray and setMenu. */\nexport type CreateTrayMenu = {\n items: CreateTrayMenuItem[];\n};\n\n/** Menu item shorthand normalized to protocol MenuItem before runtime transport. */\nexport type CreateTrayMenuItem =\n | string\n | readonly [title: string, items: readonly CreateTrayMenuItem[]]\n | CreateTrayItem\n | CreateTrayCheckItem\n | CreateTrayRadioItem\n | CreateTraySeparatorItem\n | CreateTraySubmenuItem;\n\nexport type CreateTrayItem = {\n type?: \"item\";\n id?: MenuItemId;\n title: string;\n primaryEvent?: boolean;\n enabled?: boolean;\n shortcut?: string;\n onMenuClick?: CreateTrayMenuClickHandler;\n};\n\nexport type CreateTrayCheckItem = {\n type: \"check\";\n id?: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n onMenuClick?: CreateTrayMenuClickHandler;\n};\n\nexport type CreateTrayRadioItem = {\n type: \"radio\";\n id?: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n group: number;\n onMenuClick?: CreateTrayMenuClickHandler;\n};\n\nexport type CreateTraySeparatorItem = {\n type: \"separator\";\n};\n\nexport type CreateTraySubmenuItem = {\n type: \"submenu\";\n title: string;\n enabled?: boolean;\n items: readonly CreateTrayMenuItem[];\n};\n\nexport interface NormalizedCreateTrayMenu {\n menu: Menu;\n handlers: Map<MenuItemId, CreateTrayMenuClickHandler[]>;\n}\n\nexport const normalizeCreateTrayMenu = (\n menu: CreateTrayMenu\n): NormalizedCreateTrayMenu => {\n const state: NormalizeState = {\n usedIds: collectExplicitMenuIds(menu.items),\n nextId: 1,\n handlers: new Map(),\n };\n return {\n menu: {\n items: menu.items.map((item) => normalizeCreateTrayMenuItem(item, state)),\n },\n handlers: state.handlers,\n };\n};\n\nconst normalizeCreateTrayMenuItem = (\n item: CreateTrayMenuItem,\n state: NormalizeState\n): MenuItem => {\n if (typeof item === \"string\") {\n if (isSeparatorShortcut(item)) {\n return { type: \"separator\" };\n }\n return normalizePlainItem({ title: item }, state);\n }\n if (isSubmenuTuple(item)) {\n const [title, items] = item;\n return {\n type: \"submenu\",\n title,\n items: items.map((child) => normalizeCreateTrayMenuItem(child, state)),\n };\n }\n switch (item.type) {\n case undefined:\n case \"item\":\n return normalizePlainItem(item, state);\n case \"check\":\n return normalizeCheckItem(item, state);\n case \"radio\":\n return normalizeRadioItem(item, state);\n case \"separator\":\n return item;\n case \"submenu\":\n return {\n type: \"submenu\",\n title: item.title,\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n items: item.items.map((child) =>\n normalizeCreateTrayMenuItem(child, state)\n ),\n };\n }\n throw new Error(\"unsupported menu item\");\n};\n\nconst normalizeClickableItem = (\n item: {\n id?: MenuItemId;\n onMenuClick?: CreateTrayMenuClickHandler;\n },\n state: NormalizeState\n): MenuItemId => {\n const id = item.id ?? allocateMenuItemId(state);\n registerClickId(state, id);\n if (item.onMenuClick !== undefined) {\n const handlers = state.handlers.get(id) ?? [];\n handlers.push(item.onMenuClick);\n state.handlers.set(id, handlers);\n }\n return id;\n};\n\nconst normalizePlainItem = (\n item: CreateTrayItem,\n state: NormalizeState\n): Extract<MenuItem, { type: \"item\" }> => {\n const id = normalizeClickableItem(item, state);\n return {\n type: \"item\",\n id,\n title: item.title,\n ...(item.primaryEvent === undefined\n ? {}\n : { primaryEvent: item.primaryEvent }),\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n ...(item.shortcut === undefined ? {} : { shortcut: item.shortcut }),\n };\n};\n\nconst normalizeCheckItem = (\n item: CreateTrayCheckItem,\n state: NormalizeState\n): Extract<MenuItem, { type: \"check\" }> => {\n const id = normalizeClickableItem(item, state);\n return {\n type: \"check\",\n id,\n title: item.title,\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n ...(item.checked === undefined ? {} : { checked: item.checked }),\n };\n};\n\nconst normalizeRadioItem = (\n item: CreateTrayRadioItem,\n state: NormalizeState\n): Extract<MenuItem, { type: \"radio\" }> => {\n const id = normalizeClickableItem(item, state);\n return {\n type: \"radio\",\n id,\n title: item.title,\n ...(item.enabled === undefined ? {} : { enabled: item.enabled }),\n ...(item.checked === undefined ? {} : { checked: item.checked }),\n group: item.group,\n };\n};\n\nconst allocateMenuItemId = (state: NormalizeState): MenuItemId => {\n while (state.usedIds.has(state.nextId)) {\n state.nextId += 1;\n }\n const id = state.nextId;\n state.usedIds.add(id);\n state.nextId += 1;\n return id;\n};\n\nconst collectExplicitMenuIds = (\n items: readonly CreateTrayMenuItem[]\n): Set<MenuItemId> => {\n const ids = new Set<MenuItemId>();\n for (const item of items) {\n if (typeof item === \"string\") {\n continue;\n }\n if (isSubmenuTuple(item)) {\n for (const id of collectExplicitMenuIds(item[1])) {\n ids.add(id);\n }\n continue;\n }\n switch (item.type) {\n case undefined:\n case \"item\":\n case \"check\":\n case \"radio\":\n if (item.id !== undefined) {\n ids.add(item.id);\n }\n break;\n case \"submenu\":\n for (const id of collectExplicitMenuIds(item.items)) {\n ids.add(id);\n }\n break;\n case \"separator\":\n break;\n }\n }\n return ids;\n};\n\nconst isSeparatorShortcut = (value: string): boolean => /^-+$/.test(value);\n\nconst isSubmenuTuple = (\n item: CreateTrayMenuItem\n): item is readonly [title: string, items: readonly CreateTrayMenuItem[]] =>\n Array.isArray(item);\n\nconst registerClickId = (state: NormalizeState, id: MenuItemId): void => {\n const seen = state.seenClickIds ?? new Set<MenuItemId>();\n if (seen.has(id)) {\n throw new Error(`duplicate menu item id: ${id}`);\n }\n seen.add(id);\n state.seenClickIds = seen;\n};\n\ninterface NormalizeState {\n usedIds: Set<MenuItemId>;\n nextId: MenuItemId;\n handlers: Map<MenuItemId, CreateTrayMenuClickHandler[]>;\n seenClickIds?: Set<MenuItemId>;\n}\n","// Orthogonal intents (2026-07-19; original user request: pnpm install must be sufficient):\n// 1. Expose one direct, ergonomic createTray entrypoint.\n// 2. Normalize app-facing menu shorthand into the protocol model.\n// 3. Make the returned handle own and deterministically close its broker session.\n\nimport type { Icon, Tooltip, TrayOptions } from \"@opentray/spec\";\n\nimport {\n createClient,\n type EventfulTrayHandle,\n type TrayExtension,\n} from \"./client\";\nimport { connectLocalBroker } from \"./local-broker\";\nimport {\n normalizeCreateTrayMenu,\n type CreateTrayMenu,\n type CreateTrayMenuClickHandler,\n} from \"./menu-input\";\n\nexport interface OpenTrayRuntimeOptions {\n endpoint?: string;\n homeDir?: string;\n packageVersion?: string;\n protocolVersion?: number;\n clientVersion?: string;\n appId?: string;\n appName?: string;\n appIcon?: Icon;\n autoStart?: boolean;\n}\n\n/** App-facing tray options accepted by top-level createTray. */\nexport interface CreateTrayOptions {\n id: string;\n tooltip?: Tooltip;\n icon?: Icon;\n menu?: CreateTrayMenu;\n}\n\n/** Tray handle returned by top-level createTray with ergonomic menu and session ownership. */\nexport interface CreateTrayHandle\n extends Omit<EventfulTrayHandle, \"setMenu\" | \"extend\" | \"destroy\"> {\n setMenu(menu: CreateTrayMenu): Promise<void>;\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): CreateTrayHandle & TCapability;\n destroy(): Promise<void>;\n}\n\nexport const createTray = async (\n options: CreateTrayOptions,\n runtimeOptions: OpenTrayRuntimeOptions = {}\n): Promise<CreateTrayHandle> => {\n const normalized = normalizeCreateTrayOptions(options);\n const connection = await connectLocalBroker(runtimeOptions);\n try {\n const tray = await createClient(connection, {\n appOptions: {\n ...(runtimeOptions.appName === undefined\n ? {}\n : { name: runtimeOptions.appName }),\n ...(runtimeOptions.appIcon === undefined\n ? {}\n : { icon: runtimeOptions.appIcon }),\n },\n }).createTray(normalized.options);\n return wrapCreateTrayHandle(tray, {\n closeConnection: () => connection.close(),\n destroyPromise: undefined,\n menuUnsubscribe: bindMenuClickHandlers(tray, normalized.menuHandlers),\n });\n } catch (error) {\n await connection.close().catch(noop);\n throw error;\n }\n};\n\nconst normalizeCreateTrayOptions = (\n options: CreateTrayOptions\n): NormalizedCreateTrayOptions => {\n const protocolOptions: Omit<TrayOptions, \"menu\"> = {\n id: options.id,\n ...(options.tooltip === undefined ? {} : { tooltip: options.tooltip }),\n ...(options.icon === undefined ? {} : { icon: options.icon }),\n };\n if (options.menu === undefined) {\n return { options: protocolOptions, menuHandlers: new Map() };\n }\n const normalized = normalizeCreateTrayMenu(options.menu);\n return {\n options: {\n ...protocolOptions,\n menu: normalized.menu,\n },\n menuHandlers: normalized.handlers,\n };\n};\n\nconst wrapCreateTrayHandle = (\n tray: EventfulTrayHandle,\n state: CreateTrayHandleState\n): CreateTrayHandle => {\n const handle: CreateTrayHandle = {\n ...tray,\n async setMenu(menu: CreateTrayMenu): Promise<void> {\n const normalized = normalizeCreateTrayMenu(menu);\n await tray.setMenu(normalized.menu);\n state.menuUnsubscribe();\n state.menuUnsubscribe = bindMenuClickHandlers(tray, normalized.handlers);\n },\n extend<TCapability extends object, TOptions = undefined>(\n extension: TrayExtension<TCapability, TOptions>,\n options?: TOptions\n ): CreateTrayHandle & TCapability {\n const extended = tray.extend(extension, options);\n return wrapCreateTrayHandle(extended, state) as CreateTrayHandle &\n TCapability;\n },\n async destroy(): Promise<void> {\n state.destroyPromise ??= (async () => {\n state.menuUnsubscribe();\n state.menuUnsubscribe = noop;\n try {\n await tray.destroy();\n } finally {\n await state.closeConnection();\n }\n })();\n await state.destroyPromise;\n },\n };\n return handle;\n};\n\nconst bindMenuClickHandlers = (\n tray: EventfulTrayHandle,\n handlers: Map<number, CreateTrayMenuClickHandler[]>\n): (() => void) => {\n if (handlers.size === 0) {\n return noop;\n }\n return tray.onMenuClick((event) => {\n for (const handler of handlers.get(event.itemId) ?? []) {\n handler(event);\n }\n });\n};\n\nconst noop = (): void => {};\n\ninterface NormalizedCreateTrayOptions {\n options: TrayOptions;\n menuHandlers: Map<number, CreateTrayMenuClickHandler[]>;\n}\n\ninterface CreateTrayHandleState {\n closeConnection: () => Promise<void>;\n destroyPromise: Promise<void> | undefined;\n menuUnsubscribe: () => void;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opentray",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Developer-facing OpenTray SDK and CLI package.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"sideEffects": false,
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@opentray/spec": "0.
|
|
27
|
+
"@opentray/spec": "0.16.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"tsdown": "^0.22.1",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"vitest": "^4.1.7"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@opentray/darwin-arm64": "0.
|
|
36
|
-
"@opentray/
|
|
37
|
-
"@opentray/linux-
|
|
38
|
-
"@opentray/
|
|
39
|
-
"@opentray/windows-arm64": "0.
|
|
40
|
-
"@opentray/windows-x64": "0.
|
|
35
|
+
"@opentray/darwin-arm64": "0.16.0",
|
|
36
|
+
"@opentray/linux-arm64": "0.16.0",
|
|
37
|
+
"@opentray/linux-x64": "0.16.0",
|
|
38
|
+
"@opentray/darwin-x64": "0.16.0",
|
|
39
|
+
"@opentray/windows-arm64": "0.16.0",
|
|
40
|
+
"@opentray/windows-x64": "0.16.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsdown src/index.ts src/cli.ts --format esm --dts",
|