nothing-browser 0.0.20 → 0.1.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 +1 -1
- package/dist/human/index.js +25 -1
- package/dist/launch/detect.js +13 -0
- package/dist/launch/spawn.js +13 -0
- package/dist/piggy/captcha/index.d.ts +39 -0
- package/dist/piggy/captcha/index.d.ts.map +1 -0
- package/dist/piggy/capture/index.d.ts +48 -0
- package/dist/piggy/capture/index.d.ts.map +1 -0
- package/dist/piggy/dialog/index.d.ts +28 -0
- package/dist/piggy/dialog/index.d.ts.map +1 -0
- package/dist/piggy/export/index.d.ts +62 -0
- package/dist/piggy/export/index.d.ts.map +1 -0
- package/dist/piggy/find/index.d.ts +90 -0
- package/dist/piggy/find/index.d.ts.map +1 -0
- package/dist/piggy/http/index.d.ts +14 -0
- package/dist/piggy/http/index.d.ts.map +1 -0
- package/dist/piggy/human/index.d.ts +36 -4
- package/dist/piggy/human/index.d.ts.map +1 -1
- package/dist/piggy/iframe/index.d.ts +53 -0
- package/dist/piggy/iframe/index.d.ts.map +1 -0
- package/dist/piggy/interactions/index.d.ts +24 -0
- package/dist/piggy/interactions/index.d.ts.map +1 -0
- package/dist/piggy/launch/detect.d.ts +1 -1
- package/dist/piggy/launch/detect.d.ts.map +1 -1
- package/dist/piggy/launch/spawn.d.ts.map +1 -1
- package/dist/piggy/media/index.d.ts +11 -0
- package/dist/piggy/media/index.d.ts.map +1 -0
- package/dist/piggy/navigation/index.d.ts +16 -0
- package/dist/piggy/navigation/index.d.ts.map +1 -0
- package/dist/piggy/provide/index.d.ts +81 -0
- package/dist/piggy/provide/index.d.ts.map +1 -0
- package/dist/piggy/proxy/index.d.ts +94 -0
- package/dist/piggy/proxy/index.d.ts.map +1 -0
- package/dist/piggy/register/index.d.ts.map +1 -1
- package/dist/piggy/router/index.d.ts +38 -0
- package/dist/piggy/router/index.d.ts.map +1 -0
- package/dist/piggy/session/index.d.ts +27 -0
- package/dist/piggy/session/index.d.ts.map +1 -0
- package/dist/piggy/tabs/index.d.ts +10 -0
- package/dist/piggy/tabs/index.d.ts.map +1 -0
- package/dist/piggy/wait/index.d.ts +28 -0
- package/dist/piggy/wait/index.d.ts.map +1 -0
- package/dist/piggy.d.ts.map +1 -1
- package/dist/piggy.js +914 -181
- package/dist/register/index.js +39 -86
- package/package.json +1 -1
- package/piggy/captcha/index.d.ts +35 -0
- package/piggy/captcha/index.ts +93 -0
- package/piggy/capture/index.ts +76 -0
- package/piggy/dialog/index.d.ts +29 -0
- package/piggy/dialog/index.ts +85 -0
- package/piggy/export/index.d.ts +117 -0
- package/piggy/export/index.ts +147 -0
- package/piggy/find/index.d.ts +79 -0
- package/piggy/find/index.ts +165 -0
- package/piggy/http/index.ts +65 -0
- package/piggy/human/index.ts +115 -53
- package/piggy/iframe/index.ts +79 -0
- package/piggy/interactions/index.ts +79 -0
- package/piggy/launch/detect.ts +19 -2
- package/piggy/launch/spawn.ts +1 -8
- package/piggy/media/index.ts +46 -0
- package/piggy/navigation/index.ts +52 -0
- package/piggy/provide/index.ts +144 -0
- package/piggy/proxy/index.ts +154 -0
- package/piggy/register/index.ts +41 -59
- package/piggy/router/index.ts +69 -0
- package/piggy/session/index.ts +76 -0
- package/piggy/tabs/index.ts +22 -0
- package/piggy/wait/index.ts +90 -0
- package/piggy.ts +94 -39
- package/dist/piggy/open/index.d.ts +0 -4
- package/dist/piggy/open/index.d.ts.map +0 -1
- package/piggy/open/index.d.ts +0 -4
- package/piggy/open/index.d.ts.map +0 -1
- package/piggy/open/index.ts +0 -5
package/piggy/register/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// piggy/register/index.ts
|
|
2
2
|
import { PiggyClient } from "../client";
|
|
3
|
+
import { HumanClient } from "../human";
|
|
3
4
|
import logger from "../logger";
|
|
4
5
|
import { routeRegistry, keepAliveSites, type RouteHandler, type BeforeMiddleware, type RouteDetail } from "../server";
|
|
5
|
-
import { randomDelay, humanTypeSequence } from "../human";
|
|
6
6
|
import { buildRespondScript, buildModifyResponseScript } from "../intercept/scripts";
|
|
7
7
|
import { storeRecord } from "../store";
|
|
8
8
|
import { TabPool } from "../pool";
|
|
@@ -37,8 +37,6 @@ export function createSiteObject(
|
|
|
37
37
|
let _currentUrl: string = registeredUrl;
|
|
38
38
|
let _modifyRuleCounter = 0;
|
|
39
39
|
|
|
40
|
-
// ── helpers ────────────────────────────────────────────────────────────────
|
|
41
|
-
// If pool exists, run fn with a pool tab. Otherwise use the fixed tabId.
|
|
42
40
|
function withTab<T>(fn: (t: string) => Promise<T>): Promise<T> {
|
|
43
41
|
return pool ? pool.withTab(fn) : fn(tabId);
|
|
44
42
|
}
|
|
@@ -69,10 +67,8 @@ export function createSiteObject(
|
|
|
69
67
|
_tabId: tabId,
|
|
70
68
|
_pool: pool ?? null,
|
|
71
69
|
|
|
72
|
-
// ── Pool stats ────────────────────────────────────────────────────────────
|
|
73
70
|
poolStats: () => pool?.stats ?? null,
|
|
74
71
|
|
|
75
|
-
// ── Navigation ────────────────────────────────────────────────────────────
|
|
76
72
|
navigate: (url?: string, opts?: { retries?: number }) => {
|
|
77
73
|
const target = url ?? registeredUrl;
|
|
78
74
|
return withTab(t =>
|
|
@@ -115,7 +111,6 @@ export function createSiteObject(
|
|
|
115
111
|
waitForResponse: (pattern: string, timeout = 30000) =>
|
|
116
112
|
withTab(t => client.waitForResponse(pattern, timeout, t)),
|
|
117
113
|
|
|
118
|
-
// ── Init Script ───────────────────────────────────────────────────────────
|
|
119
114
|
addInitScript: async (js: string | (() => void)) => {
|
|
120
115
|
const code = typeof js === "function" ? `(${js.toString()})();` : js;
|
|
121
116
|
await withTab(t => client.addInitScript(code, t));
|
|
@@ -123,7 +118,6 @@ export function createSiteObject(
|
|
|
123
118
|
return site;
|
|
124
119
|
},
|
|
125
120
|
|
|
126
|
-
// ── Events ────────────────────────────────────────────────────────────────
|
|
127
121
|
on: (event: string, handler: (data: any) => void): (() => void) => {
|
|
128
122
|
if (!_eventListeners.has(event)) _eventListeners.set(event, new Set());
|
|
129
123
|
_eventListeners.get(event)!.add(handler);
|
|
@@ -138,12 +132,11 @@ export function createSiteObject(
|
|
|
138
132
|
_eventListeners.get(event)?.delete(handler);
|
|
139
133
|
},
|
|
140
134
|
|
|
141
|
-
// ── Interactions ──────────────────────────────────────────────────────────
|
|
142
135
|
click: (selector: string, opts?: { retries?: number; timeout?: number }) =>
|
|
143
136
|
withErrScreen(() =>
|
|
144
137
|
withTab(t =>
|
|
145
138
|
retry(name, async () => {
|
|
146
|
-
if (humanMode) await
|
|
139
|
+
if (humanMode) await new Promise(r => setTimeout(r, 80 + Math.random() * 140));
|
|
147
140
|
await client.waitForSelector(selector, opts?.timeout ?? 15000, t);
|
|
148
141
|
const ok = await client.click(selector, t);
|
|
149
142
|
if (!ok) throw new Error(`click failed: ${selector}`);
|
|
@@ -157,7 +150,7 @@ export function createSiteObject(
|
|
|
157
150
|
doubleClick: (selector: string) =>
|
|
158
151
|
withErrScreen(() =>
|
|
159
152
|
withTab(async t => {
|
|
160
|
-
if (humanMode) await
|
|
153
|
+
if (humanMode) await new Promise(r => setTimeout(r, 80 + Math.random() * 120));
|
|
161
154
|
return client.doubleClick(selector, t);
|
|
162
155
|
}),
|
|
163
156
|
`dblclick(${selector})`
|
|
@@ -166,52 +159,50 @@ export function createSiteObject(
|
|
|
166
159
|
hover: (selector: string) =>
|
|
167
160
|
withErrScreen(() =>
|
|
168
161
|
withTab(async t => {
|
|
169
|
-
if (humanMode) await
|
|
162
|
+
if (humanMode) await new Promise(r => setTimeout(r, 50 + Math.random() * 100));
|
|
170
163
|
return client.hover(selector, t);
|
|
171
164
|
}),
|
|
172
165
|
`hover(${selector})`
|
|
173
166
|
),
|
|
174
167
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
168
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
169
|
+
// type – uses HumanClient when humanMode is true, otherwise basic client.type
|
|
170
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
171
|
+
type: (selector: string, text: string, opts?: { delay?: number; retries?: number; clear?: boolean; speed?: number }) =>
|
|
172
|
+
withErrScreen(() =>
|
|
173
|
+
withTab(async t => {
|
|
174
|
+
await client.waitForSelector(selector, 30000, t);
|
|
175
|
+
|
|
176
|
+
if (humanMode) {
|
|
177
|
+
const human = new HumanClient(client);
|
|
178
|
+
await human.type({
|
|
179
|
+
selector,
|
|
180
|
+
text,
|
|
181
|
+
clear: opts?.clear ?? false,
|
|
182
|
+
speed: opts?.speed
|
|
183
|
+
}, t);
|
|
184
|
+
} else {
|
|
185
|
+
// Fallback to basic type (with optional clear)
|
|
186
|
+
if (opts?.clear) {
|
|
187
|
+
await client.evaluate(`
|
|
188
|
+
const el = document.querySelector('${selector.replace(/'/g, "\\'")}');
|
|
189
|
+
if (el) { el.value = ''; el.dispatchEvent(new Event('input', { bubbles: true })); }
|
|
190
|
+
`, t);
|
|
191
|
+
}
|
|
192
|
+
await client.type(selector, text, t);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Fire blur to trigger reactive frameworks
|
|
185
196
|
await client.evaluate(`
|
|
186
|
-
(
|
|
187
|
-
const el = document.querySelector('${selector}');
|
|
188
|
-
const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
|
|
189
|
-
nativeSetter.call(el, '${current.replace(/'/g, "\\'")}');
|
|
190
|
-
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
191
|
-
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
192
|
-
})()
|
|
197
|
+
document.querySelector('${selector.replace(/'/g, "\\'")}')?.dispatchEvent(new Event('blur', { bubbles: true }));
|
|
193
198
|
`, t);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
await new Promise(r => setTimeout(r, opts.delay));
|
|
202
|
-
}
|
|
203
|
-
} else {
|
|
204
|
-
await client.type(selector, text, t);
|
|
205
|
-
}
|
|
206
|
-
// fire blur so Phoenix/Angular/React pick up the final value
|
|
207
|
-
await client.evaluate(`
|
|
208
|
-
document.querySelector('${selector}').dispatchEvent(new Event('blur', { bubbles: true }))
|
|
209
|
-
`, t);
|
|
210
|
-
logger.success(`[${name}] typed into: ${selector}`);
|
|
211
|
-
return true;
|
|
212
|
-
}),
|
|
213
|
-
`type(${selector})`
|
|
214
|
-
),
|
|
199
|
+
|
|
200
|
+
logger.success(`[${name}] typed into: ${selector}`);
|
|
201
|
+
return true;
|
|
202
|
+
}),
|
|
203
|
+
`type(${selector})`
|
|
204
|
+
),
|
|
205
|
+
|
|
215
206
|
select: (selector: string, value: string) => withTab(t => client.select(selector, value, t)),
|
|
216
207
|
|
|
217
208
|
evaluate: (js: string | (() => any), ...args: any[]) => {
|
|
@@ -240,7 +231,7 @@ export function createSiteObject(
|
|
|
240
231
|
const chunk = px / steps;
|
|
241
232
|
for (let i = 0; i < steps; i++) {
|
|
242
233
|
await client.scrollBy(chunk, t);
|
|
243
|
-
await
|
|
234
|
+
await new Promise(r => setTimeout(r, 30 + Math.random() * 50));
|
|
244
235
|
}
|
|
245
236
|
} else {
|
|
246
237
|
await client.scrollBy(px, t);
|
|
@@ -248,7 +239,6 @@ export function createSiteObject(
|
|
|
248
239
|
}) as Promise<void>,
|
|
249
240
|
},
|
|
250
241
|
|
|
251
|
-
// ── Fetch ─────────────────────────────────────────────────────────────────
|
|
252
242
|
fetchText: (selector: string) => withTab(t => client.fetchText(selector, t)),
|
|
253
243
|
|
|
254
244
|
fetchLinks: async (selector: string) => {
|
|
@@ -268,7 +258,6 @@ export function createSiteObject(
|
|
|
268
258
|
id: (query: string) => withTab(t => client.searchId(query, t)),
|
|
269
259
|
},
|
|
270
260
|
|
|
271
|
-
// ── Screenshot / PDF ──────────────────────────────────────────────────────
|
|
272
261
|
screenshot: async (filePath?: string) => {
|
|
273
262
|
const r = await withTab(t => client.screenshot(filePath, t));
|
|
274
263
|
logger.success(`[${name}] screenshot → ${filePath ?? "base64"}`);
|
|
@@ -284,7 +273,6 @@ export function createSiteObject(
|
|
|
284
273
|
blockImages: () => withTab(async t => { await client.blockImages(t); logger.info(`[${name}] images blocked`); }),
|
|
285
274
|
unblockImages: () => withTab(async t => { await client.unblockImages(t); logger.info(`[${name}] images unblocked`); }),
|
|
286
275
|
|
|
287
|
-
// ── Cookies ───────────────────────────────────────────────────────────────
|
|
288
276
|
cookies: {
|
|
289
277
|
set: async (cookieName: string, value: string, domain: string, path = "/") => {
|
|
290
278
|
await withTab(t => client.setCookie(cookieName, value, domain, path, t));
|
|
@@ -298,7 +286,6 @@ export function createSiteObject(
|
|
|
298
286
|
list: () => withTab(t => client.listCookies(t)),
|
|
299
287
|
},
|
|
300
288
|
|
|
301
|
-
// ── Interception ──────────────────────────────────────────────────────────
|
|
302
289
|
intercept: {
|
|
303
290
|
block: async (pattern: string) => {
|
|
304
291
|
await withTab(t => client.addInterceptRule("block", pattern, {}, t));
|
|
@@ -399,7 +386,6 @@ export function createSiteObject(
|
|
|
399
386
|
},
|
|
400
387
|
},
|
|
401
388
|
|
|
402
|
-
// ── Network capture ───────────────────────────────────────────────────────
|
|
403
389
|
capture: {
|
|
404
390
|
start: () => withTab(async t => { await client.captureStart(t); logger.info(`[${name}] capture started`); }),
|
|
405
391
|
stop: () => withTab(async t => { await client.captureStop(t); logger.info(`[${name}] capture stopped`); }),
|
|
@@ -410,7 +396,6 @@ export function createSiteObject(
|
|
|
410
396
|
clear: () => withTab(async t => { await client.captureClear(t); logger.info(`[${name}] capture cleared`); }),
|
|
411
397
|
},
|
|
412
398
|
|
|
413
|
-
// ── Session ───────────────────────────────────────────────────────────────
|
|
414
399
|
session: {
|
|
415
400
|
export: async () => {
|
|
416
401
|
const data = await withTab(t => client.sessionExport(t));
|
|
@@ -423,7 +408,6 @@ export function createSiteObject(
|
|
|
423
408
|
},
|
|
424
409
|
},
|
|
425
410
|
|
|
426
|
-
// ── Expose Function ───────────────────────────────────────────────────────
|
|
427
411
|
exposeFunction: async (fnName: string, handler: (data: any) => Promise<any> | any) => {
|
|
428
412
|
await client.exposeFunction(fnName, handler, tabId);
|
|
429
413
|
logger.success(`[${name}] exposed function: ${fnName}`);
|
|
@@ -447,7 +431,6 @@ export function createSiteObject(
|
|
|
447
431
|
return site;
|
|
448
432
|
},
|
|
449
433
|
|
|
450
|
-
// ── Store ─────────────────────────────────────────────────────────────────
|
|
451
434
|
store: async (
|
|
452
435
|
data: Record<string, any> | Record<string, any>[],
|
|
453
436
|
schemaName?: string
|
|
@@ -458,7 +441,6 @@ export function createSiteObject(
|
|
|
458
441
|
return result;
|
|
459
442
|
},
|
|
460
443
|
|
|
461
|
-
// ── Elysia API ────────────────────────────────────────────────────────────
|
|
462
444
|
api: (
|
|
463
445
|
path: string,
|
|
464
446
|
handler: RouteHandler,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// piggy/router/index.ts
|
|
2
|
+
// Mirrors PiggyCommandRouter.cpp.
|
|
3
|
+
// This is the single entry point that composes all sub-clients
|
|
4
|
+
// into one object — the same way the C++ router dispatches to sub-handlers.
|
|
5
|
+
|
|
6
|
+
import { PiggyClient } from "../client";
|
|
7
|
+
import { CaptureClient, createCaptureAPI } from "../capture";
|
|
8
|
+
import { CaptchaClient, createCaptchaAPI } from "../captcha";
|
|
9
|
+
import { DialogClient, createDialogAPI } from "../dialog";
|
|
10
|
+
import { ExportClient, createExportAPI } from "../export";
|
|
11
|
+
import { FindClient, createFindAPI } from "../find";
|
|
12
|
+
import { HumanClient, createHumanAPI } from "../human";
|
|
13
|
+
import { IframeClient, createIframeAPI } from "../iframe";
|
|
14
|
+
import { InteractionsClient, createInteractionsAPI } from "../interactions";
|
|
15
|
+
import { MediaClient, createMediaAPI } from "../media";
|
|
16
|
+
import { NavigationClient, createNavigationAPI } from "../navigation";
|
|
17
|
+
import { ProvideClient, createProvideAPI } from "../provide";
|
|
18
|
+
import { ProxyClient, createProxyAPI } from "../proxy";
|
|
19
|
+
import { SessionClient, createSessionAPI } from "../session";
|
|
20
|
+
import { TabsClient, createTabsAPI } from "../tabs";
|
|
21
|
+
import { WaitClient, EvaluateClient, FetchClient, createWaitAPI, createEvaluateAPI, createFetchAPI } from "../wait";
|
|
22
|
+
|
|
23
|
+
export interface PiggyRouter {
|
|
24
|
+
// Core transport
|
|
25
|
+
client: PiggyClient;
|
|
26
|
+
|
|
27
|
+
// Sub-routers — 1:1 with C++ files
|
|
28
|
+
tabs: TabsClient;
|
|
29
|
+
navigation: NavigationClient;
|
|
30
|
+
interactions: InteractionsClient;
|
|
31
|
+
media: MediaClient;
|
|
32
|
+
capture: CaptureClient;
|
|
33
|
+
find: FindClient;
|
|
34
|
+
provide: ProvideClient;
|
|
35
|
+
wait: WaitClient;
|
|
36
|
+
evaluate: EvaluateClient;
|
|
37
|
+
fetch: FetchClient;
|
|
38
|
+
proxy: ProxyClient;
|
|
39
|
+
captcha: CaptchaClient;
|
|
40
|
+
dialog: DialogClient;
|
|
41
|
+
human: HumanClient;
|
|
42
|
+
iframe: IframeClient;
|
|
43
|
+
session: SessionClient;
|
|
44
|
+
export: ExportClient;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function createRouter(client: PiggyClient): PiggyRouter {
|
|
48
|
+
return {
|
|
49
|
+
client,
|
|
50
|
+
tabs: createTabsAPI(client),
|
|
51
|
+
navigation: createNavigationAPI(client),
|
|
52
|
+
interactions: createInteractionsAPI(client),
|
|
53
|
+
media: createMediaAPI(client),
|
|
54
|
+
capture: createCaptureAPI(client),
|
|
55
|
+
find: createFindAPI(client),
|
|
56
|
+
provide: createProvideAPI(client),
|
|
57
|
+
wait: createWaitAPI(client),
|
|
58
|
+
evaluate: createEvaluateAPI(client),
|
|
59
|
+
fetch: createFetchAPI(client),
|
|
60
|
+
proxy: createProxyAPI(client),
|
|
61
|
+
captcha: createCaptchaAPI(client),
|
|
62
|
+
dialog: createDialogAPI(client),
|
|
63
|
+
human: createHumanAPI(client),
|
|
64
|
+
iframe: createIframeAPI(client),
|
|
65
|
+
session: createSessionAPI(client),
|
|
66
|
+
export: createExportAPI(client),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// piggy/session/index.ts
|
|
2
|
+
import { PiggyClient } from "../client";
|
|
3
|
+
import type { CookieSetOptions, CookieDeleteOptions } from "../export";
|
|
4
|
+
|
|
5
|
+
export interface SessionPaths {
|
|
6
|
+
workDir: string;
|
|
7
|
+
cookies: string;
|
|
8
|
+
profile: string;
|
|
9
|
+
ws: string;
|
|
10
|
+
pings: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class SessionClient {
|
|
14
|
+
constructor(private client: PiggyClient) {}
|
|
15
|
+
|
|
16
|
+
// Session lifecycle
|
|
17
|
+
reload(tabId = "default"): Promise<void> {
|
|
18
|
+
return this.client.send("session.reload", { tabId });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Paths
|
|
22
|
+
paths(): Promise<SessionPaths> {
|
|
23
|
+
return this.client.send("session.paths", {});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
cookiesPath(): Promise<string> {
|
|
27
|
+
return this.client.send("session.cookies.path", {});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
profilePath(): Promise<string> {
|
|
31
|
+
return this.client.send("session.profile.path", {});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
wsPath(): Promise<string> {
|
|
35
|
+
return this.client.send("session.ws.path", {});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pingsPath(): Promise<string> {
|
|
39
|
+
return this.client.send("session.pings.path", {});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Opt-in persistence
|
|
43
|
+
setWsSave(enabled: boolean): Promise<void> {
|
|
44
|
+
return this.client.send("session.ws.save", { enabled });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setPingsSave(enabled: boolean): Promise<void> {
|
|
48
|
+
return this.client.send("session.pings.save", { enabled });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Export / import
|
|
52
|
+
async export(tabId = "default"): Promise<any> {
|
|
53
|
+
const raw = await this.client.send<string>("session.export", { tabId });
|
|
54
|
+
return typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
import(data: any, tabId = "default"): Promise<void> {
|
|
58
|
+
return this.client.send("session.import", {
|
|
59
|
+
data: JSON.stringify(data),
|
|
60
|
+
tabId,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Cookies (using imported types from export)
|
|
65
|
+
setCookie(opts: CookieSetOptions, tabId = "default"): Promise<void> {
|
|
66
|
+
return this.client.send("cookie.set", { ...opts, tabId });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
deleteCookie(opts: CookieDeleteOptions, tabId = "default"): Promise<void> {
|
|
70
|
+
return this.client.send("cookie.delete", { ...opts, tabId });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createSessionAPI(client: PiggyClient): SessionClient {
|
|
75
|
+
return new SessionClient(client);
|
|
76
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// piggy/tabs/index.ts
|
|
2
|
+
import { PiggyClient } from "../client";
|
|
3
|
+
|
|
4
|
+
export class TabsClient {
|
|
5
|
+
constructor(private client: PiggyClient) {}
|
|
6
|
+
|
|
7
|
+
new(): Promise<string> {
|
|
8
|
+
return this.client.send("tab.new", {});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
close(tabId: string): Promise<void> {
|
|
12
|
+
return this.client.send("tab.close", { tabId });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
list(): Promise<string[]> {
|
|
16
|
+
return this.client.send("tab.list", {});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createTabsAPI(client: PiggyClient): TabsClient {
|
|
21
|
+
return new TabsClient(client);
|
|
22
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// piggy/wait/index.ts
|
|
2
|
+
import { PiggyClient } from "../client";
|
|
3
|
+
|
|
4
|
+
export type WaitSelectorState = "attached" | "detached" | "visible" | "hidden";
|
|
5
|
+
|
|
6
|
+
// ─── WaitClient ───────────────────────────────────────────────────────────────
|
|
7
|
+
// Maps to PiggyWait.cpp
|
|
8
|
+
|
|
9
|
+
export class WaitClient {
|
|
10
|
+
constructor(private client: PiggyClient) {}
|
|
11
|
+
|
|
12
|
+
// wait.function — poll every 100ms until JS expr is truthy
|
|
13
|
+
function(js: string, timeout = 10000, tabId = "default"): Promise<void> {
|
|
14
|
+
return this.client.send("wait.function", { js, timeout, tabId });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// wait.selector — with full state support (attached|detached|visible|hidden)
|
|
18
|
+
selector(
|
|
19
|
+
selector: string,
|
|
20
|
+
state: WaitSelectorState = "attached",
|
|
21
|
+
timeout = 10000,
|
|
22
|
+
tabId = "default"
|
|
23
|
+
): Promise<void> {
|
|
24
|
+
return this.client.send("wait.selector", { selector, state, timeout, tabId });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ─── EvaluateClient ───────────────────────────────────────────────────────────
|
|
29
|
+
// Maps to the evaluate command in PiggyWait.cpp (with timeout support)
|
|
30
|
+
// and PiggyInteractions.cpp (without timeout)
|
|
31
|
+
|
|
32
|
+
export class EvaluateClient {
|
|
33
|
+
constructor(private client: PiggyClient) {}
|
|
34
|
+
|
|
35
|
+
// evaluate with optional wall-clock timeout
|
|
36
|
+
run(js: string, timeout?: number, tabId = "default"): Promise<unknown> {
|
|
37
|
+
return this.client.send("evaluate", {
|
|
38
|
+
js,
|
|
39
|
+
tabId,
|
|
40
|
+
...(timeout !== undefined ? { timeout } : {}),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ─── FetchClient ──────────────────────────────────────────────────────────────
|
|
46
|
+
// Maps to fetch.textAll / fetch.attr / fetch.attrAll in PiggyWait.cpp
|
|
47
|
+
// and fetch.text / fetch.links / fetch.image in PiggyExport.cpp
|
|
48
|
+
|
|
49
|
+
export class FetchClient {
|
|
50
|
+
constructor(private client: PiggyClient) {}
|
|
51
|
+
|
|
52
|
+
// fetch.text — single element innerText
|
|
53
|
+
text(selector: string, tabId = "default"): Promise<string | null> {
|
|
54
|
+
return this.client.send("fetch.text", { query: selector, tabId });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// fetch.textAll — all matching elements innerText
|
|
58
|
+
textAll(selector: string, tabId = "default"): Promise<string[]> {
|
|
59
|
+
return this.client.send("fetch.textAll", { selector, tabId });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// fetch.attr — single attribute from first match
|
|
63
|
+
attr(selector: string, attr: string, tabId = "default"): Promise<string | null> {
|
|
64
|
+
return this.client.send("fetch.attr", { selector, attr, tabId });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// fetch.attrAll — attribute from all matches
|
|
68
|
+
attrAll(selector: string, attr: string, tabId = "default"): Promise<string[]> {
|
|
69
|
+
return this.client.send("fetch.attrAll", { selector, attr, tabId });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// fetch.links — links inside a selector
|
|
73
|
+
links(selector: string, tabId = "default"): Promise<string[]> {
|
|
74
|
+
return this.client.send("fetch.links", { query: selector, tabId });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// fetch.links.all — all links on page
|
|
78
|
+
linksAll(tabId = "default"): Promise<string[]> {
|
|
79
|
+
return this.client.send("fetch.links.all", { tabId });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// fetch.image — images inside a selector
|
|
83
|
+
images(selector: string, tabId = "default"): Promise<string[]> {
|
|
84
|
+
return this.client.send("fetch.image", { query: selector, tabId });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function createWaitAPI(client: PiggyClient): WaitClient { return new WaitClient(client); }
|
|
89
|
+
export function createEvaluateAPI(client: PiggyClient): EvaluateClient { return new EvaluateClient(client); }
|
|
90
|
+
export function createFetchAPI(client: PiggyClient): FetchClient { return new FetchClient(client); }
|