gestament 0.3.0 → 0.5.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 +22 -5
- package/dist/displaySession.d.ts +2 -2
- package/dist/displaySession.d.ts.map +1 -1
- package/dist/element.d.ts +2 -2
- package/dist/element.d.ts.map +1 -1
- package/dist/errors.d.ts +2 -2
- package/dist/generated/packageMetadata.d.ts +4 -4
- package/dist/gestament-config.d.ts +2 -2
- package/dist/gestament-launcher-driver.cjs +118 -5
- package/dist/gestament-launcher-driver.cjs.map +1 -1
- package/dist/gestament-launcher-driver.d.ts +2 -2
- package/dist/gestament-launcher-driver.mjs +118 -5
- package/dist/gestament-launcher-driver.mjs.map +1 -1
- package/dist/gestament-tray-host.cjs +9 -1
- package/dist/gestament-tray-host.cjs.map +1 -1
- package/dist/gestament-tray-host.d.ts +2 -2
- package/dist/gestament-tray-host.mjs +9 -1
- package/dist/gestament-tray-host.mjs.map +1 -1
- package/dist/gestament-xvfb-pool-probe.cjs +1 -1
- package/dist/gestament-xvfb-pool-probe.d.ts +2 -2
- package/dist/gestament-xvfb-pool-probe.mjs +1 -1
- package/dist/gestament-xvfb-worker.d.ts +2 -2
- package/dist/gestament-xvfb.cjs +7 -2
- package/dist/gestament-xvfb.cjs.map +1 -1
- package/dist/gestament-xvfb.d.ts +2 -2
- package/dist/gestament-xvfb.mjs +7 -2
- package/dist/gestament-xvfb.mjs.map +1 -1
- package/dist/gestament.cjs +279 -0
- package/dist/gestament.cjs.map +1 -0
- package/dist/gestament.d.ts +29 -0
- package/dist/gestament.d.ts.map +1 -0
- package/dist/gestament.mjs +278 -0
- package/dist/gestament.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{launchGtkApp-BIO_5Xjn.cjs → launchGtkApp-CzYcrc9f.cjs} +794 -89
- package/dist/launchGtkApp-CzYcrc9f.cjs.map +1 -0
- package/dist/{launchGtkApp-qi1qm5G4.js → launchGtkApp-EI6OIpPI.js} +792 -87
- package/dist/launchGtkApp-EI6OIpPI.js.map +1 -0
- package/dist/launchGtkApp.d.ts +2 -2
- package/dist/launchGtkApp.d.ts.map +1 -1
- package/dist/launcherDriverProtocol.d.ts +29 -4
- package/dist/launcherDriverProtocol.d.ts.map +1 -1
- package/dist/{native-CWdUmdty.js → native-DlCBBWlV.js} +16 -10
- package/dist/native-DlCBBWlV.js.map +1 -0
- package/dist/{native-CBXaFWP-.cjs → native-Kfm95Uxw.cjs} +12 -6
- package/dist/native-Kfm95Uxw.cjs.map +1 -0
- package/dist/native.d.ts +23 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/output.d.ts +27 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/packageMetadata-CewXH0iF.cjs +4 -0
- package/dist/packageMetadata-CewXH0iF.cjs.map +1 -0
- package/dist/packageMetadata-DjxyJCJm.js +5 -0
- package/dist/packageMetadata-DjxyJCJm.js.map +1 -0
- package/dist/prerequisites.d.ts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/tray.d.ts +2 -2
- package/dist/types.d.ts +277 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/wait.d.ts +2 -2
- package/package.json +8 -7
- package/prebuilds/linux-arm/gtk3/node.napi.armv7.glibc.node +0 -0
- package/prebuilds/linux-arm/gtk4/node.napi.armv7.glibc.node +0 -0
- package/prebuilds/linux-arm64/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-arm64/gtk4/node.napi.glibc.node +0 -0
- package/prebuilds/linux-ia32/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-ia32/gtk4/node.napi.glibc.node +0 -0
- package/prebuilds/linux-riscv64/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-riscv64/gtk4/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/gtk4/node.napi.glibc.node +0 -0
- package/dist/launchGtkApp-BIO_5Xjn.cjs.map +0 -1
- package/dist/launchGtkApp-qi1qm5G4.js.map +0 -1
- package/dist/native-CBXaFWP-.cjs.map +0 -1
- package/dist/native-CWdUmdty.js.map +0 -1
|
@@ -8,8 +8,233 @@ const node_os = require("node:os");
|
|
|
8
8
|
const node_path = require("node:path");
|
|
9
9
|
const node_url = require("node:url");
|
|
10
10
|
const prerequisites = require("./prerequisites-BuZST2Dy.cjs");
|
|
11
|
-
const native = require("./native-
|
|
11
|
+
const native = require("./native-Kfm95Uxw.cjs");
|
|
12
12
|
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
13
|
+
const normalizeOutputBufferBytes = (value, optionName = "outputBufferBytes") => {
|
|
14
|
+
if (value === void 0) {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
18
|
+
throw errors.createGtkInvalidArgumentError(
|
|
19
|
+
`${optionName} must be a non-negative safe integer.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
};
|
|
24
|
+
const createStreamState = () => ({
|
|
25
|
+
byteLength: 0,
|
|
26
|
+
chunks: [],
|
|
27
|
+
decoder: new TextDecoder(),
|
|
28
|
+
flushed: false,
|
|
29
|
+
truncated: false
|
|
30
|
+
});
|
|
31
|
+
const appendBoundedChunk = (state, chunk, maxBytes) => {
|
|
32
|
+
if (chunk.length === 0) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (maxBytes === void 0) {
|
|
36
|
+
state.chunks.push(Buffer.from(chunk));
|
|
37
|
+
state.byteLength += chunk.length;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (maxBytes === 0) {
|
|
41
|
+
state.truncated = true;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (chunk.length >= maxBytes) {
|
|
45
|
+
state.chunks.splice(
|
|
46
|
+
0,
|
|
47
|
+
state.chunks.length,
|
|
48
|
+
Buffer.from(chunk.subarray(chunk.length - maxBytes))
|
|
49
|
+
);
|
|
50
|
+
state.byteLength = maxBytes;
|
|
51
|
+
state.truncated = true;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
state.chunks.push(Buffer.from(chunk));
|
|
55
|
+
state.byteLength += chunk.length;
|
|
56
|
+
while (state.byteLength > maxBytes) {
|
|
57
|
+
const first = state.chunks[0];
|
|
58
|
+
if (first === void 0) {
|
|
59
|
+
state.byteLength = 0;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const excess = state.byteLength - maxBytes;
|
|
63
|
+
if (first.length <= excess) {
|
|
64
|
+
state.chunks.shift();
|
|
65
|
+
state.byteLength -= first.length;
|
|
66
|
+
state.truncated = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
state.chunks[0] = Buffer.from(first.subarray(excess));
|
|
70
|
+
state.byteLength -= excess;
|
|
71
|
+
state.truncated = true;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const streamText = (state) => Buffer.concat(state.chunks, state.byteLength).toString("utf8");
|
|
75
|
+
const createOutputEvent = (nextSequence, create, text) => {
|
|
76
|
+
if (text.length === 0) {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
return create(nextSequence());
|
|
80
|
+
};
|
|
81
|
+
const createGtkAppOutputRecorder = (outputBufferBytes) => {
|
|
82
|
+
const maxBytes = normalizeOutputBufferBytes(outputBufferBytes);
|
|
83
|
+
const stdout = createStreamState();
|
|
84
|
+
const stderr = createStreamState();
|
|
85
|
+
let nextSequence = 0;
|
|
86
|
+
const streamState = (stream) => stream === "stdout" ? stdout : stderr;
|
|
87
|
+
const takeSequence = () => {
|
|
88
|
+
const sequence = nextSequence;
|
|
89
|
+
nextSequence += 1;
|
|
90
|
+
return sequence;
|
|
91
|
+
};
|
|
92
|
+
const createEvent = (stream, text) => createOutputEvent(
|
|
93
|
+
takeSequence,
|
|
94
|
+
(sequence) => ({
|
|
95
|
+
sequence,
|
|
96
|
+
stream,
|
|
97
|
+
text,
|
|
98
|
+
timestampMs: Date.now()
|
|
99
|
+
}),
|
|
100
|
+
text
|
|
101
|
+
);
|
|
102
|
+
return {
|
|
103
|
+
append: (stream, chunk) => {
|
|
104
|
+
const state = streamState(stream);
|
|
105
|
+
appendBoundedChunk(state, chunk, maxBytes);
|
|
106
|
+
return createEvent(stream, state.decoder.decode(chunk, { stream: true }));
|
|
107
|
+
},
|
|
108
|
+
flush: (stream) => {
|
|
109
|
+
const state = streamState(stream);
|
|
110
|
+
if (state.flushed) {
|
|
111
|
+
return void 0;
|
|
112
|
+
}
|
|
113
|
+
state.flushed = true;
|
|
114
|
+
return createEvent(stream, state.decoder.decode());
|
|
115
|
+
},
|
|
116
|
+
snapshot: (exitCode, exitSignal) => ({
|
|
117
|
+
exitCode,
|
|
118
|
+
exitSignal,
|
|
119
|
+
stderr: streamText(stderr),
|
|
120
|
+
stderrTruncated: stderr.truncated,
|
|
121
|
+
stdout: streamText(stdout),
|
|
122
|
+
stdoutTruncated: stdout.truncated
|
|
123
|
+
})
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
const systemOutputSources = [
|
|
127
|
+
"xvfb",
|
|
128
|
+
"launcher-driver",
|
|
129
|
+
"tray-host"
|
|
130
|
+
];
|
|
131
|
+
const createSourceState = () => ({
|
|
132
|
+
stderr: createStreamState(),
|
|
133
|
+
stdout: createStreamState()
|
|
134
|
+
});
|
|
135
|
+
const createGtkSystemOutputRecorder = (systemOutputBufferBytes) => {
|
|
136
|
+
const maxBytes = normalizeOutputBufferBytes(
|
|
137
|
+
systemOutputBufferBytes,
|
|
138
|
+
"systemOutputBufferBytes"
|
|
139
|
+
);
|
|
140
|
+
const sources = /* @__PURE__ */ new Map();
|
|
141
|
+
let nextSequence = 0;
|
|
142
|
+
const takeSequence = () => {
|
|
143
|
+
const sequence = nextSequence;
|
|
144
|
+
nextSequence += 1;
|
|
145
|
+
return sequence;
|
|
146
|
+
};
|
|
147
|
+
const sourceState = (source) => {
|
|
148
|
+
const existing = sources.get(source);
|
|
149
|
+
if (existing !== void 0) {
|
|
150
|
+
return existing;
|
|
151
|
+
}
|
|
152
|
+
const state = createSourceState();
|
|
153
|
+
sources.set(source, state);
|
|
154
|
+
return state;
|
|
155
|
+
};
|
|
156
|
+
const streamState = (source, stream) => {
|
|
157
|
+
const state = sourceState(source);
|
|
158
|
+
return stream === "stdout" ? state.stdout : state.stderr;
|
|
159
|
+
};
|
|
160
|
+
const existingStreamState = (source, stream) => {
|
|
161
|
+
const state = sources.get(source);
|
|
162
|
+
if (state === void 0) {
|
|
163
|
+
return void 0;
|
|
164
|
+
}
|
|
165
|
+
return stream === "stdout" ? state.stdout : state.stderr;
|
|
166
|
+
};
|
|
167
|
+
const createEvent = (source, stream, text) => createOutputEvent(
|
|
168
|
+
takeSequence,
|
|
169
|
+
(sequence) => ({
|
|
170
|
+
sequence,
|
|
171
|
+
source,
|
|
172
|
+
stream,
|
|
173
|
+
text,
|
|
174
|
+
timestampMs: Date.now()
|
|
175
|
+
}),
|
|
176
|
+
text
|
|
177
|
+
);
|
|
178
|
+
const sourceSnapshot = (source, state) => ({
|
|
179
|
+
source,
|
|
180
|
+
stderr: streamText(state.stderr),
|
|
181
|
+
stderrTruncated: state.stderr.truncated,
|
|
182
|
+
stdout: streamText(state.stdout),
|
|
183
|
+
stdoutTruncated: state.stdout.truncated
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
append: (source, stream, chunk) => {
|
|
187
|
+
const state = streamState(source, stream);
|
|
188
|
+
appendBoundedChunk(state, chunk, maxBytes);
|
|
189
|
+
return createEvent(
|
|
190
|
+
source,
|
|
191
|
+
stream,
|
|
192
|
+
state.decoder.decode(chunk, { stream: true })
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
flush: (source, stream) => {
|
|
196
|
+
const state = existingStreamState(source, stream);
|
|
197
|
+
if (state === void 0) {
|
|
198
|
+
return void 0;
|
|
199
|
+
}
|
|
200
|
+
if (state.flushed) {
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
state.flushed = true;
|
|
204
|
+
return createEvent(source, stream, state.decoder.decode());
|
|
205
|
+
},
|
|
206
|
+
snapshot: () => ({
|
|
207
|
+
sources: systemOutputSources.flatMap((source) => {
|
|
208
|
+
const state = sources.get(source);
|
|
209
|
+
return state === void 0 ? [] : [sourceSnapshot(source, state)];
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
const notifyGtkAppOutput = (callback, event) => {
|
|
215
|
+
if (callback === void 0 || event === void 0) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
callback(event);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
queueMicrotask(() => {
|
|
222
|
+
throw error;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const notifyGtkSystemOutput = (callback, event) => {
|
|
227
|
+
if (callback === void 0 || event === void 0) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
callback(event);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
queueMicrotask(() => {
|
|
234
|
+
throw error;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
};
|
|
13
238
|
const defaultDisplay = "xvfb";
|
|
14
239
|
const defaultGSettings = "memory";
|
|
15
240
|
const defaultTheme = "Adwaita";
|
|
@@ -22,8 +247,23 @@ const sessionStartupTimeoutMs = 3e4;
|
|
|
22
247
|
const sessionReleaseTimeoutMs = 5e3;
|
|
23
248
|
const xvfbStartupTimeoutMs = 1e4;
|
|
24
249
|
const xvfbPoolProbeTimeoutMs = 5e3;
|
|
250
|
+
const xvfbPoolProbeRetryIntervalMs = 50;
|
|
251
|
+
const xvfbPoolProbePrefix = "gestament-xvfb-pool-probe: ";
|
|
252
|
+
const x11DisplayOpenFailureMessage = "Failed to open the X11 display. Ensure DISPLAY points to an X11 display.";
|
|
25
253
|
const firstPooledDisplayNumber = 90;
|
|
26
254
|
const lastPooledDisplayNumber = 590;
|
|
255
|
+
const sessionOwnedEnvironmentKeys = [
|
|
256
|
+
"DISPLAY",
|
|
257
|
+
"WAYLAND_DISPLAY",
|
|
258
|
+
"GDK_BACKEND",
|
|
259
|
+
"DBUS_SESSION_BUS_ADDRESS",
|
|
260
|
+
"AT_SPI_BUS_ADDRESS",
|
|
261
|
+
"NO_AT_BRIDGE",
|
|
262
|
+
"XAUTHORITY",
|
|
263
|
+
"GESTAMENT_XVFB_ACTIVE",
|
|
264
|
+
"XDG_SESSION_TYPE"
|
|
265
|
+
];
|
|
266
|
+
let outputScopeCounter = 0;
|
|
27
267
|
let socketCounter = 0;
|
|
28
268
|
const leasedDisplayNumbers = /* @__PURE__ */ new Set();
|
|
29
269
|
const idleXvfbByKey = /* @__PURE__ */ new Map();
|
|
@@ -40,6 +280,12 @@ const appendOutput$1 = (lines, chunk) => {
|
|
|
40
280
|
lines.splice(0, lines.length - 40);
|
|
41
281
|
}
|
|
42
282
|
};
|
|
283
|
+
const appendSystemOutput = (sink, source, stream, chunk) => {
|
|
284
|
+
sink?.append(source, stream, chunk);
|
|
285
|
+
};
|
|
286
|
+
const flushSystemOutput = (sink, source, stream) => {
|
|
287
|
+
sink?.flush(source, stream);
|
|
288
|
+
};
|
|
43
289
|
const unrefHandle = (handle) => {
|
|
44
290
|
const maybeRefHandle = handle;
|
|
45
291
|
if (typeof maybeRefHandle.unref === "function") {
|
|
@@ -58,6 +304,41 @@ ${stdoutText}
|
|
|
58
304
|
stderr:
|
|
59
305
|
${stderrText}`;
|
|
60
306
|
};
|
|
307
|
+
const createXvfbProbeError = (message, retryable) => {
|
|
308
|
+
const error = errors.createGtkOperationFailedError(message);
|
|
309
|
+
Object.defineProperty(error, "retryable", {
|
|
310
|
+
value: retryable
|
|
311
|
+
});
|
|
312
|
+
return error;
|
|
313
|
+
};
|
|
314
|
+
const parseXvfbProbeErrorPayload = (stderrText) => {
|
|
315
|
+
const lines = stderrText.trim().split("\n").reverse();
|
|
316
|
+
for (const line of lines) {
|
|
317
|
+
if (!line.startsWith(xvfbPoolProbePrefix)) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const value = JSON.parse(
|
|
322
|
+
line.slice(xvfbPoolProbePrefix.length)
|
|
323
|
+
);
|
|
324
|
+
if (!isRecord(value)) {
|
|
325
|
+
return void 0;
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
code: typeof value.code === "string" ? value.code : void 0,
|
|
329
|
+
message: typeof value.message === "string" ? value.message : void 0
|
|
330
|
+
};
|
|
331
|
+
} catch {
|
|
332
|
+
return void 0;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return void 0;
|
|
336
|
+
};
|
|
337
|
+
const isRetryableXvfbProbeExit = (stderrText) => {
|
|
338
|
+
const payload = parseXvfbProbeErrorPayload(stderrText);
|
|
339
|
+
return payload?.code === "OPERATION_FAILED" && payload.message === x11DisplayOpenFailureMessage;
|
|
340
|
+
};
|
|
341
|
+
const isRetryableXvfbProbeError = (error) => isRecord(error) && typeof error.retryable === "boolean" && error.retryable;
|
|
61
342
|
const getHostDisplayState = () => ({
|
|
62
343
|
display: process.env.DISPLAY,
|
|
63
344
|
waylandDisplay: process.env.WAYLAND_DISPLAY
|
|
@@ -83,6 +364,63 @@ const resolveDisplay = (display) => {
|
|
|
83
364
|
);
|
|
84
365
|
};
|
|
85
366
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
367
|
+
const createDriverEventKey = (channel, scopeId) => `${channel}
|
|
368
|
+
${scopeId}`;
|
|
369
|
+
const createOutputScopeId = () => {
|
|
370
|
+
const scopeId = `output-${process.pid}-${outputScopeCounter}`;
|
|
371
|
+
outputScopeCounter += 1;
|
|
372
|
+
return scopeId;
|
|
373
|
+
};
|
|
374
|
+
const isDriverEventMessage = (message) => isRecord(message) && message.type === "event" && typeof message.channel === "string" && typeof message.scopeId === "string";
|
|
375
|
+
const resolveOutputBufferBytes = (launcherValue, launchValue) => {
|
|
376
|
+
const value = launchValue ?? launcherValue;
|
|
377
|
+
if (value === void 0) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
381
|
+
throw errors.createGtkInvalidArgumentError(
|
|
382
|
+
"outputBufferBytes must be a non-negative safe integer."
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
return value;
|
|
386
|
+
};
|
|
387
|
+
const createSystemOutputSink = (recorder, callback) => ({
|
|
388
|
+
append: (source, stream, chunk) => {
|
|
389
|
+
notifyGtkSystemOutput(callback, recorder.append(source, stream, chunk));
|
|
390
|
+
},
|
|
391
|
+
flush: (source, stream) => {
|
|
392
|
+
notifyGtkSystemOutput(callback, recorder.flush(source, stream));
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
const isGtkSystemOutputSource = (value) => value === "xvfb" || value === "launcher-driver" || value === "tray-host";
|
|
396
|
+
const isGtkAppOutputStream = (value) => value === "stdout" || value === "stderr";
|
|
397
|
+
const isWireGtkSystemOutput = (value) => {
|
|
398
|
+
if (!isRecord(value)) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
if (!isGtkSystemOutputSource(value.source) || !isGtkAppOutputStream(value.stream)) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
if (value.type === "flush") {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
return value.type === "chunk" && typeof value.chunkBase64 === "string";
|
|
408
|
+
};
|
|
409
|
+
const routeWireSystemOutput = (sink, value) => {
|
|
410
|
+
if (!isWireGtkSystemOutput(value)) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (value.type === "flush") {
|
|
414
|
+
flushSystemOutput(sink, value.source, value.stream);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
appendSystemOutput(
|
|
418
|
+
sink,
|
|
419
|
+
value.source,
|
|
420
|
+
value.stream,
|
|
421
|
+
Buffer.from(value.chunkBase64, "base64")
|
|
422
|
+
);
|
|
423
|
+
};
|
|
86
424
|
const resolvePoolLimit = (name, value, defaultValue) => {
|
|
87
425
|
if (value === void 0) {
|
|
88
426
|
return defaultValue;
|
|
@@ -230,6 +568,7 @@ const retainIdleXvfb = async (xvfb, limits) => {
|
|
|
230
568
|
await terminateXvfb(xvfb);
|
|
231
569
|
return;
|
|
232
570
|
}
|
|
571
|
+
xvfb.systemOutputSink = void 0;
|
|
233
572
|
xvfb.lastUsedAt = Date.now();
|
|
234
573
|
pushArrayEntry(idleXvfbByKey, xvfb.key, xvfb);
|
|
235
574
|
await trimIdleXvfbKey(xvfb.key, limits.maxIdlePerKey);
|
|
@@ -240,6 +579,8 @@ const retainIdleAllSession = async (session, limits) => {
|
|
|
240
579
|
await session.session.terminate();
|
|
241
580
|
return;
|
|
242
581
|
}
|
|
582
|
+
session.session.setSystemOutputSink(void 0);
|
|
583
|
+
session.xvfb.systemOutputSink = void 0;
|
|
243
584
|
session.lastUsedAt = Date.now();
|
|
244
585
|
session.xvfb.lastUsedAt = session.lastUsedAt;
|
|
245
586
|
pushArrayEntry(idleAllByKey, session.key, session);
|
|
@@ -313,15 +654,37 @@ const toWireEnvironment = (env) => {
|
|
|
313
654
|
}
|
|
314
655
|
return wireEnv;
|
|
315
656
|
};
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
657
|
+
const wireEnvironmentToGtkAppEnvironment = (env) => {
|
|
658
|
+
const appEnv = {};
|
|
659
|
+
for (const [key, value] of Object.entries(env)) {
|
|
660
|
+
appEnv[key] = value === null ? void 0 : value;
|
|
661
|
+
}
|
|
662
|
+
return appEnv;
|
|
663
|
+
};
|
|
664
|
+
const assertNoSessionOwnedEnvironmentOverrides = (options, effective) => {
|
|
665
|
+
if (effective.kind !== "xvfb" || options.env === void 0) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
for (const key of sessionOwnedEnvironmentKeys) {
|
|
669
|
+
if (Object.hasOwn(options.env, key)) {
|
|
670
|
+
throw errors.createGtkInvalidArgumentError(
|
|
671
|
+
`options.env must not override ${key} when using internal Xvfb.`
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
const resolveLauncherEnvironment = (options, effective) => {
|
|
677
|
+
assertNoSessionOwnedEnvironmentOverrides(options, effective);
|
|
678
|
+
return toWireEnvironment({
|
|
679
|
+
GDK_BACKEND: resolveGdkBackend(effective),
|
|
680
|
+
GSETTINGS_BACKEND: options.gsettings === null ? void 0 : options.gsettings ?? defaultGSettings,
|
|
681
|
+
GTK_THEME: options.theme === null ? void 0 : options.theme ?? defaultTheme,
|
|
682
|
+
...options.env
|
|
683
|
+
});
|
|
684
|
+
};
|
|
322
685
|
const resolveDriverPath = () => {
|
|
323
686
|
const driverPath = node_path.resolve(
|
|
324
|
-
node_path.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("launchGtkApp-
|
|
687
|
+
node_path.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("launchGtkApp-CzYcrc9f.cjs", document.baseURI).href)),
|
|
325
688
|
"..",
|
|
326
689
|
"dist",
|
|
327
690
|
"gestament-launcher-driver.cjs"
|
|
@@ -335,7 +698,7 @@ const resolveDriverPath = () => {
|
|
|
335
698
|
};
|
|
336
699
|
const resolveXvfbPoolProbePath = () => {
|
|
337
700
|
const probePath = node_path.resolve(
|
|
338
|
-
node_path.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("launchGtkApp-
|
|
701
|
+
node_path.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("launchGtkApp-CzYcrc9f.cjs", document.baseURI).href)),
|
|
339
702
|
"..",
|
|
340
703
|
"dist",
|
|
341
704
|
"gestament-xvfb-pool-probe.cjs"
|
|
@@ -352,11 +715,17 @@ const createDriverEnvironment = (effective, xvfb) => {
|
|
|
352
715
|
delete env.AT_SPI_BUS_ADDRESS;
|
|
353
716
|
delete env.NO_AT_BRIDGE;
|
|
354
717
|
if (effective.kind === "xvfb") {
|
|
718
|
+
delete env.DBUS_SESSION_BUS_ADDRESS;
|
|
719
|
+
delete env.DISPLAY;
|
|
720
|
+
delete env.WAYLAND_DISPLAY;
|
|
721
|
+
delete env.AT_SPI_BUS_ADDRESS;
|
|
722
|
+
delete env.NO_AT_BRIDGE;
|
|
723
|
+
delete env.XAUTHORITY;
|
|
355
724
|
env.GDK_BACKEND = "x11";
|
|
356
725
|
env.GESTAMENT_XVFB_ACTIVE = "1";
|
|
726
|
+
env.XDG_SESSION_TYPE = "x11";
|
|
357
727
|
if (xvfb !== void 0) {
|
|
358
728
|
env.DISPLAY = xvfb.display;
|
|
359
|
-
delete env.XAUTHORITY;
|
|
360
729
|
}
|
|
361
730
|
}
|
|
362
731
|
return env;
|
|
@@ -424,7 +793,7 @@ const installPoolCleanup = () => {
|
|
|
424
793
|
}
|
|
425
794
|
});
|
|
426
795
|
};
|
|
427
|
-
const spawnDirectXvfb = async (screen) => {
|
|
796
|
+
const spawnDirectXvfb = async (screen, systemOutputSink) => {
|
|
428
797
|
installPoolCleanup();
|
|
429
798
|
for (let displayNumber = firstPooledDisplayNumber; displayNumber <= lastPooledDisplayNumber; displayNumber += 1) {
|
|
430
799
|
if (!isDisplayNumberAvailable(displayNumber)) {
|
|
@@ -441,11 +810,30 @@ const spawnDirectXvfb = async (screen) => {
|
|
|
441
810
|
stdio: ["ignore", "pipe", "pipe"]
|
|
442
811
|
}
|
|
443
812
|
);
|
|
813
|
+
const xvfb = {
|
|
814
|
+
child,
|
|
815
|
+
display: `:${displayNumber}`,
|
|
816
|
+
displayNumber,
|
|
817
|
+
key: screen,
|
|
818
|
+
lastUsedAt: Date.now(),
|
|
819
|
+
screen,
|
|
820
|
+
stderr,
|
|
821
|
+
stdout,
|
|
822
|
+
systemOutputSink
|
|
823
|
+
};
|
|
444
824
|
child.stdout.on("data", (chunk) => {
|
|
445
825
|
appendOutput$1(stdout, chunk);
|
|
826
|
+
appendSystemOutput(xvfb.systemOutputSink, "xvfb", "stdout", chunk);
|
|
446
827
|
});
|
|
447
828
|
child.stderr.on("data", (chunk) => {
|
|
448
829
|
appendOutput$1(stderr, chunk);
|
|
830
|
+
appendSystemOutput(xvfb.systemOutputSink, "xvfb", "stderr", chunk);
|
|
831
|
+
});
|
|
832
|
+
child.stdout.once("end", () => {
|
|
833
|
+
flushSystemOutput(xvfb.systemOutputSink, "xvfb", "stdout");
|
|
834
|
+
});
|
|
835
|
+
child.stderr.once("end", () => {
|
|
836
|
+
flushSystemOutput(xvfb.systemOutputSink, "xvfb", "stderr");
|
|
449
837
|
});
|
|
450
838
|
child.unref();
|
|
451
839
|
unrefHandle(child.stdout);
|
|
@@ -468,22 +856,10 @@ const spawnDirectXvfb = async (screen) => {
|
|
|
468
856
|
});
|
|
469
857
|
})
|
|
470
858
|
]);
|
|
471
|
-
const xvfb = {
|
|
472
|
-
child,
|
|
473
|
-
display: `:${displayNumber}`,
|
|
474
|
-
displayNumber,
|
|
475
|
-
key: screen,
|
|
476
|
-
lastUsedAt: Date.now(),
|
|
477
|
-
screen,
|
|
478
|
-
stderr,
|
|
479
|
-
stdout
|
|
480
|
-
};
|
|
481
859
|
directXvfbs.add(xvfb);
|
|
482
860
|
return xvfb;
|
|
483
861
|
} catch (error) {
|
|
484
|
-
killXvfbNow(
|
|
485
|
-
child
|
|
486
|
-
});
|
|
862
|
+
killXvfbNow(xvfb);
|
|
487
863
|
leasedDisplayNumbers.delete(displayNumber);
|
|
488
864
|
const message = error instanceof Error ? error.message : String(error);
|
|
489
865
|
if (message.includes("ENOENT")) {
|
|
@@ -511,39 +887,69 @@ const terminateXvfb = async (xvfb) => {
|
|
|
511
887
|
await delay(25);
|
|
512
888
|
}
|
|
513
889
|
}
|
|
890
|
+
xvfb.systemOutputSink = void 0;
|
|
514
891
|
leasedDisplayNumbers.delete(xvfb.displayNumber);
|
|
515
892
|
};
|
|
516
|
-
const leaseXvfb = async (screen) => {
|
|
893
|
+
const leaseXvfb = async (screen, systemOutputSink) => {
|
|
517
894
|
for (; ; ) {
|
|
518
895
|
const idle = popArrayEntry(idleXvfbByKey, screen);
|
|
519
896
|
if (idle === void 0) {
|
|
520
|
-
return spawnDirectXvfb(screen);
|
|
897
|
+
return spawnDirectXvfb(screen, systemOutputSink);
|
|
521
898
|
}
|
|
522
899
|
if (idle.child.exitCode === null && idle.child.signalCode === null) {
|
|
523
900
|
idle.lastUsedAt = Date.now();
|
|
901
|
+
idle.systemOutputSink = systemOutputSink;
|
|
524
902
|
return idle;
|
|
525
903
|
}
|
|
526
904
|
await terminateXvfb(idle);
|
|
527
905
|
}
|
|
528
906
|
};
|
|
529
|
-
const
|
|
907
|
+
const runXvfbProbeOnce = (xvfb, timeoutMs) => new Promise((resolveProbe, rejectProbe) => {
|
|
530
908
|
const probePath = resolveXvfbPoolProbePath();
|
|
531
909
|
const stdout = [];
|
|
532
910
|
const stderr = [];
|
|
911
|
+
const env = {
|
|
912
|
+
...process.env,
|
|
913
|
+
DISPLAY: xvfb.display,
|
|
914
|
+
GDK_BACKEND: "x11",
|
|
915
|
+
GESTAMENT_XVFB_ACTIVE: "1",
|
|
916
|
+
XDG_SESSION_TYPE: "x11"
|
|
917
|
+
};
|
|
918
|
+
delete env.AT_SPI_BUS_ADDRESS;
|
|
919
|
+
delete env.DBUS_SESSION_BUS_ADDRESS;
|
|
920
|
+
delete env.NO_AT_BRIDGE;
|
|
921
|
+
delete env.WAYLAND_DISPLAY;
|
|
922
|
+
delete env.XAUTHORITY;
|
|
533
923
|
const child = node_child_process.spawn(process.execPath, [probePath], {
|
|
534
|
-
env
|
|
535
|
-
...process.env,
|
|
536
|
-
DISPLAY: xvfb.display,
|
|
537
|
-
GDK_BACKEND: "x11"
|
|
538
|
-
},
|
|
924
|
+
env,
|
|
539
925
|
stdio: ["ignore", "pipe", "pipe"]
|
|
540
926
|
});
|
|
541
|
-
|
|
927
|
+
let settled = false;
|
|
928
|
+
let timeout;
|
|
929
|
+
const rejectOnce = (error) => {
|
|
930
|
+
if (settled) {
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
settled = true;
|
|
934
|
+
if (timeout !== void 0) {
|
|
935
|
+
clearTimeout(timeout);
|
|
936
|
+
}
|
|
937
|
+
rejectProbe(error);
|
|
938
|
+
};
|
|
939
|
+
const resolveOnce = (result) => {
|
|
940
|
+
if (settled) {
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
settled = true;
|
|
944
|
+
if (timeout !== void 0) {
|
|
945
|
+
clearTimeout(timeout);
|
|
946
|
+
}
|
|
947
|
+
resolveProbe(result);
|
|
948
|
+
};
|
|
949
|
+
timeout = setTimeout(() => {
|
|
542
950
|
child.kill("SIGKILL");
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
);
|
|
546
|
-
}, xvfbPoolProbeTimeoutMs);
|
|
951
|
+
rejectOnce(createXvfbProbeError("Timed out probing Xvfb pool.", false));
|
|
952
|
+
}, timeoutMs);
|
|
547
953
|
child.stdout.on("data", (chunk) => {
|
|
548
954
|
appendOutput$1(stdout, chunk);
|
|
549
955
|
});
|
|
@@ -551,42 +957,71 @@ const runXvfbProbe = (xvfb) => new Promise((resolveProbe, rejectProbe) => {
|
|
|
551
957
|
appendOutput$1(stderr, chunk);
|
|
552
958
|
});
|
|
553
959
|
child.once("error", (error) => {
|
|
554
|
-
|
|
555
|
-
rejectProbe(error);
|
|
960
|
+
rejectOnce(error);
|
|
556
961
|
});
|
|
557
962
|
child.once("exit", (code, signal) => {
|
|
558
|
-
clearTimeout(timeout);
|
|
559
963
|
if (code !== 0) {
|
|
560
|
-
|
|
561
|
-
|
|
964
|
+
const stderrText = stderr.join("");
|
|
965
|
+
rejectOnce(
|
|
966
|
+
createXvfbProbeError(
|
|
562
967
|
`Xvfb pool probe failed: code=${String(code)}, signal=${String(
|
|
563
968
|
signal
|
|
564
|
-
)}` + formatOutputTail(stdout, stderr)
|
|
969
|
+
)}` + formatOutputTail(stdout, stderr),
|
|
970
|
+
isRetryableXvfbProbeExit(stderrText)
|
|
565
971
|
)
|
|
566
972
|
);
|
|
567
973
|
return;
|
|
568
974
|
}
|
|
569
975
|
const output = stdout.join("").trim().split("\n").at(-1);
|
|
570
976
|
if (output === void 0 || output.length === 0) {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
"Xvfb pool probe did not return a result." + formatOutputTail(stdout, stderr)
|
|
977
|
+
rejectOnce(
|
|
978
|
+
createXvfbProbeError(
|
|
979
|
+
"Xvfb pool probe did not return a result." + formatOutputTail(stdout, stderr),
|
|
980
|
+
false
|
|
574
981
|
)
|
|
575
982
|
);
|
|
576
983
|
return;
|
|
577
984
|
}
|
|
578
985
|
try {
|
|
579
|
-
|
|
986
|
+
resolveOnce(JSON.parse(output));
|
|
580
987
|
} catch (error) {
|
|
581
988
|
const message = error instanceof Error ? error.message : String(error);
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
`Xvfb pool probe returned invalid JSON: ${message}` + formatOutputTail(stdout, stderr)
|
|
989
|
+
rejectOnce(
|
|
990
|
+
createXvfbProbeError(
|
|
991
|
+
`Xvfb pool probe returned invalid JSON: ${message}` + formatOutputTail(stdout, stderr),
|
|
992
|
+
false
|
|
585
993
|
)
|
|
586
994
|
);
|
|
587
995
|
}
|
|
588
996
|
});
|
|
589
997
|
});
|
|
998
|
+
const runXvfbProbe = async (xvfb) => {
|
|
999
|
+
const startedAt = Date.now();
|
|
1000
|
+
let lastError;
|
|
1001
|
+
while (Date.now() - startedAt < xvfbPoolProbeTimeoutMs) {
|
|
1002
|
+
const remainingTimeoutMs = Math.max(
|
|
1003
|
+
1,
|
|
1004
|
+
xvfbPoolProbeTimeoutMs - (Date.now() - startedAt)
|
|
1005
|
+
);
|
|
1006
|
+
try {
|
|
1007
|
+
return await runXvfbProbeOnce(xvfb, remainingTimeoutMs);
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
lastError = error;
|
|
1010
|
+
if (!isRetryableXvfbProbeError(error)) {
|
|
1011
|
+
throw error;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const remainingDelayMs = xvfbPoolProbeTimeoutMs - (Date.now() - startedAt);
|
|
1015
|
+
if (remainingDelayMs <= 0) {
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
await delay(Math.min(xvfbPoolProbeRetryIntervalMs, remainingDelayMs));
|
|
1019
|
+
}
|
|
1020
|
+
if (lastError instanceof Error) {
|
|
1021
|
+
throw lastError;
|
|
1022
|
+
}
|
|
1023
|
+
throw errors.createGtkOperationFailedError("Timed out probing Xvfb pool.");
|
|
1024
|
+
};
|
|
590
1025
|
const cleanCheckXvfb = async (xvfb, allowedMappedWindowCount) => {
|
|
591
1026
|
try {
|
|
592
1027
|
const probe = await runXvfbProbe(xvfb);
|
|
@@ -605,7 +1040,7 @@ const returnXvfbToPool = async (xvfb, limits) => {
|
|
|
605
1040
|
};
|
|
606
1041
|
const allPoolKey = (xvfb) => `${xvfb.screen}
|
|
607
1042
|
${xvfb.trayHost ? "tray" : "no-tray"}`;
|
|
608
|
-
const spawnDriverProcess = (driverPath, socketPath, effective, xvfb) => {
|
|
1043
|
+
const spawnDriverProcess = (driverPath, socketPath, effective, xvfb, systemOutputSink) => {
|
|
609
1044
|
const driverArgs = [
|
|
610
1045
|
"--socket",
|
|
611
1046
|
socketPath,
|
|
@@ -638,14 +1073,46 @@ const spawnDriverProcess = (driverPath, socketPath, effective, xvfb) => {
|
|
|
638
1073
|
env,
|
|
639
1074
|
stdio: ["ignore", "pipe", "pipe"]
|
|
640
1075
|
});
|
|
1076
|
+
const processState = {
|
|
1077
|
+
child,
|
|
1078
|
+
commandLine: [command.bin, ...command.args].join(" "),
|
|
1079
|
+
stderr,
|
|
1080
|
+
stdout,
|
|
1081
|
+
systemOutputSink
|
|
1082
|
+
};
|
|
641
1083
|
child.stdout.on("data", (chunk) => {
|
|
642
1084
|
appendOutput$1(stdout, chunk);
|
|
1085
|
+
appendSystemOutput(
|
|
1086
|
+
processState.systemOutputSink,
|
|
1087
|
+
"launcher-driver",
|
|
1088
|
+
"stdout",
|
|
1089
|
+
chunk
|
|
1090
|
+
);
|
|
643
1091
|
});
|
|
644
1092
|
child.stderr.on("data", (chunk) => {
|
|
645
1093
|
appendOutput$1(stderr, chunk);
|
|
1094
|
+
appendSystemOutput(
|
|
1095
|
+
processState.systemOutputSink,
|
|
1096
|
+
"launcher-driver",
|
|
1097
|
+
"stderr",
|
|
1098
|
+
chunk
|
|
1099
|
+
);
|
|
646
1100
|
});
|
|
647
|
-
|
|
648
|
-
|
|
1101
|
+
child.stdout.once("end", () => {
|
|
1102
|
+
flushSystemOutput(
|
|
1103
|
+
processState.systemOutputSink,
|
|
1104
|
+
"launcher-driver",
|
|
1105
|
+
"stdout"
|
|
1106
|
+
);
|
|
1107
|
+
});
|
|
1108
|
+
child.stderr.once("end", () => {
|
|
1109
|
+
flushSystemOutput(
|
|
1110
|
+
processState.systemOutputSink,
|
|
1111
|
+
"launcher-driver",
|
|
1112
|
+
"stderr"
|
|
1113
|
+
);
|
|
1114
|
+
});
|
|
1115
|
+
return processState;
|
|
649
1116
|
};
|
|
650
1117
|
const listenOnSocket = (server, socketPath) => new Promise((resolveListen, rejectListen) => {
|
|
651
1118
|
const rejectFromError = (error) => {
|
|
@@ -724,7 +1191,13 @@ const waitForDriverReady = (server, processState) => new Promise((resolveReady,
|
|
|
724
1191
|
const line = input.slice(0, newlineIndex);
|
|
725
1192
|
input = input.slice(newlineIndex + 1);
|
|
726
1193
|
try {
|
|
727
|
-
|
|
1194
|
+
const message = JSON.parse(line);
|
|
1195
|
+
if (isDriverEventMessage(message)) {
|
|
1196
|
+
const event = message;
|
|
1197
|
+
if (event.channel === "system.output") {
|
|
1198
|
+
routeWireSystemOutput(processState.systemOutputSink, event.value);
|
|
1199
|
+
}
|
|
1200
|
+
} else if (isRecord(message) && message.type === "ready" && parseReadyMessage(line) !== void 0) {
|
|
728
1201
|
if (settled) {
|
|
729
1202
|
return;
|
|
730
1203
|
}
|
|
@@ -802,6 +1275,7 @@ const decodeCapture = (capture) => ({
|
|
|
802
1275
|
visibleBounds: capture.visibleBounds
|
|
803
1276
|
});
|
|
804
1277
|
const createDriverSession = (socket, bufferedInput, processState, tempDirectory, poolOptions) => {
|
|
1278
|
+
const eventHandlers = /* @__PURE__ */ new Map();
|
|
805
1279
|
const pending = /* @__PURE__ */ new Map();
|
|
806
1280
|
let input = bufferedInput;
|
|
807
1281
|
let nextRequestId = 1;
|
|
@@ -821,8 +1295,34 @@ const createDriverSession = (socket, bufferedInput, processState, tempDirectory,
|
|
|
821
1295
|
closed = true;
|
|
822
1296
|
rejectPending(errors.createGtkAppExitedError("Launcher driver has exited."));
|
|
823
1297
|
};
|
|
1298
|
+
const handleEvent = (event) => {
|
|
1299
|
+
if (event.channel === "system.output") {
|
|
1300
|
+
routeWireSystemOutput(processState.systemOutputSink, event.value);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
const handlers = eventHandlers.get(
|
|
1304
|
+
createDriverEventKey(event.channel, event.scopeId)
|
|
1305
|
+
);
|
|
1306
|
+
if (handlers === void 0) {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
for (const handler of handlers) {
|
|
1310
|
+
try {
|
|
1311
|
+
handler(event.value);
|
|
1312
|
+
} catch (error) {
|
|
1313
|
+
queueMicrotask(() => {
|
|
1314
|
+
throw error;
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
824
1319
|
const handleResponse = (line) => {
|
|
825
|
-
const
|
|
1320
|
+
const message = JSON.parse(line);
|
|
1321
|
+
if (isDriverEventMessage(message)) {
|
|
1322
|
+
handleEvent(message);
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
const response = message;
|
|
826
1326
|
const entry = pending.get(response.id);
|
|
827
1327
|
if (entry === void 0) {
|
|
828
1328
|
return;
|
|
@@ -897,6 +1397,28 @@ const createDriverSession = (socket, bufferedInput, processState, tempDirectory,
|
|
|
897
1397
|
});
|
|
898
1398
|
});
|
|
899
1399
|
};
|
|
1400
|
+
const subscribe = (channel, scopeId, handler) => {
|
|
1401
|
+
const key = createDriverEventKey(channel, scopeId);
|
|
1402
|
+
const handlers = eventHandlers.get(key) ?? /* @__PURE__ */ new Set();
|
|
1403
|
+
handlers.add(handler);
|
|
1404
|
+
eventHandlers.set(key, handlers);
|
|
1405
|
+
let disposed = false;
|
|
1406
|
+
return {
|
|
1407
|
+
dispose: () => {
|
|
1408
|
+
if (disposed) {
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
disposed = true;
|
|
1412
|
+
handlers.delete(handler);
|
|
1413
|
+
if (handlers.size === 0) {
|
|
1414
|
+
eventHandlers.delete(key);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
};
|
|
1419
|
+
const setSystemOutputSink = (sink) => {
|
|
1420
|
+
processState.systemOutputSink = sink;
|
|
1421
|
+
};
|
|
900
1422
|
const waitForExit = async () => {
|
|
901
1423
|
const startedAt = Date.now();
|
|
902
1424
|
while (processState.child.exitCode === null && processState.child.signalCode === null) {
|
|
@@ -981,10 +1503,10 @@ const createDriverSession = (socket, bufferedInput, processState, tempDirectory,
|
|
|
981
1503
|
poolOptions.limits
|
|
982
1504
|
);
|
|
983
1505
|
};
|
|
984
|
-
session = { release, request, terminate };
|
|
1506
|
+
session = { release, request, setSystemOutputSink, subscribe, terminate };
|
|
985
1507
|
return session;
|
|
986
1508
|
};
|
|
987
|
-
const startFreshDriverSession = async (effective, xvfb, poolOptions) => {
|
|
1509
|
+
const startFreshDriverSession = async (effective, xvfb, poolOptions, systemOutputSink) => {
|
|
988
1510
|
const driverPath = resolveDriverPath();
|
|
989
1511
|
const tempDirectory = node_fs.mkdtempSync(
|
|
990
1512
|
node_path.join(node_os.tmpdir(), `gestament-launcher-${process.pid}-${socketCounter}-`)
|
|
@@ -996,7 +1518,13 @@ const startFreshDriverSession = async (effective, xvfb, poolOptions) => {
|
|
|
996
1518
|
try {
|
|
997
1519
|
await listenOnSocket(server, socketPath);
|
|
998
1520
|
server.unref();
|
|
999
|
-
processState = spawnDriverProcess(
|
|
1521
|
+
processState = spawnDriverProcess(
|
|
1522
|
+
driverPath,
|
|
1523
|
+
socketPath,
|
|
1524
|
+
effective,
|
|
1525
|
+
xvfb,
|
|
1526
|
+
systemOutputSink
|
|
1527
|
+
);
|
|
1000
1528
|
const connection = await waitForDriverReady(server, processState);
|
|
1001
1529
|
server.close();
|
|
1002
1530
|
const resolvedPoolOptions = poolOptions.mode === "all" && xvfb !== void 0 ? {
|
|
@@ -1022,7 +1550,7 @@ const startFreshDriverSession = async (effective, xvfb, poolOptions) => {
|
|
|
1022
1550
|
throw error;
|
|
1023
1551
|
}
|
|
1024
1552
|
};
|
|
1025
|
-
const startDriverSession = async (options) => {
|
|
1553
|
+
const startDriverSession = async (options, systemOutputSink) => {
|
|
1026
1554
|
const display = resolveDisplay(options.display);
|
|
1027
1555
|
const xvfbOptions = resolveXvfbOptions(options);
|
|
1028
1556
|
const effective = resolveEffectiveDisplay(display, xvfbOptions);
|
|
@@ -1030,7 +1558,8 @@ const startDriverSession = async (options) => {
|
|
|
1030
1558
|
return startFreshDriverSession(
|
|
1031
1559
|
effective,
|
|
1032
1560
|
void 0,
|
|
1033
|
-
emptyDriverSessionPoolOptions()
|
|
1561
|
+
emptyDriverSessionPoolOptions(),
|
|
1562
|
+
systemOutputSink
|
|
1034
1563
|
);
|
|
1035
1564
|
}
|
|
1036
1565
|
const pool = effective.xvfb.pool;
|
|
@@ -1038,18 +1567,24 @@ const startDriverSession = async (options) => {
|
|
|
1038
1567
|
return startFreshDriverSession(
|
|
1039
1568
|
effective,
|
|
1040
1569
|
void 0,
|
|
1041
|
-
emptyDriverSessionPoolOptions()
|
|
1570
|
+
emptyDriverSessionPoolOptions(),
|
|
1571
|
+
systemOutputSink
|
|
1042
1572
|
);
|
|
1043
1573
|
}
|
|
1044
1574
|
if (pool.type === "xvfb") {
|
|
1045
|
-
const xvfb2 = await leaseXvfb(effective.xvfb.screen);
|
|
1046
|
-
return startFreshDriverSession(
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1575
|
+
const xvfb2 = await leaseXvfb(effective.xvfb.screen, systemOutputSink);
|
|
1576
|
+
return startFreshDriverSession(
|
|
1577
|
+
effective,
|
|
1578
|
+
xvfb2,
|
|
1579
|
+
{
|
|
1580
|
+
allKey: void 0,
|
|
1581
|
+
allowedMappedWindowCount: 0,
|
|
1582
|
+
limits: poolLimits(pool),
|
|
1583
|
+
mode: "xvfb",
|
|
1584
|
+
xvfb: xvfb2
|
|
1585
|
+
},
|
|
1586
|
+
systemOutputSink
|
|
1587
|
+
);
|
|
1053
1588
|
}
|
|
1054
1589
|
const key = allPoolKey(effective.xvfb);
|
|
1055
1590
|
for (; ; ) {
|
|
@@ -1060,20 +1595,27 @@ const startDriverSession = async (options) => {
|
|
|
1060
1595
|
if (idle.xvfb.child.exitCode === null && idle.xvfb.child.signalCode === null) {
|
|
1061
1596
|
idle.lastUsedAt = Date.now();
|
|
1062
1597
|
idle.xvfb.lastUsedAt = idle.lastUsedAt;
|
|
1598
|
+
idle.xvfb.systemOutputSink = systemOutputSink;
|
|
1599
|
+
idle.session.setSystemOutputSink(systemOutputSink);
|
|
1063
1600
|
return idle.session;
|
|
1064
1601
|
}
|
|
1065
1602
|
await idle.session.terminate().catch(() => void 0);
|
|
1066
1603
|
}
|
|
1067
|
-
const xvfb = await leaseXvfb(effective.xvfb.screen);
|
|
1068
|
-
return startFreshDriverSession(
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1604
|
+
const xvfb = await leaseXvfb(effective.xvfb.screen, systemOutputSink);
|
|
1605
|
+
return startFreshDriverSession(
|
|
1606
|
+
effective,
|
|
1607
|
+
xvfb,
|
|
1608
|
+
{
|
|
1609
|
+
allKey: key,
|
|
1610
|
+
allowedMappedWindowCount: 0,
|
|
1611
|
+
limits: poolLimits(pool),
|
|
1612
|
+
mode: "all",
|
|
1613
|
+
xvfb
|
|
1614
|
+
},
|
|
1615
|
+
systemOutputSink
|
|
1616
|
+
);
|
|
1075
1617
|
};
|
|
1076
|
-
const createLaunchPayload = (options, args) => {
|
|
1618
|
+
const createLaunchPayload = (options, args, launchOptions, outputScopeId) => {
|
|
1077
1619
|
const display = resolveDisplay(options.display);
|
|
1078
1620
|
const xvfb = resolveXvfbOptions(options);
|
|
1079
1621
|
const effective = resolveEffectiveDisplay(display, xvfb);
|
|
@@ -1081,12 +1623,25 @@ const createLaunchPayload = (options, args) => {
|
|
|
1081
1623
|
appPath: options.appPath,
|
|
1082
1624
|
args: [...options.args ?? [], ...args],
|
|
1083
1625
|
env: resolveLauncherEnvironment(options, effective),
|
|
1626
|
+
outputBufferBytes: resolveOutputBufferBytes(
|
|
1627
|
+
options.outputBufferBytes,
|
|
1628
|
+
launchOptions?.outputBufferBytes
|
|
1629
|
+
),
|
|
1630
|
+
outputScopeId,
|
|
1084
1631
|
timeoutMs: options.timeoutMs ?? null
|
|
1085
1632
|
};
|
|
1086
1633
|
};
|
|
1634
|
+
const createEnvironmentPayload = (options) => {
|
|
1635
|
+
const display = resolveDisplay(options.display);
|
|
1636
|
+
const xvfb = resolveXvfbOptions(options);
|
|
1637
|
+
const effective = resolveEffectiveDisplay(display, xvfb);
|
|
1638
|
+
return {
|
|
1639
|
+
env: resolveLauncherEnvironment(options, effective)
|
|
1640
|
+
};
|
|
1641
|
+
};
|
|
1087
1642
|
const elementRefToProxy = (session, ref) => ref === null ? void 0 : createProxyGtkElement(session, ref);
|
|
1088
1643
|
const trayRefToProxy = (session, ref) => ref === null ? void 0 : createProxyGtkTrayItem(session, ref);
|
|
1089
|
-
const createProxyGtkApp = (session, ref) => {
|
|
1644
|
+
const createProxyGtkApp = (session, ref, outputSubscription) => {
|
|
1090
1645
|
let released = false;
|
|
1091
1646
|
const assertNotReleased = () => {
|
|
1092
1647
|
if (released) {
|
|
@@ -1105,10 +1660,15 @@ const createProxyGtkApp = (session, ref) => {
|
|
|
1105
1660
|
return;
|
|
1106
1661
|
}
|
|
1107
1662
|
released = true;
|
|
1663
|
+
outputSubscription?.dispose();
|
|
1108
1664
|
await session.request("app.release", { appId: ref.appId });
|
|
1109
1665
|
};
|
|
1110
1666
|
const app = {
|
|
1111
1667
|
capture: async () => decodeCapture(await appRequest("app.capture")),
|
|
1668
|
+
environment: async () => wireEnvironmentToGtkAppEnvironment(
|
|
1669
|
+
await appRequest("app.environment")
|
|
1670
|
+
),
|
|
1671
|
+
output: () => appRequest("app.output"),
|
|
1112
1672
|
findById: async (id) => elementRefToProxy(
|
|
1113
1673
|
session,
|
|
1114
1674
|
await appRequest("app.findById", { id })
|
|
@@ -1221,6 +1781,13 @@ const createProxyGtkElement = (session, ref) => {
|
|
|
1221
1781
|
};
|
|
1222
1782
|
switch (ref.kind) {
|
|
1223
1783
|
case "window":
|
|
1784
|
+
target.bounds = () => session.request("element.bounds", { elementId });
|
|
1785
|
+
target.resizeHints = () => session.request("window.resizeHints", {
|
|
1786
|
+
elementId
|
|
1787
|
+
});
|
|
1788
|
+
target.x11Info = () => session.request("window.x11Info", { elementId });
|
|
1789
|
+
addChildContainerProxyOperations(session, elementId, target);
|
|
1790
|
+
break;
|
|
1224
1791
|
case "container":
|
|
1225
1792
|
case "menu":
|
|
1226
1793
|
addChildContainerProxyOperations(session, elementId, target);
|
|
@@ -1329,19 +1896,84 @@ const createProxyGtkTrayItem = (session, ref) => {
|
|
|
1329
1896
|
};
|
|
1330
1897
|
};
|
|
1331
1898
|
const createDriverBackedGtkAppLauncher = (options) => {
|
|
1899
|
+
const outputSubscriptions = /* @__PURE__ */ new Set();
|
|
1900
|
+
let systemOutputRecorder = createGtkSystemOutputRecorder(
|
|
1901
|
+
normalizeOutputBufferBytes(
|
|
1902
|
+
options.systemOutputBufferBytes,
|
|
1903
|
+
"systemOutputBufferBytes"
|
|
1904
|
+
)
|
|
1905
|
+
);
|
|
1332
1906
|
let sessionPromise;
|
|
1333
1907
|
const ensureSession = () => {
|
|
1334
|
-
sessionPromise
|
|
1908
|
+
if (sessionPromise === void 0) {
|
|
1909
|
+
systemOutputRecorder = createGtkSystemOutputRecorder(
|
|
1910
|
+
normalizeOutputBufferBytes(
|
|
1911
|
+
options.systemOutputBufferBytes,
|
|
1912
|
+
"systemOutputBufferBytes"
|
|
1913
|
+
)
|
|
1914
|
+
);
|
|
1915
|
+
sessionPromise = startDriverSession(
|
|
1916
|
+
options,
|
|
1917
|
+
createSystemOutputSink(systemOutputRecorder, options.onSystemOutput)
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
1335
1920
|
return sessionPromise;
|
|
1336
1921
|
};
|
|
1337
|
-
const
|
|
1922
|
+
const trackOutputSubscription = (subscription) => {
|
|
1923
|
+
let tracked;
|
|
1924
|
+
tracked = {
|
|
1925
|
+
dispose: () => {
|
|
1926
|
+
if (!outputSubscriptions.delete(tracked)) {
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
subscription.dispose();
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
outputSubscriptions.add(tracked);
|
|
1933
|
+
return tracked;
|
|
1934
|
+
};
|
|
1935
|
+
const disposeOutputSubscriptions = () => {
|
|
1936
|
+
for (const subscription of [...outputSubscriptions]) {
|
|
1937
|
+
subscription.dispose();
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
const launch = async (args, launchOptions) => {
|
|
1338
1941
|
const session = await ensureSession();
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1942
|
+
const onOutput = launchOptions?.onOutput;
|
|
1943
|
+
const outputScopeId = onOutput === void 0 ? null : createOutputScopeId();
|
|
1944
|
+
const outputSubscription = outputScopeId === null ? void 0 : trackOutputSubscription(
|
|
1945
|
+
session.subscribe("app.output", outputScopeId, (value) => {
|
|
1946
|
+
onOutput?.(value);
|
|
1947
|
+
})
|
|
1948
|
+
);
|
|
1949
|
+
const payload = createLaunchPayload(
|
|
1950
|
+
options,
|
|
1951
|
+
args ?? [],
|
|
1952
|
+
launchOptions,
|
|
1953
|
+
outputScopeId
|
|
1342
1954
|
);
|
|
1343
|
-
|
|
1955
|
+
try {
|
|
1956
|
+
const appRef = await session.request(
|
|
1957
|
+
"launcher.launch",
|
|
1958
|
+
payload
|
|
1959
|
+
);
|
|
1960
|
+
return createProxyGtkApp(session, appRef, outputSubscription);
|
|
1961
|
+
} catch (error) {
|
|
1962
|
+
outputSubscription?.dispose();
|
|
1963
|
+
throw error;
|
|
1964
|
+
}
|
|
1344
1965
|
};
|
|
1966
|
+
const environment = async () => {
|
|
1967
|
+
const payload = createEnvironmentPayload(options);
|
|
1968
|
+
const session = await ensureSession();
|
|
1969
|
+
return wireEnvironmentToGtkAppEnvironment(
|
|
1970
|
+
await session.request(
|
|
1971
|
+
"launcher.environment",
|
|
1972
|
+
payload
|
|
1973
|
+
)
|
|
1974
|
+
);
|
|
1975
|
+
};
|
|
1976
|
+
const systemOutput = () => Promise.resolve(systemOutputRecorder.snapshot());
|
|
1345
1977
|
const release = async () => {
|
|
1346
1978
|
const releasingSession = sessionPromise;
|
|
1347
1979
|
sessionPromise = void 0;
|
|
@@ -1349,11 +1981,17 @@ const createDriverBackedGtkAppLauncher = (options) => {
|
|
|
1349
1981
|
return;
|
|
1350
1982
|
}
|
|
1351
1983
|
const session = await releasingSession;
|
|
1352
|
-
|
|
1984
|
+
try {
|
|
1985
|
+
await session.release();
|
|
1986
|
+
} finally {
|
|
1987
|
+
disposeOutputSubscriptions();
|
|
1988
|
+
}
|
|
1353
1989
|
};
|
|
1354
1990
|
return {
|
|
1991
|
+
environment,
|
|
1355
1992
|
launch,
|
|
1356
1993
|
release,
|
|
1994
|
+
systemOutput,
|
|
1357
1995
|
[Symbol.asyncDispose]: release
|
|
1358
1996
|
};
|
|
1359
1997
|
};
|
|
@@ -1760,6 +2398,9 @@ const createImageInfoOperation = (handle) => async () => {
|
|
|
1760
2398
|
capture: async () => native.nativeCaptureBounds(info.bounds)
|
|
1761
2399
|
};
|
|
1762
2400
|
};
|
|
2401
|
+
const createBoundsOperation = (handle) => async () => native.nativeBounds(handle);
|
|
2402
|
+
const createResizeHintsOperation = (handle) => async () => native.nativeResizeHints(handle);
|
|
2403
|
+
const createX11InfoOperation = (handle) => async () => native.nativeX11Info(handle);
|
|
1763
2404
|
const createValueOperation = (handle) => async () => native.nativeValueInfo(handle).value;
|
|
1764
2405
|
const createSetValueOperation = (handle) => async (value) => {
|
|
1765
2406
|
assertFiniteNumber("value", value);
|
|
@@ -1931,7 +2572,10 @@ const createGtkElement = (handle) => {
|
|
|
1931
2572
|
return {
|
|
1932
2573
|
...common,
|
|
1933
2574
|
kind: "window",
|
|
1934
|
-
|
|
2575
|
+
bounds: createBoundsOperation(handle),
|
|
2576
|
+
...createChildContainerOperations(handle, void 0),
|
|
2577
|
+
resizeHints: createResizeHintsOperation(handle),
|
|
2578
|
+
x11Info: createX11InfoOperation(handle)
|
|
1935
2579
|
};
|
|
1936
2580
|
case "button":
|
|
1937
2581
|
return { ...common, kind: "button", click: createClickOperation(handle) };
|
|
@@ -2259,30 +2903,70 @@ const createGtkAppEnvironment = (baseEnv, overrides) => {
|
|
|
2259
2903
|
const launchGtkApp = (appPath, args, options) => {
|
|
2260
2904
|
const _args = args ?? [];
|
|
2261
2905
|
const _timeoutMs = options?.timeoutMs ?? 1e4;
|
|
2906
|
+
const outputBufferBytes = normalizeOutputBufferBytes(
|
|
2907
|
+
options?.outputBufferBytes
|
|
2908
|
+
);
|
|
2909
|
+
const outputRecorder = createGtkAppOutputRecorder(outputBufferBytes);
|
|
2910
|
+
const appEnvironment = createGtkAppEnvironment(process.env, options?.env);
|
|
2262
2911
|
const child = node_child_process.spawn(appPath, [..._args], {
|
|
2263
|
-
env:
|
|
2912
|
+
env: appEnvironment,
|
|
2264
2913
|
stdio: "pipe"
|
|
2265
2914
|
});
|
|
2915
|
+
let resolveClosed;
|
|
2916
|
+
const closedPromise = new Promise((resolve) => {
|
|
2917
|
+
resolveClosed = resolve;
|
|
2918
|
+
});
|
|
2266
2919
|
const state = {
|
|
2267
2920
|
atspiReadiness: "missing-bus-name",
|
|
2268
2921
|
atspiReady: false,
|
|
2922
|
+
closed: false,
|
|
2923
|
+
closedPromise,
|
|
2269
2924
|
exitCode: null,
|
|
2270
2925
|
exitSignal: null,
|
|
2271
2926
|
process: child,
|
|
2927
|
+
released: false,
|
|
2272
2928
|
stderr: [],
|
|
2273
2929
|
stdout: []
|
|
2274
2930
|
};
|
|
2931
|
+
const notifyOutput = (stream, chunk) => {
|
|
2932
|
+
notifyGtkAppOutput(options?.onOutput, outputRecorder.append(stream, chunk));
|
|
2933
|
+
};
|
|
2934
|
+
const flushOutput = (stream) => {
|
|
2935
|
+
notifyGtkAppOutput(options?.onOutput, outputRecorder.flush(stream));
|
|
2936
|
+
};
|
|
2275
2937
|
child.stdout.on("data", (chunk) => {
|
|
2276
2938
|
appendOutput(state.stdout, chunk);
|
|
2939
|
+
notifyOutput("stdout", chunk);
|
|
2277
2940
|
});
|
|
2278
2941
|
child.stderr.on("data", (chunk) => {
|
|
2279
2942
|
appendOutput(state.stderr, chunk);
|
|
2943
|
+
notifyOutput("stderr", chunk);
|
|
2944
|
+
});
|
|
2945
|
+
child.stdout.on("end", () => {
|
|
2946
|
+
flushOutput("stdout");
|
|
2947
|
+
});
|
|
2948
|
+
child.stderr.on("end", () => {
|
|
2949
|
+
flushOutput("stderr");
|
|
2280
2950
|
});
|
|
2281
2951
|
child.on("exit", (code, signal) => {
|
|
2282
2952
|
state.exitCode = code;
|
|
2283
2953
|
state.exitSignal = signal;
|
|
2284
2954
|
});
|
|
2955
|
+
child.on("close", (code, signal) => {
|
|
2956
|
+
if (state.exitCode === null && state.exitSignal === null) {
|
|
2957
|
+
state.exitCode = code;
|
|
2958
|
+
state.exitSignal = signal;
|
|
2959
|
+
}
|
|
2960
|
+
flushOutput("stdout");
|
|
2961
|
+
flushOutput("stderr");
|
|
2962
|
+
state.closed = true;
|
|
2963
|
+
resolveClosed?.();
|
|
2964
|
+
});
|
|
2285
2965
|
const release = async () => {
|
|
2966
|
+
if (state.released) {
|
|
2967
|
+
return;
|
|
2968
|
+
}
|
|
2969
|
+
state.released = true;
|
|
2286
2970
|
if (state.exitCode !== null || state.exitSignal !== null) {
|
|
2287
2971
|
return;
|
|
2288
2972
|
}
|
|
@@ -2296,6 +2980,11 @@ const launchGtkApp = (appPath, args, options) => {
|
|
|
2296
2980
|
await wait.delay(25);
|
|
2297
2981
|
}
|
|
2298
2982
|
};
|
|
2983
|
+
const assertNotReleased = () => {
|
|
2984
|
+
if (state.released) {
|
|
2985
|
+
throw errors.createGtkAppExitedError("GTK application has been released.");
|
|
2986
|
+
}
|
|
2987
|
+
};
|
|
2299
2988
|
const findById = async (id) => {
|
|
2300
2989
|
const startedAt = Date.now();
|
|
2301
2990
|
const timeoutMs = wait.effectiveWaitTimeoutMs(_timeoutMs);
|
|
@@ -2403,6 +3092,7 @@ const launchGtkApp = (appPath, args, options) => {
|
|
|
2403
3092
|
};
|
|
2404
3093
|
const app = {
|
|
2405
3094
|
capture: async () => {
|
|
3095
|
+
assertNotReleased();
|
|
2406
3096
|
assertProcessRunning(state, appPath);
|
|
2407
3097
|
try {
|
|
2408
3098
|
return native.nativeCaptureScreen();
|
|
@@ -2410,6 +3100,21 @@ const launchGtkApp = (appPath, args, options) => {
|
|
|
2410
3100
|
throw errors.normalizeNativeError(error);
|
|
2411
3101
|
}
|
|
2412
3102
|
},
|
|
3103
|
+
environment: async () => {
|
|
3104
|
+
assertNotReleased();
|
|
3105
|
+
assertProcessRunning(state, appPath);
|
|
3106
|
+
return { ...appEnvironment };
|
|
3107
|
+
},
|
|
3108
|
+
output: async () => {
|
|
3109
|
+
assertNotReleased();
|
|
3110
|
+
if ((state.exitCode !== null || state.exitSignal !== null) && !state.closed) {
|
|
3111
|
+
await state.closedPromise;
|
|
3112
|
+
}
|
|
3113
|
+
return outputRecorder.snapshot(
|
|
3114
|
+
state.exitCode,
|
|
3115
|
+
state.exitSignal === null ? null : state.exitSignal
|
|
3116
|
+
);
|
|
3117
|
+
},
|
|
2413
3118
|
findById,
|
|
2414
3119
|
findByPath,
|
|
2415
3120
|
getById,
|
|
@@ -2476,4 +3181,4 @@ const createGtkAppLauncher = (options) => createDriverBackedGtkAppLauncher(optio
|
|
|
2476
3181
|
exports.createGtkAppEnvironment = createGtkAppEnvironment;
|
|
2477
3182
|
exports.createGtkAppLauncher = createGtkAppLauncher;
|
|
2478
3183
|
exports.launchGtkApp = launchGtkApp;
|
|
2479
|
-
//# sourceMappingURL=launchGtkApp-
|
|
3184
|
+
//# sourceMappingURL=launchGtkApp-CzYcrc9f.cjs.map
|