app-manager-edge-worker 1.1.2 → 1.1.4

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
@@ -203,6 +203,14 @@ Log levels: `[INFO]` · `[SUCCESS]` · `[WARN]` · `[ERROR]` · `[TASK]` (job di
203
203
 
204
204
  ## 📝 Changelog
205
205
 
206
+ ### v1.1.4
207
+ - **Persistent MongoDB Session Restoration for WhatsApp**:
208
+ - Automatically restores WhatsApp companion device credentials (`creds.json`, pre-keys, session keys) from cluster MongoDB on worker boot.
209
+ - Workers restart without losing WhatsApp connection state or requiring QR code re-pairing.
210
+ - Live 150ms debounced synchronization of key rotations and credentials to MongoDB via `bulkWrite`.
211
+ - Automatic backup of pre-existing local disk sessions to cluster database on initial connection.
212
+ - Coordinated session wiping on remote logout and phone unlinking.
213
+
206
214
  ### v1.1.0
207
215
  - **WhatsApp Multi-Device Companion Relay**:
208
216
  - Independent companion device pairing via live QR streaming to Admin Dashboard.
package/bin/worker.js CHANGED
@@ -1,16 +1,16 @@
1
- #!/usr/bin/env node
2
-
3
- import { resolveWorkerConfig } from "../src/config.js";
4
- import { startWorkerClient } from "../src/client.js";
5
-
6
- async function main() {
7
- try {
8
- const config = await resolveWorkerConfig();
9
- await startWorkerClient(config);
10
- } catch (err) {
11
- console.error("Fatal Worker Error:", err);
12
- process.exit(1);
13
- }
14
- }
15
-
16
- main();
1
+ #!/usr/bin/env node
2
+
3
+ import { resolveWorkerConfig } from "../src/config.js";
4
+ import { startWorkerClient } from "../src/client.js";
5
+
6
+ async function main() {
7
+ try {
8
+ const config = await resolveWorkerConfig();
9
+ await startWorkerClient(config);
10
+ } catch (err) {
11
+ console.error("Fatal Worker Error:", err);
12
+ process.exit(1);
13
+ }
14
+ }
15
+
16
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app-manager-edge-worker",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "Distributed Scraper Edge Worker for Apps Manager. Run on any local machine, VPS, or Termux Android device to serve browser and HTTP scraping jobs.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,9 @@
8
8
  "apps-manager-worker": "bin/worker.js"
9
9
  },
10
10
  "main": "./src/client.js",
11
+ "scripts": {
12
+ "start": "node ./bin/worker.js"
13
+ },
11
14
  "keywords": [
12
15
  "app-manager-edge-worker",
13
16
  "apps-manager",
@@ -42,8 +45,5 @@
42
45
  "puppeteer-extra-plugin-stealth": "^2.11.2",
43
46
  "qrcode": "^1.5.4",
44
47
  "socket.io-client": "^4.8.1"
45
- },
46
- "scripts": {
47
- "start": "node ./bin/worker.js"
48
48
  }
49
- }
49
+ }
package/src/banner.js CHANGED
@@ -1,80 +1,80 @@
1
- import { createRequire } from "module";
2
-
3
- const require = createRequire(import.meta.url);
4
- let workerVersion = "1.1.0";
5
- try {
6
- const pkg = require("../package.json");
7
- if (pkg?.version) workerVersion = pkg.version;
8
- } catch (_) { }
9
-
10
- // ANSI color helpers
11
- const colors = {
12
- reset: "\x1b[0m",
13
- bright: "\x1b[1m",
14
- dim: "\x1b[2m",
15
- cyan: "\x1b[36m",
16
- green: "\x1b[32m",
17
- yellow: "\x1b[33m",
18
- red: "\x1b[31m",
19
- magenta: "\x1b[35m",
20
- gray: "\x1b[90m",
21
- };
22
-
23
- /**
24
- * Returns a formatted timestamp string using the device's local time: [YYYY-MM-DD HH:mm:ss]
25
- */
26
- function timestamp() {
27
- const now = new Date();
28
- const pad = (n) => String(n).padStart(2, "0");
29
- const year = now.getFullYear();
30
- const month = pad(now.getMonth() + 1);
31
- const day = pad(now.getDate());
32
- const hours = pad(now.getHours());
33
- const minutes = pad(now.getMinutes());
34
- const seconds = pad(now.getSeconds());
35
- return `${colors.gray}[${year}-${month}-${day} ${hours}:${minutes}:${seconds}]${colors.reset}`;
36
- }
37
-
38
- export function printBanner({ workerName, serverUrl, concurrency, platform, isTermux, keepAliveMinutes }) {
39
- console.clear();
40
- console.log(`${colors.cyan}${colors.bright}`);
41
- console.log(" █████╗ ██████╗ ██████╗ ███████╗ ███╗ ███╗ █████╗ ███╗ ██╗ █████╗ ██████╗ ███████╗██████╗ ");
42
- console.log(" ██╔══██╗██╔══██╗██╔══██╗██╔════╝ ████╗ ████║██╔══██╗████╗ ██║██╔══██╗██╔════╝ ██╔════╝██╔══██╗");
43
- console.log(" ███████║██████╔╝██████╔╝███████╗ ██╔████╔██║███████║██╔██╗ ██║███████║██║ ███╗█████╗ ██████╔╝");
44
- console.log(" ██╔══██║██╔═══╝ ██╔═══╝ ╚════██║ ██║╚██╔╝██║██╔══██║██║╚██╗██║██╔══██║██║ ██║██╔══╝ ██╔══██╗");
45
- console.log(" ██║ ██║██║ ██║ ███████║██╗██║ ╚═╝ ██║██║ ██║██║ ╚████║██║ ██║╚██████╔╝███████╗██║ ██║");
46
- console.log(" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝");
47
- console.log(`${colors.reset}`);
48
- console.log(`${colors.bright} 🌐 Distributed Scraper Edge Worker Client v${workerVersion}${colors.reset}`);
49
- console.log(`${colors.dim} Zero-cost, persistent tunneling & residential edge scraping${colors.reset}`);
50
- console.log("--------------------------------------------------------------------------------");
51
- console.log(` ${colors.bright}Device Name :${colors.reset} ${colors.green}${workerName}${colors.reset}`);
52
- console.log(` ${colors.bright}Server URL :${colors.reset} ${colors.cyan}${serverUrl}${colors.reset}`);
53
- console.log(` ${colors.bright}Concurrency :${colors.reset} ${colors.yellow}${concurrency} concurrent tabs${colors.reset}`);
54
- console.log(` ${colors.bright}Environment :${colors.reset} ${platform} ${isTermux ? "(Termux Android)" : ""}`);
55
- console.log(` ${colors.bright}Keep-Alive :${colors.reset} ${keepAliveMinutes > 0 ? `${colors.green}Every ${keepAliveMinutes}m (Render Anti-Sleep Active)${colors.reset}` : `${colors.gray}Disabled${colors.reset}`}`);
56
- console.log("--------------------------------------------------------------------------------\n");
57
- }
58
-
59
- export function logInfo(msg) {
60
- console.log(`${timestamp()} ${colors.cyan}[INFO]${colors.reset} ${msg}`);
61
- }
62
-
63
- export function logSuccess(msg) {
64
- console.log(`${timestamp()} ${colors.green}[SUCCESS]${colors.reset} ${msg}`);
65
- }
66
-
67
- export function logWarn(msg) {
68
- console.log(`${timestamp()} ${colors.yellow}[WARN]${colors.reset} ${msg}`);
69
- }
70
-
71
- export function logError(msg) {
72
- console.log(`${timestamp()} ${colors.red}[ERROR]${colors.reset} ${msg}`);
73
- }
74
-
75
- export function logJob(jobType, url, durationMs = null) {
76
- const timeStr = durationMs ? ` ${colors.gray}(${durationMs}ms)${colors.reset}` : "";
77
- console.log(
78
- `${timestamp()} ${colors.magenta}[TASK]${colors.reset} ${colors.bright}${jobType}${colors.reset} -> ${url}${timeStr}`
79
- );
80
- }
1
+ import { createRequire } from "module";
2
+
3
+ const require = createRequire(import.meta.url);
4
+ let workerVersion = "1.1.0";
5
+ try {
6
+ const pkg = require("../package.json");
7
+ if (pkg?.version) workerVersion = pkg.version;
8
+ } catch (_) { }
9
+
10
+ // ANSI color helpers
11
+ const colors = {
12
+ reset: "\x1b[0m",
13
+ bright: "\x1b[1m",
14
+ dim: "\x1b[2m",
15
+ cyan: "\x1b[36m",
16
+ green: "\x1b[32m",
17
+ yellow: "\x1b[33m",
18
+ red: "\x1b[31m",
19
+ magenta: "\x1b[35m",
20
+ gray: "\x1b[90m",
21
+ };
22
+
23
+ /**
24
+ * Returns a formatted timestamp string using the device's local time: [YYYY-MM-DD HH:mm:ss]
25
+ */
26
+ function timestamp() {
27
+ const now = new Date();
28
+ const pad = (n) => String(n).padStart(2, "0");
29
+ const year = now.getFullYear();
30
+ const month = pad(now.getMonth() + 1);
31
+ const day = pad(now.getDate());
32
+ const hours = pad(now.getHours());
33
+ const minutes = pad(now.getMinutes());
34
+ const seconds = pad(now.getSeconds());
35
+ return `${colors.gray}[${year}-${month}-${day} ${hours}:${minutes}:${seconds}]${colors.reset}`;
36
+ }
37
+
38
+ export function printBanner({ workerName, serverUrl, concurrency, platform, isTermux, keepAliveMinutes }) {
39
+ console.clear();
40
+ console.log(`${colors.cyan}${colors.bright}`);
41
+ console.log(" █████╗ ██████╗ ██████╗ ███████╗ ███╗ ███╗ █████╗ ███╗ ██╗ █████╗ ██████╗ ███████╗██████╗ ");
42
+ console.log(" ██╔══██╗██╔══██╗██╔══██╗██╔════╝ ████╗ ████║██╔══██╗████╗ ██║██╔══██╗██╔════╝ ██╔════╝██╔══██╗");
43
+ console.log(" ███████║██████╔╝██████╔╝███████╗ ██╔████╔██║███████║██╔██╗ ██║███████║██║ ███╗█████╗ ██████╔╝");
44
+ console.log(" ██╔══██║██╔═══╝ ██╔═══╝ ╚════██║ ██║╚██╔╝██║██╔══██║██║╚██╗██║██╔══██║██║ ██║██╔══╝ ██╔══██╗");
45
+ console.log(" ██║ ██║██║ ██║ ███████║██╗██║ ╚═╝ ██║██║ ██║██║ ╚████║██║ ██║╚██████╔╝███████╗██║ ██║");
46
+ console.log(" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝");
47
+ console.log(`${colors.reset}`);
48
+ console.log(`${colors.bright} 🌐 Distributed Scraper Edge Worker Client v${workerVersion}${colors.reset}`);
49
+ console.log(`${colors.dim} Zero-cost, persistent tunneling & residential edge scraping${colors.reset}`);
50
+ console.log("--------------------------------------------------------------------------------");
51
+ console.log(` ${colors.bright}Device Name :${colors.reset} ${colors.green}${workerName}${colors.reset}`);
52
+ console.log(` ${colors.bright}Server URL :${colors.reset} ${colors.cyan}${serverUrl}${colors.reset}`);
53
+ console.log(` ${colors.bright}Concurrency :${colors.reset} ${colors.yellow}${concurrency} concurrent tabs${colors.reset}`);
54
+ console.log(` ${colors.bright}Environment :${colors.reset} ${platform} ${isTermux ? "(Termux Android)" : ""}`);
55
+ console.log(` ${colors.bright}Keep-Alive :${colors.reset} ${keepAliveMinutes > 0 ? `${colors.green}Every ${keepAliveMinutes}m (Render Anti-Sleep Active)${colors.reset}` : `${colors.gray}Disabled${colors.reset}`}`);
56
+ console.log("--------------------------------------------------------------------------------\n");
57
+ }
58
+
59
+ export function logInfo(msg) {
60
+ console.log(`${timestamp()} ${colors.cyan}[INFO]${colors.reset} ${msg}`);
61
+ }
62
+
63
+ export function logSuccess(msg) {
64
+ console.log(`${timestamp()} ${colors.green}[SUCCESS]${colors.reset} ${msg}`);
65
+ }
66
+
67
+ export function logWarn(msg) {
68
+ console.log(`${timestamp()} ${colors.yellow}[WARN]${colors.reset} ${msg}`);
69
+ }
70
+
71
+ export function logError(msg) {
72
+ console.log(`${timestamp()} ${colors.red}[ERROR]${colors.reset} ${msg}`);
73
+ }
74
+
75
+ export function logJob(jobType, url, durationMs = null) {
76
+ const timeStr = durationMs ? ` ${colors.gray}(${durationMs}ms)${colors.reset}` : "";
77
+ console.log(
78
+ `${timestamp()} ${colors.magenta}[TASK]${colors.reset} ${colors.bright}${jobType}${colors.reset} -> ${url}${timeStr}`
79
+ );
80
+ }