@monoes/monobrowse 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/dist/src/browser/action-builder/analyzer.d.ts +11 -0
  2. package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -0
  3. package/dist/src/browser/action-builder/analyzer.js +93 -0
  4. package/dist/src/browser/action-builder/analyzer.js.map +1 -0
  5. package/dist/src/browser/action-builder/types.d.ts +46 -0
  6. package/dist/src/browser/action-builder/types.d.ts.map +1 -0
  7. package/dist/src/browser/action-builder/types.js +2 -0
  8. package/dist/src/browser/action-builder/types.js.map +1 -0
  9. package/dist/src/browser/actions.d.ts +29 -0
  10. package/dist/src/browser/actions.d.ts.map +1 -0
  11. package/dist/src/browser/actions.js +398 -0
  12. package/dist/src/browser/actions.js.map +1 -0
  13. package/dist/src/browser/adapters/gemini.d.ts +3 -0
  14. package/dist/src/browser/adapters/gemini.d.ts.map +1 -0
  15. package/dist/src/browser/adapters/gemini.js +13 -0
  16. package/dist/src/browser/adapters/gemini.js.map +1 -0
  17. package/dist/src/browser/adapters/google.d.ts +3 -0
  18. package/dist/src/browser/adapters/google.d.ts.map +1 -0
  19. package/dist/src/browser/adapters/google.js +17 -0
  20. package/dist/src/browser/adapters/google.js.map +1 -0
  21. package/dist/src/browser/adapters/index.d.ts +15 -0
  22. package/dist/src/browser/adapters/index.d.ts.map +1 -0
  23. package/dist/src/browser/adapters/index.js +18 -0
  24. package/dist/src/browser/adapters/index.js.map +1 -0
  25. package/dist/src/browser/adapters/instagram.d.ts +3 -0
  26. package/dist/src/browser/adapters/instagram.d.ts.map +1 -0
  27. package/dist/src/browser/adapters/instagram.js +14 -0
  28. package/dist/src/browser/adapters/instagram.js.map +1 -0
  29. package/dist/src/browser/adapters/linkedin.d.ts +3 -0
  30. package/dist/src/browser/adapters/linkedin.d.ts.map +1 -0
  31. package/dist/src/browser/adapters/linkedin.js +13 -0
  32. package/dist/src/browser/adapters/linkedin.js.map +1 -0
  33. package/dist/src/browser/adapters/microsoft.d.ts +3 -0
  34. package/dist/src/browser/adapters/microsoft.d.ts.map +1 -0
  35. package/dist/src/browser/adapters/microsoft.js +16 -0
  36. package/dist/src/browser/adapters/microsoft.js.map +1 -0
  37. package/dist/src/browser/adapters/x.d.ts +3 -0
  38. package/dist/src/browser/adapters/x.d.ts.map +1 -0
  39. package/dist/src/browser/adapters/x.js +13 -0
  40. package/dist/src/browser/adapters/x.js.map +1 -0
  41. package/dist/src/browser/batch.d.ts +5 -0
  42. package/dist/src/browser/batch.d.ts.map +1 -0
  43. package/dist/src/browser/batch.js +2 -0
  44. package/dist/src/browser/batch.js.map +1 -0
  45. package/dist/src/browser/browser.d.ts +15 -0
  46. package/dist/src/browser/browser.d.ts.map +1 -0
  47. package/dist/src/browser/browser.js +256 -0
  48. package/dist/src/browser/browser.js.map +1 -0
  49. package/dist/src/browser/cdp.d.ts +18 -0
  50. package/dist/src/browser/cdp.d.ts.map +1 -0
  51. package/dist/src/browser/cdp.js +153 -0
  52. package/dist/src/browser/cdp.js.map +1 -0
  53. package/dist/src/browser/console-log.d.ts +23 -0
  54. package/dist/src/browser/console-log.d.ts.map +1 -0
  55. package/dist/src/browser/console-log.js +104 -0
  56. package/dist/src/browser/console-log.js.map +1 -0
  57. package/dist/src/browser/dashboard/api-types.d.ts +50 -0
  58. package/dist/src/browser/dashboard/api-types.d.ts.map +1 -0
  59. package/dist/src/browser/dashboard/api-types.js +14 -0
  60. package/dist/src/browser/dashboard/api-types.js.map +1 -0
  61. package/dist/src/browser/dashboard/server.d.ts +11 -0
  62. package/dist/src/browser/dashboard/server.d.ts.map +1 -0
  63. package/dist/src/browser/dashboard/server.js +191 -0
  64. package/dist/src/browser/dashboard/server.js.map +1 -0
  65. package/dist/src/browser/dialog.d.ts +12 -0
  66. package/dist/src/browser/dialog.d.ts.map +1 -0
  67. package/dist/src/browser/dialog.js +53 -0
  68. package/dist/src/browser/dialog.js.map +1 -0
  69. package/dist/src/browser/emulation.d.ts +15 -0
  70. package/dist/src/browser/emulation.d.ts.map +1 -0
  71. package/dist/src/browser/emulation.js +62 -0
  72. package/dist/src/browser/emulation.js.map +1 -0
  73. package/dist/src/browser/find.d.ts +22 -0
  74. package/dist/src/browser/find.d.ts.map +1 -0
  75. package/dist/src/browser/find.js +169 -0
  76. package/dist/src/browser/find.js.map +1 -0
  77. package/dist/src/browser/har.d.ts +27 -0
  78. package/dist/src/browser/har.d.ts.map +1 -0
  79. package/dist/src/browser/har.js +161 -0
  80. package/dist/src/browser/har.js.map +1 -0
  81. package/dist/src/browser/index.d.ts +23 -0
  82. package/dist/src/browser/index.d.ts.map +1 -0
  83. package/dist/src/browser/index.js +23 -0
  84. package/dist/src/browser/index.js.map +1 -0
  85. package/dist/src/browser/network.d.ts +32 -0
  86. package/dist/src/browser/network.d.ts.map +1 -0
  87. package/dist/src/browser/network.js +214 -0
  88. package/dist/src/browser/network.js.map +1 -0
  89. package/dist/src/browser/pdf.d.ts +15 -0
  90. package/dist/src/browser/pdf.d.ts.map +1 -0
  91. package/dist/src/browser/pdf.js +27 -0
  92. package/dist/src/browser/pdf.js.map +1 -0
  93. package/dist/src/browser/profiler.d.ts +10 -0
  94. package/dist/src/browser/profiler.d.ts.map +1 -0
  95. package/dist/src/browser/profiler.js +77 -0
  96. package/dist/src/browser/profiler.js.map +1 -0
  97. package/dist/src/browser/record.d.ts +21 -0
  98. package/dist/src/browser/record.d.ts.map +1 -0
  99. package/dist/src/browser/record.js +59 -0
  100. package/dist/src/browser/record.js.map +1 -0
  101. package/dist/src/browser/screenshot.d.ts +15 -0
  102. package/dist/src/browser/screenshot.d.ts.map +1 -0
  103. package/dist/src/browser/screenshot.js +38 -0
  104. package/dist/src/browser/screenshot.js.map +1 -0
  105. package/dist/src/browser/session.d.ts +8 -0
  106. package/dist/src/browser/session.d.ts.map +1 -0
  107. package/dist/src/browser/session.js +91 -0
  108. package/dist/src/browser/session.js.map +1 -0
  109. package/dist/src/browser/snapshot.d.ts +12 -0
  110. package/dist/src/browser/snapshot.d.ts.map +1 -0
  111. package/dist/src/browser/snapshot.js +179 -0
  112. package/dist/src/browser/snapshot.js.map +1 -0
  113. package/dist/src/browser/storage.d.ts +12 -0
  114. package/dist/src/browser/storage.d.ts.map +1 -0
  115. package/dist/src/browser/storage.js +46 -0
  116. package/dist/src/browser/storage.js.map +1 -0
  117. package/dist/src/browser/tabs.d.ts +8 -0
  118. package/dist/src/browser/tabs.d.ts.map +1 -0
  119. package/dist/src/browser/tabs.js +25 -0
  120. package/dist/src/browser/tabs.js.map +1 -0
  121. package/dist/src/browser/trace.d.ts +10 -0
  122. package/dist/src/browser/trace.d.ts.map +1 -0
  123. package/dist/src/browser/trace.js +87 -0
  124. package/dist/src/browser/trace.js.map +1 -0
  125. package/dist/src/browser/types.d.ts +111 -0
  126. package/dist/src/browser/types.d.ts.map +1 -0
  127. package/dist/src/browser/types.js +16 -0
  128. package/dist/src/browser/types.js.map +1 -0
  129. package/dist/src/browser/vitals.d.ts +15 -0
  130. package/dist/src/browser/vitals.d.ts.map +1 -0
  131. package/dist/src/browser/vitals.js +116 -0
  132. package/dist/src/browser/vitals.js.map +1 -0
  133. package/dist/src/browser/wait.d.ts +4 -0
  134. package/dist/src/browser/wait.d.ts.map +1 -0
  135. package/dist/src/browser/wait.js +146 -0
  136. package/dist/src/browser/wait.js.map +1 -0
  137. package/dist/src/browser/workflow/builtin-handlers.d.ts +3 -0
  138. package/dist/src/browser/workflow/builtin-handlers.d.ts.map +1 -0
  139. package/dist/src/browser/workflow/builtin-handlers.js +343 -0
  140. package/dist/src/browser/workflow/builtin-handlers.js.map +1 -0
  141. package/dist/src/browser/workflow/engine.d.ts +10 -0
  142. package/dist/src/browser/workflow/engine.d.ts.map +1 -0
  143. package/dist/src/browser/workflow/engine.js +174 -0
  144. package/dist/src/browser/workflow/engine.js.map +1 -0
  145. package/dist/src/browser/workflow/expression.d.ts +4 -0
  146. package/dist/src/browser/workflow/expression.d.ts.map +1 -0
  147. package/dist/src/browser/workflow/expression.js +89 -0
  148. package/dist/src/browser/workflow/expression.js.map +1 -0
  149. package/dist/src/browser/workflow/index.d.ts +6 -0
  150. package/dist/src/browser/workflow/index.d.ts.map +1 -0
  151. package/dist/src/browser/workflow/index.js +6 -0
  152. package/dist/src/browser/workflow/index.js.map +1 -0
  153. package/dist/src/browser/workflow/store.d.ts +8 -0
  154. package/dist/src/browser/workflow/store.d.ts.map +1 -0
  155. package/dist/src/browser/workflow/store.js +87 -0
  156. package/dist/src/browser/workflow/store.js.map +1 -0
  157. package/dist/src/browser/workflow/types.d.ts +62 -0
  158. package/dist/src/browser/workflow/types.d.ts.map +1 -0
  159. package/dist/src/browser/workflow/types.js +2 -0
  160. package/dist/src/browser/workflow/types.js.map +1 -0
  161. package/dist/src/index.d.ts +7 -0
  162. package/dist/src/index.d.ts.map +1 -0
  163. package/dist/src/index.js +7 -0
  164. package/dist/src/index.js.map +1 -0
  165. package/dist/tsconfig.tsbuildinfo +1 -0
  166. package/package.json +56 -0
  167. package/src/browser/action-builder/analyzer.ts +127 -0
  168. package/src/browser/action-builder/types.ts +17 -0
  169. package/src/browser/actions.ts +518 -0
  170. package/src/browser/adapters/gemini.ts +15 -0
  171. package/src/browser/adapters/google.ts +20 -0
  172. package/src/browser/adapters/index.ts +33 -0
  173. package/src/browser/adapters/instagram.ts +16 -0
  174. package/src/browser/adapters/linkedin.ts +15 -0
  175. package/src/browser/adapters/microsoft.ts +19 -0
  176. package/src/browser/adapters/x.ts +15 -0
  177. package/src/browser/batch.ts +4 -0
  178. package/src/browser/browser.ts +265 -0
  179. package/src/browser/cdp.ts +156 -0
  180. package/src/browser/console-log.ts +120 -0
  181. package/src/browser/dashboard/api-types.ts +71 -0
  182. package/src/browser/dashboard/server.ts +206 -0
  183. package/src/browser/dashboard/ui.html +444 -0
  184. package/src/browser/dialog.ts +63 -0
  185. package/src/browser/emulation.ts +94 -0
  186. package/src/browser/find.ts +225 -0
  187. package/src/browser/har.ts +202 -0
  188. package/src/browser/index.ts +22 -0
  189. package/src/browser/network.ts +244 -0
  190. package/src/browser/pdf.ts +41 -0
  191. package/src/browser/profiler.ts +96 -0
  192. package/src/browser/record.ts +92 -0
  193. package/src/browser/screenshot.ts +67 -0
  194. package/src/browser/session.ts +118 -0
  195. package/src/browser/snapshot.ts +248 -0
  196. package/src/browser/storage.ts +54 -0
  197. package/src/browser/tabs.ts +37 -0
  198. package/src/browser/trace.ts +106 -0
  199. package/src/browser/types.ts +135 -0
  200. package/src/browser/vitals.ts +122 -0
  201. package/src/browser/wait.ts +178 -0
  202. package/src/browser/workflow/builtin-handlers.ts +379 -0
  203. package/src/browser/workflow/engine.ts +202 -0
  204. package/src/browser/workflow/expression.ts +107 -0
  205. package/src/browser/workflow/index.ts +5 -0
  206. package/src/browser/workflow/store.ts +87 -0
  207. package/src/browser/workflow/types.ts +62 -0
  208. package/src/index.ts +6 -0
@@ -0,0 +1,11 @@
1
+ import type { ActionDef } from './types.js';
2
+ export interface AnalyzerPage {
3
+ evaluate<T>(expression: string): Promise<T>;
4
+ url(): Promise<string>;
5
+ }
6
+ export interface AnalyzerOptions {
7
+ apiKey?: string;
8
+ model?: string;
9
+ }
10
+ export declare function analyzePageForAction(page: AnalyzerPage, task: string, options?: AnalyzerOptions): Promise<ActionDef>;
11
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../../src/browser/action-builder/analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwDD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,SAAS,CAAC,CAqDpB"}
@@ -0,0 +1,93 @@
1
+ // src/browser/action-builder/analyzer.ts
2
+ import Anthropic from '@anthropic-ai/sdk';
3
+ const MODEL_DEFAULTS = { sonnet: 'claude-sonnet-4-6' };
4
+ const DOM_CAPTURE_EXPR = `
5
+ JSON.stringify(
6
+ Array.from(document.querySelectorAll('button,input,a,textarea,[role="button"]'))
7
+ .slice(0, 100)
8
+ .map(el => ({
9
+ tag: el.tagName.toLowerCase(),
10
+ text: el.textContent?.trim().slice(0, 80) ?? '',
11
+ attrs: {
12
+ id: el.id || undefined,
13
+ name: el.getAttribute('name') || undefined,
14
+ ariaLabel: el.getAttribute('aria-label') || undefined,
15
+ type: el.getAttribute('type') || undefined,
16
+ href: el.tagName === 'A' ? (el.getAttribute('href') || undefined) : undefined
17
+ }
18
+ }))
19
+ )`;
20
+ const SYSTEM_PROMPT = `You are an expert browser automation engineer. Given a webpage's interactive elements and a task description, generate a browser automation ActionDef JSON.
21
+
22
+ Rules:
23
+ - Output ONLY valid JSON matching the ActionDef schema, no markdown, no explanation
24
+ - Use multi-selector find steps: provide CSS selector, aria-label selector, and XPath as fallbacks
25
+ - Use {{params.param_name}} for dynamic values the caller will provide
26
+ - Steps must be executable in order
27
+
28
+ ActionDef schema:
29
+ {
30
+ "id": "<platform>:<action_name>",
31
+ "platform": "<platform>",
32
+ "name": "<human readable>",
33
+ "params": ["param1", "param2"],
34
+ "steps": [
35
+ { "type": "navigate", "url": "{{params.url}}" },
36
+ { "type": "find", "selectors": ["css-selector", "[aria-label='...']", "//xpath"], "as": "element_name" },
37
+ { "type": "click", "target": "{{element_name}}" },
38
+ { "type": "type", "target": "{{element_name}}", "text": "{{params.text}}", "humanDelay": true },
39
+ { "type": "wait", "condition": "network_idle", "timeout": 3000 },
40
+ { "type": "extract", "target": "{{element_name}}", "as": "result" },
41
+ { "type": "condition", "expression": "{{extracted_value}}", "then": [...steps], "else": [...steps] }
42
+ ]
43
+ }`;
44
+ export async function analyzePageForAction(page, task, options = {}) {
45
+ const url = await page.url();
46
+ const title = await page.evaluate('document.title');
47
+ const elementsJson = await page.evaluate(DOM_CAPTURE_EXPR);
48
+ let elements = [];
49
+ try {
50
+ elements = JSON.parse(elementsJson);
51
+ }
52
+ catch {
53
+ elements = [];
54
+ }
55
+ const domContext = `URL: ${url}
56
+ Title: ${title}
57
+ Interactive elements (${elements.length}):
58
+ ${elements.map((el, i) => {
59
+ const attrs = Object.entries(el.attrs)
60
+ .filter(([, v]) => v)
61
+ .map(([k, v]) => `${k}="${v}"`)
62
+ .join(' ');
63
+ return `${i + 1}. <${el.tag}${attrs ? ' ' + attrs : ''}>${el.text}</${el.tag}>`;
64
+ }).join('\n')}`;
65
+ const client = new Anthropic({ apiKey: options.apiKey ?? process.env['ANTHROPIC_API_KEY'] });
66
+ const model = options.model ?? MODEL_DEFAULTS.sonnet;
67
+ const message = await client.messages.create({
68
+ model,
69
+ max_tokens: 2048,
70
+ system: SYSTEM_PROMPT,
71
+ messages: [
72
+ {
73
+ role: 'user',
74
+ content: `Task: ${task}\n\nPage context:\n${domContext}`,
75
+ },
76
+ ],
77
+ });
78
+ const content = message.content[0];
79
+ if (content.type !== 'text')
80
+ throw new Error('Claude returned non-text response');
81
+ let actionDef;
82
+ try {
83
+ actionDef = JSON.parse(content.text);
84
+ }
85
+ catch {
86
+ throw new Error(`Claude returned invalid JSON:\n${content.text.slice(0, 500)}`);
87
+ }
88
+ if (!actionDef.id || !actionDef.steps || !Array.isArray(actionDef.steps)) {
89
+ throw new Error(`Claude returned invalid ActionDef: missing id or steps\n${content.text.slice(0, 500)}`);
90
+ }
91
+ return actionDef;
92
+ }
93
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../../src/browser/action-builder/analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ export interface NavigateStep {
2
+ type: 'navigate';
3
+ url: string;
4
+ }
5
+ export interface FindStep {
6
+ type: 'find';
7
+ selectors: string[];
8
+ as: string;
9
+ }
10
+ export interface ClickStep {
11
+ type: 'click';
12
+ target: string;
13
+ }
14
+ export interface TypeStep {
15
+ type: 'type';
16
+ target: string;
17
+ text: string;
18
+ humanDelay?: boolean;
19
+ }
20
+ export interface WaitStep {
21
+ type: 'wait';
22
+ condition: 'network_idle' | 'selector' | 'duration';
23
+ timeout?: number;
24
+ selector?: string;
25
+ }
26
+ export interface ExtractStep {
27
+ type: 'extract';
28
+ target: string;
29
+ as: string;
30
+ attribute?: string;
31
+ }
32
+ export interface ConditionStep {
33
+ type: 'condition';
34
+ expression: string;
35
+ then: StepDef[];
36
+ else?: StepDef[];
37
+ }
38
+ export type StepDef = NavigateStep | FindStep | ClickStep | TypeStep | WaitStep | ExtractStep | ConditionStep;
39
+ export interface ActionDef {
40
+ id: string;
41
+ platform: string;
42
+ name: string;
43
+ params: string[];
44
+ steps: StepDef[];
45
+ }
46
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/browser/action-builder/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;CAAE;AAChE,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;CAAE;AAC5E,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;CAAE;AAC7D,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAAE;AAC/F,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,cAAc,GAAG,UAAU,GAAG,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAAE;AACrI,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAAE;AACjG,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CAAE;AAE5G,MAAM,MAAM,OAAO,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAAC;AAE9G,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/browser/action-builder/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import type { CdpClient } from './cdp.js';
2
+ import type { ElementRef, ClickOptions } from './types.js';
3
+ export declare function clickElement(client: CdpClient, sessionId: string, ref: ElementRef, options?: ClickOptions): Promise<void>;
4
+ export declare function clickPoint(client: CdpClient, sessionId: string, x: number, y: number, options?: ClickOptions): Promise<void>;
5
+ export declare function fillElement(client: CdpClient, sessionId: string, ref: ElementRef, value: string): Promise<void>;
6
+ export declare function typeText(client: CdpClient, sessionId: string, text: string): Promise<void>;
7
+ export declare function pressKeyCombo(client: CdpClient, sessionId: string, key: string, modifiers: number): Promise<void>;
8
+ export declare function pressKey(client: CdpClient, sessionId: string, key: string): Promise<void>;
9
+ export declare function scrollElement(client: CdpClient, sessionId: string, direction: 'up' | 'down' | 'left' | 'right', amount?: number, ref?: ElementRef): Promise<void>;
10
+ export declare function hoverElement(client: CdpClient, sessionId: string, ref: ElementRef): Promise<void>;
11
+ export declare function selectOption(client: CdpClient, sessionId: string, ref: ElementRef, value: string): Promise<void>;
12
+ export declare function checkElement(client: CdpClient, sessionId: string, ref: ElementRef, checked?: boolean): Promise<void>;
13
+ export declare function focusElement(client: CdpClient, sessionId: string, ref: ElementRef): Promise<void>;
14
+ export declare function typeIntoElement(client: CdpClient, sessionId: string, ref: ElementRef, text: string): Promise<void>;
15
+ export declare function keyDown(client: CdpClient, sessionId: string, key: string): Promise<void>;
16
+ export declare function keyUp(client: CdpClient, sessionId: string, key: string): Promise<void>;
17
+ export declare function mouseMove(client: CdpClient, sessionId: string, x: number, y: number): Promise<void>;
18
+ export declare function mouseDown(client: CdpClient, sessionId: string, x: number, y: number, button?: 'left' | 'right' | 'middle'): Promise<void>;
19
+ export declare function mouseUp(client: CdpClient, sessionId: string, x: number, y: number, button?: 'left' | 'right' | 'middle'): Promise<void>;
20
+ export declare function mouseWheel(client: CdpClient, sessionId: string, x: number, y: number, deltaY: number, deltaX?: number): Promise<void>;
21
+ export declare function dragAndDrop(client: CdpClient, sessionId: string, src: ElementRef, tgt: ElementRef): Promise<void>;
22
+ export declare function uploadFile(client: CdpClient, sessionId: string, ref: ElementRef, filePaths: string[]): Promise<void>;
23
+ export declare function readClipboard(client: CdpClient, sessionId: string): Promise<string>;
24
+ export declare function writeClipboard(client: CdpClient, sessionId: string, text: string): Promise<void>;
25
+ export declare function pushState(client: CdpClient, sessionId: string, url: string): Promise<void>;
26
+ export declare function addInitScript(client: CdpClient, sessionId: string, script: string): Promise<string>;
27
+ export declare function removeInitScript(client: CdpClient, sessionId: string, identifier: string): Promise<void>;
28
+ export declare function evaluateJs(client: CdpClient, sessionId: string, expression: string): Promise<unknown>;
29
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/browser/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,398 @@
1
+ import { resolve } from 'path';
2
+ import { getObjectIdForRef, getElementBox } from './snapshot.js';
3
+ export async function clickElement(client, sessionId, ref, options = {}) {
4
+ const box = await getElementBox(client, sessionId, ref);
5
+ if (box) {
6
+ await clickPoint(client, sessionId, box.x, box.y, options);
7
+ return;
8
+ }
9
+ // Fallback: use JS click via objectId
10
+ const objectId = await getObjectIdForRef(client, sessionId, ref);
11
+ if (objectId) {
12
+ await client.send('Runtime.callFunctionOn', {
13
+ functionDeclaration: 'function() { this.click(); }',
14
+ objectId,
15
+ returnByValue: true,
16
+ }, sessionId);
17
+ return;
18
+ }
19
+ throw new Error(`Cannot click ref @${ref.ref}: element not found in DOM`);
20
+ }
21
+ export async function clickPoint(client, sessionId, x, y, options = {}) {
22
+ const button = options.button ?? 'left';
23
+ // Cap clickCount to prevent unbounded loop DoS
24
+ const clickCount = Math.min(Math.max(1, Math.floor(options.clickCount ?? 1)), 100);
25
+ const modifiers = options.modifiers ?? 0;
26
+ const shared = { x, y, button, modifiers };
27
+ const buttonsMask = button === 'right' ? 2 : button === 'middle' ? 4 : 1;
28
+ for (let i = 0; i < clickCount; i++) {
29
+ const count = i + 1;
30
+ await client.send('Input.dispatchMouseEvent', { ...shared, type: 'mousePressed', buttons: buttonsMask, clickCount: count }, sessionId);
31
+ await client.send('Input.dispatchMouseEvent', { ...shared, type: 'mouseReleased', buttons: i < clickCount - 1 ? buttonsMask : 0, clickCount: count }, sessionId);
32
+ }
33
+ }
34
+ export async function fillElement(client, sessionId, ref, value) {
35
+ const box = await getElementBox(client, sessionId, ref);
36
+ if (box) {
37
+ // Click to focus
38
+ await clickPoint(client, sessionId, box.x, box.y);
39
+ }
40
+ // Select all and replace
41
+ const objectId = await getObjectIdForRef(client, sessionId, ref);
42
+ if (objectId) {
43
+ const fillSelectResult = await client.send('Runtime.callFunctionOn', {
44
+ functionDeclaration: `function() {
45
+ this.focus();
46
+ if (this.tagName === 'INPUT' || this.tagName === 'TEXTAREA') {
47
+ this.select();
48
+ } else if (this.isContentEditable) {
49
+ const range = document.createRange();
50
+ range.selectNodeContents(this);
51
+ const sel = window.getSelection();
52
+ if (sel) { sel.removeAllRanges(); sel.addRange(range); }
53
+ }
54
+ }`,
55
+ objectId,
56
+ returnByValue: true,
57
+ }, sessionId);
58
+ if (fillSelectResult.exceptionDetails) {
59
+ throw new Error(`fillElement select-all failed: ${fillSelectResult.exceptionDetails.exception?.description ?? fillSelectResult.exceptionDetails.text}`);
60
+ }
61
+ }
62
+ else if (box) {
63
+ // Fallback for elements without a resolvable objectId: keyboard select-all clears existing content
64
+ const mod = process.platform === 'darwin' ? 4 : 2;
65
+ await pressKeyCombo(client, sessionId, 'a', mod);
66
+ }
67
+ if (!objectId && !box)
68
+ throw new Error(`Cannot fill ref @${ref.ref}: element not found in DOM`);
69
+ // Type the value character by character for natural input
70
+ await typeText(client, sessionId, value);
71
+ }
72
+ export async function typeText(client, sessionId, text) {
73
+ // Cap to 100 KB to prevent OOM in CDP message serializer
74
+ const safeText = text.length > 102_400 ? text.slice(0, 102_400) : text;
75
+ await client.send('Input.insertText', { text: safeText }, sessionId);
76
+ }
77
+ export async function pressKeyCombo(client, sessionId, key, modifiers) {
78
+ const { text: _text, ...keyInfo } = resolveKey(key);
79
+ // rawKeyDown prevents Chrome from inserting the character text; only the shortcut fires
80
+ await client.send('Input.dispatchKeyEvent', { type: 'rawKeyDown', ...keyInfo, modifiers }, sessionId);
81
+ await client.send('Input.dispatchKeyEvent', { type: 'keyUp', ...keyInfo, modifiers }, sessionId);
82
+ }
83
+ export async function pressKey(client, sessionId, key) {
84
+ const { text, ...keyInfo } = resolveKey(key);
85
+ // rawKeyDown does not insert text; the explicit char event handles insertion
86
+ await client.send('Input.dispatchKeyEvent', {
87
+ type: 'rawKeyDown',
88
+ ...keyInfo,
89
+ }, sessionId);
90
+ if (text) {
91
+ await client.send('Input.dispatchKeyEvent', {
92
+ type: 'char',
93
+ text,
94
+ }, sessionId);
95
+ }
96
+ await client.send('Input.dispatchKeyEvent', {
97
+ type: 'keyUp',
98
+ ...keyInfo,
99
+ }, sessionId);
100
+ }
101
+ function resolveKey(key) {
102
+ const keyMap = {
103
+ Enter: { key: 'Enter', code: 'Enter', text: '\r', windowsVirtualKeyCode: 13 },
104
+ Tab: { key: 'Tab', code: 'Tab', windowsVirtualKeyCode: 9 },
105
+ Escape: { key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27 },
106
+ Backspace: { key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 },
107
+ Delete: { key: 'Delete', code: 'Delete', windowsVirtualKeyCode: 46 },
108
+ ArrowUp: { key: 'ArrowUp', code: 'ArrowUp', windowsVirtualKeyCode: 38 },
109
+ ArrowDown: { key: 'ArrowDown', code: 'ArrowDown', windowsVirtualKeyCode: 40 },
110
+ ArrowLeft: { key: 'ArrowLeft', code: 'ArrowLeft', windowsVirtualKeyCode: 37 },
111
+ ArrowRight: { key: 'ArrowRight', code: 'ArrowRight', windowsVirtualKeyCode: 39 },
112
+ Home: { key: 'Home', code: 'Home', windowsVirtualKeyCode: 36 },
113
+ End: { key: 'End', code: 'End', windowsVirtualKeyCode: 35 },
114
+ PageUp: { key: 'PageUp', code: 'PageUp', windowsVirtualKeyCode: 33 },
115
+ PageDown: { key: 'PageDown', code: 'PageDown', windowsVirtualKeyCode: 34 },
116
+ Space: { key: ' ', code: 'Space', text: ' ', windowsVirtualKeyCode: 32 },
117
+ ' ': { key: ' ', code: 'Space', text: ' ', windowsVirtualKeyCode: 32 },
118
+ Shift: { key: 'Shift', code: 'ShiftLeft', windowsVirtualKeyCode: 16 },
119
+ Control: { key: 'Control', code: 'ControlLeft', windowsVirtualKeyCode: 17 },
120
+ Alt: { key: 'Alt', code: 'AltLeft', windowsVirtualKeyCode: 18 },
121
+ Meta: { key: 'Meta', code: 'MetaLeft', windowsVirtualKeyCode: 91 },
122
+ F1: { key: 'F1', code: 'F1', windowsVirtualKeyCode: 112 },
123
+ F2: { key: 'F2', code: 'F2', windowsVirtualKeyCode: 113 },
124
+ F3: { key: 'F3', code: 'F3', windowsVirtualKeyCode: 114 },
125
+ F4: { key: 'F4', code: 'F4', windowsVirtualKeyCode: 115 },
126
+ F5: { key: 'F5', code: 'F5', windowsVirtualKeyCode: 116 },
127
+ F6: { key: 'F6', code: 'F6', windowsVirtualKeyCode: 117 },
128
+ F7: { key: 'F7', code: 'F7', windowsVirtualKeyCode: 118 },
129
+ F8: { key: 'F8', code: 'F8', windowsVirtualKeyCode: 119 },
130
+ F9: { key: 'F9', code: 'F9', windowsVirtualKeyCode: 120 },
131
+ F10: { key: 'F10', code: 'F10', windowsVirtualKeyCode: 121 },
132
+ F11: { key: 'F11', code: 'F11', windowsVirtualKeyCode: 122 },
133
+ F12: { key: 'F12', code: 'F12', windowsVirtualKeyCode: 123 },
134
+ };
135
+ if (keyMap[key])
136
+ return keyMap[key];
137
+ // Single printable character — windowsVirtualKeyCode required for rawKeyDown shortcut dispatch
138
+ if (key.length === 1) {
139
+ const charCode = key.charCodeAt(0);
140
+ if (charCode >= 48 && charCode <= 57) {
141
+ return { key, code: `Digit${key}`, text: key, windowsVirtualKeyCode: charCode };
142
+ }
143
+ if ((charCode >= 65 && charCode <= 90) || (charCode >= 97 && charCode <= 122)) {
144
+ return { key, code: `Key${key.toUpperCase()}`, text: key, windowsVirtualKeyCode: key.toUpperCase().charCodeAt(0) };
145
+ }
146
+ // Symbol keys: map to the physical key's code and Windows virtual key code
147
+ const symbolMap = {
148
+ '!': { code: 'Digit1', windowsVirtualKeyCode: 49 },
149
+ '@': { code: 'Digit2', windowsVirtualKeyCode: 50 },
150
+ '#': { code: 'Digit3', windowsVirtualKeyCode: 51 },
151
+ '$': { code: 'Digit4', windowsVirtualKeyCode: 52 },
152
+ '%': { code: 'Digit5', windowsVirtualKeyCode: 53 },
153
+ '^': { code: 'Digit6', windowsVirtualKeyCode: 54 },
154
+ '&': { code: 'Digit7', windowsVirtualKeyCode: 55 },
155
+ '*': { code: 'Digit8', windowsVirtualKeyCode: 56 },
156
+ '(': { code: 'Digit9', windowsVirtualKeyCode: 57 },
157
+ ')': { code: 'Digit0', windowsVirtualKeyCode: 48 },
158
+ '-': { code: 'Minus', windowsVirtualKeyCode: 189 },
159
+ '_': { code: 'Minus', windowsVirtualKeyCode: 189 },
160
+ '=': { code: 'Equal', windowsVirtualKeyCode: 187 },
161
+ '+': { code: 'Equal', windowsVirtualKeyCode: 187 },
162
+ '[': { code: 'BracketLeft', windowsVirtualKeyCode: 219 },
163
+ '{': { code: 'BracketLeft', windowsVirtualKeyCode: 219 },
164
+ ']': { code: 'BracketRight', windowsVirtualKeyCode: 221 },
165
+ '}': { code: 'BracketRight', windowsVirtualKeyCode: 221 },
166
+ '\\': { code: 'Backslash', windowsVirtualKeyCode: 220 },
167
+ '|': { code: 'Backslash', windowsVirtualKeyCode: 220 },
168
+ ';': { code: 'Semicolon', windowsVirtualKeyCode: 186 },
169
+ ':': { code: 'Semicolon', windowsVirtualKeyCode: 186 },
170
+ "'": { code: 'Quote', windowsVirtualKeyCode: 222 },
171
+ '"': { code: 'Quote', windowsVirtualKeyCode: 222 },
172
+ '`': { code: 'Backquote', windowsVirtualKeyCode: 192 },
173
+ '~': { code: 'Backquote', windowsVirtualKeyCode: 192 },
174
+ ',': { code: 'Comma', windowsVirtualKeyCode: 188 },
175
+ '<': { code: 'Comma', windowsVirtualKeyCode: 188 },
176
+ '.': { code: 'Period', windowsVirtualKeyCode: 190 },
177
+ '>': { code: 'Period', windowsVirtualKeyCode: 190 },
178
+ '/': { code: 'Slash', windowsVirtualKeyCode: 191 },
179
+ '?': { code: 'Slash', windowsVirtualKeyCode: 191 },
180
+ };
181
+ const sym = symbolMap[key];
182
+ if (sym)
183
+ return { key, code: sym.code, text: key, windowsVirtualKeyCode: sym.windowsVirtualKeyCode };
184
+ // Unknown/non-ASCII character — omit code since no valid DOM KeyboardEvent.code exists
185
+ return { key, code: '', text: key };
186
+ }
187
+ return { key, code: key };
188
+ }
189
+ export async function scrollElement(client, sessionId, direction, amount = 300, ref) {
190
+ // Cap scroll amount to prevent extreme delta values
191
+ amount = Math.min(Math.max(1, Math.floor(amount)), 100_000);
192
+ let x = 0;
193
+ let y = 0;
194
+ let deltaX = 0;
195
+ let deltaY = 0;
196
+ if (ref) {
197
+ const box = await getElementBox(client, sessionId, ref);
198
+ if (!box)
199
+ throw new Error(`Cannot scroll: ref @${ref.ref} not found in DOM`);
200
+ x = box.x;
201
+ y = box.y;
202
+ }
203
+ else {
204
+ // Center of viewport
205
+ const vp = await client.send('Runtime.evaluate', {
206
+ expression: 'JSON.stringify({w: window.innerWidth, h: window.innerHeight})',
207
+ returnByValue: true,
208
+ }, sessionId);
209
+ const dims = JSON.parse(vp.result?.value ?? '{"w":1280,"h":720}');
210
+ x = dims.w / 2;
211
+ y = dims.h / 2;
212
+ }
213
+ switch (direction) {
214
+ case 'down':
215
+ deltaY = amount;
216
+ break;
217
+ case 'up':
218
+ deltaY = -amount;
219
+ break;
220
+ case 'right':
221
+ deltaX = amount;
222
+ break;
223
+ case 'left':
224
+ deltaX = -amount;
225
+ break;
226
+ }
227
+ await client.send('Input.dispatchMouseEvent', {
228
+ type: 'mouseWheel',
229
+ x,
230
+ y,
231
+ deltaX,
232
+ deltaY,
233
+ }, sessionId);
234
+ }
235
+ export async function hoverElement(client, sessionId, ref) {
236
+ const box = await getElementBox(client, sessionId, ref);
237
+ if (!box)
238
+ throw new Error(`Cannot hover ref @${ref.ref}: element not found in DOM`);
239
+ await client.send('Input.dispatchMouseEvent', {
240
+ type: 'mouseMoved',
241
+ x: box.x,
242
+ y: box.y,
243
+ }, sessionId);
244
+ }
245
+ export async function selectOption(client, sessionId, ref, value) {
246
+ const objectId = await getObjectIdForRef(client, sessionId, ref);
247
+ if (!objectId)
248
+ throw new Error(`Cannot select: ref @${ref.ref} not found in DOM`);
249
+ const selectResult = await client.send('Runtime.callFunctionOn', {
250
+ functionDeclaration: `function(value) {
251
+ if (this.tagName !== 'SELECT') throw new Error('Not a select element');
252
+ for (const opt of this.options) {
253
+ if (opt.value === value || opt.textContent.trim() === value) {
254
+ this.value = opt.value;
255
+ this.dispatchEvent(new Event('change', { bubbles: true }));
256
+ return;
257
+ }
258
+ }
259
+ throw new Error('Option not found: ' + value);
260
+ }`,
261
+ objectId,
262
+ arguments: [{ value }],
263
+ returnByValue: true,
264
+ }, sessionId);
265
+ if (selectResult.exceptionDetails) {
266
+ throw new Error(`selectOption failed: ${selectResult.exceptionDetails.exception?.description ?? selectResult.exceptionDetails.text}`);
267
+ }
268
+ }
269
+ export async function checkElement(client, sessionId, ref, checked = true) {
270
+ const objectId = await getObjectIdForRef(client, sessionId, ref);
271
+ if (!objectId)
272
+ throw new Error(`Cannot check: ref @${ref.ref} not found in DOM`);
273
+ const checkResult = await client.send('Runtime.callFunctionOn', {
274
+ functionDeclaration: `function(checked) {
275
+ if (this.checked !== checked) {
276
+ this.click();
277
+ }
278
+ }`,
279
+ objectId,
280
+ arguments: [{ value: checked }],
281
+ returnByValue: true,
282
+ }, sessionId);
283
+ if (checkResult.exceptionDetails) {
284
+ throw new Error(`checkElement failed: ${checkResult.exceptionDetails.exception?.description ?? checkResult.exceptionDetails.text}`);
285
+ }
286
+ }
287
+ export async function focusElement(client, sessionId, ref) {
288
+ const objectId = await getObjectIdForRef(client, sessionId, ref);
289
+ if (objectId) {
290
+ await client.send('Runtime.callFunctionOn', {
291
+ functionDeclaration: 'function() { this.focus(); }',
292
+ objectId,
293
+ returnByValue: true,
294
+ }, sessionId);
295
+ return;
296
+ }
297
+ const box = await getElementBox(client, sessionId, ref);
298
+ if (box) {
299
+ await clickPoint(client, sessionId, box.x, box.y);
300
+ }
301
+ else {
302
+ throw new Error(`Cannot focus ref @${ref.ref}: element not found in DOM`);
303
+ }
304
+ }
305
+ export async function typeIntoElement(client, sessionId, ref, text) {
306
+ await focusElement(client, sessionId, ref);
307
+ await typeText(client, sessionId, text);
308
+ }
309
+ export async function keyDown(client, sessionId, key) {
310
+ const { text: _text, ...keyInfo } = resolveKey(key);
311
+ await client.send('Input.dispatchKeyEvent', { type: 'rawKeyDown', ...keyInfo }, sessionId);
312
+ }
313
+ export async function keyUp(client, sessionId, key) {
314
+ const { text: _text, ...keyInfo } = resolveKey(key);
315
+ await client.send('Input.dispatchKeyEvent', { type: 'keyUp', ...keyInfo }, sessionId);
316
+ }
317
+ export async function mouseMove(client, sessionId, x, y) {
318
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y }, sessionId);
319
+ }
320
+ export async function mouseDown(client, sessionId, x, y, button = 'left') {
321
+ const buttonsMask = button === 'right' ? 2 : button === 'middle' ? 4 : 1;
322
+ await client.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button, buttons: buttonsMask, clickCount: 1 }, sessionId);
323
+ }
324
+ export async function mouseUp(client, sessionId, x, y, button = 'left') {
325
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button, buttons: 0, clickCount: 1 }, sessionId);
326
+ }
327
+ export async function mouseWheel(client, sessionId, x, y, deltaY, deltaX = 0) {
328
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseWheel', x, y, deltaX, deltaY }, sessionId);
329
+ }
330
+ export async function dragAndDrop(client, sessionId, src, tgt) {
331
+ const srcBox = await getElementBox(client, sessionId, src);
332
+ const tgtBox = await getElementBox(client, sessionId, tgt);
333
+ if (!srcBox || !tgtBox)
334
+ throw new Error('Cannot drag: one or both elements not found in DOM');
335
+ await client.send('Input.dispatchMouseEvent', { type: 'mousePressed', x: srcBox.x, y: srcBox.y, button: 'left', buttons: 1, clickCount: 1 }, sessionId);
336
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x: srcBox.x, y: srcBox.y, button: 'left', buttons: 1 }, sessionId);
337
+ // Move in steps for smooth drag
338
+ const steps = 10;
339
+ for (let i = 1; i <= steps; i++) {
340
+ const x = srcBox.x + (tgtBox.x - srcBox.x) * (i / steps);
341
+ const y = srcBox.y + (tgtBox.y - srcBox.y) * (i / steps);
342
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y, button: 'left', buttons: 1 }, sessionId);
343
+ }
344
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x: tgtBox.x, y: tgtBox.y, button: 'left', buttons: 0, clickCount: 1 }, sessionId);
345
+ }
346
+ export async function uploadFile(client, sessionId, ref, filePaths) {
347
+ if (!ref.backendDOMNodeId)
348
+ throw new Error(`Cannot upload: ref @${ref.ref} has no DOM node`);
349
+ await client.send('DOM.setFileInputFiles', {
350
+ files: filePaths.map((f) => resolve(f)),
351
+ backendNodeId: ref.backendDOMNodeId,
352
+ }, sessionId);
353
+ }
354
+ export async function readClipboard(client, sessionId) {
355
+ const result = await evaluateJs(client, sessionId, 'navigator.clipboard.readText()');
356
+ return result;
357
+ }
358
+ export async function writeClipboard(client, sessionId, text) {
359
+ // Cap to 100 KB to prevent OOM when serializing the CDP expression
360
+ const safeText = text.length > 102_400 ? text.slice(0, 102_400) : text;
361
+ await evaluateJs(client, sessionId, `navigator.clipboard.writeText(${JSON.stringify(safeText)})`);
362
+ }
363
+ export async function pushState(client, sessionId, url) {
364
+ // Try Next.js router first, then fallback to history.pushState
365
+ await evaluateJs(client, sessionId, `
366
+ (function() {
367
+ const url = ${JSON.stringify(url)};
368
+ if (window.next && window.next.router) {
369
+ window.next.router.push(url).catch(function() {});
370
+ return;
371
+ } else {
372
+ history.pushState({}, '', url);
373
+ window.dispatchEvent(new PopStateEvent('popstate'));
374
+ }
375
+ })()
376
+ `);
377
+ }
378
+ export async function addInitScript(client, sessionId, script) {
379
+ const result = await client.send('Page.addScriptToEvaluateOnNewDocument', {
380
+ source: script,
381
+ }, sessionId);
382
+ return result.identifier;
383
+ }
384
+ export async function removeInitScript(client, sessionId, identifier) {
385
+ await client.send('Page.removeScriptToEvaluateOnNewDocument', { identifier }, sessionId);
386
+ }
387
+ export async function evaluateJs(client, sessionId, expression) {
388
+ const result = await client.send('Runtime.evaluate', {
389
+ expression,
390
+ returnByValue: true,
391
+ awaitPromise: true,
392
+ }, sessionId);
393
+ if (result.exceptionDetails) {
394
+ throw new Error(`JS evaluation error: ${result.exceptionDetails.exception?.description ?? result.exceptionDetails.text}`);
395
+ }
396
+ return result.result?.value;
397
+ }
398
+ //# sourceMappingURL=actions.js.map