@monoes/monobrowse 1.0.27 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/src/__tests__/disconnect-session.test.d.ts +13 -0
  2. package/dist/src/__tests__/disconnect-session.test.d.ts.map +1 -0
  3. package/dist/src/__tests__/disconnect-session.test.js +37 -0
  4. package/dist/src/__tests__/disconnect-session.test.js.map +1 -0
  5. package/dist/src/__tests__/profile-cleanup-close.test.d.ts +16 -0
  6. package/dist/src/__tests__/profile-cleanup-close.test.d.ts.map +1 -0
  7. package/dist/src/__tests__/profile-cleanup-close.test.js +250 -0
  8. package/dist/src/__tests__/profile-cleanup-close.test.js.map +1 -0
  9. package/dist/src/__tests__/profile-dir.test.d.ts +10 -0
  10. package/dist/src/__tests__/profile-dir.test.d.ts.map +1 -0
  11. package/dist/src/__tests__/profile-dir.test.js +160 -0
  12. package/dist/src/__tests__/profile-dir.test.js.map +1 -0
  13. package/dist/src/__tests__/setup/isolated-tmpdir.global.d.ts +2 -0
  14. package/dist/src/__tests__/setup/isolated-tmpdir.global.d.ts.map +1 -0
  15. package/dist/src/__tests__/setup/isolated-tmpdir.global.js +30 -0
  16. package/dist/src/__tests__/setup/isolated-tmpdir.global.js.map +1 -0
  17. package/dist/src/browser/browser-launch.d.ts.map +1 -1
  18. package/dist/src/browser/browser-launch.js +21 -4
  19. package/dist/src/browser/browser-launch.js.map +1 -1
  20. package/dist/src/browser/browser-lifecycle.d.ts +5 -0
  21. package/dist/src/browser/browser-lifecycle.d.ts.map +1 -1
  22. package/dist/src/browser/browser-lifecycle.js +23 -11
  23. package/dist/src/browser/browser-lifecycle.js.map +1 -1
  24. package/dist/src/browser/browser-state.d.ts +4 -0
  25. package/dist/src/browser/browser-state.d.ts.map +1 -1
  26. package/dist/src/browser/browser-state.js +10 -2
  27. package/dist/src/browser/browser-state.js.map +1 -1
  28. package/dist/src/browser/browser.d.ts +1 -1
  29. package/dist/src/browser/browser.d.ts.map +1 -1
  30. package/dist/src/browser/browser.js +1 -1
  31. package/dist/src/browser/browser.js.map +1 -1
  32. package/dist/src/browser/profile-dir.d.ts +88 -0
  33. package/dist/src/browser/profile-dir.d.ts.map +1 -0
  34. package/dist/src/browser/profile-dir.js +242 -0
  35. package/dist/src/browser/profile-dir.js.map +1 -0
  36. package/dist/src/browser/ref-cache.d.ts +4 -0
  37. package/dist/src/browser/ref-cache.d.ts.map +1 -1
  38. package/dist/src/browser/ref-cache.js +2 -0
  39. package/dist/src/browser/ref-cache.js.map +1 -1
  40. package/dist/src/browser/types.d.ts +6 -0
  41. package/dist/src/browser/types.d.ts.map +1 -1
  42. package/dist/src/browser/types.js.map +1 -1
  43. package/dist/src/cli/commands.d.ts +1 -0
  44. package/dist/src/cli/commands.d.ts.map +1 -1
  45. package/dist/src/cli/commands.js +2 -0
  46. package/dist/src/cli/commands.js.map +1 -1
  47. package/dist/src/cli/session.d.ts +9 -0
  48. package/dist/src/cli/session.d.ts.map +1 -1
  49. package/dist/src/cli/session.js +21 -4
  50. package/dist/src/cli/session.js.map +1 -1
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +1 -1
  53. package/src/__tests__/disconnect-session.test.ts +42 -0
  54. package/src/__tests__/profile-cleanup-close.test.ts +285 -0
  55. package/src/__tests__/profile-dir.test.ts +196 -0
  56. package/src/__tests__/setup/isolated-tmpdir.global.ts +28 -0
  57. package/src/browser/browser-launch.ts +22 -5
  58. package/src/browser/browser-lifecycle.ts +20 -10
  59. package/src/browser/browser-state.ts +11 -2
  60. package/src/browser/browser.ts +5 -1
  61. package/src/browser/profile-dir.ts +249 -0
  62. package/src/browser/ref-cache.ts +7 -0
  63. package/src/browser/types.ts +6 -0
  64. package/src/cli/commands.ts +2 -0
  65. package/src/cli/session.ts +22 -4
@@ -0,0 +1,13 @@
1
+ /**
2
+ * disconnectSession() — drops this process's CDP connection without touching
3
+ * the browser (#408).
4
+ *
5
+ * `monomind browse` runs inside a CLI that lets the event loop drain instead
6
+ * of calling process.exit() (ADR-R001). A CDP websocket left open after the
7
+ * subcommand printed its output kept every `monomind browse …` alive until the
8
+ * 5 s force-exit watchdog. The embedder calls disconnectSession() once the
9
+ * subcommand is done; the browser must survive it, because the next command
10
+ * (a new process) reconnects to that same session.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=disconnect-session.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disconnect-session.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/disconnect-session.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * disconnectSession() — drops this process's CDP connection without touching
3
+ * the browser (#408).
4
+ *
5
+ * `monomind browse` runs inside a CLI that lets the event loop drain instead
6
+ * of calling process.exit() (ADR-R001). A CDP websocket left open after the
7
+ * subcommand printed its output kept every `monomind browse …` alive until the
8
+ * 5 s force-exit watchdog. The embedder calls disconnectSession() once the
9
+ * subcommand is done; the browser must survive it, because the next command
10
+ * (a new process) reconnects to that same session.
11
+ */
12
+ import { describe, expect, it, vi } from 'vitest';
13
+ import { disconnectSession } from '../cli/commands.js';
14
+ import { session } from '../cli/session.js';
15
+ describe('disconnectSession', () => {
16
+ it('closes the CDP client and clears it, leaving the session record alone', () => {
17
+ const close = vi.fn();
18
+ const send = vi.fn();
19
+ session.client = { close, send };
20
+ session.sessionId = 'sid-1';
21
+ session.port = 9333;
22
+ disconnectSession();
23
+ expect(close).toHaveBeenCalledTimes(1);
24
+ // No CDP command either: Browser.close would end the session others reuse.
25
+ expect(send).not.toHaveBeenCalled();
26
+ expect(session.client).toBeNull();
27
+ expect(session.sessionId).toBe('');
28
+ // The port pin survives so a later in-process command resolves the same session.
29
+ expect(session.port).toBe(9333);
30
+ });
31
+ it('is a no-op when no client was ever connected', () => {
32
+ session.client = null;
33
+ expect(() => disconnectSession()).not.toThrow();
34
+ expect(session.client).toBeNull();
35
+ });
36
+ });
37
+ //# sourceMappingURL=disconnect-session.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disconnect-session.test.js","sourceRoot":"","sources":["../../../src/__tests__/disconnect-session.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACrB,OAAO,CAAC,MAAM,GAAG,EAAE,KAAK,EAAE,IAAI,EAA0B,CAAC;QACzD,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC;QAC5B,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;QAEpB,iBAAiB,EAAE,CAAC;QAEpB,MAAM,CAAC,KAAK,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACvC,2EAA2E;QAC3E,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnC,iFAAiF;QACjF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * #395: closing (or killing) a browser monobrowse launched deletes the temp
3
+ * profile dir monobrowse created for it — and never a caller-supplied one.
4
+ *
5
+ * No real Chrome: launchBrowser spawns a fake-chrome script that behaves
6
+ * like Chrome where it matters here (creates and writes into its
7
+ * --user-data-dir, serves /json/version, announces its browser id on stderr,
8
+ * writes DevToolsActivePort for port 0). Browser.close goes over a fake `ws`
9
+ * socket that kills the fixture, as a real Chrome exits on it. A client that
10
+ * never connected drives the kill fallback (its Browser.close fails at once).
11
+ *
12
+ * TMPDIR is pointed at a root of each test's own, so both the launch-time
13
+ * sweep and the default profile dir live there — never the real /tmp.
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=profile-cleanup-close.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-cleanup-close.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/profile-cleanup-close.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,250 @@
1
+ /**
2
+ * #395: closing (or killing) a browser monobrowse launched deletes the temp
3
+ * profile dir monobrowse created for it — and never a caller-supplied one.
4
+ *
5
+ * No real Chrome: launchBrowser spawns a fake-chrome script that behaves
6
+ * like Chrome where it matters here (creates and writes into its
7
+ * --user-data-dir, serves /json/version, announces its browser id on stderr,
8
+ * writes DevToolsActivePort for port 0). Browser.close goes over a fake `ws`
9
+ * socket that kills the fixture, as a real Chrome exits on it. A client that
10
+ * never connected drives the kill fallback (its Browser.close fails at once).
11
+ *
12
+ * TMPDIR is pointed at a root of each test's own, so both the launch-time
13
+ * sweep and the default profile dir live there — never the real /tmp.
14
+ */
15
+ import { spawn } from 'node:child_process';
16
+ import { chmodSync, existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs';
17
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
18
+ import { createServer } from 'node:net';
19
+ import { tmpdir } from 'node:os';
20
+ import { join } from 'node:path';
21
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
22
+ let onBrowserClose = null;
23
+ let lastSocket = null;
24
+ /** Acknowledges every command; `Browser.close` also runs onBrowserClose. */
25
+ class FakeWs {
26
+ url;
27
+ handlers = new Map();
28
+ constructor(url) {
29
+ this.url = url;
30
+ lastSocket = this;
31
+ }
32
+ on(event, fn) {
33
+ if (!this.handlers.has(event))
34
+ this.handlers.set(event, []);
35
+ this.handlers.get(event).push(fn);
36
+ }
37
+ emit(event, ...args) {
38
+ for (const fn of [...(this.handlers.get(event) ?? [])])
39
+ fn(...args);
40
+ }
41
+ send(data) {
42
+ const { id, method } = JSON.parse(data);
43
+ if (method === 'Browser.close')
44
+ onBrowserClose?.();
45
+ queueMicrotask(() => this.emit('message', Buffer.from(JSON.stringify({ id, result: {} }))));
46
+ }
47
+ close() { }
48
+ }
49
+ vi.mock('ws', () => ({ WebSocket: FakeWs }));
50
+ // Exits once the test process is gone, and within a minute regardless, so a
51
+ // fixture never outlives the run.
52
+ const FAKE_CHROME = `#!/usr/bin/env node
53
+ const parent = process.ppid;
54
+ setInterval(() => {
55
+ try { if (process.ppid !== parent) process.exit(0); process.kill(parent, 0); } catch { process.exit(0); }
56
+ }, 1000).unref();
57
+ setTimeout(() => process.exit(0), 60000).unref();
58
+ const { createServer } = require('node:http');
59
+ const { mkdirSync, writeFileSync } = require('node:fs');
60
+ const { join } = require('node:path');
61
+ const arg = (k) => process.argv.find((a) => a.startsWith(k + '=')).slice(k.length + 1);
62
+ const dir = arg('--user-data-dir');
63
+ const wanted = Number(arg('--remote-debugging-port'));
64
+ mkdirSync(join(dir, 'Default'), { recursive: true });
65
+ writeFileSync(join(dir, 'Default', 'Preferences'), '{}');
66
+ const server = createServer((req, res) => {
67
+ const port = server.address().port;
68
+ const ws = 'ws://127.0.0.1:' + port + '/devtools/browser/fake-' + process.pid;
69
+ res.writeHead(200, { 'Content-Type': 'application/json' });
70
+ res.end(req.url === '/json/version'
71
+ ? JSON.stringify({ Browser: 'Chrome/999.0.0.0', webSocketDebuggerUrl: ws })
72
+ : '[]');
73
+ });
74
+ server.listen(wanted, '127.0.0.1', () => {
75
+ const port = server.address().port;
76
+ if (wanted === 0) writeFileSync(join(dir, 'DevToolsActivePort'), port + '\\n/devtools/browser/fake');
77
+ process.stderr.write('DevTools listening on ws://127.0.0.1:' + port + '/devtools/browser/fake-' + process.pid + '\\n');
78
+ });
79
+ `;
80
+ let root;
81
+ let fixtures;
82
+ let cwd;
83
+ let exe;
84
+ const children = [];
85
+ const launchedPids = [];
86
+ beforeEach(async () => {
87
+ root = await mkdtemp(join(tmpdir(), 'monobrowse-395-root-'));
88
+ fixtures = await mkdtemp(join(tmpdir(), 'monobrowse-395-fixture-'));
89
+ cwd = await mkdtemp(join(tmpdir(), 'monobrowse-395-cwd-'));
90
+ vi.stubEnv('TMPDIR', root);
91
+ vi.spyOn(process, 'cwd').mockReturnValue(cwd);
92
+ exe = join(fixtures, 'fake-chrome.cjs');
93
+ writeFileSync(exe, FAKE_CHROME);
94
+ chmodSync(exe, 0o755);
95
+ onBrowserClose = null;
96
+ lastSocket = null;
97
+ vi.resetModules();
98
+ });
99
+ afterEach(async () => {
100
+ vi.unstubAllEnvs();
101
+ vi.restoreAllMocks();
102
+ for (const pid of launchedPids.splice(0)) {
103
+ try {
104
+ process.kill(pid, 'SIGKILL');
105
+ }
106
+ catch {
107
+ /* already gone */
108
+ }
109
+ }
110
+ for (const child of children.splice(0))
111
+ child.kill('SIGKILL');
112
+ for (const dir of [root, fixtures, cwd])
113
+ await rm(dir, { recursive: true, force: true });
114
+ });
115
+ function freePort() {
116
+ return new Promise((resolve, reject) => {
117
+ const server = createServer();
118
+ server.once('error', reject);
119
+ server.listen(0, '127.0.0.1', () => {
120
+ const { port } = server.address();
121
+ server.close(() => resolve(port));
122
+ });
123
+ });
124
+ }
125
+ /** A client whose Browser.close is acknowledged, and makes `pid` exit the
126
+ * way Chrome does on it. */
127
+ async function gracefulClient(pid) {
128
+ const { CdpClient } = await import('../browser/cdp.js');
129
+ const client = new CdpClient();
130
+ const p = client.connect('ws://127.0.0.1:1/devtools/browser/fake');
131
+ lastSocket.emit('open');
132
+ await p;
133
+ onBrowserClose = () => process.kill(pid, 'SIGTERM');
134
+ return client;
135
+ }
136
+ /** A client that never connected: Browser.close fails at once, so
137
+ * closeBrowser takes its kill fallback. */
138
+ async function deadClient() {
139
+ const { CdpClient } = await import('../browser/cdp.js');
140
+ return new CdpClient();
141
+ }
142
+ async function launch(config) {
143
+ const browser = await import('../browser/browser.js');
144
+ const port = await browser.launchBrowser({ executablePath: exe, ...config });
145
+ const pid = browser.getLaunchedPid(port);
146
+ launchedPids.push(pid);
147
+ return { browser, port, pid, dir: browser.getLaunchedUserDataDir(port) };
148
+ }
149
+ describe.skipIf(process.platform === 'win32')('#395 profile dir cleanup on close', () => {
150
+ it('launch then graceful close removes the default profile dir it created', async () => {
151
+ const { browser, port, pid, dir } = await launch({ port: await freePort() });
152
+ expect(dir.startsWith(root)).toBe(true);
153
+ expect(existsSync(join(dir, 'Default', 'Preferences'))).toBe(true);
154
+ expect(browser.ownsLaunchedUserDataDir(port)).toBe(true);
155
+ await browser.closeBrowser(await gracefulClient(pid), port);
156
+ expect(existsSync(dir)).toBe(false);
157
+ }, 20_000);
158
+ it('removes a CLI session profile (port 0, ownsUserDataDir) on close', async () => {
159
+ const browser = await import('../browser/browser.js');
160
+ const { sessionProfileDirPath } = await import('../browser/profile-dir.js');
161
+ const own = sessionProfileDirPath('abcdef12');
162
+ expect(own.startsWith(root)).toBe(true);
163
+ const { port, pid, dir } = await launch({ port: 0, userDataDir: own, ownsUserDataDir: true });
164
+ expect(dir).toBe(own);
165
+ await browser.closeBrowser(await gracefulClient(pid), port);
166
+ expect(existsSync(own)).toBe(false);
167
+ }, 20_000);
168
+ it('never deletes a caller-supplied userDataDir, even one named like ours', async () => {
169
+ const mine = join(root, 'my-profile');
170
+ const lookalike = join(root, `monomind-browse-${process.pid}-0badc0de`);
171
+ for (const userDataDir of [mine, lookalike]) {
172
+ mkdirSync(userDataDir);
173
+ const { browser, port, pid } = await launch({ port: 0, userDataDir });
174
+ expect(browser.ownsLaunchedUserDataDir(port)).toBe(false);
175
+ await browser.closeBrowser(await gracefulClient(pid), port);
176
+ expect(existsSync(join(userDataDir, 'Default', 'Preferences')), userDataDir).toBe(true);
177
+ }
178
+ }, 30_000);
179
+ it('the kill fallback removes the created dir once the process is gone', async () => {
180
+ const { browser, port, pid, dir } = await launch({ port: await freePort() });
181
+ expect(existsSync(dir)).toBe(true);
182
+ await browser.closeBrowser(await deadClient(), port);
183
+ expect(() => process.kill(pid, 0)).toThrow();
184
+ expect(existsSync(dir)).toBe(false);
185
+ }, 20_000);
186
+ it('a failed launch removes the profile dir it created', async () => {
187
+ const dying = join(fixtures, 'dying-chrome.cjs');
188
+ writeFileSync(dying, `#!/usr/bin/env node
189
+ const dir = process.argv.find((a) => a.startsWith('--user-data-dir=')).slice(16);
190
+ require('node:fs').mkdirSync(dir, { recursive: true });
191
+ process.exit(1);
192
+ `);
193
+ chmodSync(dying, 0o755);
194
+ const browser = await import('../browser/browser.js');
195
+ const port = await freePort();
196
+ await expect(browser.launchBrowser({ port, strictPort: true, executablePath: dying })).rejects.toThrow(/exited before the CDP endpoint opened/);
197
+ expect(readdirSync(root)).toEqual([]);
198
+ }, 20_000);
199
+ });
200
+ describe.skipIf(process.platform === 'win32')('#395 fresh-process close via the persisted session', () => {
201
+ /** A live stand-in for a Chrome some earlier CLI process launched, its
202
+ * profile dir, and the session record that process left behind. */
203
+ async function persistedSession(ownsUserDataDir) {
204
+ const dir = join(root, `monomind-browse-${process.pid}-5e55107${ownsUserDataDir ? 'a' : 'b'}`);
205
+ await mkdir(join(dir, 'Default'), { recursive: true });
206
+ await writeFile(join(dir, 'Default', 'Preferences'), '{}');
207
+ const child = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)'], {
208
+ stdio: 'ignore',
209
+ });
210
+ children.push(child);
211
+ await new Promise((resolve) => child.once('spawn', resolve));
212
+ const port = await freePort();
213
+ const sessions = join(cwd, '.monomind', 'monobrowse', 'sessions');
214
+ await mkdir(sessions, { recursive: true });
215
+ await writeFile(join(sessions, `${port}.json`), JSON.stringify({
216
+ port,
217
+ launched: true,
218
+ pid: child.pid,
219
+ userDataDir: dir,
220
+ ownsUserDataDir,
221
+ savedAt: Date.now(),
222
+ }));
223
+ return { dir, pid: child.pid, port };
224
+ }
225
+ it('removes the dir when the record says monobrowse owns it', async () => {
226
+ const { dir, port } = await persistedSession(true);
227
+ const browser = await import('../browser/browser.js');
228
+ const { loadSessionRecord } = await import('../browser/ref-cache.js');
229
+ expect((await loadSessionRecord(port))?.ownsUserDataDir).toBe(true);
230
+ await browser.closeBrowser(await deadClient(), port);
231
+ expect(existsSync(dir)).toBe(false);
232
+ }, 20_000);
233
+ it('keeps the dir (still killing the browser) when the record has no ownership flag', async () => {
234
+ const { dir, pid, port } = await persistedSession(undefined);
235
+ const browser = await import('../browser/browser.js');
236
+ await browser.closeBrowser(await deadClient(), port);
237
+ for (let i = 0; i < 40; i++) {
238
+ try {
239
+ process.kill(pid, 0);
240
+ }
241
+ catch {
242
+ break;
243
+ }
244
+ await new Promise((resolve) => setTimeout(resolve, 50));
245
+ }
246
+ expect(() => process.kill(pid, 0)).toThrow();
247
+ expect(existsSync(join(dir, 'Default', 'Preferences'))).toBe(true);
248
+ }, 20_000);
249
+ });
250
+ //# sourceMappingURL=profile-cleanup-close.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-cleanup-close.test.js","sourceRoot":"","sources":["../../../src/__tests__/profile-cleanup-close.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * #395: the crash sweep and ownership checks for the temp Chrome profiles
3
+ * monobrowse creates (profile-dir.ts).
4
+ *
5
+ * Every test sweeps a root of its own made with mkdtemp — never the real
6
+ * /tmp, where other sessions' live Chrome profiles live. (The whole package
7
+ * run also gets a throwaway TMPDIR, see setup/isolated-tmpdir.global.ts.)
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=profile-dir.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-dir.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/profile-dir.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * #395: the crash sweep and ownership checks for the temp Chrome profiles
3
+ * monobrowse creates (profile-dir.ts).
4
+ *
5
+ * Every test sweeps a root of its own made with mkdtemp — never the real
6
+ * /tmp, where other sessions' live Chrome profiles live. (The whole package
7
+ * run also gets a throwaway TMPDIR, see setup/isolated-tmpdir.global.ts.)
8
+ */
9
+ import { spawn } from 'node:child_process';
10
+ import { existsSync } from 'node:fs';
11
+ import { lutimes, mkdir, mkdtemp, rm, symlink, utimes, writeFile } from 'node:fs/promises';
12
+ import { tmpdir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
15
+ import { isOwnedProfileDir, isProfileDirInUse, profileDirOwnerPid, removeOwnedProfileDir, sweepStaleProfileDirs, } from '../browser/profile-dir.js';
16
+ let root;
17
+ let outside;
18
+ const children = [];
19
+ const HOUR_AGO = new Date(Date.now() - 60 * 60 * 1000);
20
+ beforeEach(async () => {
21
+ root = await mkdtemp(join(tmpdir(), 'monobrowse-sweep-root-'));
22
+ outside = await mkdtemp(join(tmpdir(), 'monobrowse-sweep-outside-'));
23
+ });
24
+ afterEach(async () => {
25
+ for (const child of children.splice(0))
26
+ child.kill('SIGKILL');
27
+ await rm(root, { recursive: true, force: true });
28
+ await rm(outside, { recursive: true, force: true });
29
+ });
30
+ /** A pid that belonged to a process which has since exited. */
31
+ async function deadPid() {
32
+ const child = spawn(process.execPath, ['-e', ''], { stdio: 'ignore' });
33
+ await new Promise((resolve) => child.once('exit', resolve));
34
+ return child.pid;
35
+ }
36
+ /** A live process whose command line passes `--user-data-dir=<dir>`, the way
37
+ * Chrome's own does. */
38
+ async function holder(dir) {
39
+ const child = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)', '--', `--user-data-dir=${dir}`], { stdio: 'ignore' });
40
+ children.push(child);
41
+ await new Promise((resolve) => child.once('spawn', resolve));
42
+ return child;
43
+ }
44
+ /** A profile-looking directory with some content, backdated past the grace. */
45
+ async function profile(name, opts = {}) {
46
+ const dir = join(root, name);
47
+ await mkdir(join(dir, 'Default'), { recursive: true });
48
+ await writeFile(join(dir, 'Default', 'Preferences'), '{}');
49
+ if (!opts.young)
50
+ await utimes(dir, HOUR_AGO, HOUR_AGO);
51
+ return dir;
52
+ }
53
+ describe('#395 profileDirOwnerPid', () => {
54
+ it('reads the pid from exactly our two name patterns', () => {
55
+ expect(profileDirOwnerPid('monomind-browser-9222-1234-0a1b2c3d')).toBe(1234);
56
+ expect(profileDirOwnerPid('monomind-browse-4321-0a1b2c3d')).toBe(4321);
57
+ for (const name of [
58
+ 'monomind-browse-4321-0A1B2C3D',
59
+ 'monomind-browse-4321-0a1b2c3d0',
60
+ 'monomind-browse-x-0a1b2c3d',
61
+ 'monomind-browser-4321-0a1b2c3d',
62
+ 'xmonomind-browse-4321-0a1b2c3d',
63
+ 'org.chromium.Chromium.abc123',
64
+ ]) {
65
+ expect(profileDirOwnerPid(name), name).toBeNull();
66
+ }
67
+ });
68
+ });
69
+ describe('#395 sweepStaleProfileDirs', () => {
70
+ it('deletes stale dirs whose owner is dead and nothing uses', async () => {
71
+ const pid = await deadPid();
72
+ const a = await profile(`monomind-browser-9222-${pid}-aaaaaaaa`);
73
+ const b = await profile(`monomind-browse-${pid}-bbbbbbbb`);
74
+ const removed = await sweepStaleProfileDirs({ root });
75
+ expect(removed.sort()).toEqual([a, b].sort());
76
+ expect(existsSync(a)).toBe(false);
77
+ expect(existsSync(b)).toBe(false);
78
+ });
79
+ it('keeps young dirs, dirs whose pid is alive, non-matching names, symlinks and files', async () => {
80
+ const pid = await deadPid();
81
+ const young = await profile(`monomind-browse-${pid}-cccccccc`, { young: true });
82
+ const alive = await profile(`monomind-browse-${process.pid}-dddddddd`);
83
+ const foreign = [
84
+ await profile('org.chromium.Chromium.abc123'),
85
+ await profile(`monomind-browse-${pid}-ABCDEF12`),
86
+ await profile(`monomind-browse-${pid}-abcdef12-extra`),
87
+ await profile(`other-monomind-browse-${pid}-abcdef12`),
88
+ ];
89
+ // A symlink with our name, pointing out of the root at a real profile.
90
+ const target = join(outside, 'victim');
91
+ await mkdir(target);
92
+ await writeFile(join(target, 'keep.txt'), 'keep');
93
+ const link = join(root, `monomind-browse-${pid}-11111111`);
94
+ await symlink(target, link);
95
+ await lutimes(link, HOUR_AGO, HOUR_AGO);
96
+ // A plain file with our name.
97
+ const file = join(root, `monomind-browse-${pid}-22222222`);
98
+ await writeFile(file, 'not a dir');
99
+ await utimes(file, HOUR_AGO, HOUR_AGO);
100
+ expect(await sweepStaleProfileDirs({ root })).toEqual([]);
101
+ for (const kept of [young, alive, ...foreign, link, file])
102
+ expect(existsSync(kept)).toBe(true);
103
+ expect(existsSync(join(target, 'keep.txt'))).toBe(true);
104
+ });
105
+ it.skipIf(process.platform !== 'linux')('keeps a dir a live process uses as --user-data-dir, though its named pid is dead', async () => {
106
+ // A CLI `open` exits right after launching, so the pid in the name is
107
+ // dead while its Chrome runs on: only the live user of the dir says so.
108
+ const pid = await deadPid();
109
+ const inUse = await profile(`monomind-browse-${pid}-eeeeeeee`);
110
+ await holder(inUse);
111
+ expect(await sweepStaleProfileDirs({ root })).toEqual([]);
112
+ expect(existsSync(inUse)).toBe(true);
113
+ });
114
+ it('without /proc, keeps a dir whose SingletonLock names a live pid', async () => {
115
+ const pid = await deadPid();
116
+ const locked = await profile(`monomind-browse-${pid}-ffffffff`);
117
+ await symlink(`somehost-${process.pid}`, join(locked, 'SingletonLock'));
118
+ await utimes(locked, HOUR_AGO, HOUR_AGO);
119
+ const staleLock = await profile(`monomind-browse-${pid}-99999999`);
120
+ await symlink(`somehost-${pid}`, join(staleLock, 'SingletonLock'));
121
+ await utimes(staleLock, HOUR_AGO, HOUR_AGO);
122
+ expect(await sweepStaleProfileDirs({ root, procDir: null })).toEqual([staleLock]);
123
+ expect(existsSync(locked)).toBe(true);
124
+ });
125
+ it('never throws, and sweeps nothing, when the root is missing', async () => {
126
+ await expect(sweepStaleProfileDirs({ root: join(root, 'missing') })).resolves.toEqual([]);
127
+ });
128
+ });
129
+ describe('#395 isOwnedProfileDir / removeOwnedProfileDir', () => {
130
+ it('refuses a caller-supplied dir, a dir outside the root, and a symlink', async () => {
131
+ const caller = join(root, 'my-profile');
132
+ await mkdir(caller);
133
+ const nested = join(root, 'sub', `monomind-browse-${process.pid}-aaaaaaaa`);
134
+ await mkdir(nested, { recursive: true });
135
+ const target = join(outside, 'victim');
136
+ await mkdir(target);
137
+ const link = join(root, `monomind-browse-${process.pid}-bbbbbbbb`);
138
+ await symlink(target, link);
139
+ for (const dir of [caller, nested, link]) {
140
+ expect(await isOwnedProfileDir(dir, root), dir).toBe(false);
141
+ expect(await removeOwnedProfileDir(dir, { root }), dir).toBe(false);
142
+ expect(existsSync(dir), dir).toBe(true);
143
+ }
144
+ expect(existsSync(target)).toBe(true);
145
+ });
146
+ it('removes an owned dir once its browser pid has exited', async () => {
147
+ const dir = await profile(`monomind-browse-${process.pid}-cccccccc`, { young: true });
148
+ const pid = await deadPid();
149
+ expect(await removeOwnedProfileDir(dir, { root, pid })).toBe(true);
150
+ expect(existsSync(dir)).toBe(false);
151
+ });
152
+ it.skipIf(process.platform !== 'linux')('keeps an owned dir while a live process still uses it', async () => {
153
+ const dir = await profile(`monomind-browse-${process.pid}-dddddddd`, { young: true });
154
+ const child = await holder(dir);
155
+ expect(await isProfileDirInUse(dir)).toBe(true);
156
+ expect(await removeOwnedProfileDir(dir, { root, pid: child.pid })).toBe(false);
157
+ expect(existsSync(dir)).toBe(true);
158
+ }, 15_000);
159
+ });
160
+ //# sourceMappingURL=profile-dir.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-dir.test.js","sourceRoot":"","sources":["../../../src/__tests__/profile-dir.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function setup(): () => void;
2
+ //# sourceMappingURL=isolated-tmpdir.global.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isolated-tmpdir.global.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/setup/isolated-tmpdir.global.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,OAAO,UAAU,KAAK,IAAI,MAAM,IAAI,CAY1C"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Vitest globalSetup: run every monobrowse test worker against a throwaway
3
+ * TMPDIR (#395).
4
+ *
5
+ * launchBrowser() sweeps stale `monomind-browser-*` / `monomind-browse-*`
6
+ * profile dirs out of os.tmpdir() on every launch. The sweep only removes
7
+ * dead, idle, unused dirs, but a test run must never touch the real /tmp at
8
+ * all: other sessions' live Chrome profiles live there. Set in the main
9
+ * process before any worker starts, so workers and the CLI processes tests
10
+ * spawn inherit it.
11
+ */
12
+ import { mkdtempSync, rmSync } from 'node:fs';
13
+ import { tmpdir } from 'node:os';
14
+ import { join } from 'node:path';
15
+ export default function setup() {
16
+ const saved = process.env.TMPDIR;
17
+ // Short on purpose: real-Chrome tests nest their own dirs under it, and
18
+ // Chrome aborts at startup (SIGABRT) once the unix socket path it makes in
19
+ // TMPDIR (…/org.chromium.Chromium.XXXXXX/SingletonSocket) passes ~107 bytes.
20
+ const dir = mkdtempSync(join(tmpdir(), 'mb-'));
21
+ process.env.TMPDIR = dir;
22
+ return () => {
23
+ if (saved === undefined)
24
+ delete process.env.TMPDIR;
25
+ else
26
+ process.env.TMPDIR = saved;
27
+ rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
28
+ };
29
+ }
30
+ //# sourceMappingURL=isolated-tmpdir.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isolated-tmpdir.global.js","sourceRoot":"","sources":["../../../../src/__tests__/setup/isolated-tmpdir.global.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,OAAO,UAAU,KAAK;IAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;IACjC,wEAAwE;IACxE,2EAA2E;IAC3E,6EAA6E;IAC7E,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;IACzB,OAAO,GAAG,EAAE;QACV,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;;YAC9C,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC;QAChC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"browser-launch.d.ts","sourceRoot":"","sources":["../../../src/browser/browser-launch.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAehD,wBAAsB,aAAa,CAAC,MAAM,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyF/E"}
1
+ {"version":3,"file":"browser-launch.d.ts","sourceRoot":"","sources":["../../../src/browser/browser-launch.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAehD,wBAAsB,aAAa,CAAC,MAAM,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6F/E"}