opentray 0.9.0 → 0.10.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 +29 -3
- package/dist/node.d.mts +38 -3
- package/dist/node.d.mts.map +1 -1
- package/dist/node.mjs +102 -2
- package/dist/node.mjs.map +1 -1
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -8,6 +8,14 @@ Install it directly in the application or service that owns the tray lifetime:
|
|
|
8
8
|
pnpm add opentray
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
Use `latest` for the newest published package. When installing official extensions, use one protocol-line tag across the package set:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add opentray@stable-A-B @opentray/ext-webview@stable-A-B
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `alpha-A-B` for alpha packages on the same protocol line. Replace `A-B` with the current OpenTray protocol-line tag from `@opentray/spec`; do not mix `latest` and protocol-line tags unless you are debugging install drift.
|
|
18
|
+
|
|
11
19
|
## Role
|
|
12
20
|
|
|
13
21
|
- Expose `createTray()` as the public creation entrypoint.
|
|
@@ -19,6 +27,23 @@ pnpm add opentray
|
|
|
19
27
|
|
|
20
28
|
## Tray-First API
|
|
21
29
|
|
|
30
|
+
For the first app, use `runTrayApp()` from `opentray/node` so the host/worker split stays out of the user's way:
|
|
31
|
+
|
|
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 });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`createTray()` is still the direct tray API when the caller already owns the runtime process shape.
|
|
46
|
+
|
|
22
47
|
```ts
|
|
23
48
|
import { createTray } from "opentray";
|
|
24
49
|
|
|
@@ -46,7 +71,7 @@ tray.onMenuClick(({ itemId }) => {
|
|
|
46
71
|
});
|
|
47
72
|
```
|
|
48
73
|
|
|
49
|
-
Visible tray text belongs to `icon.text`, `icon["text-only"]`, or `icon["icon-text"].text`. The
|
|
74
|
+
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()`.
|
|
50
75
|
|
|
51
76
|
## Runtime Ownership
|
|
52
77
|
|
|
@@ -73,9 +98,10 @@ The `opentray/node` subpath exposes binding-resolution, visible host-loop, and b
|
|
|
73
98
|
|
|
74
99
|
## Examples
|
|
75
100
|
|
|
76
|
-
Run
|
|
101
|
+
Run the quickstart example and the protocol-only example:
|
|
77
102
|
|
|
78
103
|
```bash
|
|
104
|
+
pnpm --filter opentray example:first-app
|
|
79
105
|
pnpm --filter opentray example:basic
|
|
80
106
|
```
|
|
81
107
|
|
|
@@ -102,4 +128,4 @@ pnpm --filter opentray example:mediaQuery
|
|
|
102
128
|
pnpm --filter opentray example:debug-runtime-lynx -- --bundle packages/cli/assets/lynx-review/main.lynx.bundle
|
|
103
129
|
```
|
|
104
130
|
|
|
105
|
-
The example matrix stages the generated Node runtime artifact before `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 visible-binding
|
|
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.
|
package/dist/node.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
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";
|
|
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";
|
|
2
3
|
|
|
3
4
|
//#region src/runtime-binding-transport.d.ts
|
|
4
5
|
type RuntimeBindingTransportKind = "visible" | "headless";
|
|
@@ -21,8 +22,10 @@ declare const createRuntimeBindingTransport: ({
|
|
|
21
22
|
kind
|
|
22
23
|
}?: CreateRuntimeBindingTransportOptions) => Promise<OpenTrayConnection>;
|
|
23
24
|
//#endregion
|
|
24
|
-
//#region src/node.d.ts
|
|
25
|
+
//#region src/node-host.d.ts
|
|
26
|
+
/** Options for resolving the native binding and running the visible host loop. */
|
|
25
27
|
interface RunVisibleRuntimeHostOptions extends ResolveRuntimeBindingOptions, OpenTrayVisibleRuntimeHostOptions {}
|
|
28
|
+
/** Run the visible native host loop on the caller-owned Node main thread. */
|
|
26
29
|
declare const runVisibleRuntimeHost: ({
|
|
27
30
|
platform,
|
|
28
31
|
arch,
|
|
@@ -31,5 +34,37 @@ declare const runVisibleRuntimeHost: ({
|
|
|
31
34
|
...hostOptions
|
|
32
35
|
}?: RunVisibleRuntimeHostOptions) => Promise<void>;
|
|
33
36
|
//#endregion
|
|
34
|
-
|
|
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 };
|
|
35
70
|
//# sourceMappingURL=node.d.mts.map
|
package/dist/node.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.mts","names":[],"sources":["../src/runtime-binding-transport.ts","../src/node.ts"],"mappings":"
|
|
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"}
|
package/dist/node.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
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
|
-
|
|
2
|
+
import { Worker } from "node:worker_threads";
|
|
3
|
+
//#region src/node-host.ts
|
|
4
|
+
/** Run the visible native host loop on the caller-owned Node main thread. */
|
|
3
5
|
const runVisibleRuntimeHost = async ({ platform, arch, resolvePackageJson, nativeLoader, ...hostOptions } = {}) => {
|
|
4
6
|
const binding = await loadOpenTrayRuntimeBinding({
|
|
5
7
|
...platform === void 0 ? {} : { platform },
|
|
@@ -11,6 +13,104 @@ const runVisibleRuntimeHost = async ({ platform, arch, resolvePackageJson, nativ
|
|
|
11
13
|
binding.runVisibleRuntimeHost(hostOptions);
|
|
12
14
|
};
|
|
13
15
|
//#endregion
|
|
14
|
-
|
|
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
115
|
|
|
16
116
|
//# sourceMappingURL=node.mjs.map
|
package/dist/node.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.mjs","names":[],"sources":["../src/node.ts"],"sourcesContent":["import {\n loadOpenTrayRuntimeBinding,\n type OpenTrayVisibleRuntimeHostOptions,\n type ResolveRuntimeBindingOptions,\n} from \"./native-runtime\";\n\nexport interface RunVisibleRuntimeHostOptions\n extends ResolveRuntimeBindingOptions,\n OpenTrayVisibleRuntimeHostOptions {}\n\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":"
|
|
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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opentray",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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.
|
|
31
|
+
"@opentray/spec": "0.10.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"tsdown": "^0.22.1",
|
|
@@ -36,18 +36,19 @@
|
|
|
36
36
|
"vitest": "^4.1.7"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@opentray/darwin-arm64": "0.
|
|
40
|
-
"@opentray/darwin-x64": "0.
|
|
41
|
-
"@opentray/linux-arm64": "0.
|
|
42
|
-
"@opentray/linux-x64": "0.
|
|
43
|
-
"@opentray/windows-arm64": "0.
|
|
44
|
-
"@opentray/windows-x64": "0.
|
|
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"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsdown src/index.ts src/node.ts src/cli.ts --format esm --dts",
|
|
48
48
|
"cli": "bun run src/cli.ts",
|
|
49
49
|
"example:matrix": "bun run examples/example-matrix.ts",
|
|
50
50
|
"example:basic": "bun run examples/basic-tray.ts",
|
|
51
|
+
"example:first-app": "bun run examples/first-app.ts",
|
|
51
52
|
"example:debug-runtime-lynx": "bun run examples/debug-runtime-lynx.ts",
|
|
52
53
|
"example:debug-runtime-tray": "bun run examples/debug-runtime-tray.ts",
|
|
53
54
|
"example:visible-binding": "node examples/visible-binding-host.mjs",
|