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.
Files changed (121) hide show
  1. package/package.json +14 -26
  2. package/piggy/cache/{memory.ts → memory.js} +5 -10
  3. package/piggy/captcha/{index.ts → index.js} +19 -28
  4. package/piggy/capture/index.js +40 -0
  5. package/piggy/client/{index.ts → index.js} +133 -154
  6. package/piggy/dialog/{index.ts → index.js} +15 -31
  7. package/piggy/export/index.js +105 -0
  8. package/piggy/expose/index.js +24 -0
  9. package/piggy/find/{index.ts → index.js} +24 -39
  10. package/piggy/http/{index.ts → index.js} +7 -16
  11. package/piggy/human/{index.ts → index.js} +18 -49
  12. package/piggy/iframe/index.js +56 -0
  13. package/piggy/interactions/{index.ts → index.js} +20 -23
  14. package/piggy/intercept/{scripts.ts → scripts.js} +4 -13
  15. package/piggy/launch/{detect.ts → detect.js} +4 -6
  16. package/piggy/launch/{spawn.ts → spawn.js} +17 -22
  17. package/piggy/media/{index.ts → index.js} +13 -11
  18. package/piggy/navigation/{index.ts → index.js} +16 -14
  19. package/piggy/pool/index.js +76 -0
  20. package/piggy/provide/index.js +97 -0
  21. package/piggy/proxy/index.js +95 -0
  22. package/piggy/register/index.js +543 -0
  23. package/piggy/router/index.js +44 -0
  24. package/piggy/server/{index.ts → index.js} +16 -64
  25. package/piggy/session/index.js +69 -0
  26. package/piggy/store/{index.ts → index.js} +22 -62
  27. package/piggy/tabs/index.js +24 -0
  28. package/piggy/wait/index.js +77 -0
  29. package/piggy.js +316 -0
  30. package/dist/cache/memory.js +0 -35
  31. package/dist/client/index.js +0 -1284
  32. package/dist/human/index.js +0 -82
  33. package/dist/launch/detect.js +0 -782
  34. package/dist/launch/spawn.js +0 -915
  35. package/dist/logger/index.js +0 -733
  36. package/dist/piggy/cache/memory.d.ts +0 -7
  37. package/dist/piggy/cache/memory.d.ts.map +0 -1
  38. package/dist/piggy/captcha/index.d.ts +0 -39
  39. package/dist/piggy/captcha/index.d.ts.map +0 -1
  40. package/dist/piggy/capture/index.d.ts +0 -48
  41. package/dist/piggy/capture/index.d.ts.map +0 -1
  42. package/dist/piggy/client/index.d.ts +0 -146
  43. package/dist/piggy/client/index.d.ts.map +0 -1
  44. package/dist/piggy/dialog/index.d.ts +0 -28
  45. package/dist/piggy/dialog/index.d.ts.map +0 -1
  46. package/dist/piggy/export/index.d.ts +0 -62
  47. package/dist/piggy/export/index.d.ts.map +0 -1
  48. package/dist/piggy/expose/index.d.ts +0 -6
  49. package/dist/piggy/expose/index.d.ts.map +0 -1
  50. package/dist/piggy/find/index.d.ts +0 -52
  51. package/dist/piggy/find/index.d.ts.map +0 -1
  52. package/dist/piggy/http/index.d.ts +0 -14
  53. package/dist/piggy/http/index.d.ts.map +0 -1
  54. package/dist/piggy/human/index.d.ts +0 -39
  55. package/dist/piggy/human/index.d.ts.map +0 -1
  56. package/dist/piggy/iframe/index.d.ts +0 -53
  57. package/dist/piggy/iframe/index.d.ts.map +0 -1
  58. package/dist/piggy/interactions/index.d.ts +0 -24
  59. package/dist/piggy/interactions/index.d.ts.map +0 -1
  60. package/dist/piggy/intercept/scripts.d.ts +0 -13
  61. package/dist/piggy/intercept/scripts.d.ts.map +0 -1
  62. package/dist/piggy/launch/detect.d.ts +0 -3
  63. package/dist/piggy/launch/detect.d.ts.map +0 -1
  64. package/dist/piggy/launch/spawn.d.ts +0 -6
  65. package/dist/piggy/launch/spawn.d.ts.map +0 -1
  66. package/dist/piggy/logger/index.d.ts +0 -3
  67. package/dist/piggy/logger/index.d.ts.map +0 -1
  68. package/dist/piggy/media/index.d.ts +0 -11
  69. package/dist/piggy/media/index.d.ts.map +0 -1
  70. package/dist/piggy/navigation/index.d.ts +0 -16
  71. package/dist/piggy/navigation/index.d.ts.map +0 -1
  72. package/dist/piggy/pool/index.d.ts +0 -23
  73. package/dist/piggy/pool/index.d.ts.map +0 -1
  74. package/dist/piggy/provide/index.d.ts +0 -98
  75. package/dist/piggy/provide/index.d.ts.map +0 -1
  76. package/dist/piggy/proxy/index.d.ts +0 -94
  77. package/dist/piggy/proxy/index.d.ts.map +0 -1
  78. package/dist/piggy/register/index.d.ts +0 -9
  79. package/dist/piggy/register/index.d.ts.map +0 -1
  80. package/dist/piggy/router/index.d.ts +0 -38
  81. package/dist/piggy/router/index.d.ts.map +0 -1
  82. package/dist/piggy/server/index.d.ts +0 -42
  83. package/dist/piggy/server/index.d.ts.map +0 -1
  84. package/dist/piggy/session/index.d.ts +0 -27
  85. package/dist/piggy/session/index.d.ts.map +0 -1
  86. package/dist/piggy/store/index.d.ts +0 -22
  87. package/dist/piggy/store/index.d.ts.map +0 -1
  88. package/dist/piggy/tabs/index.d.ts +0 -12
  89. package/dist/piggy/tabs/index.d.ts.map +0 -1
  90. package/dist/piggy/wait/index.d.ts +0 -28
  91. package/dist/piggy/wait/index.d.ts.map +0 -1
  92. package/dist/piggy.d.ts +0 -10
  93. package/dist/piggy.d.ts.map +0 -1
  94. package/dist/piggy.js +0 -30186
  95. package/dist/register/index.js +0 -23710
  96. package/dist/server/index.js +0 -26831
  97. package/piggy/capture/index.ts +0 -76
  98. package/piggy/export/index.d.ts +0 -117
  99. package/piggy/export/index.ts +0 -147
  100. package/piggy/expose/index.ts +0 -42
  101. package/piggy/iframe/index.ts +0 -79
  102. package/piggy/intercept/scripts.d.ts +0 -13
  103. package/piggy/intercept/scripts.d.ts.map +0 -1
  104. package/piggy/launch/detect.d.ts +0 -3
  105. package/piggy/launch/detect.d.ts.map +0 -1
  106. package/piggy/launch/spawn.d.ts +0 -6
  107. package/piggy/launch/spawn.d.ts.map +0 -1
  108. package/piggy/logger/index.d.ts +0 -3
  109. package/piggy/logger/index.d.ts.map +0 -1
  110. package/piggy/pool/index.d.ts +0 -12
  111. package/piggy/pool/index.ts +0 -75
  112. package/piggy/provide/index.ts +0 -170
  113. package/piggy/proxy/index.ts +0 -154
  114. package/piggy/register/index.ts +0 -575
  115. package/piggy/router/index.ts +0 -69
  116. package/piggy/session/index.ts +0 -76
  117. package/piggy/store/index.d.ts +0 -26
  118. package/piggy/tabs/index.ts +0 -23
  119. package/piggy/wait/index.ts +0 -90
  120. package/piggy.ts +0 -274
  121. /package/piggy/logger/{index.ts → index.js} +0 -0
@@ -0,0 +1,105 @@
1
+ // piggy/export/index.js
2
+ import { PiggyClient } from "../client.js";
3
+
4
+ // ─── ExportClient ─────────────────────────────────────────────────────────────
5
+ export class ExportClient {
6
+ constructor(client) {
7
+ this.client = client;
8
+ }
9
+
10
+ // DOM fetch
11
+ searchCss(query, tabId = "default") {
12
+ return this.client.send("search.css", { query, tabId });
13
+ }
14
+
15
+ searchId(query, tabId = "default") {
16
+ return this.client.send("search.id", { query, tabId });
17
+ }
18
+
19
+ // Cookies
20
+ setCookie(opts, tabId = "default") {
21
+ return this.client.send("cookie.set", { ...opts, tabId });
22
+ }
23
+
24
+ deleteCookie(opts, tabId = "default") {
25
+ return this.client.send("cookie.delete", { ...opts, tabId });
26
+ }
27
+
28
+ // Session
29
+ sessionReload(tabId = "default") {
30
+ return this.client.send("session.reload", { tabId });
31
+ }
32
+
33
+ cookiesPath() {
34
+ return this.client.send("session.cookies.path", {});
35
+ }
36
+
37
+ profilePath() {
38
+ return this.client.send("session.profile.path", {});
39
+ }
40
+
41
+ wsPath() {
42
+ return this.client.send("session.ws.path", {});
43
+ }
44
+
45
+ pingsPath() {
46
+ return this.client.send("session.pings.path", {});
47
+ }
48
+
49
+ sessionPaths() {
50
+ return this.client.send("session.paths", {});
51
+ }
52
+
53
+ setWsSave(enabled) {
54
+ return this.client.send("session.ws.save", { enabled });
55
+ }
56
+
57
+ setPingsSave(enabled) {
58
+ return this.client.send("session.pings.save", { enabled });
59
+ }
60
+
61
+ // Intercept rules
62
+ addInterceptRule(rule, tabId = "default") {
63
+ return this.client.send("intercept.rule.add", { ...rule, tabId });
64
+ }
65
+
66
+ clearInterceptRules(tabId = "default") {
67
+ return this.client.send("intercept.rule.clear", { tabId });
68
+ }
69
+
70
+ // Session export / import
71
+ async exportSession(tabId = "default") {
72
+ const raw = await this.client.send("session.export", { tabId });
73
+ return typeof raw === "string" ? JSON.parse(raw) : raw;
74
+ }
75
+
76
+ importSession(data, tabId = "default") {
77
+ return this.client.send("session.import", {
78
+ data: JSON.stringify(data),
79
+ tabId,
80
+ });
81
+ }
82
+
83
+ // Exposed functions
84
+ exposeFunction(name, tabId = "default") {
85
+ return this.client.send("expose.function", { name, tabId });
86
+ }
87
+
88
+ resolveExposed(callId, result, isError = false, tabId = "default") {
89
+ return this.client.send("exposed.result", { callId, result, isError, tabId });
90
+ }
91
+
92
+ // Init scripts
93
+ addInitScript(js, tabId = "default") {
94
+ return this.client.send("addInitScript", { js, tabId });
95
+ }
96
+
97
+ // Events
98
+ onExposedFunctionCalled(tabId, handler) {
99
+ return this.client.onEvent("exposed_call", tabId, handler);
100
+ }
101
+ }
102
+
103
+ export function createExportAPI(client) {
104
+ return new ExportClient(client);
105
+ }
@@ -0,0 +1,24 @@
1
+ import { PiggyClient } from "../client.js";
2
+ import logger from "../logger.js";
3
+
4
+ export async function exposeFunction(client, fnName, handler, tabId) {
5
+ await client.exposeFunction(fnName, handler, tabId);
6
+ logger.success(`[${tabId}] exposed function: ${fnName}`);
7
+ }
8
+
9
+ export async function unexposeFunction(client, fnName, tabId) {
10
+ await client.unexposeFunction(fnName, tabId);
11
+ logger.info(`[${tabId}] unexposed function: ${fnName}`);
12
+ }
13
+
14
+ export async function clearExposedFunctions(client, tabId) {
15
+ await client.clearExposedFunctions(tabId);
16
+ logger.info(`[${tabId}] cleared all exposed functions`);
17
+ }
18
+
19
+ export async function exposeAndInject(client, fnName, handler, injectionJs, tabId) {
20
+ await client.exposeFunction(fnName, handler, tabId);
21
+ const js = typeof injectionJs === "function" ? injectionJs(fnName) : injectionJs;
22
+ await client.evaluate(js, tabId);
23
+ logger.success(`[${tabId}] exposed and injected: ${fnName}`);
24
+ }
@@ -1,22 +1,5 @@
1
- // piggy/find/index.ts
2
- import { PiggyClient } from "../client";
3
-
4
- // ─── Element descriptor ───────────────────────────────────────────────────────
5
- // Mirrors __nb_serialize() in PiggyFind.cpp
6
-
7
- export interface ElementDescriptor {
8
- tag: string;
9
- id: string;
10
- cls: string;
11
- /** First 400 chars of innerText */
12
- text: string;
13
- /** First 800 chars of innerHTML */
14
- html: string;
15
- href: string;
16
- src: string;
17
- value: string;
18
- attrs: Record<string, string>;
19
- }
1
+ // piggy/find/index.js
2
+ import { PiggyClient } from "../client.js";
20
3
 
21
4
  // ─── FindClient ───────────────────────────────────────────────────────────────
22
5
  // find answers ONE question: "is this thing here, and where?"
@@ -24,95 +7,97 @@ export interface ElementDescriptor {
24
7
  // If you need a value out of an element, use provide instead.
25
8
 
26
9
  export class FindClient {
27
- constructor(private client: PiggyClient) {}
10
+ constructor(client) {
11
+ this.client = client;
12
+ }
28
13
 
29
- // ── Multi-result ─────────────────────────────────────────────────────────────
14
+ // ── Multi-result ──────────────────────────────────────────────────────────
30
15
 
31
16
  /** querySelectorAll — returns all matching elements. */
32
- css(selector: string, tabId = "default"): Promise<ElementDescriptor[]> {
17
+ css(selector, tabId = "default") {
33
18
  return this.client.send("find.css", { selector, tabId });
34
19
  }
35
20
 
36
21
  /** Alias for css(). */
37
- all(selector: string, tabId = "default"): Promise<ElementDescriptor[]> {
22
+ all(selector, tabId = "default") {
38
23
  return this.client.send("find.all", { selector, tabId });
39
24
  }
40
25
 
41
26
  /** querySelector — returns a single-element array or []. */
42
- first(selector: string, tabId = "default"): Promise<ElementDescriptor[]> {
27
+ first(selector, tabId = "default") {
43
28
  return this.client.send("find.first", { selector, tabId });
44
29
  }
45
30
 
46
31
  /** Find elements whose innerText contains the given text. */
47
- byText(text: string, tabId = "default"): Promise<ElementDescriptor[]> {
32
+ byText(text, tabId = "default") {
48
33
  return this.client.send("find.byText", { text, tabId });
49
34
  }
50
35
 
51
36
  /** Find elements by attribute name (and optional value). */
52
- byAttr(attr: string, value?: string, tabId = "default"): Promise<ElementDescriptor[]> {
37
+ byAttr(attr, value, tabId = "default") {
53
38
  return this.client.send("find.byAttr", { attr, value, tabId });
54
39
  }
55
40
 
56
41
  /** getElementsByTagName. */
57
- byTag(tag: string, tabId = "default"): Promise<ElementDescriptor[]> {
42
+ byTag(tag, tabId = "default") {
58
43
  return this.client.send("find.byTag", { tag, tabId });
59
44
  }
60
45
 
61
46
  /** Find inputs/textareas whose placeholder contains the given text. */
62
- byPlaceholder(text: string, tabId = "default"): Promise<ElementDescriptor[]> {
47
+ byPlaceholder(text, tabId = "default") {
63
48
  return this.client.send("find.byPlaceholder", { text, tabId });
64
49
  }
65
50
 
66
51
  /** Find elements by ARIA role, optionally filtered by accessible name. */
67
- byRole(role: string, name?: string, tabId = "default"): Promise<ElementDescriptor[]> {
52
+ byRole(role, name, tabId = "default") {
68
53
  return this.client.send("find.byRole", { role, name, tabId });
69
54
  }
70
55
 
71
56
  /** Direct children of the matched element. */
72
- children(selector: string, tabId = "default"): Promise<ElementDescriptor[]> {
57
+ children(selector, tabId = "default") {
73
58
  return this.client.send("find.children", { selector, tabId });
74
59
  }
75
60
 
76
61
  /** parentElement of the matched element. */
77
- parent(selector: string, tabId = "default"): Promise<ElementDescriptor[]> {
62
+ parent(selector, tabId = "default") {
78
63
  return this.client.send("find.parent", { selector, tabId });
79
64
  }
80
65
 
81
66
  /** Walk up the DOM from selector until ancestor matches. */
82
- closest(selector: string, ancestor: string, tabId = "default"): Promise<ElementDescriptor[]> {
67
+ closest(selector, ancestor, tabId = "default") {
83
68
  return this.client.send("find.closest", { selector, ancestor, tabId });
84
69
  }
85
70
 
86
- // ── Boolean / numeric ────────────────────────────────────────────────────────
71
+ // ── Boolean / numeric ─────────────────────────────────────────────────────
87
72
 
88
73
  /** Number of elements matching the selector. */
89
- count(selector: string, tabId = "default"): Promise<number> {
74
+ count(selector, tabId = "default") {
90
75
  return this.client.send("find.count", { selector, tabId });
91
76
  }
92
77
 
93
78
  /** True if at least one element matches. */
94
- exists(selector: string, tabId = "default"): Promise<boolean> {
79
+ exists(selector, tabId = "default") {
95
80
  return this.client.send("find.exists", { selector, tabId });
96
81
  }
97
82
 
98
83
  /** True if the first matched element is visible. */
99
- visible(selector: string, tabId = "default"): Promise<boolean> {
84
+ visible(selector, tabId = "default") {
100
85
  return this.client.send("find.visible", { selector, tabId });
101
86
  }
102
87
 
103
88
  /** True if the first matched element is not disabled. */
104
- enabled(selector: string, tabId = "default"): Promise<boolean> {
89
+ enabled(selector, tabId = "default") {
105
90
  return this.client.send("find.enabled", { selector, tabId });
106
91
  }
107
92
 
108
93
  /** True if the first matched checkbox/radio is checked. */
109
- checked(selector: string, tabId = "default"): Promise<boolean> {
94
+ checked(selector, tabId = "default") {
110
95
  return this.client.send("find.checked", { selector, tabId });
111
96
  }
112
97
  }
113
98
 
114
99
  // ─── Factory helper ───────────────────────────────────────────────────────────
115
100
 
116
- export function createFindAPI(client: PiggyClient): FindClient {
101
+ export function createFindAPI(client) {
117
102
  return new FindClient(client);
118
103
  }
@@ -1,18 +1,9 @@
1
- // piggy/http/index.ts
1
+ // piggy/http/index.js
2
2
  // Mirrors PiggyHttp.cpp — connects to the HTTP server on port 2005.
3
3
  // Use this when you want to talk to the browser over HTTP instead of the unix socket.
4
4
 
5
- export interface HttpClientOptions {
6
- host?: string;
7
- port?: number;
8
- key: string;
9
- }
10
-
11
5
  export class PiggyHttpClient {
12
- private baseUrl: string;
13
- private key: string;
14
-
15
- constructor(opts: HttpClientOptions) {
6
+ constructor(opts) {
16
7
  const host = opts.host ?? "localhost";
17
8
  const port = opts.port ?? 2005;
18
9
  this.baseUrl = `http://${host}:${port}`;
@@ -21,7 +12,7 @@ export class PiggyHttpClient {
21
12
 
22
13
  // ── Health check ──────────────────────────────────────────────────────────
23
14
 
24
- async ping(): Promise<boolean> {
15
+ async ping() {
25
16
  try {
26
17
  const res = await fetch(this.baseUrl, {
27
18
  method: "POST",
@@ -40,7 +31,7 @@ export class PiggyHttpClient {
40
31
 
41
32
  // ── Send command ──────────────────────────────────────────────────────────
42
33
 
43
- async send<T = any>(cmd: string, payload: Record<string, any> = {}): Promise<T> {
34
+ async send(cmd, payload = {}) {
44
35
  const res = await fetch(this.baseUrl, {
45
36
  method: "POST",
46
37
  headers: {
@@ -54,12 +45,12 @@ export class PiggyHttpClient {
54
45
  if (res.status === 400) throw new Error("Bad request — invalid JSON");
55
46
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
56
47
 
57
- const data = await res.json() as { ok: boolean; data: T };
48
+ const data = await res.json();
58
49
  if (!data.ok) throw new Error(String(data.data) ?? "command failed");
59
50
  return data.data;
60
51
  }
61
52
  }
62
53
 
63
- export function createHttpClient(opts: HttpClientOptions): PiggyHttpClient {
54
+ export function createHttpClient(opts) {
64
55
  return new PiggyHttpClient(opts);
65
- }
56
+ }
@@ -1,14 +1,14 @@
1
- // piggy/human/index.ts
2
- import { PiggyClient } from "../client";
1
+ // piggy/human/index.js
2
+ import { PiggyClient } from "../client.js";
3
3
 
4
4
  // ─── Local utilities ──────────────────────────────────────────────────────────
5
5
 
6
- export function randomDelay(min: number, max: number): Promise<void> {
6
+ export function randomDelay(min, max) {
7
7
  return new Promise(r => setTimeout(r, Math.floor(Math.random() * (max - min + 1)) + min));
8
8
  }
9
9
 
10
- export function humanTypeSequence(text: string): string[] {
11
- const adjacent: Record<string, string[]> = {
10
+ export function humanTypeSequence(text) {
11
+ const adjacent = {
12
12
  a: ["q","w","s","z"], b: ["v","g","h","n"], c: ["x","d","f","v"],
13
13
  d: ["s","e","r","f","c","x"], e: ["w","r","d","s"],
14
14
  f: ["d","r","t","g","v","c"], g: ["f","t","y","h","b","v"],
@@ -23,8 +23,8 @@ export function humanTypeSequence(text: string): string[] {
23
23
  z: ["a","s","x"],
24
24
  };
25
25
 
26
- const actions: string[] = [];
27
- const typoIndices = new Set<number>();
26
+ const actions = [];
27
+ const typoIndices = new Set();
28
28
 
29
29
  if (text.length > 4) {
30
30
  let tries = 0;
@@ -36,7 +36,7 @@ export function humanTypeSequence(text: string): string[] {
36
36
 
37
37
  for (let i = 0; i < text.length; i++) {
38
38
  if (typoIndices.has(i)) {
39
- const ch = text[i]!.toLowerCase();
39
+ const ch = text[i].toLowerCase();
40
40
  const neighbors = adjacent[ch];
41
41
  const typo = neighbors
42
42
  ? neighbors[Math.floor(Math.random() * neighbors.length)] ?? ch
@@ -44,72 +44,41 @@ export function humanTypeSequence(text: string): string[] {
44
44
  actions.push(typo);
45
45
  actions.push("BACKSPACE");
46
46
  }
47
- actions.push(text[i]!);
47
+ actions.push(text[i]);
48
48
  }
49
49
 
50
50
  return actions;
51
51
  }
52
52
 
53
- // ─── Profile types ────────────────────────────────────────────────────────────
54
-
55
- export type TypingSpeed = "slow" | "normal" | "fast";
56
- export type ClickDelay = "cautious" | "normal" | "fast";
57
- export type ScrollSpeed = "slow" | "normal" | "fast";
58
-
59
- export interface HumanProfile {
60
- typingSpeed: TypingSpeed;
61
- clickDelay: ClickDelay;
62
- scrollSpeed: ScrollSpeed;
63
- mouseWiggle: boolean;
64
- }
65
-
66
- export interface HumanSetOptions {
67
- typingSpeed?: TypingSpeed;
68
- clickDelay?: ClickDelay;
69
- scrollSpeed?: ScrollSpeed;
70
- mouseWiggle?: boolean;
71
- }
72
-
73
- export interface HumanTypeOptions {
74
- selector: string;
75
- text: string;
76
- clear?: boolean;
77
- speed?: number;
78
- }
79
-
80
- export interface HumanClickOptions {
81
- selector: string;
82
- force?: boolean;
83
- delay?: number;
84
- }
85
-
86
53
  // ─── HumanClient ─────────────────────────────────────────────────────────────
87
54
  // Maps 1:1 to PiggyHuman.cpp commands
88
55
 
89
56
  export class HumanClient {
90
- constructor(private client: PiggyClient) {}
57
+ constructor(client) {
58
+ this.client = client;
59
+ }
91
60
 
92
61
  // human.set — update global profile
93
- set(opts: HumanSetOptions, tabId = "default"): Promise<HumanProfile> {
62
+ set(opts, tabId = "default") {
94
63
  return this.client.send("human.set", { ...opts, tabId });
95
64
  }
96
65
 
97
66
  // human.get — read current profile
98
- get(tabId = "default"): Promise<HumanProfile> {
67
+ get(tabId = "default") {
99
68
  return this.client.send("human.get", { tabId });
100
69
  }
101
70
 
102
71
  // human.type — char-by-char typing with realistic delays
103
- type(opts: HumanTypeOptions, tabId = "default"): Promise<void> {
72
+ type(opts, tabId = "default") {
104
73
  return this.client.send("human.type", { ...opts, tabId });
105
74
  }
106
75
 
107
76
  // human.click — delayed click with optional force dispatch
108
- click(opts: HumanClickOptions, tabId = "default"): Promise<void> {
77
+ click(opts, tabId = "default") {
109
78
  return this.client.send("human.click", { ...opts, tabId });
110
79
  }
111
80
  }
112
81
 
113
- export function createHumanAPI(client: PiggyClient): HumanClient {
82
+ export function createHumanAPI(client) {
114
83
  return new HumanClient(client);
115
- }
84
+ }
@@ -0,0 +1,56 @@
1
+ // piggy/iframe/index.js
2
+ import { PiggyClient } from "../client.js";
3
+
4
+ // ─── IframeClient ─────────────────────────────────────────────────────────────
5
+
6
+ export class IframeClient {
7
+ constructor(client) {
8
+ this.client = client;
9
+ }
10
+
11
+ /** List all iframes on the page: index, src, id, name. */
12
+ list(tabId = "default") {
13
+ return this.client.send("iframe.list", { tabId });
14
+ }
15
+
16
+ /** Run arbitrary JS inside the targeted iframe. Returns whatever the script returns. */
17
+ evaluate(opts, tabId = "default") {
18
+ return this.client.send("iframe.evaluate", { ...opts, tabId });
19
+ }
20
+
21
+ /** Click a selector inside the targeted iframe. */
22
+ click(opts, tabId = "default") {
23
+ return this.client.send("iframe.click", { ...opts, tabId });
24
+ }
25
+
26
+ /** Type text into a selector inside the targeted iframe. */
27
+ type(opts, tabId = "default") {
28
+ return this.client.send("iframe.type", { ...opts, tabId });
29
+ }
30
+
31
+ /** Get innerText of a selector inside the targeted iframe. */
32
+ text(opts, tabId = "default") {
33
+ return this.client.send("iframe.text", { ...opts, tabId });
34
+ }
35
+
36
+ /** Get the full HTML of the targeted iframe. */
37
+ html(opts, tabId = "default") {
38
+ return this.client.send("iframe.html", { ...opts, tabId });
39
+ }
40
+
41
+ /** Wait until a selector appears inside the targeted iframe. */
42
+ waitSel(opts, tabId = "default") {
43
+ return this.client.send("iframe.waitSel", { ...opts, tabId });
44
+ }
45
+ }
46
+
47
+ // ─── Factory helper ───────────────────────────────────────────────────────────
48
+
49
+ export function createIframeAPI(client) {
50
+ return new IframeClient(client);
51
+ }
52
+
53
+ // Usage:
54
+ // piggy.google.iframe.list()
55
+ // piggy.google.iframe.click({ index: 0, sel: "#btn" })
56
+ // piggy.google.iframe.evaluate({ src: "https://...", js: "document.title" })
@@ -1,79 +1,76 @@
1
- // piggy/interactions/index.ts
2
- import { PiggyClient } from "../client";
3
-
4
- export interface MousePosition {
5
- x: number;
6
- y: number;
7
- }
1
+ // piggy/interactions/index.js
2
+ import { PiggyClient } from "../client.js";
8
3
 
9
4
  export class InteractionsClient {
10
- constructor(private client: PiggyClient) {}
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
11
8
 
12
9
  // ── Click ─────────────────────────────────────────────────────────────────
13
10
 
14
- click(selector: string, tabId = "default"): Promise<boolean> {
11
+ click(selector, tabId = "default") {
15
12
  return this.client.send("click", { selector, tabId });
16
13
  }
17
14
 
18
- dblclick(selector: string, tabId = "default"): Promise<boolean> {
15
+ dblclick(selector, tabId = "default") {
19
16
  return this.client.send("dblclick", { selector, tabId });
20
17
  }
21
18
 
22
- hover(selector: string, tabId = "default"): Promise<boolean> {
19
+ hover(selector, tabId = "default") {
23
20
  return this.client.send("hover", { selector, tabId });
24
21
  }
25
22
 
26
23
  // ── Input ─────────────────────────────────────────────────────────────────
27
24
 
28
- type(selector: string, text: string, tabId = "default"): Promise<boolean> {
25
+ type(selector, text, tabId = "default") {
29
26
  return this.client.send("type", { selector, text, tabId });
30
27
  }
31
28
 
32
- typeClear(selector: string, text: string, tabId = "default"): Promise<boolean> {
29
+ typeClear(selector, text, tabId = "default") {
33
30
  return this.client.send("type", { selector, text, clear: true, tabId });
34
31
  }
35
32
 
36
- select(selector: string, value: string, tabId = "default"): Promise<boolean> {
33
+ select(selector, value, tabId = "default") {
37
34
  return this.client.send("select", { selector, value, tabId });
38
35
  }
39
36
 
40
37
  // ── Scroll ────────────────────────────────────────────────────────────────
41
38
 
42
- scrollTo(selector: string, tabId = "default"): Promise<boolean> {
39
+ scrollTo(selector, tabId = "default") {
43
40
  return this.client.send("scroll.to", { selector, tabId });
44
41
  }
45
42
 
46
- scrollBy(px: number, tabId = "default"): Promise<boolean> {
43
+ scrollBy(px, tabId = "default") {
47
44
  return this.client.send("scroll.by", { px, tabId });
48
45
  }
49
46
 
50
47
  // ── Keyboard ──────────────────────────────────────────────────────────────
51
48
 
52
- keyPress(key: string, tabId = "default"): Promise<boolean> {
49
+ keyPress(key, tabId = "default") {
53
50
  return this.client.send("keyboard.press", { key, tabId });
54
51
  }
55
52
 
56
- keyCombo(combo: string, tabId = "default"): Promise<boolean> {
53
+ keyCombo(combo, tabId = "default") {
57
54
  return this.client.send("keyboard.combo", { combo, tabId });
58
55
  }
59
56
 
60
57
  // ── Mouse ─────────────────────────────────────────────────────────────────
61
58
 
62
- mouseMove(x: number, y: number, tabId = "default"): Promise<boolean> {
59
+ mouseMove(x, y, tabId = "default") {
63
60
  return this.client.send("mouse.move", { x, y, tabId });
64
61
  }
65
62
 
66
- mouseDrag(from: MousePosition, to: MousePosition, tabId = "default"): Promise<boolean> {
63
+ mouseDrag(from, to, tabId = "default") {
67
64
  return this.client.send("mouse.drag", { from, to, tabId });
68
65
  }
69
66
 
70
67
  // ── Evaluate ──────────────────────────────────────────────────────────────
71
68
 
72
- evaluate(js: string, tabId = "default"): Promise<unknown> {
69
+ evaluate(js, tabId = "default") {
73
70
  return this.client.send("evaluate", { js, tabId });
74
71
  }
75
72
  }
76
73
 
77
- export function createInteractionsAPI(client: PiggyClient): InteractionsClient {
74
+ export function createInteractionsAPI(client) {
78
75
  return new InteractionsClient(client);
79
- }
76
+ }
@@ -1,4 +1,4 @@
1
- // piggy/intercept/scripts.ts
1
+ // piggy/intercept/scripts.js
2
2
  // JS injection helpers for intercept.respond and intercept.modifyResponse.
3
3
  // Both work purely in the browser's JS layer — no C++ changes needed.
4
4
 
@@ -6,12 +6,7 @@
6
6
  * Generates a script that short-circuits matching fetch/XHR requests
7
7
  * and returns a static fake response — the request never hits the network.
8
8
  */
9
- export function buildRespondScript(
10
- pattern: string,
11
- status: number,
12
- contentType: string,
13
- body: string
14
- ): string {
9
+ export function buildRespondScript(pattern, status, contentType, body) {
15
10
  const safePattern = pattern.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
16
11
  const safeBody = body.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
17
12
  const safeContentType = contentType.replace(/'/g, "\\'");
@@ -32,7 +27,6 @@ export function buildRespondScript(
32
27
  catch { return url.includes(pattern); }
33
28
  }
34
29
 
35
- // Only install wrappers once per page
36
30
  if (window.__PIGGY_RESPOND_INSTALLED__) return;
37
31
  window.__PIGGY_RESPOND_INSTALLED__ = true;
38
32
 
@@ -92,7 +86,7 @@ export function buildRespondScript(
92
86
  * The exposed function returns { body?, status?, headers? } modifications
93
87
  * or an empty object {} to pass through unchanged.
94
88
  */
95
- export function buildModifyResponseScript(pattern: string, exposedFnName: string): string {
89
+ export function buildModifyResponseScript(pattern, exposedFnName) {
96
90
  const safePattern = pattern.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
97
91
  const safeFnName = exposedFnName.replace(/'/g, "\\'");
98
92
 
@@ -107,7 +101,6 @@ export function buildModifyResponseScript(pattern: string, exposedFnName: string
107
101
  catch { return url.includes(pattern); }
108
102
  }
109
103
 
110
- // Only install wrappers once per page
111
104
  if (window.__PIGGY_MODIFY_INSTALLED__) return;
112
105
  window.__PIGGY_MODIFY_INSTALLED__ = true;
113
106
 
@@ -121,7 +114,6 @@ export function buildModifyResponseScript(pattern: string, exposedFnName: string
121
114
  if (_piggyMatchUrl(url, rule.pattern)) { matchedFn = rule.fn; break; }
122
115
  }
123
116
 
124
- // No match — pass through untouched
125
117
  const resp = await _origFetch.apply(this, arguments);
126
118
  if (!matchedFn) return resp;
127
119
 
@@ -133,7 +125,6 @@ export function buildModifyResponseScript(pattern: string, exposedFnName: string
133
125
  const handlerFn = window[matchedFn];
134
126
  if (typeof handlerFn !== 'function') return resp;
135
127
 
136
- // Call Node.js handler via exposeFunction bridge
137
128
  const mod = await handlerFn({ body: bodyText, status: resp.status, headers });
138
129
  if (!mod || typeof mod !== 'object' || Object.keys(mod).length === 0) return resp;
139
130
 
@@ -145,7 +136,7 @@ export function buildModifyResponseScript(pattern: string, exposedFnName: string
145
136
  }
146
137
  );
147
138
  } catch {
148
- return resp; // On any error, pass through original response
139
+ return resp;
149
140
  }
150
141
  };
151
142
  })();