nothing-browser 0.1.1 → 0.1.2

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.
@@ -1,4 +1,4 @@
1
- // piggy/client/index.ts
1
+ //piggy/client/index.ts
2
2
  import { connect, type Socket } from "net";
3
3
  import { writeFileSync, mkdirSync } from "fs";
4
4
  import { dirname } from "path";
@@ -280,6 +280,23 @@ export class PiggyClient {
280
280
  }
281
281
  }
282
282
  }
283
+
284
+ if (event.event === "dialog") {
285
+ const key = `dialog:${event.tabId ?? "default"}`;
286
+ const handlers = this.globalEventHandlers.get(key);
287
+ if (handlers) {
288
+ for (const h of handlers) {
289
+ try {
290
+ h({
291
+ dialogType: event.dialogType,
292
+ message: event.message,
293
+ defaultValue: event.defaultValue,
294
+ tabId: event.tabId,
295
+ });
296
+ } catch (e) { logger.error(`dialog handler error: ${e}`); }
297
+ }
298
+ }
299
+ }
283
300
  }
284
301
 
285
302
  onEvent(eventName: string, tabId: string, handler: (data: any) => void): () => void {
@@ -384,9 +401,9 @@ export class PiggyClient {
384
401
 
385
402
  // ── Cookies ───────────────────────────────────────────────────────────────
386
403
  async setCookie(name: string, value: string, domain: string, path = "/", tabId = "default"): Promise<void> { await this.send("cookie.set", { name, value, domain, path, tabId }); }
387
- async getCookie(name: string, tabId = "default"): Promise<any> { return this.send("cookie.get", { name, tabId }); }
388
- async deleteCookie(name: string, tabId = "default"): Promise<void> { await this.send("cookie.delete", { name, tabId }); }
389
- async listCookies(tabId = "default"): Promise<any[]> { return this.send<any[]>("cookie.list", { tabId }); }
404
+ async getCookie(name: string, domain = "", tabId = "default"): Promise<any> { return this.send("cookie.get", { name, domain, tabId }); }
405
+ async deleteCookie(name: string, domain: string, tabId = "default"): Promise<void> { await this.send("cookie.delete", { name, domain, tabId }); }
406
+ async listCookies(domain = "", tabId = "default"): Promise<any[]> { return this.send<any[]>("cookie.list", { domain, tabId }); }
390
407
 
391
408
  // ── Interception ──────────────────────────────────────────────────────────
392
409
  async addInterceptRule(action: "block" | "redirect" | "modifyHeaders", pattern: string, options: { redirectUrl?: string; headers?: Record<string, string> } = {}, tabId = "default"): Promise<void> {
@@ -407,55 +424,14 @@ export class PiggyClient {
407
424
  async sessionExport(tabId = "default"): Promise<any> { return this.send("session.export", { tabId }); }
408
425
  async sessionImport(data: any, tabId = "default"): Promise<void> { await this.send("session.import", { data, tabId }); }
409
426
 
410
- // ── Session persistence (opt-in) ──────────────────────────────────────────
411
- // WS frames and pings are NOT saved by default you must opt in.
412
- // Files are written to cwd (same folder as cookies.json / profile.json).
413
-
414
- /** Enable or disable saving WebSocket frames to ws.json in cwd */
415
- async sessionWsSave(enabled = true): Promise<void> {
416
- await this.send("session.ws.save", { enabled });
417
- }
418
-
419
- /** Enable or disable saving ping log to pings.json in cwd */
420
- async sessionPingsSave(enabled = true): Promise<void> {
421
- await this.send("session.pings.save", { enabled });
422
- }
423
-
424
- /** Get all data file paths for the current session */
425
- async sessionPaths(): Promise<{
426
- workDir: string;
427
- cookies: string;
428
- profile: string;
429
- ws: string;
430
- pings: string;
431
- }> {
432
- return this.send("session.paths", {});
433
- }
434
-
435
- /** Get path to cookies.json */
436
- async sessionCookiesPath(): Promise<string> {
437
- return this.send("session.cookies.path", {});
438
- }
439
-
440
- /** Get path to profile.json */
441
- async sessionProfilePath(): Promise<string> {
442
- return this.send("session.profile.path", {});
443
- }
444
-
445
- /** Get path to ws.json */
446
- async sessionWsPath(): Promise<string> {
447
- return this.send("session.ws.path", {});
448
- }
449
-
450
- /** Get path to pings.json */
451
- async sessionPingsPath(): Promise<string> {
452
- return this.send("session.pings.path", {});
453
- }
454
-
455
- /** Reload cookies.json and profile.json from disk without restarting */
456
- async sessionReload(): Promise<void> {
457
- await this.send("session.reload", {});
458
- }
427
+ async sessionWsSave(enabled = true): Promise<void> { await this.send("session.ws.save", { enabled }); }
428
+ async sessionPingsSave(enabled = true): Promise<void> { await this.send("session.pings.save", { enabled }); }
429
+ async sessionPaths(): Promise<{ workDir: string; cookies: string; profile: string; ws: string; pings: string; }> { return this.send("session.paths", {}); }
430
+ async sessionCookiesPath(): Promise<string> { return this.send("session.cookies.path", {}); }
431
+ async sessionProfilePath(): Promise<string> { return this.send("session.profile.path", {}); }
432
+ async sessionWsPath(): Promise<string> { return this.send("session.ws.path", {}); }
433
+ async sessionPingsPath(): Promise<string> { return this.send("session.pings.path", {}); }
434
+ async sessionReload(): Promise<void> { await this.send("session.reload", {}); }
459
435
 
460
436
  // ── Expose Function ───────────────────────────────────────────────────────
461
437
  async exposeFunction(name: string, handler: (data: any) => Promise<any> | any, tabId = "default"): Promise<void> {
@@ -485,82 +461,28 @@ export class PiggyClient {
485
461
  }
486
462
 
487
463
  // ── Proxy ─────────────────────────────────────────────────────────────────
488
-
489
- async proxyLoad(path: string): Promise<void> {
490
- await this.send("proxy.load", { path });
491
- }
492
-
493
- async proxyFetch(url: string): Promise<void> {
494
- await this.send("proxy.fetch", { url });
495
- }
496
-
497
- async proxyOvpn(path: string): Promise<void> {
498
- await this.send("proxy.ovpn", { path });
499
- }
464
+ async proxyLoad(path: string): Promise<void> { await this.send("proxy.load", { path }); }
465
+ async proxyFetch(url: string): Promise<void> { await this.send("proxy.fetch", { url }); }
466
+ async proxyOvpn(path: string): Promise<void> { await this.send("proxy.ovpn", { path }); }
500
467
 
501
468
  async proxySet(opts: {
502
- host?: string;
503
- port?: number;
469
+ host?: string; port?: number;
504
470
  type?: "http" | "https" | "socks5" | "socks4";
505
- user?: string;
506
- pass?: string;
507
- proxy?: string;
508
- }): Promise<void> {
509
- await this.send("proxy.set", opts as Record<string, any>);
510
- }
511
-
512
- async proxyTest(): Promise<void> {
513
- await this.send("proxy.test", {});
514
- }
515
-
516
- async proxyTestStop(): Promise<void> {
517
- await this.send("proxy.test.stop", {});
518
- }
519
-
520
- async proxyNext(): Promise<void> {
521
- await this.send("proxy.next", {});
522
- }
523
-
524
- async proxyDisable(): Promise<void> {
525
- await this.send("proxy.disable", {});
526
- }
527
-
528
- async proxyEnable(): Promise<void> {
529
- await this.send("proxy.enable", {});
530
- }
531
-
532
- async proxyCurrent(): Promise<{
533
- host: string; port: number; type: string;
534
- user?: string; alive: boolean; latencyMs?: number;
535
- }> {
536
- return this.send("proxy.current", {});
537
- }
538
-
539
- async proxyStats(): Promise<{
540
- total: number; alive: number; dead: number;
541
- index: number; checking: boolean;
542
- }> {
543
- return this.send("proxy.stats", {});
544
- }
545
-
546
- async proxyList(limit?: number): Promise<{
547
- host: string; port: number; type: string;
548
- alive: boolean; latencyMs?: number;
549
- }[]> {
550
- return this.send("proxy.list", limit !== undefined ? { limit } : {});
551
- }
552
-
553
- async proxyRotation(mode: "none" | "timed" | "perrequest", interval?: number): Promise<void> {
554
- await this.send("proxy.rotation", { mode, ...(interval !== undefined ? { interval } : {}) });
555
- }
556
-
557
- async proxyConfig(opts: { skipDead?: boolean; autoCheck?: boolean }): Promise<void> {
558
- await this.send("proxy.config", opts as Record<string, any>);
559
- }
560
-
561
- async proxySave(path: string, filter: "alive" | "dead" | "all" = "all"): Promise<void> {
562
- await this.send("proxy.save", { path, filter });
563
- }
471
+ user?: string; pass?: string; proxy?: string;
472
+ }): Promise<void> { await this.send("proxy.set", opts as Record<string, any>); }
473
+
474
+ async proxyTest(): Promise<void> { await this.send("proxy.test", {}); }
475
+ async proxyTestStop(): Promise<void> { await this.send("proxy.test.stop", {}); }
476
+ async proxyNext(): Promise<void> { await this.send("proxy.next", {}); }
477
+ async proxyDisable(): Promise<void> { await this.send("proxy.disable", {}); }
478
+ async proxyEnable(): Promise<void> { await this.send("proxy.enable", {}); }
479
+
480
+ async proxyCurrent(): Promise<{ host: string; port: number; type: string; user?: string; alive: boolean; latencyMs?: number; }> { return this.send("proxy.current", {}); }
481
+ async proxyStats(): Promise<{ total: number; alive: number; dead: number; index: number; checking: boolean; }> { return this.send("proxy.stats", {}); }
482
+ async proxyList(limit?: number): Promise<{ host: string; port: number; type: string; alive: boolean; latencyMs?: number; }[]> { return this.send("proxy.list", limit !== undefined ? { limit } : {}); }
483
+ async proxyRotation(mode: "none" | "timed" | "perrequest", interval?: number): Promise<void> { await this.send("proxy.rotation", { mode, ...(interval !== undefined ? { interval } : {}) }); }
484
+ async proxyConfig(opts: { skipDead?: boolean; autoCheck?: boolean }): Promise<void> { await this.send("proxy.config", opts as Record<string, any>); }
485
+ async proxySave(path: string, filter: "alive" | "dead" | "all" = "all"): Promise<void> { await this.send("proxy.save", { path, filter }); }
564
486
 
565
487
  onProxyEvent(event: string, handler: (data: any) => void): () => void {
566
488
  return this.onEvent(event, "*", handler);
@@ -0,0 +1,42 @@
1
+ import { PiggyClient } from "../client";
2
+ import logger from "../logger";
3
+
4
+ export async function exposeFunction(
5
+ client: PiggyClient,
6
+ fnName: string,
7
+ handler: (data: any) => Promise<any> | any,
8
+ tabId: string
9
+ ): Promise<void> {
10
+ await client.exposeFunction(fnName, handler, tabId);
11
+ logger.success(`[${tabId}] exposed function: ${fnName}`);
12
+ }
13
+
14
+ export async function unexposeFunction(
15
+ client: PiggyClient,
16
+ fnName: string,
17
+ tabId: string
18
+ ): Promise<void> {
19
+ await client.unexposeFunction(fnName, tabId);
20
+ logger.info(`[${tabId}] unexposed function: ${fnName}`);
21
+ }
22
+
23
+ export async function clearExposedFunctions(
24
+ client: PiggyClient,
25
+ tabId: string
26
+ ): Promise<void> {
27
+ await client.clearExposedFunctions(tabId);
28
+ logger.info(`[${tabId}] cleared all exposed functions`);
29
+ }
30
+
31
+ export async function exposeAndInject(
32
+ client: PiggyClient,
33
+ fnName: string,
34
+ handler: (data: any) => Promise<any> | any,
35
+ injectionJs: string | ((fnName: string) => string),
36
+ tabId: string
37
+ ): Promise<void> {
38
+ await client.exposeFunction(fnName, handler, tabId);
39
+ const js = typeof injectionJs === "function" ? injectionJs(fnName) : injectionJs;
40
+ await client.evaluate(js, tabId);
41
+ logger.success(`[${tabId}] exposed and injected: ${fnName}`);
42
+ }
@@ -6,7 +6,14 @@ import { routeRegistry, keepAliveSites, type RouteHandler, type BeforeMiddleware
6
6
  import { buildRespondScript, buildModifyResponseScript } from "../intercept/scripts";
7
7
  import { storeRecord } from "../store";
8
8
  import { TabPool } from "../pool";
9
-
9
+ import { createFindAPI } from "../find";
10
+ import { createProvideAPI } from "../provide";
11
+ import { createHumanAPI } from "../human";
12
+ import { createSessionAPI } from "../session";
13
+ import { DialogClient } from "../dialog";
14
+ import { createIframeAPI } from "../iframe";
15
+ import { exposeFunction, unexposeFunction, clearExposedFunctions, exposeAndInject } from "../expose";
16
+ import { createCaptchaAPI } from "../captcha";
10
17
  let globalClient: PiggyClient | null = null;
11
18
  export let humanMode = false;
12
19
 
@@ -105,6 +112,18 @@ export function createSiteObject(
105
112
  return client.waitForSelector(selector, timeout, t);
106
113
  }),
107
114
 
115
+ exposeFunction: (fnName: string, handler: (data: any) => Promise<any> | any) =>
116
+ exposeFunction(client, fnName, handler, tabId).then(() => site),
117
+
118
+ unexposeFunction: (fnName: string) =>
119
+ unexposeFunction(client, fnName, tabId).then(() => site),
120
+
121
+ clearExposedFunctions: () =>
122
+ clearExposedFunctions(client, tabId).then(() => site),
123
+
124
+ exposeAndInject: (fnName: string, handler: (data: any) => Promise<any> | any, injectionJs: string | ((fnName: string) => string)) =>
125
+ exposeAndInject(client, fnName, handler, injectionJs, tabId).then(() => site),
126
+
108
127
  waitForVisible: (selector: string, timeout = 30000) =>
109
128
  withTab(t => client.waitForSelector(selector, timeout, t)),
110
129
 
@@ -257,6 +276,69 @@ export function createSiteObject(
257
276
  css: (query: string) => withTab(t => client.searchCss(query, t)),
258
277
  id: (query: string) => withTab(t => client.searchId(query, t)),
259
278
  },
279
+ captcha: {
280
+ status: () => withTab(t => createCaptchaAPI(client).status(t)),
281
+ resolve: () => withTab(t => createCaptchaAPI(client).resolve(t)),
282
+ pause: () => withTab(t => createCaptchaAPI(client).pause(t)),
283
+ check: () => withTab(t => createCaptchaAPI(client).check(t)),
284
+ autoRetry: (opts: { enabled: boolean }) => withTab(t => createCaptchaAPI(client).setAutoRetry(opts.enabled)),
285
+ onCaptcha: (handler: any) => createCaptchaAPI(client).onCaptcha(tabId, handler),
286
+ onResolved:(handler: any) => createCaptchaAPI(client).onCaptchaResolved(tabId, handler),
287
+ },
288
+ block: {
289
+ status: () => withTab(t => createCaptchaAPI(client).blockStatus(t)),
290
+ retry: () => withTab(t => createCaptchaAPI(client).blockRetry(t)),
291
+ onBlocked: (handler: any) => createCaptchaAPI(client).onBlocked(tabId, handler),
292
+ onRetry: (handler: any) => createCaptchaAPI(client).onBlockRetry(tabId, handler),
293
+ },
294
+ find: {
295
+ css: (selector: string) => withTab(t => {
296
+ console.log("[DEBUG] find.css tabId:", t);
297
+ return createFindAPI(client).css(selector, t);
298
+ }),
299
+ all: (selector: string) => withTab(t => createFindAPI(client).all(selector, t)),
300
+ first: (selector: string) => withTab(t => createFindAPI(client).first(selector, t)),
301
+ byText: (text: string) => withTab(t => createFindAPI(client).byText(text, t)),
302
+ byAttr: (attr: string, value?: string) => withTab(t => createFindAPI(client).byAttr(attr, value, t)),
303
+ byTag: (tag: string) => withTab(t => createFindAPI(client).byTag(tag, t)),
304
+ byPlaceholder: (text: string) => withTab(t => createFindAPI(client).byPlaceholder(text, t)),
305
+ byRole: (role: string, name?: string) => withTab(t => createFindAPI(client).byRole(role, name, t)),
306
+ children: (selector: string) => withTab(t => createFindAPI(client).children(selector, t)),
307
+ parent: (selector: string) => withTab(t => createFindAPI(client).parent(selector, t)),
308
+ closest: (selector: string, ancestor: string) => withTab(t => createFindAPI(client).closest(selector, ancestor, t)),
309
+ count: (selector: string) => withTab(t => createFindAPI(client).count(selector, t)),
310
+ exists: (selector: string) => withTab(t => createFindAPI(client).exists(selector, t)),
311
+ visible: (selector: string) => withTab(t => createFindAPI(client).visible(selector, t)),
312
+ enabled: (selector: string) => withTab(t => createFindAPI(client).enabled(selector, t)),
313
+ checked: (selector: string) => withTab(t => createFindAPI(client).checked(selector, t)),
314
+ },
315
+
316
+ provide: {
317
+ text: (opts: any) => withTab(t => createProvideAPI(client).text(opts, t)),
318
+ textAll: (opts: any) => withTab(t => createProvideAPI(client).textAll(opts, t)),
319
+ attr: (opts: any) => withTab(t => createProvideAPI(client).attr(opts, t)),
320
+ attrAll: (opts: any) => withTab(t => createProvideAPI(client).attrAll(opts, t)),
321
+ html: (opts: any) => withTab(t => createProvideAPI(client).html(opts, t)),
322
+ table: (opts: any) => withTab(t => createProvideAPI(client).table(opts, t)),
323
+ list: (opts: any) => withTab(t => createProvideAPI(client).list(opts, t)),
324
+ links: (opts: any) => withTab(t => createProvideAPI(client).links(opts, t)),
325
+ images: (opts: any) => withTab(t => createProvideAPI(client).images(opts, t)),
326
+ form: (opts: any) => withTab(t => createProvideAPI(client).form(opts, t)),
327
+ page: () => withTab(t => createProvideAPI(client).page(t)),
328
+ div: (opts: any) => withTab(t => createProvideAPI(client).div(opts, t)),
329
+ meta: () => withTab(t => createProvideAPI(client).meta(t)),
330
+ select: (opts: any) => withTab(t => createProvideAPI(client).select(opts, t)),
331
+ json: (opts?: any) => withTab(t => createProvideAPI(client).json(opts, t)),
332
+ },
333
+ iframe: {
334
+ list: () => withTab(t => createIframeAPI(client).list(t)),
335
+ evaluate:(opts: any) => withTab(t => createIframeAPI(client).evaluate(opts, t)),
336
+ click: (opts: any) => withTab(t => createIframeAPI(client).click(opts, t)),
337
+ type: (opts: any) => withTab(t => createIframeAPI(client).type(opts, t)),
338
+ text: (opts: any) => withTab(t => createIframeAPI(client).text(opts, t)),
339
+ html: (opts: any) => withTab(t => createIframeAPI(client).html(opts, t)),
340
+ waitSel: (opts: any) => withTab(t => createIframeAPI(client).waitSel(opts, t)),
341
+ },
260
342
 
261
343
  screenshot: async (filePath?: string) => {
262
344
  const r = await withTab(t => client.screenshot(filePath, t));
@@ -269,6 +351,13 @@ export function createSiteObject(
269
351
  logger.success(`[${name}] pdf → ${filePath ?? "base64"}`);
270
352
  return r;
271
353
  },
354
+ human: {
355
+ set: (opts: any) => withTab(t => createHumanAPI(client).set(opts, t)),
356
+ get: () => withTab(t => createHumanAPI(client).get(t)),
357
+ type: (opts: any) => withTab(t => createHumanAPI(client).type(opts, t)),
358
+ click: (opts: any) => withTab(t => createHumanAPI(client).click(opts, t)),
359
+ },
360
+
272
361
 
273
362
  blockImages: () => withTab(async t => { await client.blockImages(t); logger.info(`[${name}] images blocked`); }),
274
363
  unblockImages: () => withTab(async t => { await client.unblockImages(t); logger.info(`[${name}] images unblocked`); }),
@@ -278,14 +367,14 @@ export function createSiteObject(
278
367
  await withTab(t => client.setCookie(cookieName, value, domain, path, t));
279
368
  logger.info(`[${name}] cookie set: ${cookieName} @ ${domain}`);
280
369
  },
281
- get: (cookieName: string) => withTab(t => client.getCookie(cookieName, t)),
282
- delete: async (cookieName: string) => {
283
- await withTab(t => client.deleteCookie(cookieName, t));
370
+ get: (cookieName: string, domain = "") => withTab(t => client.getCookie(cookieName, domain, t)),
371
+ delete: async (cookieName: string, domain?: string) => {
372
+ const d = domain ?? new URL(registeredUrl).hostname;
373
+ await withTab(t => client.deleteCookie(cookieName, d, t));
284
374
  logger.info(`[${name}] cookie deleted: ${cookieName}`);
285
375
  },
286
- list: () => withTab(t => client.listCookies(t)),
376
+ list: (domain = "") => withTab(t => client.listCookies(domain, t)),
287
377
  },
288
-
289
378
  intercept: {
290
379
  block: async (pattern: string) => {
291
380
  await withTab(t => client.addInterceptRule("block", pattern, {}, t));
@@ -385,6 +474,16 @@ export function createSiteObject(
385
474
  logger.info(`[${name}] intercept rules cleared`);
386
475
  },
387
476
  },
477
+ dialog: {
478
+ accept: (tabId = "default", text?: string) => new DialogClient(client).accept(tabId, text),
479
+ dismiss: (tabId = "default") => new DialogClient(client).dismiss(tabId),
480
+ status: (tabId = "default") => new DialogClient(client).status(tabId),
481
+ setAutoAction: (tabId = "default", action: "accept" | "dismiss" | "") => new DialogClient(client).setAutoAction(tabId, action),
482
+ upload: (selector: string, filePath: string, tabId = "default") => new DialogClient(client).upload(selector, filePath, tabId),
483
+ onDialog: (tabId: string, handler: (data: any) => void) => new DialogClient(client).onDialog(tabId, handler),
484
+ waitAndAccept: (tabId = "default", text?: string, timeoutMs = 30000) => new DialogClient(client).waitAndAccept(tabId, text, timeoutMs),
485
+ waitAndDismiss:(tabId = "default", timeoutMs = 30000) => new DialogClient(client).waitAndDismiss(tabId, timeoutMs),
486
+ },
388
487
 
389
488
  capture: {
390
489
  start: () => withTab(async t => { await client.captureStart(t); logger.info(`[${name}] capture started`); }),
@@ -396,40 +495,16 @@ export function createSiteObject(
396
495
  clear: () => withTab(async t => { await client.captureClear(t); logger.info(`[${name}] capture cleared`); }),
397
496
  },
398
497
 
399
- session: {
400
- export: async () => {
401
- const data = await withTab(t => client.sessionExport(t));
402
- logger.success(`[${name}] session exported`);
403
- return data;
404
- },
405
- import: async (data: any) => {
406
- await withTab(t => client.sessionImport(data, t));
407
- logger.success(`[${name}] session imported`);
408
- },
409
- },
410
-
411
- exposeFunction: async (fnName: string, handler: (data: any) => Promise<any> | any) => {
412
- await client.exposeFunction(fnName, handler, tabId);
413
- logger.success(`[${name}] exposed function: ${fnName}`);
414
- return site;
415
- },
416
- unexposeFunction: async (fnName: string) => {
417
- await client.unexposeFunction(fnName, tabId);
418
- logger.info(`[${name}] unexposed function: ${fnName}`);
419
- return site;
420
- },
421
- clearExposedFunctions: async () => {
422
- await client.clearExposedFunctions(tabId);
423
- logger.info(`[${name}] cleared all exposed functions`);
424
- return site;
425
- },
426
- exposeAndInject: async (fnName: string, handler: (data: any) => Promise<any> | any, injectionJs: string | ((fnName: string) => string)) => {
427
- await client.exposeFunction(fnName, handler, tabId);
428
- const js = typeof injectionJs === "function" ? injectionJs(fnName) : injectionJs;
429
- await withTab(t => client.evaluate(js, t));
430
- logger.success(`[${name}] exposed and injected: ${fnName}`);
431
- return site;
432
- },
498
+ session: {
499
+ export: () => withTab(t => createSessionAPI(client).export(t)),
500
+ import: (data: any) => withTab(t => createSessionAPI(client).import(data, t)),
501
+ reload: () => withTab(t => createSessionAPI(client).reload(t)),
502
+ paths: () => createSessionAPI(client).paths(),
503
+ cookies: { path: () => createSessionAPI(client).cookiesPath() },
504
+ profile: { path: () => createSessionAPI(client).profilePath() },
505
+ ws: { save: (opts: any) => createSessionAPI(client).setWsSave(opts.enabled) },
506
+ pings: { save: (opts: any) => createSessionAPI(client).setPingsSave(opts.enabled) },
507
+ },
433
508
 
434
509
  store: async (
435
510
  data: Record<string, any> | Record<string, any>[],
@@ -8,7 +8,8 @@ export class TabsClient {
8
8
  return this.client.send("tab.new", {});
9
9
  }
10
10
 
11
- close(tabId: string): Promise<void> {
11
+ close(opts: string | { tabId: string }): Promise<void> {
12
+ const tabId = typeof opts === "string" ? opts : opts.tabId;
12
13
  return this.client.send("tab.close", { tabId });
13
14
  }
14
15
 
package/piggy.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  // piggy.ts
2
+ //the main file
2
3
  import { detectBinary, type BinaryMode } from "./piggy/launch/detect";
3
4
  import { spawnBrowser, killBrowser, spawnBrowserOnSocket } from "./piggy/launch/spawn";
4
5
  import { PiggyClient } from "./piggy/client";
@@ -121,7 +122,8 @@ const piggy: any = {
121
122
 
122
123
  // ── Sub-APIs (1:1 with C++ files, available after launch/connect) ─────────
123
124
 
124
- get tabs() { return _router?.tabs ?? createTabsAPI(guardClient()); },
125
+ get tabs() { return _router?.tabs ?? createTabsAPI(guardClient()); },
126
+ get tab() { return _router?.tabs ?? createTabsAPI(guardClient()); },
125
127
  get navigation() { return _router?.navigation ?? createNavigationAPI(guardClient()); },
126
128
  get interactions() { return _router?.interactions ?? createInteractionsAPI(guardClient()); },
127
129
  get media() { return _router?.media ?? createMediaAPI(guardClient()); },
@@ -1,7 +0,0 @@
1
- export declare function get(key: string): any | null;
2
- export declare function set(key: string, data: any, ttlMs: number): void;
3
- export declare function del(key: string): void;
4
- export declare function clear(): void;
5
- export declare function size(): number;
6
- export declare function keys(): string[];
7
- //# sourceMappingURL=memory.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["memory.ts"],"names":[],"mappings":"AASA,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,CAQ3C;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,QAExD;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,QAE9B;AAED,wBAAgB,KAAK,SAEpB;AAED,wBAAgB,IAAI,WAEnB;AAED,wBAAgB,IAAI,aAEnB"}
@@ -1,35 +0,0 @@
1
- // piggy/captcha/index.d.ts
2
- import { PiggyClient } from "../client";
3
-
4
- export interface CaptchaState {
5
- detected: boolean;
6
- paused: boolean;
7
- type: string;
8
- }
9
-
10
- export interface BlockState {
11
- detected: boolean;
12
- type: string;
13
- }
14
-
15
- export declare class CaptchaClient {
16
- constructor(client: PiggyClient);
17
-
18
- status(tabId?: string): Promise<CaptchaState>;
19
- resolve(tabId?: string): Promise<void>;
20
- pause(tabId?: string): Promise<void>;
21
- check(tabId?: string): Promise<void>;
22
- setAutoRetry(enabled: boolean): Promise<void>;
23
-
24
- blockStatus(tabId?: string): Promise<BlockState>;
25
- blockRetry(tabId?: string): Promise<void>;
26
-
27
- onCaptcha(tabId: string, handler: (data: { captchaType: string; tabId: string }) => void): () => void;
28
- onCaptchaResolved(tabId: string, handler: (data: { tabId: string }) => void): () => void;
29
- onBlocked(tabId: string, handler: (data: { blockType: string; tabId: string }) => void): () => void;
30
- onBlockRetry(tabId: string, handler: (data: { tabId: string; proxy: string }) => void): () => void;
31
-
32
- waitForResolution(tabId?: string, timeoutMs?: number): Promise<void>;
33
- }
34
-
35
- export declare function createCaptchaAPI(client: PiggyClient): CaptchaClient;
@@ -1,79 +0,0 @@
1
- export declare class PiggyClient {
2
- private socketPath;
3
- private socket;
4
- private reqId;
5
- private pending;
6
- private buf;
7
- private eventBuffer;
8
- private eventHandlers;
9
- private globalEventHandlers;
10
- constructor(socketPath?: string);
11
- connect(): Promise<void>;
12
- private handleEvent;
13
- onEvent(eventName: string, tabId: string, handler: (data: any) => void): () => void;
14
- disconnect(): void;
15
- send<T = any>(cmd: string, payload?: Record<string, any>): Promise<T>;
16
- newTab(): Promise<string>;
17
- closeTab(tabId: string): Promise<void>;
18
- listTabs(): Promise<string[]>;
19
- navigate(url: string, tabId?: string): Promise<void>;
20
- reload(tabId?: string): Promise<void>;
21
- goBack(tabId?: string): Promise<void>;
22
- goForward(tabId?: string): Promise<void>;
23
- getTitle(tabId?: string): Promise<string>;
24
- getUrl(tabId?: string): Promise<string>;
25
- content(tabId?: string): Promise<string>;
26
- evaluate(js: string, tabId?: string): Promise<any>;
27
- addInitScript(js: string, tabId?: string): Promise<void>;
28
- click(selector: string, tabId?: string): Promise<boolean>;
29
- doubleClick(selector: string, tabId?: string): Promise<boolean>;
30
- hover(selector: string, tabId?: string): Promise<boolean>;
31
- type(selector: string, text: string, tabId?: string): Promise<boolean>;
32
- select(selector: string, value: string, tabId?: string): Promise<boolean>;
33
- keyPress(key: string, tabId?: string): Promise<boolean>;
34
- keyCombo(combo: string, tabId?: string): Promise<boolean>;
35
- mouseMove(x: number, y: number, tabId?: string): Promise<boolean>;
36
- mouseDrag(from: {
37
- x: number;
38
- y: number;
39
- }, to: {
40
- x: number;
41
- y: number;
42
- }, tabId?: string): Promise<boolean>;
43
- scrollTo(selector: string, tabId?: string): Promise<boolean>;
44
- scrollBy(px: number, tabId?: string): Promise<boolean>;
45
- fetchText(query: string, tabId?: string): Promise<string | null>;
46
- fetchLinks(query: string, tabId?: string): Promise<string[]>;
47
- fetchImages(query: string, tabId?: string): Promise<string[]>;
48
- searchCss(query: string, tabId?: string): Promise<any>;
49
- searchId(query: string, tabId?: string): Promise<any>;
50
- waitForSelector(selector: string, timeout?: number, tabId?: string): Promise<void>;
51
- waitForNavigation(tabId?: string): Promise<void>;
52
- waitForResponse(urlPattern: string, timeout?: number, tabId?: string): Promise<void>;
53
- screenshot(filePath?: string, tabId?: string): Promise<string>;
54
- pdf(filePath?: string, tabId?: string): Promise<string>;
55
- blockImages(tabId?: string): Promise<void>;
56
- unblockImages(tabId?: string): Promise<void>;
57
- setCookie(name: string, value: string, domain: string, path?: string, tabId?: string): Promise<void>;
58
- getCookie(name: string, tabId?: string): Promise<any>;
59
- deleteCookie(name: string, tabId?: string): Promise<void>;
60
- listCookies(tabId?: string): Promise<any[]>;
61
- addInterceptRule(action: "block" | "redirect" | "modifyHeaders", pattern: string, options?: {
62
- redirectUrl?: string;
63
- headers?: Record<string, string>;
64
- }, tabId?: string): Promise<void>;
65
- clearInterceptRules(tabId?: string): Promise<void>;
66
- captureStart(tabId?: string): Promise<void>;
67
- captureStop(tabId?: string): Promise<void>;
68
- captureRequests(tabId?: string): Promise<any[]>;
69
- captureWs(tabId?: string): Promise<any[]>;
70
- captureCookies(tabId?: string): Promise<any[]>;
71
- captureStorage(tabId?: string): Promise<any>;
72
- captureClear(tabId?: string): Promise<void>;
73
- sessionExport(tabId?: string): Promise<any>;
74
- sessionImport(data: any, tabId?: string): Promise<void>;
75
- exposeFunction(name: string, handler: (data: any) => Promise<any> | any, tabId?: string): Promise<void>;
76
- unexposeFunction(name: string, tabId?: string): Promise<void>;
77
- clearExposedFunctions(tabId?: string): Promise<void>;
78
- }
79
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}