nothing-browser 0.1.2 → 0.1.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/dist/piggy.d.ts.map +1 -1
- package/dist/piggy.js +40 -3
- package/dist/register/index.js +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +1 -1
- package/piggy.ts +80 -14
package/dist/piggy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"piggy.d.ts","sourceRoot":"","sources":["../piggy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"piggy.d.ts","sourceRoot":"","sources":["../piggy.ts"],"names":[],"mappings":"AAIA,OAAO,EAA6C,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAkD9F,QAAA,MAAM,KAAK,EAAE,GA+QZ,CAAC;AAIF,KAAK,UAAU,CAAC,KAAK,SAAS,MAAM,IAAI,OAAO,KAAK,GAAG;KACpD,CAAC,IAAI,KAAK,GAAG,UAAU;CACzB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,SAAS,MAAM,KAAK,UAAU,CAAC,KAAK,CAAC,CAElE;AAED,YAAY,EAAE,UAAU,EAAE,CAAC;AAC3B,eAAe,KAAK,CAAC;AACrB,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
package/dist/piggy.js
CHANGED
|
@@ -27311,7 +27311,7 @@ function finalize(ctx, schema) {
|
|
|
27311
27311
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
27312
27312
|
} else if (ctx.target === "draft-04") {
|
|
27313
27313
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
27314
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
27314
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
27315
27315
|
if (ctx.external?.uri) {
|
|
27316
27316
|
const id = ctx.external.registry.get(schema)?.id;
|
|
27317
27317
|
if (!id)
|
|
@@ -29966,6 +29966,7 @@ var _router = null;
|
|
|
29966
29966
|
var _tabMode = "tab";
|
|
29967
29967
|
var _extraProcs = [];
|
|
29968
29968
|
var _sites = {};
|
|
29969
|
+
var _singleSiteName = null;
|
|
29969
29970
|
function guardClient() {
|
|
29970
29971
|
if (!_client)
|
|
29971
29972
|
throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
|
|
@@ -30002,9 +30003,15 @@ var piggy = {
|
|
|
30002
30003
|
throw new Error(`No URL for site "${name}"`);
|
|
30003
30004
|
const binaryMode = opts?.binary ?? "headless";
|
|
30004
30005
|
const poolSize = opts?.pool ?? 0;
|
|
30006
|
+
const isSingle = opts?.single === true;
|
|
30007
|
+
if (isSingle && _singleSiteName && _singleSiteName !== name) {
|
|
30008
|
+
throw new Error(`piggy: site "${_singleSiteName}" is already registered as single. ` + `Only one site may use { single: true } at a time.`);
|
|
30009
|
+
}
|
|
30005
30010
|
if (_tabMode === "tab") {
|
|
30006
30011
|
const client = guardClient();
|
|
30007
30012
|
if (poolSize > 1) {
|
|
30013
|
+
if (isSingle)
|
|
30014
|
+
throw new Error("piggy: { single: true } is incompatible with pool > 1");
|
|
30008
30015
|
const pool = new TabPool(client, poolSize, url2, name);
|
|
30009
30016
|
await pool.init();
|
|
30010
30017
|
const siteObj = createSiteObject(name, url2, client, "default", pool);
|
|
@@ -30012,13 +30019,20 @@ var piggy = {
|
|
|
30012
30019
|
piggy[name] = siteObj;
|
|
30013
30020
|
logger_default.success(`[${name}] registered with pool of ${poolSize} tabs`);
|
|
30014
30021
|
} else {
|
|
30015
|
-
const tabId = await client.newTab();
|
|
30022
|
+
const tabId = isSingle ? "default" : await client.newTab();
|
|
30016
30023
|
const siteObj = createSiteObject(name, url2, client, tabId);
|
|
30017
30024
|
_sites[name] = siteObj;
|
|
30018
30025
|
piggy[name] = siteObj;
|
|
30019
|
-
|
|
30026
|
+
if (isSingle) {
|
|
30027
|
+
_singleSiteName = name;
|
|
30028
|
+
logger_default.success(`[${name}] registered as single-tab site (default tab)`);
|
|
30029
|
+
} else {
|
|
30030
|
+
logger_default.success(`[${name}] registered as tab ${tabId}`);
|
|
30031
|
+
}
|
|
30020
30032
|
}
|
|
30021
30033
|
} else {
|
|
30034
|
+
if (isSingle)
|
|
30035
|
+
throw new Error("piggy: { single: true } is only supported in tab mode");
|
|
30022
30036
|
const socketName = `piggy_${name}`;
|
|
30023
30037
|
await spawnBrowserOnSocket(socketName, binaryMode);
|
|
30024
30038
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -30032,6 +30046,28 @@ var piggy = {
|
|
|
30032
30046
|
}
|
|
30033
30047
|
return piggy;
|
|
30034
30048
|
},
|
|
30049
|
+
extend: async (...installers) => {
|
|
30050
|
+
if (!_singleSiteName) {
|
|
30051
|
+
throw new Error(`piggy.extend() requires a site registered with { single: true }.
|
|
30052
|
+
` + 'Example: await piggy.register("mysite", url, { single: true })');
|
|
30053
|
+
}
|
|
30054
|
+
if (installers.length === 0) {
|
|
30055
|
+
logger_default.warn("[piggy] extend() called with no plugins — nothing to do");
|
|
30056
|
+
return piggy;
|
|
30057
|
+
}
|
|
30058
|
+
const site = _sites[_singleSiteName];
|
|
30059
|
+
if (!site) {
|
|
30060
|
+
throw new Error(`piggy.extend(): site "${_singleSiteName}" not found — register it first`);
|
|
30061
|
+
}
|
|
30062
|
+
for (const installer of installers) {
|
|
30063
|
+
if (typeof installer !== "function") {
|
|
30064
|
+
throw new Error("piggy.extend(): each argument must be a plugin installer function");
|
|
30065
|
+
}
|
|
30066
|
+
await installer(site);
|
|
30067
|
+
}
|
|
30068
|
+
logger_default.success(`[piggy] ${installers.length} plugin(s) installed on "${_singleSiteName}"`);
|
|
30069
|
+
return piggy;
|
|
30070
|
+
},
|
|
30035
30071
|
get tabs() {
|
|
30036
30072
|
return _router?.tabs ?? createTabsAPI(guardClient());
|
|
30037
30073
|
},
|
|
@@ -30147,6 +30183,7 @@ var piggy = {
|
|
|
30147
30183
|
}),
|
|
30148
30184
|
close: async (opts) => {
|
|
30149
30185
|
stopServer();
|
|
30186
|
+
_singleSiteName = null;
|
|
30150
30187
|
if (opts?.force) {
|
|
30151
30188
|
for (const { client: c } of _extraProcs)
|
|
30152
30189
|
c.disconnect();
|
package/dist/register/index.js
CHANGED
|
@@ -21800,7 +21800,7 @@ function finalize(ctx, schema) {
|
|
|
21800
21800
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
21801
21801
|
} else if (ctx.target === "draft-04") {
|
|
21802
21802
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
21803
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
21803
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
21804
21804
|
if (ctx.external?.uri) {
|
|
21805
21805
|
const id = ctx.external.registry.get(schema)?.id;
|
|
21806
21806
|
if (!id)
|
package/dist/server/index.js
CHANGED
|
@@ -25742,7 +25742,7 @@ function finalize(ctx, schema) {
|
|
|
25742
25742
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
25743
25743
|
} else if (ctx.target === "draft-04") {
|
|
25744
25744
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
25745
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
25745
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
25746
25746
|
if (ctx.external?.uri) {
|
|
25747
25747
|
const id = ctx.external.registry.get(schema)?.id;
|
|
25748
25748
|
if (!id)
|
package/package.json
CHANGED
package/piggy.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
// piggy.ts
|
|
2
|
-
//the main file
|
|
1
|
+
// piggy.ts — patched: adds single:true + piggy.extend()
|
|
3
2
|
import { detectBinary, type BinaryMode } from "./piggy/launch/detect";
|
|
4
3
|
import { spawnBrowser, killBrowser, spawnBrowserOnSocket } from "./piggy/launch/spawn";
|
|
5
4
|
import { PiggyClient } from "./piggy/client";
|
|
@@ -27,12 +26,19 @@ import logger from "./piggy/logger";
|
|
|
27
26
|
|
|
28
27
|
type TabMode = "tab" | "process";
|
|
29
28
|
|
|
29
|
+
// A plugin installer is an async function that receives a site and enriches it.
|
|
30
|
+
type PluginInstaller = (site: SiteObject) => Promise<any>;
|
|
31
|
+
|
|
30
32
|
let _client: PiggyClient | null = null;
|
|
31
33
|
let _router: PiggyRouter | null = null;
|
|
32
34
|
let _tabMode: TabMode = "tab";
|
|
33
35
|
const _extraProcs: { socket: string; client: PiggyClient }[] = [];
|
|
34
36
|
const _sites: Record<string, SiteObject> = {};
|
|
35
37
|
|
|
38
|
+
// ── Single-site tracking for extend() ────────────────────────────────────────
|
|
39
|
+
// Only one site may be registered with { single: true } at a time.
|
|
40
|
+
let _singleSiteName: string | null = null;
|
|
41
|
+
|
|
36
42
|
// ── Internal guard ────────────────────────────────────────────────────────────
|
|
37
43
|
|
|
38
44
|
function guardClient(): PiggyClient {
|
|
@@ -74,37 +80,57 @@ const piggy: any = {
|
|
|
74
80
|
},
|
|
75
81
|
|
|
76
82
|
// ── HTTP client (port 2005 direct) ────────────────────────────────────────
|
|
77
|
-
// Use when you want to talk to the browser over HTTP without a socket client.
|
|
78
83
|
http: (opts: HttpClientOptions) => createHttpClient(opts),
|
|
79
84
|
|
|
80
85
|
// ── Register ──────────────────────────────────────────────────────────────
|
|
81
86
|
register: async (
|
|
82
87
|
name: string,
|
|
83
88
|
url: string,
|
|
84
|
-
opts?: { binary?: BinaryMode; pool?: number }
|
|
89
|
+
opts?: { binary?: BinaryMode; pool?: number; single?: boolean }
|
|
85
90
|
) => {
|
|
86
91
|
if (!url?.trim()) throw new Error(`No URL for site "${name}"`);
|
|
92
|
+
|
|
87
93
|
const binaryMode: BinaryMode = opts?.binary ?? "headless";
|
|
88
|
-
const poolSize
|
|
94
|
+
const poolSize = opts?.pool ?? 0;
|
|
95
|
+
const isSingle = opts?.single === true;
|
|
96
|
+
|
|
97
|
+
// ── single: true enforcement ───────────────────────────────────────────
|
|
98
|
+
// A single-site registration uses the default tab and blocks tab.new so
|
|
99
|
+
// the binary stays strictly single-tab. Only one site may be single.
|
|
100
|
+
if (isSingle && _singleSiteName && _singleSiteName !== name) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`piggy: site "${_singleSiteName}" is already registered as single. ` +
|
|
103
|
+
`Only one site may use { single: true } at a time.`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
89
106
|
|
|
90
107
|
if (_tabMode === "tab") {
|
|
91
108
|
const client = guardClient();
|
|
92
109
|
|
|
93
110
|
if (poolSize > 1) {
|
|
111
|
+
if (isSingle) throw new Error('piggy: { single: true } is incompatible with pool > 1');
|
|
94
112
|
const pool = new TabPool(client, poolSize, url, name);
|
|
95
113
|
await pool.init();
|
|
96
114
|
const siteObj = createSiteObject(name, url, client, "default", pool);
|
|
97
115
|
_sites[name] = siteObj;
|
|
98
|
-
piggy[name]
|
|
116
|
+
piggy[name] = siteObj;
|
|
99
117
|
logger.success(`[${name}] registered with pool of ${poolSize} tabs`);
|
|
100
118
|
} else {
|
|
101
|
-
|
|
119
|
+
// single: true → reuse the default tab, never call newTab()
|
|
120
|
+
const tabId = isSingle ? "default" : await client.newTab();
|
|
102
121
|
const siteObj = createSiteObject(name, url, client, tabId);
|
|
103
122
|
_sites[name] = siteObj;
|
|
104
|
-
piggy[name]
|
|
105
|
-
|
|
123
|
+
piggy[name] = siteObj;
|
|
124
|
+
|
|
125
|
+
if (isSingle) {
|
|
126
|
+
_singleSiteName = name;
|
|
127
|
+
logger.success(`[${name}] registered as single-tab site (default tab)`);
|
|
128
|
+
} else {
|
|
129
|
+
logger.success(`[${name}] registered as tab ${tabId}`);
|
|
130
|
+
}
|
|
106
131
|
}
|
|
107
132
|
} else {
|
|
133
|
+
if (isSingle) throw new Error('piggy: { single: true } is only supported in tab mode');
|
|
108
134
|
const socketName = `piggy_${name}`;
|
|
109
135
|
await spawnBrowserOnSocket(socketName, binaryMode);
|
|
110
136
|
await new Promise(r => setTimeout(r, 500));
|
|
@@ -113,17 +139,56 @@ const piggy: any = {
|
|
|
113
139
|
_extraProcs.push({ socket: socketName, client: c });
|
|
114
140
|
const siteObj = createSiteObject(name, url, c, "default");
|
|
115
141
|
_sites[name] = siteObj;
|
|
116
|
-
piggy[name]
|
|
142
|
+
piggy[name] = siteObj;
|
|
117
143
|
logger.success(`[${name}] registered as process on "${socketName}"`);
|
|
118
144
|
}
|
|
119
145
|
|
|
120
146
|
return piggy;
|
|
121
147
|
},
|
|
122
148
|
|
|
149
|
+
// ── extend() — installs plugins onto the single-flagged site ─────────────
|
|
150
|
+
//
|
|
151
|
+
// Each installer is an async function returned by a plugin factory, e.g.:
|
|
152
|
+
// innerstorage({ path: './wa-storage.json' }) → installer fn
|
|
153
|
+
//
|
|
154
|
+
// Usage:
|
|
155
|
+
// await piggy.extend(
|
|
156
|
+
// innerstorage({ path: './wa-storage.json' }),
|
|
157
|
+
// cookiesinject({ cookieFile: './wa-cookies.json' }),
|
|
158
|
+
// mediacapture({ downloadDir: './wa-media/' })
|
|
159
|
+
// );
|
|
160
|
+
extend: async (...installers: PluginInstaller[]) => {
|
|
161
|
+
if (!_singleSiteName) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
'piggy.extend() requires a site registered with { single: true }.\n' +
|
|
164
|
+
'Example: await piggy.register("mysite", url, { single: true })'
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (installers.length === 0) {
|
|
168
|
+
logger.warn('[piggy] extend() called with no plugins — nothing to do');
|
|
169
|
+
return piggy;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const site = _sites[_singleSiteName];
|
|
173
|
+
if (!site) {
|
|
174
|
+
throw new Error(`piggy.extend(): site "${_singleSiteName}" not found — register it first`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (const installer of installers) {
|
|
178
|
+
if (typeof installer !== 'function') {
|
|
179
|
+
throw new Error('piggy.extend(): each argument must be a plugin installer function');
|
|
180
|
+
}
|
|
181
|
+
await installer(site);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
logger.success(`[piggy] ${installers.length} plugin(s) installed on "${_singleSiteName}"`);
|
|
185
|
+
return piggy;
|
|
186
|
+
},
|
|
187
|
+
|
|
123
188
|
// ── Sub-APIs (1:1 with C++ files, available after launch/connect) ─────────
|
|
124
189
|
|
|
125
|
-
|
|
126
|
-
|
|
190
|
+
get tabs() { return _router?.tabs ?? createTabsAPI(guardClient()); },
|
|
191
|
+
get tab() { return _router?.tabs ?? createTabsAPI(guardClient()); },
|
|
127
192
|
get navigation() { return _router?.navigation ?? createNavigationAPI(guardClient()); },
|
|
128
193
|
get interactions() { return _router?.interactions ?? createInteractionsAPI(guardClient()); },
|
|
129
194
|
get media() { return _router?.media ?? createMediaAPI(guardClient()); },
|
|
@@ -146,7 +211,7 @@ const piggy: any = {
|
|
|
146
211
|
return {
|
|
147
212
|
load: (path: string) => api.load(path),
|
|
148
213
|
fetch: (url: string) => api.fetch(url),
|
|
149
|
-
ovpn: (path: string)
|
|
214
|
+
ovpn: (path: string) => api.ovpn(path),
|
|
150
215
|
set: (opts: Parameters<typeof api.set>[0]) => api.set(opts),
|
|
151
216
|
test: () => api.test(),
|
|
152
217
|
testStop: () => api.testStop(),
|
|
@@ -160,7 +225,7 @@ const piggy: any = {
|
|
|
160
225
|
rotation: (mode: "none" | "timed" | "perrequest", interval?: number) => api.rotation(mode, interval),
|
|
161
226
|
config: (opts: { skipDead?: boolean; autoCheck?: boolean }) => api.config(opts),
|
|
162
227
|
save: (path: string, filter?: "alive" | "dead" | "all") => api.save(path, filter),
|
|
163
|
-
on: (event: string, handler: (data: any) => void)
|
|
228
|
+
on: (event: string, handler: (data: any) => void) => guardClient().onProxyEvent(event, handler),
|
|
164
229
|
};
|
|
165
230
|
},
|
|
166
231
|
|
|
@@ -232,6 +297,7 @@ const piggy: any = {
|
|
|
232
297
|
// ── Shutdown ──────────────────────────────────────────────────────────────
|
|
233
298
|
close: async (opts?: { force?: boolean }) => {
|
|
234
299
|
stopServer();
|
|
300
|
+
_singleSiteName = null;
|
|
235
301
|
if (opts?.force) {
|
|
236
302
|
for (const { client: c } of _extraProcs) c.disconnect();
|
|
237
303
|
_client?.disconnect();
|