@opentray/spec 0.5.0 → 0.7.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 +24 -18
- package/dist/index.d.mts +79 -57
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +46 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,27 +4,33 @@ Shared TypeScript protocol and contract package for OpenTray.
|
|
|
4
4
|
|
|
5
5
|
## Role
|
|
6
6
|
|
|
7
|
-
- Define
|
|
8
|
-
- Define
|
|
9
|
-
- Define public `
|
|
10
|
-
- Keep protocol types reusable by
|
|
7
|
+
- Define newline-delimited JSON protocol payload shapes.
|
|
8
|
+
- Define protocol version and endpoint identity helpers.
|
|
9
|
+
- Define public `App`, `Tray`, `Session`, icon projection, menu, tooltip, and extension contract types.
|
|
10
|
+
- Keep protocol types reusable by `opentray` and official extensions.
|
|
11
11
|
|
|
12
|
-
This package
|
|
12
|
+
This package is platform-neutral and must not import native implementation packages.
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Tray Contract
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
pnpm --filter @opentray/spec example:parse
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Endpoint identity is version-scoped during the current unstable broker stage:
|
|
16
|
+
`TrayOptions` uses `id` as the tray atom identity. Visible tray text belongs to the unified `icon` field:
|
|
23
17
|
|
|
24
18
|
```ts
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
import type { Icon, TrayOptions } from "@opentray/spec";
|
|
20
|
+
|
|
21
|
+
const icon: Icon = {
|
|
22
|
+
type: "file",
|
|
23
|
+
path: "./status.png",
|
|
24
|
+
text: "Status",
|
|
25
|
+
"icon-only": { type: "file", path: "./status-small.png" },
|
|
26
|
+
"text-only": "Status",
|
|
27
|
+
"icon-text": { type: "file", path: "./status.png", text: "Status" },
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const tray: TrayOptions = {
|
|
31
|
+
id: "com.example.status",
|
|
32
|
+
icon,
|
|
33
|
+
};
|
|
30
34
|
```
|
|
35
|
+
|
|
36
|
+
`Space`, `Surface`, `spaceId`, `create-space`, and top-level tray `title` are removed public vocabulary for v0.9.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
//#region src/index.d.ts
|
|
2
2
|
type SessionId = string;
|
|
3
3
|
type RequestId = string;
|
|
4
|
-
type
|
|
4
|
+
type AppId = string;
|
|
5
5
|
type TrayId = string;
|
|
6
6
|
type MenuItemId = number;
|
|
7
|
-
/** @deprecated Use `SessionId`. */
|
|
8
|
-
type LeaseId = SessionId;
|
|
9
|
-
/** @deprecated Use `SpaceId`. */
|
|
10
|
-
type SurfaceId = SpaceId;
|
|
11
7
|
declare const PROTOCOL_VERSION = 1;
|
|
12
8
|
declare const OPENTRAY_PROTOCOL_FAMILY = "opentray-protocol";
|
|
13
9
|
declare const OPENTRAY_PROTOCOL_LINE_MAJOR = 1;
|
|
@@ -44,42 +40,59 @@ declare const formatProtocolDistTag: ({
|
|
|
44
40
|
minor
|
|
45
41
|
}: ProtocolDistTagOptions) => string;
|
|
46
42
|
declare const parseProtocolDistTag: (tag: string) => ProtocolDistTag;
|
|
43
|
+
/**
|
|
44
|
+
* Neutral caller label used when no usable caller identity can be derived.
|
|
45
|
+
* Keeps the broker honest instead of impersonating an unrelated application.
|
|
46
|
+
*/
|
|
47
|
+
declare const DEFAULT_CALLER_LABEL = "opentray";
|
|
48
|
+
/**
|
|
49
|
+
* Maximum length of a sanitized caller label. Keeps socket paths, runtime
|
|
50
|
+
* directory names, and process titles within platform limits.
|
|
51
|
+
*/
|
|
52
|
+
declare const CALLER_LABEL_MAX_LENGTH = 48;
|
|
47
53
|
interface BrokerEndpointIdentity {
|
|
48
54
|
packageVersion: string;
|
|
49
55
|
protocolVersion: number;
|
|
56
|
+
callerLabel: string;
|
|
50
57
|
}
|
|
51
58
|
interface BrokerEndpointIdentityOptions {
|
|
52
59
|
packageVersion: string;
|
|
53
60
|
protocolVersion?: number;
|
|
61
|
+
callerLabel?: string;
|
|
54
62
|
}
|
|
63
|
+
declare const sanitizeCallerLabel: (value: string | undefined) => string;
|
|
55
64
|
declare const createBrokerEndpointIdentity: ({
|
|
56
65
|
packageVersion,
|
|
57
|
-
protocolVersion
|
|
66
|
+
protocolVersion,
|
|
67
|
+
callerLabel
|
|
58
68
|
}: BrokerEndpointIdentityOptions) => BrokerEndpointIdentity;
|
|
59
69
|
declare const isSupportedProtocolVersion: (protocolVersion: number) => boolean;
|
|
60
70
|
declare const formatBrokerEndpointName: (identity: BrokerEndpointIdentity) => string;
|
|
61
71
|
declare const formatBrokerStateRoot: (homeDir: string, identity: BrokerEndpointIdentity) => string;
|
|
62
72
|
declare const formatUnixSocketPath: (homeDir: string, identity: BrokerEndpointIdentity) => string;
|
|
63
73
|
declare const formatWindowsPipeName: (identity: BrokerEndpointIdentity) => string;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Human-readable process title for a broker pinned to a caller. Used by the SDK
|
|
76
|
+
* spawn path so task managers show the owning application, not a generic name.
|
|
77
|
+
*/
|
|
78
|
+
declare const formatBrokerProcessTitle: (identity: BrokerEndpointIdentity) => string;
|
|
79
|
+
interface AppOptions {
|
|
80
|
+
id?: AppId;
|
|
81
|
+
name?: string;
|
|
67
82
|
icon?: Icon;
|
|
68
83
|
default?: boolean;
|
|
69
84
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
interface AppRef {
|
|
86
|
+
appId: AppId;
|
|
87
|
+
}
|
|
88
|
+
interface AppIdentity {
|
|
89
|
+
appId: AppId;
|
|
90
|
+
appName: string;
|
|
74
91
|
}
|
|
75
|
-
/** @deprecated Use `SpaceRef`. */
|
|
76
|
-
type SurfaceRef = SpaceRef;
|
|
77
92
|
interface TrayOptions {
|
|
78
|
-
|
|
79
|
-
appId?: string;
|
|
80
|
-
title?: string;
|
|
93
|
+
id: string;
|
|
81
94
|
tooltip?: Tooltip;
|
|
82
|
-
icon
|
|
95
|
+
icon?: Icon;
|
|
83
96
|
menu?: Menu;
|
|
84
97
|
}
|
|
85
98
|
interface Tooltip {
|
|
@@ -117,7 +130,7 @@ type MenuItem = {
|
|
|
117
130
|
enabled?: boolean;
|
|
118
131
|
items: MenuItem[];
|
|
119
132
|
};
|
|
120
|
-
type
|
|
133
|
+
type IconImage = {
|
|
121
134
|
type: "rgba";
|
|
122
135
|
data: Uint8Array | number[];
|
|
123
136
|
width: number;
|
|
@@ -129,6 +142,18 @@ type Icon = {
|
|
|
129
142
|
type: "file";
|
|
130
143
|
path: string;
|
|
131
144
|
};
|
|
145
|
+
type SimpleIcon = IconImage & {
|
|
146
|
+
text?: string;
|
|
147
|
+
};
|
|
148
|
+
type IconText = IconImage & {
|
|
149
|
+
text: string;
|
|
150
|
+
};
|
|
151
|
+
interface IconCandidates {
|
|
152
|
+
"icon-only"?: IconImage;
|
|
153
|
+
"text-only"?: string;
|
|
154
|
+
"icon-text"?: IconText;
|
|
155
|
+
}
|
|
156
|
+
type Icon = IconCandidates & Partial<SimpleIcon>;
|
|
132
157
|
interface Rect {
|
|
133
158
|
x: number;
|
|
134
159
|
y: number;
|
|
@@ -144,29 +169,29 @@ interface TrayBoundsResult {
|
|
|
144
169
|
type MouseButton = "left" | "right" | "middle";
|
|
145
170
|
type TrayEvent = {
|
|
146
171
|
type: "ready";
|
|
147
|
-
|
|
172
|
+
appId: AppId;
|
|
148
173
|
} | {
|
|
149
174
|
type: "menuClick";
|
|
150
|
-
|
|
175
|
+
appId: AppId;
|
|
151
176
|
trayId: TrayId;
|
|
152
177
|
itemId: MenuItemId;
|
|
153
178
|
} | {
|
|
154
179
|
type: "trayClick";
|
|
155
|
-
|
|
180
|
+
appId: AppId;
|
|
156
181
|
trayId: TrayId;
|
|
157
182
|
button: MouseButton;
|
|
158
183
|
x: number;
|
|
159
184
|
y: number;
|
|
160
185
|
} | {
|
|
161
186
|
type: "trayDoubleClick";
|
|
162
|
-
|
|
187
|
+
appId: AppId;
|
|
163
188
|
trayId: TrayId;
|
|
164
189
|
button: MouseButton;
|
|
165
190
|
x: number;
|
|
166
191
|
y: number;
|
|
167
192
|
};
|
|
168
193
|
interface ExtensionScope {
|
|
169
|
-
|
|
194
|
+
appId: AppId;
|
|
170
195
|
trayId?: TrayId;
|
|
171
196
|
ext: string;
|
|
172
197
|
}
|
|
@@ -174,18 +199,21 @@ interface ExtensionEnvelope<TData = unknown> {
|
|
|
174
199
|
scope: ExtensionScope;
|
|
175
200
|
data: TData;
|
|
176
201
|
}
|
|
177
|
-
interface
|
|
202
|
+
interface RuntimeHostSessionHealth {
|
|
178
203
|
sessionId: number;
|
|
179
|
-
|
|
204
|
+
internalSessionId?: SessionId;
|
|
180
205
|
initialized: boolean;
|
|
181
206
|
}
|
|
182
|
-
interface
|
|
207
|
+
interface RuntimeHostHealth {
|
|
183
208
|
pid: number;
|
|
184
209
|
packageVersion: string;
|
|
185
210
|
protocolVersion: number;
|
|
186
211
|
endpoint: string;
|
|
212
|
+
appId: AppId;
|
|
213
|
+
appName: string;
|
|
214
|
+
callerLabel: string;
|
|
187
215
|
sessionCount: number;
|
|
188
|
-
sessions:
|
|
216
|
+
sessions: RuntimeHostSessionHealth[];
|
|
189
217
|
}
|
|
190
218
|
type ClientFrame = {
|
|
191
219
|
type: "init";
|
|
@@ -195,68 +223,62 @@ type ClientFrame = {
|
|
|
195
223
|
type: "exit";
|
|
196
224
|
};
|
|
197
225
|
type ClientRequestFrame = ({
|
|
198
|
-
type: "create-
|
|
226
|
+
type: "create-app";
|
|
199
227
|
requestId: RequestId;
|
|
200
|
-
} &
|
|
201
|
-
type: "resolve-default-
|
|
228
|
+
} & AppOptions) | {
|
|
229
|
+
type: "resolve-default-app";
|
|
202
230
|
requestId: RequestId;
|
|
203
231
|
} | {
|
|
204
232
|
type: "create-tray";
|
|
205
233
|
requestId: RequestId;
|
|
206
|
-
|
|
234
|
+
app: AppRef;
|
|
207
235
|
tray: TrayOptions;
|
|
208
236
|
} | {
|
|
209
237
|
type: "destroy-tray";
|
|
210
238
|
requestId: RequestId;
|
|
211
|
-
|
|
239
|
+
appId: AppId;
|
|
212
240
|
trayId: TrayId;
|
|
213
241
|
} | {
|
|
214
242
|
type: "get-tray-bounds";
|
|
215
243
|
requestId: RequestId;
|
|
216
|
-
|
|
244
|
+
appId: AppId;
|
|
217
245
|
trayId: TrayId;
|
|
218
246
|
} | {
|
|
219
247
|
type: "set-tray-menu";
|
|
220
248
|
requestId: RequestId;
|
|
221
|
-
|
|
249
|
+
appId: AppId;
|
|
222
250
|
trayId: TrayId;
|
|
223
251
|
menu: Menu;
|
|
224
252
|
} | {
|
|
225
253
|
type: "set-tray-icon";
|
|
226
254
|
requestId: RequestId;
|
|
227
|
-
|
|
255
|
+
appId: AppId;
|
|
228
256
|
trayId: TrayId;
|
|
229
257
|
icon: Icon;
|
|
230
258
|
} | {
|
|
231
259
|
type: "set-tray-tooltip";
|
|
232
260
|
requestId: RequestId;
|
|
233
|
-
|
|
261
|
+
appId: AppId;
|
|
234
262
|
trayId: TrayId;
|
|
235
263
|
tooltip: Tooltip;
|
|
236
|
-
} | {
|
|
237
|
-
type: "set-tray-title";
|
|
238
|
-
requestId: RequestId;
|
|
239
|
-
spaceId: SpaceId;
|
|
240
|
-
trayId: TrayId;
|
|
241
|
-
title: string;
|
|
242
264
|
} | {
|
|
243
265
|
type: "load-ext";
|
|
244
266
|
requestId: RequestId;
|
|
245
|
-
|
|
267
|
+
appId: AppId;
|
|
246
268
|
name: string;
|
|
247
269
|
path: string;
|
|
248
270
|
mountId?: string;
|
|
249
271
|
} | {
|
|
250
272
|
type: "ext-command";
|
|
251
273
|
requestId: RequestId;
|
|
252
|
-
|
|
274
|
+
appId: AppId;
|
|
253
275
|
trayId: TrayId;
|
|
254
276
|
ext: string;
|
|
255
277
|
data: unknown;
|
|
256
278
|
} | {
|
|
257
279
|
type: "unload-ext";
|
|
258
280
|
requestId: RequestId;
|
|
259
|
-
|
|
281
|
+
appId: AppId;
|
|
260
282
|
name: string;
|
|
261
283
|
} | {
|
|
262
284
|
type: "health";
|
|
@@ -268,22 +290,22 @@ type ServerFrame = {
|
|
|
268
290
|
brokerVersion: string;
|
|
269
291
|
sessionId: SessionId;
|
|
270
292
|
} | {
|
|
271
|
-
type: "
|
|
293
|
+
type: "app-created";
|
|
272
294
|
requestId: RequestId;
|
|
273
|
-
|
|
295
|
+
app: AppRef;
|
|
274
296
|
} | {
|
|
275
|
-
type: "default-
|
|
297
|
+
type: "default-app";
|
|
276
298
|
requestId: RequestId;
|
|
277
|
-
|
|
299
|
+
app: AppRef;
|
|
278
300
|
} | {
|
|
279
301
|
type: "tray-created";
|
|
280
302
|
requestId: RequestId;
|
|
281
|
-
|
|
303
|
+
appId: AppId;
|
|
282
304
|
trayId: TrayId;
|
|
283
305
|
} | {
|
|
284
306
|
type: "tray-bounds";
|
|
285
307
|
requestId: RequestId;
|
|
286
|
-
|
|
308
|
+
appId: AppId;
|
|
287
309
|
trayId: TrayId;
|
|
288
310
|
bounds: TrayBoundsResult;
|
|
289
311
|
} | {
|
|
@@ -294,15 +316,15 @@ type ServerFrame = {
|
|
|
294
316
|
requestId: RequestId;
|
|
295
317
|
events: ExtensionEnvelope[];
|
|
296
318
|
} | {
|
|
297
|
-
type: "
|
|
319
|
+
type: "runtime-host-health";
|
|
298
320
|
requestId: RequestId;
|
|
299
|
-
health:
|
|
321
|
+
health: RuntimeHostHealth;
|
|
300
322
|
} | {
|
|
301
323
|
type: "event";
|
|
302
324
|
event: TrayEvent;
|
|
303
325
|
} | {
|
|
304
326
|
type: "ext-event";
|
|
305
|
-
|
|
327
|
+
appId: AppId;
|
|
306
328
|
trayId: TrayId;
|
|
307
329
|
ext: string;
|
|
308
330
|
data: unknown;
|
|
@@ -320,5 +342,5 @@ interface ParseResult<T> {
|
|
|
320
342
|
declare const parseServerFrame: (line: string) => ParseResult<ServerFrame>;
|
|
321
343
|
declare const isServerFrame: (value: unknown) => value is ServerFrame;
|
|
322
344
|
//#endregion
|
|
323
|
-
export { BrokerEndpointIdentity, BrokerEndpointIdentityOptions, ClientFrame, ClientRequestFrame,
|
|
345
|
+
export { AppId, AppIdentity, AppOptions, AppRef, BrokerEndpointIdentity, BrokerEndpointIdentityOptions, CALLER_LABEL_MAX_LENGTH, ClientFrame, ClientRequestFrame, DEFAULT_CALLER_LABEL, ExtensionEnvelope, ExtensionScope, Icon, IconCandidates, IconImage, IconText, Menu, MenuItem, MenuItemId, MouseButton, OPENTRAY_PROTOCOL_FAMILY, OPENTRAY_PROTOCOL_LINE, OPENTRAY_PROTOCOL_LINE_MAJOR, OPENTRAY_PROTOCOL_LINE_MINOR, OpenTrayProtocolLine, PROTOCOL_VERSION, ParseResult, ProtocolDistTag, ProtocolDistTagOptions, ProtocolLineReleaseChannel, Rect, RequestId, RuntimeHostHealth, RuntimeHostSessionHealth, ServerFrame, SessionId, SimpleIcon, Tooltip, TrayBoundsKind, TrayBoundsResult, TrayEvent, TrayId, TrayOptions, compareOpenTrayProtocolLine, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerProcessTitle, formatBrokerStateRoot, formatOpenTrayProtocolLine, formatProtocolDistTag, formatUnixSocketPath, formatWindowsPipeName, isOpenTrayProtocolLineCompatible, isProtocolLineReleaseChannel, isServerFrame, isSupportedProtocolVersion, parseProtocolDistTag, parseServerFrame, protocolLineReleaseChannels, sanitizeCallerLabel };
|
|
324
346
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";KAAY,SAAA;AAAA,KACA,SAAA;AAAA,KACA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -47,26 +47,54 @@ const parseProtocolDistTag = (tag) => {
|
|
|
47
47
|
minor
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Neutral caller label used when no usable caller identity can be derived.
|
|
52
|
+
* Keeps the broker honest instead of impersonating an unrelated application.
|
|
53
|
+
*/
|
|
54
|
+
const DEFAULT_CALLER_LABEL = "opentray";
|
|
55
|
+
/**
|
|
56
|
+
* Maximum length of a sanitized caller label. Keeps socket paths, runtime
|
|
57
|
+
* directory names, and process titles within platform limits.
|
|
58
|
+
*/
|
|
59
|
+
const CALLER_LABEL_MAX_LENGTH = 48;
|
|
60
|
+
const callerLabelAllowedPattern = /[a-z0-9-]+/g;
|
|
61
|
+
const sanitizeCallerLabel = (value) => {
|
|
62
|
+
if (value !== void 0 && typeof value !== "string") throw new Error(`callerLabel must be a string: ${String(value)}`);
|
|
63
|
+
const segments = (value ?? "").toLowerCase().match(callerLabelAllowedPattern);
|
|
64
|
+
if (segments === null || segments.length === 0) return DEFAULT_CALLER_LABEL;
|
|
65
|
+
const trimmed = segments.join("-").replace(/^-+|-+$/gu, "");
|
|
66
|
+
if (trimmed.length === 0) return DEFAULT_CALLER_LABEL;
|
|
67
|
+
return trimmed.slice(0, 48);
|
|
68
|
+
};
|
|
69
|
+
const createBrokerEndpointIdentity = ({ packageVersion, protocolVersion = 1, callerLabel }) => {
|
|
51
70
|
assertEndpointComponent(packageVersion, "packageVersion");
|
|
52
71
|
if (!Number.isInteger(protocolVersion) || protocolVersion <= 0) throw new Error(`protocolVersion must be a positive integer: ${protocolVersion}`);
|
|
53
72
|
return {
|
|
54
73
|
packageVersion,
|
|
55
|
-
protocolVersion
|
|
74
|
+
protocolVersion,
|
|
75
|
+
callerLabel: sanitizeCallerLabel(callerLabel)
|
|
56
76
|
};
|
|
57
77
|
};
|
|
58
78
|
const isSupportedProtocolVersion = (protocolVersion) => protocolVersion === 1;
|
|
59
79
|
const formatBrokerEndpointName = (identity) => {
|
|
60
80
|
assertEndpointIdentity(identity);
|
|
61
|
-
return `opentray-${identity.packageVersion}-p${identity.protocolVersion}`;
|
|
81
|
+
return `opentray-${identity.packageVersion}-p${identity.protocolVersion}-${identity.callerLabel}`;
|
|
62
82
|
};
|
|
63
83
|
const formatBrokerStateRoot = (homeDir, identity) => {
|
|
64
84
|
assertEndpointIdentity(identity);
|
|
65
85
|
if (homeDir.length === 0) throw new Error("homeDir must not be empty");
|
|
66
|
-
return `${homeDir.replace(/[\\/]+$/u, "")}/.opentray/${identity.packageVersion}`;
|
|
86
|
+
return `${homeDir.replace(/[\\/]+$/u, "")}/.opentray/${identity.packageVersion}/${identity.callerLabel}`;
|
|
67
87
|
};
|
|
68
88
|
const formatUnixSocketPath = (homeDir, identity) => `${formatBrokerStateRoot(homeDir, identity)}/opentray-p${identity.protocolVersion}.sock`;
|
|
69
89
|
const formatWindowsPipeName = (identity) => `\\\\.\\pipe\\${formatBrokerEndpointName(identity)}`;
|
|
90
|
+
/**
|
|
91
|
+
* Human-readable process title for a broker pinned to a caller. Used by the SDK
|
|
92
|
+
* spawn path so task managers show the owning application, not a generic name.
|
|
93
|
+
*/
|
|
94
|
+
const formatBrokerProcessTitle = (identity) => {
|
|
95
|
+
assertEndpointIdentity(identity);
|
|
96
|
+
return `opentray · ${identity.callerLabel}`;
|
|
97
|
+
};
|
|
70
98
|
const endpointComponentPattern = /^[0-9A-Za-z._+-]+$/u;
|
|
71
99
|
const assertOpenTrayProtocolLine = (line, name) => {
|
|
72
100
|
assertProtocolLineVersion(line.major, `${name}.major`);
|
|
@@ -109,15 +137,15 @@ const isServerFrame = (value) => {
|
|
|
109
137
|
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
110
138
|
switch (value.type) {
|
|
111
139
|
case "ready": return typeof value.protocolVersion === "number" && typeof value.brokerVersion === "string" && typeof value.sessionId === "string";
|
|
112
|
-
case "
|
|
113
|
-
case "default-
|
|
114
|
-
case "tray-created": return typeof value.requestId === "string" && typeof value.
|
|
115
|
-
case "tray-bounds": return typeof value.requestId === "string" && typeof value.
|
|
140
|
+
case "app-created": return typeof value.requestId === "string" && isRecord(value.app);
|
|
141
|
+
case "default-app": return typeof value.requestId === "string" && isRecord(value.app);
|
|
142
|
+
case "tray-created": return typeof value.requestId === "string" && typeof value.appId === "string" && typeof value.trayId === "string";
|
|
143
|
+
case "tray-bounds": return typeof value.requestId === "string" && typeof value.appId === "string" && typeof value.trayId === "string" && isTrayBoundsResult(value.bounds);
|
|
116
144
|
case "ack": return typeof value.requestId === "string";
|
|
117
145
|
case "ext-command-result": return typeof value.requestId === "string" && Array.isArray(value.events) && value.events.every(isExtensionEnvelope);
|
|
118
|
-
case "
|
|
146
|
+
case "runtime-host-health": return typeof value.requestId === "string" && isRuntimeHostHealth(value.health);
|
|
119
147
|
case "event": return isTrayEvent(value.event);
|
|
120
|
-
case "ext-event": return typeof value.
|
|
148
|
+
case "ext-event": return typeof value.appId === "string" && typeof value.trayId === "string" && typeof value.ext === "string";
|
|
121
149
|
case "error": return (value.requestId === void 0 || typeof value.requestId === "string") && typeof value.code === "string" && typeof value.message === "string";
|
|
122
150
|
default: return false;
|
|
123
151
|
}
|
|
@@ -125,27 +153,27 @@ const isServerFrame = (value) => {
|
|
|
125
153
|
const isExtensionEnvelope = (value) => {
|
|
126
154
|
if (!isRecord(value) || !isRecord(value.scope)) return false;
|
|
127
155
|
const scope = value.scope;
|
|
128
|
-
return
|
|
156
|
+
return typeof scope.appId === "string" && (scope.trayId === void 0 || typeof scope.trayId === "string") && typeof scope.ext === "string" && "data" in value;
|
|
129
157
|
};
|
|
130
|
-
const
|
|
158
|
+
const isRuntimeHostHealth = (value) => {
|
|
131
159
|
if (!isRecord(value)) return false;
|
|
132
|
-
return typeof value.pid === "number" && typeof value.packageVersion === "string" && typeof value.protocolVersion === "number" && typeof value.endpoint === "string" && typeof value.sessionCount === "number" && Array.isArray(value.sessions) && value.sessions.every(
|
|
160
|
+
return typeof value.pid === "number" && typeof value.packageVersion === "string" && typeof value.protocolVersion === "number" && typeof value.endpoint === "string" && typeof value.appId === "string" && typeof value.appName === "string" && typeof value.callerLabel === "string" && typeof value.sessionCount === "number" && Array.isArray(value.sessions) && value.sessions.every(isRuntimeHostSessionHealth);
|
|
133
161
|
};
|
|
134
|
-
const
|
|
162
|
+
const isRuntimeHostSessionHealth = (value) => isRecord(value) && typeof value.sessionId === "number" && (value.internalSessionId === void 0 || typeof value.internalSessionId === "string") && typeof value.initialized === "boolean";
|
|
135
163
|
const isRect = (value) => isRecord(value) && typeof value.x === "number" && typeof value.y === "number" && typeof value.width === "number" && typeof value.height === "number";
|
|
136
164
|
const isTrayBoundsResult = (value) => isRecord(value) && (value.kind === "native" || value.kind === "inferred" || value.kind === "unavailable") && typeof value.source === "string" && (value.rect === null || isRect(value.rect));
|
|
137
165
|
const isTrayEvent = (value) => {
|
|
138
166
|
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
139
167
|
switch (value.type) {
|
|
140
|
-
case "ready": return typeof value.
|
|
141
|
-
case "menuClick": return typeof value.
|
|
168
|
+
case "ready": return typeof value.appId === "string";
|
|
169
|
+
case "menuClick": return typeof value.appId === "string" && typeof value.trayId === "string" && typeof value.itemId === "number";
|
|
142
170
|
case "trayClick":
|
|
143
|
-
case "trayDoubleClick": return typeof value.
|
|
171
|
+
case "trayDoubleClick": return typeof value.appId === "string" && typeof value.trayId === "string" && isMouseButton(value.button) && typeof value.x === "number" && typeof value.y === "number";
|
|
144
172
|
default: return false;
|
|
145
173
|
}
|
|
146
174
|
};
|
|
147
175
|
const isMouseButton = (value) => value === "left" || value === "right" || value === "middle";
|
|
148
176
|
//#endregion
|
|
149
|
-
export { OPENTRAY_PROTOCOL_FAMILY, OPENTRAY_PROTOCOL_LINE, OPENTRAY_PROTOCOL_LINE_MAJOR, OPENTRAY_PROTOCOL_LINE_MINOR, PROTOCOL_VERSION, compareOpenTrayProtocolLine, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerStateRoot, formatOpenTrayProtocolLine, formatProtocolDistTag, formatUnixSocketPath, formatWindowsPipeName, isOpenTrayProtocolLineCompatible, isProtocolLineReleaseChannel, isServerFrame, isSupportedProtocolVersion, parseProtocolDistTag, parseServerFrame, protocolLineReleaseChannels };
|
|
177
|
+
export { CALLER_LABEL_MAX_LENGTH, DEFAULT_CALLER_LABEL, OPENTRAY_PROTOCOL_FAMILY, OPENTRAY_PROTOCOL_LINE, OPENTRAY_PROTOCOL_LINE_MAJOR, OPENTRAY_PROTOCOL_LINE_MINOR, PROTOCOL_VERSION, compareOpenTrayProtocolLine, createBrokerEndpointIdentity, formatBrokerEndpointName, formatBrokerProcessTitle, formatBrokerStateRoot, formatOpenTrayProtocolLine, formatProtocolDistTag, formatUnixSocketPath, formatWindowsPipeName, isOpenTrayProtocolLineCompatible, isProtocolLineReleaseChannel, isServerFrame, isSupportedProtocolVersion, parseProtocolDistTag, parseServerFrame, protocolLineReleaseChannels, sanitizeCallerLabel };
|
|
150
178
|
|
|
151
179
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export type SessionId = string;\nexport type RequestId = string;\nexport type SpaceId = string;\nexport type TrayId = string;\nexport type MenuItemId = number;\n\n/** @deprecated Use `SessionId`. */\nexport type LeaseId = SessionId;\n/** @deprecated Use `SpaceId`. */\nexport type SurfaceId = SpaceId;\n\nexport const PROTOCOL_VERSION = 1;\nexport const OPENTRAY_PROTOCOL_FAMILY = \"opentray-protocol\";\nexport const OPENTRAY_PROTOCOL_LINE_MAJOR = 1;\nexport const OPENTRAY_PROTOCOL_LINE_MINOR = 1;\n\nexport const protocolLineReleaseChannels = [\"stable\", \"alpha\"] as const;\nexport type ProtocolLineReleaseChannel = (typeof protocolLineReleaseChannels)[number];\n\nexport interface OpenTrayProtocolLine {\n family: typeof OPENTRAY_PROTOCOL_FAMILY;\n major: number;\n minor: number;\n}\n\nexport interface ProtocolDistTagOptions {\n channel: ProtocolLineReleaseChannel;\n major?: number;\n minor?: number;\n}\n\nexport interface ProtocolDistTag {\n channel: ProtocolLineReleaseChannel;\n major: number;\n minor: number;\n}\n\nexport const OPENTRAY_PROTOCOL_LINE: OpenTrayProtocolLine = {\n family: OPENTRAY_PROTOCOL_FAMILY,\n major: OPENTRAY_PROTOCOL_LINE_MAJOR,\n minor: OPENTRAY_PROTOCOL_LINE_MINOR,\n};\n\n// Install-time protocol lines can advance by minor version while runtime authority stays numeric.\nexport const compareOpenTrayProtocolLine = (\n left: OpenTrayProtocolLine,\n right: OpenTrayProtocolLine,\n): number => {\n assertOpenTrayProtocolLine(left, \"left\");\n assertOpenTrayProtocolLine(right, \"right\");\n if (left.major !== right.major) {\n return left.major - right.major;\n }\n return left.minor - right.minor;\n};\n\nexport const isOpenTrayProtocolLineCompatible = (\n supported: OpenTrayProtocolLine,\n required: OpenTrayProtocolLine,\n): boolean => {\n assertOpenTrayProtocolLine(supported, \"supported\");\n assertOpenTrayProtocolLine(required, \"required\");\n return supported.major === required.major && supported.minor >= required.minor;\n};\n\nexport const formatOpenTrayProtocolLine = ({\n family,\n major,\n minor,\n}: OpenTrayProtocolLine = OPENTRAY_PROTOCOL_LINE): string => {\n assertProtocolLineVersion(major, \"major\");\n assertProtocolLineVersion(minor, \"minor\");\n return `${family}/${major}.${minor}`;\n};\n\nexport const isProtocolLineReleaseChannel = (value: string): value is ProtocolLineReleaseChannel =>\n protocolLineReleaseChannels.includes(value as ProtocolLineReleaseChannel);\n\nexport const formatProtocolDistTag = ({\n channel,\n major = OPENTRAY_PROTOCOL_LINE_MAJOR,\n minor = OPENTRAY_PROTOCOL_LINE_MINOR,\n}: ProtocolDistTagOptions): string => {\n assertProtocolLineReleaseChannel(channel);\n assertProtocolLineVersion(major, \"major\");\n assertProtocolLineVersion(minor, \"minor\");\n return `${channel}-${major}-${minor}`;\n};\n\nexport const parseProtocolDistTag = (tag: string): ProtocolDistTag => {\n const match = /^(?<channel>[a-z]+)-(?<major>\\d+)-(?<minor>\\d+)$/u.exec(tag);\n const groups = match?.groups;\n if (groups === undefined) {\n throw new Error(`invalid OpenTray protocol dist-tag: ${tag}`);\n }\n const channel = groups.channel;\n if (channel === undefined || !isProtocolLineReleaseChannel(channel)) {\n throw new Error(`unsupported OpenTray protocol dist-tag channel: ${channel ?? \"\"}`);\n }\n const major = Number(groups.major);\n const minor = Number(groups.minor);\n assertProtocolLineVersion(major, \"major\");\n assertProtocolLineVersion(minor, \"minor\");\n return { channel, major, minor };\n};\n\nexport interface BrokerEndpointIdentity {\n packageVersion: string;\n protocolVersion: number;\n}\n\nexport interface BrokerEndpointIdentityOptions {\n packageVersion: string;\n protocolVersion?: number;\n}\n\nexport const createBrokerEndpointIdentity = ({\n packageVersion,\n protocolVersion = PROTOCOL_VERSION,\n}: BrokerEndpointIdentityOptions): BrokerEndpointIdentity => {\n assertEndpointComponent(packageVersion, \"packageVersion\");\n if (!Number.isInteger(protocolVersion) || protocolVersion <= 0) {\n throw new Error(`protocolVersion must be a positive integer: ${protocolVersion}`);\n }\n\n return {\n packageVersion,\n protocolVersion,\n };\n};\n\nexport const isSupportedProtocolVersion = (protocolVersion: number): boolean =>\n protocolVersion === PROTOCOL_VERSION;\n\nexport const formatBrokerEndpointName = (identity: BrokerEndpointIdentity): string => {\n assertEndpointIdentity(identity);\n return `opentray-${identity.packageVersion}-p${identity.protocolVersion}`;\n};\n\nexport const formatBrokerStateRoot = (homeDir: string, identity: BrokerEndpointIdentity): string => {\n assertEndpointIdentity(identity);\n if (homeDir.length === 0) {\n throw new Error(\"homeDir must not be empty\");\n }\n\n const normalizedHome = homeDir.replace(/[\\\\/]+$/u, \"\");\n return `${normalizedHome}/.opentray/${identity.packageVersion}`;\n};\n\nexport const formatUnixSocketPath = (homeDir: string, identity: BrokerEndpointIdentity): string =>\n `${formatBrokerStateRoot(homeDir, identity)}/opentray-p${identity.protocolVersion}.sock`;\n\nexport const formatWindowsPipeName = (identity: BrokerEndpointIdentity): string =>\n `\\\\\\\\.\\\\pipe\\\\${formatBrokerEndpointName(identity)}`;\n\nconst endpointComponentPattern = /^[0-9A-Za-z._+-]+$/u;\n\nconst assertOpenTrayProtocolLine = (line: OpenTrayProtocolLine, name: string): void => {\n assertProtocolLineVersion(line.major, `${name}.major`);\n assertProtocolLineVersion(line.minor, `${name}.minor`);\n};\n\nconst assertProtocolLineReleaseChannel = (channel: string): void => {\n if (!isProtocolLineReleaseChannel(channel)) {\n throw new Error(`unsupported OpenTray protocol release channel: ${channel}`);\n }\n};\n\nconst assertProtocolLineVersion = (value: number, name: string): void => {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`protocol line ${name} must be a non-negative integer: ${value}`);\n }\n};\n\nconst assertEndpointIdentity = (identity: BrokerEndpointIdentity): void => {\n assertEndpointComponent(identity.packageVersion, \"packageVersion\");\n if (!Number.isInteger(identity.protocolVersion) || identity.protocolVersion <= 0) {\n throw new Error(`protocolVersion must be a positive integer: ${identity.protocolVersion}`);\n }\n};\n\nconst assertEndpointComponent = (value: string, name: string): void => {\n if (value.length === 0) {\n throw new Error(`${name} must not be empty`);\n }\n if (!endpointComponentPattern.test(value)) {\n throw new Error(`${name} contains invalid endpoint characters: ${value}`);\n }\n};\n\nexport interface SpaceOptions {\n id?: SpaceId;\n title?: string;\n icon?: Icon;\n default?: boolean;\n}\n\n/** @deprecated Use `SpaceOptions`. */\nexport type SurfaceOptions = SpaceOptions;\n\nexport interface SpaceRef {\n spaceId: SpaceId;\n}\n\n/** @deprecated Use `SpaceRef`. */\nexport type SurfaceRef = SpaceRef;\n\nexport interface TrayOptions {\n trayId?: TrayId;\n appId?: string;\n title?: string;\n tooltip?: Tooltip;\n icon: Icon;\n menu?: Menu;\n}\n\nexport interface Tooltip {\n title: string;\n description: string;\n}\n\nexport interface Menu {\n items: MenuItem[];\n}\n\nexport type MenuItem =\n | {\n type: \"item\";\n id: MenuItemId;\n title: string;\n primaryEvent?: boolean;\n enabled?: boolean;\n shortcut?: string;\n }\n | {\n type: \"check\";\n id: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n }\n | {\n type: \"radio\";\n id: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n group: number;\n }\n | {\n type: \"separator\";\n }\n | {\n type: \"submenu\";\n title: string;\n enabled?: boolean;\n items: MenuItem[];\n };\n\nexport type Icon =\n | { type: \"rgba\"; data: Uint8Array | number[]; width: number; height: number }\n | { type: \"encoded\"; data: Uint8Array | number[] }\n | { type: \"file\"; path: string };\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport type TrayBoundsKind = \"native\" | \"inferred\" | \"unavailable\";\n\nexport interface TrayBoundsResult {\n kind: TrayBoundsKind;\n source: string;\n rect: Rect | null;\n}\n\nexport type MouseButton = \"left\" | \"right\" | \"middle\";\n\nexport type TrayEvent =\n | { type: \"ready\"; spaceId: SpaceId }\n | { type: \"menuClick\"; spaceId: SpaceId; trayId: TrayId; itemId: MenuItemId }\n | { type: \"trayClick\"; spaceId: SpaceId; trayId: TrayId; button: MouseButton; x: number; y: number }\n | { type: \"trayDoubleClick\"; spaceId: SpaceId; trayId: TrayId; button: MouseButton; x: number; y: number };\n\nexport interface ExtensionScope {\n spaceId: SpaceId;\n trayId?: TrayId;\n ext: string;\n}\n\nexport interface ExtensionEnvelope<TData = unknown> {\n scope: ExtensionScope;\n data: TData;\n}\n\nexport interface DaemonSessionHealth {\n sessionId: number;\n internalLeaseId?: SessionId;\n initialized: boolean;\n}\n\nexport interface DaemonHealth {\n pid: number;\n packageVersion: string;\n protocolVersion: number;\n endpoint: string;\n sessionCount: number;\n sessions: DaemonSessionHealth[];\n}\n\nexport type ClientFrame =\n | { type: \"init\"; protocolVersion: number; clientVersion: string }\n | ClientRequestFrame\n | { type: \"exit\" };\n\nexport type ClientRequestFrame =\n | ({ type: \"create-space\"; requestId: RequestId } & SpaceOptions)\n | { type: \"resolve-default-space\"; requestId: RequestId }\n | { type: \"create-tray\"; requestId: RequestId; space: SpaceRef; tray: TrayOptions }\n | { type: \"destroy-tray\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId }\n | { type: \"get-tray-bounds\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId }\n | { type: \"set-tray-menu\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId; menu: Menu }\n | { type: \"set-tray-icon\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId; icon: Icon }\n | { type: \"set-tray-tooltip\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId; tooltip: Tooltip }\n | { type: \"set-tray-title\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId; title: string }\n | { type: \"load-ext\"; requestId: RequestId; spaceId: SpaceId; name: string; path: string; mountId?: string }\n | { type: \"ext-command\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId; ext: string; data: unknown }\n | { type: \"unload-ext\"; requestId: RequestId; spaceId: SpaceId; name: string }\n | { type: \"health\"; requestId: RequestId };\n\nexport type ServerFrame =\n | { type: \"ready\"; protocolVersion: number; brokerVersion: string; sessionId: SessionId }\n | { type: \"space-created\"; requestId: RequestId; space: SpaceRef }\n | { type: \"default-space\"; requestId: RequestId; space: SpaceRef }\n | { type: \"tray-created\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId }\n | { type: \"tray-bounds\"; requestId: RequestId; spaceId: SpaceId; trayId: TrayId; bounds: TrayBoundsResult }\n | { type: \"ack\"; requestId: RequestId }\n | { type: \"ext-command-result\"; requestId: RequestId; events: ExtensionEnvelope[] }\n | { type: \"daemon-health\"; requestId: RequestId; health: DaemonHealth }\n | { type: \"event\"; event: TrayEvent }\n | { type: \"ext-event\"; spaceId: SpaceId; trayId: TrayId; ext: string; data: unknown }\n | { type: \"error\"; requestId?: RequestId; code: string; message: string };\n\nexport interface ParseResult<T> {\n ok: boolean;\n frame?: T;\n error?: string;\n}\n\nexport const parseServerFrame = (line: string): ParseResult<ServerFrame> => {\n try {\n const value: unknown = JSON.parse(line);\n if (!isServerFrame(value)) {\n return { ok: false, error: \"invalid server frame\" };\n }\n return { ok: true, frame: value };\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : \"unknown parse error\",\n };\n }\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport const isServerFrame = (value: unknown): value is ServerFrame => {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"ready\":\n return (\n typeof value.protocolVersion === \"number\" &&\n typeof value.brokerVersion === \"string\" &&\n typeof value.sessionId === \"string\"\n );\n case \"space-created\":\n return typeof value.requestId === \"string\" && isRecord(value.space);\n case \"default-space\":\n return typeof value.requestId === \"string\" && isRecord(value.space);\n case \"tray-created\":\n return (\n typeof value.requestId === \"string\" &&\n typeof value.spaceId === \"string\" &&\n typeof value.trayId === \"string\"\n );\n case \"tray-bounds\":\n return (\n typeof value.requestId === \"string\" &&\n typeof value.spaceId === \"string\" &&\n typeof value.trayId === \"string\" &&\n isTrayBoundsResult(value.bounds)\n );\n case \"ack\":\n return typeof value.requestId === \"string\";\n case \"ext-command-result\":\n return typeof value.requestId === \"string\" && Array.isArray(value.events) && value.events.every(isExtensionEnvelope);\n case \"daemon-health\":\n return typeof value.requestId === \"string\" && isDaemonHealth(value.health);\n case \"event\":\n return isTrayEvent(value.event);\n case \"ext-event\":\n return (\n typeof value.spaceId === \"string\" &&\n typeof value.trayId === \"string\" &&\n typeof value.ext === \"string\"\n );\n case \"error\":\n return (\n (value.requestId === undefined || typeof value.requestId === \"string\") &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n default:\n return false;\n }\n};\n\nconst isExtensionEnvelope = (value: unknown): value is ExtensionEnvelope => {\n if (!isRecord(value) || !isRecord(value.scope)) {\n return false;\n }\n const scope = value.scope as Record<string, unknown>;\n return (\n (typeof scope.spaceId === \"string\" || typeof scope.surfaceId === \"string\") &&\n (scope.trayId === undefined || typeof scope.trayId === \"string\") &&\n typeof scope.ext === \"string\" &&\n \"data\" in value\n );\n};\n\nconst isDaemonHealth = (value: unknown): value is DaemonHealth => {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n typeof value.pid === \"number\" &&\n typeof value.packageVersion === \"string\" &&\n typeof value.protocolVersion === \"number\" &&\n typeof value.endpoint === \"string\" &&\n typeof value.sessionCount === \"number\" &&\n Array.isArray(value.sessions) &&\n value.sessions.every(isDaemonSessionHealth)\n );\n};\n\nconst isDaemonSessionHealth = (value: unknown): value is DaemonSessionHealth =>\n isRecord(value) &&\n typeof value.sessionId === \"number\" &&\n (value.internalLeaseId === undefined || typeof value.internalLeaseId === \"string\") &&\n typeof value.initialized === \"boolean\";\n\nconst isRect = (value: unknown): value is Rect =>\n isRecord(value) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\" &&\n typeof value.width === \"number\" &&\n typeof value.height === \"number\";\n\nconst isTrayBoundsResult = (value: unknown): value is TrayBoundsResult =>\n isRecord(value) &&\n (value.kind === \"native\" || value.kind === \"inferred\" || value.kind === \"unavailable\") &&\n typeof value.source === \"string\" &&\n (value.rect === null || isRect(value.rect));\n\nconst isTrayEvent = (value: unknown): value is TrayEvent => {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"ready\":\n return typeof value.spaceId === \"string\";\n case \"menuClick\":\n return (\n typeof value.spaceId === \"string\" &&\n typeof value.trayId === \"string\" &&\n typeof value.itemId === \"number\"\n );\n case \"trayClick\":\n case \"trayDoubleClick\":\n return (\n typeof value.spaceId === \"string\" &&\n typeof value.trayId === \"string\" &&\n isMouseButton(value.button) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\"\n );\n default:\n return false;\n }\n};\n\nconst isMouseButton = (value: unknown): value is MouseButton =>\n value === \"left\" || value === \"right\" || value === \"middle\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export type SessionId = string;\nexport type RequestId = string;\nexport type AppId = string;\nexport type TrayId = string;\nexport type MenuItemId = number;\n\nexport const PROTOCOL_VERSION = 1;\nexport const OPENTRAY_PROTOCOL_FAMILY = \"opentray-protocol\";\nexport const OPENTRAY_PROTOCOL_LINE_MAJOR = 1;\nexport const OPENTRAY_PROTOCOL_LINE_MINOR = 1;\n\nexport const protocolLineReleaseChannels = [\"stable\", \"alpha\"] as const;\nexport type ProtocolLineReleaseChannel =\n (typeof protocolLineReleaseChannels)[number];\n\nexport interface OpenTrayProtocolLine {\n family: typeof OPENTRAY_PROTOCOL_FAMILY;\n major: number;\n minor: number;\n}\n\nexport interface ProtocolDistTagOptions {\n channel: ProtocolLineReleaseChannel;\n major?: number;\n minor?: number;\n}\n\nexport interface ProtocolDistTag {\n channel: ProtocolLineReleaseChannel;\n major: number;\n minor: number;\n}\n\nexport const OPENTRAY_PROTOCOL_LINE: OpenTrayProtocolLine = {\n family: OPENTRAY_PROTOCOL_FAMILY,\n major: OPENTRAY_PROTOCOL_LINE_MAJOR,\n minor: OPENTRAY_PROTOCOL_LINE_MINOR,\n};\n\n// Install-time protocol lines can advance by minor version while runtime authority stays numeric.\nexport const compareOpenTrayProtocolLine = (\n left: OpenTrayProtocolLine,\n right: OpenTrayProtocolLine\n): number => {\n assertOpenTrayProtocolLine(left, \"left\");\n assertOpenTrayProtocolLine(right, \"right\");\n if (left.major !== right.major) {\n return left.major - right.major;\n }\n return left.minor - right.minor;\n};\n\nexport const isOpenTrayProtocolLineCompatible = (\n supported: OpenTrayProtocolLine,\n required: OpenTrayProtocolLine\n): boolean => {\n assertOpenTrayProtocolLine(supported, \"supported\");\n assertOpenTrayProtocolLine(required, \"required\");\n return (\n supported.major === required.major && supported.minor >= required.minor\n );\n};\n\nexport const formatOpenTrayProtocolLine = ({\n family,\n major,\n minor,\n}: OpenTrayProtocolLine = OPENTRAY_PROTOCOL_LINE): string => {\n assertProtocolLineVersion(major, \"major\");\n assertProtocolLineVersion(minor, \"minor\");\n return `${family}/${major}.${minor}`;\n};\n\nexport const isProtocolLineReleaseChannel = (\n value: string\n): value is ProtocolLineReleaseChannel =>\n protocolLineReleaseChannels.includes(value as ProtocolLineReleaseChannel);\n\nexport const formatProtocolDistTag = ({\n channel,\n major = OPENTRAY_PROTOCOL_LINE_MAJOR,\n minor = OPENTRAY_PROTOCOL_LINE_MINOR,\n}: ProtocolDistTagOptions): string => {\n assertProtocolLineReleaseChannel(channel);\n assertProtocolLineVersion(major, \"major\");\n assertProtocolLineVersion(minor, \"minor\");\n return `${channel}-${major}-${minor}`;\n};\n\nexport const parseProtocolDistTag = (tag: string): ProtocolDistTag => {\n const match = /^(?<channel>[a-z]+)-(?<major>\\d+)-(?<minor>\\d+)$/u.exec(tag);\n const groups = match?.groups;\n if (groups === undefined) {\n throw new Error(`invalid OpenTray protocol dist-tag: ${tag}`);\n }\n const channel = groups.channel;\n if (channel === undefined || !isProtocolLineReleaseChannel(channel)) {\n throw new Error(\n `unsupported OpenTray protocol dist-tag channel: ${channel ?? \"\"}`\n );\n }\n const major = Number(groups.major);\n const minor = Number(groups.minor);\n assertProtocolLineVersion(major, \"major\");\n assertProtocolLineVersion(minor, \"minor\");\n return { channel, major, minor };\n};\n\n/**\n * Neutral caller label used when no usable caller identity can be derived.\n * Keeps the broker honest instead of impersonating an unrelated application.\n */\nexport const DEFAULT_CALLER_LABEL = \"opentray\";\n\n/**\n * Maximum length of a sanitized caller label. Keeps socket paths, runtime\n * directory names, and process titles within platform limits.\n */\nexport const CALLER_LABEL_MAX_LENGTH = 48;\n\nconst callerLabelAllowedPattern = /[a-z0-9-]+/g;\n\nexport interface BrokerEndpointIdentity {\n packageVersion: string;\n protocolVersion: number;\n callerLabel: string;\n}\n\nexport interface BrokerEndpointIdentityOptions {\n packageVersion: string;\n protocolVersion?: number;\n callerLabel?: string;\n}\n\nexport const sanitizeCallerLabel = (value: string | undefined): string => {\n if (value !== undefined && typeof value !== \"string\") {\n throw new Error(`callerLabel must be a string: ${String(value)}`);\n }\n const raw = value ?? \"\";\n const lowered = raw.toLowerCase();\n const segments = lowered.match(callerLabelAllowedPattern);\n if (segments === null || segments.length === 0) {\n return DEFAULT_CALLER_LABEL;\n }\n const joined = segments.join(\"-\");\n const trimmed = joined.replace(/^-+|-+$/gu, \"\");\n if (trimmed.length === 0) {\n return DEFAULT_CALLER_LABEL;\n }\n return trimmed.slice(0, CALLER_LABEL_MAX_LENGTH);\n};\n\nexport const createBrokerEndpointIdentity = ({\n packageVersion,\n protocolVersion = PROTOCOL_VERSION,\n callerLabel,\n}: BrokerEndpointIdentityOptions): BrokerEndpointIdentity => {\n assertEndpointComponent(packageVersion, \"packageVersion\");\n if (!Number.isInteger(protocolVersion) || protocolVersion <= 0) {\n throw new Error(\n `protocolVersion must be a positive integer: ${protocolVersion}`\n );\n }\n\n return {\n packageVersion,\n protocolVersion,\n callerLabel: sanitizeCallerLabel(callerLabel),\n };\n};\n\nexport const isSupportedProtocolVersion = (protocolVersion: number): boolean =>\n protocolVersion === PROTOCOL_VERSION;\n\nexport const formatBrokerEndpointName = (\n identity: BrokerEndpointIdentity\n): string => {\n assertEndpointIdentity(identity);\n return `opentray-${identity.packageVersion}-p${identity.protocolVersion}-${identity.callerLabel}`;\n};\n\nexport const formatBrokerStateRoot = (\n homeDir: string,\n identity: BrokerEndpointIdentity\n): string => {\n assertEndpointIdentity(identity);\n if (homeDir.length === 0) {\n throw new Error(\"homeDir must not be empty\");\n }\n\n const normalizedHome = homeDir.replace(/[\\\\/]+$/u, \"\");\n return `${normalizedHome}/.opentray/${identity.packageVersion}/${identity.callerLabel}`;\n};\n\nexport const formatUnixSocketPath = (\n homeDir: string,\n identity: BrokerEndpointIdentity\n): string =>\n `${formatBrokerStateRoot(homeDir, identity)}/opentray-p${\n identity.protocolVersion\n }.sock`;\n\nexport const formatWindowsPipeName = (\n identity: BrokerEndpointIdentity\n): string => `\\\\\\\\.\\\\pipe\\\\${formatBrokerEndpointName(identity)}`;\n\n/**\n * Human-readable process title for a broker pinned to a caller. Used by the SDK\n * spawn path so task managers show the owning application, not a generic name.\n */\nexport const formatBrokerProcessTitle = (\n identity: BrokerEndpointIdentity\n): string => {\n assertEndpointIdentity(identity);\n return `opentray · ${identity.callerLabel}`;\n};\n\nconst endpointComponentPattern = /^[0-9A-Za-z._+-]+$/u;\n\nconst assertOpenTrayProtocolLine = (\n line: OpenTrayProtocolLine,\n name: string\n): void => {\n assertProtocolLineVersion(line.major, `${name}.major`);\n assertProtocolLineVersion(line.minor, `${name}.minor`);\n};\n\nconst assertProtocolLineReleaseChannel = (channel: string): void => {\n if (!isProtocolLineReleaseChannel(channel)) {\n throw new Error(\n `unsupported OpenTray protocol release channel: ${channel}`\n );\n }\n};\n\nconst assertProtocolLineVersion = (value: number, name: string): void => {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(\n `protocol line ${name} must be a non-negative integer: ${value}`\n );\n }\n};\n\nconst assertEndpointIdentity = (identity: BrokerEndpointIdentity): void => {\n assertEndpointComponent(identity.packageVersion, \"packageVersion\");\n if (\n !Number.isInteger(identity.protocolVersion) ||\n identity.protocolVersion <= 0\n ) {\n throw new Error(\n `protocolVersion must be a positive integer: ${identity.protocolVersion}`\n );\n }\n};\n\nconst assertEndpointComponent = (value: string, name: string): void => {\n if (value.length === 0) {\n throw new Error(`${name} must not be empty`);\n }\n if (!endpointComponentPattern.test(value)) {\n throw new Error(`${name} contains invalid endpoint characters: ${value}`);\n }\n};\n\nexport interface AppOptions {\n id?: AppId;\n name?: string;\n icon?: Icon;\n default?: boolean;\n}\n\nexport interface AppRef {\n appId: AppId;\n}\n\nexport interface AppIdentity {\n appId: AppId;\n appName: string;\n}\n\nexport interface TrayOptions {\n id: string;\n tooltip?: Tooltip;\n icon?: Icon;\n menu?: Menu;\n}\n\nexport interface Tooltip {\n title: string;\n description: string;\n}\n\nexport interface Menu {\n items: MenuItem[];\n}\n\nexport type MenuItem =\n | {\n type: \"item\";\n id: MenuItemId;\n title: string;\n primaryEvent?: boolean;\n enabled?: boolean;\n shortcut?: string;\n }\n | {\n type: \"check\";\n id: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n }\n | {\n type: \"radio\";\n id: MenuItemId;\n title: string;\n enabled?: boolean;\n checked?: boolean;\n group: number;\n }\n | {\n type: \"separator\";\n }\n | {\n type: \"submenu\";\n title: string;\n enabled?: boolean;\n items: MenuItem[];\n };\n\nexport type IconImage =\n | { type: \"rgba\"; data: Uint8Array | number[]; width: number; height: number }\n | { type: \"encoded\"; data: Uint8Array | number[] }\n | { type: \"file\"; path: string };\n\nexport type SimpleIcon = IconImage & { text?: string };\n\nexport type IconText = IconImage & { text: string };\n\nexport interface IconCandidates {\n \"icon-only\"?: IconImage;\n \"text-only\"?: string;\n \"icon-text\"?: IconText;\n}\n\nexport type Icon = IconCandidates & Partial<SimpleIcon>;\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport type TrayBoundsKind = \"native\" | \"inferred\" | \"unavailable\";\n\nexport interface TrayBoundsResult {\n kind: TrayBoundsKind;\n source: string;\n rect: Rect | null;\n}\n\nexport type MouseButton = \"left\" | \"right\" | \"middle\";\n\nexport type TrayEvent =\n | { type: \"ready\"; appId: AppId }\n | { type: \"menuClick\"; appId: AppId; trayId: TrayId; itemId: MenuItemId }\n | {\n type: \"trayClick\";\n appId: AppId;\n trayId: TrayId;\n button: MouseButton;\n x: number;\n y: number;\n }\n | {\n type: \"trayDoubleClick\";\n appId: AppId;\n trayId: TrayId;\n button: MouseButton;\n x: number;\n y: number;\n };\n\nexport interface ExtensionScope {\n appId: AppId;\n trayId?: TrayId;\n ext: string;\n}\n\nexport interface ExtensionEnvelope<TData = unknown> {\n scope: ExtensionScope;\n data: TData;\n}\n\nexport interface RuntimeHostSessionHealth {\n sessionId: number;\n internalSessionId?: SessionId;\n initialized: boolean;\n}\n\nexport interface RuntimeHostHealth {\n pid: number;\n packageVersion: string;\n protocolVersion: number;\n endpoint: string;\n appId: AppId;\n appName: string;\n callerLabel: string;\n sessionCount: number;\n sessions: RuntimeHostSessionHealth[];\n}\n\nexport type ClientFrame =\n | { type: \"init\"; protocolVersion: number; clientVersion: string }\n | ClientRequestFrame\n | { type: \"exit\" };\n\nexport type ClientRequestFrame =\n | ({ type: \"create-app\"; requestId: RequestId } & AppOptions)\n | { type: \"resolve-default-app\"; requestId: RequestId }\n | {\n type: \"create-tray\";\n requestId: RequestId;\n app: AppRef;\n tray: TrayOptions;\n }\n | { type: \"destroy-tray\"; requestId: RequestId; appId: AppId; trayId: TrayId }\n | {\n type: \"get-tray-bounds\";\n requestId: RequestId;\n appId: AppId;\n trayId: TrayId;\n }\n | {\n type: \"set-tray-menu\";\n requestId: RequestId;\n appId: AppId;\n trayId: TrayId;\n menu: Menu;\n }\n | {\n type: \"set-tray-icon\";\n requestId: RequestId;\n appId: AppId;\n trayId: TrayId;\n icon: Icon;\n }\n | {\n type: \"set-tray-tooltip\";\n requestId: RequestId;\n appId: AppId;\n trayId: TrayId;\n tooltip: Tooltip;\n }\n | {\n type: \"load-ext\";\n requestId: RequestId;\n appId: AppId;\n name: string;\n path: string;\n mountId?: string;\n }\n | {\n type: \"ext-command\";\n requestId: RequestId;\n appId: AppId;\n trayId: TrayId;\n ext: string;\n data: unknown;\n }\n | { type: \"unload-ext\"; requestId: RequestId; appId: AppId; name: string }\n | { type: \"health\"; requestId: RequestId };\n\nexport type ServerFrame =\n | {\n type: \"ready\";\n protocolVersion: number;\n brokerVersion: string;\n sessionId: SessionId;\n }\n | { type: \"app-created\"; requestId: RequestId; app: AppRef }\n | { type: \"default-app\"; requestId: RequestId; app: AppRef }\n | { type: \"tray-created\"; requestId: RequestId; appId: AppId; trayId: TrayId }\n | {\n type: \"tray-bounds\";\n requestId: RequestId;\n appId: AppId;\n trayId: TrayId;\n bounds: TrayBoundsResult;\n }\n | { type: \"ack\"; requestId: RequestId }\n | {\n type: \"ext-command-result\";\n requestId: RequestId;\n events: ExtensionEnvelope[];\n }\n | {\n type: \"runtime-host-health\";\n requestId: RequestId;\n health: RuntimeHostHealth;\n }\n | { type: \"event\"; event: TrayEvent }\n | {\n type: \"ext-event\";\n appId: AppId;\n trayId: TrayId;\n ext: string;\n data: unknown;\n }\n | { type: \"error\"; requestId?: RequestId; code: string; message: string };\n\nexport interface ParseResult<T> {\n ok: boolean;\n frame?: T;\n error?: string;\n}\n\nexport const parseServerFrame = (line: string): ParseResult<ServerFrame> => {\n try {\n const value: unknown = JSON.parse(line);\n if (!isServerFrame(value)) {\n return { ok: false, error: \"invalid server frame\" };\n }\n return { ok: true, frame: value };\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : \"unknown parse error\",\n };\n }\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport const isServerFrame = (value: unknown): value is ServerFrame => {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"ready\":\n return (\n typeof value.protocolVersion === \"number\" &&\n typeof value.brokerVersion === \"string\" &&\n typeof value.sessionId === \"string\"\n );\n case \"app-created\":\n return typeof value.requestId === \"string\" && isRecord(value.app);\n case \"default-app\":\n return typeof value.requestId === \"string\" && isRecord(value.app);\n case \"tray-created\":\n return (\n typeof value.requestId === \"string\" &&\n typeof value.appId === \"string\" &&\n typeof value.trayId === \"string\"\n );\n case \"tray-bounds\":\n return (\n typeof value.requestId === \"string\" &&\n typeof value.appId === \"string\" &&\n typeof value.trayId === \"string\" &&\n isTrayBoundsResult(value.bounds)\n );\n case \"ack\":\n return typeof value.requestId === \"string\";\n case \"ext-command-result\":\n return (\n typeof value.requestId === \"string\" &&\n Array.isArray(value.events) &&\n value.events.every(isExtensionEnvelope)\n );\n case \"runtime-host-health\":\n return (\n typeof value.requestId === \"string\" && isRuntimeHostHealth(value.health)\n );\n case \"event\":\n return isTrayEvent(value.event);\n case \"ext-event\":\n return (\n typeof value.appId === \"string\" &&\n typeof value.trayId === \"string\" &&\n typeof value.ext === \"string\"\n );\n case \"error\":\n return (\n (value.requestId === undefined ||\n typeof value.requestId === \"string\") &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n default:\n return false;\n }\n};\n\nconst isExtensionEnvelope = (value: unknown): value is ExtensionEnvelope => {\n if (!isRecord(value) || !isRecord(value.scope)) {\n return false;\n }\n const scope = value.scope as Record<string, unknown>;\n return (\n typeof scope.appId === \"string\" &&\n (scope.trayId === undefined || typeof scope.trayId === \"string\") &&\n typeof scope.ext === \"string\" &&\n \"data\" in value\n );\n};\n\nconst isRuntimeHostHealth = (value: unknown): value is RuntimeHostHealth => {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n typeof value.pid === \"number\" &&\n typeof value.packageVersion === \"string\" &&\n typeof value.protocolVersion === \"number\" &&\n typeof value.endpoint === \"string\" &&\n typeof value.appId === \"string\" &&\n typeof value.appName === \"string\" &&\n typeof value.callerLabel === \"string\" &&\n typeof value.sessionCount === \"number\" &&\n Array.isArray(value.sessions) &&\n value.sessions.every(isRuntimeHostSessionHealth)\n );\n};\n\nconst isRuntimeHostSessionHealth = (\n value: unknown\n): value is RuntimeHostSessionHealth =>\n isRecord(value) &&\n typeof value.sessionId === \"number\" &&\n (value.internalSessionId === undefined ||\n typeof value.internalSessionId === \"string\") &&\n typeof value.initialized === \"boolean\";\n\nconst isRect = (value: unknown): value is Rect =>\n isRecord(value) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\" &&\n typeof value.width === \"number\" &&\n typeof value.height === \"number\";\n\nconst isTrayBoundsResult = (value: unknown): value is TrayBoundsResult =>\n isRecord(value) &&\n (value.kind === \"native\" ||\n value.kind === \"inferred\" ||\n value.kind === \"unavailable\") &&\n typeof value.source === \"string\" &&\n (value.rect === null || isRect(value.rect));\n\nconst isTrayEvent = (value: unknown): value is TrayEvent => {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"ready\":\n return typeof value.appId === \"string\";\n case \"menuClick\":\n return (\n typeof value.appId === \"string\" &&\n typeof value.trayId === \"string\" &&\n typeof value.itemId === \"number\"\n );\n case \"trayClick\":\n case \"trayDoubleClick\":\n return (\n typeof value.appId === \"string\" &&\n typeof value.trayId === \"string\" &&\n isMouseButton(value.button) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\"\n );\n default:\n return false;\n }\n};\n\nconst isMouseButton = (value: unknown): value is MouseButton =>\n value === \"left\" || value === \"right\" || value === \"middle\";\n"],"mappings":"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"}
|