nothing-browser 0.1.2 → 0.1.4
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/package.json +14 -26
- package/piggy/cache/{memory.ts → memory.js} +5 -10
- package/piggy/captcha/{index.ts → index.js} +19 -28
- package/piggy/capture/index.js +40 -0
- package/piggy/client/{index.ts → index.js} +133 -154
- package/piggy/dialog/{index.ts → index.js} +15 -31
- package/piggy/export/index.js +105 -0
- package/piggy/expose/index.js +24 -0
- package/piggy/find/{index.ts → index.js} +24 -39
- package/piggy/http/{index.ts → index.js} +7 -16
- package/piggy/human/{index.ts → index.js} +18 -49
- package/piggy/iframe/index.js +56 -0
- package/piggy/interactions/{index.ts → index.js} +20 -23
- package/piggy/intercept/{scripts.ts → scripts.js} +4 -13
- package/piggy/launch/{detect.ts → detect.js} +4 -6
- package/piggy/launch/{spawn.ts → spawn.js} +17 -22
- package/piggy/media/{index.ts → index.js} +13 -11
- package/piggy/navigation/{index.ts → index.js} +16 -14
- package/piggy/pool/index.js +76 -0
- package/piggy/provide/index.js +97 -0
- package/piggy/proxy/index.js +95 -0
- package/piggy/register/index.js +543 -0
- package/piggy/router/index.js +44 -0
- package/piggy/server/{index.ts → index.js} +16 -64
- package/piggy/session/index.js +69 -0
- package/piggy/store/{index.ts → index.js} +22 -62
- package/piggy/tabs/index.js +24 -0
- package/piggy/wait/index.js +77 -0
- package/piggy.js +316 -0
- package/dist/cache/memory.js +0 -35
- package/dist/client/index.js +0 -1284
- package/dist/human/index.js +0 -82
- package/dist/launch/detect.js +0 -782
- package/dist/launch/spawn.js +0 -915
- package/dist/logger/index.js +0 -733
- package/dist/piggy/cache/memory.d.ts +0 -7
- package/dist/piggy/cache/memory.d.ts.map +0 -1
- package/dist/piggy/captcha/index.d.ts +0 -39
- package/dist/piggy/captcha/index.d.ts.map +0 -1
- package/dist/piggy/capture/index.d.ts +0 -48
- package/dist/piggy/capture/index.d.ts.map +0 -1
- package/dist/piggy/client/index.d.ts +0 -146
- package/dist/piggy/client/index.d.ts.map +0 -1
- package/dist/piggy/dialog/index.d.ts +0 -28
- package/dist/piggy/dialog/index.d.ts.map +0 -1
- package/dist/piggy/export/index.d.ts +0 -62
- package/dist/piggy/export/index.d.ts.map +0 -1
- package/dist/piggy/expose/index.d.ts +0 -6
- package/dist/piggy/expose/index.d.ts.map +0 -1
- package/dist/piggy/find/index.d.ts +0 -52
- package/dist/piggy/find/index.d.ts.map +0 -1
- package/dist/piggy/http/index.d.ts +0 -14
- package/dist/piggy/http/index.d.ts.map +0 -1
- package/dist/piggy/human/index.d.ts +0 -39
- package/dist/piggy/human/index.d.ts.map +0 -1
- package/dist/piggy/iframe/index.d.ts +0 -53
- package/dist/piggy/iframe/index.d.ts.map +0 -1
- package/dist/piggy/interactions/index.d.ts +0 -24
- package/dist/piggy/interactions/index.d.ts.map +0 -1
- package/dist/piggy/intercept/scripts.d.ts +0 -13
- package/dist/piggy/intercept/scripts.d.ts.map +0 -1
- package/dist/piggy/launch/detect.d.ts +0 -3
- package/dist/piggy/launch/detect.d.ts.map +0 -1
- package/dist/piggy/launch/spawn.d.ts +0 -6
- package/dist/piggy/launch/spawn.d.ts.map +0 -1
- package/dist/piggy/logger/index.d.ts +0 -3
- package/dist/piggy/logger/index.d.ts.map +0 -1
- package/dist/piggy/media/index.d.ts +0 -11
- package/dist/piggy/media/index.d.ts.map +0 -1
- package/dist/piggy/navigation/index.d.ts +0 -16
- package/dist/piggy/navigation/index.d.ts.map +0 -1
- package/dist/piggy/pool/index.d.ts +0 -23
- package/dist/piggy/pool/index.d.ts.map +0 -1
- package/dist/piggy/provide/index.d.ts +0 -98
- package/dist/piggy/provide/index.d.ts.map +0 -1
- package/dist/piggy/proxy/index.d.ts +0 -94
- package/dist/piggy/proxy/index.d.ts.map +0 -1
- package/dist/piggy/register/index.d.ts +0 -9
- package/dist/piggy/register/index.d.ts.map +0 -1
- package/dist/piggy/router/index.d.ts +0 -38
- package/dist/piggy/router/index.d.ts.map +0 -1
- package/dist/piggy/server/index.d.ts +0 -42
- package/dist/piggy/server/index.d.ts.map +0 -1
- package/dist/piggy/session/index.d.ts +0 -27
- package/dist/piggy/session/index.d.ts.map +0 -1
- package/dist/piggy/store/index.d.ts +0 -22
- package/dist/piggy/store/index.d.ts.map +0 -1
- package/dist/piggy/tabs/index.d.ts +0 -12
- package/dist/piggy/tabs/index.d.ts.map +0 -1
- package/dist/piggy/wait/index.d.ts +0 -28
- package/dist/piggy/wait/index.d.ts.map +0 -1
- package/dist/piggy.d.ts +0 -10
- package/dist/piggy.d.ts.map +0 -1
- package/dist/piggy.js +0 -30186
- package/dist/register/index.js +0 -23710
- package/dist/server/index.js +0 -26831
- package/piggy/capture/index.ts +0 -76
- package/piggy/export/index.d.ts +0 -117
- package/piggy/export/index.ts +0 -147
- package/piggy/expose/index.ts +0 -42
- package/piggy/iframe/index.ts +0 -79
- package/piggy/intercept/scripts.d.ts +0 -13
- package/piggy/intercept/scripts.d.ts.map +0 -1
- package/piggy/launch/detect.d.ts +0 -3
- package/piggy/launch/detect.d.ts.map +0 -1
- package/piggy/launch/spawn.d.ts +0 -6
- package/piggy/launch/spawn.d.ts.map +0 -1
- package/piggy/logger/index.d.ts +0 -3
- package/piggy/logger/index.d.ts.map +0 -1
- package/piggy/pool/index.d.ts +0 -12
- package/piggy/pool/index.ts +0 -75
- package/piggy/provide/index.ts +0 -170
- package/piggy/proxy/index.ts +0 -154
- package/piggy/register/index.ts +0 -575
- package/piggy/router/index.ts +0 -69
- package/piggy/session/index.ts +0 -76
- package/piggy/store/index.d.ts +0 -26
- package/piggy/tabs/index.ts +0 -23
- package/piggy/wait/index.ts +0 -90
- package/piggy.ts +0 -274
- /package/piggy/logger/{index.ts → index.js} +0 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
|
+
|
|
1
2
|
import { existsSync } from 'fs';
|
|
2
3
|
import { join } from 'path';
|
|
3
|
-
import logger from '../logger';
|
|
4
|
-
|
|
5
|
-
export type BinaryMode = 'headless' | 'headful' | (string & {});
|
|
4
|
+
import logger from '../logger.js';
|
|
6
5
|
|
|
7
|
-
const BINARY_NAMES
|
|
6
|
+
const BINARY_NAMES = {
|
|
8
7
|
headless: 'nothing-browser-headless',
|
|
9
8
|
headful: 'nothing-browser-headful',
|
|
10
9
|
};
|
|
11
10
|
|
|
12
|
-
export function detectBinary(mode
|
|
11
|
+
export function detectBinary(mode = 'headless') {
|
|
13
12
|
const cwd = process.cwd();
|
|
14
13
|
|
|
15
14
|
// Custom path passed directly
|
|
@@ -18,7 +17,6 @@ export function detectBinary(mode: BinaryMode = 'headless'): string | null {
|
|
|
18
17
|
logger.success(`Binary found (custom path): ${mode}`);
|
|
19
18
|
return mode;
|
|
20
19
|
}
|
|
21
|
-
// try relative to cwd
|
|
22
20
|
const abs = join(cwd, mode);
|
|
23
21
|
if (existsSync(abs)) {
|
|
24
22
|
logger.success(`Binary found (custom path): ${abs}`);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { spawn as nodeSpawn } from "child_process";
|
|
2
2
|
import { execSync } from "child_process";
|
|
3
3
|
import { platform } from "os";
|
|
4
|
-
import { detectBinary
|
|
5
|
-
import logger from "../logger";
|
|
4
|
+
import { detectBinary } from "./detect.js";
|
|
5
|
+
import logger from "../logger.js";
|
|
6
6
|
|
|
7
|
-
let activeProcess
|
|
8
|
-
const extraProcesses
|
|
7
|
+
let activeProcess = null;
|
|
8
|
+
const extraProcesses = [];
|
|
9
9
|
|
|
10
|
-
const isBun = typeof
|
|
10
|
+
const isBun = typeof globalThis.Bun !== 'undefined';
|
|
11
11
|
|
|
12
|
-
export function killAllBrowsers()
|
|
12
|
+
export function killAllBrowsers() {
|
|
13
13
|
try {
|
|
14
14
|
logger.info('Cleaning up existing browser processes...');
|
|
15
15
|
if (platform() === 'win32') {
|
|
@@ -27,7 +27,7 @@ export function killAllBrowsers(): void {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export async function spawnBrowser(mode
|
|
30
|
+
export async function spawnBrowser(mode = 'headless') {
|
|
31
31
|
killAllBrowsers();
|
|
32
32
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
33
33
|
|
|
@@ -39,8 +39,7 @@ export async function spawnBrowser(mode: BinaryMode = 'headless'): Promise<strin
|
|
|
39
39
|
logger.info(`Spawning Nothing Browser (${mode}) from: ${binaryPath}`);
|
|
40
40
|
|
|
41
41
|
if (isBun) {
|
|
42
|
-
|
|
43
|
-
activeProcess = Bun.spawn([binaryPath], {
|
|
42
|
+
activeProcess = globalThis.Bun.spawn([binaryPath], {
|
|
44
43
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
45
44
|
env: process.env,
|
|
46
45
|
});
|
|
@@ -57,7 +56,7 @@ export async function spawnBrowser(mode: BinaryMode = 'headless'): Promise<strin
|
|
|
57
56
|
read();
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
activeProcess.exited.then((code
|
|
59
|
+
activeProcess.exited.then((code) => {
|
|
61
60
|
logger.warn(`Browser process exited with code: ${code}`);
|
|
62
61
|
activeProcess = null;
|
|
63
62
|
});
|
|
@@ -68,18 +67,18 @@ export async function spawnBrowser(mode: BinaryMode = 'headless'): Promise<strin
|
|
|
68
67
|
});
|
|
69
68
|
|
|
70
69
|
if (activeProcess.stdout) {
|
|
71
|
-
activeProcess.stdout.on('data', (data
|
|
70
|
+
activeProcess.stdout.on('data', (data) => {
|
|
72
71
|
logger.debug(`[Browser] ${data.toString()}`);
|
|
73
72
|
});
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
if (activeProcess.stderr) {
|
|
77
|
-
activeProcess.stderr.on('data', (data
|
|
76
|
+
activeProcess.stderr.on('data', (data) => {
|
|
78
77
|
logger.debug(`[Browser Error] ${data.toString()}`);
|
|
79
78
|
});
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
activeProcess.on('exit', (code
|
|
81
|
+
activeProcess.on('exit', (code) => {
|
|
83
82
|
logger.warn(`Browser process exited with code: ${code}`);
|
|
84
83
|
activeProcess = null;
|
|
85
84
|
});
|
|
@@ -96,10 +95,7 @@ export async function spawnBrowser(mode: BinaryMode = 'headless'): Promise<strin
|
|
|
96
95
|
return binaryPath;
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
export async function spawnBrowserOnSocket(
|
|
100
|
-
socketName: string,
|
|
101
|
-
mode: BinaryMode = 'headless'
|
|
102
|
-
): Promise<void> {
|
|
98
|
+
export async function spawnBrowserOnSocket(socketName, mode = 'headless') {
|
|
103
99
|
const binaryPath = detectBinary(mode);
|
|
104
100
|
if (!binaryPath) {
|
|
105
101
|
throw new Error(`Binary not found (${mode}). Cannot launch.`);
|
|
@@ -108,15 +104,14 @@ export async function spawnBrowserOnSocket(
|
|
|
108
104
|
logger.info(`Spawning browser (${mode}) on socket: ${socketName}`);
|
|
109
105
|
|
|
110
106
|
if (isBun) {
|
|
111
|
-
const
|
|
112
|
-
const proc = Bun.spawn([binaryPath], {
|
|
107
|
+
const proc = globalThis.Bun.spawn([binaryPath], {
|
|
113
108
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
114
109
|
env: { ...process.env, PIGGY_SOCKET: socketName },
|
|
115
110
|
});
|
|
116
111
|
|
|
117
112
|
extraProcesses.push(proc);
|
|
118
113
|
|
|
119
|
-
proc.exited.then((code
|
|
114
|
+
proc.exited.then((code) => {
|
|
120
115
|
logger.warn(`Browser on socket ${socketName} exited with code: ${code}`);
|
|
121
116
|
});
|
|
122
117
|
} else {
|
|
@@ -127,7 +122,7 @@ export async function spawnBrowserOnSocket(
|
|
|
127
122
|
|
|
128
123
|
extraProcesses.push(proc);
|
|
129
124
|
|
|
130
|
-
proc.on('exit', (code
|
|
125
|
+
proc.on('exit', (code) => {
|
|
131
126
|
logger.warn(`Browser on socket ${socketName} exited with code: ${code}`);
|
|
132
127
|
});
|
|
133
128
|
}
|
|
@@ -136,7 +131,7 @@ export async function spawnBrowserOnSocket(
|
|
|
136
131
|
logger.success(`Browser spawned (${mode}) on socket: ${socketName}`);
|
|
137
132
|
}
|
|
138
133
|
|
|
139
|
-
export function killBrowser()
|
|
134
|
+
export function killBrowser() {
|
|
140
135
|
if (activeProcess) {
|
|
141
136
|
logger.info('Killing browser process...');
|
|
142
137
|
if (isBun) {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
// piggy/media/index.
|
|
2
|
-
import { PiggyClient } from "../client";
|
|
1
|
+
// piggy/media/index.js
|
|
2
|
+
import { PiggyClient } from "../client.js";
|
|
3
3
|
import { writeFileSync, mkdirSync } from "fs";
|
|
4
4
|
import { dirname } from "path";
|
|
5
5
|
|
|
6
6
|
export class MediaClient {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
}
|
|
8
10
|
|
|
9
11
|
// ── Screenshot ────────────────────────────────────────────────────────────
|
|
10
12
|
|
|
11
|
-
async screenshot(filePath
|
|
12
|
-
const b64 = await this.client.send
|
|
13
|
+
async screenshot(filePath, tabId = "default") {
|
|
14
|
+
const b64 = await this.client.send("screenshot", { tabId });
|
|
13
15
|
if (filePath) {
|
|
14
16
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
15
17
|
writeFileSync(filePath, Buffer.from(b64, "base64"));
|
|
@@ -20,8 +22,8 @@ export class MediaClient {
|
|
|
20
22
|
|
|
21
23
|
// ── PDF ───────────────────────────────────────────────────────────────────
|
|
22
24
|
|
|
23
|
-
async pdf(filePath
|
|
24
|
-
const b64 = await this.client.send
|
|
25
|
+
async pdf(filePath, tabId = "default") {
|
|
26
|
+
const b64 = await this.client.send("pdf", { tabId });
|
|
25
27
|
if (filePath) {
|
|
26
28
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
27
29
|
writeFileSync(filePath, Buffer.from(b64, "base64"));
|
|
@@ -32,15 +34,15 @@ export class MediaClient {
|
|
|
32
34
|
|
|
33
35
|
// ── Image blocking ────────────────────────────────────────────────────────
|
|
34
36
|
|
|
35
|
-
blockImages(tabId = "default")
|
|
37
|
+
blockImages(tabId = "default") {
|
|
36
38
|
return this.client.send("intercept.block.images", { tabId });
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
unblockImages(tabId = "default")
|
|
41
|
+
unblockImages(tabId = "default") {
|
|
40
42
|
return this.client.send("intercept.unblock.images", { tabId });
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
export function createMediaAPI(client
|
|
46
|
+
export function createMediaAPI(client) {
|
|
45
47
|
return new MediaClient(client);
|
|
46
|
-
}
|
|
48
|
+
}
|
|
@@ -1,52 +1,54 @@
|
|
|
1
|
-
// piggy/navigation/index.
|
|
2
|
-
import { PiggyClient } from "../client";
|
|
1
|
+
// piggy/navigation/index.js
|
|
2
|
+
import { PiggyClient } from "../client.js";
|
|
3
3
|
|
|
4
4
|
export class NavigationClient {
|
|
5
|
-
constructor(
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
6
8
|
|
|
7
9
|
// ── Navigation ────────────────────────────────────────────────────────────
|
|
8
10
|
|
|
9
|
-
navigate(url
|
|
11
|
+
navigate(url, tabId = "default") {
|
|
10
12
|
return this.client.send("navigate", { url, tabId });
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
reload(tabId = "default")
|
|
15
|
+
reload(tabId = "default") {
|
|
14
16
|
return this.client.send("reload", { tabId });
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
goBack(tabId = "default")
|
|
19
|
+
goBack(tabId = "default") {
|
|
18
20
|
return this.client.send("go.back", { tabId });
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
goForward(tabId = "default")
|
|
23
|
+
goForward(tabId = "default") {
|
|
22
24
|
return this.client.send("go.forward", { tabId });
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
// ── Page info ─────────────────────────────────────────────────────────────
|
|
26
28
|
|
|
27
|
-
url(tabId = "default")
|
|
29
|
+
url(tabId = "default") {
|
|
28
30
|
return this.client.send("page.url", { tabId });
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
title(tabId = "default")
|
|
33
|
+
title(tabId = "default") {
|
|
32
34
|
return this.client.send("page.title", { tabId });
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
content(tabId = "default")
|
|
37
|
+
content(tabId = "default") {
|
|
36
38
|
return this.client.send("page.content", { tabId });
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
// ── Wait ──────────────────────────────────────────────────────────────────
|
|
40
42
|
|
|
41
|
-
waitForNavigation(tabId = "default")
|
|
43
|
+
waitForNavigation(tabId = "default") {
|
|
42
44
|
return this.client.send("wait.navigation", { tabId });
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
waitForSelector(selector
|
|
47
|
+
waitForSelector(selector, timeout = 10000, tabId = "default") {
|
|
46
48
|
return this.client.send("wait.selector", { selector, timeout, tabId });
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
export function createNavigationAPI(client
|
|
52
|
+
export function createNavigationAPI(client) {
|
|
51
53
|
return new NavigationClient(client);
|
|
52
|
-
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// piggy/pool/index.js
|
|
2
|
+
import { PiggyClient } from "../client.js";
|
|
3
|
+
import logger from "../logger.js";
|
|
4
|
+
|
|
5
|
+
export class TabPool {
|
|
6
|
+
#idle = [];
|
|
7
|
+
#busy = new Set();
|
|
8
|
+
#queue = [];
|
|
9
|
+
|
|
10
|
+
constructor(client, size, seedUrl, name) {
|
|
11
|
+
this.client = client;
|
|
12
|
+
this.size = size;
|
|
13
|
+
this.seedUrl = seedUrl;
|
|
14
|
+
this.name = name;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async init() {
|
|
18
|
+
for (let i = 0; i < this.size; i++) {
|
|
19
|
+
const tabId = await this.client.newTab();
|
|
20
|
+
await this.client.navigate(this.seedUrl, tabId);
|
|
21
|
+
this.#idle.push(tabId);
|
|
22
|
+
logger.success(`[${this.name}] pool tab ${i + 1}/${this.size} ready: ${tabId}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
acquire() {
|
|
27
|
+
return new Promise(resolve => {
|
|
28
|
+
const tabId = this.#idle.pop();
|
|
29
|
+
if (tabId) {
|
|
30
|
+
this.#busy.add(tabId);
|
|
31
|
+
resolve(tabId);
|
|
32
|
+
} else {
|
|
33
|
+
this.#queue.push(resolve);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
release(tabId) {
|
|
39
|
+
this.#busy.delete(tabId);
|
|
40
|
+
const next = this.#queue.shift();
|
|
41
|
+
if (next) {
|
|
42
|
+
this.#busy.add(tabId);
|
|
43
|
+
next(tabId);
|
|
44
|
+
} else {
|
|
45
|
+
this.#idle.push(tabId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async withTab(fn) {
|
|
50
|
+
logger.warn("[TabPool] withTab() is deprecated and will be removed in a later version — use the new tab API instead.");
|
|
51
|
+
const tabId = await this.acquire();
|
|
52
|
+
try {
|
|
53
|
+
return await fn(tabId);
|
|
54
|
+
} finally {
|
|
55
|
+
this.release(tabId);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async close() {
|
|
60
|
+
for (const tabId of [...this.#idle, ...this.#busy]) {
|
|
61
|
+
try { await this.client.closeTab(tabId); } catch {}
|
|
62
|
+
}
|
|
63
|
+
this.#idle = [];
|
|
64
|
+
this.#busy.clear();
|
|
65
|
+
this.#queue = [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get stats() {
|
|
69
|
+
return {
|
|
70
|
+
idle: this.#idle.length,
|
|
71
|
+
busy: this.#busy.size,
|
|
72
|
+
queued: this.#queue.length,
|
|
73
|
+
total: this.size,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// piggy/provide/index.js
|
|
2
|
+
import { PiggyClient } from "../client.js";
|
|
3
|
+
|
|
4
|
+
// ─── ProvideClient ────────────────────────────────────────────────────────────
|
|
5
|
+
// provide answers ONE question: "give me the actual value from this element."
|
|
6
|
+
// All methods take an options object { selector, parent? } so scoping is consistent.
|
|
7
|
+
// If you just want to know if something exists, use find instead.
|
|
8
|
+
|
|
9
|
+
export class ProvideClient {
|
|
10
|
+
constructor(client) {
|
|
11
|
+
this.client = client;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** innerText of the first matched element. */
|
|
15
|
+
text(opts, tabId = "default") {
|
|
16
|
+
return this.client.send("provide.text", { ...opts, tabId });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** innerText of all matched elements. */
|
|
20
|
+
textAll(opts, tabId = "default") {
|
|
21
|
+
return this.client.send("provide.textAll", { ...opts, tabId });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Single attribute value from the first matched element. */
|
|
25
|
+
attr(opts, tabId = "default") {
|
|
26
|
+
return this.client.send("provide.attr", { ...opts, tabId });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Attribute value from all matched elements. */
|
|
30
|
+
attrAll(opts, tabId = "default") {
|
|
31
|
+
return this.client.send("provide.attrAll", { ...opts, tabId });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** innerHTML of the first matched element. */
|
|
35
|
+
html(opts, tabId = "default") {
|
|
36
|
+
return this.client.send("provide.html", { ...opts, tabId });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Extract a table into headers + rows. */
|
|
40
|
+
table(opts, tabId = "default") {
|
|
41
|
+
return this.client.send("provide.table", { ...opts, tabId });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Extract a list of text items, optionally scoped to child items. */
|
|
45
|
+
list(opts, tabId = "default") {
|
|
46
|
+
return this.client.send("provide.list", { ...opts, tabId });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** All links inside the matched selector. */
|
|
50
|
+
links(opts, tabId = "default") {
|
|
51
|
+
return this.client.send("provide.links", { ...opts, tabId });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** All images inside the matched selector. */
|
|
55
|
+
images(opts, tabId = "default") {
|
|
56
|
+
return this.client.send("provide.images", { ...opts, tabId });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Form field name→value map. */
|
|
60
|
+
form(opts, tabId = "default") {
|
|
61
|
+
return this.client.send("provide.form", { ...opts, tabId });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Full page info: title, url, html, text. No selector needed. */
|
|
65
|
+
page(tabId = "default") {
|
|
66
|
+
return this.client.send("provide.page", { tabId });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Structured div tree: tag, id, cls, text, html, children[]. */
|
|
70
|
+
div(opts, tabId = "default") {
|
|
71
|
+
return this.client.send("provide.div", { ...opts, tabId });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** All <meta> name→content pairs. No selector needed. */
|
|
75
|
+
meta(tabId = "default") {
|
|
76
|
+
return this.client.send("provide.meta", { tabId });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** <select> current value + all options. */
|
|
80
|
+
select(opts, tabId = "default") {
|
|
81
|
+
return this.client.send("provide.select", { ...opts, tabId });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Parse JSON from element innerText or script[type=application/json].
|
|
86
|
+
* selector is optional — defaults to the first matching JSON script tag.
|
|
87
|
+
*/
|
|
88
|
+
json(opts, tabId = "default") {
|
|
89
|
+
return this.client.send("provide.json", { ...opts, tabId });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─── Factory helper ───────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
export function createProvideAPI(client) {
|
|
96
|
+
return new ProvideClient(client);
|
|
97
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// piggy/proxy/index.js
|
|
2
|
+
import { PiggyClient } from "../client.js";
|
|
3
|
+
|
|
4
|
+
export class ProxyClient {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Load proxies from a local file path. */
|
|
10
|
+
load(path) {
|
|
11
|
+
return this.client.send("proxy.load", { path });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Fetch proxies from a URL. Result comes via proxy:loaded / proxy:fetch:failed events. */
|
|
15
|
+
fetch(url) {
|
|
16
|
+
return this.client.send("proxy.fetch", { url });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Load an .ovpn config file. */
|
|
20
|
+
ovpn(path) {
|
|
21
|
+
return this.client.send("proxy.ovpn", { path });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Set a single proxy inline. */
|
|
25
|
+
set(opts) {
|
|
26
|
+
return this.client.send("proxy.set", opts);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Health-check all loaded proxies. Results come via events. */
|
|
30
|
+
test() {
|
|
31
|
+
return this.client.send("proxy.test", {});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Abort an in-progress health check. */
|
|
35
|
+
testStop() {
|
|
36
|
+
return this.client.send("proxy.test.stop", {});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Rotate to the next proxy in the pool. */
|
|
40
|
+
next() {
|
|
41
|
+
return this.client.send("proxy.next", {});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Alias for next(). */
|
|
45
|
+
rotate() {
|
|
46
|
+
return this.client.send("proxy.rotate", {});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Disable the proxy — use the real IP. */
|
|
50
|
+
disable() {
|
|
51
|
+
return this.client.send("proxy.disable", {});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Re-enable the current proxy. */
|
|
55
|
+
enable() {
|
|
56
|
+
return this.client.send("proxy.enable", {});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Get the current active proxy details. */
|
|
60
|
+
current() {
|
|
61
|
+
return this.client.send("proxy.current", {});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Get pool stats: total, alive, dead, index, active, checking. */
|
|
65
|
+
stats() {
|
|
66
|
+
return this.client.send("proxy.stats", {});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** List all proxies with health info. limit defaults to 500. */
|
|
70
|
+
list(limit) {
|
|
71
|
+
return this.client.send("proxy.list", { limit });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Set rotation mode and interval (seconds, only used for "timed"). */
|
|
75
|
+
rotation(mode, interval) {
|
|
76
|
+
return this.client.send("proxy.rotation", { mode, interval });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Set skipDead / autoCheck flags. */
|
|
80
|
+
config(opts) {
|
|
81
|
+
return this.client.send("proxy.config", opts);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Save the current proxy list to a file.
|
|
86
|
+
* filter: "all" | "alive" | "dead" — defaults to "all".
|
|
87
|
+
*/
|
|
88
|
+
save(path, filter) {
|
|
89
|
+
return this.client.send("proxy.save", { path, filter });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function createProxyAPI(client) {
|
|
94
|
+
return new ProxyClient(client);
|
|
95
|
+
}
|