opentray 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -28
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +1 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +139 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +172 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -14
- package/dist/native-runtime-Cn8BaffH.d.mts +0 -136
- package/dist/native-runtime-Cn8BaffH.d.mts.map +0 -1
- package/dist/node.d.mts +0 -37
- package/dist/node.d.mts.map +0 -1
- package/dist/node.mjs +0 -17
- package/dist/node.mjs.map +0 -1
- package/dist/runtime-binding-transport-UPunusBT.mjs +0 -177
- package/dist/runtime-binding-transport-UPunusBT.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -30,18 +30,33 @@ Use `alpha-A-B` for alpha packages on the same protocol line. Replace `A-B` with
|
|
|
30
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 {
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
import {
|
|
34
|
+
createTray,
|
|
35
|
+
type CreateTrayHandle,
|
|
36
|
+
type CreateTrayOptions,
|
|
37
|
+
type TrayIcon,
|
|
38
|
+
} from "opentray";
|
|
39
|
+
|
|
40
|
+
const icon: TrayIcon = { "text-only": "OT" };
|
|
41
|
+
let tray: CreateTrayHandle;
|
|
42
|
+
const options: CreateTrayOptions = {
|
|
36
43
|
id: "com.example.first-app",
|
|
37
|
-
icon
|
|
38
|
-
menu: {
|
|
39
|
-
|
|
44
|
+
icon,
|
|
45
|
+
menu: {
|
|
46
|
+
items: [
|
|
47
|
+
{
|
|
48
|
+
title: "Quit",
|
|
49
|
+
primaryEvent: true,
|
|
50
|
+
onMenuClick: () => void tray.destroy(),
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
tray = await createTray(options, {
|
|
40
57
|
appId: "com.example.first-app",
|
|
41
58
|
appName: "First App",
|
|
42
59
|
});
|
|
43
|
-
|
|
44
|
-
tray.onMenuClick(({ itemId }) => void (itemId === 1 && tray.destroy()));
|
|
45
60
|
```
|
|
46
61
|
|
|
47
62
|
`createTray()` remains the direct tray API when the caller already owns the runtime process shape.
|
|
@@ -62,28 +77,55 @@ const tray = await createTray({
|
|
|
62
77
|
description: "Background service is running",
|
|
63
78
|
},
|
|
64
79
|
menu: {
|
|
65
|
-
items: [
|
|
80
|
+
items: [
|
|
81
|
+
{
|
|
82
|
+
title: "Open",
|
|
83
|
+
primaryEvent: true,
|
|
84
|
+
onMenuClick: () => {
|
|
85
|
+
// Open an app-owned window, command, or extension surface.
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
"-",
|
|
89
|
+
["More", ["Settings", "Quit"]],
|
|
90
|
+
],
|
|
66
91
|
},
|
|
67
92
|
});
|
|
68
|
-
|
|
69
|
-
tray.onMenuClick(({ itemId }) => {
|
|
70
|
-
if (itemId === 1) {
|
|
71
|
-
// Open an app-owned window, command, or extension surface.
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
93
|
```
|
|
75
94
|
|
|
76
|
-
Visible tray text belongs to `icon.text`, `icon["text-only"]`, or `icon["icon-text"].text`. The current tray-first API does not export `createSpace()`, `createSurface()`, `resolveDefaultSpace()`, or `TrayHandle.setTitle()`.
|
|
95
|
+
Visible tray text belongs to `icon.text`, `icon["text-only"]`, or `icon["icon-text"].text`. If no visible icon/text survives projection, native tray backends fall back to the runtime `appName`. The current tray-first API does not export `createSpace()`, `createSurface()`, `resolveDefaultSpace()`, or `TrayHandle.setTitle()`.
|
|
96
|
+
|
|
97
|
+
The package re-exports common application-facing types including `CreateTrayOptions`, `TrayIcon`, `TrayMenu`, `TrayTooltip`, `TrayEvent`, and `TrayBoundsResult`. Use those public names instead of deriving SDK shapes with `typeof` in application code.
|
|
98
|
+
|
|
99
|
+
Top-level `createTray(...)` and its returned `setMenu(...)` accept app-facing
|
|
100
|
+
menu shorthand. Lower-level `createClient(...)` remains protocol-only for tools
|
|
101
|
+
that need exact wire shapes.
|
|
102
|
+
|
|
103
|
+
`primaryEvent` is a role on a normal menu item and emits the usual `menuClick`.
|
|
104
|
+
Use `tray.onTrayClick(...)` when you want to listen to raw tray-icon clicks
|
|
105
|
+
without making a menu item the primary route.
|
|
77
106
|
|
|
78
107
|
## Runtime Ownership
|
|
79
108
|
|
|
80
109
|
OpenTray does not ask developers to create a public broker object. The application process or an application-owned background service imports `opentray`, calls `createTray()`, owns event handlers, and releases the tray when that process exits.
|
|
81
110
|
|
|
82
|
-
|
|
111
|
+
Platform runtime packages carry the packaged runtime executable at `bin/opentray` or `bin/opentray.exe`.
|
|
112
|
+
|
|
113
|
+
When a local consumer links this workspace, refresh native package artifacts explicitly instead of relying on `pnpm run build` alone:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pnpm run npm:cp-bin:runtime
|
|
117
|
+
pnpm run npm:cp-bin:webview
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use `pnpm run npm:cp-bin` to refresh both the packaged runtime executable and the current platform WebView native library. Without `--target`, it compares existing `target/debug` and `target/release` artifacts and copies the newest binary for each kind. Pass `--target debug`, `-t debug`, or `--target release` to build and copy a specific target into the package projection:
|
|
83
121
|
|
|
84
|
-
|
|
122
|
+
```bash
|
|
123
|
+
pnpm run npm:cp-bin
|
|
124
|
+
pnpm run npm:cp-bin -- --target debug
|
|
125
|
+
pnpm run npm:cp-bin:webview -- -t debug
|
|
126
|
+
```
|
|
85
127
|
|
|
86
|
-
|
|
128
|
+
By default, `createTray()` routes through the local runtime host and starts it on first use when needed. The executable host remains the source of truth for tray lifecycle, session cleanup, and native event routing on supported platforms.
|
|
87
129
|
|
|
88
130
|
Runtime options may also carry app identity facts:
|
|
89
131
|
|
|
@@ -96,8 +138,6 @@ await createTray(options, {
|
|
|
96
138
|
|
|
97
139
|
The runtime host reports those facts as `appId` and `appName` in `runtime-host-health`; tray icon text, menu labels, and tooltip text remain projection data.
|
|
98
140
|
|
|
99
|
-
The `opentray/node` subpath exposes binding-resolution, visible host-loop, and binding-transport helpers. Source-tree diagnostics may still use the internal local broker transport, but that transport is not exported as a package contract.
|
|
100
|
-
|
|
101
141
|
## Examples
|
|
102
142
|
|
|
103
143
|
Run the quickstart example and the protocol-only example:
|
|
@@ -111,17 +151,13 @@ Run the finite source-tree smoke matrix instead of relying on shell expansion fo
|
|
|
111
151
|
|
|
112
152
|
```bash
|
|
113
153
|
pnpm --filter opentray example:matrix
|
|
114
|
-
pnpm --filter opentray example:matrix -- --row
|
|
154
|
+
pnpm --filter opentray example:matrix -- --row webview-control
|
|
115
155
|
```
|
|
116
156
|
|
|
117
157
|
Run human-visible tray and extension examples from a source checkout:
|
|
118
158
|
|
|
119
159
|
```bash
|
|
120
|
-
cargo build -p opentray-
|
|
121
|
-
pnpm --filter opentray build
|
|
122
|
-
bun run scripts/binaries/stage-local.ts --kind runtime --source target/debug/libopentray_runtime_node.dylib
|
|
123
|
-
OPENTRAY_EXAMPLE_EXIT_AFTER_MS=1500 pnpm --filter opentray example:visible-binding
|
|
124
|
-
|
|
160
|
+
cargo build -p opentray-bin
|
|
125
161
|
pnpm --filter opentray example:debug-runtime-tray
|
|
126
162
|
pnpm --filter opentray example:webview-control
|
|
127
163
|
pnpm --filter opentray example:tray-panel
|
|
@@ -130,4 +166,4 @@ pnpm --filter opentray example:mediaQuery
|
|
|
130
166
|
pnpm --filter opentray example:debug-runtime-lynx -- --bundle packages/cli/assets/lynx-review/main.lynx.bundle
|
|
131
167
|
```
|
|
132
168
|
|
|
133
|
-
The example matrix
|
|
169
|
+
The example matrix warms the runtime executable 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 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/cli.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.mts","names":[],"sources":["../src/cli.ts"],"mappings":";KAMK,UAAA;EACC,IAAA;EAAc,QAAA;AAAA;EACd,IAAA;EAAqB,OAAA;AAAA;AAAA,cAEd,eAAA,GAAmB,IAAA,eAAiB,UAMhD;AAAA,cAEY,MAAA,GAAgB,IAAA,eAAiB,OAAO;AAAA,
|
|
1
|
+
{"version":3,"file":"cli.d.mts","names":[],"sources":["../src/cli.ts"],"mappings":";KAMK,UAAA;EACC,IAAA;EAAc,QAAA;AAAA;EACd,IAAA;EAAqB,OAAA;AAAA;AAAA,cAEd,eAAA,GAAmB,IAAA,eAAiB,UAMhD;AAAA,cAEY,MAAA,GAAgB,IAAA,eAAiB,OAAO;AAAA,cAsBxC,eAAA,GACX,aAAA,sBACA,UAAkB"}
|
package/dist/cli.mjs
CHANGED
|
@@ -22,12 +22,11 @@ const runCli = async (argv) => {
|
|
|
22
22
|
const printHelp = (unsupportedCommand) => {
|
|
23
23
|
if (unsupportedCommand !== void 0) console.error(`Unsupported opentray command: ${unsupportedCommand}`);
|
|
24
24
|
console.error([
|
|
25
|
-
"OpenTray
|
|
25
|
+
"OpenTray does not expose daemon lifecycle commands.",
|
|
26
26
|
"Create trays from an app-owned process with:",
|
|
27
27
|
"",
|
|
28
28
|
" import { createTray } from \"opentray\";",
|
|
29
29
|
"",
|
|
30
|
-
"Node runtime diagnostics live under the opentray/node binding helpers.",
|
|
31
30
|
"Source-tree visual diagnostics live in packages/cli/examples."
|
|
32
31
|
].join("\n"));
|
|
33
32
|
};
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nconst cliModulePath = fileURLToPath(import.meta.url);\n\ntype CliCommand =\n | { type: \"help\"; exitCode: 0 }\n | { type: \"unsupported\"; command: string | undefined };\n\nexport const parseCliCommand = (argv: string[]): CliCommand => {\n const [command] = argv;\n if (command === undefined || command === \"--help\" || command === \"-h\") {\n return { type: \"help\", exitCode: 0 };\n }\n return { type: \"unsupported\", command };\n};\n\nexport const runCli = async (argv: string[]): Promise<number> => {\n const command = parseCliCommand(argv);\n printHelp(command.type === \"unsupported\" ? command.command : undefined);\n return command.type === \"help\" ? command.exitCode : 1;\n};\n\nconst printHelp = (unsupportedCommand?: string): void => {\n if (unsupportedCommand !== undefined) {\n console.error(`Unsupported opentray command: ${unsupportedCommand}`);\n }\n console.error(\n [\n \"OpenTray
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nconst cliModulePath = fileURLToPath(import.meta.url);\n\ntype CliCommand =\n | { type: \"help\"; exitCode: 0 }\n | { type: \"unsupported\"; command: string | undefined };\n\nexport const parseCliCommand = (argv: string[]): CliCommand => {\n const [command] = argv;\n if (command === undefined || command === \"--help\" || command === \"-h\") {\n return { type: \"help\", exitCode: 0 };\n }\n return { type: \"unsupported\", command };\n};\n\nexport const runCli = async (argv: string[]): Promise<number> => {\n const command = parseCliCommand(argv);\n printHelp(command.type === \"unsupported\" ? command.command : undefined);\n return command.type === \"help\" ? command.exitCode : 1;\n};\n\nconst printHelp = (unsupportedCommand?: string): void => {\n if (unsupportedCommand !== undefined) {\n console.error(`Unsupported opentray command: ${unsupportedCommand}`);\n }\n console.error(\n [\n \"OpenTray does not expose daemon lifecycle commands.\",\n \"Create trays from an app-owned process with:\",\n \"\",\n ' import { createTray } from \"opentray\";',\n \"\",\n \"Source-tree visual diagnostics live in packages/cli/examples.\",\n ].join(\"\\n\")\n );\n};\n\nexport const isCliEntrypoint = (\n argvEntryPath: string | undefined,\n modulePath: string\n): boolean => {\n if (argvEntryPath === undefined) return false;\n try {\n return realpathSync(argvEntryPath) === realpathSync(modulePath);\n } catch {\n return argvEntryPath === modulePath;\n }\n};\n\nif (isCliEntrypoint(process.argv[1], cliModulePath)) {\n runCli(process.argv.slice(2)).then((code) => {\n process.exitCode = code;\n });\n}\n"],"mappings":";;;;AAIA,MAAM,gBAAgB,cAAc,OAAO,KAAK,GAAG;AAMnD,MAAa,mBAAmB,SAA+B;CAC7D,MAAM,CAAC,WAAW;CAClB,IAAI,YAAY,KAAA,KAAa,YAAY,YAAY,YAAY,MAC/D,OAAO;EAAE,MAAM;EAAQ,UAAU;CAAE;CAErC,OAAO;EAAE,MAAM;EAAe;CAAQ;AACxC;AAEA,MAAa,SAAS,OAAO,SAAoC;CAC/D,MAAM,UAAU,gBAAgB,IAAI;CACpC,UAAU,QAAQ,SAAS,gBAAgB,QAAQ,UAAU,KAAA,CAAS;CACtE,OAAO,QAAQ,SAAS,SAAS,QAAQ,WAAW;AACtD;AAEA,MAAM,aAAa,uBAAsC;CACvD,IAAI,uBAAuB,KAAA,GACzB,QAAQ,MAAM,iCAAiC,oBAAoB;CAErE,QAAQ,MACN;EACE;EACA;EACA;EACA;EACA;EACA;CACF,EAAE,KAAK,IAAI,CACb;AACF;AAEA,MAAa,mBACX,eACA,eACY;CACZ,IAAI,kBAAkB,KAAA,GAAW,OAAO;CACxC,IAAI;EACF,OAAO,aAAa,aAAa,MAAM,aAAa,UAAU;CAChE,QAAQ;EACN,OAAO,kBAAkB;CAC3B;AACF;AAEA,IAAI,gBAAgB,QAAQ,KAAK,IAAI,aAAa,GAChD,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,SAAS;CAC3C,QAAQ,WAAW;AACrB,CAAC"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,130 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BrokerEndpointIdentity, BrokerEndpointIdentityOptions, PROTOCOL_VERSION, TrayOptions, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion } from "@opentray/spec";
|
|
1
|
+
import { AppId, AppIdentity, AppOptions, AppRef, BrokerEndpointIdentity, BrokerEndpointIdentityOptions, ClientFrame, ClientFrame as ClientFrame$1, ClientRequestFrame, ClientRequestFrame as ClientRequestFrame$1, DarwinIcon, DarwinIconText, ExtensionEnvelope, ExtensionEnvelope as ExtensionEnvelope$1, Icon, Icon as Icon$1, Icon as TrayIcon, IconCandidates, IconImage, IconText, LinuxIcon, Menu, Menu as Menu$1, MenuItem, MenuItemId, MenuItemId as MenuItemId$1, MouseButton, PROTOCOL_VERSION, Rect, RequestId, ServerFrame, ServerFrame as ServerFrame$1, SimpleIcon, Tooltip, Tooltip as Tooltip$1, Tooltip as TrayTooltip, TrayBoundsKind, TrayBoundsResult, TrayBoundsResult as TrayBoundsResult$1, TrayEvent, TrayEvent as TrayEvent$1, TrayId, TrayId as TrayId$1, TrayOptions, TrayOptions as TrayOptions$1, Win32Icon, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion } from "@opentray/spec";
|
|
3
2
|
|
|
3
|
+
//#region src/client.d.ts
|
|
4
|
+
interface OpenTrayTransport {
|
|
5
|
+
request(frame: ClientRequestFrame$1): Promise<ServerFrame$1>;
|
|
6
|
+
}
|
|
7
|
+
type OpenTrayEventFrame = Extract<ServerFrame$1, {
|
|
8
|
+
type: "event" | "ext-event";
|
|
9
|
+
}>;
|
|
10
|
+
interface OpenTrayEventSource {
|
|
11
|
+
onEvent(listener: (frame: OpenTrayEventFrame) => void): () => void;
|
|
12
|
+
}
|
|
13
|
+
interface OpenTrayConnection extends OpenTrayTransport, OpenTrayEventSource {}
|
|
14
|
+
interface OpenTrayClient {
|
|
15
|
+
createTray(options: TrayOptions$1): Promise<TrayHandle>;
|
|
16
|
+
}
|
|
17
|
+
interface OpenTrayEventfulClient extends OpenTrayClient {
|
|
18
|
+
createTray(options: TrayOptions$1): Promise<EventfulTrayHandle>;
|
|
19
|
+
}
|
|
20
|
+
interface TrayHandle {
|
|
21
|
+
trayId: TrayId$1;
|
|
22
|
+
getBounds(): Promise<TrayBoundsResult$1>;
|
|
23
|
+
setMenu(menu: Menu$1): Promise<void>;
|
|
24
|
+
setTooltip(tooltip: Tooltip$1): Promise<void>;
|
|
25
|
+
setIcon(icon: Icon$1): Promise<void>;
|
|
26
|
+
loadExtension(options: ExtensionLoadOptions): Promise<void>;
|
|
27
|
+
commandExtension(ext: string, data: unknown): Promise<void>;
|
|
28
|
+
requestExtension(ext: string, data: unknown): Promise<ExtensionEnvelope$1[]>;
|
|
29
|
+
extend<TCapability extends object, TOptions = undefined>(extension: TrayExtension<TCapability, TOptions>, options?: TOptions): TrayHandle & TCapability;
|
|
30
|
+
destroy(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
type TrayScopedEvent = Exclude<TrayEvent$1, {
|
|
33
|
+
type: "ready";
|
|
34
|
+
}>;
|
|
35
|
+
type TrayEventType = TrayScopedEvent["type"];
|
|
36
|
+
type TrayEventByType<TEvent extends TrayEventType> = Extract<TrayScopedEvent, {
|
|
37
|
+
type: TEvent;
|
|
38
|
+
}>;
|
|
39
|
+
interface EventfulTrayHandle extends TrayHandle {
|
|
40
|
+
extend<TCapability extends object, TOptions = undefined>(extension: TrayExtension<TCapability, TOptions>, options?: TOptions): EventfulTrayHandle & TCapability;
|
|
41
|
+
listenExtension<TData = unknown>(ext: string, handler: (event: ExtensionEnvelope$1<TData>) => void): () => void;
|
|
42
|
+
listen<TEvent extends TrayEventType>(event: TEvent, handler: (event: TrayEventByType<TEvent>) => void): () => void;
|
|
43
|
+
onMenuClick(handler: (event: TrayEventByType<"menuClick">) => void): () => void;
|
|
44
|
+
onTrayClick(handler: (event: TrayEventByType<"trayClick">) => void): () => void;
|
|
45
|
+
onTrayDoubleClick(handler: (event: TrayEventByType<"trayDoubleClick">) => void): () => void;
|
|
46
|
+
}
|
|
47
|
+
interface ExtensionLoadOptions {
|
|
48
|
+
name: string;
|
|
49
|
+
path: string;
|
|
50
|
+
mountId?: string;
|
|
51
|
+
}
|
|
52
|
+
interface TrayExtensionMountSpec {
|
|
53
|
+
name?: string;
|
|
54
|
+
path?: string;
|
|
55
|
+
mountId?: string;
|
|
56
|
+
}
|
|
57
|
+
interface TrayExtensionContext {
|
|
58
|
+
readonly appId: string;
|
|
59
|
+
readonly trayId: TrayId$1;
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly path: string;
|
|
62
|
+
readonly mountId: string;
|
|
63
|
+
ensureLoaded(): Promise<void>;
|
|
64
|
+
command(data: unknown): Promise<void>;
|
|
65
|
+
request(data: unknown): Promise<ExtensionEnvelope$1[]>;
|
|
66
|
+
}
|
|
67
|
+
interface TrayExtension<TCapability extends object, TOptions = undefined> {
|
|
68
|
+
readonly name: string;
|
|
69
|
+
readonly path: string;
|
|
70
|
+
resolveMount?(options: TOptions | undefined): TrayExtensionMountSpec;
|
|
71
|
+
extend(tray: TrayHandle, context: TrayExtensionContext, options: TOptions | undefined): TCapability;
|
|
72
|
+
}
|
|
73
|
+
declare const createInitFrame: (clientVersion: string) => ClientFrame$1;
|
|
74
|
+
interface CreateClientOptions {
|
|
75
|
+
requestIdPrefix?: string;
|
|
76
|
+
}
|
|
77
|
+
declare function createClient(transport: OpenTrayConnection, options?: CreateClientOptions): OpenTrayEventfulClient;
|
|
78
|
+
declare function createClient(transport: OpenTrayTransport, options?: CreateClientOptions): OpenTrayClient;
|
|
79
|
+
declare function createTrayHandle(transport: OpenTrayConnection, appId: string, trayId: TrayId$1, nextRequestId?: () => RequestId): EventfulTrayHandle;
|
|
80
|
+
declare function createTrayHandle(transport: OpenTrayTransport, appId: string, trayId: TrayId$1, nextRequestId?: () => RequestId): TrayHandle;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/menu-input.d.ts
|
|
83
|
+
type CreateTrayMenuClickHandler = (event: TrayEventByType<"menuClick">) => void;
|
|
84
|
+
/** App-facing menu input accepted by top-level createTray and setMenu. */
|
|
85
|
+
type CreateTrayMenu = {
|
|
86
|
+
items: CreateTrayMenuItem[];
|
|
87
|
+
};
|
|
88
|
+
/** Menu item shorthand normalized to protocol MenuItem before runtime transport. */
|
|
89
|
+
type CreateTrayMenuItem = string | readonly [title: string, items: readonly CreateTrayMenuItem[]] | CreateTrayItem | CreateTrayCheckItem | CreateTrayRadioItem | CreateTraySeparatorItem | CreateTraySubmenuItem;
|
|
90
|
+
type CreateTrayItem = {
|
|
91
|
+
type?: "item";
|
|
92
|
+
id?: MenuItemId$1;
|
|
93
|
+
title: string;
|
|
94
|
+
primaryEvent?: boolean;
|
|
95
|
+
enabled?: boolean;
|
|
96
|
+
shortcut?: string;
|
|
97
|
+
onMenuClick?: CreateTrayMenuClickHandler;
|
|
98
|
+
};
|
|
99
|
+
type CreateTrayCheckItem = {
|
|
100
|
+
type: "check";
|
|
101
|
+
id?: MenuItemId$1;
|
|
102
|
+
title: string;
|
|
103
|
+
enabled?: boolean;
|
|
104
|
+
checked?: boolean;
|
|
105
|
+
onMenuClick?: CreateTrayMenuClickHandler;
|
|
106
|
+
};
|
|
107
|
+
type CreateTrayRadioItem = {
|
|
108
|
+
type: "radio";
|
|
109
|
+
id?: MenuItemId$1;
|
|
110
|
+
title: string;
|
|
111
|
+
enabled?: boolean;
|
|
112
|
+
checked?: boolean;
|
|
113
|
+
group: number;
|
|
114
|
+
onMenuClick?: CreateTrayMenuClickHandler;
|
|
115
|
+
};
|
|
116
|
+
type CreateTraySeparatorItem = {
|
|
117
|
+
type: "separator";
|
|
118
|
+
};
|
|
119
|
+
type CreateTraySubmenuItem = {
|
|
120
|
+
type: "submenu";
|
|
121
|
+
title: string;
|
|
122
|
+
enabled?: boolean;
|
|
123
|
+
items: readonly CreateTrayMenuItem[];
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
4
126
|
//#region src/sdk.d.ts
|
|
5
|
-
type OpenTrayRuntimeMode = "visible-binding" | "local-broker" | "headless-binding";
|
|
6
127
|
interface OpenTrayRuntimeOptions {
|
|
7
|
-
runtime?: OpenTrayRuntimeMode;
|
|
8
128
|
endpoint?: string;
|
|
9
129
|
homeDir?: string;
|
|
10
130
|
packageVersion?: string;
|
|
@@ -13,9 +133,21 @@ interface OpenTrayRuntimeOptions {
|
|
|
13
133
|
appId?: string;
|
|
14
134
|
appName?: string;
|
|
15
135
|
autoStart?: boolean;
|
|
16
|
-
binding?: OpenTrayRuntimeBinding;
|
|
17
136
|
}
|
|
18
|
-
|
|
137
|
+
/** App-facing tray options accepted by top-level createTray. */
|
|
138
|
+
interface CreateTrayOptions {
|
|
139
|
+
id: string;
|
|
140
|
+
tooltip?: Tooltip$1;
|
|
141
|
+
icon?: Icon$1;
|
|
142
|
+
menu?: CreateTrayMenu;
|
|
143
|
+
}
|
|
144
|
+
/** Tray handle returned by top-level createTray with ergonomic setMenu input. */
|
|
145
|
+
interface CreateTrayHandle extends Omit<EventfulTrayHandle, "setMenu" | "extend" | "destroy"> {
|
|
146
|
+
setMenu(menu: CreateTrayMenu): Promise<void>;
|
|
147
|
+
extend<TCapability extends object, TOptions = undefined>(extension: TrayExtension<TCapability, TOptions>, options?: TOptions): CreateTrayHandle & TCapability;
|
|
148
|
+
destroy(): Promise<void>;
|
|
149
|
+
}
|
|
150
|
+
declare const createTray: (options: CreateTrayOptions, runtimeOptions?: OpenTrayRuntimeOptions) => Promise<CreateTrayHandle>;
|
|
19
151
|
//#endregion
|
|
20
|
-
export { type BrokerEndpointIdentity, type BrokerEndpointIdentityOptions, type CreateClientOptions, type EventfulTrayHandle, type ExtensionLoadOptions, type OpenTrayClient, type OpenTrayConnection, type OpenTrayEventFrame, type OpenTrayEventSource, type OpenTrayRuntimeOptions, type OpenTrayTransport, PROTOCOL_VERSION, type TrayEventByType, type TrayEventType, type TrayExtension, type TrayExtensionContext, type TrayExtensionMountSpec, type TrayHandle, createBrokerEndpointIdentity, createClient, createInitFrame, createTray, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion };
|
|
152
|
+
export { type AppId, type AppIdentity, type AppOptions, type AppRef, type BrokerEndpointIdentity, type BrokerEndpointIdentityOptions, type ClientFrame, type ClientRequestFrame, type CreateClientOptions, type CreateTrayCheckItem, type CreateTrayHandle, type CreateTrayItem, type CreateTrayMenu, type CreateTrayMenu as TrayMenu, type CreateTrayMenuClickHandler, type CreateTrayMenuItem, type CreateTrayOptions, type CreateTrayRadioItem, type CreateTraySeparatorItem, type CreateTraySubmenuItem, type DarwinIcon, type DarwinIconText, type EventfulTrayHandle, type ExtensionEnvelope, type ExtensionLoadOptions, type Icon, type IconCandidates, type IconImage, type IconText, type LinuxIcon, type Menu, type MenuItem, type MenuItemId, type MouseButton, type OpenTrayClient, type OpenTrayConnection, type OpenTrayEventFrame, type OpenTrayEventSource, type OpenTrayRuntimeOptions, type OpenTrayTransport, PROTOCOL_VERSION, type Rect, type ServerFrame, type SimpleIcon, type Tooltip, type TrayBoundsKind, type TrayBoundsResult, type TrayEvent, type TrayEventByType, type TrayEventType, type TrayExtension, type TrayExtensionContext, type TrayExtensionMountSpec, type TrayHandle, type TrayIcon, type TrayId, type TrayOptions, type TrayTooltip, type Win32Icon, createBrokerEndpointIdentity, createClient, createInitFrame, createTray, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion };
|
|
21
153
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/sdk.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/client.ts","../src/menu-input.ts","../src/sdk.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { t as createRuntimeBindingTransport } from "./runtime-binding-transport-UPunusBT.mjs";
|
|
2
1
|
import { PROTOCOL_VERSION, PROTOCOL_VERSION as PROTOCOL_VERSION$1, createBrokerEndpointIdentity, createBrokerEndpointIdentity as createBrokerEndpointIdentity$1, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatUnixSocketPath as formatUnixSocketPath$1, formatWindowsPipeName, formatWindowsPipeName as formatWindowsPipeName$1, isSupportedProtocolVersion, parseServerFrame, sanitizeCallerLabel } from "@opentray/spec";
|
|
3
2
|
import { createConnection } from "node:net";
|
|
4
3
|
import { homedir } from "node:os";
|
|
@@ -106,7 +105,7 @@ function createTrayHandle(transport, appId, trayId, nextRequestId = createReques
|
|
|
106
105
|
return expectResponse(response, requestId, "ext-command-result").events;
|
|
107
106
|
},
|
|
108
107
|
extend(extension, options) {
|
|
109
|
-
const context = createTrayExtensionContext(handle, extension, options, nextMountId);
|
|
108
|
+
const context = createTrayExtensionContext(handle, appId, extension, options, nextMountId);
|
|
110
109
|
const capability = extension.extend(handle, context, options);
|
|
111
110
|
return Object.assign({}, handle, capability);
|
|
112
111
|
},
|
|
@@ -156,7 +155,7 @@ const attachEventfulTrayHandle = (handle, source, appId, nextMountId) => {
|
|
|
156
155
|
return listen("trayDoubleClick", handler);
|
|
157
156
|
},
|
|
158
157
|
extend(extension, options) {
|
|
159
|
-
const context = createTrayExtensionContext(eventful, extension, options, nextMountId);
|
|
158
|
+
const context = createTrayExtensionContext(eventful, appId, extension, options, nextMountId);
|
|
160
159
|
const capability = extension.extend(eventful, context, options);
|
|
161
160
|
return Object.assign({}, eventful, capability);
|
|
162
161
|
}
|
|
@@ -172,7 +171,7 @@ const resolveDefaultAppRef = async (transport, nextRequestId) => {
|
|
|
172
171
|
requestId
|
|
173
172
|
}), requestId, "default-app").app;
|
|
174
173
|
};
|
|
175
|
-
const createTrayExtensionContext = (tray, extension, options, nextMountId) => {
|
|
174
|
+
const createTrayExtensionContext = (tray, appId, extension, options, nextMountId) => {
|
|
176
175
|
const mount = extension.resolveMount?.(options) ?? {};
|
|
177
176
|
const name = mount.name ?? extension.name;
|
|
178
177
|
const path = mount.path ?? extension.path;
|
|
@@ -190,6 +189,8 @@ const createTrayExtensionContext = (tray, extension, options, nextMountId) => {
|
|
|
190
189
|
await loadPromise;
|
|
191
190
|
};
|
|
192
191
|
return {
|
|
192
|
+
appId,
|
|
193
|
+
trayId: tray.trayId,
|
|
193
194
|
name,
|
|
194
195
|
path,
|
|
195
196
|
mountId,
|
|
@@ -307,7 +308,7 @@ const resolveBrokerCommand = async (paths, options = {}) => {
|
|
|
307
308
|
if (explicit !== void 0 && explicit.length > 0) return commandForBinary(explicit, paths);
|
|
308
309
|
const sourceDir = options.sourceDir ?? dirname(fileURLToPath(sourceUrl));
|
|
309
310
|
const workspaceRoot = await (options.findWorkspaceRoot ?? findWorkspaceRoot)(sourceDir);
|
|
310
|
-
if (workspaceRoot !== void 0) return commandForBinary(await (options.ensureDevBrokerBinary ?? ensureDevBrokerBinary)(workspaceRoot), paths
|
|
311
|
+
if (workspaceRoot !== void 0) return commandForBinary(await (options.ensureDevBrokerBinary ?? ensureDevBrokerBinary)(workspaceRoot), paths);
|
|
311
312
|
const platform = options.platform ?? process.platform;
|
|
312
313
|
const arch = options.arch ?? process.arch;
|
|
313
314
|
const target = resolveBrokerNativeTarget(platform, arch);
|
|
@@ -758,22 +759,176 @@ const resolveCliEntrypoint = () => {
|
|
|
758
759
|
return fileURLToPath(new URL(`./${suffix}`, import.meta.url));
|
|
759
760
|
};
|
|
760
761
|
//#endregion
|
|
762
|
+
//#region src/menu-input.ts
|
|
763
|
+
const normalizeCreateTrayMenu = (menu) => {
|
|
764
|
+
const state = {
|
|
765
|
+
usedIds: collectExplicitMenuIds(menu.items),
|
|
766
|
+
nextId: 1,
|
|
767
|
+
handlers: /* @__PURE__ */ new Map()
|
|
768
|
+
};
|
|
769
|
+
return {
|
|
770
|
+
menu: { items: menu.items.map((item) => normalizeCreateTrayMenuItem(item, state)) },
|
|
771
|
+
handlers: state.handlers
|
|
772
|
+
};
|
|
773
|
+
};
|
|
774
|
+
const normalizeCreateTrayMenuItem = (item, state) => {
|
|
775
|
+
if (typeof item === "string") {
|
|
776
|
+
if (isSeparatorShortcut(item)) return { type: "separator" };
|
|
777
|
+
return normalizePlainItem({ title: item }, state);
|
|
778
|
+
}
|
|
779
|
+
if (isSubmenuTuple(item)) {
|
|
780
|
+
const [title, items] = item;
|
|
781
|
+
return {
|
|
782
|
+
type: "submenu",
|
|
783
|
+
title,
|
|
784
|
+
items: items.map((child) => normalizeCreateTrayMenuItem(child, state))
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
switch (item.type) {
|
|
788
|
+
case void 0:
|
|
789
|
+
case "item": return normalizePlainItem(item, state);
|
|
790
|
+
case "check": return normalizeCheckItem(item, state);
|
|
791
|
+
case "radio": return normalizeRadioItem(item, state);
|
|
792
|
+
case "separator": return item;
|
|
793
|
+
case "submenu": return {
|
|
794
|
+
type: "submenu",
|
|
795
|
+
title: item.title,
|
|
796
|
+
...item.enabled === void 0 ? {} : { enabled: item.enabled },
|
|
797
|
+
items: item.items.map((child) => normalizeCreateTrayMenuItem(child, state))
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
throw new Error("unsupported menu item");
|
|
801
|
+
};
|
|
802
|
+
const normalizeClickableItem = (item, state) => {
|
|
803
|
+
const id = item.id ?? allocateMenuItemId(state);
|
|
804
|
+
registerClickId(state, id);
|
|
805
|
+
if (item.onMenuClick !== void 0) {
|
|
806
|
+
const handlers = state.handlers.get(id) ?? [];
|
|
807
|
+
handlers.push(item.onMenuClick);
|
|
808
|
+
state.handlers.set(id, handlers);
|
|
809
|
+
}
|
|
810
|
+
return id;
|
|
811
|
+
};
|
|
812
|
+
const normalizePlainItem = (item, state) => {
|
|
813
|
+
return {
|
|
814
|
+
type: "item",
|
|
815
|
+
id: normalizeClickableItem(item, state),
|
|
816
|
+
title: item.title,
|
|
817
|
+
...item.primaryEvent === void 0 ? {} : { primaryEvent: item.primaryEvent },
|
|
818
|
+
...item.enabled === void 0 ? {} : { enabled: item.enabled },
|
|
819
|
+
...item.shortcut === void 0 ? {} : { shortcut: item.shortcut }
|
|
820
|
+
};
|
|
821
|
+
};
|
|
822
|
+
const normalizeCheckItem = (item, state) => {
|
|
823
|
+
return {
|
|
824
|
+
type: "check",
|
|
825
|
+
id: normalizeClickableItem(item, state),
|
|
826
|
+
title: item.title,
|
|
827
|
+
...item.enabled === void 0 ? {} : { enabled: item.enabled },
|
|
828
|
+
...item.checked === void 0 ? {} : { checked: item.checked }
|
|
829
|
+
};
|
|
830
|
+
};
|
|
831
|
+
const normalizeRadioItem = (item, state) => {
|
|
832
|
+
return {
|
|
833
|
+
type: "radio",
|
|
834
|
+
id: normalizeClickableItem(item, state),
|
|
835
|
+
title: item.title,
|
|
836
|
+
...item.enabled === void 0 ? {} : { enabled: item.enabled },
|
|
837
|
+
...item.checked === void 0 ? {} : { checked: item.checked },
|
|
838
|
+
group: item.group
|
|
839
|
+
};
|
|
840
|
+
};
|
|
841
|
+
const allocateMenuItemId = (state) => {
|
|
842
|
+
while (state.usedIds.has(state.nextId)) state.nextId += 1;
|
|
843
|
+
const id = state.nextId;
|
|
844
|
+
state.usedIds.add(id);
|
|
845
|
+
state.nextId += 1;
|
|
846
|
+
return id;
|
|
847
|
+
};
|
|
848
|
+
const collectExplicitMenuIds = (items) => {
|
|
849
|
+
const ids = /* @__PURE__ */ new Set();
|
|
850
|
+
for (const item of items) {
|
|
851
|
+
if (typeof item === "string") continue;
|
|
852
|
+
if (isSubmenuTuple(item)) {
|
|
853
|
+
for (const id of collectExplicitMenuIds(item[1])) ids.add(id);
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
switch (item.type) {
|
|
857
|
+
case void 0:
|
|
858
|
+
case "item":
|
|
859
|
+
case "check":
|
|
860
|
+
case "radio":
|
|
861
|
+
if (item.id !== void 0) ids.add(item.id);
|
|
862
|
+
break;
|
|
863
|
+
case "submenu":
|
|
864
|
+
for (const id of collectExplicitMenuIds(item.items)) ids.add(id);
|
|
865
|
+
break;
|
|
866
|
+
case "separator": break;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
return ids;
|
|
870
|
+
};
|
|
871
|
+
const isSeparatorShortcut = (value) => /^-+$/.test(value);
|
|
872
|
+
const isSubmenuTuple = (item) => Array.isArray(item);
|
|
873
|
+
const registerClickId = (state, id) => {
|
|
874
|
+
const seen = state.seenClickIds ?? /* @__PURE__ */ new Set();
|
|
875
|
+
if (seen.has(id)) throw new Error(`duplicate menu item id: ${id}`);
|
|
876
|
+
seen.add(id);
|
|
877
|
+
state.seenClickIds = seen;
|
|
878
|
+
};
|
|
879
|
+
//#endregion
|
|
761
880
|
//#region src/sdk.ts
|
|
762
881
|
const createTray = async (options, runtimeOptions = {}) => {
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
882
|
+
const connection = await connectLocalBroker(runtimeOptions);
|
|
883
|
+
const normalized = normalizeCreateTrayOptions(options);
|
|
884
|
+
const tray = await createClient(connection).createTray(normalized.options);
|
|
885
|
+
return wrapCreateTrayHandle(tray, { menuUnsubscribe: bindMenuClickHandlers(tray, normalized.menuHandlers) });
|
|
886
|
+
};
|
|
887
|
+
const normalizeCreateTrayOptions = (options) => {
|
|
888
|
+
const protocolOptions = {
|
|
889
|
+
id: options.id,
|
|
890
|
+
...options.tooltip === void 0 ? {} : { tooltip: options.tooltip },
|
|
891
|
+
...options.icon === void 0 ? {} : { icon: options.icon }
|
|
770
892
|
};
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
893
|
+
if (options.menu === void 0) return {
|
|
894
|
+
options: protocolOptions,
|
|
895
|
+
menuHandlers: /* @__PURE__ */ new Map()
|
|
896
|
+
};
|
|
897
|
+
const normalized = normalizeCreateTrayMenu(options.menu);
|
|
898
|
+
return {
|
|
899
|
+
options: {
|
|
900
|
+
...protocolOptions,
|
|
901
|
+
menu: normalized.menu
|
|
902
|
+
},
|
|
903
|
+
menuHandlers: normalized.handlers
|
|
904
|
+
};
|
|
905
|
+
};
|
|
906
|
+
const wrapCreateTrayHandle = (tray, state) => {
|
|
907
|
+
return {
|
|
908
|
+
...tray,
|
|
909
|
+
async setMenu(menu) {
|
|
910
|
+
const normalized = normalizeCreateTrayMenu(menu);
|
|
911
|
+
await tray.setMenu(normalized.menu);
|
|
912
|
+
state.menuUnsubscribe();
|
|
913
|
+
state.menuUnsubscribe = bindMenuClickHandlers(tray, normalized.handlers);
|
|
914
|
+
},
|
|
915
|
+
extend(extension, options) {
|
|
916
|
+
return wrapCreateTrayHandle(tray.extend(extension, options), state);
|
|
917
|
+
},
|
|
918
|
+
async destroy() {
|
|
919
|
+
state.menuUnsubscribe();
|
|
920
|
+
state.menuUnsubscribe = noop;
|
|
921
|
+
await tray.destroy();
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
};
|
|
925
|
+
const bindMenuClickHandlers = (tray, handlers) => {
|
|
926
|
+
if (handlers.size === 0) return noop;
|
|
927
|
+
return tray.onMenuClick((event) => {
|
|
928
|
+
for (const handler of handlers.get(event.itemId) ?? []) handler(event);
|
|
929
|
+
});
|
|
776
930
|
};
|
|
931
|
+
const noop = () => {};
|
|
777
932
|
//#endregion
|
|
778
933
|
export { PROTOCOL_VERSION, createBrokerEndpointIdentity, createClient, createInitFrame, createTray, createTrayHandle, formatBrokerEndpointName, formatBrokerStateRoot, formatUnixSocketPath, formatWindowsPipeName, isSupportedProtocolVersion };
|
|
779
934
|
|