@hera-al/browser-server 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.
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +74 -0
- package/dist/core/cdp.d.ts +124 -0
- package/dist/core/cdp.helpers.d.ts +14 -0
- package/dist/core/cdp.helpers.js +148 -0
- package/dist/core/cdp.js +309 -0
- package/dist/core/chrome.d.ts +21 -0
- package/dist/core/chrome.executables.d.ts +10 -0
- package/dist/core/chrome.executables.js +559 -0
- package/dist/core/chrome.js +257 -0
- package/dist/core/chrome.profile-decoration.d.ts +11 -0
- package/dist/core/chrome.profile-decoration.js +148 -0
- package/dist/core/constants.d.ts +9 -0
- package/dist/core/constants.js +9 -0
- package/dist/core/profiles.d.ts +31 -0
- package/dist/core/profiles.js +99 -0
- package/dist/core/target-id.d.ts +12 -0
- package/dist/core/target-id.js +21 -0
- package/dist/data-dir.d.ts +2 -0
- package/dist/data-dir.js +6 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +125 -0
- package/dist/playwright/pw-role-snapshot.d.ts +32 -0
- package/dist/playwright/pw-role-snapshot.js +337 -0
- package/dist/playwright/pw-session.d.ts +119 -0
- package/dist/playwright/pw-session.js +530 -0
- package/dist/playwright/pw-tools-core.activity.d.ts +22 -0
- package/dist/playwright/pw-tools-core.activity.js +47 -0
- package/dist/playwright/pw-tools-core.d.ts +9 -0
- package/dist/playwright/pw-tools-core.downloads.d.ts +35 -0
- package/dist/playwright/pw-tools-core.downloads.js +186 -0
- package/dist/playwright/pw-tools-core.interactions.d.ts +104 -0
- package/dist/playwright/pw-tools-core.interactions.js +404 -0
- package/dist/playwright/pw-tools-core.js +9 -0
- package/dist/playwright/pw-tools-core.responses.d.ts +14 -0
- package/dist/playwright/pw-tools-core.responses.js +91 -0
- package/dist/playwright/pw-tools-core.shared.d.ts +7 -0
- package/dist/playwright/pw-tools-core.shared.js +50 -0
- package/dist/playwright/pw-tools-core.snapshot.d.ts +65 -0
- package/dist/playwright/pw-tools-core.snapshot.js +144 -0
- package/dist/playwright/pw-tools-core.state.d.ts +47 -0
- package/dist/playwright/pw-tools-core.state.js +154 -0
- package/dist/playwright/pw-tools-core.storage.d.ts +48 -0
- package/dist/playwright/pw-tools-core.storage.js +76 -0
- package/dist/playwright/pw-tools-core.trace.d.ts +13 -0
- package/dist/playwright/pw-tools-core.trace.js +26 -0
- package/dist/server/browser-context.d.ts +29 -0
- package/dist/server/browser-context.js +137 -0
- package/dist/server/browser-server.d.ts +7 -0
- package/dist/server/browser-server.js +49 -0
- package/dist/server/routes/act.d.ts +4 -0
- package/dist/server/routes/act.js +176 -0
- package/dist/server/routes/basic.d.ts +4 -0
- package/dist/server/routes/basic.js +36 -0
- package/dist/server/routes/index.d.ts +4 -0
- package/dist/server/routes/index.js +16 -0
- package/dist/server/routes/snapshot.d.ts +4 -0
- package/dist/server/routes/snapshot.js +143 -0
- package/dist/server/routes/storage.d.ts +4 -0
- package/dist/server/routes/storage.js +117 -0
- package/dist/server/routes/tabs.d.ts +4 -0
- package/dist/server/routes/tabs.js +51 -0
- package/dist/server/standalone.d.ts +9 -0
- package/dist/server/standalone.js +42 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +58 -0
- package/package.json +66 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function responseBodyViaPlaywright(opts: {
|
|
2
|
+
cdpUrl: string;
|
|
3
|
+
targetId?: string;
|
|
4
|
+
url: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
maxChars?: number;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
url: string;
|
|
9
|
+
status?: number;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
body: string;
|
|
12
|
+
truncated?: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=pw-tools-core.responses.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ensurePageState, getPageForTargetId } from "./pw-session.js";
|
|
2
|
+
import { normalizeTimeoutMs } from "./pw-tools-core.shared.js";
|
|
3
|
+
function matchUrlPattern(pattern, url) {
|
|
4
|
+
const p = pattern.trim();
|
|
5
|
+
if (!p) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (p === url) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (p.includes("*")) {
|
|
12
|
+
const escaped = p.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
13
|
+
const regex = new RegExp(`^${escaped.replace(/\*\*/g, ".*").replace(/\*/g, ".*")}$`);
|
|
14
|
+
return regex.test(url);
|
|
15
|
+
}
|
|
16
|
+
return url.includes(p);
|
|
17
|
+
}
|
|
18
|
+
export async function responseBodyViaPlaywright(opts) {
|
|
19
|
+
const pattern = String(opts.url ?? "").trim();
|
|
20
|
+
if (!pattern) {
|
|
21
|
+
throw new Error("url is required");
|
|
22
|
+
}
|
|
23
|
+
const maxChars = typeof opts.maxChars === "number" && Number.isFinite(opts.maxChars)
|
|
24
|
+
? Math.max(1, Math.min(5_000_000, Math.floor(opts.maxChars)))
|
|
25
|
+
: 200_000;
|
|
26
|
+
const timeout = normalizeTimeoutMs(opts.timeoutMs, 20_000);
|
|
27
|
+
const page = await getPageForTargetId(opts);
|
|
28
|
+
ensurePageState(page);
|
|
29
|
+
const promise = new Promise((resolve, reject) => {
|
|
30
|
+
let done = false;
|
|
31
|
+
let timer;
|
|
32
|
+
let handler;
|
|
33
|
+
const cleanup = () => {
|
|
34
|
+
if (timer) {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
}
|
|
37
|
+
timer = undefined;
|
|
38
|
+
if (handler) {
|
|
39
|
+
page.off("response", handler);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
handler = (resp) => {
|
|
43
|
+
if (done) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const r = resp;
|
|
47
|
+
const u = r.url?.() || "";
|
|
48
|
+
if (!matchUrlPattern(pattern, u)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
done = true;
|
|
52
|
+
cleanup();
|
|
53
|
+
resolve(resp);
|
|
54
|
+
};
|
|
55
|
+
page.on("response", handler);
|
|
56
|
+
timer = setTimeout(() => {
|
|
57
|
+
if (done) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
done = true;
|
|
61
|
+
cleanup();
|
|
62
|
+
reject(new Error(`Response not found for url pattern "${pattern}". Check recent network activity.`));
|
|
63
|
+
}, timeout);
|
|
64
|
+
});
|
|
65
|
+
const resp = (await promise);
|
|
66
|
+
const url = resp.url?.() || "";
|
|
67
|
+
const status = resp.status?.();
|
|
68
|
+
const headers = resp.headers?.();
|
|
69
|
+
let bodyText = "";
|
|
70
|
+
try {
|
|
71
|
+
if (typeof resp.text === "function") {
|
|
72
|
+
bodyText = await resp.text();
|
|
73
|
+
}
|
|
74
|
+
else if (typeof resp.body === "function") {
|
|
75
|
+
const buf = await resp.body();
|
|
76
|
+
bodyText = new TextDecoder("utf-8").decode(buf);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
throw new Error(`Failed to read response body for "${url}": ${String(err)}`, { cause: err });
|
|
81
|
+
}
|
|
82
|
+
const trimmed = bodyText.length > maxChars ? bodyText.slice(0, maxChars) : bodyText;
|
|
83
|
+
return {
|
|
84
|
+
url,
|
|
85
|
+
status,
|
|
86
|
+
headers,
|
|
87
|
+
body: trimmed,
|
|
88
|
+
truncated: bodyText.length > maxChars ? true : undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=pw-tools-core.responses.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function bumpUploadArmId(): number;
|
|
2
|
+
export declare function bumpDialogArmId(): number;
|
|
3
|
+
export declare function bumpDownloadArmId(): number;
|
|
4
|
+
export declare function requireRef(value: unknown): string;
|
|
5
|
+
export declare function normalizeTimeoutMs(timeoutMs: number | undefined, fallback: number): number;
|
|
6
|
+
export declare function toAIFriendlyError(error: unknown, selector: string): Error;
|
|
7
|
+
//# sourceMappingURL=pw-tools-core.shared.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { parseRoleRef } from "./pw-role-snapshot.js";
|
|
2
|
+
let nextUploadArmId = 0;
|
|
3
|
+
let nextDialogArmId = 0;
|
|
4
|
+
let nextDownloadArmId = 0;
|
|
5
|
+
export function bumpUploadArmId() {
|
|
6
|
+
nextUploadArmId += 1;
|
|
7
|
+
return nextUploadArmId;
|
|
8
|
+
}
|
|
9
|
+
export function bumpDialogArmId() {
|
|
10
|
+
nextDialogArmId += 1;
|
|
11
|
+
return nextDialogArmId;
|
|
12
|
+
}
|
|
13
|
+
export function bumpDownloadArmId() {
|
|
14
|
+
nextDownloadArmId += 1;
|
|
15
|
+
return nextDownloadArmId;
|
|
16
|
+
}
|
|
17
|
+
export function requireRef(value) {
|
|
18
|
+
const raw = typeof value === "string" ? value.trim() : "";
|
|
19
|
+
const roleRef = raw ? parseRoleRef(raw) : null;
|
|
20
|
+
const ref = roleRef ?? (raw.startsWith("@") ? raw.slice(1) : raw);
|
|
21
|
+
if (!ref) {
|
|
22
|
+
throw new Error("ref is required");
|
|
23
|
+
}
|
|
24
|
+
return ref;
|
|
25
|
+
}
|
|
26
|
+
export function normalizeTimeoutMs(timeoutMs, fallback) {
|
|
27
|
+
return Math.max(500, Math.min(120_000, timeoutMs ?? fallback));
|
|
28
|
+
}
|
|
29
|
+
export function toAIFriendlyError(error, selector) {
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
if (message.includes("strict mode violation")) {
|
|
32
|
+
const countMatch = message.match(/resolved to (\d+) elements/);
|
|
33
|
+
const count = countMatch ? countMatch[1] : "multiple";
|
|
34
|
+
return new Error(`Selector "${selector}" matched ${count} elements. ` +
|
|
35
|
+
`Run a new snapshot to get updated refs, or use a different ref.`);
|
|
36
|
+
}
|
|
37
|
+
if ((message.includes("Timeout") || message.includes("waiting for")) &&
|
|
38
|
+
(message.includes("to be visible") || message.includes("not visible"))) {
|
|
39
|
+
return new Error(`Element "${selector}" not found or not visible. ` +
|
|
40
|
+
`Run a new snapshot to see current page elements.`);
|
|
41
|
+
}
|
|
42
|
+
if (message.includes("intercepts pointer events") ||
|
|
43
|
+
message.includes("not visible") ||
|
|
44
|
+
message.includes("not receive pointer events")) {
|
|
45
|
+
return new Error(`Element "${selector}" is not interactable (hidden or covered). ` +
|
|
46
|
+
`Try scrolling it into view, closing overlays, or re-snapshotting.`);
|
|
47
|
+
}
|
|
48
|
+
return error instanceof Error ? error : new Error(message);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=pw-tools-core.shared.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type AriaSnapshotNode } from "../core/cdp.js";
|
|
2
|
+
import { type RoleSnapshotOptions, type RoleRefMap } from "./pw-role-snapshot.js";
|
|
3
|
+
export declare function snapshotAriaViaPlaywright(opts: {
|
|
4
|
+
cdpUrl: string;
|
|
5
|
+
targetId?: string;
|
|
6
|
+
limit?: number;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
nodes: AriaSnapshotNode[];
|
|
9
|
+
}>;
|
|
10
|
+
export declare function snapshotAiViaPlaywright(opts: {
|
|
11
|
+
cdpUrl: string;
|
|
12
|
+
targetId?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
maxChars?: number;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
snapshot: string;
|
|
17
|
+
truncated?: boolean;
|
|
18
|
+
refs: RoleRefMap;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function snapshotRoleViaPlaywright(opts: {
|
|
21
|
+
cdpUrl: string;
|
|
22
|
+
targetId?: string;
|
|
23
|
+
selector?: string;
|
|
24
|
+
frameSelector?: string;
|
|
25
|
+
refsMode?: "role" | "aria";
|
|
26
|
+
options?: RoleSnapshotOptions;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
snapshot: string;
|
|
29
|
+
refs: Record<string, {
|
|
30
|
+
role: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
nth?: number;
|
|
33
|
+
}>;
|
|
34
|
+
stats: {
|
|
35
|
+
lines: number;
|
|
36
|
+
chars: number;
|
|
37
|
+
refs: number;
|
|
38
|
+
interactive: number;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
41
|
+
export declare function navigateViaPlaywright(opts: {
|
|
42
|
+
cdpUrl: string;
|
|
43
|
+
targetId?: string;
|
|
44
|
+
url: string;
|
|
45
|
+
timeoutMs?: number;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
url: string;
|
|
48
|
+
}>;
|
|
49
|
+
export declare function resizeViewportViaPlaywright(opts: {
|
|
50
|
+
cdpUrl: string;
|
|
51
|
+
targetId?: string;
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
}): Promise<void>;
|
|
55
|
+
export declare function closePageViaPlaywright(opts: {
|
|
56
|
+
cdpUrl: string;
|
|
57
|
+
targetId?: string;
|
|
58
|
+
}): Promise<void>;
|
|
59
|
+
export declare function pdfViaPlaywright(opts: {
|
|
60
|
+
cdpUrl: string;
|
|
61
|
+
targetId?: string;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
buffer: Buffer;
|
|
64
|
+
}>;
|
|
65
|
+
//# sourceMappingURL=pw-tools-core.snapshot.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { formatAriaSnapshot } from "../core/cdp.js";
|
|
2
|
+
import { buildRoleSnapshotFromAiSnapshot, buildRoleSnapshotFromAriaSnapshot, getRoleSnapshotStats, } from "./pw-role-snapshot.js";
|
|
3
|
+
import { ensurePageState, getPageForTargetId, storeRoleRefsForTarget, } from "./pw-session.js";
|
|
4
|
+
export async function snapshotAriaViaPlaywright(opts) {
|
|
5
|
+
const limit = Math.max(1, Math.min(2000, Math.floor(opts.limit ?? 500)));
|
|
6
|
+
const page = await getPageForTargetId({
|
|
7
|
+
cdpUrl: opts.cdpUrl,
|
|
8
|
+
targetId: opts.targetId,
|
|
9
|
+
});
|
|
10
|
+
ensurePageState(page);
|
|
11
|
+
const session = await page.context().newCDPSession(page);
|
|
12
|
+
try {
|
|
13
|
+
await session.send("Accessibility.enable").catch(() => { });
|
|
14
|
+
const res = (await session.send("Accessibility.getFullAXTree"));
|
|
15
|
+
const nodes = Array.isArray(res?.nodes) ? res.nodes : [];
|
|
16
|
+
return { nodes: formatAriaSnapshot(nodes, limit) };
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
await session.detach().catch(() => { });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function snapshotAiViaPlaywright(opts) {
|
|
23
|
+
const page = await getPageForTargetId({
|
|
24
|
+
cdpUrl: opts.cdpUrl,
|
|
25
|
+
targetId: opts.targetId,
|
|
26
|
+
});
|
|
27
|
+
ensurePageState(page);
|
|
28
|
+
const maybe = page;
|
|
29
|
+
if (!maybe._snapshotForAI) {
|
|
30
|
+
throw new Error("Playwright _snapshotForAI is not available. Upgrade playwright-core.");
|
|
31
|
+
}
|
|
32
|
+
const result = await maybe._snapshotForAI({
|
|
33
|
+
timeout: Math.max(500, Math.min(60_000, Math.floor(opts.timeoutMs ?? 5000))),
|
|
34
|
+
track: "response",
|
|
35
|
+
});
|
|
36
|
+
let snapshot = String(result?.full ?? "");
|
|
37
|
+
const maxChars = opts.maxChars;
|
|
38
|
+
const limit = typeof maxChars === "number" && Number.isFinite(maxChars) && maxChars > 0
|
|
39
|
+
? Math.floor(maxChars)
|
|
40
|
+
: undefined;
|
|
41
|
+
let truncated = false;
|
|
42
|
+
if (limit && snapshot.length > limit) {
|
|
43
|
+
snapshot = `${snapshot.slice(0, limit)}\n\n[...TRUNCATED - page too large]`;
|
|
44
|
+
truncated = true;
|
|
45
|
+
}
|
|
46
|
+
const built = buildRoleSnapshotFromAiSnapshot(snapshot);
|
|
47
|
+
storeRoleRefsForTarget({
|
|
48
|
+
page,
|
|
49
|
+
cdpUrl: opts.cdpUrl,
|
|
50
|
+
targetId: opts.targetId,
|
|
51
|
+
refs: built.refs,
|
|
52
|
+
mode: "aria",
|
|
53
|
+
});
|
|
54
|
+
return truncated ? { snapshot, truncated, refs: built.refs } : { snapshot, refs: built.refs };
|
|
55
|
+
}
|
|
56
|
+
export async function snapshotRoleViaPlaywright(opts) {
|
|
57
|
+
const page = await getPageForTargetId({
|
|
58
|
+
cdpUrl: opts.cdpUrl,
|
|
59
|
+
targetId: opts.targetId,
|
|
60
|
+
});
|
|
61
|
+
ensurePageState(page);
|
|
62
|
+
if (opts.refsMode === "aria") {
|
|
63
|
+
if (opts.selector?.trim() || opts.frameSelector?.trim()) {
|
|
64
|
+
throw new Error("refs=aria does not support selector/frame snapshots yet.");
|
|
65
|
+
}
|
|
66
|
+
const maybe = page;
|
|
67
|
+
if (!maybe._snapshotForAI) {
|
|
68
|
+
throw new Error("refs=aria requires Playwright _snapshotForAI support.");
|
|
69
|
+
}
|
|
70
|
+
const result = await maybe._snapshotForAI({
|
|
71
|
+
timeout: 5000,
|
|
72
|
+
track: "response",
|
|
73
|
+
});
|
|
74
|
+
const built = buildRoleSnapshotFromAiSnapshot(String(result?.full ?? ""), opts.options);
|
|
75
|
+
storeRoleRefsForTarget({
|
|
76
|
+
page,
|
|
77
|
+
cdpUrl: opts.cdpUrl,
|
|
78
|
+
targetId: opts.targetId,
|
|
79
|
+
refs: built.refs,
|
|
80
|
+
mode: "aria",
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
snapshot: built.snapshot,
|
|
84
|
+
refs: built.refs,
|
|
85
|
+
stats: getRoleSnapshotStats(built.snapshot, built.refs),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const frameSelector = opts.frameSelector?.trim() || "";
|
|
89
|
+
const selector = opts.selector?.trim() || "";
|
|
90
|
+
const locator = frameSelector
|
|
91
|
+
? selector
|
|
92
|
+
? page.frameLocator(frameSelector).locator(selector)
|
|
93
|
+
: page.frameLocator(frameSelector).locator(":root")
|
|
94
|
+
: selector
|
|
95
|
+
? page.locator(selector)
|
|
96
|
+
: page.locator(":root");
|
|
97
|
+
const ariaSnapshot = await locator.ariaSnapshot();
|
|
98
|
+
const built = buildRoleSnapshotFromAriaSnapshot(String(ariaSnapshot ?? ""), opts.options);
|
|
99
|
+
storeRoleRefsForTarget({
|
|
100
|
+
page,
|
|
101
|
+
cdpUrl: opts.cdpUrl,
|
|
102
|
+
targetId: opts.targetId,
|
|
103
|
+
refs: built.refs,
|
|
104
|
+
frameSelector: frameSelector || undefined,
|
|
105
|
+
mode: "role",
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
snapshot: built.snapshot,
|
|
109
|
+
refs: built.refs,
|
|
110
|
+
stats: getRoleSnapshotStats(built.snapshot, built.refs),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export async function navigateViaPlaywright(opts) {
|
|
114
|
+
const url = String(opts.url ?? "").trim();
|
|
115
|
+
if (!url) {
|
|
116
|
+
throw new Error("url is required");
|
|
117
|
+
}
|
|
118
|
+
const page = await getPageForTargetId(opts);
|
|
119
|
+
ensurePageState(page);
|
|
120
|
+
await page.goto(url, {
|
|
121
|
+
timeout: Math.max(1000, Math.min(120_000, opts.timeoutMs ?? 20_000)),
|
|
122
|
+
});
|
|
123
|
+
return { url: page.url() };
|
|
124
|
+
}
|
|
125
|
+
export async function resizeViewportViaPlaywright(opts) {
|
|
126
|
+
const page = await getPageForTargetId(opts);
|
|
127
|
+
ensurePageState(page);
|
|
128
|
+
await page.setViewportSize({
|
|
129
|
+
width: Math.max(1, Math.floor(opts.width)),
|
|
130
|
+
height: Math.max(1, Math.floor(opts.height)),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
export async function closePageViaPlaywright(opts) {
|
|
134
|
+
const page = await getPageForTargetId(opts);
|
|
135
|
+
ensurePageState(page);
|
|
136
|
+
await page.close();
|
|
137
|
+
}
|
|
138
|
+
export async function pdfViaPlaywright(opts) {
|
|
139
|
+
const page = await getPageForTargetId(opts);
|
|
140
|
+
ensurePageState(page);
|
|
141
|
+
const buffer = await page.pdf({ printBackground: true });
|
|
142
|
+
return { buffer };
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=pw-tools-core.snapshot.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare function setOfflineViaPlaywright(opts: {
|
|
2
|
+
cdpUrl: string;
|
|
3
|
+
targetId?: string;
|
|
4
|
+
offline: boolean;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function setExtraHTTPHeadersViaPlaywright(opts: {
|
|
7
|
+
cdpUrl: string;
|
|
8
|
+
targetId?: string;
|
|
9
|
+
headers: Record<string, string>;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
export declare function setHttpCredentialsViaPlaywright(opts: {
|
|
12
|
+
cdpUrl: string;
|
|
13
|
+
targetId?: string;
|
|
14
|
+
username?: string;
|
|
15
|
+
password?: string;
|
|
16
|
+
clear?: boolean;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
export declare function setGeolocationViaPlaywright(opts: {
|
|
19
|
+
cdpUrl: string;
|
|
20
|
+
targetId?: string;
|
|
21
|
+
latitude?: number;
|
|
22
|
+
longitude?: number;
|
|
23
|
+
accuracy?: number;
|
|
24
|
+
origin?: string;
|
|
25
|
+
clear?: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
export declare function emulateMediaViaPlaywright(opts: {
|
|
28
|
+
cdpUrl: string;
|
|
29
|
+
targetId?: string;
|
|
30
|
+
colorScheme: "dark" | "light" | "no-preference" | null;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
export declare function setLocaleViaPlaywright(opts: {
|
|
33
|
+
cdpUrl: string;
|
|
34
|
+
targetId?: string;
|
|
35
|
+
locale: string;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
export declare function setTimezoneViaPlaywright(opts: {
|
|
38
|
+
cdpUrl: string;
|
|
39
|
+
targetId?: string;
|
|
40
|
+
timezoneId: string;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
export declare function setDeviceViaPlaywright(opts: {
|
|
43
|
+
cdpUrl: string;
|
|
44
|
+
targetId?: string;
|
|
45
|
+
name: string;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
//# sourceMappingURL=pw-tools-core.state.d.ts.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { devices as playwrightDevices } from "playwright-core";
|
|
2
|
+
import { ensurePageState, getPageForTargetId } from "./pw-session.js";
|
|
3
|
+
async function withCdpSession(page, fn) {
|
|
4
|
+
const session = await page.context().newCDPSession(page);
|
|
5
|
+
try {
|
|
6
|
+
return await fn(session);
|
|
7
|
+
}
|
|
8
|
+
finally {
|
|
9
|
+
await session.detach().catch(() => { });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export async function setOfflineViaPlaywright(opts) {
|
|
13
|
+
const page = await getPageForTargetId(opts);
|
|
14
|
+
ensurePageState(page);
|
|
15
|
+
await page.context().setOffline(Boolean(opts.offline));
|
|
16
|
+
}
|
|
17
|
+
export async function setExtraHTTPHeadersViaPlaywright(opts) {
|
|
18
|
+
const page = await getPageForTargetId(opts);
|
|
19
|
+
ensurePageState(page);
|
|
20
|
+
await page.context().setExtraHTTPHeaders(opts.headers);
|
|
21
|
+
}
|
|
22
|
+
export async function setHttpCredentialsViaPlaywright(opts) {
|
|
23
|
+
const page = await getPageForTargetId(opts);
|
|
24
|
+
ensurePageState(page);
|
|
25
|
+
if (opts.clear) {
|
|
26
|
+
await page.context().setHTTPCredentials(null);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const username = String(opts.username ?? "");
|
|
30
|
+
const password = String(opts.password ?? "");
|
|
31
|
+
if (!username) {
|
|
32
|
+
throw new Error("username is required (or set clear=true)");
|
|
33
|
+
}
|
|
34
|
+
await page.context().setHTTPCredentials({ username, password });
|
|
35
|
+
}
|
|
36
|
+
export async function setGeolocationViaPlaywright(opts) {
|
|
37
|
+
const page = await getPageForTargetId(opts);
|
|
38
|
+
ensurePageState(page);
|
|
39
|
+
const context = page.context();
|
|
40
|
+
if (opts.clear) {
|
|
41
|
+
await context.setGeolocation(null);
|
|
42
|
+
await context.clearPermissions().catch(() => { });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (typeof opts.latitude !== "number" || typeof opts.longitude !== "number") {
|
|
46
|
+
throw new Error("latitude and longitude are required (or set clear=true)");
|
|
47
|
+
}
|
|
48
|
+
await context.setGeolocation({
|
|
49
|
+
latitude: opts.latitude,
|
|
50
|
+
longitude: opts.longitude,
|
|
51
|
+
accuracy: typeof opts.accuracy === "number" ? opts.accuracy : undefined,
|
|
52
|
+
});
|
|
53
|
+
const origin = opts.origin?.trim() ||
|
|
54
|
+
(() => {
|
|
55
|
+
try {
|
|
56
|
+
return new URL(page.url()).origin;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
})();
|
|
62
|
+
if (origin) {
|
|
63
|
+
await context.grantPermissions(["geolocation"], { origin }).catch(() => { });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function emulateMediaViaPlaywright(opts) {
|
|
67
|
+
const page = await getPageForTargetId(opts);
|
|
68
|
+
ensurePageState(page);
|
|
69
|
+
await page.emulateMedia({ colorScheme: opts.colorScheme });
|
|
70
|
+
}
|
|
71
|
+
export async function setLocaleViaPlaywright(opts) {
|
|
72
|
+
const page = await getPageForTargetId(opts);
|
|
73
|
+
ensurePageState(page);
|
|
74
|
+
const locale = String(opts.locale ?? "").trim();
|
|
75
|
+
if (!locale) {
|
|
76
|
+
throw new Error("locale is required");
|
|
77
|
+
}
|
|
78
|
+
await withCdpSession(page, async (session) => {
|
|
79
|
+
try {
|
|
80
|
+
await session.send("Emulation.setLocaleOverride", { locale });
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (String(err).includes("Another locale override is already in effect")) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export async function setTimezoneViaPlaywright(opts) {
|
|
91
|
+
const page = await getPageForTargetId(opts);
|
|
92
|
+
ensurePageState(page);
|
|
93
|
+
const timezoneId = String(opts.timezoneId ?? "").trim();
|
|
94
|
+
if (!timezoneId) {
|
|
95
|
+
throw new Error("timezoneId is required");
|
|
96
|
+
}
|
|
97
|
+
await withCdpSession(page, async (session) => {
|
|
98
|
+
try {
|
|
99
|
+
await session.send("Emulation.setTimezoneOverride", { timezoneId });
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const msg = String(err);
|
|
103
|
+
if (msg.includes("Timezone override is already in effect")) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (msg.includes("Invalid timezone")) {
|
|
107
|
+
throw new Error(`Invalid timezone ID: ${timezoneId}`, { cause: err });
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export async function setDeviceViaPlaywright(opts) {
|
|
114
|
+
const page = await getPageForTargetId(opts);
|
|
115
|
+
ensurePageState(page);
|
|
116
|
+
const name = String(opts.name ?? "").trim();
|
|
117
|
+
if (!name) {
|
|
118
|
+
throw new Error("device name is required");
|
|
119
|
+
}
|
|
120
|
+
const descriptor = playwrightDevices[name];
|
|
121
|
+
if (!descriptor) {
|
|
122
|
+
throw new Error(`Unknown device "${name}".`);
|
|
123
|
+
}
|
|
124
|
+
if (descriptor.viewport) {
|
|
125
|
+
await page.setViewportSize({
|
|
126
|
+
width: descriptor.viewport.width,
|
|
127
|
+
height: descriptor.viewport.height,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
await withCdpSession(page, async (session) => {
|
|
131
|
+
if (descriptor.userAgent || descriptor.locale) {
|
|
132
|
+
await session.send("Emulation.setUserAgentOverride", {
|
|
133
|
+
userAgent: descriptor.userAgent ?? "",
|
|
134
|
+
acceptLanguage: descriptor.locale ?? undefined,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (descriptor.viewport) {
|
|
138
|
+
await session.send("Emulation.setDeviceMetricsOverride", {
|
|
139
|
+
mobile: Boolean(descriptor.isMobile),
|
|
140
|
+
width: descriptor.viewport.width,
|
|
141
|
+
height: descriptor.viewport.height,
|
|
142
|
+
deviceScaleFactor: descriptor.deviceScaleFactor ?? 1,
|
|
143
|
+
screenWidth: descriptor.viewport.width,
|
|
144
|
+
screenHeight: descriptor.viewport.height,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (descriptor.hasTouch) {
|
|
148
|
+
await session.send("Emulation.setTouchEmulationEnabled", {
|
|
149
|
+
enabled: true,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=pw-tools-core.state.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export declare function cookiesGetViaPlaywright(opts: {
|
|
2
|
+
cdpUrl: string;
|
|
3
|
+
targetId?: string;
|
|
4
|
+
}): Promise<{
|
|
5
|
+
cookies: unknown[];
|
|
6
|
+
}>;
|
|
7
|
+
export declare function cookiesSetViaPlaywright(opts: {
|
|
8
|
+
cdpUrl: string;
|
|
9
|
+
targetId?: string;
|
|
10
|
+
cookie: {
|
|
11
|
+
name: string;
|
|
12
|
+
value: string;
|
|
13
|
+
url?: string;
|
|
14
|
+
domain?: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
expires?: number;
|
|
17
|
+
httpOnly?: boolean;
|
|
18
|
+
secure?: boolean;
|
|
19
|
+
sameSite?: "Lax" | "None" | "Strict";
|
|
20
|
+
};
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export declare function cookiesClearViaPlaywright(opts: {
|
|
23
|
+
cdpUrl: string;
|
|
24
|
+
targetId?: string;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
type StorageKind = "local" | "session";
|
|
27
|
+
export declare function storageGetViaPlaywright(opts: {
|
|
28
|
+
cdpUrl: string;
|
|
29
|
+
targetId?: string;
|
|
30
|
+
kind: StorageKind;
|
|
31
|
+
key?: string;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
values: Record<string, string>;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function storageSetViaPlaywright(opts: {
|
|
36
|
+
cdpUrl: string;
|
|
37
|
+
targetId?: string;
|
|
38
|
+
kind: StorageKind;
|
|
39
|
+
key: string;
|
|
40
|
+
value: string;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
export declare function storageClearViaPlaywright(opts: {
|
|
43
|
+
cdpUrl: string;
|
|
44
|
+
targetId?: string;
|
|
45
|
+
kind: StorageKind;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=pw-tools-core.storage.d.ts.map
|