nothing-browser 0.0.17 → 0.0.18

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.js CHANGED
@@ -7029,66 +7029,179 @@ import { connect } from "net";
7029
7029
  import { writeFileSync, mkdirSync } from "fs";
7030
7030
  import { dirname } from "path";
7031
7031
  import { platform as platform2 } from "os";
7032
- var SOCKET_PATH = platform2() === "win32" ? "\\\\.\\pipe\\piggy" : "/tmp/piggy";
7032
+ var DEFAULT_SOCKET_PATH = platform2() === "win32" ? "\\\\.\\pipe\\piggy" : "/tmp/piggy";
7033
+
7034
+ class SocketTransport {
7035
+ sock;
7036
+ constructor(sock) {
7037
+ this.sock = sock;
7038
+ }
7039
+ send(data) {
7040
+ this.sock.write(data);
7041
+ }
7042
+ on(event, handler) {
7043
+ this.sock.on(event, handler);
7044
+ }
7045
+ destroy() {
7046
+ this.sock.destroy();
7047
+ }
7048
+ }
7049
+
7050
+ class HttpTransport {
7051
+ host;
7052
+ key;
7053
+ dataHandlers = [];
7054
+ errorHandlers = [];
7055
+ closeHandlers = [];
7056
+ _destroyed = false;
7057
+ constructor(host, key) {
7058
+ this.host = host.replace(/\/$/, "");
7059
+ this.key = key;
7060
+ }
7061
+ on(event, handler) {
7062
+ if (event === "data")
7063
+ this.dataHandlers.push(handler);
7064
+ if (event === "error")
7065
+ this.errorHandlers.push(handler);
7066
+ if (event === "close")
7067
+ this.closeHandlers.push(handler);
7068
+ }
7069
+ send(data) {
7070
+ if (this._destroyed)
7071
+ return;
7072
+ fetch(this.host, {
7073
+ method: "POST",
7074
+ headers: {
7075
+ "Content-Type": "application/json",
7076
+ "X-Piggy-Key": this.key
7077
+ },
7078
+ body: data
7079
+ }).then(async (res) => {
7080
+ if (!res.ok) {
7081
+ const text2 = await res.text().catch(() => `HTTP ${res.status}`);
7082
+ this.errorHandlers.forEach((h) => h(new Error(`HTTP ${res.status}: ${text2}`)));
7083
+ return;
7084
+ }
7085
+ const text = await res.text();
7086
+ const lines = text.split(`
7087
+ `).filter((l) => l.trim());
7088
+ for (const line of lines) {
7089
+ this.dataHandlers.forEach((h) => h(line + `
7090
+ `));
7091
+ }
7092
+ }).catch((e) => {
7093
+ if (!this._destroyed) {
7094
+ this.errorHandlers.forEach((h) => h(e));
7095
+ }
7096
+ });
7097
+ }
7098
+ destroy() {
7099
+ this._destroyed = true;
7100
+ this.closeHandlers.forEach((h) => h());
7101
+ }
7102
+ }
7033
7103
 
7034
7104
  class PiggyClient {
7035
7105
  socketPath;
7036
- socket = null;
7106
+ httpHost = null;
7107
+ httpKey = null;
7108
+ transport = null;
7037
7109
  reqId = 0;
7038
7110
  pending = new Map;
7039
7111
  buf = "";
7040
- eventBuffer = "";
7041
7112
  eventHandlers = new Map;
7042
7113
  globalEventHandlers = new Map;
7043
- constructor(socketPath = SOCKET_PATH) {
7044
- this.socketPath = socketPath;
7114
+ constructor(arg) {
7115
+ if (arg && typeof arg === "object") {
7116
+ this.socketPath = "";
7117
+ this.httpHost = arg.host.replace(/\/$/, "");
7118
+ this.httpKey = arg.key;
7119
+ } else {
7120
+ this.socketPath = arg ?? DEFAULT_SOCKET_PATH;
7121
+ }
7045
7122
  this.eventHandlers.set("default", new Map);
7046
7123
  }
7047
7124
  connect() {
7125
+ if (this.httpHost)
7126
+ return this._connectHttp();
7127
+ return this._connectSocket();
7128
+ }
7129
+ _connectSocket() {
7048
7130
  return new Promise((resolve, reject) => {
7049
7131
  logger_default.info(`Connecting to socket: ${this.socketPath}`);
7050
7132
  const sock = connect(this.socketPath);
7051
7133
  sock.setEncoding("utf8");
7052
7134
  sock.on("connect", () => {
7053
- this.socket = sock;
7054
- logger_default.success("Connected to Piggy server");
7135
+ this.transport = new SocketTransport(sock);
7136
+ this._wireTransport();
7137
+ logger_default.success("Connected to Piggy server (socket)");
7055
7138
  resolve();
7056
7139
  });
7057
- sock.on("data", (chunk) => {
7058
- this.eventBuffer += chunk;
7059
- const lines = this.eventBuffer.split(`
7060
- `);
7061
- this.eventBuffer = lines.pop();
7062
- for (const line of lines) {
7063
- if (!line.trim())
7064
- continue;
7065
- try {
7066
- const msg = JSON.parse(line);
7067
- if (msg.type === "event") {
7068
- this.handleEvent(msg);
7069
- continue;
7070
- }
7071
- const p = this.pending.get(msg.id);
7072
- if (p) {
7073
- this.pending.delete(msg.id);
7074
- msg.ok ? p.resolve(msg.data) : p.reject(new Error(msg.data ?? "command failed"));
7075
- }
7076
- } catch {
7077
- logger_default.error(`Bad JSON from server: ${line}`);
7078
- }
7079
- }
7080
- });
7081
7140
  sock.on("error", (e) => {
7082
7141
  for (const p of this.pending.values())
7083
7142
  p.reject(e);
7084
7143
  this.pending.clear();
7085
7144
  reject(e);
7086
7145
  });
7087
- sock.on("close", () => {
7088
- for (const p of this.pending.values())
7089
- p.reject(new Error("Socket closed"));
7090
- this.pending.clear();
7146
+ });
7147
+ }
7148
+ async _connectHttp() {
7149
+ logger_default.info(`Connecting to Piggy server (HTTP): ${this.httpHost}`);
7150
+ try {
7151
+ const res = await fetch(this.httpHost, {
7152
+ method: "POST",
7153
+ headers: {
7154
+ "Content-Type": "application/json",
7155
+ "X-Piggy-Key": this.httpKey
7156
+ },
7157
+ body: "hello"
7091
7158
  });
7159
+ if (res.status === 401) {
7160
+ throw new Error("Unauthorized — invalid X-Piggy-Key");
7161
+ }
7162
+ this.transport = new HttpTransport(this.httpHost, this.httpKey);
7163
+ this._wireTransport();
7164
+ logger_default.success(`Connected to Piggy server (HTTP): ${this.httpHost}`);
7165
+ } catch (e) {
7166
+ throw new Error(`Failed to connect to Piggy HTTP server: ${e.message}`);
7167
+ }
7168
+ }
7169
+ _wireTransport() {
7170
+ if (!this.transport)
7171
+ return;
7172
+ this.transport.on("data", (chunk) => {
7173
+ this.buf += chunk;
7174
+ const lines = this.buf.split(`
7175
+ `);
7176
+ this.buf = lines.pop();
7177
+ for (const line of lines) {
7178
+ if (!line.trim())
7179
+ continue;
7180
+ try {
7181
+ const msg = JSON.parse(line);
7182
+ if (msg.type === "event") {
7183
+ this.handleEvent(msg);
7184
+ continue;
7185
+ }
7186
+ const p = this.pending.get(msg.id);
7187
+ if (p) {
7188
+ this.pending.delete(msg.id);
7189
+ msg.ok ? p.resolve(msg.data) : p.reject(new Error(msg.data ?? "command failed"));
7190
+ }
7191
+ } catch {
7192
+ logger_default.error(`Bad JSON from server: ${line}`);
7193
+ }
7194
+ }
7195
+ });
7196
+ this.transport.on("error", (e) => {
7197
+ for (const p of this.pending.values())
7198
+ p.reject(e);
7199
+ this.pending.clear();
7200
+ });
7201
+ this.transport.on("close", () => {
7202
+ for (const p of this.pending.values())
7203
+ p.reject(new Error("Connection closed"));
7204
+ this.pending.clear();
7092
7205
  });
7093
7206
  }
7094
7207
  handleEvent(event) {
@@ -7152,7 +7265,6 @@ class PiggyClient {
7152
7265
  } catch {}
7153
7266
  }
7154
7267
  }
7155
- return;
7156
7268
  }
7157
7269
  }
7158
7270
  onEvent(eventName, tabId, handler) {
@@ -7164,16 +7276,16 @@ class PiggyClient {
7164
7276
  return () => this.globalEventHandlers.get(key)?.delete(handler);
7165
7277
  }
7166
7278
  disconnect() {
7167
- this.socket?.destroy();
7168
- this.socket = null;
7279
+ this.transport?.destroy();
7280
+ this.transport = null;
7169
7281
  }
7170
7282
  send(cmd, payload = {}) {
7171
7283
  return new Promise((resolve, reject) => {
7172
- if (!this.socket)
7284
+ if (!this.transport)
7173
7285
  return reject(new Error("Not connected"));
7174
7286
  const id = String(++this.reqId);
7175
7287
  this.pending.set(id, { resolve, reject });
7176
- this.socket.write(JSON.stringify({ id, cmd, payload }) + `
7288
+ this.transport.send(JSON.stringify({ id, cmd, payload }) + `
7177
7289
  `);
7178
7290
  });
7179
7291
  }
@@ -7343,6 +7455,30 @@ class PiggyClient {
7343
7455
  async sessionImport(data, tabId = "default") {
7344
7456
  await this.send("session.import", { data, tabId });
7345
7457
  }
7458
+ async sessionWsSave(enabled = true) {
7459
+ await this.send("session.ws.save", { enabled });
7460
+ }
7461
+ async sessionPingsSave(enabled = true) {
7462
+ await this.send("session.pings.save", { enabled });
7463
+ }
7464
+ async sessionPaths() {
7465
+ return this.send("session.paths", {});
7466
+ }
7467
+ async sessionCookiesPath() {
7468
+ return this.send("session.cookies.path", {});
7469
+ }
7470
+ async sessionProfilePath() {
7471
+ return this.send("session.profile.path", {});
7472
+ }
7473
+ async sessionWsPath() {
7474
+ return this.send("session.ws.path", {});
7475
+ }
7476
+ async sessionPingsPath() {
7477
+ return this.send("session.pings.path", {});
7478
+ }
7479
+ async sessionReload() {
7480
+ await this.send("session.reload", {});
7481
+ }
7346
7482
  async exposeFunction(name, handler, tabId = "default") {
7347
7483
  if (!this.eventHandlers.has(tabId))
7348
7484
  this.eventHandlers.set(tabId, new Map);
@@ -7369,6 +7505,54 @@ class PiggyClient {
7369
7505
  this.eventHandlers.set(tabId, new Map);
7370
7506
  logger_default.info(`[${tabId}] cleared all exposed functions`);
7371
7507
  }
7508
+ async proxyLoad(path) {
7509
+ await this.send("proxy.load", { path });
7510
+ }
7511
+ async proxyFetch(url) {
7512
+ await this.send("proxy.fetch", { url });
7513
+ }
7514
+ async proxyOvpn(path) {
7515
+ await this.send("proxy.ovpn", { path });
7516
+ }
7517
+ async proxySet(opts) {
7518
+ await this.send("proxy.set", opts);
7519
+ }
7520
+ async proxyTest() {
7521
+ await this.send("proxy.test", {});
7522
+ }
7523
+ async proxyTestStop() {
7524
+ await this.send("proxy.test.stop", {});
7525
+ }
7526
+ async proxyNext() {
7527
+ await this.send("proxy.next", {});
7528
+ }
7529
+ async proxyDisable() {
7530
+ await this.send("proxy.disable", {});
7531
+ }
7532
+ async proxyEnable() {
7533
+ await this.send("proxy.enable", {});
7534
+ }
7535
+ async proxyCurrent() {
7536
+ return this.send("proxy.current", {});
7537
+ }
7538
+ async proxyStats() {
7539
+ return this.send("proxy.stats", {});
7540
+ }
7541
+ async proxyList(limit) {
7542
+ return this.send("proxy.list", limit !== undefined ? { limit } : {});
7543
+ }
7544
+ async proxyRotation(mode, interval) {
7545
+ await this.send("proxy.rotation", { mode, ...interval !== undefined ? { interval } : {} });
7546
+ }
7547
+ async proxyConfig(opts) {
7548
+ await this.send("proxy.config", opts);
7549
+ }
7550
+ async proxySave(path, filter = "all") {
7551
+ await this.send("proxy.save", { path, filter });
7552
+ }
7553
+ onProxyEvent(event, handler) {
7554
+ return this.onEvent(event, "*", handler);
7555
+ }
7372
7556
  }
7373
7557
 
7374
7558
  // node_modules/memoirist/dist/index.mjs
@@ -21803,12 +21987,12 @@ var _Elysia = class _Elysia2 {
21803
21987
  }), this) : (typeof this.server?.reload == "function" && this.server.reload(this.server || {}), this._handle = composeGeneralHandler(this), this);
21804
21988
  }
21805
21989
  get fetch() {
21806
- const fetch = this.config.aot ? composeGeneralHandler(this) : createDynamicHandler(this);
21990
+ const fetch2 = this.config.aot ? composeGeneralHandler(this) : createDynamicHandler(this);
21807
21991
  return Object.defineProperty(this, "fetch", {
21808
- value: fetch,
21992
+ value: fetch2,
21809
21993
  configurable: true,
21810
21994
  writable: true
21811
- }), fetch;
21995
+ }), fetch2;
21812
21996
  }
21813
21997
  get modules() {
21814
21998
  return this.promisedModules;
@@ -28949,6 +29133,14 @@ var piggy = {
28949
29133
  logger_default.info(`[piggy] launched — tab mode: "${_tabMode}", binary: "${binaryMode}"`);
28950
29134
  return piggy;
28951
29135
  },
29136
+ connect: async (opts) => {
29137
+ _tabMode = "tab";
29138
+ _client = new PiggyClient({ host: opts.host, key: opts.key });
29139
+ await _client.connect();
29140
+ setClient(_client);
29141
+ logger_default.info(`[piggy] connected (HTTP) → ${opts.host}`);
29142
+ return piggy;
29143
+ },
28952
29144
  register: async (name, url2, opts) => {
28953
29145
  if (!url2?.trim())
28954
29146
  throw new Error(`No URL for site "${name}"`);
@@ -28956,12 +29148,11 @@ var piggy = {
28956
29148
  const poolSize = opts?.pool ?? 0;
28957
29149
  if (_tabMode === "tab") {
28958
29150
  if (!_client)
28959
- throw new Error("No client. Call piggy.launch() first.");
29151
+ throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
28960
29152
  if (poolSize > 1) {
28961
29153
  const pool = new TabPool(_client, poolSize, url2, name);
28962
29154
  await pool.init();
28963
- const firstTabId = "default";
28964
- const siteObj = createSiteObject(name, url2, _client, firstTabId, pool);
29155
+ const siteObj = createSiteObject(name, url2, _client, "default", pool);
28965
29156
  _sites[name] = siteObj;
28966
29157
  piggy[name] = siteObj;
28967
29158
  logger_default.success(`[${name}] registered with pool of ${poolSize} tabs`);
@@ -28997,18 +29188,100 @@ var piggy = {
28997
29188
  },
28998
29189
  expose: async (name, handler, tabId = "default") => {
28999
29190
  if (!_client)
29000
- throw new Error("No client. Call piggy.launch() first.");
29191
+ throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
29001
29192
  await _client.exposeFunction(name, handler, tabId);
29002
29193
  logger_default.success(`[piggy] exposed global function: ${name}`);
29003
29194
  return piggy;
29004
29195
  },
29005
29196
  unexpose: async (name, tabId = "default") => {
29006
29197
  if (!_client)
29007
- throw new Error("No client. Call piggy.launch() first.");
29198
+ throw new Error("No client. Call piggy.launch() or piggy.connect() first.");
29008
29199
  await _client.unexposeFunction(name, tabId);
29009
29200
  logger_default.info(`[piggy] unexposed function: ${name}`);
29010
29201
  return piggy;
29011
29202
  },
29203
+ proxy: {
29204
+ load: (path) => {
29205
+ if (!_client)
29206
+ throw new Error("No client");
29207
+ return _client.proxyLoad(path);
29208
+ },
29209
+ fetch: (url2) => {
29210
+ if (!_client)
29211
+ throw new Error("No client");
29212
+ return _client.proxyFetch(url2);
29213
+ },
29214
+ ovpn: (path) => {
29215
+ if (!_client)
29216
+ throw new Error("No client");
29217
+ return _client.proxyOvpn(path);
29218
+ },
29219
+ set: (opts) => {
29220
+ if (!_client)
29221
+ throw new Error("No client");
29222
+ return _client.proxySet(opts);
29223
+ },
29224
+ test: () => {
29225
+ if (!_client)
29226
+ throw new Error("No client");
29227
+ return _client.proxyTest();
29228
+ },
29229
+ testStop: () => {
29230
+ if (!_client)
29231
+ throw new Error("No client");
29232
+ return _client.proxyTestStop();
29233
+ },
29234
+ next: () => {
29235
+ if (!_client)
29236
+ throw new Error("No client");
29237
+ return _client.proxyNext();
29238
+ },
29239
+ disable: () => {
29240
+ if (!_client)
29241
+ throw new Error("No client");
29242
+ return _client.proxyDisable();
29243
+ },
29244
+ enable: () => {
29245
+ if (!_client)
29246
+ throw new Error("No client");
29247
+ return _client.proxyEnable();
29248
+ },
29249
+ current: () => {
29250
+ if (!_client)
29251
+ throw new Error("No client");
29252
+ return _client.proxyCurrent();
29253
+ },
29254
+ stats: () => {
29255
+ if (!_client)
29256
+ throw new Error("No client");
29257
+ return _client.proxyStats();
29258
+ },
29259
+ list: (limit) => {
29260
+ if (!_client)
29261
+ throw new Error("No client");
29262
+ return _client.proxyList(limit);
29263
+ },
29264
+ rotation: (mode, interval) => {
29265
+ if (!_client)
29266
+ throw new Error("No client");
29267
+ return _client.proxyRotation(mode, interval);
29268
+ },
29269
+ config: (opts) => {
29270
+ if (!_client)
29271
+ throw new Error("No client");
29272
+ return _client.proxyConfig(opts);
29273
+ },
29274
+ save: (path, filter) => {
29275
+ if (!_client)
29276
+ throw new Error("No client");
29277
+ return _client.proxySave(path, filter);
29278
+ },
29279
+ on: (event, handler) => {
29280
+ if (!_client)
29281
+ throw new Error("No client");
29282
+ return _client.onProxyEvent(event, handler);
29283
+ }
29284
+ },
29012
29285
  serve: (port, opts) => startServer(port, opts?.hostname, opts),
29013
29286
  stopServer,
29014
29287
  routes: () => Array.from(routeRegistry.entries()).map(([key, cfg]) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothing-browser",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "Browser automation library powered by Nothing Browser",
5
5
  "homepage": "https://github.com/ernest-tech-house-co-operation/nothing-browser#readme",
6
6
  "repository": {