gestament 0.2.0 → 0.3.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.
Files changed (86) hide show
  1. package/README.md +4 -6
  2. package/dist/displaySession.d.ts +18 -0
  3. package/dist/displaySession.d.ts.map +1 -0
  4. package/dist/element.d.ts +2 -2
  5. package/dist/errors-6gj5YuLw.cjs +36 -0
  6. package/dist/errors-6gj5YuLw.cjs.map +1 -0
  7. package/dist/errors-CCW4ATME.js +37 -0
  8. package/dist/errors-CCW4ATME.js.map +1 -0
  9. package/dist/errors.d.ts +2 -2
  10. package/dist/errors.d.ts.map +1 -1
  11. package/dist/generated/packageMetadata.d.ts +4 -4
  12. package/dist/gestament-config.d.ts +2 -2
  13. package/dist/gestament-launcher-driver.cjs +656 -0
  14. package/dist/gestament-launcher-driver.cjs.map +1 -0
  15. package/dist/gestament-launcher-driver.d.ts +13 -0
  16. package/dist/gestament-launcher-driver.d.ts.map +1 -0
  17. package/dist/gestament-launcher-driver.mjs +655 -0
  18. package/dist/gestament-launcher-driver.mjs.map +1 -0
  19. package/dist/gestament-tray-host.cjs +1 -1
  20. package/dist/gestament-tray-host.d.ts +2 -2
  21. package/dist/gestament-tray-host.mjs +1 -1
  22. package/dist/gestament-xvfb-pool-probe.cjs +29 -0
  23. package/dist/gestament-xvfb-pool-probe.cjs.map +1 -0
  24. package/dist/gestament-xvfb-pool-probe.d.ts +13 -0
  25. package/dist/gestament-xvfb-pool-probe.d.ts.map +1 -0
  26. package/dist/gestament-xvfb-pool-probe.mjs +28 -0
  27. package/dist/gestament-xvfb-pool-probe.mjs.map +1 -0
  28. package/dist/gestament-xvfb-worker.d.ts +2 -2
  29. package/dist/gestament-xvfb.cjs +8 -2
  30. package/dist/gestament-xvfb.cjs.map +1 -1
  31. package/dist/gestament-xvfb.d.ts +2 -2
  32. package/dist/gestament-xvfb.mjs +8 -2
  33. package/dist/gestament-xvfb.mjs.map +1 -1
  34. package/dist/index.cjs +4 -1147
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.mjs +4 -1147
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/launchGtkApp-BIO_5Xjn.cjs +2479 -0
  40. package/dist/launchGtkApp-BIO_5Xjn.cjs.map +1 -0
  41. package/dist/launchGtkApp-qi1qm5G4.js +2479 -0
  42. package/dist/launchGtkApp-qi1qm5G4.js.map +1 -0
  43. package/dist/launchGtkApp.d.ts +2 -2
  44. package/dist/launchGtkApp.d.ts.map +1 -1
  45. package/dist/launcherDriverProtocol.d.ts +107 -0
  46. package/dist/launcherDriverProtocol.d.ts.map +1 -0
  47. package/dist/{native-ie_XIt1J.cjs → native-CBXaFWP-.cjs} +14 -40
  48. package/dist/native-CBXaFWP-.cjs.map +1 -0
  49. package/dist/{native-DUeVYIBs.js → native-CWdUmdty.js} +48 -74
  50. package/dist/native-CWdUmdty.js.map +1 -0
  51. package/dist/native.d.ts +4 -2
  52. package/dist/native.d.ts.map +1 -1
  53. package/dist/prerequisites-BuZST2Dy.cjs +15 -0
  54. package/dist/prerequisites-BuZST2Dy.cjs.map +1 -0
  55. package/dist/prerequisites-JB0SKPVd.js +16 -0
  56. package/dist/prerequisites-JB0SKPVd.js.map +1 -0
  57. package/dist/prerequisites.d.ts +23 -0
  58. package/dist/prerequisites.d.ts.map +1 -0
  59. package/dist/testing.cjs +3 -0
  60. package/dist/testing.cjs.map +1 -1
  61. package/dist/testing.d.ts +4 -2
  62. package/dist/testing.d.ts.map +1 -1
  63. package/dist/testing.mjs +4 -1
  64. package/dist/testing.mjs.map +1 -1
  65. package/dist/tray.d.ts +2 -2
  66. package/dist/types.d.ts +64 -2
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/wait-DV5gkXs8.js +113 -0
  69. package/dist/wait-DV5gkXs8.js.map +1 -0
  70. package/dist/wait-eOIz4nZm.cjs +112 -0
  71. package/dist/wait-eOIz4nZm.cjs.map +1 -0
  72. package/dist/wait.d.ts +67 -0
  73. package/dist/wait.d.ts.map +1 -0
  74. package/package.json +7 -7
  75. package/prebuilds/linux-arm/gtk3/node.napi.armv7.glibc.node +0 -0
  76. package/prebuilds/linux-arm/gtk4/node.napi.armv7.glibc.node +0 -0
  77. package/prebuilds/linux-arm64/gtk3/node.napi.glibc.node +0 -0
  78. package/prebuilds/linux-arm64/gtk4/node.napi.glibc.node +0 -0
  79. package/prebuilds/linux-ia32/gtk3/node.napi.glibc.node +0 -0
  80. package/prebuilds/linux-ia32/gtk4/node.napi.glibc.node +0 -0
  81. package/prebuilds/linux-riscv64/gtk3/node.napi.glibc.node +0 -0
  82. package/prebuilds/linux-riscv64/gtk4/node.napi.glibc.node +0 -0
  83. package/prebuilds/linux-x64/gtk3/node.napi.glibc.node +0 -0
  84. package/prebuilds/linux-x64/gtk4/node.napi.glibc.node +0 -0
  85. package/dist/native-DUeVYIBs.js.map +0 -1
  86. package/dist/native-ie_XIt1J.cjs.map +0 -1
@@ -0,0 +1,655 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import { createConnection } from "node:net";
4
+ import { realpathSync } from "node:fs";
5
+ import { resolve, dirname } from "node:path";
6
+ import { c as createGtkOperationFailedError, a as createGtkAppExitedError, b as createGtkStaleElementError, d as createGtkUnsupportedInterfaceError } from "./errors-CCW4ATME.js";
7
+ import { l as launchGtkApp } from "./launchGtkApp-qi1qm5G4.js";
8
+ import { r as runWithWaitDeadline } from "./wait-DV5gkXs8.js";
9
+ const trayHostReadyLine = "gestament-tray-host-ready";
10
+ const trayHostReadyTimeoutMs = 3e4;
11
+ const apps = /* @__PURE__ */ new Map();
12
+ const elements = /* @__PURE__ */ new Map();
13
+ const trayItems = /* @__PURE__ */ new Map();
14
+ const imageInfos = /* @__PURE__ */ new Map();
15
+ const staleElementIds = /* @__PURE__ */ new Set();
16
+ const staleTrayItemIds = /* @__PURE__ */ new Set();
17
+ const staleImageInfoIds = /* @__PURE__ */ new Set();
18
+ let nextAppId = 1;
19
+ let nextElementId = 1;
20
+ let nextTrayItemId = 1;
21
+ let nextImageInfoId = 1;
22
+ let shuttingDown = false;
23
+ let trayHostProcess;
24
+ const parseArguments = (args) => {
25
+ let socketPath;
26
+ let withTrayHost = false;
27
+ let index = 0;
28
+ while (index < args.length) {
29
+ const argument = args[index];
30
+ if (argument === "--socket") {
31
+ const value = args[index + 1];
32
+ if (value === void 0 || value.length === 0) {
33
+ throw new Error("--socket requires a Unix socket path.");
34
+ }
35
+ socketPath = value;
36
+ index += 2;
37
+ continue;
38
+ }
39
+ if (argument === "--with-tray-host") {
40
+ withTrayHost = true;
41
+ index += 1;
42
+ continue;
43
+ }
44
+ throw new Error(`Unknown gestament launcher driver option: ${argument}`);
45
+ }
46
+ if (socketPath === void 0) {
47
+ throw new Error("Missing --socket option.");
48
+ }
49
+ return { socketPath, withTrayHost };
50
+ };
51
+ const waitForTrayHostReady = (host) => new Promise((resolveReady, rejectReady) => {
52
+ if (host.stdout === null) {
53
+ rejectReady(new Error("gestament tray host did not expose stdout."));
54
+ return;
55
+ }
56
+ let output = "";
57
+ let settled = false;
58
+ const timeout = setTimeout(() => {
59
+ if (!settled) {
60
+ settled = true;
61
+ rejectReady(new Error("Timed out waiting for gestament tray host."));
62
+ }
63
+ }, trayHostReadyTimeoutMs);
64
+ host.stdout.on("data", (chunk) => {
65
+ const text = chunk.toString("utf8");
66
+ output += text;
67
+ if (!settled && output.includes(trayHostReadyLine)) {
68
+ settled = true;
69
+ clearTimeout(timeout);
70
+ resolveReady();
71
+ return;
72
+ }
73
+ if (settled) {
74
+ process.stdout.write(text);
75
+ }
76
+ });
77
+ host.once("exit", (code, signal) => {
78
+ if (!settled) {
79
+ settled = true;
80
+ clearTimeout(timeout);
81
+ rejectReady(
82
+ new Error(
83
+ `gestament tray host exited before ready: code=${String(
84
+ code
85
+ )}, signal=${String(signal)}`
86
+ )
87
+ );
88
+ }
89
+ });
90
+ host.once("error", (error) => {
91
+ if (!settled) {
92
+ settled = true;
93
+ clearTimeout(timeout);
94
+ rejectReady(error);
95
+ }
96
+ });
97
+ });
98
+ const startTrayHost = async () => {
99
+ const executablePath = process.argv[1];
100
+ if (executablePath === void 0) {
101
+ throw new Error("Missing executable path.");
102
+ }
103
+ const hostPath = resolve(
104
+ dirname(realpathSync(executablePath)),
105
+ "gestament-tray-host.cjs"
106
+ );
107
+ const host = spawn(process.execPath, [hostPath], {
108
+ env: process.env,
109
+ stdio: ["ignore", "pipe", "inherit"]
110
+ });
111
+ try {
112
+ await waitForTrayHostReady(host);
113
+ return host;
114
+ } catch (error) {
115
+ if (host.exitCode === null && host.signalCode === null) {
116
+ host.kill("SIGTERM");
117
+ }
118
+ throw error;
119
+ }
120
+ };
121
+ const connectToParent = (socketPath) => new Promise((resolveConnect, rejectConnect) => {
122
+ const socket = createConnection(socketPath);
123
+ const rejectFromError = (error) => {
124
+ socket.removeListener("connect", resolveFromConnect);
125
+ rejectConnect(error);
126
+ };
127
+ const resolveFromConnect = () => {
128
+ socket.removeListener("error", rejectFromError);
129
+ resolveConnect(socket);
130
+ };
131
+ socket.once("error", rejectFromError);
132
+ socket.once("connect", resolveFromConnect);
133
+ });
134
+ const writeReady = (socket) => {
135
+ const ready = { type: "ready" };
136
+ socket.write(`${JSON.stringify(ready)}
137
+ `);
138
+ };
139
+ const wireEnvironmentToGtkAppEnvironment = (env) => {
140
+ const appEnv = {};
141
+ for (const [key, value] of Object.entries(env)) {
142
+ appEnv[key] = value === null ? void 0 : value;
143
+ }
144
+ return appEnv;
145
+ };
146
+ const toWireCapture = (capture) => ({
147
+ bounds: capture.bounds,
148
+ clipped: capture.clipped,
149
+ imageBase64: capture.image.toString("base64"),
150
+ visibleBounds: capture.visibleBounds
151
+ });
152
+ const registerApp = (app) => {
153
+ const appId = `app-${nextAppId}`;
154
+ nextAppId += 1;
155
+ apps.set(appId, app);
156
+ return { appId };
157
+ };
158
+ const registerElement = (appId, element) => {
159
+ const elementId = `element-${nextElementId}`;
160
+ nextElementId += 1;
161
+ elements.set(elementId, { appId, element });
162
+ return { elementId, kind: element.kind };
163
+ };
164
+ const registerTrayItem = (appId, trayItem) => {
165
+ const trayItemId = `tray-${nextTrayItemId}`;
166
+ nextTrayItemId += 1;
167
+ trayItems.set(trayItemId, { appId, trayItem });
168
+ return { trayItemId };
169
+ };
170
+ const registerImageInfo = (appId, info) => {
171
+ const imageInfoId = `image-info-${nextImageInfoId}`;
172
+ nextImageInfoId += 1;
173
+ imageInfos.set(imageInfoId, { appId, capture: info.capture });
174
+ return {
175
+ bounds: info.bounds,
176
+ description: info.description,
177
+ imageInfoId,
178
+ locale: info.locale,
179
+ position: info.position,
180
+ size: info.size
181
+ };
182
+ };
183
+ const resolveApp = (appId) => {
184
+ const app = apps.get(appId);
185
+ if (app === void 0) {
186
+ throw createGtkAppExitedError(
187
+ "GTK application has exited or was released."
188
+ );
189
+ }
190
+ return app;
191
+ };
192
+ const resolveElementEntry = (elementId) => {
193
+ const entry = elements.get(elementId);
194
+ if (entry === void 0) {
195
+ if (staleElementIds.has(elementId)) {
196
+ throw createGtkStaleElementError("GTK element is no longer available.");
197
+ }
198
+ throw createGtkAppExitedError("GTK element is not registered.");
199
+ }
200
+ if (!apps.has(entry.appId)) {
201
+ throw createGtkStaleElementError("GTK element is no longer available.");
202
+ }
203
+ return entry;
204
+ };
205
+ const resolveTrayItemEntry = (trayItemId) => {
206
+ const entry = trayItems.get(trayItemId);
207
+ if (entry === void 0) {
208
+ if (staleTrayItemIds.has(trayItemId)) {
209
+ throw createGtkStaleElementError("Tray item is no longer registered.");
210
+ }
211
+ throw createGtkAppExitedError("GTK tray item is not registered.");
212
+ }
213
+ if (!apps.has(entry.appId)) {
214
+ throw createGtkStaleElementError("Tray item is no longer registered.");
215
+ }
216
+ return entry;
217
+ };
218
+ const resolveImageInfoEntry = (imageInfoId) => {
219
+ const entry = imageInfos.get(imageInfoId);
220
+ if (entry === void 0) {
221
+ if (staleImageInfoIds.has(imageInfoId)) {
222
+ throw createGtkStaleElementError(
223
+ "GTK image info is no longer available."
224
+ );
225
+ }
226
+ throw createGtkAppExitedError("GTK image info is not registered.");
227
+ }
228
+ if (!apps.has(entry.appId)) {
229
+ throw createGtkStaleElementError("GTK image info is no longer available.");
230
+ }
231
+ return entry;
232
+ };
233
+ const removeAppRefs = (appId) => {
234
+ for (const [elementId, entry] of elements) {
235
+ if (entry.appId === appId) {
236
+ staleElementIds.add(elementId);
237
+ elements.delete(elementId);
238
+ }
239
+ }
240
+ for (const [trayItemId, entry] of trayItems) {
241
+ if (entry.appId === appId) {
242
+ staleTrayItemIds.add(trayItemId);
243
+ trayItems.delete(trayItemId);
244
+ }
245
+ }
246
+ for (const [imageInfoId, entry] of imageInfos) {
247
+ if (entry.appId === appId) {
248
+ staleImageInfoIds.add(imageInfoId);
249
+ imageInfos.delete(imageInfoId);
250
+ }
251
+ }
252
+ };
253
+ const releaseApp = async (appId) => {
254
+ const app = apps.get(appId);
255
+ if (app === void 0) {
256
+ return;
257
+ }
258
+ apps.delete(appId);
259
+ removeAppRefs(appId);
260
+ await app.release();
261
+ };
262
+ const releaseApps = async () => {
263
+ const appIds = [...apps.keys()];
264
+ await Promise.all(appIds.map((appId) => releaseApp(appId)));
265
+ };
266
+ const stopTrayHost = () => {
267
+ if (trayHostProcess !== void 0 && trayHostProcess.exitCode === null && trayHostProcess.signalCode === null) {
268
+ trayHostProcess.kill("SIGTERM");
269
+ }
270
+ };
271
+ const releaseAll = async () => {
272
+ await releaseApps();
273
+ stopTrayHost();
274
+ };
275
+ const asMethod = (target, methodName, kindLabel) => {
276
+ const value = target[methodName];
277
+ if (typeof value !== "function") {
278
+ throw createGtkUnsupportedInterfaceError(
279
+ `${kindLabel} does not support ${methodName}().`
280
+ );
281
+ }
282
+ return value;
283
+ };
284
+ const callElementMethod = (entry, methodName, args = []) => asMethod(
285
+ entry.element,
286
+ methodName,
287
+ `GTK ${entry.element.kind} element`
288
+ )(...args);
289
+ const callTrayItemMethod = (entry, methodName, args = []) => asMethod(entry.trayItem, methodName, "GTK tray item")(...args);
290
+ const serializeError = (error) => {
291
+ if (error instanceof Error) {
292
+ const maybeCode = error.code;
293
+ const base = {
294
+ message: error.message,
295
+ name: error.name
296
+ };
297
+ const withStack = error.stack === void 0 ? base : { ...base, stack: error.stack };
298
+ return typeof maybeCode === "string" ? { ...withStack, code: maybeCode } : withStack;
299
+ }
300
+ return {
301
+ message: String(error),
302
+ name: "Error"
303
+ };
304
+ };
305
+ const appPayload = (payload) => payload;
306
+ const elementPayload = (payload) => payload;
307
+ const trayPayload = (payload) => payload;
308
+ const optionalElementRef = (appId, element) => element === void 0 ? null : registerElement(appId, element);
309
+ const optionalTrayItemRef = (appId, trayItem) => trayItem === void 0 ? null : registerTrayItem(appId, trayItem);
310
+ const handleLauncherCommand = async (command, payload) => {
311
+ switch (command) {
312
+ case "launcher.launch": {
313
+ const launchPayload = payload;
314
+ const launchOptions = {
315
+ env: wireEnvironmentToGtkAppEnvironment(launchPayload.env),
316
+ ...launchPayload.timeoutMs === null ? {} : { timeoutMs: launchPayload.timeoutMs }
317
+ };
318
+ const app = await launchGtkApp(
319
+ launchPayload.appPath,
320
+ launchPayload.args,
321
+ launchOptions
322
+ );
323
+ return registerApp(app);
324
+ }
325
+ case "launcher.release":
326
+ await releaseAll();
327
+ return null;
328
+ case "launcher.reset":
329
+ await releaseApps();
330
+ return {
331
+ appCount: apps.size,
332
+ elementCount: elements.size,
333
+ imageInfoCount: imageInfos.size,
334
+ trayItemCount: trayItems.size
335
+ };
336
+ default:
337
+ throw createGtkOperationFailedError(`Unsupported command: ${command}`);
338
+ }
339
+ };
340
+ const handleAppCommand = async (command, payload) => {
341
+ const { appId } = appPayload(payload);
342
+ const app = resolveApp(appId);
343
+ switch (command) {
344
+ case "app.release":
345
+ await releaseApp(appId);
346
+ return null;
347
+ case "app.capture":
348
+ return toWireCapture(await app.capture());
349
+ case "app.findById": {
350
+ const { id } = payload;
351
+ return optionalElementRef(appId, await app.findById(id));
352
+ }
353
+ case "app.getById": {
354
+ const { id } = payload;
355
+ return registerElement(appId, await app.getById(id));
356
+ }
357
+ case "app.findByPath": {
358
+ const { path } = payload;
359
+ return optionalElementRef(appId, await app.findByPath(path));
360
+ }
361
+ case "app.getByPath": {
362
+ const { path } = payload;
363
+ return registerElement(appId, await app.getByPath(path));
364
+ }
365
+ case "app.windowAt": {
366
+ const { index } = payload;
367
+ return optionalElementRef(appId, await app.windowAt(index));
368
+ }
369
+ case "app.getWindowCount":
370
+ return app.getWindowCount();
371
+ case "app.findTrayItem": {
372
+ const { selector } = payload;
373
+ return optionalTrayItemRef(appId, await app.findTrayItem(selector));
374
+ }
375
+ case "app.getTrayItem": {
376
+ const { selector } = payload;
377
+ return registerTrayItem(appId, await app.getTrayItem(selector));
378
+ }
379
+ case "app.trayItemAt": {
380
+ const { index } = payload;
381
+ return optionalTrayItemRef(appId, await app.trayItemAt(index));
382
+ }
383
+ case "app.getTrayItemCount":
384
+ return app.getTrayItemCount();
385
+ default:
386
+ throw createGtkOperationFailedError(
387
+ `Unsupported app command: ${command}`
388
+ );
389
+ }
390
+ };
391
+ const handleElementCommand = async (command, payload) => {
392
+ const { elementId } = elementPayload(payload);
393
+ const entry = resolveElementEntry(elementId);
394
+ switch (command) {
395
+ case "element.info":
396
+ return entry.element.info();
397
+ case "element.capture":
398
+ return toWireCapture(await entry.element.capture());
399
+ case "element.childAt": {
400
+ const { index } = payload;
401
+ return optionalElementRef(
402
+ entry.appId,
403
+ await callElementMethod(entry, "childAt", [index])
404
+ );
405
+ }
406
+ case "element.getChildCount":
407
+ return callElementMethod(entry, "getChildCount");
408
+ case "element.click":
409
+ await callElementMethod(entry, "click");
410
+ return null;
411
+ case "element.text":
412
+ return callElementMethod(entry, "text");
413
+ case "element.setText": {
414
+ const { text } = payload;
415
+ await callElementMethod(entry, "setText", [text]);
416
+ return null;
417
+ }
418
+ case "element.isChecked":
419
+ return callElementMethod(entry, "isChecked");
420
+ case "element.toggle":
421
+ await callElementMethod(entry, "toggle");
422
+ return null;
423
+ case "element.value":
424
+ return callElementMethod(entry, "value");
425
+ case "element.valueInfo":
426
+ return callElementMethod(entry, "valueInfo");
427
+ case "element.setValue": {
428
+ const { value } = payload;
429
+ await callElementMethod(entry, "setValue", [value]);
430
+ return null;
431
+ }
432
+ case "element.increment":
433
+ await callElementMethod(entry, "increment");
434
+ return null;
435
+ case "element.decrement":
436
+ await callElementMethod(entry, "decrement");
437
+ return null;
438
+ case "element.getSelectedChildCount":
439
+ return callElementMethod(entry, "getSelectedChildCount");
440
+ case "element.selectedChildAt": {
441
+ const { selectedIndex } = payload;
442
+ return optionalElementRef(
443
+ entry.appId,
444
+ await callElementMethod(entry, "selectedChildAt", [selectedIndex])
445
+ );
446
+ }
447
+ case "element.isChildSelected": {
448
+ const { index } = payload;
449
+ return callElementMethod(entry, "isChildSelected", [index]);
450
+ }
451
+ case "element.selectChildAt": {
452
+ const { index } = payload;
453
+ await callElementMethod(entry, "selectChildAt", [index]);
454
+ return null;
455
+ }
456
+ case "element.deselectChildAt": {
457
+ const { index } = payload;
458
+ await callElementMethod(entry, "deselectChildAt", [index]);
459
+ return null;
460
+ }
461
+ case "element.selectAllChildren":
462
+ await callElementMethod(entry, "selectAllChildren");
463
+ return null;
464
+ case "element.clearSelection":
465
+ await callElementMethod(entry, "clearSelection");
466
+ return null;
467
+ case "element.getRowCount":
468
+ return callElementMethod(entry, "getRowCount");
469
+ case "element.getColumnCount":
470
+ return callElementMethod(entry, "getColumnCount");
471
+ case "element.cellAt": {
472
+ const { column, row } = payload;
473
+ return optionalElementRef(
474
+ entry.appId,
475
+ await callElementMethod(entry, "cellAt", [row, column])
476
+ );
477
+ }
478
+ case "element.selectedRows":
479
+ return callElementMethod(entry, "selectedRows");
480
+ case "element.selectedColumns":
481
+ return callElementMethod(entry, "selectedColumns");
482
+ case "element.isRowSelected": {
483
+ const { row } = payload;
484
+ return callElementMethod(entry, "isRowSelected", [row]);
485
+ }
486
+ case "element.isColumnSelected": {
487
+ const { column } = payload;
488
+ return callElementMethod(entry, "isColumnSelected", [column]);
489
+ }
490
+ case "element.isCellSelected": {
491
+ const { column, row } = payload;
492
+ return callElementMethod(entry, "isCellSelected", [row, column]);
493
+ }
494
+ case "element.selectRow": {
495
+ const { row } = payload;
496
+ await callElementMethod(entry, "selectRow", [row]);
497
+ return null;
498
+ }
499
+ case "element.deselectRow": {
500
+ const { row } = payload;
501
+ await callElementMethod(entry, "deselectRow", [row]);
502
+ return null;
503
+ }
504
+ case "element.selectColumn": {
505
+ const { column } = payload;
506
+ await callElementMethod(entry, "selectColumn", [column]);
507
+ return null;
508
+ }
509
+ case "element.deselectColumn": {
510
+ const { column } = payload;
511
+ await callElementMethod(entry, "deselectColumn", [column]);
512
+ return null;
513
+ }
514
+ case "element.imageInfo": {
515
+ const info = await callElementMethod(
516
+ entry,
517
+ "imageInfo"
518
+ );
519
+ return registerImageInfo(entry.appId, info);
520
+ }
521
+ default:
522
+ throw createGtkOperationFailedError(
523
+ `Unsupported element command: ${command}`
524
+ );
525
+ }
526
+ };
527
+ const handleImageInfoCommand = async (command, payload) => {
528
+ if (command !== "imageInfo.capture") {
529
+ throw createGtkOperationFailedError(
530
+ `Unsupported image info command: ${command}`
531
+ );
532
+ }
533
+ const { imageInfoId } = payload;
534
+ const entry = resolveImageInfoEntry(imageInfoId);
535
+ return toWireCapture(await entry.capture());
536
+ };
537
+ const handleTrayCommand = async (command, payload) => {
538
+ const { trayItemId } = trayPayload(payload);
539
+ const entry = resolveTrayItemEntry(trayItemId);
540
+ switch (command) {
541
+ case "tray.metadata":
542
+ return entry.trayItem.metadata();
543
+ case "tray.element":
544
+ return optionalElementRef(
545
+ entry.appId,
546
+ await callTrayItemMethod(entry, "element")
547
+ );
548
+ case "tray.capture":
549
+ return toWireCapture(await entry.trayItem.capture());
550
+ case "tray.click":
551
+ await entry.trayItem.click();
552
+ return null;
553
+ case "tray.openMenu":
554
+ return optionalElementRef(
555
+ entry.appId,
556
+ await callTrayItemMethod(entry, "openMenu")
557
+ );
558
+ default:
559
+ throw createGtkOperationFailedError(
560
+ `Unsupported tray command: ${command}`
561
+ );
562
+ }
563
+ };
564
+ const handleRequest = async (request) => {
565
+ if (request.command.startsWith("launcher.")) {
566
+ return handleLauncherCommand(request.command, request.payload);
567
+ }
568
+ if (request.command.startsWith("app.")) {
569
+ return handleAppCommand(request.command, request.payload);
570
+ }
571
+ if (request.command.startsWith("element.")) {
572
+ return handleElementCommand(request.command, request.payload);
573
+ }
574
+ if (request.command.startsWith("imageInfo.")) {
575
+ return handleImageInfoCommand(request.command, request.payload);
576
+ }
577
+ if (request.command.startsWith("tray.")) {
578
+ return handleTrayCommand(request.command, request.payload);
579
+ }
580
+ throw createGtkOperationFailedError(
581
+ `Unsupported launcher driver command: ${request.command}`
582
+ );
583
+ };
584
+ const writeResponse = (socket, id, response) => {
585
+ socket.write(`${JSON.stringify({ id, ...response })}
586
+ `);
587
+ };
588
+ const handleRequestLine = async (socket, line) => {
589
+ const request = JSON.parse(line);
590
+ try {
591
+ const value = request.deadlineMs === void 0 || request.deadlineMs === null ? await handleRequest(request) : await runWithWaitDeadline(
592
+ request.deadlineMs,
593
+ () => handleRequest(request)
594
+ );
595
+ writeResponse(socket, request.id, { ok: true, value });
596
+ if (request.command === "launcher.release") {
597
+ socket.end();
598
+ }
599
+ } catch (error) {
600
+ writeResponse(socket, request.id, {
601
+ error: serializeError(error),
602
+ ok: false
603
+ });
604
+ }
605
+ };
606
+ const installSocketProtocol = (socket) => {
607
+ let input = "";
608
+ socket.on("data", (chunk) => {
609
+ input += chunk.toString("utf8");
610
+ let newlineIndex = input.indexOf("\n");
611
+ while (newlineIndex >= 0) {
612
+ const line = input.slice(0, newlineIndex);
613
+ input = input.slice(newlineIndex + 1);
614
+ void handleRequestLine(socket, line);
615
+ newlineIndex = input.indexOf("\n");
616
+ }
617
+ });
618
+ socket.once("close", () => {
619
+ void shutdown(0);
620
+ });
621
+ socket.once("error", () => {
622
+ void shutdown(1);
623
+ });
624
+ };
625
+ const shutdown = async (exitCode) => {
626
+ if (shuttingDown) {
627
+ return;
628
+ }
629
+ shuttingDown = true;
630
+ await releaseAll();
631
+ process.exitCode = exitCode;
632
+ setImmediate(() => {
633
+ process.exit(exitCode);
634
+ });
635
+ };
636
+ const run = async () => {
637
+ const parsed = parseArguments(process.argv.slice(2));
638
+ trayHostProcess = parsed.withTrayHost ? await startTrayHost() : void 0;
639
+ const socket = await connectToParent(parsed.socketPath);
640
+ installSocketProtocol(socket);
641
+ writeReady(socket);
642
+ process.once("SIGINT", () => {
643
+ void shutdown(130);
644
+ });
645
+ process.once("SIGTERM", () => {
646
+ void shutdown(143);
647
+ });
648
+ };
649
+ run().catch((error) => {
650
+ const message = error instanceof Error ? error.message : String(error);
651
+ process.stderr.write(`gestament launcher driver: ${message}
652
+ `);
653
+ process.exitCode = 2;
654
+ });
655
+ //# sourceMappingURL=gestament-launcher-driver.mjs.map