opentray 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,22 +27,24 @@ Use `alpha-A-B` for alpha packages on the same protocol line. Replace `A-B` with
27
27
 
28
28
  ## Tray-First API
29
29
 
30
- For the first app, use `runTrayApp()` from `opentray/node` so the host/worker split stays out of the user's way:
30
+ For the first app, call `createTray()` directly. The quickstart stays in one file and does not ask the user to wire a worker or a host loop first:
31
31
 
32
32
  ```ts
33
- import { runTrayApp } from "opentray/node";
34
-
35
- await runTrayApp(async ({ createTray }) => {
36
- const tray = await createTray({
37
- id: "com.example.first-app",
38
- icon: { "text-only": "OT" },
39
- menu: { items: [{ type: "item", id: 1, title: "Quit", primaryEvent: true }] },
40
- });
41
- tray.onMenuClick(({ itemId }) => void (itemId === 1 && tray.destroy()));
42
- }, { autoExitAfterMs: 1500 });
33
+ import { createTray } from "opentray";
34
+
35
+ const tray = await createTray({
36
+ id: "com.example.first-app",
37
+ icon: { "text-only": "OT" },
38
+ menu: { items: [{ type: "item", id: 1, title: "Quit", primaryEvent: true }] },
39
+ }, {
40
+ appId: "com.example.first-app",
41
+ appName: "First App",
42
+ });
43
+
44
+ tray.onMenuClick(({ itemId }) => void (itemId === 1 && tray.destroy()));
43
45
  ```
44
46
 
45
- `createTray()` is still the direct tray API when the caller already owns the runtime process shape.
47
+ `createTray()` remains the direct tray API when the caller already owns the runtime process shape.
46
48
 
47
49
  ```ts
48
50
  import { createTray } from "opentray";
@@ -79,9 +81,9 @@ OpenTray does not ask developers to create a public broker object. The applicati
79
81
 
80
82
  Node platform packages carry the host-loadable runtime artifact at `runtime/opentray_runtime.node`. `opentray/node` exposes `runVisibleRuntimeHost()`, `loadOpenTrayRuntimeBinding()`, and `resolveInstalledRuntimeBindingPath()` for Node-specific host-loop ownership, runtime diagnostics, and packaging checks.
81
83
 
82
- By default, `createTray()` routes through the visible Node runtime binding. The host main thread must run `runVisibleRuntimeHost()` while app logic runs in a worker or another app-owned execution source. This is a platform law, not a convenience wrapper: on macOS native tray creation must happen on the application main thread, and all native menu/tray events route back only to the live session that owns the tray.
84
+ By default, `createTray()` routes through the local broker and starts it on first use when needed. `runVisibleRuntimeHost()` remains available from `opentray/node` as an explicit diagnostic path for the visible-binding smoke mode. That diagnostic path still follows the application main-thread law on macOS and the app-owned event-loop law on Windows.
83
85
 
84
- For protocol/session diagnostics, `createTray(options, { runtime: "headless-binding" })` routes through the Node binding without visible native state. Source-tree diagnostics may use `{ runtime: "local-broker" }`, but that transport is not the default package runtime.
86
+ For protocol/session diagnostics, `createTray(options, { runtime: "headless-binding" })` routes through the Node binding without visible native state. Source-tree diagnostics may use `{ runtime: "visible-binding" }` or `{ runtime: "local-broker" }`, but those transports are not the default package runtime.
85
87
 
86
88
  Runtime options may also carry app identity facts:
87
89
 
@@ -128,4 +130,4 @@ pnpm --filter opentray example:mediaQuery
128
130
  pnpm --filter opentray example:debug-runtime-lynx -- --bundle packages/cli/assets/lynx-review/main.lynx.bundle
129
131
  ```
130
132
 
131
- The example matrix stages the generated Node runtime artifact before `first-app` and `visible-binding`, skips unsupported or missing native extension carrier artifacts with an explicit reason, and labels contributor-only extension rows as `extension-debug-runtime` coverage. The first-app and visible-binding examples exercise the default package runtime on macOS and Windows. The debug-runtime examples exercise the contributor-only source-tree transport for extension and panel iteration. The public API they demonstrate is tray-first: application code creates trays directly and treats background/service lifecycle as application-owned.
133
+ The example matrix stages the generated Node runtime artifact before `visible-binding`, warms the broker binary before `first-app`, skips unsupported or missing native extension carrier artifacts with an explicit reason, and labels contributor-only extension rows as `extension-debug-runtime` coverage. The first-app example exercises the default package runtime. The visible-binding example is an explicit diagnostic row. The debug-runtime examples exercise the contributor-only source-tree transport for extension and panel iteration. The public API they demonstrate is tray-first: application code creates trays directly and treats background/service lifecycle as application-owned.
package/dist/index.mjs CHANGED
@@ -768,7 +768,7 @@ const createTray = async (options, runtimeOptions = {}) => {
768
768
  ...runtimeOptions.appId === void 0 ? {} : { appId: runtimeOptions.appId },
769
769
  ...runtimeOptions.appName === void 0 ? {} : { appName: runtimeOptions.appName }
770
770
  };
771
- const runtime = runtimeOptions.runtime ?? "visible-binding";
771
+ const runtime = runtimeOptions.runtime ?? "local-broker";
772
772
  return createClient(runtime === "local-broker" ? await connectLocalBroker(runtimeOptions) : await createRuntimeBindingTransport({
773
773
  ...bindingTransportOptions,
774
774
  kind: runtime === "headless-binding" ? "headless" : "visible"
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["PROTOCOL_VERSION","createBrokerEndpointIdentity","normalizeAppIdentityField","formatWindowsPipeName","formatUnixSocketPath","PROTOCOL_VERSION"],"sources":["../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/sdk.ts"],"sourcesContent":["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\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 path: string;\n mountId?: string;\n}\n\nexport interface TrayExtensionMountSpec {\n name?: string;\n path?: string;\n mountId?: string;\n}\n\nexport interface TrayExtensionContext {\n readonly name: string;\n readonly path: string;\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 path: string;\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 response = await transport.request({\n type: \"load-ext\",\n requestId,\n appId,\n name: options.name,\n path: options.path,\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 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 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 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 path = mount.path ?? extension.path;\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 loadPromise = tray\n .loadExtension({ name, path, mountId })\n .catch((error: unknown) => {\n loadPromise = undefined;\n throw error;\n });\n }\n await loadPromise;\n };\n\n return {\n name,\n path,\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","export type BrokerPackageOs = \"darwin\" | \"linux\" | \"windows\";\nexport type BrokerArch = \"arm64\" | \"x64\";\n\nexport interface BrokerNativeTarget {\n packageName: string;\n binaryRelativePath: string;\n}\n\nexport const resolveBrokerNativeTarget = (\n platform: string = process.platform,\n arch: string = process.arch,\n): BrokerNativeTarget => {\n const packageOs = platformToPackageOs(platform);\n const nativeArch = normalizeArch(arch);\n return {\n packageName: `@opentray/${packageOs}-${nativeArch}`,\n binaryRelativePath: `bin/${packageOs === \"windows\" ? \"opentray.exe\" : \"opentray\"}`,\n };\n};\n\nconst platformToPackageOs = (platform: string): BrokerPackageOs => {\n switch (platform) {\n case \"darwin\":\n case \"linux\":\n return platform;\n case \"win32\":\n return \"windows\";\n default:\n throw new MissingPlatformBrokerBinaryError(\n `unsupported OpenTray broker platform: ${platform}`,\n platform,\n process.arch,\n );\n }\n};\n\nconst normalizeArch = (arch: string): BrokerArch => {\n switch (arch) {\n case \"arm64\":\n case \"x64\":\n return arch;\n default:\n throw new MissingPlatformBrokerBinaryError(\n `unsupported OpenTray broker architecture: ${arch}`,\n process.platform,\n arch,\n );\n }\n};\n\nexport class MissingPlatformBrokerBinaryError extends Error {\n readonly code = \"OPENTRAY_MISSING_PLATFORM_BROKER_BINARY\";\n readonly platform: string;\n readonly arch: string;\n readonly packageName: string | undefined;\n readonly binaryPath: string | undefined;\n\n constructor(\n message: string,\n platform: string,\n arch: string,\n options: {\n packageName?: string;\n binaryPath?: string;\n cause?: unknown;\n } = {},\n ) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = \"MissingPlatformBrokerBinaryError\";\n this.platform = platform;\n this.arch = arch;\n this.packageName = options.packageName;\n this.binaryPath = options.binaryPath;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn } from \"node:child_process\";\n\nimport type { DaemonPaths } from \"./paths\";\nimport {\n MissingPlatformBrokerBinaryError,\n resolveBrokerNativeTarget,\n} from \"./native-target\";\n\nexport interface BrokerCommand {\n command: string;\n args: string[];\n cwd?: string;\n}\n\nconst sourceUrl = import.meta.url;\n\nexport interface ResolveBrokerCommandOptions {\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n arch?: string;\n sourceDir?: string;\n findWorkspaceRoot?: (start: string) => Promise<string | undefined>;\n ensureDevBrokerBinary?: (workspaceRoot: string) => Promise<string>;\n}\n\nexport const resolveBrokerCommand = async (\n paths: DaemonPaths,\n options: ResolveBrokerCommandOptions = {}\n): Promise<BrokerCommand> => {\n const env = options.env ?? process.env;\n const explicit = env.OPENTRAY_BROKER_BIN;\n if (explicit !== undefined && explicit.length > 0) {\n return commandForBinary(explicit, paths);\n }\n\n const sourceDir = options.sourceDir ?? dirname(fileURLToPath(sourceUrl));\n const workspaceRoot = await (options.findWorkspaceRoot ?? findWorkspaceRoot)(\n sourceDir\n );\n if (workspaceRoot !== undefined) {\n const binary = await (\n options.ensureDevBrokerBinary ?? ensureDevBrokerBinary\n )(workspaceRoot);\n return commandForBinary(binary, paths, workspaceRoot);\n }\n\n const platform = options.platform ?? process.platform;\n const arch = options.arch ?? process.arch;\n const target = resolveBrokerNativeTarget(platform, arch);\n throw new MissingPlatformBrokerBinaryError(\n `unable to resolve OpenTray debug broker binary for ${platform}/${arch}; run from the source workspace or set OPENTRAY_BROKER_BIN`,\n platform,\n arch,\n { packageName: target.packageName }\n );\n};\n\nconst commandForBinary = (\n binary: string,\n paths: DaemonPaths,\n cwd?: string\n): 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 (\n start: string\n): 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): string =>\n join(\n workspaceRoot,\n \"target\",\n \"debug\",\n platform === \"win32\" ? \"opentray.exe\" : \"opentray\"\n );\n\nexport const terminateWorkspaceDevBrokerProcess = async (\n workspaceRoot: string,\n platform: NodeJS.Platform = process.platform\n): Promise<void> => {\n if (platform !== \"win32\") {\n return;\n }\n await terminateWindowsProcessByExecutable(\n resolveDevBrokerBinaryPath(workspaceRoot, platform)\n );\n};\n\nconst ensureDevBrokerBinary = async (\n workspaceRoot: string\n): Promise<string> => {\n const binary = resolveDevBrokerBinaryPath(workspaceRoot);\n await terminateWorkspaceDevBrokerProcess(workspaceRoot);\n await runCargoBuild(workspaceRoot);\n return binary;\n};\n\nconst runCargoBuild = (workspaceRoot: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const child = spawn(\"cargo\", [\"build\", \"-p\", \"opentray-bin\"], {\n cwd: workspaceRoot,\n stdio:\n process.env.OPENTRAY_BROKER_BUILD_LOGS === \"1\" ? \"inherit\" : \"ignore\",\n });\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(\n new Error(\n `cargo build -p opentray-bin failed with code ${code ?? \"unknown\"}`\n )\n );\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 terminateWindowsProcessByExecutable = (binary: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const script = String.raw`\n$ErrorActionPreference = 'Stop'\n$target = [System.IO.Path]::GetFullPath(${powerShellString(binary)})\n$processes = @(Get-CimInstance Win32_Process -Filter \"Name = 'opentray.exe'\" | Where-Object {\n $_.ExecutablePath -and ([System.IO.Path]::GetFullPath($_.ExecutablePath) -ieq $target)\n})\nforeach ($process in $processes) {\n Stop-Process -Id $process.ProcessId -Force -ErrorAction Stop\n}\nforeach ($process in $processes) {\n Wait-Process -Id $process.ProcessId -Timeout 5 -ErrorAction SilentlyContinue\n}\n`;\n const child = spawn(\n \"powershell.exe\",\n [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-ExecutionPolicy\",\n \"Bypass\",\n \"-Command\",\n script,\n ],\n { stdio: [\"ignore\", \"ignore\", \"pipe\"] }\n );\n let stderr = \"\";\n child.stderr?.on(\"data\", (chunk: Buffer | string) => {\n stderr += String(chunk);\n });\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(\n new Error(\n `failed to stop running dev broker before cargo build: ${\n stderr.trim() || code\n }`\n )\n );\n });\n });\n\nconst powerShellString = (value: string): string =>\n `'${value.replace(/'/g, \"''\")}'`;\n\nconst isNodeError = (error: unknown): error is NodeJS.ErrnoException =>\n error instanceof Error && \"code\" in error;\n","import { constants } from \"node:fs\";\nimport { mkdir, open, readFile, rm, unlink, writeFile } from \"node:fs/promises\";\nimport { spawn } from \"node:child_process\";\n\nimport { resolveBrokerCommand } from \"./broker-command\";\nimport type { DaemonPaths } from \"./paths\";\n\nconst DAEMON_STDIO_ENV = \"OPENTRAY_DAEMON_STDIO\";\n\nexport type DaemonStartResult =\n | { status: \"started\"; pid: number; paths: DaemonPaths }\n | { status: \"already-running\"; pid: number; paths: DaemonPaths };\n\nexport type DaemonStopResult =\n | { status: \"stopped\"; pid: number; paths: DaemonPaths }\n | { status: \"not-running\"; paths: DaemonPaths };\n\nexport type DaemonInspectResult =\n | { status: \"running\"; pid: number; paths: DaemonPaths }\n | { status: \"not-running\"; paths: DaemonPaths; stalePid?: number };\n\nexport interface DaemonDriver {\n isAlive(pid: number): Promise<boolean>;\n spawnBroker(paths: DaemonPaths): Promise<number>;\n stop(pid: number): Promise<void>;\n}\n\nexport interface StartDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n lockTimeoutMs?: number;\n}\n\nexport interface StopDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n}\n\nexport interface InspectDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n}\n\nexport const createNodeDaemonDriver = (\n cliEntrypoint: string\n): DaemonDriver => ({\n async isAlive(pid) {\n return isProcessAlive(pid);\n },\n async spawnBroker(paths) {\n const broker = await resolveBrokerCommand(paths);\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 = (\n value: string | undefined\n): \"ignore\" | \"inherit\" => {\n return value === \"inherit\" ? \"inherit\" : \"ignore\";\n};\n\nexport const startDaemon = async ({\n paths,\n driver,\n lockTimeoutMs = 1_000,\n}: StartDaemonOptions): Promise<DaemonStartResult> => {\n await mkdir(paths.runtimeDir, { recursive: true });\n\n const lock = await acquireLock(paths.lockFile, lockTimeoutMs);\n try {\n const existingPid = await readPid(paths.pidFile);\n if (existingPid !== undefined && (await driver.isAlive(existingPid))) {\n return { status: \"already-running\", pid: existingPid, paths };\n }\n\n await cleanupRuntimeFiles(paths);\n const pid = await driver.spawnBroker(paths);\n if (!Number.isInteger(pid) || pid <= 0) {\n throw new Error(\"daemon broker process did not expose a valid pid\");\n }\n await writeFile(paths.pidFile, `${pid}\\n`, \"utf8\");\n await waitForReadyFile(paths.readyFile, driver, pid);\n return { status: \"started\", pid, paths };\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 await waitUntilStopped(driver, pid);\n await cleanupRuntimeFiles(paths);\n return { status: \"stopped\", pid, paths };\n};\n\nexport const restartDaemon = async (\n options: StartDaemonOptions\n): 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 (\n driver: DaemonDriver,\n pid: number\n): Promise<void> => {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (!(await driver.isAlive(pid))) {\n return;\n }\n await sleep(50);\n }\n};\n\nconst waitForReadyFile = async (\n readyFile: string,\n driver: DaemonDriver,\n pid: number\n): Promise<void> => {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n try {\n await readFile(readyFile, \"utf8\");\n return;\n } catch (error) {\n if (!isNodeError(error) || error.code !== \"ENOENT\") {\n throw error;\n }\n if (!(await driver.isAlive(pid))) {\n throw new Error(\n `daemon broker exited before readiness: pid=${pid}; readyFile=${readyFile}; set ${DAEMON_STDIO_ENV}=inherit to inspect broker stderr`\n );\n }\n await sleep(50);\n }\n }\n\n throw new Error(`timed out waiting for daemon readiness: ${readyFile}`);\n};\n\nconst acquireLock = async (\n lockFile: string,\n timeoutMs: number\n): Promise<{\n release(): Promise<void>;\n}> => {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() <= deadline) {\n try {\n const handle = await open(\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> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst isNodeError = (error: unknown): error is NodeJS.ErrnoException =>\n error instanceof Error && \"code\" in error;\n","import { readFile } from \"node:fs/promises\";\n\nexport const readPackageVersion = async (packageJsonUrl: URL): Promise<string> => {\n const value: unknown = JSON.parse(await readFile(packageJsonUrl, \"utf8\"));\n if (!isPackageJsonWithVersion(value)) {\n throw new Error(`package.json is missing a string version: ${packageJsonUrl.href}`);\n }\n\n return value.version;\n};\n\nconst isPackageJsonWithVersion = (value: unknown): value is { version: string } =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"version\" in value &&\n typeof value.version === \"string\";\n","import {\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 parseServerFrame,\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}\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 if (autoStart) {\n const cliEntrypoint = options.cliEntrypoint ?? resolveCliEntrypoint();\n const driver =\n options.daemonDriver ?? createNodeDaemonDriver(cliEntrypoint);\n await startDaemon({ paths, driver });\n }\n const socket = await connectSocket(endpoint);\n const connection = new LocalBrokerConnection(socket, endpoint, callerLabel);\n\n await connection.init(\n clientVersion,\n options.protocolVersion ?? PROTOCOL_VERSION\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(clientVersion: string, protocolVersion: number): 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 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 { TrayOptions } from \"@opentray/spec\";\n\nimport { createClient, type EventfulTrayHandle } from \"./client\";\nimport { connectLocalBroker } from \"./local-broker\";\nimport type { OpenTrayRuntimeBinding } from \"./native-runtime\";\nimport { createRuntimeBindingTransport } from \"./runtime-binding-transport\";\n\nexport type OpenTrayRuntimeMode =\n | \"visible-binding\"\n | \"local-broker\"\n | \"headless-binding\";\n\nexport interface OpenTrayRuntimeOptions {\n runtime?: OpenTrayRuntimeMode;\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 binding?: OpenTrayRuntimeBinding;\n}\n\nexport const createTray = async (\n options: TrayOptions,\n runtimeOptions: OpenTrayRuntimeOptions = {}\n): Promise<EventfulTrayHandle> => {\n const bindingTransportOptions = {\n ...(runtimeOptions.binding === undefined\n ? {}\n : { binding: runtimeOptions.binding }),\n ...(runtimeOptions.packageVersion === undefined\n ? {}\n : { packageVersion: runtimeOptions.packageVersion }),\n ...(runtimeOptions.clientVersion === undefined\n ? {}\n : { clientVersion: runtimeOptions.clientVersion }),\n ...(runtimeOptions.protocolVersion === undefined\n ? {}\n : { protocolVersion: runtimeOptions.protocolVersion }),\n ...(runtimeOptions.appId === undefined\n ? {}\n : { appId: runtimeOptions.appId }),\n ...(runtimeOptions.appName === undefined\n ? {}\n : { appName: runtimeOptions.appName }),\n };\n const runtime = runtimeOptions.runtime ?? \"visible-binding\";\n const connection =\n runtime === \"local-broker\"\n ? await connectLocalBroker(runtimeOptions)\n : await createRuntimeBindingTransport({\n ...bindingTransportOptions,\n kind: runtime === \"headless-binding\" ? \"headless\" : \"visible\",\n });\n return createClient(connection).createTray(options);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["PROTOCOL_VERSION","createBrokerEndpointIdentity","normalizeAppIdentityField","formatWindowsPipeName","formatUnixSocketPath","PROTOCOL_VERSION"],"sources":["../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/sdk.ts"],"sourcesContent":["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\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 path: string;\n mountId?: string;\n}\n\nexport interface TrayExtensionMountSpec {\n name?: string;\n path?: string;\n mountId?: string;\n}\n\nexport interface TrayExtensionContext {\n readonly name: string;\n readonly path: string;\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 path: string;\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 response = await transport.request({\n type: \"load-ext\",\n requestId,\n appId,\n name: options.name,\n path: options.path,\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 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 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 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 path = mount.path ?? extension.path;\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 loadPromise = tray\n .loadExtension({ name, path, mountId })\n .catch((error: unknown) => {\n loadPromise = undefined;\n throw error;\n });\n }\n await loadPromise;\n };\n\n return {\n name,\n path,\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","export type BrokerPackageOs = \"darwin\" | \"linux\" | \"windows\";\nexport type BrokerArch = \"arm64\" | \"x64\";\n\nexport interface BrokerNativeTarget {\n packageName: string;\n binaryRelativePath: string;\n}\n\nexport const resolveBrokerNativeTarget = (\n platform: string = process.platform,\n arch: string = process.arch,\n): BrokerNativeTarget => {\n const packageOs = platformToPackageOs(platform);\n const nativeArch = normalizeArch(arch);\n return {\n packageName: `@opentray/${packageOs}-${nativeArch}`,\n binaryRelativePath: `bin/${packageOs === \"windows\" ? \"opentray.exe\" : \"opentray\"}`,\n };\n};\n\nconst platformToPackageOs = (platform: string): BrokerPackageOs => {\n switch (platform) {\n case \"darwin\":\n case \"linux\":\n return platform;\n case \"win32\":\n return \"windows\";\n default:\n throw new MissingPlatformBrokerBinaryError(\n `unsupported OpenTray broker platform: ${platform}`,\n platform,\n process.arch,\n );\n }\n};\n\nconst normalizeArch = (arch: string): BrokerArch => {\n switch (arch) {\n case \"arm64\":\n case \"x64\":\n return arch;\n default:\n throw new MissingPlatformBrokerBinaryError(\n `unsupported OpenTray broker architecture: ${arch}`,\n process.platform,\n arch,\n );\n }\n};\n\nexport class MissingPlatformBrokerBinaryError extends Error {\n readonly code = \"OPENTRAY_MISSING_PLATFORM_BROKER_BINARY\";\n readonly platform: string;\n readonly arch: string;\n readonly packageName: string | undefined;\n readonly binaryPath: string | undefined;\n\n constructor(\n message: string,\n platform: string,\n arch: string,\n options: {\n packageName?: string;\n binaryPath?: string;\n cause?: unknown;\n } = {},\n ) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = \"MissingPlatformBrokerBinaryError\";\n this.platform = platform;\n this.arch = arch;\n this.packageName = options.packageName;\n this.binaryPath = options.binaryPath;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn } from \"node:child_process\";\n\nimport type { DaemonPaths } from \"./paths\";\nimport {\n MissingPlatformBrokerBinaryError,\n resolveBrokerNativeTarget,\n} from \"./native-target\";\n\nexport interface BrokerCommand {\n command: string;\n args: string[];\n cwd?: string;\n}\n\nconst sourceUrl = import.meta.url;\n\nexport interface ResolveBrokerCommandOptions {\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n arch?: string;\n sourceDir?: string;\n findWorkspaceRoot?: (start: string) => Promise<string | undefined>;\n ensureDevBrokerBinary?: (workspaceRoot: string) => Promise<string>;\n}\n\nexport const resolveBrokerCommand = async (\n paths: DaemonPaths,\n options: ResolveBrokerCommandOptions = {}\n): Promise<BrokerCommand> => {\n const env = options.env ?? process.env;\n const explicit = env.OPENTRAY_BROKER_BIN;\n if (explicit !== undefined && explicit.length > 0) {\n return commandForBinary(explicit, paths);\n }\n\n const sourceDir = options.sourceDir ?? dirname(fileURLToPath(sourceUrl));\n const workspaceRoot = await (options.findWorkspaceRoot ?? findWorkspaceRoot)(\n sourceDir\n );\n if (workspaceRoot !== undefined) {\n const binary = await (\n options.ensureDevBrokerBinary ?? ensureDevBrokerBinary\n )(workspaceRoot);\n return commandForBinary(binary, paths, workspaceRoot);\n }\n\n const platform = options.platform ?? process.platform;\n const arch = options.arch ?? process.arch;\n const target = resolveBrokerNativeTarget(platform, arch);\n throw new MissingPlatformBrokerBinaryError(\n `unable to resolve OpenTray debug broker binary for ${platform}/${arch}; run from the source workspace or set OPENTRAY_BROKER_BIN`,\n platform,\n arch,\n { packageName: target.packageName }\n );\n};\n\nconst commandForBinary = (\n binary: string,\n paths: DaemonPaths,\n cwd?: string\n): 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 (\n start: string\n): 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): string =>\n join(\n workspaceRoot,\n \"target\",\n \"debug\",\n platform === \"win32\" ? \"opentray.exe\" : \"opentray\"\n );\n\nexport const terminateWorkspaceDevBrokerProcess = async (\n workspaceRoot: string,\n platform: NodeJS.Platform = process.platform\n): Promise<void> => {\n if (platform !== \"win32\") {\n return;\n }\n await terminateWindowsProcessByExecutable(\n resolveDevBrokerBinaryPath(workspaceRoot, platform)\n );\n};\n\nconst ensureDevBrokerBinary = async (\n workspaceRoot: string\n): Promise<string> => {\n const binary = resolveDevBrokerBinaryPath(workspaceRoot);\n await terminateWorkspaceDevBrokerProcess(workspaceRoot);\n await runCargoBuild(workspaceRoot);\n return binary;\n};\n\nconst runCargoBuild = (workspaceRoot: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const child = spawn(\"cargo\", [\"build\", \"-p\", \"opentray-bin\"], {\n cwd: workspaceRoot,\n stdio:\n process.env.OPENTRAY_BROKER_BUILD_LOGS === \"1\" ? \"inherit\" : \"ignore\",\n });\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(\n new Error(\n `cargo build -p opentray-bin failed with code ${code ?? \"unknown\"}`\n )\n );\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 terminateWindowsProcessByExecutable = (binary: string): Promise<void> =>\n new Promise((resolve, reject) => {\n const script = String.raw`\n$ErrorActionPreference = 'Stop'\n$target = [System.IO.Path]::GetFullPath(${powerShellString(binary)})\n$processes = @(Get-CimInstance Win32_Process -Filter \"Name = 'opentray.exe'\" | Where-Object {\n $_.ExecutablePath -and ([System.IO.Path]::GetFullPath($_.ExecutablePath) -ieq $target)\n})\nforeach ($process in $processes) {\n Stop-Process -Id $process.ProcessId -Force -ErrorAction Stop\n}\nforeach ($process in $processes) {\n Wait-Process -Id $process.ProcessId -Timeout 5 -ErrorAction SilentlyContinue\n}\n`;\n const child = spawn(\n \"powershell.exe\",\n [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-ExecutionPolicy\",\n \"Bypass\",\n \"-Command\",\n script,\n ],\n { stdio: [\"ignore\", \"ignore\", \"pipe\"] }\n );\n let stderr = \"\";\n child.stderr?.on(\"data\", (chunk: Buffer | string) => {\n stderr += String(chunk);\n });\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(\n new Error(\n `failed to stop running dev broker before cargo build: ${\n stderr.trim() || code\n }`\n )\n );\n });\n });\n\nconst powerShellString = (value: string): string =>\n `'${value.replace(/'/g, \"''\")}'`;\n\nconst isNodeError = (error: unknown): error is NodeJS.ErrnoException =>\n error instanceof Error && \"code\" in error;\n","import { constants } from \"node:fs\";\nimport { mkdir, open, readFile, rm, unlink, writeFile } from \"node:fs/promises\";\nimport { spawn } from \"node:child_process\";\n\nimport { resolveBrokerCommand } from \"./broker-command\";\nimport type { DaemonPaths } from \"./paths\";\n\nconst DAEMON_STDIO_ENV = \"OPENTRAY_DAEMON_STDIO\";\n\nexport type DaemonStartResult =\n | { status: \"started\"; pid: number; paths: DaemonPaths }\n | { status: \"already-running\"; pid: number; paths: DaemonPaths };\n\nexport type DaemonStopResult =\n | { status: \"stopped\"; pid: number; paths: DaemonPaths }\n | { status: \"not-running\"; paths: DaemonPaths };\n\nexport type DaemonInspectResult =\n | { status: \"running\"; pid: number; paths: DaemonPaths }\n | { status: \"not-running\"; paths: DaemonPaths; stalePid?: number };\n\nexport interface DaemonDriver {\n isAlive(pid: number): Promise<boolean>;\n spawnBroker(paths: DaemonPaths): Promise<number>;\n stop(pid: number): Promise<void>;\n}\n\nexport interface StartDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n lockTimeoutMs?: number;\n}\n\nexport interface StopDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n}\n\nexport interface InspectDaemonOptions {\n paths: DaemonPaths;\n driver: DaemonDriver;\n}\n\nexport const createNodeDaemonDriver = (\n cliEntrypoint: string\n): DaemonDriver => ({\n async isAlive(pid) {\n return isProcessAlive(pid);\n },\n async spawnBroker(paths) {\n const broker = await resolveBrokerCommand(paths);\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 = (\n value: string | undefined\n): \"ignore\" | \"inherit\" => {\n return value === \"inherit\" ? \"inherit\" : \"ignore\";\n};\n\nexport const startDaemon = async ({\n paths,\n driver,\n lockTimeoutMs = 1_000,\n}: StartDaemonOptions): Promise<DaemonStartResult> => {\n await mkdir(paths.runtimeDir, { recursive: true });\n\n const lock = await acquireLock(paths.lockFile, lockTimeoutMs);\n try {\n const existingPid = await readPid(paths.pidFile);\n if (existingPid !== undefined && (await driver.isAlive(existingPid))) {\n return { status: \"already-running\", pid: existingPid, paths };\n }\n\n await cleanupRuntimeFiles(paths);\n const pid = await driver.spawnBroker(paths);\n if (!Number.isInteger(pid) || pid <= 0) {\n throw new Error(\"daemon broker process did not expose a valid pid\");\n }\n await writeFile(paths.pidFile, `${pid}\\n`, \"utf8\");\n await waitForReadyFile(paths.readyFile, driver, pid);\n return { status: \"started\", pid, paths };\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 await waitUntilStopped(driver, pid);\n await cleanupRuntimeFiles(paths);\n return { status: \"stopped\", pid, paths };\n};\n\nexport const restartDaemon = async (\n options: StartDaemonOptions\n): 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 (\n driver: DaemonDriver,\n pid: number\n): Promise<void> => {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (!(await driver.isAlive(pid))) {\n return;\n }\n await sleep(50);\n }\n};\n\nconst waitForReadyFile = async (\n readyFile: string,\n driver: DaemonDriver,\n pid: number\n): Promise<void> => {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n try {\n await readFile(readyFile, \"utf8\");\n return;\n } catch (error) {\n if (!isNodeError(error) || error.code !== \"ENOENT\") {\n throw error;\n }\n if (!(await driver.isAlive(pid))) {\n throw new Error(\n `daemon broker exited before readiness: pid=${pid}; readyFile=${readyFile}; set ${DAEMON_STDIO_ENV}=inherit to inspect broker stderr`\n );\n }\n await sleep(50);\n }\n }\n\n throw new Error(`timed out waiting for daemon readiness: ${readyFile}`);\n};\n\nconst acquireLock = async (\n lockFile: string,\n timeoutMs: number\n): Promise<{\n release(): Promise<void>;\n}> => {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() <= deadline) {\n try {\n const handle = await open(\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> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst isNodeError = (error: unknown): error is NodeJS.ErrnoException =>\n error instanceof Error && \"code\" in error;\n","import { readFile } from \"node:fs/promises\";\n\nexport const readPackageVersion = async (packageJsonUrl: URL): Promise<string> => {\n const value: unknown = JSON.parse(await readFile(packageJsonUrl, \"utf8\"));\n if (!isPackageJsonWithVersion(value)) {\n throw new Error(`package.json is missing a string version: ${packageJsonUrl.href}`);\n }\n\n return value.version;\n};\n\nconst isPackageJsonWithVersion = (value: unknown): value is { version: string } =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"version\" in value &&\n typeof value.version === \"string\";\n","import {\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 parseServerFrame,\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}\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 if (autoStart) {\n const cliEntrypoint = options.cliEntrypoint ?? resolveCliEntrypoint();\n const driver =\n options.daemonDriver ?? createNodeDaemonDriver(cliEntrypoint);\n await startDaemon({ paths, driver });\n }\n const socket = await connectSocket(endpoint);\n const connection = new LocalBrokerConnection(socket, endpoint, callerLabel);\n\n await connection.init(\n clientVersion,\n options.protocolVersion ?? PROTOCOL_VERSION\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(clientVersion: string, protocolVersion: number): 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 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 { TrayOptions } from \"@opentray/spec\";\n\nimport { createClient, type EventfulTrayHandle } from \"./client\";\nimport { connectLocalBroker } from \"./local-broker\";\nimport type { OpenTrayRuntimeBinding } from \"./native-runtime\";\nimport { createRuntimeBindingTransport } from \"./runtime-binding-transport\";\n\nexport type OpenTrayRuntimeMode =\n | \"visible-binding\"\n | \"local-broker\"\n | \"headless-binding\";\n\nexport interface OpenTrayRuntimeOptions {\n runtime?: OpenTrayRuntimeMode;\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 binding?: OpenTrayRuntimeBinding;\n}\n\nexport const createTray = async (\n options: TrayOptions,\n runtimeOptions: OpenTrayRuntimeOptions = {}\n): Promise<EventfulTrayHandle> => {\n const bindingTransportOptions = {\n ...(runtimeOptions.binding === undefined\n ? {}\n : { binding: runtimeOptions.binding }),\n ...(runtimeOptions.packageVersion === undefined\n ? {}\n : { packageVersion: runtimeOptions.packageVersion }),\n ...(runtimeOptions.clientVersion === undefined\n ? {}\n : { clientVersion: runtimeOptions.clientVersion }),\n ...(runtimeOptions.protocolVersion === undefined\n ? {}\n : { protocolVersion: runtimeOptions.protocolVersion }),\n ...(runtimeOptions.appId === undefined\n ? {}\n : { appId: runtimeOptions.appId }),\n ...(runtimeOptions.appName === undefined\n ? {}\n : { appName: runtimeOptions.appName }),\n };\n const runtime = runtimeOptions.runtime ?? \"local-broker\";\n const connection =\n runtime === \"local-broker\"\n ? await connectLocalBroker(runtimeOptions)\n : await createRuntimeBindingTransport({\n ...bindingTransportOptions,\n kind: runtime === \"headless-binding\" ? \"headless\" : \"visible\",\n });\n return createClient(connection).createTray(options);\n};\n"],"mappings":"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"}
package/dist/node.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- import { a as ResolveRuntimeBindingOptions, c as resolveInstalledRuntimeBindingPath, d as EventfulTrayHandle, i as OpenTrayVisibleRuntimeHostOptions, l as resolveRuntimeNativeTarget, m as OpenTrayConnection, n as OpenTrayRuntimeBinding, o as RuntimeNativeTarget, r as OpenTrayRuntimeBindingInfo, s as loadOpenTrayRuntimeBinding, t as MissingPlatformRuntimeBindingError } from "./native-runtime-Cn8BaffH.mjs";
2
- import { TrayOptions } from "@opentray/spec";
1
+ import { a as ResolveRuntimeBindingOptions, c as resolveInstalledRuntimeBindingPath, i as OpenTrayVisibleRuntimeHostOptions, l as resolveRuntimeNativeTarget, m as OpenTrayConnection, n as OpenTrayRuntimeBinding, o as RuntimeNativeTarget, r as OpenTrayRuntimeBindingInfo, s as loadOpenTrayRuntimeBinding, t as MissingPlatformRuntimeBindingError } from "./native-runtime-Cn8BaffH.mjs";
3
2
 
4
3
  //#region src/runtime-binding-transport.d.ts
5
4
  type RuntimeBindingTransportKind = "visible" | "headless";
@@ -34,37 +33,5 @@ declare const runVisibleRuntimeHost: ({
34
33
  ...hostOptions
35
34
  }?: RunVisibleRuntimeHostOptions) => Promise<void>;
36
35
  //#endregion
37
- //#region src/node-app.d.ts
38
- interface RunTrayAppOptions {
39
- /** Runtime package version used for host state partitioning and diagnostics. */
40
- readonly packageVersion?: string;
41
- /** Client version reported to the runtime host handshake. */
42
- readonly clientVersion?: string;
43
- /** Protocol version reported to the runtime host handshake. */
44
- readonly protocolVersion?: number;
45
- /** App identity for diagnostics and runtime isolation. */
46
- readonly appId?: string;
47
- /** Human-readable app identity for diagnostics. */
48
- readonly appName?: string;
49
- /** Optional finite runtime window for examples and smoke tests. */
50
- readonly autoExitAfterMs?: number;
51
- /** Delay before the worker callback runs, giving the visible host time to boot. */
52
- readonly startupDelayMs?: number;
53
- }
54
- interface TrayAppContext {
55
- /** Create a tray in the app worker while the helper owns the visible host loop. */
56
- createTray(options: TrayOptions): Promise<EventfulTrayHandle>;
57
- }
58
- /**
59
- * First-app entrypoint executed inside the app worker.
60
- *
61
- * Keep the callback self-contained. Imports needed by the callback should be
62
- * dynamic imports inside the callback because the helper runs it in a worker.
63
- */
64
- type TrayAppMain = (context: TrayAppContext) => void | Promise<void>;
65
- /** Run a self-contained tray app without exposing host-thread choreography. */
66
- declare const runTrayApp: (main: TrayAppMain, options?: RunTrayAppOptions) => Promise<void>;
67
- declare const createTrayAppWorkerSource: () => string;
68
- //#endregion
69
- export { type CreateRuntimeBindingTransportOptions, MissingPlatformRuntimeBindingError, type OpenTrayRuntimeBinding, type OpenTrayRuntimeBindingInfo, type OpenTrayVisibleRuntimeHostOptions, type ResolveRuntimeBindingOptions, type RunTrayAppOptions, type RunVisibleRuntimeHostOptions, type RuntimeNativeTarget, type TrayAppContext, type TrayAppMain, createRuntimeBindingTransport, createTrayAppWorkerSource, loadOpenTrayRuntimeBinding, resolveInstalledRuntimeBindingPath, resolveRuntimeNativeTarget, runTrayApp, runVisibleRuntimeHost };
36
+ export { type CreateRuntimeBindingTransportOptions, MissingPlatformRuntimeBindingError, type OpenTrayRuntimeBinding, type OpenTrayRuntimeBindingInfo, type OpenTrayVisibleRuntimeHostOptions, type ResolveRuntimeBindingOptions, type RunVisibleRuntimeHostOptions, type RuntimeNativeTarget, createRuntimeBindingTransport, loadOpenTrayRuntimeBinding, resolveInstalledRuntimeBindingPath, resolveRuntimeNativeTarget, runVisibleRuntimeHost };
70
37
  //# sourceMappingURL=node.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.mts","names":[],"sources":["../src/runtime-binding-transport.ts","../src/node-host.ts","../src/node-app.ts"],"mappings":";;;;KAgBY,2BAAA;AAAA,UAEK,oCAAA;EAAA,SACN,IAAA,GAAO,2BAAA;EAAA,SACP,OAAA,GAAU,sBAAsB;EAAA,SAChC,cAAA;EAAA,SACA,aAAA;EAAA,SACA,eAAA;EAAA,SACA,KAAA;EAAA,SACA,OAAA;AAAA;AAAA,cAGE,6BAAA;EAAuC,OAAA;EAAA,cAAA;EAAA,aAAA;EAAA,eAAA;EAAA,KAAA;EAAA,OAAA;EAAA;AAAA,IAQjD,oCAAA,KAA4C,OAAA,CAAQ,kBAAA;;;;UC7BtC,4BAAA,SACP,4BAAA,EACN,iCAAiC;ADOrC;AAAA,cCJa,qBAAA;EAA+B,QAAA;EAAA,IAAA;EAAA,kBAAA;EAAA,YAAA;EAAA,GAAA;AAAA,IAMzC,4BAAA,KAAoC,OAAA;;;UCZtB,iBAAA;;WAEN,cAAA;EFQ4B;EAAA,SEN5B,aAAA;EFM4B;EAAA,SEJ5B,eAAA;EFMM;EAAA,SEJN,KAAA;;WAEA,OAAA;EFGA;EAAA,SEDA,eAAA;EFEA;EAAA,SEAA,cAAA;AAAA;AAAA,UAGM,cAAA;EFAN;EEET,UAAA,CAAW,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,kBAAA;AAAA;;AFA1B;AAGlB;;;;KEMY,WAAA,IAAe,OAAA,EAAS,cAAA,YAA0B,OAAO;;cAgBxD,UAAA,GACX,IAAA,EAAM,WAAA,EACN,OAAA,GAAS,iBAAA,KACR,OAAA;AAAA,cA8CU,yBAAA"}
1
+ {"version":3,"file":"node.d.mts","names":[],"sources":["../src/runtime-binding-transport.ts","../src/node-host.ts"],"mappings":";;;KAgBY,2BAAA;AAAA,UAEK,oCAAA;EAAA,SACN,IAAA,GAAO,2BAAA;EAAA,SACP,OAAA,GAAU,sBAAsB;EAAA,SAChC,cAAA;EAAA,SACA,aAAA;EAAA,SACA,eAAA;EAAA,SACA,KAAA;EAAA,SACA,OAAA;AAAA;AAAA,cAGE,6BAAA;EAAuC,OAAA;EAAA,cAAA;EAAA,aAAA;EAAA,eAAA;EAAA,KAAA;EAAA,OAAA;EAAA;AAAA,IAQjD,oCAAA,KAA4C,OAAA,CAAQ,kBAAA;;;;UC7BtC,4BAAA,SACP,4BAAA,EACN,iCAAiC;;cAGxB,qBAAA;EAA+B,QAAA;EAAA,IAAA;EAAA,kBAAA;EAAA,YAAA;EAAA,GAAA;AAAA,IAMzC,4BAAA,KAAoC,OAAA"}
package/dist/node.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { a as resolveRuntimeNativeTarget, i as resolveInstalledRuntimeBindingPath, n as MissingPlatformRuntimeBindingError, r as loadOpenTrayRuntimeBinding, t as createRuntimeBindingTransport } from "./runtime-binding-transport-UPunusBT.mjs";
2
- import { Worker } from "node:worker_threads";
3
2
  //#region src/node-host.ts
4
3
  /** Run the visible native host loop on the caller-owned Node main thread. */
5
4
  const runVisibleRuntimeHost = async ({ platform, arch, resolvePackageJson, nativeLoader, ...hostOptions } = {}) => {
@@ -13,104 +12,6 @@ const runVisibleRuntimeHost = async ({ platform, arch, resolvePackageJson, nativ
13
12
  binding.runVisibleRuntimeHost(hostOptions);
14
13
  };
15
14
  //#endregion
16
- //#region src/node-app.ts
17
- /** Run a self-contained tray app without exposing host-thread choreography. */
18
- const runTrayApp = async (main, options = {}) => {
19
- if (typeof main !== "function") throw new TypeError("main must be a function");
20
- const worker = new Worker(createTrayAppWorkerSource(), {
21
- eval: true,
22
- workerData: {
23
- mainSource: main.toString(),
24
- sdkUrl: resolveWorkerSdkUrl(),
25
- runtimeOptions: {
26
- ...options.packageVersion === void 0 ? {} : { packageVersion: options.packageVersion },
27
- ...options.clientVersion === void 0 ? {} : { clientVersion: options.clientVersion },
28
- ...options.protocolVersion === void 0 ? {} : { protocolVersion: options.protocolVersion },
29
- ...options.appId === void 0 ? {} : { appId: options.appId },
30
- ...options.appName === void 0 ? {} : { appName: options.appName }
31
- },
32
- startupDelayMs: normalizeDelay(options.startupDelayMs)
33
- }
34
- });
35
- await waitForWorkerOnline(worker);
36
- worker.postMessage("start");
37
- try {
38
- await runVisibleRuntimeHost({
39
- ...options.packageVersion === void 0 ? {} : { packageVersion: options.packageVersion },
40
- ...options.appId === void 0 ? {} : { appId: options.appId },
41
- ...options.appName === void 0 ? {} : { appName: options.appName },
42
- ...options.autoExitAfterMs === void 0 ? {} : { autoExitAfterMs: options.autoExitAfterMs }
43
- });
44
- } finally {
45
- await worker.terminate();
46
- }
47
- };
48
- const createTrayAppWorkerSource = () => `
49
- const { parentPort, workerData } = require("node:worker_threads");
50
-
51
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
52
- const isStartMessage = (value) => value === "start";
53
-
54
- if (parentPort === null) {
55
- throw new Error("OpenTray tray app worker requires a parent port");
56
- }
57
-
58
- import(workerData.sdkUrl)
59
- .then(({ createTray: rawCreateTray }) => {
60
- const createTray = (options) =>
61
- rawCreateTray(options, workerData.runtimeOptions);
62
- const main = eval("(" + workerData.mainSource + ")");
63
-
64
- parentPort.postMessage("online");
65
- parentPort.once("message", async (message) => {
66
- if (!isStartMessage(message)) {
67
- return;
68
- }
69
- if (workerData.startupDelayMs > 0) {
70
- await delay(workerData.startupDelayMs);
71
- }
72
- await main({ createTray });
73
- parentPort.postMessage("done");
74
- });
75
- })
76
- .catch((error) => {
77
- throw error;
78
- });
79
- `;
80
- const normalizeDelay = (value) => {
81
- if (value === void 0) return 250;
82
- if (!Number.isFinite(value) || value < 0) throw new Error(`startupDelayMs must be a non-negative number: ${value}`);
83
- return value;
84
- };
85
- const resolveWorkerSdkUrl = () => import.meta.url.endsWith(".mjs") ? new URL("./sdk.mjs", import.meta.url).href : new URL("./sdk.ts", import.meta.url).href;
86
- const waitForWorkerOnline = async (worker) => new Promise((resolve, reject) => {
87
- const onMessage = (value) => {
88
- if (value === "online") {
89
- cleanup();
90
- resolve();
91
- return;
92
- }
93
- };
94
- const onError = (error) => {
95
- cleanup();
96
- reject(error);
97
- };
98
- const onExit = (code) => {
99
- if (code !== 0) {
100
- cleanup();
101
- reject(/* @__PURE__ */ new Error(`tray app worker exited with code ${code}`));
102
- }
103
- };
104
- const cleanup = () => {
105
- worker.off("message", onMessage);
106
- worker.off("error", onError);
107
- worker.off("exit", onExit);
108
- };
109
- worker.on("message", onMessage);
110
- worker.on("error", onError);
111
- worker.on("exit", onExit);
112
- });
113
- //#endregion
114
- export { MissingPlatformRuntimeBindingError, createRuntimeBindingTransport, createTrayAppWorkerSource, loadOpenTrayRuntimeBinding, resolveInstalledRuntimeBindingPath, resolveRuntimeNativeTarget, runTrayApp, runVisibleRuntimeHost };
15
+ export { MissingPlatformRuntimeBindingError, createRuntimeBindingTransport, loadOpenTrayRuntimeBinding, resolveInstalledRuntimeBindingPath, resolveRuntimeNativeTarget, runVisibleRuntimeHost };
115
16
 
116
17
  //# sourceMappingURL=node.mjs.map
package/dist/node.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.mjs","names":[],"sources":["../src/node-host.ts","../src/node-app.ts"],"sourcesContent":["import {\n loadOpenTrayRuntimeBinding,\n type OpenTrayVisibleRuntimeHostOptions,\n type ResolveRuntimeBindingOptions,\n} from \"./native-runtime\";\n\n/** Options for resolving the native binding and running the visible host loop. */\nexport interface RunVisibleRuntimeHostOptions\n extends ResolveRuntimeBindingOptions,\n OpenTrayVisibleRuntimeHostOptions {}\n\n/** Run the visible native host loop on the caller-owned Node main thread. */\nexport const runVisibleRuntimeHost = async ({\n platform,\n arch,\n resolvePackageJson,\n nativeLoader,\n ...hostOptions\n}: RunVisibleRuntimeHostOptions = {}): Promise<void> => {\n const binding = await loadOpenTrayRuntimeBinding({\n ...(platform === undefined ? {} : { platform }),\n ...(arch === undefined ? {} : { arch }),\n ...(resolvePackageJson === undefined ? {} : { resolvePackageJson }),\n ...(nativeLoader === undefined ? {} : { nativeLoader }),\n });\n if (binding.runVisibleRuntimeHost === undefined) {\n throw new Error(\n \"OpenTray runtime binding does not expose runVisibleRuntimeHost()\"\n );\n }\n binding.runVisibleRuntimeHost(hostOptions);\n};\n\nexport {\n MissingPlatformRuntimeBindingError,\n resolveInstalledRuntimeBindingPath,\n resolveRuntimeNativeTarget,\n loadOpenTrayRuntimeBinding,\n type OpenTrayRuntimeBinding,\n type OpenTrayRuntimeBindingInfo,\n type OpenTrayVisibleRuntimeHostOptions,\n type ResolveRuntimeBindingOptions,\n type RuntimeNativeTarget,\n} from \"./native-runtime\";\nexport {\n createRuntimeBindingTransport,\n type CreateRuntimeBindingTransportOptions,\n} from \"./runtime-binding-transport\";\n","import { Worker } from \"node:worker_threads\";\n\nimport type { EventfulTrayHandle } from \"./client\";\nimport type { TrayOptions } from \"@opentray/spec\";\nimport { runVisibleRuntimeHost } from \"./node-host\";\n\nexport interface RunTrayAppOptions {\n /** Runtime package version used for host state partitioning and diagnostics. */\n readonly packageVersion?: string;\n /** Client version reported to the runtime host handshake. */\n readonly clientVersion?: string;\n /** Protocol version reported to the runtime host handshake. */\n readonly protocolVersion?: number;\n /** App identity for diagnostics and runtime isolation. */\n readonly appId?: string;\n /** Human-readable app identity for diagnostics. */\n readonly appName?: string;\n /** Optional finite runtime window for examples and smoke tests. */\n readonly autoExitAfterMs?: number;\n /** Delay before the worker callback runs, giving the visible host time to boot. */\n readonly startupDelayMs?: number;\n}\n\nexport interface TrayAppContext {\n /** Create a tray in the app worker while the helper owns the visible host loop. */\n createTray(options: TrayOptions): Promise<EventfulTrayHandle>;\n}\n\n/**\n * First-app entrypoint executed inside the app worker.\n *\n * Keep the callback self-contained. Imports needed by the callback should be\n * dynamic imports inside the callback because the helper runs it in a worker.\n */\nexport type TrayAppMain = (context: TrayAppContext) => void | Promise<void>;\n\ninterface RunTrayAppWorkerData {\n readonly mainSource: string;\n readonly sdkUrl: string;\n readonly runtimeOptions: {\n readonly packageVersion?: string;\n readonly clientVersion?: string;\n readonly protocolVersion?: number;\n readonly appId?: string;\n readonly appName?: string;\n };\n readonly startupDelayMs: number;\n}\n\n/** Run a self-contained tray app without exposing host-thread choreography. */\nexport const runTrayApp = async (\n main: TrayAppMain,\n options: RunTrayAppOptions = {}\n): Promise<void> => {\n if (typeof main !== \"function\") {\n throw new TypeError(\"main must be a function\");\n }\n\n const worker = new Worker(createTrayAppWorkerSource(), {\n eval: true,\n workerData: {\n mainSource: main.toString(),\n sdkUrl: resolveWorkerSdkUrl(),\n runtimeOptions: {\n ...(options.packageVersion === undefined\n ? {}\n : { packageVersion: options.packageVersion }),\n ...(options.clientVersion === undefined\n ? {}\n : { clientVersion: options.clientVersion }),\n ...(options.protocolVersion === undefined\n ? {}\n : { protocolVersion: options.protocolVersion }),\n ...(options.appId === undefined ? {} : { appId: options.appId }),\n ...(options.appName === undefined ? {} : { appName: options.appName }),\n },\n startupDelayMs: normalizeDelay(options.startupDelayMs),\n } satisfies RunTrayAppWorkerData,\n });\n\n await waitForWorkerOnline(worker);\n worker.postMessage(\"start\");\n\n try {\n await runVisibleRuntimeHost({\n ...(options.packageVersion === undefined\n ? {}\n : { packageVersion: options.packageVersion }),\n ...(options.appId === undefined ? {} : { appId: options.appId }),\n ...(options.appName === undefined ? {} : { appName: options.appName }),\n ...(options.autoExitAfterMs === undefined\n ? {}\n : { autoExitAfterMs: options.autoExitAfterMs }),\n });\n } finally {\n await worker.terminate();\n }\n}\n\nexport const createTrayAppWorkerSource = (): string => `\n const { parentPort, workerData } = require(\"node:worker_threads\");\n\n const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n const isStartMessage = (value) => value === \"start\";\n\n if (parentPort === null) {\n throw new Error(\"OpenTray tray app worker requires a parent port\");\n }\n\n import(workerData.sdkUrl)\n .then(({ createTray: rawCreateTray }) => {\n const createTray = (options) =>\n rawCreateTray(options, workerData.runtimeOptions);\n const main = eval(\"(\" + workerData.mainSource + \")\");\n\n parentPort.postMessage(\"online\");\n parentPort.once(\"message\", async (message) => {\n if (!isStartMessage(message)) {\n return;\n }\n if (workerData.startupDelayMs > 0) {\n await delay(workerData.startupDelayMs);\n }\n await main({ createTray });\n parentPort.postMessage(\"done\");\n });\n })\n .catch((error) => {\n throw error;\n });\n`;\n\nconst normalizeDelay = (value: number | undefined): number => {\n if (value === undefined) {\n return 250;\n }\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`startupDelayMs must be a non-negative number: ${value}`);\n }\n return value;\n};\n\nconst resolveWorkerSdkUrl = (): string =>\n import.meta.url.endsWith(\".mjs\")\n ? new URL(\"./sdk.mjs\", import.meta.url).href\n : new URL(\"./sdk.ts\", import.meta.url).href;\n\nconst waitForWorkerOnline = async (worker: Worker): Promise<void> =>\n new Promise((resolve, reject) => {\n const onMessage = (value: unknown): void => {\n if (value === \"online\") {\n cleanup();\n resolve();\n return;\n }\n };\n const onError = (error: Error): void => {\n cleanup();\n reject(error);\n };\n const onExit = (code: number): void => {\n if (code !== 0) {\n cleanup();\n reject(new Error(`tray app worker exited with code ${code}`));\n }\n };\n const cleanup = (): void => {\n worker.off(\"message\", onMessage);\n worker.off(\"error\", onError);\n worker.off(\"exit\", onExit);\n };\n\n worker.on(\"message\", onMessage);\n worker.on(\"error\", onError);\n worker.on(\"exit\", onExit);\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"node.mjs","names":[],"sources":["../src/node-host.ts"],"sourcesContent":["import {\n loadOpenTrayRuntimeBinding,\n type OpenTrayVisibleRuntimeHostOptions,\n type ResolveRuntimeBindingOptions,\n} from \"./native-runtime\";\n\n/** Options for resolving the native binding and running the visible host loop. */\nexport interface RunVisibleRuntimeHostOptions\n extends ResolveRuntimeBindingOptions,\n OpenTrayVisibleRuntimeHostOptions {}\n\n/** Run the visible native host loop on the caller-owned Node main thread. */\nexport const runVisibleRuntimeHost = async ({\n platform,\n arch,\n resolvePackageJson,\n nativeLoader,\n ...hostOptions\n}: RunVisibleRuntimeHostOptions = {}): Promise<void> => {\n const binding = await loadOpenTrayRuntimeBinding({\n ...(platform === undefined ? {} : { platform }),\n ...(arch === undefined ? {} : { arch }),\n ...(resolvePackageJson === undefined ? {} : { resolvePackageJson }),\n ...(nativeLoader === undefined ? {} : { nativeLoader }),\n });\n if (binding.runVisibleRuntimeHost === undefined) {\n throw new Error(\n \"OpenTray runtime binding does not expose runVisibleRuntimeHost()\"\n );\n }\n binding.runVisibleRuntimeHost(hostOptions);\n};\n\nexport {\n MissingPlatformRuntimeBindingError,\n resolveInstalledRuntimeBindingPath,\n resolveRuntimeNativeTarget,\n loadOpenTrayRuntimeBinding,\n type OpenTrayRuntimeBinding,\n type OpenTrayRuntimeBindingInfo,\n type OpenTrayVisibleRuntimeHostOptions,\n type ResolveRuntimeBindingOptions,\n type RuntimeNativeTarget,\n} from \"./native-runtime\";\nexport {\n createRuntimeBindingTransport,\n type CreateRuntimeBindingTransportOptions,\n} from \"./runtime-binding-transport\";\n"],"mappings":";;;AAYA,MAAa,wBAAwB,OAAO,EAC1C,UACA,MACA,oBACA,cACA,GAAG,gBAC6B,CAAC,MAAqB;CACtD,MAAM,UAAU,MAAM,2BAA2B;EAC/C,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC7C,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC,GAAI,uBAAuB,KAAA,IAAY,CAAC,IAAI,EAAE,mBAAmB;EACjE,GAAI,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa;CACvD,CAAC;CACD,IAAI,QAAQ,0BAA0B,KAAA,GACpC,MAAM,IAAI,MACR,kEACF;CAEF,QAAQ,sBAAsB,WAAW;AAC3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opentray",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Developer-facing OpenTray SDK and CLI package.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "sideEffects": false,
30
30
  "dependencies": {
31
- "@opentray/spec": "0.10.0"
31
+ "@opentray/spec": "0.10.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsdown": "^0.22.1",
@@ -36,12 +36,12 @@
36
36
  "vitest": "^4.1.7"
37
37
  },
38
38
  "optionalDependencies": {
39
- "@opentray/darwin-arm64": "0.10.0",
40
- "@opentray/darwin-x64": "0.10.0",
41
- "@opentray/linux-arm64": "0.10.0",
42
- "@opentray/linux-x64": "0.10.0",
43
- "@opentray/windows-arm64": "0.10.0",
44
- "@opentray/windows-x64": "0.10.0"
39
+ "@opentray/darwin-arm64": "0.10.2",
40
+ "@opentray/darwin-x64": "0.10.2",
41
+ "@opentray/linux-arm64": "0.10.2",
42
+ "@opentray/linux-x64": "0.10.2",
43
+ "@opentray/windows-arm64": "0.10.2",
44
+ "@opentray/windows-x64": "0.10.2"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "tsdown src/index.ts src/node.ts src/cli.ts --format esm --dts",