web-agent-bridge 1.1.2 → 2.0.0

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.
Files changed (94) hide show
  1. package/LICENSE +21 -21
  2. package/README.ar.md +446 -446
  3. package/README.md +780 -844
  4. package/bin/cli.js +80 -80
  5. package/bin/wab.js +80 -80
  6. package/examples/bidi-agent.js +119 -119
  7. package/examples/mcp-agent.js +94 -94
  8. package/examples/next-app-router/README.md +44 -0
  9. package/examples/puppeteer-agent.js +108 -108
  10. package/examples/saas-dashboard/README.md +55 -0
  11. package/examples/shopify-hydrogen/README.md +74 -0
  12. package/examples/vision-agent.js +171 -171
  13. package/examples/wordpress-elementor/README.md +77 -0
  14. package/package.json +69 -78
  15. package/public/.well-known/ai-assets.json +59 -0
  16. package/public/admin/login.html +84 -84
  17. package/public/ai.html +196 -0
  18. package/public/cookies.html +208 -208
  19. package/public/css/premium.css +317 -0
  20. package/public/css/styles.css +1235 -1235
  21. package/public/dashboard.html +704 -704
  22. package/public/demo.html +259 -0
  23. package/public/docs.html +585 -585
  24. package/public/feed.xml +89 -0
  25. package/public/index.html +495 -332
  26. package/public/js/auth-nav.js +31 -31
  27. package/public/js/auth-redirect.js +12 -12
  28. package/public/js/cookie-consent.js +56 -56
  29. package/public/js/wab-demo-page.js +721 -0
  30. package/public/js/ws-client.js +74 -74
  31. package/public/llms-full.txt +309 -0
  32. package/public/llms.txt +85 -0
  33. package/public/login.html +83 -83
  34. package/public/openapi.json +580 -0
  35. package/public/premium-dashboard.html +2487 -0
  36. package/public/premium.html +791 -0
  37. package/public/privacy.html +295 -295
  38. package/public/register.html +103 -103
  39. package/public/robots.txt +87 -0
  40. package/public/script/wab-consent.d.ts +36 -0
  41. package/public/script/wab-consent.js +104 -0
  42. package/public/script/wab-schema.js +131 -0
  43. package/public/script/wab.d.ts +108 -0
  44. package/public/script/wab.min.js +234 -0
  45. package/public/sitemap.xml +93 -0
  46. package/public/terms.html +254 -254
  47. package/public/video/tutorial.mp4 +0 -0
  48. package/script/ai-agent-bridge.js +1558 -1513
  49. package/sdk/README.md +55 -55
  50. package/sdk/index.d.ts +118 -0
  51. package/sdk/index.js +257 -203
  52. package/sdk/package.json +14 -14
  53. package/sdk/schema-discovery.js +83 -0
  54. package/server/config/secrets.js +94 -92
  55. package/server/index.js +0 -9
  56. package/server/middleware/adminAuth.js +30 -30
  57. package/server/middleware/auth.js +41 -41
  58. package/server/middleware/rateLimits.js +24 -24
  59. package/server/migrations/001_add_analytics_indexes.sql +7 -7
  60. package/server/migrations/002_premium_features.sql +418 -0
  61. package/server/models/adapters/index.js +33 -33
  62. package/server/models/adapters/mysql.js +183 -183
  63. package/server/models/adapters/postgresql.js +172 -172
  64. package/server/models/adapters/sqlite.js +7 -7
  65. package/server/models/db.js +561 -561
  66. package/server/routes/admin-premium.js +671 -0
  67. package/server/routes/admin.js +247 -247
  68. package/server/routes/api.js +131 -138
  69. package/server/routes/auth.js +51 -51
  70. package/server/routes/billing.js +45 -45
  71. package/server/routes/discovery.js +406 -329
  72. package/server/routes/license.js +240 -240
  73. package/server/routes/noscript.js +543 -543
  74. package/server/routes/premium-v2.js +686 -0
  75. package/server/routes/premium.js +724 -0
  76. package/server/routes/wab-api.js +476 -476
  77. package/server/services/agent-memory.js +625 -0
  78. package/server/services/email.js +204 -204
  79. package/server/services/fairness.js +420 -420
  80. package/server/services/plugins.js +747 -0
  81. package/server/services/premium.js +1883 -0
  82. package/server/services/self-healing.js +843 -0
  83. package/server/services/stripe.js +192 -192
  84. package/server/services/swarm.js +788 -0
  85. package/server/services/vision.js +871 -0
  86. package/server/utils/cache.js +125 -125
  87. package/server/utils/migrate.js +81 -81
  88. package/server/utils/secureFields.js +50 -50
  89. package/server/ws.js +101 -101
  90. package/docs/DEPLOY.md +0 -118
  91. package/docs/SPEC.md +0 -1540
  92. package/wab-mcp-adapter/README.md +0 -136
  93. package/wab-mcp-adapter/index.js +0 -555
  94. package/wab-mcp-adapter/package.json +0 -17
package/server/ws.js CHANGED
@@ -1,101 +1,101 @@
1
- const WebSocket = require('ws');
2
- const { verifyUserToken, verifyAdminToken } = require('./config/secrets');
3
- const { findSiteById } = require('./models/db');
4
-
5
- // Map of siteId → Set of WebSocket clients
6
- const siteClients = new Map();
7
-
8
- function setupWebSocket(server) {
9
- const wss = new WebSocket.Server({ server, path: '/ws/analytics' });
10
-
11
- wss.on('connection', (ws, req) => {
12
- let authenticatedSiteId = null;
13
-
14
- ws.isAlive = true;
15
- ws.on('pong', () => { ws.isAlive = true; });
16
-
17
- ws.on('message', (data) => {
18
- try {
19
- const msg = JSON.parse(data);
20
-
21
- if (msg.type === 'auth') {
22
- if (!msg.token || !msg.siteId) {
23
- ws.send(JSON.stringify({ type: 'error', message: 'token and siteId required' }));
24
- return;
25
- }
26
-
27
- let decoded;
28
- let isAdmin = false;
29
- try {
30
- decoded = verifyUserToken(msg.token);
31
- } catch {
32
- try {
33
- decoded = verifyAdminToken(msg.token);
34
- isAdmin = decoded.isAdmin === true;
35
- } catch {
36
- ws.send(JSON.stringify({ type: 'error', message: 'Invalid message or auth failed' }));
37
- return;
38
- }
39
- }
40
-
41
- if (!isAdmin) {
42
- const site = findSiteById.get(msg.siteId);
43
- if (!site || site.user_id !== decoded.id) {
44
- ws.send(JSON.stringify({ type: 'error', message: 'Forbidden: not your site' }));
45
- return;
46
- }
47
- }
48
-
49
- authenticatedSiteId = msg.siteId;
50
- if (!siteClients.has(msg.siteId)) {
51
- siteClients.set(msg.siteId, new Set());
52
- }
53
- siteClients.get(msg.siteId).add(ws);
54
- ws.send(JSON.stringify({ type: 'auth:success', siteId: msg.siteId }));
55
- }
56
- } catch (e) {
57
- ws.send(JSON.stringify({ type: 'error', message: 'Invalid message or auth failed' }));
58
- }
59
- });
60
-
61
- ws.on('close', () => {
62
- if (authenticatedSiteId && siteClients.has(authenticatedSiteId)) {
63
- siteClients.get(authenticatedSiteId).delete(ws);
64
- if (siteClients.get(authenticatedSiteId).size === 0) {
65
- siteClients.delete(authenticatedSiteId);
66
- }
67
- }
68
- });
69
- });
70
-
71
- const interval = setInterval(() => {
72
- wss.clients.forEach((ws) => {
73
- if (!ws.isAlive) return ws.terminate();
74
- ws.isAlive = false;
75
- ws.ping();
76
- });
77
- }, 30000);
78
-
79
- wss.on('close', () => clearInterval(interval));
80
-
81
- return wss;
82
- }
83
-
84
- function broadcastAnalytic(siteId, eventData) {
85
- const clients = siteClients.get(siteId);
86
- if (!clients || clients.size === 0) return;
87
-
88
- const message = JSON.stringify({
89
- type: 'analytic',
90
- timestamp: new Date().toISOString(),
91
- ...eventData
92
- });
93
-
94
- clients.forEach((ws) => {
95
- if (ws.readyState === WebSocket.OPEN) {
96
- ws.send(message);
97
- }
98
- });
99
- }
100
-
101
- module.exports = { setupWebSocket, broadcastAnalytic };
1
+ const WebSocket = require('ws');
2
+ const { verifyUserToken, verifyAdminToken } = require('./config/secrets');
3
+ const { findSiteById } = require('./models/db');
4
+
5
+ // Map of siteId → Set of WebSocket clients
6
+ const siteClients = new Map();
7
+
8
+ function setupWebSocket(server) {
9
+ const wss = new WebSocket.Server({ server, path: '/ws/analytics' });
10
+
11
+ wss.on('connection', (ws, req) => {
12
+ let authenticatedSiteId = null;
13
+
14
+ ws.isAlive = true;
15
+ ws.on('pong', () => { ws.isAlive = true; });
16
+
17
+ ws.on('message', (data) => {
18
+ try {
19
+ const msg = JSON.parse(data);
20
+
21
+ if (msg.type === 'auth') {
22
+ if (!msg.token || !msg.siteId) {
23
+ ws.send(JSON.stringify({ type: 'error', message: 'token and siteId required' }));
24
+ return;
25
+ }
26
+
27
+ let decoded;
28
+ let isAdmin = false;
29
+ try {
30
+ decoded = verifyUserToken(msg.token);
31
+ } catch {
32
+ try {
33
+ decoded = verifyAdminToken(msg.token);
34
+ isAdmin = decoded.isAdmin === true;
35
+ } catch {
36
+ ws.send(JSON.stringify({ type: 'error', message: 'Invalid message or auth failed' }));
37
+ return;
38
+ }
39
+ }
40
+
41
+ if (!isAdmin) {
42
+ const site = findSiteById.get(msg.siteId);
43
+ if (!site || site.user_id !== decoded.id) {
44
+ ws.send(JSON.stringify({ type: 'error', message: 'Forbidden: not your site' }));
45
+ return;
46
+ }
47
+ }
48
+
49
+ authenticatedSiteId = msg.siteId;
50
+ if (!siteClients.has(msg.siteId)) {
51
+ siteClients.set(msg.siteId, new Set());
52
+ }
53
+ siteClients.get(msg.siteId).add(ws);
54
+ ws.send(JSON.stringify({ type: 'auth:success', siteId: msg.siteId }));
55
+ }
56
+ } catch (e) {
57
+ ws.send(JSON.stringify({ type: 'error', message: 'Invalid message or auth failed' }));
58
+ }
59
+ });
60
+
61
+ ws.on('close', () => {
62
+ if (authenticatedSiteId && siteClients.has(authenticatedSiteId)) {
63
+ siteClients.get(authenticatedSiteId).delete(ws);
64
+ if (siteClients.get(authenticatedSiteId).size === 0) {
65
+ siteClients.delete(authenticatedSiteId);
66
+ }
67
+ }
68
+ });
69
+ });
70
+
71
+ const interval = setInterval(() => {
72
+ wss.clients.forEach((ws) => {
73
+ if (!ws.isAlive) return ws.terminate();
74
+ ws.isAlive = false;
75
+ ws.ping();
76
+ });
77
+ }, 30000);
78
+
79
+ wss.on('close', () => clearInterval(interval));
80
+
81
+ return wss;
82
+ }
83
+
84
+ function broadcastAnalytic(siteId, eventData) {
85
+ const clients = siteClients.get(siteId);
86
+ if (!clients || clients.size === 0) return;
87
+
88
+ const message = JSON.stringify({
89
+ type: 'analytic',
90
+ timestamp: new Date().toISOString(),
91
+ ...eventData
92
+ });
93
+
94
+ clients.forEach((ws) => {
95
+ if (ws.readyState === WebSocket.OPEN) {
96
+ ws.send(message);
97
+ }
98
+ });
99
+ }
100
+
101
+ module.exports = { setupWebSocket, broadcastAnalytic };
package/docs/DEPLOY.md DELETED
@@ -1,118 +0,0 @@
1
- # Deploying Web Agent Bridge to your server
2
-
3
- The code is on GitHub (`master`). **You** deploy by SSH-ing into your VPS and pulling + restarting the app.
4
-
5
- ## Prerequisites
6
-
7
- - Ubuntu/Debian (or similar) with Docker **or** Node.js 20+
8
- - Firewall: open port **3000** (or your reverse proxy port 80/443)
9
- - Strong `JWT_SECRET` and `JWT_SECRET_ADMIN` in production (never commit them)
10
-
11
- ---
12
-
13
- ## Option A — Docker Compose (recommended)
14
-
15
- On the server, first time:
16
-
17
- ```bash
18
- cd /opt # or your preferred path
19
- git clone https://github.com/abokenan444/web-agent-bridge.git
20
- cd web-agent-bridge
21
- cp .env.example .env # if present; else create .env with secrets and PORT
22
- # Edit .env: JWT_SECRET=... JWT_SECRET_ADMIN=... PORT=3000
23
- docker compose up -d --build
24
- ```
25
-
26
- Updates:
27
-
28
- ```bash
29
- cd /path/to/web-agent-bridge
30
- git pull origin master
31
- docker compose up -d --build
32
- ```
33
-
34
- Data persists in the Docker volume `wab-data` (SQLite under `/app/data` in the container).
35
-
36
- ---
37
-
38
- ## Option B — Node.js (no Docker)
39
-
40
- ```bash
41
- cd /path/to/web-agent-bridge
42
- git pull origin master
43
- npm ci --production
44
- export NODE_ENV=production
45
- export JWT_SECRET="your-long-random-secret"
46
- export JWT_SECRET_ADMIN="your-different-long-random-secret"
47
- export PORT=3000
48
- node server/index.js
49
- ```
50
-
51
- Use **systemd**, **PM2**, or **screen/tmux** to keep the process running.
52
-
53
- Example **PM2**:
54
-
55
- ```bash
56
- npm ci --production
57
- pm2 start server/index.js --name wab
58
- pm2 save
59
- ```
60
-
61
- After `git pull`:
62
-
63
- ```bash
64
- npm ci --production
65
- pm2 restart wab
66
- ```
67
-
68
- ---
69
-
70
- ## Reverse proxy (HTTPS)
71
-
72
- Put **Nginx** or **Caddy** in front of `127.0.0.1:3000` and obtain TLS certificates (Let’s Encrypt).
73
-
74
- Example Nginx location:
75
-
76
- ```nginx
77
- location / {
78
- proxy_pass http://127.0.0.1:3000;
79
- proxy_http_version 1.1;
80
- proxy_set_header Host $host;
81
- proxy_set_header X-Real-IP $remote_addr;
82
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
83
- proxy_set_header X-Forwarded-Proto $scheme;
84
- }
85
- ```
86
-
87
- ---
88
-
89
- ## WordPress plugin
90
-
91
- Upload `web-agent-bridge-wordpress/` to the WordPress server (`wp-content/plugins/`) or sync via SFTP/rsync. Point **WAB API base URL** to your public URL (e.g. `https://wab.example.com`).
92
-
93
- ---
94
-
95
- ## Why we do **not** recommend auto-deploy from this public repo
96
-
97
- This project is **open source**. Wiring GitHub Actions (or similar) so that every push to `main`/`master` deploys to your production server is **high risk**:
98
-
99
- | Risk | Why it matters |
100
- |------|----------------|
101
- | **Supply chain** | Anyone who can merge code (or bypass reviews) can change what runs on your server. |
102
- | **Fork / PR abuse** | CI that builds untrusted PRs with secrets in scope has led to credential theft. |
103
- | **Secret leakage** | Deploy keys and SSH keys in CI are juicy targets; misconfiguration exposes them in logs or artifacts. |
104
- | **Public visibility** | Attackers see your pipeline definition and know exactly how prod is updated. |
105
-
106
- **Recommended for operators:** deploy **manually** after you review changes (SSH → `git pull` → rebuild), or use a **private** deployment path (e.g. internal CI, private mirror, or release artifacts you promote by hand).
107
-
108
- **If you must automate** (enterprise, private fork only): use a **private** repo or private runners, **branch protection**, required reviews, **deploy only from signed tags** or approved releases—not raw `main`—and never store production SSH keys in workflows reachable from public PR builds.
109
-
110
- This repository intentionally does **not** ship a “deploy to production on push” workflow.
111
-
112
- ---
113
-
114
- ## Checklist after deploy
115
-
116
- - [ ] `curl -s https://your-domain/api/license/verify` returns JSON (POST with body) or app responds on `/`
117
- - [ ] `https://your-domain/script/ai-agent-bridge.js` loads
118
- - [ ] `.env` / `JWT_SECRET` / `JWT_SECRET_ADMIN` not exposed in git