@flrande/browserctl 0.5.0-dev.22.1 → 0.6.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.
- package/dist/client.d.ts +34 -0
- package/dist/client.js +138 -0
- package/dist/commandRegistry.d.ts +16 -0
- package/dist/commandRegistry.js +21 -0
- package/dist/help.d.ts +4 -0
- package/dist/help.js +24 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +23 -0
- package/dist/runCli.d.ts +5 -0
- package/dist/runCli.js +170 -0
- package/package.json +32 -59
- package/INSTALL-CN.md +0 -92
- package/INSTALL.md +0 -92
- package/LICENSE +0 -21
- package/README-CN.md +0 -69
- package/README.md +0 -69
- package/apps/browserctl/src/commands/a11y-snapshot.ts +0 -20
- package/apps/browserctl/src/commands/act.test.ts +0 -71
- package/apps/browserctl/src/commands/act.ts +0 -64
- package/apps/browserctl/src/commands/command-wrappers.test.ts +0 -688
- package/apps/browserctl/src/commands/common.test.ts +0 -87
- package/apps/browserctl/src/commands/common.ts +0 -191
- package/apps/browserctl/src/commands/console-list.test.ts +0 -102
- package/apps/browserctl/src/commands/console-list.ts +0 -108
- package/apps/browserctl/src/commands/cookie-clear.ts +0 -18
- package/apps/browserctl/src/commands/cookie-get.ts +0 -18
- package/apps/browserctl/src/commands/cookie-set.ts +0 -22
- package/apps/browserctl/src/commands/dialog-arm.ts +0 -20
- package/apps/browserctl/src/commands/dom-query-all.ts +0 -18
- package/apps/browserctl/src/commands/dom-query.ts +0 -18
- package/apps/browserctl/src/commands/download-trigger.ts +0 -22
- package/apps/browserctl/src/commands/download-wait.test.ts +0 -67
- package/apps/browserctl/src/commands/download-wait.ts +0 -27
- package/apps/browserctl/src/commands/element-screenshot.ts +0 -20
- package/apps/browserctl/src/commands/frame-list.ts +0 -16
- package/apps/browserctl/src/commands/frame-snapshot.ts +0 -18
- package/apps/browserctl/src/commands/har-export.test.ts +0 -112
- package/apps/browserctl/src/commands/har-export.ts +0 -120
- package/apps/browserctl/src/commands/memory-delete.ts +0 -20
- package/apps/browserctl/src/commands/memory-inspect.ts +0 -20
- package/apps/browserctl/src/commands/memory-list.ts +0 -90
- package/apps/browserctl/src/commands/memory-mode-set.ts +0 -29
- package/apps/browserctl/src/commands/memory-purge.ts +0 -16
- package/apps/browserctl/src/commands/memory-resolve.ts +0 -56
- package/apps/browserctl/src/commands/memory-status.ts +0 -16
- package/apps/browserctl/src/commands/memory-ttl-set.ts +0 -28
- package/apps/browserctl/src/commands/memory-upsert.ts +0 -142
- package/apps/browserctl/src/commands/network-list.test.ts +0 -110
- package/apps/browserctl/src/commands/network-list.ts +0 -112
- package/apps/browserctl/src/commands/network-wait-for.test.ts +0 -90
- package/apps/browserctl/src/commands/network-wait-for.ts +0 -100
- package/apps/browserctl/src/commands/profile-list.ts +0 -16
- package/apps/browserctl/src/commands/profile-use.ts +0 -18
- package/apps/browserctl/src/commands/response-body.ts +0 -24
- package/apps/browserctl/src/commands/screenshot.ts +0 -16
- package/apps/browserctl/src/commands/session-drop.test.ts +0 -36
- package/apps/browserctl/src/commands/session-drop.ts +0 -16
- package/apps/browserctl/src/commands/session-list.test.ts +0 -81
- package/apps/browserctl/src/commands/session-list.ts +0 -70
- package/apps/browserctl/src/commands/snapshot.ts +0 -16
- package/apps/browserctl/src/commands/status.ts +0 -10
- package/apps/browserctl/src/commands/storage-get.ts +0 -20
- package/apps/browserctl/src/commands/storage-set.ts +0 -22
- package/apps/browserctl/src/commands/tab-close.ts +0 -20
- package/apps/browserctl/src/commands/tab-focus.ts +0 -20
- package/apps/browserctl/src/commands/tab-open.ts +0 -19
- package/apps/browserctl/src/commands/tabs.ts +0 -13
- package/apps/browserctl/src/commands/trace-get.test.ts +0 -61
- package/apps/browserctl/src/commands/trace-get.ts +0 -62
- package/apps/browserctl/src/commands/upload-arm.ts +0 -26
- package/apps/browserctl/src/commands/wait-element.test.ts +0 -80
- package/apps/browserctl/src/commands/wait-element.ts +0 -76
- package/apps/browserctl/src/commands/wait-text.test.ts +0 -110
- package/apps/browserctl/src/commands/wait-text.ts +0 -93
- package/apps/browserctl/src/commands/wait-url.test.ts +0 -80
- package/apps/browserctl/src/commands/wait-url.ts +0 -76
- package/apps/browserctl/src/daemon-client.test.ts +0 -512
- package/apps/browserctl/src/daemon-client.ts +0 -632
- package/apps/browserctl/src/e2e.test.ts +0 -103
- package/apps/browserctl/src/main.dispatch.test.ts +0 -461
- package/apps/browserctl/src/main.test.ts +0 -334
- package/apps/browserctl/src/main.ts +0 -957
- package/apps/browserctl/src/smoke.e2e.test.ts +0 -97
- package/apps/browserctl/src/test-port.ts +0 -26
- package/apps/browserd/src/bootstrap.ts +0 -432
- package/apps/browserd/src/chrome-relay-extension-bridge.test.ts +0 -250
- package/apps/browserd/src/chrome-relay-extension-bridge.ts +0 -506
- package/apps/browserd/src/container.ts +0 -3088
- package/apps/browserd/src/main.test.ts +0 -1522
- package/apps/browserd/src/main.ts +0 -7
- package/apps/browserd/src/test-port.ts +0 -26
- package/apps/browserd/src/tool-matrix.test.ts +0 -887
- package/bin/browserctl.cjs +0 -21
- package/bin/browserd.cjs +0 -21
- package/extensions/chrome-relay/README-CN.md +0 -39
- package/extensions/chrome-relay/README.md +0 -39
- package/extensions/chrome-relay/background.js +0 -1687
- package/extensions/chrome-relay/manifest.json +0 -15
- package/extensions/chrome-relay/popup.html +0 -369
- package/extensions/chrome-relay/popup.js +0 -972
- package/packages/core/src/bootstrap.test.ts +0 -10
- package/packages/core/src/driver-registry.test.ts +0 -45
- package/packages/core/src/driver-registry.ts +0 -22
- package/packages/core/src/driver.ts +0 -47
- package/packages/core/src/index.ts +0 -6
- package/packages/core/src/navigation-memory.test.ts +0 -259
- package/packages/core/src/navigation-memory.ts +0 -360
- package/packages/core/src/ref-cache.test.ts +0 -61
- package/packages/core/src/ref-cache.ts +0 -28
- package/packages/core/src/session-store.test.ts +0 -82
- package/packages/core/src/session-store.ts +0 -138
- package/packages/core/src/types.ts +0 -9
- package/packages/driver-chrome-relay/src/chrome-relay-driver.test.ts +0 -744
- package/packages/driver-chrome-relay/src/chrome-relay-driver.ts +0 -2429
- package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.test.ts +0 -264
- package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.ts +0 -521
- package/packages/driver-chrome-relay/src/index.ts +0 -26
- package/packages/driver-managed/src/index.ts +0 -22
- package/packages/driver-managed/src/managed-driver.test.ts +0 -183
- package/packages/driver-managed/src/managed-driver.ts +0 -341
- package/packages/driver-managed/src/managed-local-driver.test.ts +0 -608
- package/packages/driver-managed/src/managed-local-driver.ts +0 -2243
- package/packages/driver-remote-cdp/src/index.ts +0 -19
- package/packages/driver-remote-cdp/src/remote-cdp-driver.test.ts +0 -727
- package/packages/driver-remote-cdp/src/remote-cdp-driver.ts +0 -2264
- package/packages/protocol/src/envelope.test.ts +0 -25
- package/packages/protocol/src/envelope.ts +0 -31
- package/packages/protocol/src/errors.test.ts +0 -17
- package/packages/protocol/src/errors.ts +0 -11
- package/packages/protocol/src/index.ts +0 -3
- package/packages/protocol/src/tools.ts +0 -3
- package/packages/transport-mcp-stdio/src/index.ts +0 -3
- package/packages/transport-mcp-stdio/src/sdk-server.ts +0 -139
- package/packages/transport-mcp-stdio/src/server.test.ts +0 -281
- package/packages/transport-mcp-stdio/src/server.ts +0 -183
- package/packages/transport-mcp-stdio/src/tool-map.ts +0 -84
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ChromeRelayBrowser,
|
|
3
|
-
ChromeRelayBrowserContext,
|
|
4
|
-
ChromeRelayDriverRuntime,
|
|
5
|
-
ChromeRelayLocator,
|
|
6
|
-
ChromeRelayPage
|
|
7
|
-
} from "./chrome-relay-driver";
|
|
8
|
-
|
|
9
|
-
export type ChromeRelayExtensionTransport = {
|
|
10
|
-
invoke(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
11
|
-
isConnected?(): boolean;
|
|
12
|
-
onEvent?(listener: (event: ChromeRelayExtensionTransportEvent) => void): () => void;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type ChromeRelayExtensionRuntimeConfig = {
|
|
16
|
-
transport: ChromeRelayExtensionTransport;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type ChromeRelayExtensionTransportConsoleEvent = {
|
|
20
|
-
kind: "console";
|
|
21
|
-
tabId: number;
|
|
22
|
-
entry: {
|
|
23
|
-
type: string;
|
|
24
|
-
text: string;
|
|
25
|
-
location?: {
|
|
26
|
-
url?: string;
|
|
27
|
-
lineNumber?: number;
|
|
28
|
-
columnNumber?: number;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type ChromeRelayExtensionTransportNetworkEvent = {
|
|
34
|
-
kind: "response";
|
|
35
|
-
tabId: number;
|
|
36
|
-
response: {
|
|
37
|
-
requestId: string;
|
|
38
|
-
url: string;
|
|
39
|
-
status?: number;
|
|
40
|
-
method?: string;
|
|
41
|
-
resourceType?: string;
|
|
42
|
-
body?: string;
|
|
43
|
-
encoding?: "utf8" | "base64";
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export type ChromeRelayExtensionTransportEvent =
|
|
48
|
-
| ChromeRelayExtensionTransportConsoleEvent
|
|
49
|
-
| ChromeRelayExtensionTransportNetworkEvent;
|
|
50
|
-
|
|
51
|
-
type ExtensionPageState = {
|
|
52
|
-
tabId?: number;
|
|
53
|
-
currentUrl: string;
|
|
54
|
-
closed: boolean;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
type ExtensionPageEventListener = (payload: unknown) => unknown;
|
|
58
|
-
|
|
59
|
-
type ExtensionPageRecord = {
|
|
60
|
-
page: ChromeRelayPage;
|
|
61
|
-
state: ExtensionPageState;
|
|
62
|
-
close(): Promise<void>;
|
|
63
|
-
emitConsole(entry: ChromeRelayExtensionTransportConsoleEvent["entry"]): Promise<void>;
|
|
64
|
-
emitResponse(response: ChromeRelayExtensionTransportNetworkEvent["response"]): Promise<void>;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
function isObjectRecord(value: unknown): value is Record<string, unknown> {
|
|
68
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function readObjectStringProperty(value: unknown, key: string): string | undefined {
|
|
72
|
-
if (!isObjectRecord(value)) {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const propertyValue = value[key];
|
|
77
|
-
return typeof propertyValue === "string" ? propertyValue : undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function readObjectNumberProperty(value: unknown, key: string): number | undefined {
|
|
81
|
-
if (!isObjectRecord(value)) {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const propertyValue = value[key];
|
|
86
|
-
return typeof propertyValue === "number" ? propertyValue : undefined;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function toOptionalPositiveNumber(value: number | undefined): number | undefined {
|
|
90
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
type ExtensionPageScreenshot = {
|
|
94
|
-
mimeType: string;
|
|
95
|
-
encoding: "base64";
|
|
96
|
-
imageBase64: string;
|
|
97
|
-
width?: number;
|
|
98
|
-
height?: number;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
function readScreenshotResult(value: unknown): ExtensionPageScreenshot {
|
|
102
|
-
if (!isObjectRecord(value)) {
|
|
103
|
-
throw new Error("Extension relay response is missing screenshot payload.");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const imageBase64 = readObjectStringProperty(value, "imageBase64");
|
|
107
|
-
if (imageBase64 === undefined || imageBase64.trim().length === 0) {
|
|
108
|
-
throw new Error("Extension relay response is missing screenshot imageBase64.");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const rawEncoding = readObjectStringProperty(value, "encoding");
|
|
112
|
-
if (rawEncoding !== undefined && rawEncoding !== "base64") {
|
|
113
|
-
throw new Error(`Unsupported extension screenshot encoding: ${rawEncoding}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const mimeType = readObjectStringProperty(value, "mimeType") ?? "image/png";
|
|
117
|
-
const width = toOptionalPositiveNumber(readObjectNumberProperty(value, "width"));
|
|
118
|
-
const height = toOptionalPositiveNumber(readObjectNumberProperty(value, "height"));
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
mimeType,
|
|
122
|
-
encoding: "base64",
|
|
123
|
-
imageBase64: imageBase64.trim(),
|
|
124
|
-
...(width !== undefined ? { width } : {}),
|
|
125
|
-
...(height !== undefined ? { height } : {})
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function requireConnected(transport: ChromeRelayExtensionTransport): void {
|
|
130
|
-
if (transport.isConnected?.() === false) {
|
|
131
|
-
throw new Error("Chrome relay extension is not connected.");
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function requireTabId(result: unknown, method: string): number {
|
|
136
|
-
const tabId = readObjectNumberProperty(result, "tabId");
|
|
137
|
-
if (typeof tabId !== "number" || !Number.isFinite(tabId)) {
|
|
138
|
-
throw new Error(`Extension relay response is missing numeric tabId for ${method}.`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return tabId;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function createLocator(
|
|
145
|
-
transport: ChromeRelayExtensionTransport,
|
|
146
|
-
state: ExtensionPageState,
|
|
147
|
-
selector: string
|
|
148
|
-
): ChromeRelayLocator {
|
|
149
|
-
const invokeAction = async (type: string, payload: Record<string, unknown>) => {
|
|
150
|
-
if (state.tabId === undefined) {
|
|
151
|
-
throw new Error("No extension-backed tab is currently attached to this page.");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
await transport.invoke("tab.act", {
|
|
155
|
-
tabId: state.tabId,
|
|
156
|
-
action: {
|
|
157
|
-
type,
|
|
158
|
-
payload
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
click: async () => {
|
|
165
|
-
await invokeAction("click", { selector });
|
|
166
|
-
},
|
|
167
|
-
fill: async (value) => {
|
|
168
|
-
await invokeAction("fill", { selector, value });
|
|
169
|
-
},
|
|
170
|
-
type: async (value) => {
|
|
171
|
-
await invokeAction("type", { selector, text: value });
|
|
172
|
-
},
|
|
173
|
-
setInputFiles: async (files: string[]) => {
|
|
174
|
-
await invokeAction("setFiles", { selector, files: [...files] });
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function toConsoleEventPayload(entry: ChromeRelayExtensionTransportConsoleEvent["entry"]): {
|
|
180
|
-
type(): string;
|
|
181
|
-
text(): string;
|
|
182
|
-
location(): { url?: string; lineNumber?: number; columnNumber?: number };
|
|
183
|
-
} {
|
|
184
|
-
return {
|
|
185
|
-
type: () => entry.type,
|
|
186
|
-
text: () => entry.text,
|
|
187
|
-
location: () => ({ ...(entry.location ?? {}) })
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function toResponseEventPayload(response: ChromeRelayExtensionTransportNetworkEvent["response"]): {
|
|
192
|
-
url(): string;
|
|
193
|
-
status(): number;
|
|
194
|
-
request(): {
|
|
195
|
-
method(): string;
|
|
196
|
-
resourceType(): string | undefined;
|
|
197
|
-
};
|
|
198
|
-
text(): Promise<string>;
|
|
199
|
-
body(): Promise<string | Uint8Array>;
|
|
200
|
-
} {
|
|
201
|
-
return {
|
|
202
|
-
url: () => response.url,
|
|
203
|
-
status: () => response.status ?? 0,
|
|
204
|
-
request: () => ({
|
|
205
|
-
method: () => response.method ?? "GET",
|
|
206
|
-
resourceType: () => response.resourceType
|
|
207
|
-
}),
|
|
208
|
-
text: async () => {
|
|
209
|
-
if (response.body === undefined) {
|
|
210
|
-
return "";
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (response.encoding === "base64") {
|
|
214
|
-
return Buffer.from(response.body, "base64").toString("utf8");
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return response.body;
|
|
218
|
-
},
|
|
219
|
-
body: async () => {
|
|
220
|
-
if (response.body === undefined) {
|
|
221
|
-
return "";
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (response.encoding === "base64") {
|
|
225
|
-
return Buffer.from(response.body, "base64");
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return response.body;
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async function emitPageEvent(
|
|
234
|
-
listeners: Map<string, ExtensionPageEventListener[]>,
|
|
235
|
-
eventName: string,
|
|
236
|
-
payload: unknown
|
|
237
|
-
): Promise<void> {
|
|
238
|
-
const eventListeners = listeners.get(eventName);
|
|
239
|
-
if (eventListeners === undefined || eventListeners.length === 0) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
for (const listener of [...eventListeners]) {
|
|
244
|
-
await listener(payload);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function createPageRecord(
|
|
249
|
-
transport: ChromeRelayExtensionTransport,
|
|
250
|
-
releasePage: () => void
|
|
251
|
-
): ExtensionPageRecord {
|
|
252
|
-
const state: ExtensionPageState = {
|
|
253
|
-
currentUrl: "about:blank",
|
|
254
|
-
closed: false
|
|
255
|
-
};
|
|
256
|
-
const listeners = new Map<string, ExtensionPageEventListener[]>();
|
|
257
|
-
|
|
258
|
-
const ensureOpen = () => {
|
|
259
|
-
if (state.closed) {
|
|
260
|
-
throw new Error("Cannot operate on closed extension-backed page.");
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const ensureTabId = () => {
|
|
265
|
-
if (state.tabId === undefined) {
|
|
266
|
-
throw new Error("No extension-backed tab is currently attached to this page.");
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return state.tabId;
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const page: ChromeRelayPage = {
|
|
273
|
-
goto: async (url) => {
|
|
274
|
-
ensureOpen();
|
|
275
|
-
if (state.tabId === undefined) {
|
|
276
|
-
const result = await transport.invoke("tab.open", { url });
|
|
277
|
-
state.tabId = requireTabId(result, "tab.open");
|
|
278
|
-
state.currentUrl = readObjectStringProperty(result, "url") ?? url;
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const result = await transport.invoke("tab.goto", {
|
|
283
|
-
tabId: state.tabId,
|
|
284
|
-
url
|
|
285
|
-
});
|
|
286
|
-
state.currentUrl = readObjectStringProperty(result, "url") ?? url;
|
|
287
|
-
},
|
|
288
|
-
bringToFront: async () => {
|
|
289
|
-
ensureOpen();
|
|
290
|
-
const tabId = ensureTabId();
|
|
291
|
-
await transport.invoke("tab.focus", { tabId });
|
|
292
|
-
},
|
|
293
|
-
close: async () => {
|
|
294
|
-
if (state.closed) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (state.tabId !== undefined) {
|
|
299
|
-
await transport.invoke("tab.close", { tabId: state.tabId });
|
|
300
|
-
}
|
|
301
|
-
state.closed = true;
|
|
302
|
-
releasePage();
|
|
303
|
-
},
|
|
304
|
-
url: () => state.currentUrl,
|
|
305
|
-
title: async () => {
|
|
306
|
-
ensureOpen();
|
|
307
|
-
if (state.tabId === undefined) {
|
|
308
|
-
return "";
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const result = await transport.invoke("tab.info", { tabId: state.tabId });
|
|
312
|
-
state.currentUrl = readObjectStringProperty(result, "url") ?? state.currentUrl;
|
|
313
|
-
return readObjectStringProperty(result, "title") ?? "";
|
|
314
|
-
},
|
|
315
|
-
content: async () => {
|
|
316
|
-
ensureOpen();
|
|
317
|
-
if (state.tabId === undefined) {
|
|
318
|
-
return "";
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const result = await transport.invoke("tab.snapshot", { tabId: state.tabId });
|
|
322
|
-
state.currentUrl = readObjectStringProperty(result, "url") ?? state.currentUrl;
|
|
323
|
-
return readObjectStringProperty(result, "html") ?? "";
|
|
324
|
-
},
|
|
325
|
-
screenshot: async () => {
|
|
326
|
-
ensureOpen();
|
|
327
|
-
const tabId = ensureTabId();
|
|
328
|
-
const result = await transport.invoke("tab.screenshot", { tabId });
|
|
329
|
-
return readScreenshotResult(result);
|
|
330
|
-
},
|
|
331
|
-
domQuery: async (selector: string) => {
|
|
332
|
-
ensureOpen();
|
|
333
|
-
const tabId = ensureTabId();
|
|
334
|
-
const result = await transport.invoke("tab.dom.query", { tabId, selector });
|
|
335
|
-
return isObjectRecord(result) ? result : { selector, found: false };
|
|
336
|
-
},
|
|
337
|
-
domQueryAll: async (selector: string) => {
|
|
338
|
-
ensureOpen();
|
|
339
|
-
const tabId = ensureTabId();
|
|
340
|
-
const result = await transport.invoke("tab.dom.queryAll", { tabId, selector });
|
|
341
|
-
return isObjectRecord(result) ? result : { selector, count: 0, nodes: [] };
|
|
342
|
-
},
|
|
343
|
-
elementScreenshot: async (selector: string) => {
|
|
344
|
-
ensureOpen();
|
|
345
|
-
const tabId = ensureTabId();
|
|
346
|
-
const result = await transport.invoke("tab.element.screenshot", { tabId, selector });
|
|
347
|
-
return isObjectRecord(result) ? result : { selector, found: false };
|
|
348
|
-
},
|
|
349
|
-
a11ySnapshot: async (selector?: string) => {
|
|
350
|
-
ensureOpen();
|
|
351
|
-
const tabId = ensureTabId();
|
|
352
|
-
const result = await transport.invoke("tab.a11y.snapshot", { tabId, selector });
|
|
353
|
-
return isObjectRecord(result) ? result : { found: false };
|
|
354
|
-
},
|
|
355
|
-
cookieGet: async (name?: string) => {
|
|
356
|
-
ensureOpen();
|
|
357
|
-
const tabId = ensureTabId();
|
|
358
|
-
const result = await transport.invoke("tab.cookie.get", { tabId, name });
|
|
359
|
-
return isObjectRecord(result) ? result : { cookies: [] };
|
|
360
|
-
},
|
|
361
|
-
cookieSet: async (cookie: { name: string; value: string; url?: string }) => {
|
|
362
|
-
ensureOpen();
|
|
363
|
-
const tabId = ensureTabId();
|
|
364
|
-
const result = await transport.invoke("tab.cookie.set", {
|
|
365
|
-
tabId,
|
|
366
|
-
...cookie
|
|
367
|
-
});
|
|
368
|
-
return isObjectRecord(result) ? result : { set: true };
|
|
369
|
-
},
|
|
370
|
-
cookieClear: async (name?: string) => {
|
|
371
|
-
ensureOpen();
|
|
372
|
-
const tabId = ensureTabId();
|
|
373
|
-
const result = await transport.invoke("tab.cookie.clear", { tabId, name });
|
|
374
|
-
return isObjectRecord(result) ? result : { cleared: true };
|
|
375
|
-
},
|
|
376
|
-
storageGet: async (scope: string, key: string) => {
|
|
377
|
-
ensureOpen();
|
|
378
|
-
const tabId = ensureTabId();
|
|
379
|
-
const result = await transport.invoke("tab.storage.get", { tabId, scope, key });
|
|
380
|
-
return isObjectRecord(result) ? result : { scope, key, exists: false };
|
|
381
|
-
},
|
|
382
|
-
storageSet: async (scope: string, key: string, value: string) => {
|
|
383
|
-
ensureOpen();
|
|
384
|
-
const tabId = ensureTabId();
|
|
385
|
-
const result = await transport.invoke("tab.storage.set", { tabId, scope, key, value });
|
|
386
|
-
return isObjectRecord(result) ? result : { scope, key, value, set: true };
|
|
387
|
-
},
|
|
388
|
-
frameList: async () => {
|
|
389
|
-
ensureOpen();
|
|
390
|
-
const tabId = ensureTabId();
|
|
391
|
-
const result = await transport.invoke("tab.frame.list", { tabId });
|
|
392
|
-
return isObjectRecord(result) ? result : { frames: [] };
|
|
393
|
-
},
|
|
394
|
-
frameSnapshot: async (frameId: string) => {
|
|
395
|
-
ensureOpen();
|
|
396
|
-
const tabId = ensureTabId();
|
|
397
|
-
const result = await transport.invoke("tab.frame.snapshot", { tabId, frameId });
|
|
398
|
-
return isObjectRecord(result) ? result : { frameId, found: false };
|
|
399
|
-
},
|
|
400
|
-
scroll: async (deltaX = 0, deltaY = 900) => {
|
|
401
|
-
ensureOpen();
|
|
402
|
-
const tabId = ensureTabId();
|
|
403
|
-
const result = await transport.invoke("tab.act", {
|
|
404
|
-
tabId,
|
|
405
|
-
action: {
|
|
406
|
-
type: "scroll",
|
|
407
|
-
payload: {
|
|
408
|
-
deltaX,
|
|
409
|
-
deltaY
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
return isObjectRecord(result)
|
|
414
|
-
? result
|
|
415
|
-
: {
|
|
416
|
-
executed: true,
|
|
417
|
-
deltaX,
|
|
418
|
-
deltaY
|
|
419
|
-
};
|
|
420
|
-
},
|
|
421
|
-
locator: (selector) => createLocator(transport, state, selector),
|
|
422
|
-
on: (eventName, listener) => {
|
|
423
|
-
const currentListeners = listeners.get(eventName);
|
|
424
|
-
if (currentListeners !== undefined) {
|
|
425
|
-
currentListeners.push(listener as ExtensionPageEventListener);
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
listeners.set(eventName, [listener as ExtensionPageEventListener]);
|
|
430
|
-
},
|
|
431
|
-
keyboard: {
|
|
432
|
-
press: async (key) => {
|
|
433
|
-
ensureOpen();
|
|
434
|
-
const tabId = ensureTabId();
|
|
435
|
-
await transport.invoke("tab.act", {
|
|
436
|
-
tabId,
|
|
437
|
-
action: {
|
|
438
|
-
type: "press",
|
|
439
|
-
payload: { key }
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
return {
|
|
447
|
-
page,
|
|
448
|
-
state,
|
|
449
|
-
close: async () => {
|
|
450
|
-
await page.close();
|
|
451
|
-
},
|
|
452
|
-
emitConsole: async (entry) => {
|
|
453
|
-
await emitPageEvent(listeners, "console", toConsoleEventPayload(entry));
|
|
454
|
-
},
|
|
455
|
-
emitResponse: async (response) => {
|
|
456
|
-
await emitPageEvent(listeners, "response", toResponseEventPayload(response));
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function createBrowser(transport: ChromeRelayExtensionTransport): ChromeRelayBrowser {
|
|
462
|
-
const pageRecords = new Set<ExtensionPageRecord>();
|
|
463
|
-
let detachEventListener: (() => void) | undefined;
|
|
464
|
-
|
|
465
|
-
if (typeof transport.onEvent === "function") {
|
|
466
|
-
detachEventListener = transport.onEvent((event) => {
|
|
467
|
-
for (const pageRecord of [...pageRecords]) {
|
|
468
|
-
if (pageRecord.state.tabId === undefined || pageRecord.state.tabId !== event.tabId) {
|
|
469
|
-
continue;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (event.kind === "console") {
|
|
473
|
-
void pageRecord.emitConsole(event.entry);
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
if (event.kind === "response") {
|
|
478
|
-
void pageRecord.emitResponse(event.response);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
const context: ChromeRelayBrowserContext = {
|
|
485
|
-
newPage: async () => {
|
|
486
|
-
const pageRecord = createPageRecord(transport, () => {
|
|
487
|
-
pageRecords.delete(pageRecord);
|
|
488
|
-
});
|
|
489
|
-
pageRecords.add(pageRecord);
|
|
490
|
-
return pageRecord.page;
|
|
491
|
-
},
|
|
492
|
-
close: async () => {
|
|
493
|
-
for (const pageRecord of [...pageRecords]) {
|
|
494
|
-
await pageRecord.close();
|
|
495
|
-
}
|
|
496
|
-
pageRecords.clear();
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
return {
|
|
501
|
-
contexts: () => [context],
|
|
502
|
-
newContext: async () => context,
|
|
503
|
-
close: async () => {
|
|
504
|
-
await context.close?.();
|
|
505
|
-
detachEventListener?.();
|
|
506
|
-
detachEventListener = undefined;
|
|
507
|
-
}
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
export function createChromeRelayExtensionRuntime(
|
|
512
|
-
config: ChromeRelayExtensionRuntimeConfig
|
|
513
|
-
): ChromeRelayDriverRuntime {
|
|
514
|
-
return {
|
|
515
|
-
connectOverCDP: async (_endpointUrl) => {
|
|
516
|
-
requireConnected(config.transport);
|
|
517
|
-
return createBrowser(config.transport);
|
|
518
|
-
},
|
|
519
|
-
isConnected: () => config.transport.isConnected?.() ?? false
|
|
520
|
-
};
|
|
521
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export { createChromeRelayDriver } from "./chrome-relay-driver";
|
|
2
|
-
export { createChromeRelayExtensionRuntime } from "./chrome-relay-extension-runtime";
|
|
3
|
-
export type {
|
|
4
|
-
ChromeRelayBrowser,
|
|
5
|
-
ChromeRelayBrowserContext,
|
|
6
|
-
ChromeRelayConsoleEntry,
|
|
7
|
-
ChromeRelayConsoleEntryLocation,
|
|
8
|
-
ChromeRelayDriverConfig,
|
|
9
|
-
ChromeRelayDriverRuntime,
|
|
10
|
-
ChromeRelayDriverStatus,
|
|
11
|
-
ChromeRelayKeyboard,
|
|
12
|
-
ChromeRelayLocator,
|
|
13
|
-
ChromeRelayNetworkRequestSummary,
|
|
14
|
-
ChromeRelayNetworkResponseBody,
|
|
15
|
-
ChromeRelayPage,
|
|
16
|
-
ChromeRelayScreenshot,
|
|
17
|
-
ChromeRelaySnapshot,
|
|
18
|
-
ChromeRelayTelemetryDriverExtensions
|
|
19
|
-
} from "./chrome-relay-driver";
|
|
20
|
-
export type {
|
|
21
|
-
ChromeRelayExtensionRuntimeConfig,
|
|
22
|
-
ChromeRelayExtensionTransportEvent,
|
|
23
|
-
ChromeRelayExtensionTransportConsoleEvent,
|
|
24
|
-
ChromeRelayExtensionTransportNetworkEvent,
|
|
25
|
-
ChromeRelayExtensionTransport
|
|
26
|
-
} from "./chrome-relay-extension-runtime";
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export { createManagedDriver } from "./managed-driver";
|
|
2
|
-
export type { ManagedDriverStatus } from "./managed-driver";
|
|
3
|
-
export { createManagedLocalDriver } from "./managed-local-driver";
|
|
4
|
-
export type {
|
|
5
|
-
ManagedLocalBrowser,
|
|
6
|
-
ManagedLocalBrowserContext,
|
|
7
|
-
ManagedLocalBrowserLaunchConfig,
|
|
8
|
-
ManagedLocalBrowserName,
|
|
9
|
-
ManagedLocalConsoleEntry,
|
|
10
|
-
ManagedLocalConsoleEntryLocation,
|
|
11
|
-
ManagedLocalDriverConfig,
|
|
12
|
-
ManagedLocalDriverRuntime,
|
|
13
|
-
ManagedLocalDriverStatus,
|
|
14
|
-
ManagedLocalKeyboard,
|
|
15
|
-
ManagedLocalLocator,
|
|
16
|
-
ManagedLocalNetworkRequestSummary,
|
|
17
|
-
ManagedLocalNetworkResponseBody,
|
|
18
|
-
ManagedLocalPage,
|
|
19
|
-
ManagedLocalScreenshot,
|
|
20
|
-
ManagedLocalSnapshot,
|
|
21
|
-
ManagedLocalTelemetryDriverExtensions
|
|
22
|
-
} from "./managed-local-driver";
|