nothing-browser 0.0.1 → 0.0.3

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/README.md CHANGED
@@ -20,7 +20,21 @@ A scraper-first headless browser library powered by the Nothing Browser Qt6/Chro
20
20
  ## Requirements
21
21
 
22
22
  - [Bun](https://bun.sh) ≥ 1.0
23
- - Nothing Browser headless binary (see below)
23
+ - A Nothing Browser binary placed in your **project root** (see below)
24
+
25
+ ---
26
+
27
+ ## Binaries
28
+
29
+ There are three binaries. All are downloaded from the same place — [GitHub Releases](https://github.com/BunElysiaReact/nothing-browser/releases).
30
+
31
+ | Binary | What it is | Where it goes |
32
+ |--------|-----------|---------------|
33
+ | `nothing-browser` | Full UI browser app — DevTools, YouTube tab, Plugins, etc. | Install system-wide |
34
+ | `nothing-browser-headless` | No window, no GPU. Runs as a background daemon for the scraping lib. | **Your project root** |
35
+ | `nothing-browser-headful` | Visible browser window, script-controlled. Useful when a site needs a real display. | **Your project root** |
36
+
37
+ The `nothingbrowser` npm/Bun lib talks to whichever binary is in your project root over a local socket. You pick headless or headful depending on your use case.
24
38
 
25
39
  ---
26
40
 
@@ -30,17 +44,38 @@ A scraper-first headless browser library powered by the Nothing Browser Qt6/Chro
30
44
  bun add nothing-browser
31
45
  ```
32
46
 
33
- Then download the **headless binary** for your platform from [GitHub Releases](https://github.com/BunElysiaReact/nothing-browser/releases) and place it in your project root.
47
+ Then download the binary for your platform from [GitHub Releases](https://github.com/BunElysiaReact/nothing-browser/releases) and place it in your project root.
34
48
 
35
- **Linux**
49
+ ### Linux
50
+
51
+ **Headless** (no visible window — most common for scraping)
36
52
  ```bash
37
53
  tar -xzf nothing-browser-headless-*-linux-x86_64.tar.gz
38
54
  chmod +x nothing-browser-headless
39
55
  ```
40
56
 
41
- **Windows** extract the `.zip`, place `nothing-browser-headless.exe` in project root.
57
+ **Headful** (visible window, script-controlled)
58
+ ```bash
59
+ tar -xzf nothing-browser-headful-*-linux-x86_64.tar.gz
60
+ chmod +x nothing-browser-headful
61
+ ```
62
+
63
+ **Full browser** (system-wide install, for using the UI)
64
+ ```bash
65
+ sudo dpkg -i nothing-browser_*_amd64.deb
66
+ # or
67
+ tar -xzf nothing-browser-*-linux-x86_64.tar.gz
68
+ cd nothing-browser-*-linux-x86_64
69
+ ./nothing-browser
70
+ ```
71
+
72
+ ### Windows
73
+
74
+ Download the `.zip` for your chosen binary → extract → place `nothing-browser-headless.exe` or `nothing-browser-headful.exe` in your project root. The JRE is bundled in the full browser zip.
42
75
 
43
- **macOS** — extract the `.tar.gz`, place `nothing-browser-headless` in project root.
76
+ ### macOS
77
+
78
+ Download the `.tar.gz` for your chosen binary → extract → place the binary in your project root.
44
79
 
45
80
  ---
46
81
 
@@ -86,6 +121,24 @@ await piggy.launch({ mode: "process" });
86
121
 
87
122
  ---
88
123
 
124
+ ## Headless vs Headful
125
+
126
+ **Headless** — no display needed, runs anywhere including CI. Use this by default.
127
+
128
+ ```
129
+ nothing-browser-headless ← in your project root
130
+ ```
131
+
132
+ **Headful** — opens a real visible Chromium window that your script drives. Use this when a site detects headless mode or requires a real display (canvas fingerprinting, certain login flows, etc).
133
+
134
+ ```
135
+ nothing-browser-headful ← in your project root
136
+ ```
137
+
138
+ Both binaries expose the exact same socket API. Switching is just swapping which binary is in your project root.
139
+
140
+ ---
141
+
89
142
  ## Examples
90
143
 
91
144
  ### Scrape a site and expose it as an API
@@ -96,7 +149,6 @@ import piggy from "nothing-browser";
96
149
  await piggy.launch({ mode: "tab" });
97
150
  await piggy.register("books", "https://books.toscrape.com");
98
151
 
99
- // Block ads/trackers before any navigation
100
152
  await piggy.books.intercept.block("*google-analytics*");
101
153
  await piggy.books.intercept.block("*doubleclick*");
102
154
  await piggy.books.intercept.block("*facebook*");
@@ -127,8 +179,6 @@ piggy.books.api("/list", async (_params, query) => {
127
179
 
128
180
  piggy.books.noclose();
129
181
  await piggy.serve(3000);
130
- // GET http://localhost:3000/books/list
131
- // GET http://localhost:3000/books/list?page=2
132
182
  ```
133
183
 
134
184
  ---
@@ -167,8 +217,6 @@ piggy.books.api("/search", async (_params, query) => {
167
217
 
168
218
  return { query: query.q, count: books.length, books };
169
219
  }, { ttl: 120_000, before: [logMiddleware, authMiddleware] });
170
-
171
- // curl -H 'x-api-key: piggy-secret' 'http://localhost:3000/books/search?q=light'
172
220
  ```
173
221
 
174
222
  ---
@@ -178,11 +226,11 @@ piggy.books.api("/search", async (_params, query) => {
178
226
  ```ts
179
227
  await piggy.books.capture.clear();
180
228
  await piggy.books.capture.start();
181
- await piggy.books.wait(300); // ensure capture is active before nav
229
+ await piggy.books.wait(300);
182
230
 
183
231
  await piggy.books.navigate("https://books.toscrape.com");
184
232
  await piggy.books.waitForSelector("body", 10000);
185
- await piggy.books.wait(2000); // let async XHR/fetch calls settle
233
+ await piggy.books.wait(2000);
186
234
 
187
235
  await piggy.books.capture.stop();
188
236
 
@@ -203,13 +251,11 @@ import { existsSync, readFileSync, writeFileSync } from "fs";
203
251
 
204
252
  const SESSION_FILE = "./session.json";
205
253
 
206
- // Restore on startup
207
254
  if (existsSync(SESSION_FILE)) {
208
255
  const saved = JSON.parse(readFileSync(SESSION_FILE, "utf8"));
209
256
  await piggy.books.session.import(saved);
210
257
  }
211
258
 
212
- // Save on shutdown — always BEFORE piggy.close()
213
259
  process.on("SIGINT", async () => {
214
260
  const session = await piggy.books.session.export();
215
261
  writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
@@ -222,8 +268,6 @@ process.on("SIGINT", async () => {
222
268
 
223
269
  ### Human mode
224
270
 
225
- Makes interactions look less robotic — random delays, simulated typos + self-correction.
226
-
227
271
  ```ts
228
272
  piggy.actHuman(true);
229
273
 
@@ -232,18 +276,14 @@ await piggy.books.type("#search", "mystery novels");
232
276
  await piggy.books.scroll.by(400);
233
277
  ```
234
278
 
235
- Affects: `click`, `type`, `hover`, `scroll.by`, `wait`.
236
-
237
279
  ---
238
280
 
239
281
  ### Screenshot / PDF
240
282
 
241
283
  ```ts
242
- // Save to disk
243
284
  await piggy.books.screenshot("./out/page.png");
244
285
  await piggy.books.pdf("./out/page.pdf");
245
286
 
246
- // Or get base64
247
287
  const b64 = await piggy.books.screenshot();
248
288
  ```
249
289
 
@@ -255,11 +295,8 @@ const b64 = await piggy.books.screenshot();
255
295
  await piggy.register("site1", "https://example.com");
256
296
  await piggy.register("site2", "https://example.org");
257
297
 
258
- // Same method on both sites in parallel
259
298
  const titles = await piggy.all([piggy.site1, piggy.site2]).title();
260
-
261
- // Keyed results by site name
262
- const h1s = await piggy.diff([piggy.site1, piggy.site2]).fetchText("h1");
299
+ const h1s = await piggy.diff([piggy.site1, piggy.site2]).fetchText("h1");
263
300
  // → { site1: "...", site2: "..." }
264
301
  ```
265
302
 
@@ -351,7 +388,7 @@ site.api(path, handler, opts?)
351
388
  // opts: { ttl?, method?, before?: middleware[] }
352
389
  // handler: (params, query, body) => Promise<any>
353
390
 
354
- site.noclose() // keep site alive across piggy.close()
391
+ site.noclose()
355
392
  site.screenshot(filePath?) / site.pdf(filePath?)
356
393
  ```
357
394
 
@@ -359,12 +396,12 @@ site.screenshot(filePath?) / site.pdf(filePath?)
359
396
 
360
397
  ## Binary download
361
398
 
362
- | Platform | File |
363
- |----------|------|
364
- | Linux x86_64 (deb) | `nothing-browser-headless_*_amd64.deb` |
365
- | Linux x86_64 (tar.gz) | `nothing-browser-headless-*-linux-x86_64.tar.gz` |
366
- | Windows x64 | `nothing-browser-headless-*.zip` |
367
- | macOS | `nothing-browser-headless-*.tar.gz` |
399
+ | Platform | Headless | Headful | Full Browser |
400
+ |----------|----------|---------|--------------|
401
+ | Linux x86_64 (deb) | `nothing-browser-headless_*_amd64.deb` | `nothing-browser-headful_*_amd64.deb` | `nothing-browser_*_amd64.deb` |
402
+ | Linux x86_64 (tar.gz) | `nothing-browser-headless-*-linux-x86_64.tar.gz` | `nothing-browser-headful-*-linux-x86_64.tar.gz` | `nothing-browser-*-linux-x86_64.tar.gz` |
403
+ | Windows x64 | `nothing-browser-headless-*-windows-x64.zip` | `nothing-browser-headful-*-windows-x64.zip` | `nothing-browser-*-windows-x64.zip` |
404
+ | macOS | `nothing-browser-headless-*-macos.tar.gz` | `nothing-browser-headful-*-macos.tar.gz` | `nothing-browser-*-macos.dmg` |
368
405
 
369
406
  → [All releases](https://github.com/BunElysiaReact/nothing-browser/releases)
370
407
 
@@ -372,4 +409,4 @@ site.screenshot(filePath?) / site.pdf(filePath?)
372
409
 
373
410
  ## License
374
411
 
375
- MIT © [Ernest Tech House](https://github.com/BunElysiaReact)
412
+ MIT © [Ernest Tech House](https://github.com/BunElysiaReact/nothing-browser)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothing-browser",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Scraper-first headless browser library — control real tabs, intercept network traffic, capture WebSockets, spoof fingerprints. Powered by Qt6/Chromium.",
5
5
  "module": "piggy.ts",
6
6
  "main": "piggy.ts",
@@ -24,15 +24,15 @@
24
24
  "fingerprint-spoofing",
25
25
  "network-interception"
26
26
  ],
27
- "author": "Ernest Tech House <BunElysiaReact>",
27
+ "author": "Ernest Tech House",
28
28
  "license": "MIT",
29
- "homepage": "https://github.com/BunElysiaReact/nothing-browser#readme",
29
+ "homepage": "https://github.com/ernest-tech-house-co-operation/nothing-browser#readme",
30
30
  "repository": {
31
31
  "type": "git",
32
- "url": "https://github.com/BunElysiaReact/nothing-browser.git"
32
+ "url": "https://github.com/ernest-tech-house-co-operation/nothing-browser.git"
33
33
  },
34
34
  "bugs": {
35
- "url": "https://github.com/BunElysiaReact/nothing-browser/issues"
35
+ "url": "https://github.com/ernest-tech-house-co-operation/nothing-browser/issues"
36
36
  },
37
37
  "files": [
38
38
  "piggy.ts",
@@ -2,32 +2,42 @@ import { existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import logger from '../logger';
4
4
 
5
- export function detectBinary(): string | null {
6
- const cwd = process.cwd();
7
-
8
- // Windows
9
- const windowsPath = join(cwd, 'nothing-browser-headless.exe');
10
- if (process.platform === 'win32' && existsSync(windowsPath)) {
11
- logger.success(`Binary found! Platform: Windows`);
12
- return windowsPath;
13
- }
14
-
15
- // Linux / macOS
16
- const unixPath = join(cwd, 'nothing-browser-headless');
17
- if (existsSync(unixPath)) {
18
- logger.success(`Binary found at: ${unixPath}`);
19
- return unixPath;
20
- }
21
-
22
- logger.error("❌ Binary not found in project root");
23
- logger.error("");
24
- logger.error("Download from:");
25
- logger.error(" https://github.com/BunElysiaReact/nothing-browser/releases/");
26
- logger.error("");
27
- logger.error(`Place in: ${cwd}/nothing-browser-headless${process.platform === 'win32' ? '.exe' : ''}`);
28
- if (process.platform !== 'win32') {
29
- logger.error("Then run: chmod +x nothing-browser-headless");
5
+ export type BinaryMode = 'headless' | 'headful';
6
+
7
+ const BINARY_NAMES: Record<BinaryMode, string> = {
8
+ headless: 'nothing-browser-headless',
9
+ headful: 'nothing-browser-headful',
10
+ };
11
+
12
+ export function detectBinary(mode: BinaryMode = 'headless'): string | null {
13
+ const cwd = process.cwd();
14
+ const name = BINARY_NAMES[mode];
15
+
16
+ // Windows
17
+ if (process.platform === 'win32') {
18
+ const p = join(cwd, `${name}.exe`);
19
+ if (existsSync(p)) {
20
+ logger.success(`Binary found (${mode}): ${p}`);
21
+ return p;
30
22
  }
31
-
32
- return null;
23
+ }
24
+
25
+ // Linux / macOS
26
+ const p = join(cwd, name);
27
+ if (existsSync(p)) {
28
+ logger.success(`Binary found (${mode}): ${p}`);
29
+ return p;
30
+ }
31
+
32
+ logger.error(`❌ Binary not found in project root: ${name}`);
33
+ logger.error('');
34
+ logger.error('Download from:');
35
+ logger.error(' https://github.com/BunElysiaReact/nothing-browser/releases/');
36
+ logger.error('');
37
+ logger.error(`Place in: ${cwd}/${name}${process.platform === 'win32' ? '.exe' : ''}`);
38
+ if (process.platform !== 'win32') {
39
+ logger.error(`Then run: chmod +x ${name}`);
40
+ }
41
+
42
+ return null;
33
43
  }
@@ -1,101 +1,99 @@
1
1
  import { spawn } from 'bun';
2
2
  import { execSync } from 'child_process';
3
- import { detectBinary } from './detect';
3
+ import { detectBinary, type BinaryMode } from './detect';
4
4
  import logger from '../logger';
5
5
 
6
6
  let activeProcess: any = null;
7
7
  const extraProcesses: any[] = [];
8
8
 
9
9
  export function killAllBrowsers(): void {
10
- try {
11
- logger.info("Cleaning up existing browser processes...");
12
- execSync('pkill -f nothing-browser-headless 2>/dev/null || true', { stdio: 'ignore' });
13
- execSync('pkill -f QtWebEngineProcess 2>/dev/null || true', { stdio: 'ignore' });
14
- execSync('rm -f /tmp/piggy', { stdio: 'ignore' });
15
- } catch {
16
- // Ignore errors - no processes to kill
17
- }
10
+ try {
11
+ logger.info('Cleaning up existing browser processes...');
12
+ execSync('pkill -f nothing-browser-headless 2>/dev/null || true', { stdio: 'ignore' });
13
+ execSync('pkill -f nothing-browser-headful 2>/dev/null || true', { stdio: 'ignore' });
14
+ execSync('pkill -f QtWebEngineProcess 2>/dev/null || true', { stdio: 'ignore' });
15
+ execSync('rm -f /tmp/piggy', { stdio: 'ignore' });
16
+ } catch {
17
+ // no processes to kill
18
+ }
18
19
  }
19
20
 
20
- export async function spawnBrowser(): Promise<string> {
21
- killAllBrowsers();
22
-
23
- // Give OS time to release the socket
24
- await new Promise(resolve => setTimeout(resolve, 500));
25
-
26
- const binaryPath = detectBinary();
27
- if (!binaryPath) {
28
- throw new Error("Binary not found. Cannot launch.");
29
- }
30
-
31
- logger.info(`Spawning Nothing Browser from: ${binaryPath}`);
32
-
33
- activeProcess = spawn([binaryPath], {
34
- stdio: ['ignore', 'pipe', 'pipe'],
35
- env: process.env
36
- });
37
-
38
- if (activeProcess.stdout) {
39
- const reader = activeProcess.stdout.getReader();
40
- const read = async () => {
41
- const { done, value } = await reader.read();
42
- if (!done) {
43
- const output = new TextDecoder().decode(value);
44
- logger.debug(`[Browser] ${output}`);
45
- read();
46
- }
47
- };
21
+ export async function spawnBrowser(mode: BinaryMode = 'headless'): Promise<string> {
22
+ killAllBrowsers();
23
+ await new Promise(resolve => setTimeout(resolve, 500));
24
+
25
+ const binaryPath = detectBinary(mode);
26
+ if (!binaryPath) {
27
+ throw new Error(`Binary not found (${mode}). Cannot launch.`);
28
+ }
29
+
30
+ logger.info(`Spawning Nothing Browser (${mode}) from: ${binaryPath}`);
31
+
32
+ activeProcess = spawn([binaryPath], {
33
+ stdio: ['ignore', 'pipe', 'pipe'],
34
+ env: process.env,
35
+ });
36
+
37
+ if (activeProcess.stdout) {
38
+ const reader = activeProcess.stdout.getReader();
39
+ const read = async () => {
40
+ const { done, value } = await reader.read();
41
+ if (!done) {
42
+ logger.debug(`[Browser] ${new TextDecoder().decode(value)}`);
48
43
  read();
49
- }
44
+ }
45
+ };
46
+ read();
47
+ }
50
48
 
51
- activeProcess.exited.then((code: number | null) => {
52
- logger.warn(`Browser process exited with code: ${code}`);
53
- activeProcess = null;
54
- });
49
+ activeProcess.exited.then((code: number | null) => {
50
+ logger.warn(`Browser process exited with code: ${code}`);
51
+ activeProcess = null;
52
+ });
55
53
 
56
- await new Promise(resolve => setTimeout(resolve, 2000));
54
+ await new Promise(resolve => setTimeout(resolve, 2000));
57
55
 
58
- if (activeProcess) {
59
- logger.success("Browser spawned and running");
60
- } else {
61
- logger.error("Browser started but exited immediately");
62
- }
56
+ if (activeProcess) {
57
+ logger.success(`Browser spawned and running (${mode})`);
58
+ } else {
59
+ logger.error('Browser started but exited immediately');
60
+ }
63
61
 
64
- return binaryPath;
62
+ return binaryPath;
65
63
  }
66
64
 
67
- export async function spawnBrowserOnSocket(socketName: string): Promise<void> {
68
- const binaryPath = detectBinary();
69
- if (!binaryPath) {
70
- throw new Error("Binary not found. Cannot launch.");
71
- }
65
+ export async function spawnBrowserOnSocket(
66
+ socketName: string,
67
+ mode: BinaryMode = 'headless'
68
+ ): Promise<void> {
69
+ const binaryPath = detectBinary(mode);
70
+ if (!binaryPath) {
71
+ throw new Error(`Binary not found (${mode}). Cannot launch.`);
72
+ }
72
73
 
73
- logger.info(`Spawning browser on socket: ${socketName}`);
74
+ logger.info(`Spawning browser (${mode}) on socket: ${socketName}`);
74
75
 
75
- const proc = spawn([binaryPath], {
76
- stdio: ['ignore', 'pipe', 'pipe'],
77
- env: { ...process.env, PIGGY_SOCKET: socketName }
78
- });
76
+ const proc = spawn([binaryPath], {
77
+ stdio: ['ignore', 'pipe', 'pipe'],
78
+ env: { ...process.env, PIGGY_SOCKET: socketName },
79
+ });
79
80
 
80
- extraProcesses.push(proc);
81
+ extraProcesses.push(proc);
81
82
 
82
- proc.exited.then((code: number | null) => {
83
- logger.warn(`Browser on socket ${socketName} exited with code: ${code}`);
84
- });
83
+ proc.exited.then((code: number | null) => {
84
+ logger.warn(`Browser on socket ${socketName} exited with code: ${code}`);
85
+ });
85
86
 
86
- await new Promise(resolve => setTimeout(resolve, 1000));
87
- logger.success(`Browser spawned on socket: ${socketName}`);
87
+ await new Promise(resolve => setTimeout(resolve, 1000));
88
+ logger.success(`Browser spawned (${mode}) on socket: ${socketName}`);
88
89
  }
89
90
 
90
91
  export function killBrowser(): void {
91
- if (activeProcess) {
92
- logger.info("Killing browser process...");
93
- activeProcess.kill();
94
- activeProcess = null;
95
- }
96
-
97
- for (const proc of extraProcesses) {
98
- proc.kill();
99
- }
100
- extraProcesses.length = 0;
92
+ if (activeProcess) {
93
+ logger.info('Killing browser process...');
94
+ activeProcess.kill();
95
+ activeProcess = null;
96
+ }
97
+ for (const proc of extraProcesses) proc.kill();
98
+ extraProcesses.length = 0;
101
99
  }
package/piggy.ts CHANGED
@@ -1,45 +1,47 @@
1
1
  // piggy.ts
2
- import { detectBinary } from "./piggy/launch/detect";
2
+ import { detectBinary, type BinaryMode } from "./piggy/launch/detect";
3
3
  import { spawnBrowser, killBrowser, spawnBrowserOnSocket } from "./piggy/launch/spawn";
4
4
  import { PiggyClient } from "./piggy/client";
5
5
  import { setClient, setHumanMode, createSiteObject } from "./piggy/register";
6
6
  import { routeRegistry, keepAliveSites, startServer, stopServer } from "./piggy/server";
7
7
  import logger from "./piggy/logger";
8
8
 
9
- type BrowserMode = "tab" | "process";
9
+ type TabMode = "tab" | "process";
10
10
  type SiteObject = ReturnType<typeof createSiteObject>;
11
11
 
12
12
  let _client: PiggyClient | null = null;
13
- let _mode: BrowserMode = "tab";
13
+ let _tabMode: TabMode = "tab";
14
14
  const _extraProcs: { socket: string; client: PiggyClient }[] = [];
15
15
  const _sites: Record<string, SiteObject> = {};
16
16
 
17
17
  const piggy: any = {
18
18
  // ── Lifecycle ───────────────────────────────────────────────────────────────
19
19
 
20
- launch: async (opts?: { mode?: BrowserMode }) => {
21
- _mode = opts?.mode ?? "tab";
22
- await spawnBrowser();
20
+ launch: async (opts?: { mode?: TabMode; binary?: BinaryMode }) => {
21
+ _tabMode = opts?.mode ?? "tab";
22
+ const binaryMode: BinaryMode = opts?.binary ?? "headless";
23
+ await spawnBrowser(binaryMode);
23
24
  await new Promise(r => setTimeout(r, 500));
24
25
  _client = new PiggyClient();
25
26
  await _client.connect();
26
27
  setClient(_client);
27
- logger.info(`[piggy] launched in "${_mode}" mode`);
28
+ logger.info(`[piggy] launched tab mode: "${_tabMode}", binary: "${binaryMode}"`);
28
29
  return piggy;
29
30
  },
30
31
 
31
- register: async (name: string, url: string, opts?: any) => {
32
+ register: async (name: string, url: string, opts?: { binary?: BinaryMode }) => {
32
33
  if (!url?.trim()) throw new Error(`No URL for site "${name}"`);
34
+ const binaryMode: BinaryMode = opts?.binary ?? "headless";
33
35
 
34
36
  let tabId = "default";
35
- if (_mode === "tab") {
37
+ if (_tabMode === "tab") {
36
38
  tabId = await _client!.newTab();
37
39
  _sites[name] = createSiteObject(name, url, _client!, tabId);
38
40
  piggy[name] = _sites[name];
39
41
  logger.success(`[${name}] registered as tab ${tabId}`);
40
42
  } else {
41
43
  const socketName = `piggy_${name}`;
42
- await spawnBrowserOnSocket(socketName);
44
+ await spawnBrowserOnSocket(socketName, binaryMode);
43
45
  await new Promise(r => setTimeout(r, 500));
44
46
  const c = new PiggyClient(socketName);
45
47
  await c.connect();
@@ -49,7 +51,6 @@ const piggy: any = {
49
51
  logger.success(`[${name}] registered as process on "${socketName}"`);
50
52
  }
51
53
 
52
- if (opts?.mode) logger.info(`[${name}] mode: ${opts.mode}`);
53
54
  return piggy;
54
55
  },
55
56
 
@@ -61,7 +62,7 @@ const piggy: any = {
61
62
  return piggy;
62
63
  },
63
64
 
64
- mode: (m: BrowserMode) => { _mode = m; return piggy; },
65
+ mode: (m: TabMode) => { _tabMode = m; return piggy; },
65
66
 
66
67
  // ── Elysia server ────────────────────────────────────────────────────────────
67
68