nothing-browser 0.0.19 → 0.0.21
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/launch/detect.js +7 -2
- package/dist/launch/spawn.js +7 -2
- package/dist/piggy/launch/detect.d.ts.map +1 -1
- package/dist/piggy/launch/spawn.d.ts.map +1 -1
- package/dist/piggy/register/index.d.ts.map +1 -1
- package/dist/piggy.d.ts +0 -1
- package/dist/piggy.d.ts.map +1 -1
- package/dist/piggy.js +21 -5
- 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 +59 -51
- package/piggy/launch/spawn.d.ts +5 -5
- package/piggy/launch/spawn.ts +157 -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 -221
package/piggy.ts
CHANGED
|
@@ -1,222 +1,217 @@
|
|
|
1
|
-
// piggy.ts
|
|
2
|
-
import { detectBinary } from "./piggy/launch/detect";
|
|
3
|
-
import { spawnBrowser, killBrowser, spawnBrowserOnSocket } from "./piggy/launch/spawn";
|
|
4
|
-
import { PiggyClient } from "./piggy/client";
|
|
5
|
-
import { setClient, setHumanMode, createSiteObject, type SiteObject } from "./piggy/register";
|
|
6
|
-
import { routeRegistry, keepAliveSites, startServer, stopServer } from "./piggy/server";
|
|
7
|
-
import { TabPool } from "./piggy/pool";
|
|
8
|
-
import logger from "./piggy/logger";
|
|
9
|
-
|
|
10
|
-
type TabMode = "tab" | "process";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (!_client) throw new Error("No client
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
export
|
|
217
|
-
return piggy as TypedPiggy<Sites>;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export type { SiteObject };
|
|
221
|
-
export default piggy;
|
|
1
|
+
// piggy.ts
|
|
2
|
+
import { detectBinary, type BinaryMode } from "./piggy/launch/detect";
|
|
3
|
+
import { spawnBrowser, killBrowser, spawnBrowserOnSocket } from "./piggy/launch/spawn";
|
|
4
|
+
import { PiggyClient } from "./piggy/client";
|
|
5
|
+
import { setClient, setHumanMode, createSiteObject, type SiteObject } from "./piggy/register";
|
|
6
|
+
import { routeRegistry, keepAliveSites, startServer, stopServer } from "./piggy/server";
|
|
7
|
+
import { TabPool } from "./piggy/pool";
|
|
8
|
+
import logger from "./piggy/logger";
|
|
9
|
+
|
|
10
|
+
type TabMode = "tab" | "process";
|
|
11
|
+
|
|
12
|
+
let _client: PiggyClient | null = null;
|
|
13
|
+
let _tabMode: TabMode = "tab";
|
|
14
|
+
const _extraProcs: { socket: string; client: PiggyClient }[] = [];
|
|
15
|
+
const _sites: Record<string, SiteObject> = [];
|
|
16
|
+
|
|
17
|
+
const piggy: any = {
|
|
18
|
+
// ── Local launch (socket) ─────────────────────────────────────────────────
|
|
19
|
+
launch: async (opts?: { mode?: TabMode; binary?: BinaryMode }) => {
|
|
20
|
+
_tabMode = opts?.mode ?? "tab";
|
|
21
|
+
const binaryMode: BinaryMode = opts?.binary ?? "headless";
|
|
22
|
+
await spawnBrowser(binaryMode);
|
|
23
|
+
await new Promise(r => setTimeout(r, 500));
|
|
24
|
+
_client = new PiggyClient();
|
|
25
|
+
await _client.connect();
|
|
26
|
+
setClient(_client);
|
|
27
|
+
logger.info(`[piggy] launched — tab mode: "${_tabMode}", binary: "${binaryMode}"`);
|
|
28
|
+
return piggy;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// ── Remote connect (HTTP) ─────────────────────────────────────────────────
|
|
32
|
+
connect: async (opts: { host: string; key: string }) => {
|
|
33
|
+
_tabMode = "tab";
|
|
34
|
+
_client = new PiggyClient({ host: opts.host, key: opts.key });
|
|
35
|
+
await _client.connect();
|
|
36
|
+
setClient(_client);
|
|
37
|
+
logger.info(`[piggy] connected (HTTP) → ${opts.host}`);
|
|
38
|
+
return piggy;
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// ── Register ──────────────────────────────────────────────────────────────
|
|
42
|
+
register: async (
|
|
43
|
+
name: string,
|
|
44
|
+
url: string,
|
|
45
|
+
opts?: {
|
|
46
|
+
binary?: BinaryMode;
|
|
47
|
+
pool?: number;
|
|
48
|
+
}
|
|
49
|
+
) => {
|
|
50
|
+
if (!url?.trim()) throw new Error(`No URL for site "${name}"`);
|
|
51
|
+
const binaryMode: BinaryMode = opts?.binary ?? "headless";
|
|
52
|
+
const poolSize = opts?.pool ?? 0;
|
|
53
|
+
|
|
54
|
+
if (_tabMode === "tab") {
|
|
55
|
+
if (!_client) throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
|
|
56
|
+
|
|
57
|
+
if (poolSize > 1) {
|
|
58
|
+
const pool = new TabPool(_client, poolSize, url, name);
|
|
59
|
+
await pool.init();
|
|
60
|
+
const siteObj = createSiteObject(name, url, _client, "default", pool);
|
|
61
|
+
_sites[name] = siteObj;
|
|
62
|
+
piggy[name] = siteObj;
|
|
63
|
+
logger.success(`[${name}] registered with pool of ${poolSize} tabs`);
|
|
64
|
+
} else {
|
|
65
|
+
const tabId = await _client.newTab();
|
|
66
|
+
const siteObj = createSiteObject(name, url, _client, tabId);
|
|
67
|
+
_sites[name] = siteObj;
|
|
68
|
+
piggy[name] = siteObj;
|
|
69
|
+
logger.success(`[${name}] registered as tab ${tabId}`);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
const socketName = `piggy_${name}`;
|
|
73
|
+
await spawnBrowserOnSocket(socketName, binaryMode);
|
|
74
|
+
await new Promise(r => setTimeout(r, 500));
|
|
75
|
+
const c = new PiggyClient(socketName);
|
|
76
|
+
await c.connect();
|
|
77
|
+
_extraProcs.push({ socket: socketName, client: c });
|
|
78
|
+
const siteObj = createSiteObject(name, url, c, "default");
|
|
79
|
+
_sites[name] = siteObj;
|
|
80
|
+
piggy[name] = siteObj;
|
|
81
|
+
logger.success(`[${name}] registered as process on "${socketName}"`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return piggy;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// ── Global controls ───────────────────────────────────────────────────────
|
|
88
|
+
actHuman: (enable: boolean) => {
|
|
89
|
+
setHumanMode(enable);
|
|
90
|
+
logger.info(`[piggy] actHuman: ${enable}`);
|
|
91
|
+
return piggy;
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
mode: (m: TabMode) => { _tabMode = m; return piggy; },
|
|
95
|
+
|
|
96
|
+
// ── Expose Function ───────────────────────────────────────────────────────
|
|
97
|
+
expose: async (name: string, handler: (data: any) => Promise<any> | any, tabId = "default") => {
|
|
98
|
+
if (!_client) throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
|
|
99
|
+
await _client.exposeFunction(name, handler, tabId);
|
|
100
|
+
logger.success(`[piggy] exposed global function: ${name}`);
|
|
101
|
+
return piggy;
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
unexpose: async (name: string, tabId = "default") => {
|
|
105
|
+
if (!_client) throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
|
|
106
|
+
await _client.unexposeFunction(name, tabId);
|
|
107
|
+
logger.info(`[piggy] unexposed function: ${name}`);
|
|
108
|
+
return piggy;
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// ── Proxy ─────────────────────────────────────────────────────────────────
|
|
112
|
+
proxy: {
|
|
113
|
+
load: (path: string) => { if (!_client) throw new Error("No client"); return _client.proxyLoad(path); },
|
|
114
|
+
fetch: (url: string) => { if (!_client) throw new Error("No client"); return _client.proxyFetch(url); },
|
|
115
|
+
ovpn: (path: string) => { if (!_client) throw new Error("No client"); return _client.proxyOvpn(path); },
|
|
116
|
+
set: (opts: Parameters<PiggyClient["proxySet"]>[0]) => { if (!_client) throw new Error("No client"); return _client.proxySet(opts); },
|
|
117
|
+
test: () => { if (!_client) throw new Error("No client"); return _client.proxyTest(); },
|
|
118
|
+
testStop: () => { if (!_client) throw new Error("No client"); return _client.proxyTestStop(); },
|
|
119
|
+
next: () => { if (!_client) throw new Error("No client"); return _client.proxyNext(); },
|
|
120
|
+
disable: () => { if (!_client) throw new Error("No client"); return _client.proxyDisable(); },
|
|
121
|
+
enable: () => { if (!_client) throw new Error("No client"); return _client.proxyEnable(); },
|
|
122
|
+
current: () => { if (!_client) throw new Error("No client"); return _client.proxyCurrent(); },
|
|
123
|
+
stats: () => { if (!_client) throw new Error("No client"); return _client.proxyStats(); },
|
|
124
|
+
list: (limit?: number) => { if (!_client) throw new Error("No client"); return _client.proxyList(limit); },
|
|
125
|
+
rotation: (mode: "none" | "timed" | "perrequest", interval?: number) => { if (!_client) throw new Error("No client"); return _client.proxyRotation(mode, interval); },
|
|
126
|
+
config: (opts: { skipDead?: boolean; autoCheck?: boolean }) => { if (!_client) throw new Error("No client"); return _client.proxyConfig(opts); },
|
|
127
|
+
save: (path: string, filter?: "alive" | "dead" | "all") => { if (!_client) throw new Error("No client"); return _client.proxySave(path, filter); },
|
|
128
|
+
on: (event: string, handler: (data: any) => void) => { if (!_client) throw new Error("No client"); return _client.onProxyEvent(event, handler); },
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// ── Elysia server ─────────────────────────────────────────────────────────
|
|
132
|
+
serve: (
|
|
133
|
+
port: number,
|
|
134
|
+
opts?: {
|
|
135
|
+
hostname?: string;
|
|
136
|
+
title?: string;
|
|
137
|
+
version?: string;
|
|
138
|
+
description?: string;
|
|
139
|
+
path?: string;
|
|
140
|
+
}
|
|
141
|
+
) => startServer(port, opts?.hostname, opts),
|
|
142
|
+
|
|
143
|
+
stopServer,
|
|
144
|
+
|
|
145
|
+
// ── Route listing ─────────────────────────────────────────────────────────
|
|
146
|
+
routes: () =>
|
|
147
|
+
Array.from(routeRegistry.entries()).map(([key, cfg]) => {
|
|
148
|
+
const [site] = key.split(":");
|
|
149
|
+
return {
|
|
150
|
+
site,
|
|
151
|
+
method: cfg.method,
|
|
152
|
+
path: `/${site}${cfg.path}`,
|
|
153
|
+
ttl: cfg.ttl,
|
|
154
|
+
middlewareCount: cfg.before.length,
|
|
155
|
+
};
|
|
156
|
+
}),
|
|
157
|
+
|
|
158
|
+
// ── Multi-site ────────────────────────────────────────────────────────────
|
|
159
|
+
all: (sites: SiteObject[]) =>
|
|
160
|
+
new Proxy({} as any, {
|
|
161
|
+
get: (_, method: string) =>
|
|
162
|
+
(...args: any[]) => Promise.all(sites.map((s: any) => s[method]?.(...args))),
|
|
163
|
+
}),
|
|
164
|
+
|
|
165
|
+
diff: (sites: SiteObject[]) =>
|
|
166
|
+
new Proxy({} as any, {
|
|
167
|
+
get: (_, method: string) =>
|
|
168
|
+
async (...args: any[]) => {
|
|
169
|
+
const results = await Promise.all(sites.map((s: any) => s[method]?.(...args)));
|
|
170
|
+
return Object.fromEntries(sites.map((s: any, i) => [s._name ?? i, results[i]]));
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
|
|
174
|
+
// ── Shutdown ──────────────────────────────────────────────────────────────
|
|
175
|
+
close: async (opts?: { force?: boolean }) => {
|
|
176
|
+
stopServer();
|
|
177
|
+
if (opts?.force) {
|
|
178
|
+
for (const { client: c } of _extraProcs) c.disconnect();
|
|
179
|
+
_client?.disconnect();
|
|
180
|
+
killBrowser();
|
|
181
|
+
routeRegistry.clear();
|
|
182
|
+
keepAliveSites.clear();
|
|
183
|
+
} else {
|
|
184
|
+
for (const [name, site] of Object.entries(_sites)) {
|
|
185
|
+
if (!keepAliveSites.has(name)) await (site as any).close?.();
|
|
186
|
+
}
|
|
187
|
+
if (keepAliveSites.size === 0) {
|
|
188
|
+
for (const { client: c } of _extraProcs) c.disconnect();
|
|
189
|
+
_extraProcs.length = 0;
|
|
190
|
+
_client?.disconnect();
|
|
191
|
+
_client = null;
|
|
192
|
+
setClient(null);
|
|
193
|
+
killBrowser();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
logger.info("[piggy] closed");
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
detect: detectBinary,
|
|
200
|
+
logger,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// ── usePiggy ──────────────────────────────────────────────────────────────────
|
|
204
|
+
// Typed accessor — call AFTER register() so sites exist on piggy.
|
|
205
|
+
// const { amazon, ebay } = usePiggy<"amazon" | "ebay">()
|
|
206
|
+
|
|
207
|
+
type TypedPiggy<Sites extends string> = typeof piggy & {
|
|
208
|
+
[K in Sites]: SiteObject;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export function usePiggy<Sites extends string>(): TypedPiggy<Sites> {
|
|
212
|
+
return piggy as TypedPiggy<Sites>;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export type { SiteObject };
|
|
216
|
+
export default piggy;
|
|
222
217
|
export { piggy };
|