nothing-browser 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.md +253 -253
- package/dist/piggy/register/index.d.ts.map +1 -1
- package/dist/piggy.js +14 -3
- package/dist/register/index.js +14 -3
- package/nothing_browser_pig_pink.svg +58 -58
- package/package.json +4 -3
- package/piggy/cache/memory.d.ts +6 -6
- package/piggy/cache/memory.ts +37 -37
- package/piggy/client/index.d.ts +78 -78
- package/piggy/client/index.ts +567 -567
- package/piggy/human/index.d.ts +6 -6
- package/piggy/human/index.ts +52 -52
- package/piggy/intercept/scripts.d.ts +12 -12
- package/piggy/intercept/scripts.ts +152 -152
- package/piggy/launch/detect.d.ts +2 -2
- package/piggy/launch/detect.ts +42 -42
- package/piggy/launch/spawn.d.ts +5 -5
- package/piggy/launch/spawn.ts +164 -164
- package/piggy/logger/index.d.ts +2 -2
- package/piggy/logger/index.ts +58 -58
- package/piggy/open/index.d.ts +3 -3
- package/piggy/open/index.ts +4 -4
- package/piggy/pool/index.d.ts +11 -11
- package/piggy/pool/index.ts +74 -74
- package/piggy/register/index.d.ts +6 -6
- package/piggy/register/index.ts +517 -506
- package/piggy/server/index.d.ts +57 -57
- package/piggy/server/index.ts +189 -189
- package/piggy/store/index.d.ts +25 -25
- package/piggy/store/index.ts +229 -229
- package/piggy.ts +216 -216
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 BunElysiaReact
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 BunElysiaReact
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,254 +1,254 @@
|
|
|
1
|
-
# `nothing-browser`
|
|
2
|
-
|
|
3
|
-
<p align="center">
|
|
4
|
-
<img src="nothing_browser_pig_pink.svg" width="160" alt="Nothing Browser logo"/>
|
|
5
|
-
</p>
|
|
6
|
-
|
|
7
|
-
<h1 align="center">nothing-browser</h1>
|
|
8
|
-
<p align="center"><em>Does nothing... except everything that matters.</em></p>
|
|
9
|
-
|
|
10
|
-
<p align="center">
|
|
11
|
-
<a href="https://www.npmjs.com/package/nothing-browser"><img src="https://img.shields.io/npm/v/nothing-browser" alt="npm version"/></a>
|
|
12
|
-
<a href="LICENSE"><img src="https://img.shields.io/github/license/BunElysiaReact/nothing-browser" alt="license"/></a>
|
|
13
|
-
<a href="https://github.com/BunElysiaReact/nothing-browser/releases"><img src="https://img.shields.io/github/v/release/BunElysiaReact/nothing-browser" alt="releases"/></a>
|
|
14
|
-
</p>
|
|
15
|
-
|
|
16
|
-
**A scraper-first headless browser library** powered by the Nothing Browser Qt6/Chromium engine. Control real browser tabs, intercept network traffic, spoof fingerprints, capture WebSockets — all from Bun + TypeScript.
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
import piggy from "nothing-browser";
|
|
20
|
-
|
|
21
|
-
await piggy.launch();
|
|
22
|
-
await piggy.register("books", "https://books.toscrape.com");
|
|
23
|
-
await piggy.books.navigate();
|
|
24
|
-
|
|
25
|
-
const books = await piggy.books.evaluate(() =>
|
|
26
|
-
Array.from(document.querySelectorAll(".product_pod")).map(el => ({
|
|
27
|
-
title: el.querySelector("h3 a")?.getAttribute("title") ?? "",
|
|
28
|
-
price: el.querySelector(".price_color")?.textContent?.trim() ?? "",
|
|
29
|
-
}))
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
console.log(books);
|
|
33
|
-
await piggy.close();
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
> **📚 Full documentation is available here:**
|
|
37
|
-
> [https://nothing-browser-docs.pages.dev/guide/piggy/quickstart](https://nothing-browser-docs.pages.dev/guide/piggy/quickstart)
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Why nothing-browser?
|
|
42
|
-
|
|
43
|
-
| | nothing-browser | Puppeteer | Playwright |
|
|
44
|
-
|------------------------|----------------|-----------|------------|
|
|
45
|
-
| Imports | **1** | 5–10 | 5–10 |
|
|
46
|
-
| Lines to scrape a site | **~20** | 80–200 | 80–200 |
|
|
47
|
-
| Fingerprint spoofing | ✅ built in | ❌ plugin | ❌ plugin |
|
|
48
|
-
| Network capture | ✅ built in | ❌ manual | ❌ manual |
|
|
49
|
-
| Built-in API server | ✅ | ❌ | ❌ |
|
|
50
|
-
| Cloudflare bypass | ✅ passes | ⚠️ often blocked | ⚠️ often blocked |
|
|
51
|
-
| **Browser → Node.js RPC** | ✅ **`exposeFunction`** | ✅ `page.exposeFunction` | ✅ `page.exposeFunction` |
|
|
52
|
-
|
|
53
|
-
One import. No 47 plugins to avoid detection. Just write your scraper and go.
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Requirements
|
|
58
|
-
|
|
59
|
-
- **[Bun](https://bun.sh) ≥ 1.0**
|
|
60
|
-
- A **Nothing Browser binary** placed in your **project root** (see [Binaries](#binaries))
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Binaries
|
|
65
|
-
|
|
66
|
-
Download the correct binary from **[GitHub Releases](https://github.com/BunElysiaReact/nothing-browser/releases)**.
|
|
67
|
-
|
|
68
|
-
| Binary | What it is | Where it goes |
|
|
69
|
-
|--------|-----------|---------------|
|
|
70
|
-
| `nothing-browser` | Full UI browser app (DevTools, YouTube, Plugins) | Install system-wide |
|
|
71
|
-
| `nothing-browser-headless` | No window, no GPU – for automated scraping | **Your project root** |
|
|
72
|
-
| `nothing-browser-headful` | Visible window, script-controlled – for debugging | **Your project root** |
|
|
73
|
-
|
|
74
|
-
The library communicates with the binary in your project root over a local socket.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Install
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
bun add nothing-browser
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Then download the binary and place it in your project root.
|
|
85
|
-
|
|
86
|
-
<details>
|
|
87
|
-
<summary><strong>Linux</strong></summary>
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
# Headless (most common for scraping)
|
|
91
|
-
tar -xzf nothing-browser-headless-*-linux-x86_64.tar.gz
|
|
92
|
-
chmod +x nothing-browser-headless
|
|
93
|
-
|
|
94
|
-
# Headful (visible window)
|
|
95
|
-
tar -xzf nothing-browser-headful-*-linux-x86_64.tar.gz
|
|
96
|
-
chmod +x nothing-browser-headful
|
|
97
|
-
|
|
98
|
-
# Full browser (system-wide)
|
|
99
|
-
sudo dpkg -i nothing-browser_*_amd64.deb
|
|
100
|
-
```
|
|
101
|
-
</details>
|
|
102
|
-
|
|
103
|
-
<details>
|
|
104
|
-
<summary><strong>Windows</strong></summary>
|
|
105
|
-
|
|
106
|
-
Download the `.zip` → extract → place `.exe` in your project root.
|
|
107
|
-
</details>
|
|
108
|
-
|
|
109
|
-
<details>
|
|
110
|
-
<summary><strong>macOS</strong></summary>
|
|
111
|
-
|
|
112
|
-
Download the `.tar.gz` → extract → place binary in your project root.
|
|
113
|
-
</details>
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## Headless vs Headful
|
|
118
|
-
|
|
119
|
-
```ts
|
|
120
|
-
// Headless – no display, runs anywhere (default)
|
|
121
|
-
await piggy.launch({ mode: "tab", binary: "headless" });
|
|
122
|
-
|
|
123
|
-
// Headful – visible window for debugging
|
|
124
|
-
await piggy.launch({ mode: "tab", binary: "headful" });
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Switching is just changing one word.
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Key Features (with Examples)
|
|
132
|
-
|
|
133
|
-
### 🔥 Browser → Node.js RPC (`exposeFunction`)
|
|
134
|
-
|
|
135
|
-
Call Node.js functions directly from browser JavaScript.
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
await piggy.whatsapp.exposeFunction("onNewMessage", async (message) => {
|
|
139
|
-
await db.messages.insert(message);
|
|
140
|
-
return { saved: true, id: crypto.randomUUID() };
|
|
141
|
-
});
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### 📡 Request Interception
|
|
145
|
-
|
|
146
|
-
Block, redirect, or serve custom responses.
|
|
147
|
-
|
|
148
|
-
```ts
|
|
149
|
-
await piggy.app.intercept.respond("*/api/users*", async () => ({
|
|
150
|
-
status: 200,
|
|
151
|
-
body: JSON.stringify([{ id: 1, name: "Cached User" }])
|
|
152
|
-
}));
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### 🧠 Human Mode
|
|
156
|
-
|
|
157
|
-
Add random delays, typos, and natural scrolling.
|
|
158
|
-
|
|
159
|
-
```ts
|
|
160
|
-
piggy.actHuman(true);
|
|
161
|
-
await piggy.books.click(".product_pod h3 a");
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### 💾 Session Persistence
|
|
165
|
-
|
|
166
|
-
Save and restore cookies, storage, and state.
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
await piggy.site.session.export(); // save
|
|
170
|
-
await piggy.site.session.import(data); // restore
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### 🚀 Built‑in API Server
|
|
174
|
-
|
|
175
|
-
Turn your scraper into a REST API.
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
piggy.books.api("/list", async () => ({ books }));
|
|
179
|
-
await piggy.serve(3000);
|
|
180
|
-
// GET http://localhost:3000/books/list
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
> **For many more examples** (WebSocket capture, multi‑site scraping, PDF/screenshot, middleware, etc.), see the **[full documentation](https://nothing-browser-docs.pages.dev/guide/piggy/quickstart)**.
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## API Reference (Quick)
|
|
188
|
-
|
|
189
|
-
### Core
|
|
190
|
-
|
|
191
|
-
| Method | Description |
|
|
192
|
-
|--------|-------------|
|
|
193
|
-
| `piggy.launch(opts?)` | Start browser (`mode`, `binary`) |
|
|
194
|
-
| `piggy.register(name, url)` | Register a site → `piggy.<name>` |
|
|
195
|
-
| `piggy.actHuman(enable)` | Enable human‑like timing |
|
|
196
|
-
| `piggy.expose(name, handler)` | Global RPC function |
|
|
197
|
-
| `piggy.serve(port)` | Start API server |
|
|
198
|
-
| `piggy.close(opts?)` | Close gracefully or force |
|
|
199
|
-
|
|
200
|
-
### Site Methods
|
|
201
|
-
|
|
202
|
-
| Category | Methods |
|
|
203
|
-
|----------|---------|
|
|
204
|
-
| **Navigation** | `navigate()`, `reload()`, `goBack()`, `goForward()`, `waitForSelector()` |
|
|
205
|
-
| **Interactions** | `click()`, `type()`, `hover()`, `select()`, `keyboard.press()`, `scroll.to()` |
|
|
206
|
-
| **Data** | `evaluate()`, `fetchText()`, `fetchLinks()`, `fetchImages()` |
|
|
207
|
-
| **RPC** | `exposeFunction()`, `unexposeFunction()`, `exposeAndInject()` |
|
|
208
|
-
| **Network** | `capture.start()`, `intercept.respond()`, `intercept.modifyResponse()`, `blockImages()` |
|
|
209
|
-
| **Session** | `cookies.set()`, `session.export()`, `session.import()` |
|
|
210
|
-
| **Output** | `screenshot()`, `pdf()` |
|
|
211
|
-
|
|
212
|
-
> **Full API reference:** [https://nothing-browser-docs.pages.dev/guide/piggy/api-reference](https://nothing-browser-docs.pages.dev/guide/piggy/api-reference)
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## How `exposeFunction` Works
|
|
217
|
-
|
|
218
|
-
1. Browser injects a Promise‑returning stub into `window.fnName`.
|
|
219
|
-
2. Calls are queued to `__NOTHING_QUEUE__`.
|
|
220
|
-
3. C++ polls the queue (every 250ms) and sends the call via socket.
|
|
221
|
-
4. Your Node.js handler runs.
|
|
222
|
-
5. The result is sent back and the browser’s Promise resolves.
|
|
223
|
-
|
|
224
|
-
The function survives page navigations (injected at `DocumentCreation`) and works in both tab and process modes.
|
|
225
|
-
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
## Binary Download Links
|
|
229
|
-
|
|
230
|
-
| Platform | Headless | Headful | Full Browser |
|
|
231
|
-
|----------|----------|---------|--------------|
|
|
232
|
-
| Linux x86_64 (deb) | `nothing-browser-headless_*_amd64.deb` | `nothing-browser-headful_*_amd64.deb` | `nothing-browser_*_amd64.deb` |
|
|
233
|
-
| 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` |
|
|
234
|
-
| Windows x64 | `nothing-browser-headless-*-windows-x64.zip` | `nothing-browser-headful-*-windows-x64.zip` | `nothing-browser-*-windows-x64.zip` |
|
|
235
|
-
| macOS | `nothing-browser-headless-*-macos.tar.gz` | `nothing-browser-headful-*-macos.tar.gz` | `nothing-browser-*-macos.dmg` |
|
|
236
|
-
|
|
237
|
-
➡️ **[All releases on GitHub](https://github.com/BunElysiaReact/nothing-browser/releases)**
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
## Contributing & Security
|
|
242
|
-
|
|
243
|
-
- **Contributing:** See the [Contributing Guide](https://nothing-browser-docs.pages.dev/guide/community/contributing)
|
|
244
|
-
- **Security issues:** Email `ernesttechhouse@gmail.com` (not a public issue)
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
## License
|
|
249
|
-
|
|
250
|
-
MIT © [Ernest Tech House](https://github.com/BunElysiaReact/nothing-browser)
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
1
|
+
# `nothing-browser`
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="nothing_browser_pig_pink.svg" width="160" alt="Nothing Browser logo"/>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">nothing-browser</h1>
|
|
8
|
+
<p align="center"><em>Does nothing... except everything that matters.</em></p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/nothing-browser"><img src="https://img.shields.io/npm/v/nothing-browser" alt="npm version"/></a>
|
|
12
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/BunElysiaReact/nothing-browser" alt="license"/></a>
|
|
13
|
+
<a href="https://github.com/BunElysiaReact/nothing-browser/releases"><img src="https://img.shields.io/github/v/release/BunElysiaReact/nothing-browser" alt="releases"/></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
**A scraper-first headless browser library** powered by the Nothing Browser Qt6/Chromium engine. Control real browser tabs, intercept network traffic, spoof fingerprints, capture WebSockets — all from Bun + TypeScript.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import piggy from "nothing-browser";
|
|
20
|
+
|
|
21
|
+
await piggy.launch();
|
|
22
|
+
await piggy.register("books", "https://books.toscrape.com");
|
|
23
|
+
await piggy.books.navigate();
|
|
24
|
+
|
|
25
|
+
const books = await piggy.books.evaluate(() =>
|
|
26
|
+
Array.from(document.querySelectorAll(".product_pod")).map(el => ({
|
|
27
|
+
title: el.querySelector("h3 a")?.getAttribute("title") ?? "",
|
|
28
|
+
price: el.querySelector(".price_color")?.textContent?.trim() ?? "",
|
|
29
|
+
}))
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
console.log(books);
|
|
33
|
+
await piggy.close();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> **📚 Full documentation is available here:**
|
|
37
|
+
> [https://nothing-browser-docs.pages.dev/guide/piggy/quickstart](https://nothing-browser-docs.pages.dev/guide/piggy/quickstart)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Why nothing-browser?
|
|
42
|
+
|
|
43
|
+
| | nothing-browser | Puppeteer | Playwright |
|
|
44
|
+
|------------------------|----------------|-----------|------------|
|
|
45
|
+
| Imports | **1** | 5–10 | 5–10 |
|
|
46
|
+
| Lines to scrape a site | **~20** | 80–200 | 80–200 |
|
|
47
|
+
| Fingerprint spoofing | ✅ built in | ❌ plugin | ❌ plugin |
|
|
48
|
+
| Network capture | ✅ built in | ❌ manual | ❌ manual |
|
|
49
|
+
| Built-in API server | ✅ | ❌ | ❌ |
|
|
50
|
+
| Cloudflare bypass | ✅ passes | ⚠️ often blocked | ⚠️ often blocked |
|
|
51
|
+
| **Browser → Node.js RPC** | ✅ **`exposeFunction`** | ✅ `page.exposeFunction` | ✅ `page.exposeFunction` |
|
|
52
|
+
|
|
53
|
+
One import. No 47 plugins to avoid detection. Just write your scraper and go.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Requirements
|
|
58
|
+
|
|
59
|
+
- **[Bun](https://bun.sh) ≥ 1.0**
|
|
60
|
+
- A **Nothing Browser binary** placed in your **project root** (see [Binaries](#binaries))
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Binaries
|
|
65
|
+
|
|
66
|
+
Download the correct binary from **[GitHub Releases](https://github.com/BunElysiaReact/nothing-browser/releases)**.
|
|
67
|
+
|
|
68
|
+
| Binary | What it is | Where it goes |
|
|
69
|
+
|--------|-----------|---------------|
|
|
70
|
+
| `nothing-browser` | Full UI browser app (DevTools, YouTube, Plugins) | Install system-wide |
|
|
71
|
+
| `nothing-browser-headless` | No window, no GPU – for automated scraping | **Your project root** |
|
|
72
|
+
| `nothing-browser-headful` | Visible window, script-controlled – for debugging | **Your project root** |
|
|
73
|
+
|
|
74
|
+
The library communicates with the binary in your project root over a local socket.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
bun add nothing-browser
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then download the binary and place it in your project root.
|
|
85
|
+
|
|
86
|
+
<details>
|
|
87
|
+
<summary><strong>Linux</strong></summary>
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Headless (most common for scraping)
|
|
91
|
+
tar -xzf nothing-browser-headless-*-linux-x86_64.tar.gz
|
|
92
|
+
chmod +x nothing-browser-headless
|
|
93
|
+
|
|
94
|
+
# Headful (visible window)
|
|
95
|
+
tar -xzf nothing-browser-headful-*-linux-x86_64.tar.gz
|
|
96
|
+
chmod +x nothing-browser-headful
|
|
97
|
+
|
|
98
|
+
# Full browser (system-wide)
|
|
99
|
+
sudo dpkg -i nothing-browser_*_amd64.deb
|
|
100
|
+
```
|
|
101
|
+
</details>
|
|
102
|
+
|
|
103
|
+
<details>
|
|
104
|
+
<summary><strong>Windows</strong></summary>
|
|
105
|
+
|
|
106
|
+
Download the `.zip` → extract → place `.exe` in your project root.
|
|
107
|
+
</details>
|
|
108
|
+
|
|
109
|
+
<details>
|
|
110
|
+
<summary><strong>macOS</strong></summary>
|
|
111
|
+
|
|
112
|
+
Download the `.tar.gz` → extract → place binary in your project root.
|
|
113
|
+
</details>
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Headless vs Headful
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
// Headless – no display, runs anywhere (default)
|
|
121
|
+
await piggy.launch({ mode: "tab", binary: "headless" });
|
|
122
|
+
|
|
123
|
+
// Headful – visible window for debugging
|
|
124
|
+
await piggy.launch({ mode: "tab", binary: "headful" });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Switching is just changing one word.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Key Features (with Examples)
|
|
132
|
+
|
|
133
|
+
### 🔥 Browser → Node.js RPC (`exposeFunction`)
|
|
134
|
+
|
|
135
|
+
Call Node.js functions directly from browser JavaScript.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
await piggy.whatsapp.exposeFunction("onNewMessage", async (message) => {
|
|
139
|
+
await db.messages.insert(message);
|
|
140
|
+
return { saved: true, id: crypto.randomUUID() };
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 📡 Request Interception
|
|
145
|
+
|
|
146
|
+
Block, redirect, or serve custom responses.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
await piggy.app.intercept.respond("*/api/users*", async () => ({
|
|
150
|
+
status: 200,
|
|
151
|
+
body: JSON.stringify([{ id: 1, name: "Cached User" }])
|
|
152
|
+
}));
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 🧠 Human Mode
|
|
156
|
+
|
|
157
|
+
Add random delays, typos, and natural scrolling.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
piggy.actHuman(true);
|
|
161
|
+
await piggy.books.click(".product_pod h3 a");
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 💾 Session Persistence
|
|
165
|
+
|
|
166
|
+
Save and restore cookies, storage, and state.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
await piggy.site.session.export(); // save
|
|
170
|
+
await piggy.site.session.import(data); // restore
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 🚀 Built‑in API Server
|
|
174
|
+
|
|
175
|
+
Turn your scraper into a REST API.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
piggy.books.api("/list", async () => ({ books }));
|
|
179
|
+
await piggy.serve(3000);
|
|
180
|
+
// GET http://localhost:3000/books/list
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
> **For many more examples** (WebSocket capture, multi‑site scraping, PDF/screenshot, middleware, etc.), see the **[full documentation](https://nothing-browser-docs.pages.dev/guide/piggy/quickstart)**.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## API Reference (Quick)
|
|
188
|
+
|
|
189
|
+
### Core
|
|
190
|
+
|
|
191
|
+
| Method | Description |
|
|
192
|
+
|--------|-------------|
|
|
193
|
+
| `piggy.launch(opts?)` | Start browser (`mode`, `binary`) |
|
|
194
|
+
| `piggy.register(name, url)` | Register a site → `piggy.<name>` |
|
|
195
|
+
| `piggy.actHuman(enable)` | Enable human‑like timing |
|
|
196
|
+
| `piggy.expose(name, handler)` | Global RPC function |
|
|
197
|
+
| `piggy.serve(port)` | Start API server |
|
|
198
|
+
| `piggy.close(opts?)` | Close gracefully or force |
|
|
199
|
+
|
|
200
|
+
### Site Methods
|
|
201
|
+
|
|
202
|
+
| Category | Methods |
|
|
203
|
+
|----------|---------|
|
|
204
|
+
| **Navigation** | `navigate()`, `reload()`, `goBack()`, `goForward()`, `waitForSelector()` |
|
|
205
|
+
| **Interactions** | `click()`, `type()`, `hover()`, `select()`, `keyboard.press()`, `scroll.to()` |
|
|
206
|
+
| **Data** | `evaluate()`, `fetchText()`, `fetchLinks()`, `fetchImages()` |
|
|
207
|
+
| **RPC** | `exposeFunction()`, `unexposeFunction()`, `exposeAndInject()` |
|
|
208
|
+
| **Network** | `capture.start()`, `intercept.respond()`, `intercept.modifyResponse()`, `blockImages()` |
|
|
209
|
+
| **Session** | `cookies.set()`, `session.export()`, `session.import()` |
|
|
210
|
+
| **Output** | `screenshot()`, `pdf()` |
|
|
211
|
+
|
|
212
|
+
> **Full API reference:** [https://nothing-browser-docs.pages.dev/guide/piggy/api-reference](https://nothing-browser-docs.pages.dev/guide/piggy/api-reference)
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## How `exposeFunction` Works
|
|
217
|
+
|
|
218
|
+
1. Browser injects a Promise‑returning stub into `window.fnName`.
|
|
219
|
+
2. Calls are queued to `__NOTHING_QUEUE__`.
|
|
220
|
+
3. C++ polls the queue (every 250ms) and sends the call via socket.
|
|
221
|
+
4. Your Node.js handler runs.
|
|
222
|
+
5. The result is sent back and the browser’s Promise resolves.
|
|
223
|
+
|
|
224
|
+
The function survives page navigations (injected at `DocumentCreation`) and works in both tab and process modes.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Binary Download Links
|
|
229
|
+
|
|
230
|
+
| Platform | Headless | Headful | Full Browser |
|
|
231
|
+
|----------|----------|---------|--------------|
|
|
232
|
+
| Linux x86_64 (deb) | `nothing-browser-headless_*_amd64.deb` | `nothing-browser-headful_*_amd64.deb` | `nothing-browser_*_amd64.deb` |
|
|
233
|
+
| 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` |
|
|
234
|
+
| Windows x64 | `nothing-browser-headless-*-windows-x64.zip` | `nothing-browser-headful-*-windows-x64.zip` | `nothing-browser-*-windows-x64.zip` |
|
|
235
|
+
| macOS | `nothing-browser-headless-*-macos.tar.gz` | `nothing-browser-headful-*-macos.tar.gz` | `nothing-browser-*-macos.dmg` |
|
|
236
|
+
|
|
237
|
+
➡️ **[All releases on GitHub](https://github.com/BunElysiaReact/nothing-browser/releases)**
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Contributing & Security
|
|
242
|
+
|
|
243
|
+
- **Contributing:** See the [Contributing Guide](https://nothing-browser-docs.pages.dev/guide/community/contributing)
|
|
244
|
+
- **Security issues:** Email `ernesttechhouse@gmail.com` (not a public issue)
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT © [Ernest Tech House](https://github.com/BunElysiaReact/nothing-browser)
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
254
|
*Part of the [Nothing Ecosystem](https://nothing-browser-docs.pages.dev). Built in Kenya 🇰🇪*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../piggy/register/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAMxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,eAAO,IAAI,SAAS,SAAQ,CAAC;AAE7B,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,QAAuB;AACtE,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,QAAoB;AAgB3D,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../piggy/register/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAMxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,eAAO,IAAI,SAAS,SAAQ,CAAC;AAE7B,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,QAAuB;AACtE,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,QAAoB;AAgB3D,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,OAAO,OAkdf;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC,EAC3E,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,GACV,OAAO,CAAC,IAAI,CAAC,CASf"}
|
package/dist/piggy.js
CHANGED
|
@@ -6105,7 +6105,7 @@ var require_file_uri_to_path = __commonJS((exports, module) => {
|
|
|
6105
6105
|
|
|
6106
6106
|
// node_modules/bindings/bindings.js
|
|
6107
6107
|
var require_bindings = __commonJS((exports, module) => {
|
|
6108
|
-
var __filename = "
|
|
6108
|
+
var __filename = "C:\\Users\\CENTURY CYBER\\Desktop\\piggy\\nothing-browser\\node_modules\\bindings\\bindings.js";
|
|
6109
6109
|
var fs = __require("fs");
|
|
6110
6110
|
var path = __require("path");
|
|
6111
6111
|
var fileURLToPath = require_file_uri_to_path();
|
|
@@ -28768,7 +28768,7 @@ function createSiteObject(name, registeredUrl, client, tabId, pool) {
|
|
|
28768
28768
|
return client.hover(selector, t2);
|
|
28769
28769
|
}), `hover(${selector})`),
|
|
28770
28770
|
type: (selector, text, opts) => withErrScreen(() => withTab(async (t2) => {
|
|
28771
|
-
await client.waitForSelector(selector,
|
|
28771
|
+
await client.waitForSelector(selector, 30000, t2);
|
|
28772
28772
|
if (humanMode && !opts?.fact) {
|
|
28773
28773
|
const seq = humanTypeSequence(text);
|
|
28774
28774
|
let current = "";
|
|
@@ -28777,7 +28777,15 @@ function createSiteObject(name, registeredUrl, client, tabId, pool) {
|
|
|
28777
28777
|
current = current.slice(0, -1);
|
|
28778
28778
|
else
|
|
28779
28779
|
current += action;
|
|
28780
|
-
await client.
|
|
28780
|
+
await client.evaluate(`
|
|
28781
|
+
(function() {
|
|
28782
|
+
const el = document.querySelector('${selector}');
|
|
28783
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
|
|
28784
|
+
nativeSetter.call(el, '${current.replace(/'/g, "\\'")}');
|
|
28785
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
28786
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
28787
|
+
})()
|
|
28788
|
+
`, t2);
|
|
28781
28789
|
const wpm = opts?.wpm ?? 120;
|
|
28782
28790
|
const msPerChar = Math.round(60000 / (wpm * 5));
|
|
28783
28791
|
await randomDelay(msPerChar * 0.5, msPerChar * 1.8);
|
|
@@ -28790,6 +28798,9 @@ function createSiteObject(name, registeredUrl, client, tabId, pool) {
|
|
|
28790
28798
|
} else {
|
|
28791
28799
|
await client.type(selector, text, t2);
|
|
28792
28800
|
}
|
|
28801
|
+
await client.evaluate(`
|
|
28802
|
+
document.querySelector('${selector}').dispatchEvent(new Event('blur', { bubbles: true }))
|
|
28803
|
+
`, t2);
|
|
28793
28804
|
logger_default.success(`[${name}] typed into: ${selector}`);
|
|
28794
28805
|
return true;
|
|
28795
28806
|
}), `type(${selector})`),
|
package/dist/register/index.js
CHANGED
|
@@ -6105,7 +6105,7 @@ var require_file_uri_to_path = __commonJS((exports, module) => {
|
|
|
6105
6105
|
|
|
6106
6106
|
// node_modules/bindings/bindings.js
|
|
6107
6107
|
var require_bindings = __commonJS((exports, module) => {
|
|
6108
|
-
var __filename = "
|
|
6108
|
+
var __filename = "C:\\Users\\CENTURY CYBER\\Desktop\\piggy\\nothing-browser\\node_modules\\bindings\\bindings.js";
|
|
6109
6109
|
var fs = __require("fs");
|
|
6110
6110
|
var path = __require("path");
|
|
6111
6111
|
var fileURLToPath = require_file_uri_to_path();
|
|
@@ -23054,7 +23054,7 @@ function createSiteObject(name, registeredUrl, client, tabId, pool) {
|
|
|
23054
23054
|
return client.hover(selector, t2);
|
|
23055
23055
|
}), `hover(${selector})`),
|
|
23056
23056
|
type: (selector, text, opts) => withErrScreen(() => withTab(async (t2) => {
|
|
23057
|
-
await client.waitForSelector(selector,
|
|
23057
|
+
await client.waitForSelector(selector, 30000, t2);
|
|
23058
23058
|
if (humanMode && !opts?.fact) {
|
|
23059
23059
|
const seq = humanTypeSequence(text);
|
|
23060
23060
|
let current = "";
|
|
@@ -23063,7 +23063,15 @@ function createSiteObject(name, registeredUrl, client, tabId, pool) {
|
|
|
23063
23063
|
current = current.slice(0, -1);
|
|
23064
23064
|
else
|
|
23065
23065
|
current += action;
|
|
23066
|
-
await client.
|
|
23066
|
+
await client.evaluate(`
|
|
23067
|
+
(function() {
|
|
23068
|
+
const el = document.querySelector('${selector}');
|
|
23069
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
|
|
23070
|
+
nativeSetter.call(el, '${current.replace(/'/g, "\\'")}');
|
|
23071
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
23072
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
23073
|
+
})()
|
|
23074
|
+
`, t2);
|
|
23067
23075
|
const wpm = opts?.wpm ?? 120;
|
|
23068
23076
|
const msPerChar = Math.round(60000 / (wpm * 5));
|
|
23069
23077
|
await randomDelay(msPerChar * 0.5, msPerChar * 1.8);
|
|
@@ -23076,6 +23084,9 @@ function createSiteObject(name, registeredUrl, client, tabId, pool) {
|
|
|
23076
23084
|
} else {
|
|
23077
23085
|
await client.type(selector, text, t2);
|
|
23078
23086
|
}
|
|
23087
|
+
await client.evaluate(`
|
|
23088
|
+
document.querySelector('${selector}').dispatchEvent(new Event('blur', { bubbles: true }))
|
|
23089
|
+
`, t2);
|
|
23079
23090
|
logger_default.success(`[${name}] typed into: ${selector}`);
|
|
23080
23091
|
return true;
|
|
23081
23092
|
}), `type(${selector})`),
|