@gtkx/vitest 0.21.0 → 1.0.0-rc.2
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 +137 -34
- package/dist/headless-display.d.ts +31 -0
- package/dist/headless-display.d.ts.map +1 -0
- package/dist/headless-display.js +335 -0
- package/dist/headless-display.js.map +1 -0
- package/dist/headless-globals.d.ts +10 -0
- package/dist/headless-globals.d.ts.map +1 -0
- package/dist/headless-globals.js +13 -0
- package/dist/headless-globals.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -1
- package/dist/index.js.map +1 -1
- package/dist/install-headless-shutdown.d.ts +3 -0
- package/dist/install-headless-shutdown.d.ts.map +1 -0
- package/dist/install-headless-shutdown.js +12 -0
- package/dist/install-headless-shutdown.js.map +1 -0
- package/dist/notification-service.d.ts +3 -0
- package/dist/notification-service.d.ts.map +1 -0
- package/dist/notification-service.js +48 -0
- package/dist/notification-service.js.map +1 -0
- package/dist/resolve-executable.d.ts +3 -0
- package/dist/resolve-executable.d.ts.map +1 -0
- package/dist/resolve-executable.js +26 -0
- package/dist/resolve-executable.js.map +1 -0
- package/dist/virtual-seat.d.ts +3 -0
- package/dist/virtual-seat.d.ts.map +1 -0
- package/dist/virtual-seat.js +155 -0
- package/dist/virtual-seat.js.map +1 -0
- package/dist/worker-preload.d.ts +2 -0
- package/dist/worker-preload.d.ts.map +1 -0
- package/dist/worker-preload.js +7 -0
- package/dist/worker-preload.js.map +1 -0
- package/dist/worker-setup.d.ts +2 -0
- package/dist/worker-setup.d.ts.map +1 -0
- package/dist/worker-setup.js +3 -0
- package/dist/worker-setup.js.map +1 -0
- package/package.json +14 -7
- package/src/dbus-native.d.ts +17 -0
- package/src/headless-display.ts +507 -0
- package/src/headless-globals.ts +22 -0
- package/src/index.ts +72 -1
- package/src/install-headless-shutdown.ts +15 -0
- package/src/notification-service.ts +57 -0
- package/src/resolve-executable.ts +32 -0
- package/src/virtual-seat.ts +214 -0
- package/src/worker-preload.ts +8 -0
- package/src/worker-setup.ts +3 -0
- package/dist/plugin.d.ts +0 -22
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -36
- package/dist/plugin.js.map +0 -1
- package/dist/setup.d.ts +0 -2
- package/dist/setup.d.ts.map +0 -1
- package/dist/setup.js +0 -44
- package/dist/setup.js.map +0 -1
- package/src/plugin.ts +0 -41
- package/src/setup.ts +0 -52
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
var gtkxHeadlessTeardown: (() => void) | undefined;
|
|
3
|
+
var gtkxHeadlessShutdownInstalled: boolean | undefined;
|
|
4
|
+
}
|
|
5
|
+
declare const setHeadlessTeardown: (teardown: (() => void) | undefined) => void;
|
|
6
|
+
declare const headlessTeardown: () => (() => void) | undefined;
|
|
7
|
+
declare const setHeadlessShutdownInstalled: (installed: boolean | undefined) => void;
|
|
8
|
+
declare const isHeadlessShutdownInstalled: () => boolean;
|
|
9
|
+
export { setHeadlessTeardown, headlessTeardown, setHeadlessShutdownInstalled, isHeadlessShutdownInstalled };
|
|
10
|
+
//# sourceMappingURL=headless-globals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-globals.d.ts","sourceRoot":"","sources":["../src/headless-globals.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACX,IAAI,oBAAoB,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACnD,IAAI,6BAA6B,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1D;AAMD,QAAA,MAAM,mBAAmB,GAAI,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,KAAG,IAEjE,CAAC;AAEF,QAAA,MAAM,gBAAgB,QAAO,CAAC,MAAM,IAAI,CAAC,GAAG,SAA4C,CAAC;AAEzF,QAAA,MAAM,4BAA4B,GAAI,WAAW,OAAO,GAAG,SAAS,KAAG,IAEtE,CAAC;AAEF,QAAA,MAAM,2BAA2B,QAAO,OAA4D,CAAC;AAErG,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const defineGlobal = (key, value) => {
|
|
2
|
+
Object.defineProperty(globalThis, key, { value, configurable: true, writable: true });
|
|
3
|
+
};
|
|
4
|
+
const setHeadlessTeardown = (teardown) => {
|
|
5
|
+
defineGlobal("gtkxHeadlessTeardown", teardown);
|
|
6
|
+
};
|
|
7
|
+
const headlessTeardown = () => globalThis.gtkxHeadlessTeardown;
|
|
8
|
+
const setHeadlessShutdownInstalled = (installed) => {
|
|
9
|
+
defineGlobal("gtkxHeadlessShutdownInstalled", installed);
|
|
10
|
+
};
|
|
11
|
+
const isHeadlessShutdownInstalled = () => globalThis.gtkxHeadlessShutdownInstalled === true;
|
|
12
|
+
export { setHeadlessTeardown, headlessTeardown, setHeadlessShutdownInstalled, isHeadlessShutdownInstalled };
|
|
13
|
+
//# sourceMappingURL=headless-globals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-globals.js","sourceRoot":"","sources":["../src/headless-globals.ts"],"names":[],"mappings":"AAKA,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,KAAc,EAAQ,EAAE;IACvD,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1F,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,QAAkC,EAAQ,EAAE;IACrE,YAAY,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,GAA6B,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC;AAEzF,MAAM,4BAA4B,GAAG,CAAC,SAA8B,EAAQ,EAAE;IAC1E,YAAY,CAAC,+BAA+B,EAAE,SAAS,CAAC,CAAC;AAC7D,CAAC,CAAC;AAEF,MAAM,2BAA2B,GAAG,GAAY,EAAE,CAAC,UAAU,CAAC,6BAA6B,KAAK,IAAI,CAAC;AAErG,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,CAAC","sourcesContent":["declare global {\n var gtkxHeadlessTeardown: (() => void) | undefined;\n var gtkxHeadlessShutdownInstalled: boolean | undefined;\n}\n\nconst defineGlobal = (key: string, value: unknown): void => {\n Object.defineProperty(globalThis, key, { value, configurable: true, writable: true });\n};\n\nconst setHeadlessTeardown = (teardown: (() => void) | undefined): void => {\n defineGlobal(\"gtkxHeadlessTeardown\", teardown);\n};\n\nconst headlessTeardown = (): (() => void) | undefined => globalThis.gtkxHeadlessTeardown;\n\nconst setHeadlessShutdownInstalled = (installed: boolean | undefined): void => {\n defineGlobal(\"gtkxHeadlessShutdownInstalled\", installed);\n};\n\nconst isHeadlessShutdownInstalled = (): boolean => globalThis.gtkxHeadlessShutdownInstalled === true;\n\nexport { setHeadlessTeardown, headlessTeardown, setHeadlessShutdownInstalled, isHeadlessShutdownInstalled };\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Plugin } from "vitest/config";
|
|
2
|
+
import { type HeadlessOptions } from "./headless-display.js";
|
|
3
|
+
/**
|
|
4
|
+
* Options accepted by the {@link gtkx} Vitest plugin. Every headless display
|
|
5
|
+
* setting is optional and falls back to a built-in default when omitted.
|
|
6
|
+
*/
|
|
7
|
+
type GtkxPluginOptions = Partial<HeadlessOptions>;
|
|
8
|
+
/**
|
|
9
|
+
* Vitest plugin that runs each test worker against its own isolated headless
|
|
10
|
+
* Wayland display. It configures the forks pool, injects the worker preload and
|
|
11
|
+
* setup files, and sets the environment needed for headless GTK4 rendering.
|
|
12
|
+
*
|
|
13
|
+
* @param options Headless display settings (size, compositor) forwarded to each worker.
|
|
14
|
+
* @returns A Vitest config plugin.
|
|
15
|
+
*/
|
|
16
|
+
declare const gtkx: (options?: GtkxPluginOptions) => Plugin;
|
|
17
|
+
export default gtkx;
|
|
18
|
+
export { type CompositorId, type HeadlessOptions } from "./headless-display.js";
|
|
19
|
+
export { type GtkxPluginOptions };
|
|
2
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,OAAO,EAAE,KAAK,eAAe,EAAuB,MAAM,uBAAuB,CAAC;AAElF;;;GAGG;AACH,KAAK,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AA2BlD;;;;;;;GAOG;AACH,QAAA,MAAM,IAAI,GAAI,UAAS,iBAAsB,KAAG,MAqB1C,CAAC;AAEP,eAAe,IAAI,CAAC;AACpB,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,KAAK,iBAAiB,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,55 @@
|
|
|
1
|
-
|
|
1
|
+
import createConfigPlugin from "@gtkx/config/vite-plugin";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { STATIC_HEADLESS_ENV } from "./headless-display.js";
|
|
6
|
+
const GTKX_INLINE_DEPS = [/@gtkx\/(?!native)/, /[/\\]\.gtkx[/\\]/];
|
|
7
|
+
const workerPreloadUrl = () => {
|
|
8
|
+
const sibling = join(import.meta.dirname, "worker-preload.js");
|
|
9
|
+
const path = existsSync(sibling) ? sibling : join(import.meta.dirname, "..", "dist", "worker-preload.js");
|
|
10
|
+
return pathToFileURL(path);
|
|
11
|
+
};
|
|
12
|
+
const headlessPreloadSpecifier = (options) => {
|
|
13
|
+
const url = workerPreloadUrl();
|
|
14
|
+
for (const [key, value] of Object.entries(options)) {
|
|
15
|
+
url.searchParams.set(key, value);
|
|
16
|
+
}
|
|
17
|
+
return url.href;
|
|
18
|
+
};
|
|
19
|
+
const workerSetupPath = () => {
|
|
20
|
+
const sibling = join(import.meta.dirname, "worker-setup.js");
|
|
21
|
+
return existsSync(sibling) ? sibling : join(import.meta.dirname, "..", "dist", "worker-setup.js");
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Vitest plugin that runs each test worker against its own isolated headless
|
|
25
|
+
* Wayland display. It configures the forks pool, injects the worker preload and
|
|
26
|
+
* setup files, and sets the environment needed for headless GTK4 rendering.
|
|
27
|
+
*
|
|
28
|
+
* @param options Headless display settings (size, compositor) forwarded to each worker.
|
|
29
|
+
* @returns A Vitest config plugin.
|
|
30
|
+
*/
|
|
31
|
+
const gtkx = (options = {}) => createConfigPlugin({
|
|
32
|
+
name: "gtkx:vitest",
|
|
33
|
+
config() {
|
|
34
|
+
return {
|
|
35
|
+
test: {
|
|
36
|
+
globals: true,
|
|
37
|
+
execArgv: ["--import", headlessPreloadSpecifier(options)],
|
|
38
|
+
setupFiles: [workerSetupPath()],
|
|
39
|
+
testTimeout: 30_000,
|
|
40
|
+
hookTimeout: 30_000,
|
|
41
|
+
pool: "forks",
|
|
42
|
+
env: STATIC_HEADLESS_ENV,
|
|
43
|
+
server: {
|
|
44
|
+
deps: {
|
|
45
|
+
inline: GTKX_INLINE_DEPS,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
export default gtkx;
|
|
53
|
+
export {} from "./headless-display.js";
|
|
54
|
+
export {};
|
|
2
55
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,kBAAkB,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAwB,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAQlF,MAAM,gBAAgB,GAAa,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAAC;AAE7E,MAAM,gBAAgB,GAAG,GAAQ,EAAE;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAE1G,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,OAA0B,EAAU,EAAE;IACpE,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAE/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,GAAW,EAAE;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAE7D,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;AACtG,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,IAAI,GAAG,CAAC,UAA6B,EAAE,EAAU,EAAE,CACrD,kBAAkB,CAAC;IACf,IAAI,EAAE,aAAa;IACnB,MAAM;QACF,OAAO;YACH,IAAI,EAAE;gBACF,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,CAAC,UAAU,EAAE,wBAAwB,CAAC,OAAO,CAAC,CAAC;gBACzD,UAAU,EAAE,CAAC,eAAe,EAAE,CAAC;gBAC/B,WAAW,EAAE,MAAM;gBACnB,WAAW,EAAE,MAAM;gBACnB,IAAI,EAAE,OAAO;gBACb,GAAG,EAAE,mBAAmB;gBACxB,MAAM,EAAE;oBACJ,IAAI,EAAE;wBACF,MAAM,EAAE,gBAAgB;qBAC3B;iBACJ;aACJ;SACJ,CAAC;IACN,CAAC;CACJ,CAAC,CAAC;AAEP,eAAe,IAAI,CAAC;AACpB,OAAO,EAA2C,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAA0B,CAAC","sourcesContent":["import type { Plugin } from \"vitest/config\";\nimport createConfigPlugin from \"@gtkx/config/vite-plugin\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { type HeadlessOptions, STATIC_HEADLESS_ENV } from \"./headless-display.js\";\n\n/**\n * Options accepted by the {@link gtkx} Vitest plugin. Every headless display\n * setting is optional and falls back to a built-in default when omitted.\n */\ntype GtkxPluginOptions = Partial<HeadlessOptions>;\n\nconst GTKX_INLINE_DEPS: RegExp[] = [/@gtkx\\/(?!native)/, /[/\\\\]\\.gtkx[/\\\\]/];\n\nconst workerPreloadUrl = (): URL => {\n const sibling = join(import.meta.dirname, \"worker-preload.js\");\n const path = existsSync(sibling) ? sibling : join(import.meta.dirname, \"..\", \"dist\", \"worker-preload.js\");\n\n return pathToFileURL(path);\n};\n\nconst headlessPreloadSpecifier = (options: GtkxPluginOptions): string => {\n const url = workerPreloadUrl();\n\n for (const [key, value] of Object.entries(options)) {\n url.searchParams.set(key, value);\n }\n\n return url.href;\n};\n\nconst workerSetupPath = (): string => {\n const sibling = join(import.meta.dirname, \"worker-setup.js\");\n\n return existsSync(sibling) ? sibling : join(import.meta.dirname, \"..\", \"dist\", \"worker-setup.js\");\n};\n\n/**\n * Vitest plugin that runs each test worker against its own isolated headless\n * Wayland display. It configures the forks pool, injects the worker preload and\n * setup files, and sets the environment needed for headless GTK4 rendering.\n *\n * @param options Headless display settings (size, compositor) forwarded to each worker.\n * @returns A Vitest config plugin.\n */\nconst gtkx = (options: GtkxPluginOptions = {}): Plugin =>\n createConfigPlugin({\n name: \"gtkx:vitest\",\n config() {\n return {\n test: {\n globals: true,\n execArgv: [\"--import\", headlessPreloadSpecifier(options)],\n setupFiles: [workerSetupPath()],\n testTimeout: 30_000,\n hookTimeout: 30_000,\n pool: \"forks\",\n env: STATIC_HEADLESS_ENV,\n server: {\n deps: {\n inline: GTKX_INLINE_DEPS,\n },\n },\n },\n };\n },\n });\n\nexport default gtkx;\nexport { type CompositorId, type HeadlessOptions } from \"./headless-display.js\";\nexport { type GtkxPluginOptions };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-headless-shutdown.d.ts","sourceRoot":"","sources":["../src/install-headless-shutdown.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,uBAAuB,QAAO,IASnC,CAAC;AAEF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { installGracefulShutdown } from "@gtkx/utils";
|
|
2
|
+
import { headlessTeardown, isHeadlessShutdownInstalled, setHeadlessShutdownInstalled } from "./headless-globals.js";
|
|
3
|
+
const installHeadlessShutdown = () => {
|
|
4
|
+
const teardown = headlessTeardown();
|
|
5
|
+
if (teardown === undefined || isHeadlessShutdownInstalled()) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
setHeadlessShutdownInstalled(true);
|
|
9
|
+
installGracefulShutdown({ onSignal: teardown });
|
|
10
|
+
};
|
|
11
|
+
export { installHeadlessShutdown };
|
|
12
|
+
//# sourceMappingURL=install-headless-shutdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-headless-shutdown.js","sourceRoot":"","sources":["../src/install-headless-shutdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAEpH,MAAM,uBAAuB,GAAG,GAAS,EAAE;IACvC,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IAEpC,IAAI,QAAQ,KAAK,SAAS,IAAI,2BAA2B,EAAE,EAAE,CAAC;QAC1D,OAAO;IACX,CAAC;IAED,4BAA4B,CAAC,IAAI,CAAC,CAAC;IACnC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,OAAO,EAAE,uBAAuB,EAAE,CAAC","sourcesContent":["import { installGracefulShutdown } from \"@gtkx/utils\";\nimport { headlessTeardown, isHeadlessShutdownInstalled, setHeadlessShutdownInstalled } from \"./headless-globals.js\";\n\nconst installHeadlessShutdown = (): void => {\n const teardown = headlessTeardown();\n\n if (teardown === undefined || isHeadlessShutdownInstalled()) {\n return;\n }\n\n setHeadlessShutdownInstalled(true);\n installGracefulShutdown({ onSignal: teardown });\n};\n\nexport { installHeadlessShutdown };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-service.d.ts","sourceRoot":"","sources":["../src/notification-service.ts"],"names":[],"mappings":"AAuBA,QAAA,MAAM,wBAAwB,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,MAAM,IAAI,CAe9E,CAAC;AAkBF,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { sessionBus } from "@homebridge/dbus-native";
|
|
2
|
+
const NOTIFICATIONS_NAME = "org.freedesktop.Notifications";
|
|
3
|
+
const NOTIFICATIONS_PATH = "/org/freedesktop/Notifications";
|
|
4
|
+
const DESCRIPTOR = {
|
|
5
|
+
name: NOTIFICATIONS_NAME,
|
|
6
|
+
methods: {
|
|
7
|
+
Notify: [
|
|
8
|
+
"susssasa{sv}i",
|
|
9
|
+
"u",
|
|
10
|
+
["app_name", "replaces_id", "app_icon", "summary", "body", "actions", "hints", "expire_timeout"],
|
|
11
|
+
["id"],
|
|
12
|
+
],
|
|
13
|
+
CloseNotification: ["u", "", ["id"], []],
|
|
14
|
+
GetCapabilities: ["", "as", [], ["capabilities"]],
|
|
15
|
+
},
|
|
16
|
+
signals: {
|
|
17
|
+
NotificationClosed: ["uu", "id", "reason"],
|
|
18
|
+
ActionInvoked: ["us", "id", "action_key"],
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const startNotificationService = async (busAddress) => {
|
|
22
|
+
const bus = sessionBus({ busAddress });
|
|
23
|
+
bus.exportInterface(new NotificationService(), NOTIFICATIONS_PATH, DESCRIPTOR);
|
|
24
|
+
await new Promise((resolve, reject) => {
|
|
25
|
+
bus.requestName(NOTIFICATIONS_NAME, 0, (error) => {
|
|
26
|
+
if (error) {
|
|
27
|
+
reject(error);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
resolve();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
return () => bus.connection.stream.destroy();
|
|
35
|
+
};
|
|
36
|
+
class NotificationService extends EventTarget {
|
|
37
|
+
lastId = 0;
|
|
38
|
+
CloseNotification = () => undefined;
|
|
39
|
+
Notify() {
|
|
40
|
+
this.lastId += 1;
|
|
41
|
+
return this.lastId;
|
|
42
|
+
}
|
|
43
|
+
GetCapabilities() {
|
|
44
|
+
return ["body", "actions"];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export { startNotificationService };
|
|
48
|
+
//# sourceMappingURL=notification-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-service.js","sourceRoot":"","sources":["../src/notification-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE/E,MAAM,kBAAkB,GAAG,+BAA+B,CAAC;AAC3D,MAAM,kBAAkB,GAAG,gCAAgC,CAAC;AAE5D,MAAM,UAAU,GAAwB;IACpC,IAAI,EAAE,kBAAkB;IACxB,OAAO,EAAE;QACL,MAAM,EAAE;YACJ,eAAe;YACf,GAAG;YACH,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC;YAChG,CAAC,IAAI,CAAC;SACT;QACD,iBAAiB,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACxC,eAAe,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC;KACpD;IACD,OAAO,EAAE;QACL,kBAAkB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC1C,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC;KAC5C;CACJ,CAAC;AAEF,MAAM,wBAAwB,GAAG,KAAK,EAAE,UAAkB,EAAuB,EAAE;IAC/E,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IACvC,GAAG,CAAC,eAAe,CAAC,IAAI,mBAAmB,EAAE,EAAE,kBAAkB,EAAE,UAAU,CAAC,CAAC;IAE/E,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,GAAG,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7C,IAAI,KAAK,EAAE,CAAC;gBACR,MAAM,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACJ,OAAO,EAAE,CAAC;YACd,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,mBAAoB,SAAQ,WAAW;IACjC,MAAM,GAAG,CAAC,CAAC;IAEnB,iBAAiB,GAAG,GAAS,EAAE,CAAC,SAAS,CAAC;IAE1C,MAAM;QACF,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QAEjB,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,eAAe;QACX,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/B,CAAC;CACJ;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC","sourcesContent":["import { type InterfaceDescriptor, sessionBus } from \"@homebridge/dbus-native\";\n\nconst NOTIFICATIONS_NAME = \"org.freedesktop.Notifications\";\nconst NOTIFICATIONS_PATH = \"/org/freedesktop/Notifications\";\n\nconst DESCRIPTOR: InterfaceDescriptor = {\n name: NOTIFICATIONS_NAME,\n methods: {\n Notify: [\n \"susssasa{sv}i\",\n \"u\",\n [\"app_name\", \"replaces_id\", \"app_icon\", \"summary\", \"body\", \"actions\", \"hints\", \"expire_timeout\"],\n [\"id\"],\n ],\n CloseNotification: [\"u\", \"\", [\"id\"], []],\n GetCapabilities: [\"\", \"as\", [], [\"capabilities\"]],\n },\n signals: {\n NotificationClosed: [\"uu\", \"id\", \"reason\"],\n ActionInvoked: [\"us\", \"id\", \"action_key\"],\n },\n};\n\nconst startNotificationService = async (busAddress: string): Promise<() => void> => {\n const bus = sessionBus({ busAddress });\n bus.exportInterface(new NotificationService(), NOTIFICATIONS_PATH, DESCRIPTOR);\n\n await new Promise<void>((resolve, reject) => {\n bus.requestName(NOTIFICATIONS_NAME, 0, (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n\n return () => bus.connection.stream.destroy();\n};\n\nclass NotificationService extends EventTarget {\n private lastId = 0;\n\n CloseNotification = (): void => undefined;\n\n Notify(): number {\n this.lastId += 1;\n\n return this.lastId;\n }\n\n GetCapabilities(): string[] {\n return [\"body\", \"actions\"];\n }\n}\n\nexport { startNotificationService };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-executable.d.ts","sourceRoot":"","sources":["../src/resolve-executable.ts"],"names":[],"mappings":"AAaA,QAAA,MAAM,iBAAiB,GAAI,SAAS,MAAM,KAAG,MAgB5C,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { accessSync, constants } from "node:fs";
|
|
2
|
+
import { delimiter, isAbsolute, join } from "node:path";
|
|
3
|
+
const isExecutable = (path) => {
|
|
4
|
+
try {
|
|
5
|
+
accessSync(path, constants.X_OK);
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const resolveExecutable = (command) => {
|
|
13
|
+
if (isAbsolute(command)) {
|
|
14
|
+
return command;
|
|
15
|
+
}
|
|
16
|
+
const searchPaths = (process.env.PATH ?? "").split(delimiter).filter((entry) => entry.length > 0);
|
|
17
|
+
for (const directory of searchPaths) {
|
|
18
|
+
const candidate = join(directory, command);
|
|
19
|
+
if (isExecutable(candidate)) {
|
|
20
|
+
return candidate;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`Cannot find the "${command}" executable on PATH`);
|
|
24
|
+
};
|
|
25
|
+
export { resolveExecutable };
|
|
26
|
+
//# sourceMappingURL=resolve-executable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-executable.js","sourceRoot":"","sources":["../src/resolve-executable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,YAAY,GAAG,CAAC,IAAY,EAAW,EAAE;IAC3C,IAAI,CAAC;QACD,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAEjC,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,OAAe,EAAU,EAAE;IAClD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAElG,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE3C,IAAI,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,OAAO,SAAS,CAAC;QACrB,CAAC;IACL,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,sBAAsB,CAAC,CAAC;AACvE,CAAC,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["import { accessSync, constants } from \"node:fs\";\nimport { delimiter, isAbsolute, join } from \"node:path\";\n\nconst isExecutable = (path: string): boolean => {\n try {\n accessSync(path, constants.X_OK);\n\n return true;\n } catch {\n return false;\n }\n};\n\nconst resolveExecutable = (command: string): string => {\n if (isAbsolute(command)) {\n return command;\n }\n\n const searchPaths = (process.env.PATH ?? \"\").split(delimiter).filter((entry) => entry.length > 0);\n\n for (const directory of searchPaths) {\n const candidate = join(directory, command);\n\n if (isExecutable(candidate)) {\n return candidate;\n }\n }\n\n throw new Error(`Cannot find the \"${command}\" executable on PATH`);\n};\n\nexport { resolveExecutable };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-seat.d.ts","sourceRoot":"","sources":["../src/virtual-seat.ts"],"names":[],"mappings":"AAwMA,QAAA,MAAM,gBAAgB,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,MAAM,IAAI,CAWtE,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { connect } from "node:net";
|
|
2
|
+
const DISPLAY_ID = 1;
|
|
3
|
+
const REGISTRY_ID = 2;
|
|
4
|
+
const FIRST_CLIENT_ID = 3;
|
|
5
|
+
const HEADER_SIZE = 8;
|
|
6
|
+
const WORD_SIZE = 4;
|
|
7
|
+
const OPCODE_MASK = 0xFF_FF;
|
|
8
|
+
const DISPLAY_ERROR = 0;
|
|
9
|
+
const DISPLAY_SYNC = 0;
|
|
10
|
+
const DISPLAY_GET_REGISTRY = 1;
|
|
11
|
+
const REGISTRY_GLOBAL = 0;
|
|
12
|
+
const REGISTRY_BIND = 0;
|
|
13
|
+
const CREATE_DEVICE = 0;
|
|
14
|
+
const SEAT_INTERFACE = "wl_seat";
|
|
15
|
+
const KEYBOARD_MANAGER_INTERFACE = "zwp_virtual_keyboard_manager_v1";
|
|
16
|
+
const POINTER_MANAGER_INTERFACE = "zwlr_virtual_pointer_manager_v1";
|
|
17
|
+
const align4 = (size) => (size + 3) & ~3;
|
|
18
|
+
const encodeString = (value) => {
|
|
19
|
+
const bytes = Buffer.from(`${value}\0`, "utf8");
|
|
20
|
+
const encoded = Buffer.alloc(WORD_SIZE + align4(bytes.length));
|
|
21
|
+
encoded.writeUInt32LE(bytes.length, 0);
|
|
22
|
+
bytes.copy(encoded, WORD_SIZE);
|
|
23
|
+
return encoded;
|
|
24
|
+
};
|
|
25
|
+
const encodeArgument = (argument) => {
|
|
26
|
+
if (typeof argument === "string") {
|
|
27
|
+
return encodeString(argument);
|
|
28
|
+
}
|
|
29
|
+
const encoded = Buffer.alloc(WORD_SIZE);
|
|
30
|
+
encoded.writeUInt32LE(argument, 0);
|
|
31
|
+
return encoded;
|
|
32
|
+
};
|
|
33
|
+
const sendRequest = (state, objectId, opcode, args) => {
|
|
34
|
+
const body = Buffer.concat(args.map((argument) => encodeArgument(argument)));
|
|
35
|
+
const header = Buffer.alloc(HEADER_SIZE);
|
|
36
|
+
header.writeUInt32LE(objectId, 0);
|
|
37
|
+
header.writeUInt32LE(((body.length + HEADER_SIZE) << 16) | opcode, WORD_SIZE);
|
|
38
|
+
state.socket.write(Buffer.concat([header, body]));
|
|
39
|
+
};
|
|
40
|
+
const readString = (body, offset) => {
|
|
41
|
+
const length = body.readUInt32LE(offset);
|
|
42
|
+
return body.subarray(offset + WORD_SIZE, offset + WORD_SIZE + length - 1).toString("utf8");
|
|
43
|
+
};
|
|
44
|
+
const allocateId = (state) => {
|
|
45
|
+
const id = state.nextId;
|
|
46
|
+
state.nextId += 1;
|
|
47
|
+
return id;
|
|
48
|
+
};
|
|
49
|
+
const storeGlobal = (state, body) => {
|
|
50
|
+
const name = body.readUInt32LE(0);
|
|
51
|
+
const interfaceName = readString(body, WORD_SIZE);
|
|
52
|
+
const versionOffset = WORD_SIZE + WORD_SIZE + align4(interfaceName.length + 1);
|
|
53
|
+
state.globals.set(interfaceName, { name, version: body.readUInt32LE(versionOffset) });
|
|
54
|
+
};
|
|
55
|
+
const rejectPending = (state, error) => {
|
|
56
|
+
for (const callback of state.pending.values()) {
|
|
57
|
+
callback.reject(error);
|
|
58
|
+
}
|
|
59
|
+
state.pending.clear();
|
|
60
|
+
};
|
|
61
|
+
const settlePending = (state, objectId) => {
|
|
62
|
+
const callback = state.pending.get(objectId);
|
|
63
|
+
if (callback === undefined) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
state.pending.delete(objectId);
|
|
67
|
+
callback.resolve();
|
|
68
|
+
};
|
|
69
|
+
const handleEvent = (state, objectId, opcode, body) => {
|
|
70
|
+
if (objectId === DISPLAY_ID && opcode === DISPLAY_ERROR) {
|
|
71
|
+
rejectPending(state, new Error(`virtual seat request rejected: ${readString(body, HEADER_SIZE)}`));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (objectId === REGISTRY_ID && opcode === REGISTRY_GLOBAL) {
|
|
75
|
+
storeGlobal(state, body);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
settlePending(state, objectId);
|
|
79
|
+
};
|
|
80
|
+
const consumeMessages = (state) => {
|
|
81
|
+
while (state.inbox.length >= HEADER_SIZE) {
|
|
82
|
+
const objectId = state.inbox.readUInt32LE(0);
|
|
83
|
+
const word = state.inbox.readUInt32LE(WORD_SIZE);
|
|
84
|
+
const size = word >>> 16;
|
|
85
|
+
if (size < HEADER_SIZE || state.inbox.length < size) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
handleEvent(state, objectId, word & OPCODE_MASK, state.inbox.subarray(HEADER_SIZE, size));
|
|
89
|
+
state.inbox = state.inbox.subarray(size);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const receive = (state, chunk) => {
|
|
93
|
+
state.inbox = Buffer.concat([state.inbox, chunk]);
|
|
94
|
+
consumeMessages(state);
|
|
95
|
+
};
|
|
96
|
+
const attachHandlers = (state, onOpen, onFailure) => {
|
|
97
|
+
state.socket.on("data", (chunk) => {
|
|
98
|
+
receive(state, chunk);
|
|
99
|
+
});
|
|
100
|
+
state.socket.on("error", onFailure);
|
|
101
|
+
state.socket.on("close", () => {
|
|
102
|
+
onFailure(new Error("the compositor closed the virtual seat connection"));
|
|
103
|
+
});
|
|
104
|
+
state.socket.once("connect", onOpen);
|
|
105
|
+
};
|
|
106
|
+
const openConnection = (socketPath) => new Promise((resolve, reject) => {
|
|
107
|
+
const socket = connect(socketPath);
|
|
108
|
+
const state = {
|
|
109
|
+
socket,
|
|
110
|
+
globals: new Map(),
|
|
111
|
+
pending: new Map(),
|
|
112
|
+
inbox: Buffer.alloc(0),
|
|
113
|
+
nextId: FIRST_CLIENT_ID,
|
|
114
|
+
};
|
|
115
|
+
attachHandlers(state, () => {
|
|
116
|
+
resolve(state);
|
|
117
|
+
}, (error) => {
|
|
118
|
+
reject(error);
|
|
119
|
+
rejectPending(state, error);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
const roundtrip = (state) => new Promise((resolve, reject) => {
|
|
123
|
+
const callbackId = allocateId(state);
|
|
124
|
+
state.pending.set(callbackId, { resolve, reject });
|
|
125
|
+
sendRequest(state, DISPLAY_ID, DISPLAY_SYNC, [callbackId]);
|
|
126
|
+
});
|
|
127
|
+
const bindGlobal = (state, interfaceName, version) => {
|
|
128
|
+
const entry = state.globals.get(interfaceName);
|
|
129
|
+
if (entry === undefined) {
|
|
130
|
+
throw new Error(`the headless compositor does not implement ${interfaceName}`);
|
|
131
|
+
}
|
|
132
|
+
const id = allocateId(state);
|
|
133
|
+
sendRequest(state, REGISTRY_ID, REGISTRY_BIND, [entry.name, interfaceName, Math.min(version, entry.version), id]);
|
|
134
|
+
return id;
|
|
135
|
+
};
|
|
136
|
+
const createDevices = (state) => {
|
|
137
|
+
const seat = bindGlobal(state, SEAT_INTERFACE, 1);
|
|
138
|
+
const keyboardManager = bindGlobal(state, KEYBOARD_MANAGER_INTERFACE, 1);
|
|
139
|
+
const pointerManager = bindGlobal(state, POINTER_MANAGER_INTERFACE, 1);
|
|
140
|
+
sendRequest(state, keyboardManager, CREATE_DEVICE, [seat, allocateId(state)]);
|
|
141
|
+
sendRequest(state, pointerManager, CREATE_DEVICE, [seat, allocateId(state)]);
|
|
142
|
+
};
|
|
143
|
+
const startVirtualSeat = async (socketPath) => {
|
|
144
|
+
const state = await openConnection(socketPath);
|
|
145
|
+
sendRequest(state, DISPLAY_ID, DISPLAY_GET_REGISTRY, [REGISTRY_ID]);
|
|
146
|
+
await roundtrip(state);
|
|
147
|
+
createDevices(state);
|
|
148
|
+
await roundtrip(state);
|
|
149
|
+
state.socket.unref();
|
|
150
|
+
return () => {
|
|
151
|
+
state.socket.destroy();
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
export { startVirtualSeat };
|
|
155
|
+
//# sourceMappingURL=virtual-seat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-seat.js","sourceRoot":"","sources":["../src/virtual-seat.ts"],"names":[],"mappings":"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","sourcesContent":["import { connect, type Socket } from \"node:net\";\n\ntype WireGlobal = { name: number; version: number };\ntype PendingCallback = { resolve: () => void; reject: (error: Error) => void };\n\ntype WireState = {\n socket: Socket;\n globals: Map<string, WireGlobal>;\n pending: Map<number, PendingCallback>;\n inbox: Buffer;\n nextId: number;\n};\n\nconst DISPLAY_ID = 1;\nconst REGISTRY_ID = 2;\nconst FIRST_CLIENT_ID = 3;\nconst HEADER_SIZE = 8;\nconst WORD_SIZE = 4;\nconst OPCODE_MASK = 0xFF_FF;\nconst DISPLAY_ERROR = 0;\nconst DISPLAY_SYNC = 0;\nconst DISPLAY_GET_REGISTRY = 1;\nconst REGISTRY_GLOBAL = 0;\nconst REGISTRY_BIND = 0;\nconst CREATE_DEVICE = 0;\nconst SEAT_INTERFACE = \"wl_seat\";\nconst KEYBOARD_MANAGER_INTERFACE = \"zwp_virtual_keyboard_manager_v1\";\nconst POINTER_MANAGER_INTERFACE = \"zwlr_virtual_pointer_manager_v1\";\n\nconst align4 = (size: number): number => (size + 3) & ~3;\n\nconst encodeString = (value: string): Buffer => {\n const bytes = Buffer.from(`${value}\\0`, \"utf8\");\n const encoded = Buffer.alloc(WORD_SIZE + align4(bytes.length));\n encoded.writeUInt32LE(bytes.length, 0);\n bytes.copy(encoded, WORD_SIZE);\n\n return encoded;\n};\n\nconst encodeArgument = (argument: number | string): Buffer => {\n if (typeof argument === \"string\") {\n return encodeString(argument);\n }\n\n const encoded = Buffer.alloc(WORD_SIZE);\n encoded.writeUInt32LE(argument, 0);\n\n return encoded;\n};\n\nconst sendRequest = (state: WireState, objectId: number, opcode: number, args: (number | string)[]): void => {\n const body = Buffer.concat(args.map((argument) => encodeArgument(argument)));\n const header = Buffer.alloc(HEADER_SIZE);\n header.writeUInt32LE(objectId, 0);\n header.writeUInt32LE(((body.length + HEADER_SIZE) << 16) | opcode, WORD_SIZE);\n state.socket.write(Buffer.concat([header, body]));\n};\n\nconst readString = (body: Buffer, offset: number): string => {\n const length = body.readUInt32LE(offset);\n\n return body.subarray(offset + WORD_SIZE, offset + WORD_SIZE + length - 1).toString(\"utf8\");\n};\n\nconst allocateId = (state: WireState): number => {\n const id = state.nextId;\n state.nextId += 1;\n\n return id;\n};\n\nconst storeGlobal = (state: WireState, body: Buffer): void => {\n const name = body.readUInt32LE(0);\n const interfaceName = readString(body, WORD_SIZE);\n const versionOffset = WORD_SIZE + WORD_SIZE + align4(interfaceName.length + 1);\n state.globals.set(interfaceName, { name, version: body.readUInt32LE(versionOffset) });\n};\n\nconst rejectPending = (state: WireState, error: Error): void => {\n for (const callback of state.pending.values()) {\n callback.reject(error);\n }\n\n state.pending.clear();\n};\n\nconst settlePending = (state: WireState, objectId: number): void => {\n const callback = state.pending.get(objectId);\n\n if (callback === undefined) {\n return;\n }\n\n state.pending.delete(objectId);\n callback.resolve();\n};\n\nconst handleEvent = (state: WireState, objectId: number, opcode: number, body: Buffer): void => {\n if (objectId === DISPLAY_ID && opcode === DISPLAY_ERROR) {\n rejectPending(state, new Error(`virtual seat request rejected: ${readString(body, HEADER_SIZE)}`));\n\n return;\n }\n\n if (objectId === REGISTRY_ID && opcode === REGISTRY_GLOBAL) {\n storeGlobal(state, body);\n\n return;\n }\n\n settlePending(state, objectId);\n};\n\nconst consumeMessages = (state: WireState): void => {\n while (state.inbox.length >= HEADER_SIZE) {\n const objectId = state.inbox.readUInt32LE(0);\n const word = state.inbox.readUInt32LE(WORD_SIZE);\n const size = word >>> 16;\n\n if (size < HEADER_SIZE || state.inbox.length < size) {\n return;\n }\n\n handleEvent(state, objectId, word & OPCODE_MASK, state.inbox.subarray(HEADER_SIZE, size));\n state.inbox = state.inbox.subarray(size);\n }\n};\n\nconst receive = (state: WireState, chunk: Buffer): void => {\n state.inbox = Buffer.concat([state.inbox, chunk]);\n consumeMessages(state);\n};\n\nconst attachHandlers = (state: WireState, onOpen: () => void, onFailure: (error: Error) => void): void => {\n state.socket.on(\"data\", (chunk: Buffer) => {\n receive(state, chunk);\n });\n\n state.socket.on(\"error\", onFailure);\n\n state.socket.on(\"close\", () => {\n onFailure(new Error(\"the compositor closed the virtual seat connection\"));\n });\n\n state.socket.once(\"connect\", onOpen);\n};\n\nconst openConnection = (socketPath: string): Promise<WireState> =>\n new Promise((resolve, reject) => {\n const socket = connect(socketPath);\n\n const state: WireState = {\n socket,\n globals: new Map(),\n pending: new Map(),\n inbox: Buffer.alloc(0),\n nextId: FIRST_CLIENT_ID,\n };\n\n attachHandlers(\n state,\n () => {\n resolve(state);\n },\n (error) => {\n reject(error);\n rejectPending(state, error);\n },\n );\n });\n\nconst roundtrip = (state: WireState): Promise<void> =>\n new Promise((resolve, reject) => {\n const callbackId = allocateId(state);\n state.pending.set(callbackId, { resolve, reject });\n sendRequest(state, DISPLAY_ID, DISPLAY_SYNC, [callbackId]);\n });\n\nconst bindGlobal = (state: WireState, interfaceName: string, version: number): number => {\n const entry = state.globals.get(interfaceName);\n\n if (entry === undefined) {\n throw new Error(`the headless compositor does not implement ${interfaceName}`);\n }\n\n const id = allocateId(state);\n sendRequest(state, REGISTRY_ID, REGISTRY_BIND, [entry.name, interfaceName, Math.min(version, entry.version), id]);\n\n return id;\n};\n\nconst createDevices = (state: WireState): void => {\n const seat = bindGlobal(state, SEAT_INTERFACE, 1);\n const keyboardManager = bindGlobal(state, KEYBOARD_MANAGER_INTERFACE, 1);\n const pointerManager = bindGlobal(state, POINTER_MANAGER_INTERFACE, 1);\n sendRequest(state, keyboardManager, CREATE_DEVICE, [seat, allocateId(state)]);\n sendRequest(state, pointerManager, CREATE_DEVICE, [seat, allocateId(state)]);\n};\n\nconst startVirtualSeat = async (socketPath: string): Promise<() => void> => {\n const state = await openConnection(socketPath);\n sendRequest(state, DISPLAY_ID, DISPLAY_GET_REGISTRY, [REGISTRY_ID]);\n await roundtrip(state);\n createDevices(state);\n await roundtrip(state);\n state.socket.unref();\n\n return () => {\n state.socket.destroy();\n };\n};\n\nexport { startVirtualSeat };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-preload.d.ts","sourceRoot":"","sources":["../src/worker-preload.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { readHeadlessOptions, resolveHeadlessOptions, startHeadlessDisplay } from "./headless-display.js";
|
|
2
|
+
import { setHeadlessTeardown } from "./headless-globals.js";
|
|
3
|
+
const options = readHeadlessOptions(new URL(import.meta.url).searchParams);
|
|
4
|
+
const teardown = await startHeadlessDisplay(resolveHeadlessOptions(options));
|
|
5
|
+
process.on("exit", teardown);
|
|
6
|
+
setHeadlessTeardown(teardown);
|
|
7
|
+
//# sourceMappingURL=worker-preload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-preload.js","sourceRoot":"","sources":["../src/worker-preload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC1G,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;AAC3E,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC;AAE7E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC7B,mBAAmB,CAAC,QAAQ,CAAC,CAAC","sourcesContent":["import { readHeadlessOptions, resolveHeadlessOptions, startHeadlessDisplay } from \"./headless-display.js\";\nimport { setHeadlessTeardown } from \"./headless-globals.js\";\n\nconst options = readHeadlessOptions(new URL(import.meta.url).searchParams);\nconst teardown = await startHeadlessDisplay(resolveHeadlessOptions(options));\n\nprocess.on(\"exit\", teardown);\nsetHeadlessTeardown(teardown);\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-setup.d.ts","sourceRoot":"","sources":["../src/worker-setup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-setup.js","sourceRoot":"","sources":["../src/worker-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,uBAAuB,EAAE,CAAC","sourcesContent":["import { installHeadlessShutdown } from \"./install-headless-shutdown.js\";\n\ninstallHeadlessShutdown();\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/vitest",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Vitest plugin for GTKX applications with
|
|
3
|
+
"version": "1.0.0-rc.2",
|
|
4
|
+
"description": "Vitest plugin for GTKX applications with headless Wayland display isolation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtkx",
|
|
7
7
|
"gtk",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"vitest",
|
|
10
10
|
"testing",
|
|
11
11
|
"plugin",
|
|
12
|
-
"
|
|
12
|
+
"wayland",
|
|
13
13
|
"linux",
|
|
14
14
|
"desktop"
|
|
15
15
|
],
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/gtkx-org/gtkx.git",
|
|
22
|
+
"url": "git+https://github.com/gtkx-org/gtkx.git",
|
|
23
23
|
"directory": "packages/vitest"
|
|
24
24
|
},
|
|
25
25
|
"license": "MPL-2.0",
|
|
@@ -37,14 +37,21 @@
|
|
|
37
37
|
"dist",
|
|
38
38
|
"src"
|
|
39
39
|
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=24"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@homebridge/dbus-native": "^0.7.8",
|
|
45
|
+
"@gtkx/utils": "1.0.0-rc.2",
|
|
46
|
+
"@gtkx/config": "1.0.0-rc.2"
|
|
47
|
+
},
|
|
40
48
|
"devDependencies": {
|
|
41
|
-
"vitest": "^4.1.
|
|
49
|
+
"vitest": "^4.1.10"
|
|
42
50
|
},
|
|
43
51
|
"peerDependencies": {
|
|
44
52
|
"vitest": ">=4"
|
|
45
53
|
},
|
|
46
54
|
"scripts": {
|
|
47
|
-
"
|
|
48
|
-
"typecheck": "tsc -b --emitDeclarationOnly"
|
|
55
|
+
"release": "tsx ../../scripts/release-package.ts"
|
|
49
56
|
}
|
|
50
57
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "@homebridge/dbus-native";
|
|
2
|
+
|
|
3
|
+
declare module "@homebridge/dbus-native" {
|
|
4
|
+
export type InterfaceDescriptor = {
|
|
5
|
+
name: string;
|
|
6
|
+
methods: Record<string, [string, string, string[], string[]]>;
|
|
7
|
+
signals?: Record<string, [string, ...string[]]>;
|
|
8
|
+
properties?: Record<string, string>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
interface MessageBus {
|
|
12
|
+
exportInterface(implementation: object, path: string, descriptor: InterfaceDescriptor): void;
|
|
13
|
+
requestName(name: string, flags: number, callback: (error: Error | null, result?: number) => void): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function sessionBus(options?: { busAddress?: string }): MessageBus;
|
|
17
|
+
}
|