@monoes/monobrowse 1.0.1 → 1.0.3
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/src/__tests__/output.test.d.ts +2 -0
- package/dist/src/__tests__/output.test.d.ts.map +1 -0
- package/dist/src/__tests__/output.test.js +54 -0
- package/dist/src/__tests__/output.test.js.map +1 -0
- package/dist/src/__tests__/ref-cache.test.d.ts +2 -0
- package/dist/src/__tests__/ref-cache.test.d.ts.map +1 -0
- package/dist/src/__tests__/ref-cache.test.js +109 -0
- package/dist/src/__tests__/ref-cache.test.js.map +1 -0
- package/dist/src/browser/action-builder/analyzer.d.ts +0 -1
- package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
- package/dist/src/browser/action-builder/analyzer.js +43 -21
- package/dist/src/browser/action-builder/analyzer.js.map +1 -1
- package/dist/src/browser/action-builder/types.d.ts +0 -0
- package/dist/src/browser/action-builder/types.d.ts.map +0 -0
- package/dist/src/browser/action-builder/types.js +0 -0
- package/dist/src/browser/action-builder/types.js.map +0 -0
- package/dist/src/browser/actions.d.ts +0 -0
- package/dist/src/browser/actions.d.ts.map +0 -0
- package/dist/src/browser/actions.js +0 -0
- package/dist/src/browser/actions.js.map +0 -0
- package/dist/src/browser/adapters/gemini.d.ts +0 -0
- package/dist/src/browser/adapters/gemini.d.ts.map +0 -0
- package/dist/src/browser/adapters/gemini.js +0 -0
- package/dist/src/browser/adapters/gemini.js.map +0 -0
- package/dist/src/browser/adapters/google.d.ts +0 -0
- package/dist/src/browser/adapters/google.d.ts.map +0 -0
- package/dist/src/browser/adapters/google.js +0 -0
- package/dist/src/browser/adapters/google.js.map +0 -0
- package/dist/src/browser/adapters/index.d.ts +0 -0
- package/dist/src/browser/adapters/index.d.ts.map +0 -0
- package/dist/src/browser/adapters/index.js +0 -0
- package/dist/src/browser/adapters/index.js.map +0 -0
- package/dist/src/browser/adapters/instagram.d.ts +0 -0
- package/dist/src/browser/adapters/instagram.d.ts.map +0 -0
- package/dist/src/browser/adapters/instagram.js +0 -0
- package/dist/src/browser/adapters/instagram.js.map +0 -0
- package/dist/src/browser/adapters/linkedin.d.ts +0 -0
- package/dist/src/browser/adapters/linkedin.d.ts.map +0 -0
- package/dist/src/browser/adapters/linkedin.js +0 -0
- package/dist/src/browser/adapters/linkedin.js.map +0 -0
- package/dist/src/browser/adapters/microsoft.d.ts +0 -0
- package/dist/src/browser/adapters/microsoft.d.ts.map +0 -0
- package/dist/src/browser/adapters/microsoft.js +0 -0
- package/dist/src/browser/adapters/microsoft.js.map +0 -0
- package/dist/src/browser/adapters/x.d.ts +0 -0
- package/dist/src/browser/adapters/x.d.ts.map +0 -0
- package/dist/src/browser/adapters/x.js +0 -0
- package/dist/src/browser/adapters/x.js.map +0 -0
- package/dist/src/browser/batch.d.ts +0 -0
- package/dist/src/browser/batch.d.ts.map +0 -0
- package/dist/src/browser/batch.js +0 -0
- package/dist/src/browser/batch.js.map +0 -0
- package/dist/src/browser/browser.d.ts +0 -0
- package/dist/src/browser/browser.d.ts.map +0 -0
- package/dist/src/browser/browser.js +0 -0
- package/dist/src/browser/browser.js.map +0 -0
- package/dist/src/browser/cdp.d.ts +0 -0
- package/dist/src/browser/cdp.d.ts.map +0 -0
- package/dist/src/browser/cdp.js +0 -0
- package/dist/src/browser/cdp.js.map +0 -0
- package/dist/src/browser/console-log.d.ts +0 -0
- package/dist/src/browser/console-log.d.ts.map +0 -0
- package/dist/src/browser/console-log.js +0 -0
- package/dist/src/browser/console-log.js.map +0 -0
- package/dist/src/browser/dashboard/api-types.d.ts +0 -0
- package/dist/src/browser/dashboard/api-types.d.ts.map +0 -0
- package/dist/src/browser/dashboard/api-types.js +0 -0
- package/dist/src/browser/dashboard/api-types.js.map +0 -0
- package/dist/src/browser/dashboard/server.d.ts +12 -1
- package/dist/src/browser/dashboard/server.d.ts.map +1 -1
- package/dist/src/browser/dashboard/server.js +4 -198
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +0 -0
- package/dist/src/browser/dialog.d.ts +0 -0
- package/dist/src/browser/dialog.d.ts.map +0 -0
- package/dist/src/browser/dialog.js +0 -0
- package/dist/src/browser/dialog.js.map +0 -0
- package/dist/src/browser/emulation.d.ts +0 -0
- package/dist/src/browser/emulation.d.ts.map +0 -0
- package/dist/src/browser/emulation.js +0 -0
- package/dist/src/browser/emulation.js.map +0 -0
- package/dist/src/browser/find.d.ts +0 -0
- package/dist/src/browser/find.d.ts.map +0 -0
- package/dist/src/browser/find.js +0 -0
- package/dist/src/browser/find.js.map +0 -0
- package/dist/src/browser/har.d.ts +0 -0
- package/dist/src/browser/har.d.ts.map +0 -0
- package/dist/src/browser/har.js +0 -0
- package/dist/src/browser/har.js.map +0 -0
- package/dist/src/browser/index.d.ts +1 -0
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +1 -0
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/browser/network.d.ts +0 -0
- package/dist/src/browser/network.d.ts.map +0 -0
- package/dist/src/browser/network.js +0 -0
- package/dist/src/browser/network.js.map +0 -0
- package/dist/src/browser/pdf.d.ts +0 -0
- package/dist/src/browser/pdf.d.ts.map +0 -0
- package/dist/src/browser/pdf.js +0 -0
- package/dist/src/browser/pdf.js.map +0 -0
- package/dist/src/browser/profiler.d.ts +0 -0
- package/dist/src/browser/profiler.d.ts.map +0 -0
- package/dist/src/browser/profiler.js +0 -0
- package/dist/src/browser/profiler.js.map +0 -0
- package/dist/src/browser/record.d.ts +0 -0
- package/dist/src/browser/record.d.ts.map +0 -0
- package/dist/src/browser/record.js +0 -0
- package/dist/src/browser/record.js.map +0 -0
- package/dist/src/browser/ref-cache.d.ts +21 -0
- package/dist/src/browser/ref-cache.d.ts.map +1 -0
- package/dist/src/browser/ref-cache.js +70 -0
- package/dist/src/browser/ref-cache.js.map +1 -0
- package/dist/src/browser/screenshot.d.ts +0 -0
- package/dist/src/browser/screenshot.d.ts.map +0 -0
- package/dist/src/browser/screenshot.js +0 -0
- package/dist/src/browser/screenshot.js.map +0 -0
- package/dist/src/browser/session.d.ts +0 -0
- package/dist/src/browser/session.d.ts.map +0 -0
- package/dist/src/browser/session.js +0 -0
- package/dist/src/browser/session.js.map +0 -0
- package/dist/src/browser/snapshot.d.ts +0 -0
- package/dist/src/browser/snapshot.d.ts.map +0 -0
- package/dist/src/browser/snapshot.js +0 -0
- package/dist/src/browser/snapshot.js.map +0 -0
- package/dist/src/browser/storage.d.ts +0 -0
- package/dist/src/browser/storage.d.ts.map +0 -0
- package/dist/src/browser/storage.js +0 -0
- package/dist/src/browser/storage.js.map +0 -0
- package/dist/src/browser/tabs.d.ts +1 -1
- package/dist/src/browser/tabs.d.ts.map +1 -1
- package/dist/src/browser/tabs.js +20 -4
- package/dist/src/browser/tabs.js.map +1 -1
- package/dist/src/browser/trace.d.ts +0 -0
- package/dist/src/browser/trace.d.ts.map +0 -0
- package/dist/src/browser/trace.js +0 -0
- package/dist/src/browser/trace.js.map +0 -0
- package/dist/src/browser/types.d.ts +0 -0
- package/dist/src/browser/types.d.ts.map +0 -0
- package/dist/src/browser/types.js +0 -0
- package/dist/src/browser/types.js.map +0 -0
- package/dist/src/browser/vitals.d.ts +0 -0
- package/dist/src/browser/vitals.d.ts.map +0 -0
- package/dist/src/browser/vitals.js +0 -0
- package/dist/src/browser/vitals.js.map +0 -0
- package/dist/src/browser/wait.d.ts +0 -0
- package/dist/src/browser/wait.d.ts.map +0 -0
- package/dist/src/browser/wait.js +0 -0
- package/dist/src/browser/wait.js.map +0 -0
- package/dist/src/cli/action.d.ts +0 -0
- package/dist/src/cli/action.d.ts.map +1 -1
- package/dist/src/cli/action.js +92 -4
- package/dist/src/cli/action.js.map +1 -1
- package/dist/src/cli/commands.d.ts +0 -0
- package/dist/src/cli/commands.d.ts.map +1 -1
- package/dist/src/cli/commands.js +32 -6
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/output.d.ts +0 -0
- package/dist/src/cli/output.d.ts.map +0 -0
- package/dist/src/cli/output.js +0 -0
- package/dist/src/cli/output.js.map +0 -0
- package/dist/src/cli/platform.d.ts +0 -0
- package/dist/src/cli/platform.d.ts.map +0 -0
- package/dist/src/cli/platform.js +0 -0
- package/dist/src/cli/platform.js.map +0 -0
- package/dist/src/cli/types.d.ts +0 -0
- package/dist/src/cli/types.d.ts.map +0 -0
- package/dist/src/cli/types.js +0 -0
- package/dist/src/cli/types.js.map +0 -0
- package/dist/src/cli.d.ts +0 -0
- package/dist/src/cli.d.ts.map +0 -0
- package/dist/src/cli.js.map +0 -0
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +0 -16
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -15
- package/src/__tests__/output.test.ts +62 -0
- package/src/__tests__/ref-cache.test.ts +134 -0
- package/src/browser/action-builder/analyzer.ts +41 -23
- package/src/browser/action-builder/types.ts +0 -0
- package/src/browser/actions.ts +0 -0
- package/src/browser/adapters/gemini.ts +0 -0
- package/src/browser/adapters/google.ts +0 -0
- package/src/browser/adapters/index.ts +0 -0
- package/src/browser/adapters/instagram.ts +0 -0
- package/src/browser/adapters/linkedin.ts +0 -0
- package/src/browser/adapters/microsoft.ts +0 -0
- package/src/browser/adapters/x.ts +0 -0
- package/src/browser/batch.ts +0 -0
- package/src/browser/browser.ts +0 -0
- package/src/browser/cdp.ts +0 -0
- package/src/browser/console-log.ts +0 -0
- package/src/browser/dashboard/api-types.ts +0 -0
- package/src/browser/dashboard/server.ts +16 -198
- package/src/browser/dashboard/ui.html +0 -0
- package/src/browser/dialog.ts +0 -0
- package/src/browser/emulation.ts +0 -0
- package/src/browser/find.ts +0 -0
- package/src/browser/har.ts +0 -0
- package/src/browser/index.ts +1 -0
- package/src/browser/network.ts +0 -0
- package/src/browser/pdf.ts +0 -0
- package/src/browser/profiler.ts +0 -0
- package/src/browser/record.ts +0 -0
- package/src/browser/ref-cache.ts +90 -0
- package/src/browser/screenshot.ts +0 -0
- package/src/browser/session.ts +0 -0
- package/src/browser/snapshot.ts +0 -0
- package/src/browser/storage.ts +0 -0
- package/src/browser/tabs.ts +36 -7
- package/src/browser/trace.ts +0 -0
- package/src/browser/types.ts +0 -0
- package/src/browser/vitals.ts +0 -0
- package/src/browser/wait.ts +0 -0
- package/src/cli/action.ts +91 -5
- package/src/cli/commands.ts +35 -6
- package/src/cli/output.ts +0 -0
- package/src/cli/platform.ts +0 -0
- package/src/cli/types.ts +0 -0
- package/src/cli.ts +0 -0
- package/src/index.ts +0 -20
- package/dist/package.json +0 -75
- package/dist/src/browser/playbook/browser-handlers.d.ts +0 -3
- package/dist/src/browser/playbook/browser-handlers.d.ts.map +0 -1
- package/dist/src/browser/playbook/browser-handlers.js +0 -377
- package/dist/src/browser/playbook/browser-handlers.js.map +0 -1
- package/dist/src/browser/playbook/builtin-handlers.d.ts +0 -3
- package/dist/src/browser/playbook/builtin-handlers.d.ts.map +0 -1
- package/dist/src/browser/playbook/builtin-handlers.js +0 -364
- package/dist/src/browser/playbook/builtin-handlers.js.map +0 -1
- package/dist/src/browser/playbook/index.d.ts +0 -3
- package/dist/src/browser/playbook/index.d.ts.map +0 -1
- package/dist/src/browser/playbook/index.js +0 -3
- package/dist/src/browser/playbook/index.js.map +0 -1
- package/dist/src/browser/playbook/store.d.ts +0 -8
- package/dist/src/browser/playbook/store.d.ts.map +0 -1
- package/dist/src/browser/playbook/store.js +0 -87
- package/dist/src/browser/playbook/store.js.map +0 -1
- package/dist/src/browser/workflow/builtin-handlers.d.ts +0 -3
- package/dist/src/browser/workflow/builtin-handlers.d.ts.map +0 -1
- package/dist/src/browser/workflow/builtin-handlers.js +0 -343
- package/dist/src/browser/workflow/builtin-handlers.js.map +0 -1
- package/dist/src/browser/workflow/engine.d.ts +0 -10
- package/dist/src/browser/workflow/engine.d.ts.map +0 -1
- package/dist/src/browser/workflow/engine.js +0 -174
- package/dist/src/browser/workflow/engine.js.map +0 -1
- package/dist/src/browser/workflow/expression.d.ts +0 -4
- package/dist/src/browser/workflow/expression.d.ts.map +0 -1
- package/dist/src/browser/workflow/expression.js +0 -89
- package/dist/src/browser/workflow/expression.js.map +0 -1
- package/dist/src/browser/workflow/index.d.ts +0 -6
- package/dist/src/browser/workflow/index.d.ts.map +0 -1
- package/dist/src/browser/workflow/index.js +0 -6
- package/dist/src/browser/workflow/index.js.map +0 -1
- package/dist/src/browser/workflow/store.d.ts +0 -8
- package/dist/src/browser/workflow/store.d.ts.map +0 -1
- package/dist/src/browser/workflow/store.js +0 -87
- package/dist/src/browser/workflow/store.js.map +0 -1
- package/dist/src/browser/workflow/types.d.ts +0 -62
- package/dist/src/browser/workflow/types.d.ts.map +0 -1
- package/dist/src/browser/workflow/types.js +0 -2
- package/dist/src/browser/workflow/types.js.map +0 -1
- package/dist/src/cli/playbook.d.ts +0 -3
- package/dist/src/cli/playbook.d.ts.map +0 -1
- package/dist/src/cli/playbook.js +0 -265
- package/dist/src/cli/playbook.js.map +0 -1
- package/dist/src/cli/workflow.d.ts +0 -2
- package/dist/src/cli/workflow.d.ts.map +0 -1
- package/dist/src/cli/workflow.js +0 -3
- package/dist/src/cli/workflow.js.map +0 -1
- package/src/browser/playbook/browser-handlers.ts +0 -449
- package/src/browser/playbook/builtin-handlers.ts +0 -400
- package/src/browser/playbook/index.ts +0 -2
- package/src/browser/playbook/store.ts +0 -87
- package/src/cli/playbook.ts +0 -280
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
// createBrowserHandlers — CDP-backed NodeHandler implementations for @monoes/monoplaybook.
|
|
2
|
-
//
|
|
3
|
-
// browser.open — connect to Chrome CDP and open a URL
|
|
4
|
-
// browser.navigate — navigate the current tab to a URL
|
|
5
|
-
// browser.click — click an element (selector | role | text | label | placeholder)
|
|
6
|
-
// browser.type — type text into an element (keystroke-by-keystroke)
|
|
7
|
-
// browser.fill — set an input value directly (faster than type)
|
|
8
|
-
// browser.select — pick an <option> by value or visible text
|
|
9
|
-
// browser.check — check or uncheck a checkbox / radio
|
|
10
|
-
// browser.hover — hover over an element
|
|
11
|
-
// browser.press — press a key or combo (e.g. "Enter", "Ctrl+A")
|
|
12
|
-
// browser.scroll — scroll up/down/left/right by pixel amount
|
|
13
|
-
// browser.wait — wait for selector | url | load | networkidle | duration
|
|
14
|
-
// browser.extract — pull text, attribute, html, all_text, url, or title into item.data
|
|
15
|
-
// browser.snapshot — capture an accessibility tree snapshot
|
|
16
|
-
// browser.screenshot — take a screenshot (saves to file or returns base64)
|
|
17
|
-
// browser.evaluate — run arbitrary JS; result goes into item.data
|
|
18
|
-
// browser.close — drop the cached CDP connection (does not kill Chrome)
|
|
19
|
-
|
|
20
|
-
import type { NodeHandler, Item } from '@monoes/monoplaybook';
|
|
21
|
-
import { CdpClient } from '../cdp.js';
|
|
22
|
-
import {
|
|
23
|
-
connectToTarget,
|
|
24
|
-
openUrl,
|
|
25
|
-
waitForLoad,
|
|
26
|
-
getCurrentUrl,
|
|
27
|
-
getCurrentTitle,
|
|
28
|
-
} from '../browser.js';
|
|
29
|
-
import {
|
|
30
|
-
clickElement,
|
|
31
|
-
fillElement,
|
|
32
|
-
typeText,
|
|
33
|
-
pressKey,
|
|
34
|
-
pressKeyCombo,
|
|
35
|
-
scrollElement,
|
|
36
|
-
hoverElement,
|
|
37
|
-
selectOption,
|
|
38
|
-
checkElement,
|
|
39
|
-
evaluateJs,
|
|
40
|
-
} from '../actions.js';
|
|
41
|
-
import {
|
|
42
|
-
findBySelector,
|
|
43
|
-
findByRole,
|
|
44
|
-
findByText,
|
|
45
|
-
findByLabel,
|
|
46
|
-
findByPlaceholder,
|
|
47
|
-
} from '../find.js';
|
|
48
|
-
import { waitFor } from '../wait.js';
|
|
49
|
-
import { captureSnapshot } from '../snapshot.js';
|
|
50
|
-
import { captureScreenshot } from '../screenshot.js';
|
|
51
|
-
import type { ElementRef } from '../types.js';
|
|
52
|
-
import { mkdir } from 'node:fs/promises';
|
|
53
|
-
import { dirname, resolve } from 'node:path';
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Shared connection state — cached per CDP port across nodes in one playbook run
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
interface BrowserConnection {
|
|
60
|
-
client: CdpClient;
|
|
61
|
-
sessionId: string;
|
|
62
|
-
refs: Map<string, ElementRef>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const connectionCache = new Map<number, BrowserConnection>();
|
|
66
|
-
|
|
67
|
-
async function getConnection(port: number): Promise<BrowserConnection> {
|
|
68
|
-
if (connectionCache.has(port)) {
|
|
69
|
-
const cached = connectionCache.get(port)!;
|
|
70
|
-
try {
|
|
71
|
-
// Lightweight liveness check — if the CDP connection has dropped, this throws
|
|
72
|
-
await cached.client.send('Runtime.evaluate', { expression: '1', returnByValue: true }, cached.sessionId);
|
|
73
|
-
return cached;
|
|
74
|
-
} catch {
|
|
75
|
-
// Stale connection — evict and reconnect below
|
|
76
|
-
connectionCache.delete(port);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
const { client, sessionId } = await connectToTarget(port);
|
|
80
|
-
const conn: BrowserConnection = { client, sessionId, refs: new Map() };
|
|
81
|
-
connectionCache.set(port, conn);
|
|
82
|
-
return conn;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function releaseConnection(port: number): void {
|
|
86
|
-
connectionCache.delete(port);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function safeResolvePath(rawPath: string): string {
|
|
90
|
-
const cwd = process.cwd();
|
|
91
|
-
const abs = resolve(cwd, rawPath);
|
|
92
|
-
if (abs !== cwd && !abs.startsWith(cwd + '/')) {
|
|
93
|
-
throw new Error(`Path traversal blocked: "${rawPath}" resolves outside working directory`);
|
|
94
|
-
}
|
|
95
|
-
return abs;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
// Element resolution — locator types: selector | role | text | label | placeholder
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
|
|
102
|
-
async function findElement(
|
|
103
|
-
conn: BrowserConnection,
|
|
104
|
-
config: Record<string, unknown>,
|
|
105
|
-
): Promise<ElementRef> {
|
|
106
|
-
const locator = (config['locator'] as string | undefined) ?? 'selector';
|
|
107
|
-
const value = config['value'] as string;
|
|
108
|
-
if (!value) throw new Error(`browser handler requires config.value (the element locator)`);
|
|
109
|
-
|
|
110
|
-
const { client, sessionId, refs } = conn;
|
|
111
|
-
const opts = {
|
|
112
|
-
exact: config['exact'] as boolean | undefined,
|
|
113
|
-
nth: config['nth'] as number | undefined,
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
let ref: ElementRef | null = null;
|
|
117
|
-
switch (locator) {
|
|
118
|
-
case 'selector': ref = await findBySelector(client, sessionId, refs, value); break;
|
|
119
|
-
case 'role': ref = await findByRole(client, sessionId, refs, value, opts); break;
|
|
120
|
-
case 'text': ref = await findByText(client, sessionId, refs, value, opts); break;
|
|
121
|
-
case 'label': ref = await findByLabel(client, sessionId, refs, value, opts); break;
|
|
122
|
-
case 'placeholder': ref = await findByPlaceholder(client, sessionId, refs, value, opts); break;
|
|
123
|
-
default: throw new Error(`Unknown locator "${locator}". Use: selector|role|text|label|placeholder`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (!ref) throw new Error(`Element not found: ${locator}="${value}"`);
|
|
127
|
-
return ref;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Modifier bitmask used by CDP (matches DevTools protocol)
|
|
131
|
-
function modifierBits(modifiers: string[]): number {
|
|
132
|
-
let bits = 0;
|
|
133
|
-
for (const m of modifiers) {
|
|
134
|
-
switch (m.toLowerCase()) {
|
|
135
|
-
case 'alt': bits |= 1; break;
|
|
136
|
-
case 'ctrl':
|
|
137
|
-
case 'control': bits |= 2; break;
|
|
138
|
-
case 'meta':
|
|
139
|
-
case 'cmd': bits |= 4; break;
|
|
140
|
-
case 'shift': bits |= 8; break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return bits;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ---------------------------------------------------------------------------
|
|
147
|
-
// Handlers
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
|
|
150
|
-
export function createBrowserHandlers(): Map<string, NodeHandler> {
|
|
151
|
-
const h = new Map<string, NodeHandler>();
|
|
152
|
-
|
|
153
|
-
// ── browser.open ──────────────────────────────────────────────────────────
|
|
154
|
-
h.set('browser.open', async (items, config): Promise<Item[]> => {
|
|
155
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
156
|
-
const url = config['url'] as string;
|
|
157
|
-
if (!url) throw new Error('browser.open requires config.url');
|
|
158
|
-
const timeout = (config['timeoutMs'] as number | undefined) ?? 30000;
|
|
159
|
-
const condition = (config['waitUntil'] as 'load' | 'networkidle' | 'domcontentloaded' | undefined) ?? 'load';
|
|
160
|
-
|
|
161
|
-
const conn = await getConnection(port);
|
|
162
|
-
await openUrl(conn.client, conn.sessionId, url);
|
|
163
|
-
await waitForLoad(conn.client, conn.sessionId, condition, timeout);
|
|
164
|
-
|
|
165
|
-
const currentUrl = await getCurrentUrl(conn.client, conn.sessionId);
|
|
166
|
-
const title = await getCurrentTitle(conn.client, conn.sessionId);
|
|
167
|
-
return items.map(item => ({ ...item, data: { ...item.data, url: currentUrl, title, port } }));
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// ── browser.navigate ──────────────────────────────────────────────────────
|
|
171
|
-
h.set('browser.navigate', async (items, config): Promise<Item[]> => {
|
|
172
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
173
|
-
const url = config['url'] as string;
|
|
174
|
-
if (!url) throw new Error('browser.navigate requires config.url');
|
|
175
|
-
const timeout = (config['timeoutMs'] as number | undefined) ?? 30000;
|
|
176
|
-
const condition = (config['waitUntil'] as 'load' | 'networkidle' | 'domcontentloaded' | undefined) ?? 'load';
|
|
177
|
-
|
|
178
|
-
const conn = await getConnection(port);
|
|
179
|
-
await openUrl(conn.client, conn.sessionId, url);
|
|
180
|
-
await waitForLoad(conn.client, conn.sessionId, condition, timeout);
|
|
181
|
-
|
|
182
|
-
const currentUrl = await getCurrentUrl(conn.client, conn.sessionId);
|
|
183
|
-
const title = await getCurrentTitle(conn.client, conn.sessionId);
|
|
184
|
-
return items.map(item => ({ ...item, data: { ...item.data, url: currentUrl, title } }));
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// ── browser.click ─────────────────────────────────────────────────────────
|
|
188
|
-
h.set('browser.click', async (items, config): Promise<Item[]> => {
|
|
189
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
190
|
-
const conn = await getConnection(port);
|
|
191
|
-
const ref = await findElement(conn, config);
|
|
192
|
-
await clickElement(conn.client, conn.sessionId, ref);
|
|
193
|
-
return items;
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// ── browser.type ──────────────────────────────────────────────────────────
|
|
197
|
-
h.set('browser.type', async (items, config): Promise<Item[]> => {
|
|
198
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
199
|
-
const text = config['text'] as string;
|
|
200
|
-
if (text === undefined) throw new Error('browser.type requires config.text');
|
|
201
|
-
|
|
202
|
-
const conn = await getConnection(port);
|
|
203
|
-
const ref = await findElement(conn, config);
|
|
204
|
-
if (config['clear'] !== false) {
|
|
205
|
-
await fillElement(conn.client, conn.sessionId, ref, '');
|
|
206
|
-
}
|
|
207
|
-
await typeText(conn.client, conn.sessionId, text);
|
|
208
|
-
return items;
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
// ── browser.fill ──────────────────────────────────────────────────────────
|
|
212
|
-
h.set('browser.fill', async (items, config): Promise<Item[]> => {
|
|
213
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
214
|
-
const text = (config['text'] as string | undefined) ?? '';
|
|
215
|
-
|
|
216
|
-
const conn = await getConnection(port);
|
|
217
|
-
const ref = await findElement(conn, config);
|
|
218
|
-
await fillElement(conn.client, conn.sessionId, ref, text);
|
|
219
|
-
return items;
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// ── browser.select ────────────────────────────────────────────────────────
|
|
223
|
-
h.set('browser.select', async (items, config): Promise<Item[]> => {
|
|
224
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
225
|
-
const option = config['option'] as string;
|
|
226
|
-
if (!option) throw new Error('browser.select requires config.option');
|
|
227
|
-
|
|
228
|
-
const conn = await getConnection(port);
|
|
229
|
-
const ref = await findElement(conn, config);
|
|
230
|
-
await selectOption(conn.client, conn.sessionId, ref, option);
|
|
231
|
-
return items;
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// ── browser.check ─────────────────────────────────────────────────────────
|
|
235
|
-
h.set('browser.check', async (items, config): Promise<Item[]> => {
|
|
236
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
237
|
-
const checked = (config['checked'] as boolean | undefined) ?? true;
|
|
238
|
-
|
|
239
|
-
const conn = await getConnection(port);
|
|
240
|
-
const ref = await findElement(conn, config);
|
|
241
|
-
await checkElement(conn.client, conn.sessionId, ref, checked);
|
|
242
|
-
return items;
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
// ── browser.hover ─────────────────────────────────────────────────────────
|
|
246
|
-
h.set('browser.hover', async (items, config): Promise<Item[]> => {
|
|
247
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
248
|
-
const conn = await getConnection(port);
|
|
249
|
-
const ref = await findElement(conn, config);
|
|
250
|
-
await hoverElement(conn.client, conn.sessionId, ref);
|
|
251
|
-
return items;
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// ── browser.press ─────────────────────────────────────────────────────────
|
|
255
|
-
// Config: port, key — e.g. "Enter", "Tab", "Escape", "Ctrl+A", "Shift+Tab"
|
|
256
|
-
h.set('browser.press', async (items, config): Promise<Item[]> => {
|
|
257
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
258
|
-
const key = config['key'] as string;
|
|
259
|
-
if (!key) throw new Error('browser.press requires config.key');
|
|
260
|
-
|
|
261
|
-
const conn = await getConnection(port);
|
|
262
|
-
if (key.includes('+')) {
|
|
263
|
-
const parts = key.split('+').map(k => k.trim());
|
|
264
|
-
const mainKey = parts[parts.length - 1];
|
|
265
|
-
const bits = modifierBits(parts.slice(0, -1));
|
|
266
|
-
// Delegate to pressKeyCombo which uses resolveKey() for correct code/key mapping
|
|
267
|
-
// (avoids KeyENTER-style bugs from naive Key${mainKey.toUpperCase()} construction)
|
|
268
|
-
await pressKeyCombo(conn.client, conn.sessionId, mainKey, bits);
|
|
269
|
-
} else {
|
|
270
|
-
await pressKey(conn.client, conn.sessionId, key);
|
|
271
|
-
}
|
|
272
|
-
return items;
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// ── browser.scroll ────────────────────────────────────────────────────────
|
|
276
|
-
// Config: port, direction (up|down|left|right, default "down"), amount (px, default 300),
|
|
277
|
-
// locator + value (optional — scroll a specific element)
|
|
278
|
-
h.set('browser.scroll', async (items, config): Promise<Item[]> => {
|
|
279
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
280
|
-
const direction = (config['direction'] as 'up' | 'down' | 'left' | 'right' | undefined) ?? 'down';
|
|
281
|
-
const amount = (config['amount'] as number | undefined) ?? 300;
|
|
282
|
-
|
|
283
|
-
const conn = await getConnection(port);
|
|
284
|
-
const hasLocator = !!(config['value']);
|
|
285
|
-
|
|
286
|
-
if (hasLocator) {
|
|
287
|
-
const ref = await findElement(conn, config);
|
|
288
|
-
await scrollElement(conn.client, conn.sessionId, direction, amount, ref);
|
|
289
|
-
} else {
|
|
290
|
-
await scrollElement(conn.client, conn.sessionId, direction, amount);
|
|
291
|
-
}
|
|
292
|
-
return items;
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// ── browser.wait ──────────────────────────────────────────────────────────
|
|
296
|
-
// Config: port, for (selector|url|load|networkidle|duration), value, timeoutMs
|
|
297
|
-
h.set('browser.wait', async (items, config): Promise<Item[]> => {
|
|
298
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
299
|
-
const conn = await getConnection(port);
|
|
300
|
-
const waitKind = (config['for'] as string | undefined) ?? 'duration';
|
|
301
|
-
const timeout = (config['timeoutMs'] as number | undefined) ?? 30000;
|
|
302
|
-
const value = config['value'];
|
|
303
|
-
|
|
304
|
-
switch (waitKind) {
|
|
305
|
-
case 'duration':
|
|
306
|
-
await new Promise(res => setTimeout(res, (value as number | undefined) ?? 1000));
|
|
307
|
-
break;
|
|
308
|
-
case 'selector':
|
|
309
|
-
await waitFor(conn.client, conn.sessionId, { selector: value as string, timeout });
|
|
310
|
-
break;
|
|
311
|
-
case 'url':
|
|
312
|
-
await waitFor(conn.client, conn.sessionId, { url: value as string, timeout });
|
|
313
|
-
break;
|
|
314
|
-
case 'load':
|
|
315
|
-
await waitForLoad(conn.client, conn.sessionId, 'load', timeout);
|
|
316
|
-
break;
|
|
317
|
-
case 'networkidle':
|
|
318
|
-
await waitForLoad(conn.client, conn.sessionId, 'networkidle', timeout);
|
|
319
|
-
break;
|
|
320
|
-
default:
|
|
321
|
-
throw new Error(`browser.wait: unknown 'for' value: "${waitKind}". Use selector|url|load|networkidle|duration`);
|
|
322
|
-
}
|
|
323
|
-
return items;
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// ── browser.extract ───────────────────────────────────────────────────────
|
|
327
|
-
// Config: port, as (text|attribute|html|all_text|url|title), locator, value,
|
|
328
|
-
// attribute (when as=attribute), outputKey (default "extracted")
|
|
329
|
-
h.set('browser.extract', async (items, config): Promise<Item[]> => {
|
|
330
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
331
|
-
const as = (config['as'] as string | undefined) ?? 'text';
|
|
332
|
-
const outputKey = (config['outputKey'] as string | undefined) ?? 'extracted';
|
|
333
|
-
const conn = await getConnection(port);
|
|
334
|
-
|
|
335
|
-
if (as === 'url') {
|
|
336
|
-
const url = await getCurrentUrl(conn.client, conn.sessionId);
|
|
337
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: url } }));
|
|
338
|
-
}
|
|
339
|
-
if (as === 'title') {
|
|
340
|
-
const title = await getCurrentTitle(conn.client, conn.sessionId);
|
|
341
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: title } }));
|
|
342
|
-
}
|
|
343
|
-
if (as === 'all_text') {
|
|
344
|
-
const text = await evaluateJs(conn.client, conn.sessionId, 'document.body.innerText');
|
|
345
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: text } }));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const ref = await findElement(conn, config);
|
|
349
|
-
|
|
350
|
-
if (as === 'text') {
|
|
351
|
-
const result = await conn.client.send<{ result: { value: unknown } }>(
|
|
352
|
-
'Runtime.callFunctionOn',
|
|
353
|
-
{ objectId: ref.objectId, functionDeclaration: 'function(){return this.innerText ?? this.textContent ?? ""}', returnByValue: true },
|
|
354
|
-
conn.sessionId,
|
|
355
|
-
);
|
|
356
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: result.result.value } }));
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (as === 'attribute') {
|
|
360
|
-
const attr = config['attribute'] as string;
|
|
361
|
-
if (!attr) throw new Error('browser.extract with as=attribute requires config.attribute');
|
|
362
|
-
const result = await conn.client.send<{ result: { value: unknown } }>(
|
|
363
|
-
'Runtime.callFunctionOn',
|
|
364
|
-
{
|
|
365
|
-
objectId: ref.objectId,
|
|
366
|
-
functionDeclaration: `function(){return this.getAttribute(${JSON.stringify(attr)})}`,
|
|
367
|
-
returnByValue: true,
|
|
368
|
-
},
|
|
369
|
-
conn.sessionId,
|
|
370
|
-
);
|
|
371
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: result.result.value } }));
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if (as === 'html') {
|
|
375
|
-
const result = await conn.client.send<{ result: { value: unknown } }>(
|
|
376
|
-
'Runtime.callFunctionOn',
|
|
377
|
-
{ objectId: ref.objectId, functionDeclaration: 'function(){return this.outerHTML}', returnByValue: true },
|
|
378
|
-
conn.sessionId,
|
|
379
|
-
);
|
|
380
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: result.result.value } }));
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
throw new Error(`browser.extract: unknown 'as' value: "${as}". Use text|attribute|html|all_text|url|title`);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// ── browser.snapshot ──────────────────────────────────────────────────────
|
|
387
|
-
// Captures an accessibility tree. Output stored in item.data[outputKey].
|
|
388
|
-
// Config: port, selector (scope to element), interactiveOnly, compact, outputKey
|
|
389
|
-
h.set('browser.snapshot', async (items, config): Promise<Item[]> => {
|
|
390
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
391
|
-
const outputKey = (config['outputKey'] as string | undefined) ?? 'snapshot';
|
|
392
|
-
const conn = await getConnection(port);
|
|
393
|
-
|
|
394
|
-
const result = await captureSnapshot(conn.client, conn.sessionId, {
|
|
395
|
-
selector: config['selector'] as string | undefined,
|
|
396
|
-
interactiveOnly: (config['interactiveOnly'] as boolean | undefined) ?? false,
|
|
397
|
-
compact: (config['compact'] as boolean | undefined) ?? true,
|
|
398
|
-
});
|
|
399
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: result } }));
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// ── browser.screenshot ────────────────────────────────────────────────────
|
|
403
|
-
// Config: port, path (optional file path), fullPage, format (jpeg|png|webp),
|
|
404
|
-
// quality, outputKey (default "screenshot")
|
|
405
|
-
// Output: if path is set → saves file and puts path in data; else → puts dataUrl in data + binaryBase64
|
|
406
|
-
h.set('browser.screenshot', async (items, config): Promise<Item[]> => {
|
|
407
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
408
|
-
const outputKey = (config['outputKey'] as string | undefined) ?? 'screenshot';
|
|
409
|
-
const conn = await getConnection(port);
|
|
410
|
-
|
|
411
|
-
const userPath = config['path'] as string | undefined;
|
|
412
|
-
const absPath = userPath ? safeResolvePath(userPath) : undefined;
|
|
413
|
-
if (absPath) await mkdir(dirname(absPath), { recursive: true });
|
|
414
|
-
|
|
415
|
-
const { path: savedPath, dataUrl } = await captureScreenshot(conn.client, conn.sessionId, {
|
|
416
|
-
path: absPath,
|
|
417
|
-
fullPage: (config['fullPage'] as boolean | undefined) ?? false,
|
|
418
|
-
format: (config['format'] as 'jpeg' | 'png' | 'webp' | undefined) ?? 'png',
|
|
419
|
-
quality: config['quality'] as number | undefined,
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
return items.map(item => ({
|
|
423
|
-
...item,
|
|
424
|
-
data: { ...item.data, [outputKey]: userPath ? savedPath : dataUrl },
|
|
425
|
-
}));
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
// ── browser.evaluate ──────────────────────────────────────────────────────
|
|
429
|
-
// Config: port, script (JS expression), outputKey (default "result")
|
|
430
|
-
h.set('browser.evaluate', async (items, config): Promise<Item[]> => {
|
|
431
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
432
|
-
const script = config['script'] as string;
|
|
433
|
-
if (!script) throw new Error('browser.evaluate requires config.script');
|
|
434
|
-
const outputKey = (config['outputKey'] as string | undefined) ?? 'result';
|
|
435
|
-
|
|
436
|
-
const conn = await getConnection(port);
|
|
437
|
-
const result = await evaluateJs(conn.client, conn.sessionId, script);
|
|
438
|
-
return items.map(item => ({ ...item, data: { ...item.data, [outputKey]: result } }));
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
// ── browser.close ─────────────────────────────────────────────────────────
|
|
442
|
-
h.set('browser.close', async (items, config): Promise<Item[]> => {
|
|
443
|
-
const port = (config['port'] as number | undefined) ?? 9222;
|
|
444
|
-
releaseConnection(port);
|
|
445
|
-
return items;
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
return h;
|
|
449
|
-
}
|