@nyssance/tauri-hasgard 0.6.0-alpha.1 → 0.6.0-alpha.4

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.
@@ -1,12 +1,42 @@
1
- import {
2
- stopProcessGroup
3
- } from "./chunk-N7YDYAKI.js";
1
+ // src/process-supervisor.js
2
+ import { spawn } from "node:child_process";
3
+ import { lstatSync, unlinkSync } from "node:fs";
4
+ import { createConnection } from "node:net";
5
+ import { setTimeout as delay2 } from "node:timers/promises";
6
+
7
+ // src/process-group.js
8
+ import { setTimeout as delay } from "node:timers/promises";
9
+ function signalGroup(pid, signal) {
10
+ try {
11
+ process.kill(-pid, signal);
12
+ return true;
13
+ } catch (error) {
14
+ if (error.code === "ESRCH")
15
+ return false;
16
+ if (signal === 0 && error.code === "EPERM")
17
+ return true;
18
+ throw error;
19
+ }
20
+ }
21
+ async function waitForExit(pid, timeoutMs) {
22
+ const deadline = Date.now() + timeoutMs;
23
+ while (signalGroup(pid, 0)) {
24
+ if (Date.now() >= deadline)
25
+ return false;
26
+ await delay(25);
27
+ }
28
+ return true;
29
+ }
30
+ async function stopProcessGroup(pid) {
31
+ signalGroup(pid, "SIGTERM");
32
+ if (!await waitForExit(pid, 5000)) {
33
+ signalGroup(pid, "SIGKILL");
34
+ if (!await waitForExit(pid, 5000))
35
+ throw new Error(`Hasgard process group ${pid} survived SIGKILL`);
36
+ }
37
+ }
4
38
 
5
39
  // src/process-supervisor.js
6
- import { spawn } from "child_process";
7
- import { lstatSync, unlinkSync } from "fs";
8
- import { createConnection } from "net";
9
- import { setTimeout as delay } from "timers/promises";
10
40
  var application;
11
41
  var starting = false;
12
42
  var stopping;
@@ -19,7 +49,8 @@ function identity(path) {
19
49
  const stat = lstatSync(path);
20
50
  return { dev: stat.dev, ino: stat.ino, socket: stat.isSocket() };
21
51
  } catch (error) {
22
- if (error.code === "ENOENT") return void 0;
52
+ if (error.code === "ENOENT")
53
+ return;
23
54
  throw error;
24
55
  }
25
56
  }
@@ -27,7 +58,8 @@ function sameIdentity(first, second) {
27
58
  return first && second && first.dev === second.dev && first.ino === second.ino;
28
59
  }
29
60
  function captureEndpoint() {
30
- if (ownedEndpoint || !endpoint) return;
61
+ if (ownedEndpoint || !endpoint)
62
+ return;
31
63
  const current = identity(endpoint);
32
64
  if (current?.socket && !sameIdentity(current, initialEndpoint)) {
33
65
  ownedEndpoint = current;
@@ -35,7 +67,8 @@ function captureEndpoint() {
35
67
  }
36
68
  }
37
69
  async function removeOwnedEndpoint() {
38
- if (!ownedEndpoint || !sameIdentity(identity(endpoint), ownedEndpoint)) return;
70
+ if (!ownedEndpoint || !sameIdentity(identity(endpoint), ownedEndpoint))
71
+ return;
39
72
  const accepting = await new Promise((resolve, reject) => {
40
73
  const socket = createConnection({ path: endpoint });
41
74
  socket.once("connect", () => {
@@ -43,10 +76,12 @@ async function removeOwnedEndpoint() {
43
76
  resolve(true);
44
77
  });
45
78
  socket.once("error", (error) => {
46
- if (error.code === "ECONNREFUSED" || error.code === "ENOENT") resolve(false);
47
- else reject(error);
79
+ if (error.code === "ECONNREFUSED" || error.code === "ENOENT")
80
+ resolve(false);
81
+ else
82
+ reject(error);
48
83
  });
49
- socket.setTimeout(1e3, () => {
84
+ socket.setTimeout(1000, () => {
50
85
  socket.destroy();
51
86
  reject(new Error("Endpoint cleanup probe timed out"));
52
87
  });
@@ -55,35 +90,44 @@ async function removeOwnedEndpoint() {
55
90
  try {
56
91
  unlinkSync(endpoint);
57
92
  } catch (error) {
58
- if (error.code !== "ENOENT") throw error;
93
+ if (error.code !== "ENOENT")
94
+ throw error;
59
95
  }
60
96
  }
61
97
  }
62
98
  process.stderr.on("error", (error) => {
63
- if (error.code !== "EPIPE") shutdown(1);
99
+ if (error.code !== "EPIPE")
100
+ shutdown(1);
64
101
  });
65
102
  function send(message, stream) {
66
- if (!process.connected) return;
103
+ if (!process.connected)
104
+ return;
67
105
  const writable = process.send(message, (error) => {
68
106
  if (error) {
69
107
  if (error.code !== "ERR_IPC_CHANNEL_CLOSED" && error.code !== "EPIPE")
70
108
  process.stderr.write(`Hasgard supervisor IPC: ${error.message}
71
109
  `);
72
- if (process.connected) process.disconnect();
73
- } else stream?.resume();
110
+ if (process.connected)
111
+ process.disconnect();
112
+ } else
113
+ stream?.resume();
74
114
  });
75
- if (!writable) stream?.pause();
115
+ if (!writable)
116
+ stream?.pause();
76
117
  }
77
118
  process.once("message", (config) => {
78
- if (!process.connected || stopping) return;
119
+ if (!process.connected || stopping)
120
+ return;
79
121
  starting = true;
80
122
  try {
81
123
  endpoint = config.env.TAURI_HASGARD_SOCKET;
82
- if (typeof endpoint !== "string" || !endpoint) throw new Error("Supervisor requires TAURI_HASGARD_SOCKET");
124
+ if (typeof endpoint !== "string" || !endpoint)
125
+ throw new Error("Supervisor requires TAURI_HASGARD_SOCKET");
83
126
  initialEndpoint = identity(endpoint);
84
127
  endpointWatch = setInterval(captureEndpoint, 25);
85
128
  process.on("message", (message) => {
86
- if (message.type !== "endpoint") return;
129
+ if (message.type !== "endpoint")
130
+ return;
87
131
  const current = identity(endpoint);
88
132
  if (!current?.socket || !sameIdentity(current, message.identity)) {
89
133
  send({ type: "error", message: "Application endpoint changed during readiness" });
@@ -109,7 +153,8 @@ process.once("message", (config) => {
109
153
  }
110
154
  });
111
155
  process.once("disconnect", () => shutdown(0));
112
- for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"]) process.on(signal, () => shutdown(0));
156
+ for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"])
157
+ process.on(signal, () => shutdown(0));
113
158
  process.on("uncaughtException", (error) => {
114
159
  process.stderr.write(`Hasgard supervisor error: ${error.stack}
115
160
  `);
@@ -121,15 +166,17 @@ process.on("unhandledRejection", (error) => {
121
166
  shutdown(1);
122
167
  });
123
168
  function shutdown(exitCode) {
124
- if (!stopping) stopping = cleanup(exitCode);
169
+ if (!stopping)
170
+ stopping = cleanup(exitCode);
125
171
  }
126
172
  async function cleanup(exitCode) {
127
173
  clearInterval(endpointWatch);
128
174
  const pid = application?.pid;
129
- if (!starting || pid === void 0) process.exit(exitCode);
175
+ if (!starting || pid === undefined)
176
+ process.exit(exitCode);
130
177
  let groupStopped = false;
131
178
  let endpointFailures = 0;
132
- for (; ; ) {
179
+ for (;; ) {
133
180
  try {
134
181
  let endpointError;
135
182
  try {
@@ -141,14 +188,16 @@ async function cleanup(exitCode) {
141
188
  await stopProcessGroup(pid);
142
189
  groupStopped = true;
143
190
  }
144
- if (endpointError) throw endpointError;
191
+ if (endpointError)
192
+ throw endpointError;
145
193
  await removeOwnedEndpoint();
146
194
  process.exit(exitCode);
147
195
  } catch (error) {
148
196
  process.stderr.write(`Hasgard orphan cleanup: ${error.message}
149
197
  `);
150
- if (groupStopped && ++endpointFailures >= 3) process.exit(1);
151
- await delay(1e3);
198
+ if (groupStopped && ++endpointFailures >= 3)
199
+ process.exit(1);
200
+ await delay2(1000);
152
201
  }
153
202
  }
154
203
  }
package/dist/window.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { HasgardRpcClient } from "./rpc-client.js";
1
+ import type { HasgardRpcClient } from "./rpc-client.js";
2
2
  import type { BoundingBox, ClickOptions, ConsoleLogEntry, ConsoleLogOptions, DialogListing, DialogPolicy, DiffOptions, DragOffset, DropFile, FileInput, FilterOptions, FormsDump, FulfillOptions, HasgardTarget, JsonValue, NativeScreenshot, NativeScreenshotOptions, NetworkRequestEntry, NetworkRequestOptions, PressOptions, QueryDimension, RecorderEntry, RecorderResult, RecorderStatus, RoleQuery, RouteListing, RouteOptions, ScrollOptions, Snapshot, SnapshotDiff, SnapshotOptions, StorageListing, StorageOptions, TextQuery, WaitForFunctionOptions, WaitOptions, WatchChanges, WatchOptions, WindowInfo, WindowState } from "./types.js";
3
3
  export declare const byRef: (ref: string) => HasgardTarget;
4
4
  export declare const bySelector: (selector: string) => HasgardTarget;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nyssance/tauri-hasgard",
3
- "version": "0.6.0-alpha.1",
3
+ "version": "0.6.0-alpha.4",
4
4
  "description": "Playwright Test fixtures for native Tauri Hasgard automation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,24 +18,23 @@
18
18
  "NOTICE.md"
19
19
  ],
20
20
  "scripts": {
21
- "build": "bun node_modules/tsup/dist/cli-default.js src/index.ts src/process-supervisor.js --format esm --outDir dist --clean && bun node_modules/typescript/bin/tsc -p tsconfig.json --noEmit false --emitDeclarationOnly --declaration true",
21
+ "build": "bun run clean && bun build src/index.ts src/process-supervisor.js --target node --format esm --outdir dist --packages external && bun node_modules/typescript/bin/tsc -p tsconfig.json --noEmit false --emitDeclarationOnly --declaration true",
22
22
  "dev": "bun run --parallel dev:js dev:types",
23
23
  "test": "vitest run",
24
24
  "test:watch": "vitest",
25
- "typecheck": "tsc --noEmit",
25
+ "typecheck": "bun check --no-script",
26
26
  "clean": "rm -rf dist",
27
- "dev:js": "tsup src/index.ts src/process-supervisor.js --format esm --outDir dist --watch",
27
+ "dev:js": "bun build src/index.ts src/process-supervisor.js --target node --format esm --outdir dist --packages external --watch",
28
28
  "dev:types": "tsc -p tsconfig.json --noEmit false --emitDeclarationOnly --declaration true --watch"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@playwright/test": ">=1.61.1 <2"
32
32
  },
33
33
  "devDependencies": {
34
- "@playwright/test": "1.62.1",
35
- "@types/node": "^26.1.0",
36
- "tsup": "^8.5.1",
34
+ "@playwright/test": "1.64.1",
35
+ "@types/node": "^26.6.5",
37
36
  "typescript": "^7.0.2",
38
- "vitest": "^4.1.10"
37
+ "vitest": "^5.0.5"
39
38
  },
40
39
  "keywords": [
41
40
  "tauri",
@@ -1,31 +0,0 @@
1
- // src/process-group.js
2
- import { setTimeout as delay } from "timers/promises";
3
- function signalGroup(pid, signal) {
4
- try {
5
- process.kill(-pid, signal);
6
- return true;
7
- } catch (error) {
8
- if (error.code === "ESRCH") return false;
9
- if (signal === 0 && error.code === "EPERM") return true;
10
- throw error;
11
- }
12
- }
13
- async function waitForExit(pid, timeoutMs) {
14
- const deadline = Date.now() + timeoutMs;
15
- while (signalGroup(pid, 0)) {
16
- if (Date.now() >= deadline) return false;
17
- await delay(25);
18
- }
19
- return true;
20
- }
21
- async function stopProcessGroup(pid) {
22
- signalGroup(pid, "SIGTERM");
23
- if (!await waitForExit(pid, 5e3)) {
24
- signalGroup(pid, "SIGKILL");
25
- if (!await waitForExit(pid, 5e3)) throw new Error(`Hasgard process group ${pid} survived SIGKILL`);
26
- }
27
- }
28
-
29
- export {
30
- stopProcessGroup
31
- };