@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
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AX-tree ref cache persistence.
|
|
3
|
+
*
|
|
4
|
+
* `snapshot` and `find` are separate CLI invocations — each starts a fresh
|
|
5
|
+
* node process, so the in-memory ElementRef Map built by captureSnapshot()
|
|
6
|
+
* does not survive between them. This module persists a lightweight lookup
|
|
7
|
+
* index (ref -> role/name/nodeId/backendDOMNodeId, i.e. everything CDP needs
|
|
8
|
+
* to re-target an element) to disk so a later process can rehydrate it.
|
|
9
|
+
*
|
|
10
|
+
* The full AX-tree text/dump is intentionally NOT persisted — only the
|
|
11
|
+
* per-ref index, to keep the file small.
|
|
12
|
+
*/
|
|
13
|
+
import { readFile, writeFile, mkdir, rm } from 'fs/promises';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import type { ElementRef } from './types.js';
|
|
16
|
+
|
|
17
|
+
const CACHE_DIR = join(process.cwd(), '.monomind', 'monobrowse');
|
|
18
|
+
const CACHE_FILE = join(CACHE_DIR, 'ax-snapshot.json');
|
|
19
|
+
|
|
20
|
+
/** Snapshot older than this is flagged as possibly stale (page may have changed). */
|
|
21
|
+
export const REF_CACHE_STALE_MS = 30_000;
|
|
22
|
+
|
|
23
|
+
interface RefCacheFile {
|
|
24
|
+
targetId: string;
|
|
25
|
+
url: string;
|
|
26
|
+
savedAt: number;
|
|
27
|
+
refs: ElementRef[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RefCacheEntry {
|
|
31
|
+
refs: Map<string, ElementRef>;
|
|
32
|
+
url: string;
|
|
33
|
+
savedAt: number;
|
|
34
|
+
ageMs: number;
|
|
35
|
+
stale: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Persist the current ref index for a target so a later CLI process can read it back. */
|
|
39
|
+
export async function saveRefCache(
|
|
40
|
+
targetId: string,
|
|
41
|
+
url: string,
|
|
42
|
+
refs: Map<string, ElementRef>
|
|
43
|
+
): Promise<void> {
|
|
44
|
+
try {
|
|
45
|
+
await mkdir(CACHE_DIR, { recursive: true });
|
|
46
|
+
const data: RefCacheFile = {
|
|
47
|
+
targetId,
|
|
48
|
+
url,
|
|
49
|
+
savedAt: Date.now(),
|
|
50
|
+
refs: [...refs.values()],
|
|
51
|
+
};
|
|
52
|
+
await writeFile(CACHE_FILE, JSON.stringify(data));
|
|
53
|
+
} catch {
|
|
54
|
+
// Best-effort — persistence failure just means cross-process rehydration
|
|
55
|
+
// won't work; in-process (same run) behavior is unaffected.
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Load the persisted ref index, scoped to the given targetId (a cache from a
|
|
61
|
+
* different tab/target is ignored). Returns null if no usable cache exists —
|
|
62
|
+
* callers fall back to an empty in-memory Map, matching prior behavior.
|
|
63
|
+
*/
|
|
64
|
+
export async function loadRefCache(targetId: string): Promise<RefCacheEntry | null> {
|
|
65
|
+
try {
|
|
66
|
+
const raw = await readFile(CACHE_FILE, 'utf8');
|
|
67
|
+
const data: RefCacheFile = JSON.parse(raw);
|
|
68
|
+
if (!data || !Array.isArray(data.refs) || data.targetId !== targetId) return null;
|
|
69
|
+
|
|
70
|
+
const refs = new Map<string, ElementRef>();
|
|
71
|
+
for (const ref of data.refs) {
|
|
72
|
+
if (ref && typeof ref.ref === 'string') refs.set(ref.ref, ref);
|
|
73
|
+
}
|
|
74
|
+
if (refs.size === 0) return null;
|
|
75
|
+
|
|
76
|
+
const ageMs = Date.now() - data.savedAt;
|
|
77
|
+
return { refs, url: data.url, savedAt: data.savedAt, ageMs, stale: ageMs > REF_CACHE_STALE_MS };
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Drop the persisted ref index — call whenever refs are invalidated (navigation, tab switch, close). */
|
|
84
|
+
export async function clearRefCache(): Promise<void> {
|
|
85
|
+
try {
|
|
86
|
+
await rm(CACHE_FILE, { force: true });
|
|
87
|
+
} catch {
|
|
88
|
+
// Nothing to clear, or not writable — non-fatal.
|
|
89
|
+
}
|
|
90
|
+
}
|
|
File without changes
|
package/src/browser/session.ts
CHANGED
|
File without changes
|
package/src/browser/snapshot.ts
CHANGED
|
File without changes
|
package/src/browser/storage.ts
CHANGED
|
File without changes
|
package/src/browser/tabs.ts
CHANGED
|
@@ -25,13 +25,42 @@ export async function activateTab(client: CdpClient, oldSessionId: string, targe
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export async function switchToFrame(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
client: CdpClient,
|
|
29
|
+
sessionId: string,
|
|
30
|
+
frameSelector: string
|
|
31
31
|
): Promise<string | null> {
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const { result } = await client.send<{ result: { result: { value: string | null } } }>(
|
|
33
|
+
'Runtime.evaluate',
|
|
34
|
+
{
|
|
35
|
+
expression: `(() => {
|
|
36
|
+
const el = document.querySelector(${JSON.stringify(frameSelector)});
|
|
37
|
+
if (!el || el.tagName !== 'IFRAME') return null;
|
|
38
|
+
return el.src || null;
|
|
39
|
+
})()`,
|
|
40
|
+
returnByValue: true,
|
|
41
|
+
},
|
|
42
|
+
sessionId
|
|
36
43
|
);
|
|
44
|
+
const frameSrc = result?.result?.value ?? null;
|
|
45
|
+
|
|
46
|
+
const { frameTree } = await client.send<{
|
|
47
|
+
frameTree: { childFrames?: Array<{ frame: { id: string; url: string; securityOrigin: string } }> };
|
|
48
|
+
}>('Page.getFrameTree', {}, sessionId);
|
|
49
|
+
|
|
50
|
+
const match = frameTree.childFrames?.find(
|
|
51
|
+
(cf) => cf.frame.url === frameSrc || cf.frame.id === frameSelector
|
|
52
|
+
);
|
|
53
|
+
if (!match) return frameSrc;
|
|
54
|
+
|
|
55
|
+
const targets = await client.send<{ targetInfos: Array<{ targetId: string; type: string; url: string }> }>(
|
|
56
|
+
'Target.getTargets', {}
|
|
57
|
+
);
|
|
58
|
+
const oopif = targets.targetInfos.find(
|
|
59
|
+
(t) => t.type === 'iframe' && t.url === match.frame.url
|
|
60
|
+
);
|
|
61
|
+
if (oopif) {
|
|
62
|
+
await client.send('Target.attachToTarget', { targetId: oopif.targetId, flatten: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return frameSrc;
|
|
37
66
|
}
|
package/src/browser/trace.ts
CHANGED
|
File without changes
|
package/src/browser/types.ts
CHANGED
|
File without changes
|
package/src/browser/vitals.ts
CHANGED
|
File without changes
|
package/src/browser/wait.ts
CHANGED
|
File without changes
|
package/src/cli/action.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// src/commands/browse-action.ts
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { readdir, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
4
4
|
import { existsSync } from 'node:fs';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import { analyzePageForAction, type AnalyzerPage
|
|
7
|
-
import type { ActionDef } from '../index.js';
|
|
6
|
+
import { analyzePageForAction, type AnalyzerPage } from '../index.js';
|
|
7
|
+
import type { ActionDef, StepDef } from '../index.js';
|
|
8
|
+
|
|
9
|
+
async function readAction(filePath: string): Promise<ActionDef> {
|
|
10
|
+
return JSON.parse(await readFile(filePath, 'utf8')) as ActionDef;
|
|
11
|
+
}
|
|
8
12
|
|
|
9
13
|
// Built-in actions (shipped with the CLI) — actual step definitions live in adapters/
|
|
10
14
|
const BUILTIN_ACTIONS: { id: string; platform: string; name: string }[] = [
|
|
@@ -92,8 +96,90 @@ export function createActionCommand(): Command {
|
|
|
92
96
|
if (eq > 0) params[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
93
97
|
}
|
|
94
98
|
console.log(`Running action: ${actionId} with account: ${opts.account}`);
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
|
|
100
|
+
const custom = await getCustomActions();
|
|
101
|
+
const def = custom.find(a => a.id === actionId);
|
|
102
|
+
if (!def) {
|
|
103
|
+
console.error(`Action not found in custom actions: ${actionId}`);
|
|
104
|
+
console.error('Built-in actions require adapter step definitions — use "action build" to create a custom action.');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const { connectToTarget } = await import('../browser/browser.js');
|
|
109
|
+
const { openUrl } = await import('../browser/browser.js');
|
|
110
|
+
const { clickElement, fillElement, evaluateJs } = await import('../browser/actions.js');
|
|
111
|
+
const { findBySelector } = await import('../browser/find.js');
|
|
112
|
+
const { waitFor } = await import('../browser/wait.js');
|
|
113
|
+
const port = parseInt(process.env.MONOBROWSE_PORT ?? '9222', 10);
|
|
114
|
+
const { client, sessionId } = await connectToTarget(port);
|
|
115
|
+
const refs = new Map<string, import('../browser/types.js').ElementRef>();
|
|
116
|
+
|
|
117
|
+
const interpolate = (s: string) =>
|
|
118
|
+
s.replace(/\{\{(\w+)\}\}/g, (_, k: string) => params[k] ?? `{{${k}}}`);
|
|
119
|
+
|
|
120
|
+
async function runSteps(steps: StepDef[]): Promise<void> {
|
|
121
|
+
for (const step of steps) {
|
|
122
|
+
switch (step.type) {
|
|
123
|
+
case 'navigate':
|
|
124
|
+
await openUrl(client, sessionId, interpolate(step.url));
|
|
125
|
+
console.log(` navigate → ${step.url}`);
|
|
126
|
+
break;
|
|
127
|
+
case 'find': {
|
|
128
|
+
for (const sel of step.selectors) {
|
|
129
|
+
const found = await findBySelector(client, sessionId, refs, interpolate(sel)).catch(() => null);
|
|
130
|
+
if (found) { refs.set(step.as, found); break; }
|
|
131
|
+
}
|
|
132
|
+
console.log(` find → ${step.as}`);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'click': {
|
|
136
|
+
const ref = refs.get(step.target);
|
|
137
|
+
if (!ref) throw new Error(`Element "${step.target}" not found`);
|
|
138
|
+
await clickElement(client, sessionId, ref);
|
|
139
|
+
console.log(` click → ${step.target}`);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case 'type': {
|
|
143
|
+
const ref = refs.get(step.target);
|
|
144
|
+
if (!ref) throw new Error(`Element "${step.target}" not found`);
|
|
145
|
+
await fillElement(client, sessionId, ref, interpolate(step.text));
|
|
146
|
+
console.log(` type → ${step.target}`);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'wait':
|
|
150
|
+
if (step.condition === 'network_idle') {
|
|
151
|
+
await waitFor(client, sessionId, { load: 'networkidle', timeout: step.timeout });
|
|
152
|
+
} else if (step.condition === 'selector' && step.selector) {
|
|
153
|
+
await waitFor(client, sessionId, { selector: step.selector, timeout: step.timeout });
|
|
154
|
+
} else if (step.condition === 'duration') {
|
|
155
|
+
await new Promise(r => setTimeout(r, step.timeout ?? 1000));
|
|
156
|
+
}
|
|
157
|
+
console.log(` wait → ${step.condition}`);
|
|
158
|
+
break;
|
|
159
|
+
case 'extract': {
|
|
160
|
+
const ref = refs.get(step.target);
|
|
161
|
+
if (!ref) throw new Error(`Element "${step.target}" not found`);
|
|
162
|
+
const val = step.attribute
|
|
163
|
+
? await evaluateJs(client, sessionId, `document.querySelector('[data-ref="${ref.ref}"]')?.getAttribute('${step.attribute}')`)
|
|
164
|
+
: await evaluateJs(client, sessionId, `document.querySelector('[data-ref="${ref.ref}"]')?.textContent`);
|
|
165
|
+
console.log(` extract → ${step.as}: ${val}`);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'condition': {
|
|
169
|
+
const result = await evaluateJs(client, sessionId, step.expression);
|
|
170
|
+
if (result) {
|
|
171
|
+
await runSteps(step.then);
|
|
172
|
+
} else if (step.else) {
|
|
173
|
+
await runSteps(step.else);
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
await runSteps(def.steps);
|
|
182
|
+
console.log(`\nAction ${actionId} completed successfully.`);
|
|
97
183
|
});
|
|
98
184
|
|
|
99
185
|
cmd
|
package/src/cli/commands.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import type { Command, CommandContext, CommandResult } from './types.js';
|
|
7
7
|
import { output } from './output.js';
|
|
8
|
-
import { createPlaybookCommand } from './playbook.js';
|
|
9
8
|
import { createActionCommand } from './action.js';
|
|
10
9
|
import { createPlatformCommand } from './platform.js';
|
|
11
10
|
import type { CdpClient, ElementRef, NetworkRoute, FindAction } from '../index.js';
|
|
@@ -37,10 +36,27 @@ async function ensureConnected(port: number, targetId?: string) {
|
|
|
37
36
|
_sessionId = conn.sessionId;
|
|
38
37
|
_targetId = conn.target.id;
|
|
39
38
|
_refs = new Map();
|
|
39
|
+
await hydrateRefsFromCache(browser, _targetId);
|
|
40
40
|
}
|
|
41
41
|
return { client: _client!, sessionId: _sessionId, targetId: _targetId };
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// Each CLI invocation is a fresh process, so the in-memory _refs Map built by
|
|
45
|
+
// a prior `snapshot` command is gone by the time a later `find`/`click`/etc.
|
|
46
|
+
// command runs. Rehydrate it from the on-disk ref cache (written by
|
|
47
|
+
// captureSnapshot call sites below) so refs resolved by a previous process
|
|
48
|
+
// remain usable. Falls back silently to an empty Map if no cache exists.
|
|
49
|
+
async function hydrateRefsFromCache(browser: Awaited<ReturnType<typeof getBrowser>>, targetId: string): Promise<void> {
|
|
50
|
+
const cached = await browser.loadRefCache(targetId);
|
|
51
|
+
if (!cached) return;
|
|
52
|
+
_refs = cached.refs;
|
|
53
|
+
if (cached.stale) {
|
|
54
|
+
output.printWarning(
|
|
55
|
+
`AX ref cache is ${Math.round(cached.ageMs / 1000)}s old — page may have changed since the last snapshot; re-run snapshot if refs don't resolve as expected`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
// URL patterns that signal an unambiguous login/auth wall.
|
|
45
61
|
// Excludes 'auth', 'oauth', 'sso', 'saml' — their callback/ACS/token paths
|
|
46
62
|
// (/auth/callback, /sso/callback, /saml/acs) are completion endpoints, not walls.
|
|
@@ -155,6 +171,18 @@ async function switchToHeaded(url: string, port: number): Promise<void> {
|
|
|
155
171
|
}
|
|
156
172
|
}
|
|
157
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Sanitize an image-format flag. The host CLI (monomind) defines a GLOBAL
|
|
176
|
+
* --format flag for output shaping (text|json|table, default 'text') that
|
|
177
|
+
* leaks into subcommand flags — so ctx.flags.format arrives as 'text' even
|
|
178
|
+
* when the user never passed it, and Chrome rejects it with
|
|
179
|
+
* "CDP error -32602: Invalid image format". Only trust values that are real
|
|
180
|
+
* image formats; otherwise fall back to the subcommand's own default.
|
|
181
|
+
*/
|
|
182
|
+
function imageFormat<T extends string>(value: unknown, allowed: readonly T[], fallback: T): T {
|
|
183
|
+
return allowed.includes(value as T) ? (value as T) : fallback;
|
|
184
|
+
}
|
|
185
|
+
|
|
158
186
|
function print(msg: string) {
|
|
159
187
|
process.stdout.write(msg + '\n');
|
|
160
188
|
}
|
|
@@ -267,6 +295,7 @@ const snapshotCommand: Command = {
|
|
|
267
295
|
});
|
|
268
296
|
|
|
269
297
|
_refs = result.refs;
|
|
298
|
+
await browser.saveRefCache(_targetId, result.url, _refs);
|
|
270
299
|
|
|
271
300
|
const applyOutputLimits = (text: string): string => {
|
|
272
301
|
let out = text;
|
|
@@ -546,7 +575,7 @@ const screenshotCommand: Command = {
|
|
|
546
575
|
result = await browser.captureScreenshot(client, sessionId, {
|
|
547
576
|
path: ctx.args[0] as string,
|
|
548
577
|
fullPage: ctx.flags.full as boolean,
|
|
549
|
-
format: ctx.flags.format
|
|
578
|
+
format: imageFormat(ctx.flags.format, ['png', 'jpeg', 'webp'] as const, 'png'),
|
|
550
579
|
quality: ctx.flags.quality as number,
|
|
551
580
|
annotate,
|
|
552
581
|
refs: annotate ? _refs : undefined,
|
|
@@ -919,6 +948,7 @@ const stateCommand: Command = {
|
|
|
919
948
|
await browser.clearLocalStorage(c, sid);
|
|
920
949
|
await browser.clearSessionStorage(c, sid);
|
|
921
950
|
_refs = new Map();
|
|
951
|
+
await browser.clearRefCache();
|
|
922
952
|
output.printSuccess('Browser state cleared (cookies, localStorage, sessionStorage, refs)');
|
|
923
953
|
return { success: true };
|
|
924
954
|
}
|
|
@@ -2229,6 +2259,7 @@ const diffCommand: Command = {
|
|
|
2229
2259
|
const snap2 = await browser.captureSnapshot(client, sessionId, { interactiveOnly: ctx.flags.interactive as boolean });
|
|
2230
2260
|
|
|
2231
2261
|
_refs = snap2.refs;
|
|
2262
|
+
await browser.saveRefCache(_targetId, snap2.url, _refs);
|
|
2232
2263
|
|
|
2233
2264
|
// Text diff
|
|
2234
2265
|
const lines1 = snap1.text.split('\n');
|
|
@@ -2497,7 +2528,7 @@ const recordCommand: Command = {
|
|
|
2497
2528
|
switch (action) {
|
|
2498
2529
|
case 'start':
|
|
2499
2530
|
await browser.startRecording(client, sessionId, {
|
|
2500
|
-
format: ctx.flags.format
|
|
2531
|
+
format: imageFormat(ctx.flags.format, ['jpeg', 'png'] as const, 'jpeg'),
|
|
2501
2532
|
quality: ctx.flags.quality as number,
|
|
2502
2533
|
});
|
|
2503
2534
|
output.printSuccess('Recording started');
|
|
@@ -2516,7 +2547,7 @@ const recordCommand: Command = {
|
|
|
2516
2547
|
output.printInfo(`Previous recording saved: ${prevPath}`);
|
|
2517
2548
|
}
|
|
2518
2549
|
await browser.startRecording(client, sessionId, {
|
|
2519
|
-
format: ctx.flags.format
|
|
2550
|
+
format: imageFormat(ctx.flags.format, ['jpeg', 'png'] as const, 'jpeg'),
|
|
2520
2551
|
quality: ctx.flags.quality as number,
|
|
2521
2552
|
});
|
|
2522
2553
|
output.printSuccess('Recording restarted');
|
|
@@ -2734,7 +2765,6 @@ function wrapCommanderCommand(factory: () => import('commander').Command): Comma
|
|
|
2734
2765
|
};
|
|
2735
2766
|
}
|
|
2736
2767
|
|
|
2737
|
-
const playbookSubcommand: Command = wrapCommanderCommand(createPlaybookCommand);
|
|
2738
2768
|
const actionSubcommand: Command = wrapCommanderCommand(createActionCommand);
|
|
2739
2769
|
const platformSubcommand: Command = wrapCommanderCommand(createPlatformCommand);
|
|
2740
2770
|
|
|
@@ -2806,7 +2836,6 @@ const browseCommand: Command = {
|
|
|
2806
2836
|
harCommand,
|
|
2807
2837
|
resizeCommand,
|
|
2808
2838
|
closeCommand,
|
|
2809
|
-
playbookSubcommand,
|
|
2810
2839
|
actionSubcommand,
|
|
2811
2840
|
platformSubcommand,
|
|
2812
2841
|
],
|
package/src/cli/output.ts
CHANGED
|
File without changes
|
package/src/cli/platform.ts
CHANGED
|
File without changes
|
package/src/cli/types.ts
CHANGED
|
File without changes
|
package/src/cli.ts
CHANGED
|
File without changes
|
package/src/index.ts
CHANGED
|
@@ -1,25 +1,5 @@
|
|
|
1
|
-
// Re-export the full monoplaybook engine so consumers only need @monoes/monobrowse
|
|
2
|
-
export * from '@monoes/monoplaybook';
|
|
3
|
-
|
|
4
1
|
export * from './browser/index.js';
|
|
5
2
|
export * from './browser/action-builder/analyzer.js';
|
|
6
3
|
export * from './browser/action-builder/types.js';
|
|
7
4
|
export * from './browser/adapters/index.js';
|
|
8
5
|
export { startDashboard, getDashboard } from './browser/dashboard/server.js';
|
|
9
|
-
export { createBuiltinHandlers, createBrowserHandlers } from './browser/playbook/index.js';
|
|
10
|
-
export { readAction } from './browser/playbook/store.js';
|
|
11
|
-
|
|
12
|
-
// Batteries-included handler factory: service nodes + browser automation + builtins.
|
|
13
|
-
// This is the recommended entry point when using monobrowse as the default executor.
|
|
14
|
-
import { createNodeHandlers } from '@monoes/monoplaybook';
|
|
15
|
-
import { createBrowserHandlers } from './browser/playbook/browser-handlers.js';
|
|
16
|
-
import { createBuiltinHandlers } from './browser/playbook/builtin-handlers.js';
|
|
17
|
-
import type { NodeHandler } from '@monoes/monoplaybook';
|
|
18
|
-
|
|
19
|
-
export function createDefaultHandlers(): Map<string, NodeHandler> {
|
|
20
|
-
return new Map<string, NodeHandler>([
|
|
21
|
-
...createNodeHandlers(),
|
|
22
|
-
...createBrowserHandlers(),
|
|
23
|
-
...createBuiltinHandlers(),
|
|
24
|
-
]);
|
|
25
|
-
}
|
package/dist/package.json
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@monoes/monobrowse",
|
|
3
|
-
"version": "1.0.1",
|
|
4
|
-
"description": "Native browser automation via Chrome DevTools Protocol — the engine powering monomind browse",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"monobrowse": "./dist/src/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"main": "./dist/src/index.js",
|
|
10
|
-
"types": "./dist/src/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/src/index.d.ts",
|
|
14
|
-
"import": "./dist/src/index.js"
|
|
15
|
-
},
|
|
16
|
-
"./cli": {
|
|
17
|
-
"types": "./dist/src/cli.d.ts",
|
|
18
|
-
"import": "./dist/src/cli.js"
|
|
19
|
-
},
|
|
20
|
-
"./cli/commands": {
|
|
21
|
-
"types": "./dist/src/cli/commands.d.ts",
|
|
22
|
-
"import": "./dist/src/cli/commands.js"
|
|
23
|
-
},
|
|
24
|
-
"./cli/types": {
|
|
25
|
-
"types": "./dist/src/cli/types.d.ts",
|
|
26
|
-
"import": "./dist/src/cli/types.js"
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"files": [
|
|
30
|
-
"dist",
|
|
31
|
-
"src"
|
|
32
|
-
],
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">=18.0.0"
|
|
35
|
-
},
|
|
36
|
-
"scripts": {
|
|
37
|
-
"build": "tsc && mkdir -p dist/src/browser/dashboard && cp src/browser/dashboard/ui.html dist/src/browser/dashboard/ui.html",
|
|
38
|
-
"prepublishOnly": "npm run build"
|
|
39
|
-
},
|
|
40
|
-
"keywords": [
|
|
41
|
-
"browser-automation",
|
|
42
|
-
"cdp",
|
|
43
|
-
"chrome-devtools-protocol",
|
|
44
|
-
"monomind",
|
|
45
|
-
"web-scraping",
|
|
46
|
-
"accessibility"
|
|
47
|
-
],
|
|
48
|
-
"author": {
|
|
49
|
-
"name": "nokhodian",
|
|
50
|
-
"email": "nokhodian@gmail.com",
|
|
51
|
-
"url": "https://github.com/nokhodian"
|
|
52
|
-
},
|
|
53
|
-
"license": "MIT",
|
|
54
|
-
"repository": {
|
|
55
|
-
"type": "git",
|
|
56
|
-
"url": "https://github.com/monoes/monomind.git",
|
|
57
|
-
"directory": "packages/@monoes/monobrowse"
|
|
58
|
-
},
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"commander": "^12.1.0",
|
|
61
|
-
"ws": "^8.21.0"
|
|
62
|
-
},
|
|
63
|
-
"peerDependencies": {
|
|
64
|
-
"@anthropic-ai/sdk": ">=0.20.0"
|
|
65
|
-
},
|
|
66
|
-
"peerDependenciesMeta": {
|
|
67
|
-
"@anthropic-ai/sdk": {
|
|
68
|
-
"optional": true
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
"devDependencies": {
|
|
72
|
-
"@anthropic-ai/sdk": "^0.39.0",
|
|
73
|
-
"typescript": "^5.8.3"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browser-handlers.d.ts","sourceRoot":"","sources":["../../../../src/browser/playbook/browser-handlers.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAQ,MAAM,sBAAsB,CAAC;AAkI9D,wBAAgB,qBAAqB,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CA2ShE"}
|