@opice/browser 0.1.1 → 0.2.1
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/dist/builtins.d.ts +10 -0
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +42 -1
- package/dist/builtins.js.map +1 -1
- package/dist/cli.js +32 -60
- package/dist/cli.js.map +1 -1
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +171 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +20 -16
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +96 -106
- package/dist/session.js.map +1 -1
- package/package.json +2 -2
package/dist/builtins.d.ts
CHANGED
|
@@ -6,4 +6,14 @@ export declare const builtins: Command[];
|
|
|
6
6
|
* browser-tools.ts are flag-only.
|
|
7
7
|
*/
|
|
8
8
|
export declare const positionalHints: Record<string, string[]>;
|
|
9
|
+
/** Build the full registry: built-ins + user verbs (user verbs override). */
|
|
10
|
+
export declare function buildRegistry(): Promise<Map<string, Command>>;
|
|
11
|
+
/** Field names for positional mapping: explicit hint, else object-schema keys. */
|
|
12
|
+
export declare function positionalNames(name: string, cmd: Command): string[];
|
|
13
|
+
/** Merge parsed flags + positionals into the args object a command expects. */
|
|
14
|
+
export declare function buildArgs(name: string, cmd: Command, flags: Record<string, unknown>, positionals: string[]): Record<string, unknown>;
|
|
15
|
+
/** One-line `<param> <param>` summary for `commands` listing. */
|
|
16
|
+
export declare function paramSummary(cmd: Command): string;
|
|
17
|
+
/** Is `name` a built-in (vs a user verb)? */
|
|
18
|
+
export declare function isBuiltin(name: string): boolean;
|
|
9
19
|
//# sourceMappingURL=builtins.d.ts.map
|
package/dist/builtins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,OAAO,EAAmB,MAAM,gBAAgB,CAAA;AA0C5F,eAAO,MAAM,QAAQ,EAAE,OAAO,EA8E7B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAcpD,CAAA;AAED,6EAA6E;AAC7E,wBAAsB,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMnE;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAIpE;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQpI;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAMjD;AAED,6CAA6C;AAC7C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE/C"}
|
package/dist/builtins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { command, z } from '@opice/harness';
|
|
1
|
+
import { command, loadUserCommands, z } from '@opice/harness';
|
|
2
2
|
/**
|
|
3
3
|
* Built-in browser verbs for the authoring CLI, defined with the same
|
|
4
4
|
* `command()` primitive a repo's `browser-tools.ts` uses. The agent drives the
|
|
@@ -114,4 +114,45 @@ export const positionalHints = {
|
|
|
114
114
|
'aria-snapshot': ['selector'],
|
|
115
115
|
eval: ['js'],
|
|
116
116
|
};
|
|
117
|
+
/** Build the full registry: built-ins + user verbs (user verbs override). */
|
|
118
|
+
export async function buildRegistry() {
|
|
119
|
+
const registry = new Map();
|
|
120
|
+
for (const cmd of builtins)
|
|
121
|
+
registry.set(cmd.name, cmd);
|
|
122
|
+
const user = await loadUserCommands();
|
|
123
|
+
for (const [name, cmd] of user)
|
|
124
|
+
registry.set(name, cmd);
|
|
125
|
+
return registry;
|
|
126
|
+
}
|
|
127
|
+
/** Field names for positional mapping: explicit hint, else object-schema keys. */
|
|
128
|
+
export function positionalNames(name, cmd) {
|
|
129
|
+
if (positionalHints[name])
|
|
130
|
+
return positionalHints[name];
|
|
131
|
+
if (cmd.params instanceof z.ZodObject)
|
|
132
|
+
return Object.keys(cmd.params.shape);
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
/** Merge parsed flags + positionals into the args object a command expects. */
|
|
136
|
+
export function buildArgs(name, cmd, flags, positionals) {
|
|
137
|
+
const names = positionalNames(name, cmd);
|
|
138
|
+
const args = { ...flags };
|
|
139
|
+
positionals.forEach((val, i) => {
|
|
140
|
+
const key = names[i];
|
|
141
|
+
if (key && !(key in args))
|
|
142
|
+
args[key] = val;
|
|
143
|
+
});
|
|
144
|
+
return args;
|
|
145
|
+
}
|
|
146
|
+
/** One-line `<param> <param>` summary for `commands` listing. */
|
|
147
|
+
export function paramSummary(cmd) {
|
|
148
|
+
if (cmd.params instanceof z.ZodObject) {
|
|
149
|
+
const keys = Object.keys(cmd.params.shape);
|
|
150
|
+
return keys.length ? keys.map((k) => `<${k}>`).join(' ') : '(no args)';
|
|
151
|
+
}
|
|
152
|
+
return '';
|
|
153
|
+
}
|
|
154
|
+
/** Is `name` a built-in (vs a user verb)? */
|
|
155
|
+
export function isBuiltin(name) {
|
|
156
|
+
return builtins.some((b) => b.name === name);
|
|
157
|
+
}
|
|
117
158
|
//# sourceMappingURL=builtins.js.map
|
package/dist/builtins.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtins.js","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,CAAC,EAAiC,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"builtins.js","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { launch, quit, sessionAlive, setSessionName, withPage } from './session.js';
|
|
4
|
+
import { buildRegistry, isBuiltin, paramSummary } from './builtins.js';
|
|
5
|
+
import { launch, quit, runVerb, sessionAlive, setSessionName } from './session.js';
|
|
7
6
|
// opice-browser must run under Node: Playwright's `connectOverCDP` websocket
|
|
8
7
|
// can't complete its handshake under Bun. However it gets launched (bunx, a
|
|
9
8
|
// bun-created bin shim, `bun run`), re-exec under Node so the verb always works.
|
|
@@ -21,6 +20,9 @@ const HELP = `opice-browser — stateful Playwright browser for opice authoring
|
|
|
21
20
|
|
|
22
21
|
Usage: opice-browser [--session NAME] <command> [positionals] [--flag value]
|
|
23
22
|
|
|
23
|
+
A launched session holds one browser connection + page for its whole life, so
|
|
24
|
+
focus and open popovers survive between commands (verbs are socket clients).
|
|
25
|
+
|
|
24
26
|
Sessions: each named session is its own browser (default: "default", or
|
|
25
27
|
$OPICE_BROWSER_SESSION). opice-batch gives each parallel author its own.
|
|
26
28
|
|
|
@@ -70,41 +72,6 @@ function parseArgs(tokens) {
|
|
|
70
72
|
}
|
|
71
73
|
return { flags, positionals };
|
|
72
74
|
}
|
|
73
|
-
/** Field names for positional mapping: explicit hint, else object-schema keys. */
|
|
74
|
-
function positionalNames(name, cmd) {
|
|
75
|
-
if (positionalHints[name])
|
|
76
|
-
return positionalHints[name];
|
|
77
|
-
if (cmd.params instanceof z.ZodObject)
|
|
78
|
-
return Object.keys(cmd.params.shape);
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
function paramSummary(cmd) {
|
|
82
|
-
if (cmd.params instanceof z.ZodObject) {
|
|
83
|
-
const keys = Object.keys(cmd.params.shape);
|
|
84
|
-
return keys.length ? keys.map((k) => `<${k}>`).join(' ') : '(no args)';
|
|
85
|
-
}
|
|
86
|
-
return '';
|
|
87
|
-
}
|
|
88
|
-
async function buildRegistry() {
|
|
89
|
-
const registry = new Map();
|
|
90
|
-
for (const cmd of builtins)
|
|
91
|
-
registry.set(cmd.name, cmd);
|
|
92
|
-
const user = await loadUserCommands();
|
|
93
|
-
for (const [name, cmd] of user)
|
|
94
|
-
registry.set(name, cmd); // user verbs override built-ins
|
|
95
|
-
return registry;
|
|
96
|
-
}
|
|
97
|
-
function printResult(result) {
|
|
98
|
-
if (result === undefined || result === null) {
|
|
99
|
-
console.log('ok');
|
|
100
|
-
}
|
|
101
|
-
else if (typeof result === 'string') {
|
|
102
|
-
console.log(result);
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
console.log(JSON.stringify(result));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
75
|
/** Consume a leading `--session NAME` / `--session=NAME` (else env / default). */
|
|
109
76
|
function takeSession(argv) {
|
|
110
77
|
const first = argv[0];
|
|
@@ -118,6 +85,17 @@ function takeSession(argv) {
|
|
|
118
85
|
}
|
|
119
86
|
return argv;
|
|
120
87
|
}
|
|
88
|
+
function printResult(result) {
|
|
89
|
+
if (result === undefined || result === null) {
|
|
90
|
+
console.log('ok');
|
|
91
|
+
}
|
|
92
|
+
else if (typeof result === 'string') {
|
|
93
|
+
console.log(result);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.log(JSON.stringify(result));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
121
99
|
async function main(rawArgv) {
|
|
122
100
|
reexecUnderNodeIfBun();
|
|
123
101
|
const [name, ...rest] = takeSession(rawArgv);
|
|
@@ -129,49 +107,43 @@ async function main(rawArgv) {
|
|
|
129
107
|
case '-h':
|
|
130
108
|
console.log(HELP);
|
|
131
109
|
return 0;
|
|
110
|
+
case '__serve': {
|
|
111
|
+
// Internal: the long-running server process spawned by `launch`.
|
|
112
|
+
const { runServer } = await import('./server.js');
|
|
113
|
+
await runServer({ headed: !!flags['headed'], url: typeof flags['url'] === 'string' ? flags['url'] : undefined });
|
|
114
|
+
// Block forever — the server's shutdown() calls process.exit on quit.
|
|
115
|
+
// Returning here would let the top-level process.exit kill the server.
|
|
116
|
+
await new Promise(() => { });
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
132
119
|
case 'launch': {
|
|
133
120
|
const session = await launch({ headed: !!flags['headed'], url: positionals[0] });
|
|
134
|
-
console.error(`[opice-browser] session up (pid ${session.
|
|
121
|
+
console.error(`[opice-browser] session up (pid ${session.serverPid}, port ${session.port})`);
|
|
135
122
|
return 0;
|
|
136
123
|
}
|
|
137
124
|
case 'status': {
|
|
138
|
-
const session = sessionAlive();
|
|
139
|
-
console.log(session ? `alive (pid ${session.
|
|
125
|
+
const session = await sessionAlive();
|
|
126
|
+
console.log(session ? `alive (pid ${session.serverPid}, port ${session.port})` : 'no session');
|
|
140
127
|
return session ? 0 : 1;
|
|
141
128
|
}
|
|
142
129
|
case 'quit':
|
|
143
130
|
case 'close': {
|
|
144
|
-
quit();
|
|
131
|
+
await quit();
|
|
145
132
|
console.error('[opice-browser] session closed');
|
|
146
133
|
return 0;
|
|
147
134
|
}
|
|
148
135
|
case 'commands': {
|
|
136
|
+
// Listed locally — no running server needed.
|
|
149
137
|
const registry = await buildRegistry();
|
|
150
138
|
for (const cmd of registry.values()) {
|
|
151
|
-
const
|
|
152
|
-
const tag = builtin ? '' : ' (user)';
|
|
139
|
+
const tag = isBuiltin(cmd.name) ? '' : ' (user)';
|
|
153
140
|
console.log(`${cmd.name} ${paramSummary(cmd)}${tag}\n ${cmd.description ?? ''}`.trimEnd());
|
|
154
141
|
}
|
|
155
142
|
return 0;
|
|
156
143
|
}
|
|
157
144
|
default: {
|
|
158
|
-
const registry = await buildRegistry();
|
|
159
|
-
const cmd = registry.get(name);
|
|
160
|
-
if (!cmd) {
|
|
161
|
-
console.error(`Unknown command: ${name}\n`);
|
|
162
|
-
console.error(HELP);
|
|
163
|
-
return 1;
|
|
164
|
-
}
|
|
165
|
-
const names = positionalNames(name, cmd);
|
|
166
|
-
const args = { ...flags };
|
|
167
|
-
positionals.forEach((val, i) => {
|
|
168
|
-
const key = names[i];
|
|
169
|
-
if (key && !(key in args))
|
|
170
|
-
args[key] = val;
|
|
171
|
-
});
|
|
172
145
|
try {
|
|
173
|
-
|
|
174
|
-
printResult(result);
|
|
146
|
+
printResult(await runVerb(name, flags, positionals));
|
|
175
147
|
return 0;
|
|
176
148
|
}
|
|
177
149
|
catch (err) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface ServeOptions {
|
|
2
|
+
headed?: boolean;
|
|
3
|
+
url?: string;
|
|
4
|
+
}
|
|
5
|
+
/** Spawn Chrome, hold a page, and serve verbs until told to quit. Never returns. */
|
|
6
|
+
export declare function runServer(opts: ServeOptions): Promise<void>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA+CA,UAAU,YAAY;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,oFAAoF;AACpF,wBAAsB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HjE"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createServer } from 'node:net';
|
|
3
|
+
import { mkdirSync, rmSync } from 'node:fs';
|
|
4
|
+
import { loadUserSetup, runCommand } from '@opice/harness';
|
|
5
|
+
import { chromium } from 'playwright';
|
|
6
|
+
import { buildArgs, buildRegistry } from './builtins.js';
|
|
7
|
+
import { profileDir, sessionFile, socketPath, writeSession } from './session.js';
|
|
8
|
+
/**
|
|
9
|
+
* The persistent authoring server. `opice-browser launch` spawns one of these
|
|
10
|
+
* (detached); it spawns Chrome, holds ONE `connectOverCDP` connection + page
|
|
11
|
+
* for its whole lifetime, and serves verbs over a unix socket. Because the
|
|
12
|
+
* connection is held — never torn down between verbs — transient page state
|
|
13
|
+
* (keyboard focus, an open Radix popover, in-flight navigation) survives from
|
|
14
|
+
* one command to the next, exactly like the in-process page in a test. Verb
|
|
15
|
+
* commands (`opice-browser click …`) are thin socket clients (see session.ts).
|
|
16
|
+
*/
|
|
17
|
+
async function freePort() {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const srv = createServer();
|
|
20
|
+
srv.once('error', reject);
|
|
21
|
+
srv.listen(0, '127.0.0.1', () => {
|
|
22
|
+
const addr = srv.address();
|
|
23
|
+
const port = typeof addr === 'object' && addr ? addr.port : 0;
|
|
24
|
+
srv.close(() => resolve(port));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async function waitForEndpoint(port, timeoutMs = 15_000) {
|
|
29
|
+
const deadline = Date.now() + timeoutMs;
|
|
30
|
+
while (Date.now() < deadline) {
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch(`http://127.0.0.1:${port}/json/version`);
|
|
33
|
+
if (res.ok) {
|
|
34
|
+
const body = (await res.json());
|
|
35
|
+
if (body.webSocketDebuggerUrl)
|
|
36
|
+
return body.webSocketDebuggerUrl;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// not up yet
|
|
41
|
+
}
|
|
42
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`Chrome did not expose a CDP endpoint on port ${port} within ${timeoutMs}ms`);
|
|
45
|
+
}
|
|
46
|
+
/** Spawn Chrome, hold a page, and serve verbs until told to quit. Never returns. */
|
|
47
|
+
export async function runServer(opts) {
|
|
48
|
+
const port = await freePort();
|
|
49
|
+
const userDataDir = profileDir();
|
|
50
|
+
mkdirSync(userDataDir, { recursive: true });
|
|
51
|
+
// Always boot Chrome on about:blank, never the requested URL: the launch URL
|
|
52
|
+
// is navigated via Playwright below (after browser-setup.ts runs), so its
|
|
53
|
+
// init scripts apply to the first real paint just like in a test.
|
|
54
|
+
const chrome = spawn(chromium.executablePath(), [
|
|
55
|
+
`--remote-debugging-port=${port}`,
|
|
56
|
+
`--user-data-dir=${userDataDir}`,
|
|
57
|
+
'--no-first-run',
|
|
58
|
+
'--no-default-browser-check',
|
|
59
|
+
// Match the test harness's default viewport. A connectOverCDP page has no
|
|
60
|
+
// Playwright viewport emulation, so without this the headless window is
|
|
61
|
+
// ~800×600 and portalled content (a popover's lower options, a long form)
|
|
62
|
+
// renders off-fold — Playwright then refuses to click "outside of the
|
|
63
|
+
// viewport". Keep authoring and tests seeing the same layout.
|
|
64
|
+
'--window-size=1280,720',
|
|
65
|
+
...(opts.headed ? [] : ['--headless=new']),
|
|
66
|
+
'about:blank',
|
|
67
|
+
], { detached: true, stdio: 'ignore' });
|
|
68
|
+
chrome.unref();
|
|
69
|
+
if (chrome.pid == null)
|
|
70
|
+
throw new Error('Failed to spawn Chrome');
|
|
71
|
+
const wsEndpoint = await waitForEndpoint(port);
|
|
72
|
+
const browser = await chromium.connectOverCDP(wsEndpoint);
|
|
73
|
+
const context = browser.contexts()[0] ?? (await browser.newContext());
|
|
74
|
+
const page = context.pages()[0] ?? (await context.newPage());
|
|
75
|
+
// Playwright-launched browsers emulate focus so a headless page reports as
|
|
76
|
+
// focused and `.focus()` sticks; a `connectOverCDP`-attached page does not,
|
|
77
|
+
// so a focus-trap popover (Radix) would blur and close as soon as a verb
|
|
78
|
+
// ends. Enable it on the held CDP session — it persists for the connection's
|
|
79
|
+
// life, so focus survives across separate verb commands.
|
|
80
|
+
try {
|
|
81
|
+
const cdp = await context.newCDPSession(page);
|
|
82
|
+
await cdp.send('Emulation.setFocusEmulationEnabled', { enabled: true });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// non-fatal: focus-trap popovers may close between verbs without it
|
|
86
|
+
}
|
|
87
|
+
// Repo-level context setup (browser-setup.ts) before the first navigation —
|
|
88
|
+
// the same hook the test harness runs, so the authored page matches the test
|
|
89
|
+
// page (e.g. both suppress dev-only chrome via an addInitScript flag).
|
|
90
|
+
const setup = await loadUserSetup();
|
|
91
|
+
if (setup)
|
|
92
|
+
await setup(context);
|
|
93
|
+
if (opts.url)
|
|
94
|
+
await page.goto(opts.url);
|
|
95
|
+
const registry = await buildRegistry();
|
|
96
|
+
const sockPath = socketPath();
|
|
97
|
+
rmSync(sockPath, { force: true });
|
|
98
|
+
let shuttingDown = false;
|
|
99
|
+
const shutdown = () => {
|
|
100
|
+
if (shuttingDown)
|
|
101
|
+
return;
|
|
102
|
+
shuttingDown = true;
|
|
103
|
+
server.close();
|
|
104
|
+
void browser.close().catch(() => { });
|
|
105
|
+
try {
|
|
106
|
+
process.kill(chrome.pid);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// already gone
|
|
110
|
+
}
|
|
111
|
+
rmSync(sockPath, { force: true });
|
|
112
|
+
rmSync(sessionFile(), { force: true });
|
|
113
|
+
process.exit(0);
|
|
114
|
+
};
|
|
115
|
+
const handle = async (req) => {
|
|
116
|
+
const control = req['control'];
|
|
117
|
+
if (control === 'ping')
|
|
118
|
+
return { ok: true };
|
|
119
|
+
if (control === 'quit')
|
|
120
|
+
return { ok: true, quit: true };
|
|
121
|
+
const name = String(req['name'] ?? '');
|
|
122
|
+
const cmd = registry.get(name);
|
|
123
|
+
if (!cmd)
|
|
124
|
+
return { ok: false, error: `Unknown command: ${name}` };
|
|
125
|
+
const flags = (req['flags'] ?? {});
|
|
126
|
+
const positionals = (req['positionals'] ?? []);
|
|
127
|
+
try {
|
|
128
|
+
const result = await runCommand(page, cmd, buildArgs(name, cmd, flags, positionals));
|
|
129
|
+
return { ok: true, result };
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
// allowHalfOpen: the client half-closes after writing its request; we must
|
|
136
|
+
// still be able to write the response back before ending our side.
|
|
137
|
+
const server = createServer({ allowHalfOpen: true }, (conn) => {
|
|
138
|
+
let buf = '';
|
|
139
|
+
conn.on('data', (d) => { buf += d; });
|
|
140
|
+
conn.on('error', () => { });
|
|
141
|
+
conn.on('end', () => {
|
|
142
|
+
void (async () => {
|
|
143
|
+
let resp;
|
|
144
|
+
try {
|
|
145
|
+
resp = await handle(JSON.parse(buf));
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
resp = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
149
|
+
}
|
|
150
|
+
const quit = resp.quit === true;
|
|
151
|
+
conn.end(JSON.stringify({ ok: resp.ok, result: resp.result, error: resp.error }));
|
|
152
|
+
if (quit)
|
|
153
|
+
conn.on('close', shutdown);
|
|
154
|
+
})();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
// Die with the page: if Chrome or the connection drops, don't linger.
|
|
158
|
+
browser.on('disconnected', shutdown);
|
|
159
|
+
process.on('SIGTERM', shutdown);
|
|
160
|
+
process.on('SIGINT', shutdown);
|
|
161
|
+
await new Promise((resolve, reject) => {
|
|
162
|
+
server.once('error', reject);
|
|
163
|
+
server.listen(sockPath, () => {
|
|
164
|
+
const session = { serverPid: process.pid, chromePid: chrome.pid, socketPath: sockPath, port };
|
|
165
|
+
writeSession(session);
|
|
166
|
+
resolve();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
// Keep the event loop alive indefinitely; shutdown() exits the process.
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAe,MAAM,UAAU,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAgB,MAAM,gBAAgB,CAAA;AACxE,OAAO,EAAE,QAAQ,EAA2B,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,UAAU,EAAgB,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE9F;;;;;;;;GAQG;AAEH,KAAK,UAAU,QAAQ;IACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAA;QAC1B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACzB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;YAC1B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;YAC7D,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QAC/B,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,SAAS,GAAG,MAAM;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;IACvC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,eAAe,CAAC,CAAA;YAChE,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsC,CAAA;gBACpE,IAAI,IAAI,CAAC,oBAAoB;oBAAE,OAAO,IAAI,CAAC,oBAAoB,CAAA;YAChE,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,aAAa;QACd,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IAC7C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,IAAI,WAAW,SAAS,IAAI,CAAC,CAAA;AAC9F,CAAC;AAOD,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAkB;IACjD,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAA;IAC7B,MAAM,WAAW,GAAG,UAAU,EAAE,CAAA;IAChC,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,6EAA6E;IAC7E,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE;QAC/C,2BAA2B,IAAI,EAAE;QACjC,mBAAmB,WAAW,EAAE;QAChC,gBAAgB;QAChB,4BAA4B;QAC5B,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,sEAAsE;QACtE,8DAA8D;QAC9D,wBAAwB;QACxB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;QAC1C,aAAa;KACb,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IACvC,MAAM,CAAC,KAAK,EAAE,CAAA;IACd,IAAI,MAAM,CAAC,GAAG,IAAI,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;IAEjE,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAA;IAC9C,MAAM,OAAO,GAAY,MAAM,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;IAClE,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;IACrE,MAAM,IAAI,GAAS,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAElE,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,6EAA6E;IAC7E,yDAAyD;IACzD,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;QAC7C,MAAM,GAAG,CAAC,IAAI,CAAC,oCAAoC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACxE,CAAC;IAAC,MAAM,CAAC;QACR,oEAAoE;IACrE,CAAC;IAED,4EAA4E;IAC5E,6EAA6E;IAC7E,uEAAuE;IACvE,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAA;IACnC,IAAI,KAAK;QAAE,MAAM,KAAK,CAAC,OAAO,CAAC,CAAA;IAC/B,IAAI,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAEvC,MAAM,QAAQ,GAAyB,MAAM,aAAa,EAAE,CAAA;IAE5D,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAA;IAC7B,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAEjC,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC3B,IAAI,YAAY;YAAE,OAAM;QACxB,YAAY,GAAG,IAAI,CAAA;QACnB,MAAM,CAAC,KAAK,EAAE,CAAA;QACd,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACpC,IAAI,CAAC;YACJ,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,CAAA;QAC1B,CAAC;QAAC,MAAM,CAAC;YACR,eAAe;QAChB,CAAC;QACD,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACjC,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAChB,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,KAAK,EAAE,GAA4B,EAA8E,EAAE;QACjI,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;QAC9B,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;QAC3C,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;QACvD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;QACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,IAAI,EAAE,EAAE,CAAA;QACjE,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAA4B,CAAA;QAC7D,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAa,CAAA;QAC1D,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAA;YACpF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;QAC9E,CAAC;IACF,CAAC,CAAA;IAED,2EAA2E;IAC3E,mEAAmE;IACnE,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,CAAC,IAAY,EAAE,EAAE;QACrE,IAAI,GAAG,GAAG,EAAE,CAAA;QACZ,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;QACpC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC1B,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACnB,KAAK,CAAC,KAAK,IAAI,EAAE;gBAChB,IAAI,IAAwC,CAAA;gBAC5C,IAAI,CAAC;oBACJ,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC,CAAA;gBAChE,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;gBAC9E,CAAC;gBACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAA;gBAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;gBACjF,IAAI,IAAI;oBAAE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;YACrC,CAAC,CAAC,EAAE,CAAA;QACL,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,sEAAsE;IACtE,OAAO,CAAC,EAAE,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAE9B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5B,MAAM,OAAO,GAAY,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,GAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;YACvG,YAAY,CAAC,OAAO,CAAC,CAAA;YACrB,OAAO,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IACF,wEAAwE;AACzE,CAAC"}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
import { type Page } from 'playwright';
|
|
2
1
|
export declare function setSessionName(name: string): void;
|
|
2
|
+
export declare function sessionFile(): string;
|
|
3
|
+
export declare function socketPath(): string;
|
|
4
|
+
export declare function profileDir(): string;
|
|
3
5
|
export interface Session {
|
|
4
|
-
|
|
6
|
+
serverPid: number;
|
|
7
|
+
chromePid: number;
|
|
8
|
+
socketPath: string;
|
|
5
9
|
port: number;
|
|
6
|
-
wsEndpoint: string;
|
|
7
|
-
userDataDir: string;
|
|
8
10
|
}
|
|
9
|
-
export declare function
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
export declare function writeSession(session: Session): void;
|
|
12
|
+
export interface RpcRequest {
|
|
13
|
+
control?: 'ping' | 'quit';
|
|
14
|
+
name?: string;
|
|
15
|
+
flags?: Record<string, unknown>;
|
|
16
|
+
positionals?: string[];
|
|
17
|
+
}
|
|
18
|
+
/** Is a server listening on this session's socket? */
|
|
19
|
+
export declare function sessionAlive(): Promise<Session | null>;
|
|
12
20
|
export interface LaunchOptions {
|
|
13
21
|
headed?: boolean;
|
|
14
22
|
url?: string;
|
|
15
23
|
}
|
|
16
|
-
/**
|
|
24
|
+
/** Start the persistent server (idempotent) and wait until it's serving. */
|
|
17
25
|
export declare function launch(opts?: LaunchOptions): Promise<Session>;
|
|
18
|
-
/**
|
|
19
|
-
export declare function
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
* Disconnecting (`browser.close()` on a CDP connection) does NOT terminate the
|
|
23
|
-
* browser process — the page state persists for the next verb.
|
|
24
|
-
*/
|
|
25
|
-
export declare function withPage<T>(fn: (page: Page) => Promise<T>): Promise<T>;
|
|
26
|
+
/** Run a verb against the held page (RPC to the server). Returns its result. */
|
|
27
|
+
export declare function runVerb(name: string, flags: Record<string, unknown>, positionals: string[]): Promise<unknown>;
|
|
28
|
+
/** Stop the server (and its browser). Falls back to killing pids if unreachable. */
|
|
29
|
+
export declare function quit(): Promise<void>;
|
|
26
30
|
//# sourceMappingURL=session.d.ts.map
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAuBA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,MAAM,WAAW,OAAO;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;CACZ;AAYD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAGnD;AAED,MAAM,WAAW,UAAU;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB;AA+BD,sDAAsD;AACtD,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQ5D;AAED,MAAM,WAAW,aAAa;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,4EAA4E;AAC5E,wBAAsB,MAAM,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAyBvE;AAED,gFAAgF;AAChF,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAInH;AAED,oFAAoF;AACpF,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB1C"}
|
package/dist/session.js
CHANGED
|
@@ -1,148 +1,138 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import {
|
|
2
|
+
import { connect } from 'node:net';
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import { chromium } from 'playwright';
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
7
|
+
* Session bookkeeping + the socket client for the persistent authoring server.
|
|
9
8
|
*
|
|
10
|
-
* `launch` spawns a
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
9
|
+
* `opice-browser launch` spawns a long-running server (see server.ts) that
|
|
10
|
+
* holds one browser connection + page; verb commands here are thin clients that
|
|
11
|
+
* RPC a single newline-framed JSON message over the session's unix socket.
|
|
12
|
+
* Holding the connection server-side is what lets transient page state (focus,
|
|
13
|
+
* an open popover) survive between separate verb invocations.
|
|
14
|
+
*
|
|
15
|
+
* Multiple named sessions run side by side (own server, own socket) — set via
|
|
16
|
+
* `--session NAME` or `OPICE_BROWSER_SESSION`; defaults to `default`.
|
|
17
17
|
*/
|
|
18
18
|
const SESSION_DIR = path.join(tmpdir(), 'opice-browser');
|
|
19
|
-
/**
|
|
20
|
-
* Active session name. Multiple named sessions can run side by side, each its
|
|
21
|
-
* own browser — `opice-batch` gives every parallel author its own so they
|
|
22
|
-
* don't share a page. Set via `--session NAME` or `OPICE_BROWSER_SESSION`;
|
|
23
|
-
* defaults to `default`.
|
|
24
|
-
*/
|
|
25
19
|
let sessionName = process.env['OPICE_BROWSER_SESSION'] ?? 'default';
|
|
26
20
|
export function setSessionName(name) {
|
|
27
21
|
sessionName = name;
|
|
28
22
|
}
|
|
29
|
-
function sessionFile() {
|
|
23
|
+
export function sessionFile() {
|
|
30
24
|
return path.join(SESSION_DIR, `${sessionName}.json`);
|
|
31
25
|
}
|
|
32
|
-
function
|
|
26
|
+
export function socketPath() {
|
|
27
|
+
return path.join(SESSION_DIR, `${sessionName}.sock`);
|
|
28
|
+
}
|
|
29
|
+
export function profileDir() {
|
|
33
30
|
return path.join(SESSION_DIR, `profile-${sessionName}`);
|
|
34
31
|
}
|
|
35
|
-
|
|
32
|
+
function readSession() {
|
|
36
33
|
const file = sessionFile();
|
|
37
|
-
if (!existsSync(file))
|
|
38
|
-
throw new Error(`No browser session "${sessionName}". Run \`opice-browser launch\` first.`);
|
|
39
|
-
}
|
|
40
|
-
return JSON.parse(readFileSync(file, 'utf-8'));
|
|
41
|
-
}
|
|
42
|
-
function writeSession(session) {
|
|
43
|
-
mkdirSync(SESSION_DIR, { recursive: true });
|
|
44
|
-
writeFileSync(sessionFile(), JSON.stringify(session), 'utf-8');
|
|
45
|
-
}
|
|
46
|
-
function clearSession() {
|
|
47
|
-
rmSync(sessionFile(), { force: true });
|
|
48
|
-
}
|
|
49
|
-
/** Is there a live session whose browser process is still running? */
|
|
50
|
-
export function sessionAlive() {
|
|
51
|
-
if (!existsSync(sessionFile()))
|
|
34
|
+
if (!existsSync(file))
|
|
52
35
|
return null;
|
|
53
|
-
const session = readSession();
|
|
54
36
|
try {
|
|
55
|
-
|
|
56
|
-
return session;
|
|
37
|
+
return JSON.parse(readFileSync(file, 'utf-8'));
|
|
57
38
|
}
|
|
58
39
|
catch {
|
|
59
|
-
clearSession();
|
|
60
40
|
return null;
|
|
61
41
|
}
|
|
62
42
|
}
|
|
63
|
-
|
|
43
|
+
export function writeSession(session) {
|
|
44
|
+
mkdirSync(SESSION_DIR, { recursive: true });
|
|
45
|
+
writeFileSync(sessionFile(), JSON.stringify(session), 'utf-8');
|
|
46
|
+
}
|
|
47
|
+
/** One request → one response over the session socket (server stays up). */
|
|
48
|
+
function rpc(request, { timeoutMs = 35_000 } = {}) {
|
|
64
49
|
return new Promise((resolve, reject) => {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
50
|
+
const sock = connect(socketPath());
|
|
51
|
+
let buf = '';
|
|
52
|
+
const timer = setTimeout(() => {
|
|
53
|
+
sock.destroy();
|
|
54
|
+
reject(new Error('opice-browser: request timed out'));
|
|
55
|
+
}, timeoutMs);
|
|
56
|
+
sock.on('connect', () => sock.end(JSON.stringify(request)));
|
|
57
|
+
sock.on('data', (d) => { buf += d; });
|
|
58
|
+
sock.on('error', (err) => { clearTimeout(timer); reject(err); });
|
|
59
|
+
sock.on('end', () => {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
try {
|
|
62
|
+
resolve(JSON.parse(buf));
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
66
|
+
}
|
|
71
67
|
});
|
|
72
68
|
});
|
|
73
69
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// not up yet
|
|
87
|
-
}
|
|
88
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
70
|
+
/** Is a server listening on this session's socket? */
|
|
71
|
+
export async function sessionAlive() {
|
|
72
|
+
if (!existsSync(socketPath()))
|
|
73
|
+
return null;
|
|
74
|
+
try {
|
|
75
|
+
const res = await rpc({ control: 'ping' }, { timeoutMs: 2_000 });
|
|
76
|
+
return res.ok ? readSession() : null;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
89
80
|
}
|
|
90
|
-
throw new Error(`Chrome did not expose a CDP endpoint on port ${port} within ${timeoutMs}ms`);
|
|
91
81
|
}
|
|
92
|
-
/**
|
|
82
|
+
/** Start the persistent server (idempotent) and wait until it's serving. */
|
|
93
83
|
export async function launch(opts = {}) {
|
|
94
|
-
const existing = sessionAlive();
|
|
84
|
+
const existing = await sessionAlive();
|
|
95
85
|
if (existing)
|
|
96
86
|
return existing;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
87
|
+
mkdirSync(SESSION_DIR, { recursive: true });
|
|
88
|
+
rmSync(socketPath(), { force: true });
|
|
89
|
+
rmSync(sessionFile(), { force: true });
|
|
100
90
|
const args = [
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
'
|
|
104
|
-
'--
|
|
105
|
-
...(opts.
|
|
106
|
-
opts.url ?? 'about:blank',
|
|
91
|
+
process.argv[1],
|
|
92
|
+
'--session', sessionName,
|
|
93
|
+
'__serve',
|
|
94
|
+
...(opts.headed ? ['--headed'] : []),
|
|
95
|
+
...(opts.url ? ['--url', opts.url] : []),
|
|
107
96
|
];
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
/** Kill the persistent browser and clear the session. */
|
|
118
|
-
export function quit() {
|
|
119
|
-
const session = sessionAlive();
|
|
120
|
-
if (session) {
|
|
121
|
-
try {
|
|
122
|
-
process.kill(session.pid);
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
// already gone
|
|
126
|
-
}
|
|
97
|
+
const server = spawn(process.execPath, args, { detached: true, stdio: 'ignore' });
|
|
98
|
+
server.unref();
|
|
99
|
+
const deadline = Date.now() + 30_000;
|
|
100
|
+
while (Date.now() < deadline) {
|
|
101
|
+
const session = await sessionAlive();
|
|
102
|
+
if (session)
|
|
103
|
+
return session;
|
|
104
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
127
105
|
}
|
|
128
|
-
|
|
106
|
+
throw new Error('opice-browser: server did not come up within 30s');
|
|
129
107
|
}
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
108
|
+
/** Run a verb against the held page (RPC to the server). Returns its result. */
|
|
109
|
+
export async function runVerb(name, flags, positionals) {
|
|
110
|
+
const res = await rpc({ name, flags, positionals });
|
|
111
|
+
if (!res.ok)
|
|
112
|
+
throw new Error(res.error ?? `${name} failed`);
|
|
113
|
+
return res.result;
|
|
114
|
+
}
|
|
115
|
+
/** Stop the server (and its browser). Falls back to killing pids if unreachable. */
|
|
116
|
+
export async function quit() {
|
|
138
117
|
try {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
118
|
+
await rpc({ control: 'quit' });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// socket gone — best-effort kill from the session file
|
|
143
123
|
}
|
|
144
|
-
|
|
145
|
-
|
|
124
|
+
const session = readSession();
|
|
125
|
+
for (const pid of [session?.serverPid, session?.chromePid]) {
|
|
126
|
+
if (pid) {
|
|
127
|
+
try {
|
|
128
|
+
process.kill(pid);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// already gone
|
|
132
|
+
}
|
|
133
|
+
}
|
|
146
134
|
}
|
|
135
|
+
rmSync(socketPath(), { force: true });
|
|
136
|
+
rmSync(sessionFile(), { force: true });
|
|
147
137
|
}
|
|
148
138
|
//# sourceMappingURL=session.js.map
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opice/browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "opice-browser — stateful Playwright browser for opice test authoring (CLI over CDP)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"typecheck": "tsc --build"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@opice/harness": "^0.
|
|
17
|
+
"@opice/harness": "^0.2.1",
|
|
18
18
|
"playwright": "^1.60.0",
|
|
19
19
|
"zod": "^4.4.3"
|
|
20
20
|
},
|