nothing-browser 0.1.3 → 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 (120) 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.ts → piggy.js} +122 -146
  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 -30223
  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/logger/{index.ts → index.js} +0 -0
@@ -1,55 +1,15 @@
1
- // piggy/server/index.ts
1
+ // piggy/server/index.js
2
2
  import { Elysia } from "elysia";
3
3
  import { openapi } from "@elysiajs/openapi";
4
- import * as cache from "../cache/memory";
5
- import logger from "../logger";
6
-
7
- export type BeforeMiddleware = (ctx: {
8
- params: Record<string, string>;
9
- query: Record<string, string>;
10
- body: any;
11
- headers: Record<string, string>;
12
- set: any;
13
- }) => void | Promise<void>;
14
-
15
- export type RouteHandler = (
16
- params: Record<string, string>,
17
- query: Record<string, string>,
18
- body: any
19
- ) => Promise<any>;
20
-
21
- export interface RouteParameter {
22
- name: string;
23
- in: "query" | "path" | "header" | "cookie";
24
- description?: string;
25
- required?: boolean;
26
- schema?: Record<string, any>;
27
- }
28
-
29
- export interface RouteDetail {
30
- tags?: string[];
31
- summary?: string;
32
- description?: string;
33
- deprecated?: boolean;
34
- hide?: boolean;
35
- parameters?: RouteParameter[];
36
- }
4
+ import * as cache from "../cache/memory.js";
5
+ import logger from "../logger.js";
37
6
 
38
- export interface RouteConfig {
39
- path: string;
40
- method: "GET" | "POST" | "PUT" | "DELETE";
41
- handler: RouteHandler;
42
- ttl: number;
43
- before: BeforeMiddleware[];
44
- detail?: RouteDetail;
45
- }
46
-
47
- export const routeRegistry = new Map<string, RouteConfig>();
48
- export const keepAliveSites = new Set<string>();
7
+ export const routeRegistry = new Map();
8
+ export const keepAliveSites = new Set();
49
9
 
50
10
  // ── Error mapper ──────────────────────────────────────────────────────────────
51
11
 
52
- function mapError(err: Error, site: string) {
12
+ function mapError(err, site) {
53
13
  const msg = err.message.toLowerCase();
54
14
  if (msg.includes("selector") || msg.includes("not found") || msg.includes("null"))
55
15
  return { status: 404, error: "Not found", site, details: err.message };
@@ -62,18 +22,9 @@ function mapError(err: Error, site: string) {
62
22
 
63
23
  // ── Server factory ────────────────────────────────────────────────────────────
64
24
 
65
- let _app: Elysia | null = null;
25
+ let _app = null;
66
26
 
67
- export async function startServer(
68
- port: number,
69
- hostname = "0.0.0.0",
70
- openapiOpts?: {
71
- title?: string;
72
- version?: string;
73
- description?: string;
74
- path?: string;
75
- }
76
- ): Promise<Elysia> {
27
+ export async function startServer(port, hostname = "0.0.0.0", openapiOpts) {
77
28
  _app = new Elysia();
78
29
 
79
30
  // ── OpenAPI ───────────────────────────────────────────────────────────────
@@ -117,15 +68,15 @@ export async function startServer(
117
68
  const colonIdx = registryKey.indexOf(":");
118
69
  const siteName = registryKey.substring(0, colonIdx);
119
70
  const fullPath = `/${siteName}${config.path}`;
120
- const method = config.method.toLowerCase() as "get" | "post" | "put" | "delete";
71
+ const method = config.method.toLowerCase();
121
72
 
122
73
  logger.info(`[server] mounting ${config.method} ${fullPath} (ttl=${config.ttl}ms)`);
123
74
 
124
- const routeHandler = async ({ params, query, body, headers, set }: any) => {
75
+ const routeHandler = async ({ params, query, body, headers, set }) => {
125
76
  for (const mw of config.before) {
126
77
  try {
127
78
  await mw({ params, query, body, headers, set });
128
- } catch (e: any) {
79
+ } catch (e) {
129
80
  set.status = set.status ?? 400;
130
81
  return { error: e.message };
131
82
  }
@@ -139,10 +90,10 @@ export async function startServer(
139
90
  return hit;
140
91
  }
141
92
 
142
- let result: any;
93
+ let result;
143
94
  try {
144
95
  result = await config.handler(params, query, body);
145
- } catch (e: any) {
96
+ } catch (e) {
146
97
  const mapped = mapError(e, siteName);
147
98
  set.status = mapped.status;
148
99
  return mapped;
@@ -173,8 +124,9 @@ export async function startServer(
173
124
 
174
125
  _app.listen({ port, hostname });
175
126
 
176
- logger.success(`🚀 Piggy API server → http://${hostname === "0.0.0.0" ? "localhost" : hostname}:${port}`);
177
- logger.success(`📖 OpenAPI docs → http://${hostname === "0.0.0.0" ? "localhost" : hostname}:${port}/openapi`);
127
+ const host = hostname === "0.0.0.0" ? "localhost" : hostname;
128
+ logger.success(`🚀 Piggy API server → http://${host}:${port}`);
129
+ logger.success(`📖 OpenAPI docs → http://${host}:${port}/openapi`);
178
130
  logger.info(` Routes mounted: ${routeRegistry.size}`);
179
131
  routeRegistry.forEach((cfg, key) => {
180
132
  const siteName = key.substring(0, key.indexOf(":"));
@@ -0,0 +1,69 @@
1
+ // piggy/session/index.js
2
+ import { PiggyClient } from "../client.js";
3
+
4
+ export class SessionClient {
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
8
+
9
+ // Session lifecycle
10
+ reload(tabId = "default") {
11
+ return this.client.send("session.reload", { tabId });
12
+ }
13
+
14
+ // Paths
15
+ paths() {
16
+ return this.client.send("session.paths", {});
17
+ }
18
+
19
+ cookiesPath() {
20
+ return this.client.send("session.cookies.path", {});
21
+ }
22
+
23
+ profilePath() {
24
+ return this.client.send("session.profile.path", {});
25
+ }
26
+
27
+ wsPath() {
28
+ return this.client.send("session.ws.path", {});
29
+ }
30
+
31
+ pingsPath() {
32
+ return this.client.send("session.pings.path", {});
33
+ }
34
+
35
+ // Opt-in persistence
36
+ setWsSave(enabled) {
37
+ return this.client.send("session.ws.save", { enabled });
38
+ }
39
+
40
+ setPingsSave(enabled) {
41
+ return this.client.send("session.pings.save", { enabled });
42
+ }
43
+
44
+ // Export / import
45
+ async export(tabId = "default") {
46
+ const raw = await this.client.send("session.export", { tabId });
47
+ return typeof raw === "string" ? JSON.parse(raw) : raw;
48
+ }
49
+
50
+ import(data, tabId = "default") {
51
+ return this.client.send("session.import", {
52
+ data: JSON.stringify(data),
53
+ tabId,
54
+ });
55
+ }
56
+
57
+ // Cookies
58
+ setCookie(opts, tabId = "default") {
59
+ return this.client.send("cookie.set", { ...opts, tabId });
60
+ }
61
+
62
+ deleteCookie(opts, tabId = "default") {
63
+ return this.client.send("cookie.delete", { ...opts, tabId });
64
+ }
65
+ }
66
+
67
+ export function createSessionAPI(client) {
68
+ return new SessionClient(client);
69
+ }
@@ -1,33 +1,13 @@
1
- // piggy/store/index.ts
1
+ // piggy/store/index.js
2
2
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
3
3
  import { dirname, resolve } from "path";
4
- import logger from "../logger";
5
-
6
- // ── Types ─────────────────────────────────────────────────────────────────────
7
-
8
- export type FieldType = "string" | "number" | "boolean" | "object" | "array";
9
-
10
- export interface FieldSchema {
11
- type: FieldType;
12
- required?: boolean; // default false — missing = NULL not error
13
- default?: any; // fallback if missing (overrides NULL)
14
- }
15
-
16
- export interface StoreSchema {
17
- name: string; // store identifier (matches site name or custom)
18
- destination: string; // "./data.json" or "./data.db"
19
- fields: Record<string, FieldSchema>;
20
- }
21
-
22
- export interface PiggyStoreConfig {
23
- stores: StoreSchema[];
24
- }
4
+ import logger from "../logger.js";
25
5
 
26
6
  // ── Load piggy.store.json ─────────────────────────────────────────────────────
27
7
 
28
- let _config: PiggyStoreConfig | null = null;
8
+ let _config = null;
29
9
 
30
- export function loadStoreConfig(configPath = "./piggy.store.json"): PiggyStoreConfig {
10
+ export function loadStoreConfig(configPath = "./piggy.store.json") {
31
11
  if (_config) return _config;
32
12
 
33
13
  const abs = resolve(configPath);
@@ -37,39 +17,33 @@ export function loadStoreConfig(configPath = "./piggy.store.json"): PiggyStoreCo
37
17
  }
38
18
 
39
19
  try {
40
- _config = JSON.parse(readFileSync(abs, "utf8")) as PiggyStoreConfig;
20
+ _config = JSON.parse(readFileSync(abs, "utf8"));
41
21
  logger.success(`[store] loaded ${_config.stores.length} schema(s) from ${abs}`);
42
22
  return _config;
43
- } catch (e: any) {
23
+ } catch (e) {
44
24
  logger.error(`[store] failed to parse piggy.store.json: ${e.message}`);
45
25
  return { stores: [] };
46
26
  }
47
27
  }
48
28
 
49
- export function getSchema(storeName: string): StoreSchema | null {
29
+ export function getSchema(storeName) {
50
30
  const config = loadStoreConfig();
51
31
  return config.stores.find(s => s.name === storeName) ?? null;
52
32
  }
53
33
 
54
34
  // ── Validate & shape one record against schema ────────────────────────────────
55
35
 
56
- export function shapeRecord(data: Record<string, any>, schema: StoreSchema): Record<string, any> {
57
- const shaped: Record<string, any> = {};
36
+ export function shapeRecord(data, schema) {
37
+ const shaped = {};
58
38
 
59
39
  for (const [field, def] of Object.entries(schema.fields)) {
60
40
  const raw = data[field];
61
41
 
62
- // Missing field
63
42
  if (raw === undefined || raw === null) {
64
- if (def.default !== undefined) {
65
- shaped[field] = def.default;
66
- } else {
67
- shaped[field] = null; // NULL — not an error, just absent
68
- }
43
+ shaped[field] = def.default !== undefined ? def.default : null;
69
44
  continue;
70
45
  }
71
46
 
72
- // Type coercion / validation
73
47
  switch (def.type) {
74
48
  case "string":
75
49
  shaped[field] = String(raw);
@@ -92,17 +66,16 @@ export function shapeRecord(data: Record<string, any>, schema: StoreSchema): Rec
92
66
  }
93
67
  }
94
68
 
95
- // Extra fields on incoming data are silently dropped — not in schema = ignored
96
69
  return shaped;
97
70
  }
98
71
 
99
72
  // ── JSON backend ──────────────────────────────────────────────────────────────
100
73
 
101
- function appendToJson(destination: string, record: Record<string, any>): void {
74
+ function appendToJson(destination, record) {
102
75
  const abs = resolve(destination);
103
76
  mkdirSync(dirname(abs), { recursive: true });
104
77
 
105
- let existing: any[] = [];
78
+ let existing = [];
106
79
  if (existsSync(abs)) {
107
80
  try {
108
81
  existing = JSON.parse(readFileSync(abs, "utf8"));
@@ -118,15 +91,14 @@ function appendToJson(destination: string, record: Record<string, any>): void {
118
91
 
119
92
  // ── SQLite backend ────────────────────────────────────────────────────────────
120
93
 
121
- function appendToSqlite(destination: string, record: Record<string, any>, schema: StoreSchema): void {
122
- // Use bun:sqlite if available, else require better-sqlite3
94
+ function appendToSqlite(destination, record, schema) {
123
95
  const abs = resolve(destination);
124
96
  mkdirSync(dirname(abs), { recursive: true });
125
97
 
126
- const isBun = typeof (globalThis as any).Bun !== "undefined";
98
+ const isBun = typeof globalThis.Bun !== "undefined";
127
99
 
128
100
  if (isBun) {
129
- const { Database } = require("bun:sqlite") as typeof import("bun:sqlite");
101
+ const { Database } = require("bun:sqlite");
130
102
  const db = new Database(abs);
131
103
  ensureTable(db, schema, "bun");
132
104
  insertRecord(db, schema, record, "bun");
@@ -140,12 +112,12 @@ function appendToSqlite(destination: string, record: Record<string, any>, schema
140
112
  }
141
113
  }
142
114
 
143
- function ensureTable(db: any, schema: StoreSchema, runtime: "bun" | "node"): void {
115
+ function ensureTable(db, schema, runtime) {
144
116
  const tableName = schema.name.replace(/[^a-zA-Z0-9_]/g, "_");
145
117
  const cols = Object.entries(schema.fields).map(([name, def]) => {
146
118
  const sqlType = def.type === "number" ? "REAL"
147
119
  : def.type === "boolean" ? "INTEGER"
148
- : def.type === "object" || def.type === "array" ? "TEXT" // JSON stringified
120
+ : def.type === "object" || def.type === "array" ? "TEXT"
149
121
  : "TEXT";
150
122
  return ` ${name} ${sqlType}`;
151
123
  });
@@ -153,20 +125,15 @@ function ensureTable(db: any, schema: StoreSchema, runtime: "bun" | "node"): voi
153
125
 
154
126
  const sql = `CREATE TABLE IF NOT EXISTS ${tableName} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n${cols.join(",\n")}\n)`;
155
127
 
156
- if (runtime === "bun") {
157
- db.run(sql);
158
- } else {
159
- db.prepare(sql).run();
160
- }
128
+ runtime === "bun" ? db.run(sql) : db.prepare(sql).run();
161
129
  }
162
130
 
163
- function insertRecord(db: any, schema: StoreSchema, record: Record<string, any>, runtime: "bun" | "node"): void {
131
+ function insertRecord(db, schema, record, runtime) {
164
132
  const tableName = schema.name.replace(/[^a-zA-Z0-9_]/g, "_");
165
133
  const fields = [...Object.keys(schema.fields), "_storedAt"];
166
134
  const values = fields.map(f => {
167
135
  if (f === "_storedAt") return new Date().toISOString();
168
136
  const v = record[f];
169
- // Serialize objects/arrays as JSON strings for SQLite
170
137
  if (v !== null && (typeof v === "object" || Array.isArray(v))) return JSON.stringify(v);
171
138
  return v ?? null;
172
139
  });
@@ -177,19 +144,12 @@ function insertRecord(db: any, schema: StoreSchema, record: Record<string, any>,
177
144
 
178
145
  const sql = `INSERT INTO ${tableName} (${fields.join(", ")}) VALUES (${placeholders})`;
179
146
 
180
- if (runtime === "bun") {
181
- db.run(sql, values);
182
- } else {
183
- db.prepare(sql).run(values);
184
- }
147
+ runtime === "bun" ? db.run(sql, values) : db.prepare(sql).run(values);
185
148
  }
186
149
 
187
150
  // ── Main store function ───────────────────────────────────────────────────────
188
151
 
189
- export async function storeRecord(
190
- storeName: string,
191
- data: Record<string, any> | Record<string, any>[]
192
- ): Promise<{ stored: number; skipped: number }> {
152
+ export async function storeRecord(storeName, data) {
193
153
  const schema = getSchema(storeName);
194
154
 
195
155
  if (!schema) {
@@ -220,7 +180,7 @@ export async function storeRecord(
220
180
 
221
181
  stored++;
222
182
  logger.success(`[store][${storeName}] stored record → ${schema.destination}`);
223
- } catch (e: any) {
183
+ } catch (e) {
224
184
  logger.error(`[store][${storeName}] failed to store record: ${e.message}`);
225
185
  skipped++;
226
186
  }
@@ -0,0 +1,24 @@
1
+ // piggy/tabs/index.js
2
+
3
+ export class TabsClient {
4
+ constructor(client) {
5
+ this.client = client;
6
+ }
7
+
8
+ new() {
9
+ return this.client.send("tab.new", {});
10
+ }
11
+
12
+ close(opts) {
13
+ const tabId = typeof opts === "string" ? opts : opts.tabId;
14
+ return this.client.send("tab.close", { tabId });
15
+ }
16
+
17
+ list() {
18
+ return this.client.send("tab.list", {});
19
+ }
20
+ }
21
+
22
+ export function createTabsAPI(client) {
23
+ return new TabsClient(client);
24
+ }
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ // ─── WaitClient ───────────────────────────────────────────────────────────────
4
+
5
+ class WaitClient {
6
+ constructor(client) {
7
+ this.client = client;
8
+ }
9
+
10
+ function(js, timeout = 10000, tabId = "default") {
11
+ return this.client.send("wait.function", { js, timeout, tabId });
12
+ }
13
+
14
+ selector(selector, state = "attached", timeout = 10000, tabId = "default") {
15
+ return this.client.send("wait.selector", { selector, state, timeout, tabId });
16
+ }
17
+ }
18
+
19
+ // ─── EvaluateClient ───────────────────────────────────────────────────────────
20
+
21
+ class EvaluateClient {
22
+ constructor(client) {
23
+ this.client = client;
24
+ }
25
+
26
+ run(js, timeout, tabId = "default") {
27
+ return this.client.send("evaluate", {
28
+ js,
29
+ tabId,
30
+ ...(timeout !== undefined ? { timeout } : {}),
31
+ });
32
+ }
33
+ }
34
+
35
+ // ─── FetchClient ──────────────────────────────────────────────────────────────
36
+
37
+ class FetchClient {
38
+ constructor(client) {
39
+ this.client = client;
40
+ }
41
+
42
+ text(selector, tabId = "default") {
43
+ return this.client.send("fetch.text", { query: selector, tabId });
44
+ }
45
+
46
+ textAll(selector, tabId = "default") {
47
+ return this.client.send("fetch.textAll", { selector, tabId });
48
+ }
49
+
50
+ attr(selector, attr, tabId = "default") {
51
+ return this.client.send("fetch.attr", { selector, attr, tabId });
52
+ }
53
+
54
+ attrAll(selector, attr, tabId = "default") {
55
+ return this.client.send("fetch.attrAll", { selector, attr, tabId });
56
+ }
57
+
58
+ links(selector, tabId = "default") {
59
+ return this.client.send("fetch.links", { query: selector, tabId });
60
+ }
61
+
62
+ linksAll(tabId = "default") {
63
+ return this.client.send("fetch.links.all", { tabId });
64
+ }
65
+
66
+ images(selector, tabId = "default") {
67
+ return this.client.send("fetch.image", { query: selector, tabId });
68
+ }
69
+ }
70
+
71
+ // ─── Factories ────────────────────────────────────────────────────────────────
72
+
73
+ function createWaitAPI(client) { return new WaitClient(client); }
74
+ function createEvaluateAPI(client) { return new EvaluateClient(client); }
75
+ function createFetchAPI(client) { return new FetchClient(client); }
76
+
77
+ module.exports = { WaitClient, EvaluateClient, FetchClient, createWaitAPI, createEvaluateAPI, createFetchAPI };