web-agent-bridge 3.2.0 → 3.4.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 (256) hide show
  1. package/LICENSE +84 -72
  2. package/README.ar.md +1304 -1152
  3. package/README.md +298 -1635
  4. package/bin/agent-runner.js +474 -474
  5. package/bin/cli.js +237 -138
  6. package/bin/wab-init.js +223 -0
  7. package/bin/wab.js +80 -80
  8. package/examples/azure-dns-wab.js +83 -0
  9. package/examples/bidi-agent.js +119 -119
  10. package/examples/cloudflare-wab-dns.js +121 -0
  11. package/examples/cpanel-wab-dns.js +114 -0
  12. package/examples/cross-site-agent.js +91 -91
  13. package/examples/dns-discovery-agent.js +166 -0
  14. package/examples/gcp-dns-wab.js +76 -0
  15. package/examples/governance-agent.js +169 -0
  16. package/examples/mcp-agent.js +94 -94
  17. package/examples/next-app-router/README.md +44 -44
  18. package/examples/plesk-wab-dns.js +103 -0
  19. package/examples/puppeteer-agent.js +108 -108
  20. package/examples/route53-wab-dns.js +144 -0
  21. package/examples/saas-dashboard/README.md +55 -55
  22. package/examples/safe-mode-agent.js +96 -0
  23. package/examples/shopify-hydrogen/README.md +74 -74
  24. package/examples/vision-agent.js +171 -171
  25. package/examples/wab-sign.js +74 -0
  26. package/examples/wab-verify.js +60 -0
  27. package/examples/wordpress-elementor/README.md +77 -77
  28. package/package.json +19 -6
  29. package/public/.well-known/agent-tools.json +180 -180
  30. package/public/.well-known/ai-assets.json +59 -59
  31. package/public/.well-known/security.txt +8 -0
  32. package/public/.well-known/wab.json +28 -0
  33. package/public/activate.html +368 -0
  34. package/public/adoption-metrics.html +188 -0
  35. package/public/agent-workspace.html +349 -349
  36. package/public/ai.html +198 -198
  37. package/public/api.html +413 -412
  38. package/public/azure-dns-integration.html +289 -0
  39. package/public/browser.html +486 -486
  40. package/public/cloudflare-integration.html +380 -0
  41. package/public/commander-dashboard.html +243 -243
  42. package/public/cookies.html +210 -210
  43. package/public/cpanel-integration.html +398 -0
  44. package/public/css/agent-workspace.css +1713 -1713
  45. package/public/css/premium.css +317 -317
  46. package/public/css/styles.css +1263 -1235
  47. package/public/dashboard.html +707 -706
  48. package/public/dns.html +436 -0
  49. package/public/docs.html +588 -587
  50. package/public/feed.xml +89 -89
  51. package/public/gcp-dns-integration.html +318 -0
  52. package/public/growth.html +465 -463
  53. package/public/index.html +1266 -982
  54. package/public/integrations.html +556 -0
  55. package/public/js/activate.js +145 -0
  56. package/public/js/agent-workspace.js +1740 -1740
  57. package/public/js/auth-nav.js +65 -31
  58. package/public/js/auth-redirect.js +12 -12
  59. package/public/js/cookie-consent.js +56 -56
  60. package/public/js/dns.js +438 -0
  61. package/public/js/wab-demo-page.js +721 -721
  62. package/public/js/ws-client.js +74 -74
  63. package/public/llms-full.txt +360 -360
  64. package/public/llms.txt +125 -125
  65. package/public/login.html +85 -85
  66. package/public/mesh-dashboard.html +328 -328
  67. package/public/openapi.json +669 -580
  68. package/public/phone-shield.html +281 -0
  69. package/public/plesk-integration.html +375 -0
  70. package/public/premium-dashboard.html +2489 -2489
  71. package/public/premium.html +793 -793
  72. package/public/privacy.html +297 -297
  73. package/public/provider-onboarding.html +172 -0
  74. package/public/provider-sandbox.html +134 -0
  75. package/public/providers.html +359 -0
  76. package/public/register.html +105 -105
  77. package/public/registrar-integrations.html +141 -0
  78. package/public/robots.txt +99 -87
  79. package/public/route53-integration.html +531 -0
  80. package/public/script/wab-consent.d.ts +36 -36
  81. package/public/script/wab-consent.js +104 -104
  82. package/public/script/wab-schema.js +131 -131
  83. package/public/script/wab.d.ts +108 -108
  84. package/public/script/wab.min.js +580 -580
  85. package/public/security.txt +8 -0
  86. package/public/shieldqr.html +231 -0
  87. package/public/sitemap.xml +6 -0
  88. package/public/terms.html +256 -256
  89. package/public/wab-trust.html +200 -0
  90. package/public/wab-vs-protocols.html +210 -0
  91. package/public/whitepaper.html +449 -0
  92. package/script/ai-agent-bridge.js +1754 -1754
  93. package/sdk/README.md +99 -99
  94. package/sdk/agent-mesh.js +449 -449
  95. package/sdk/auto-discovery.js +288 -0
  96. package/sdk/commander.js +262 -262
  97. package/sdk/governance.js +262 -0
  98. package/sdk/index.d.ts +464 -464
  99. package/sdk/index.js +25 -1
  100. package/sdk/multi-agent.js +318 -318
  101. package/sdk/package.json +2 -2
  102. package/sdk/safe-mode.js +221 -0
  103. package/sdk/safety-shield.js +219 -0
  104. package/sdk/schema-discovery.js +83 -83
  105. package/server/adapters/index.js +520 -520
  106. package/server/config/plans.js +367 -367
  107. package/server/config/secrets.js +102 -102
  108. package/server/control-plane/index.js +301 -301
  109. package/server/data-plane/index.js +354 -354
  110. package/server/index.js +670 -427
  111. package/server/llm/index.js +404 -404
  112. package/server/middleware/adminAuth.js +35 -35
  113. package/server/middleware/auth.js +50 -50
  114. package/server/middleware/featureGate.js +88 -88
  115. package/server/middleware/rateLimits.js +100 -100
  116. package/server/middleware/sensitiveAction.js +157 -0
  117. package/server/migrations/001_add_analytics_indexes.sql +7 -7
  118. package/server/migrations/002_premium_features.sql +418 -418
  119. package/server/migrations/003_ads_integer_cents.sql +33 -33
  120. package/server/migrations/004_agent_os.sql +158 -158
  121. package/server/migrations/005_marketplace_metering.sql +126 -126
  122. package/server/migrations/007_governance.sql +106 -0
  123. package/server/migrations/008_plans.sql +144 -0
  124. package/server/migrations/009_shieldqr.sql +30 -0
  125. package/server/migrations/010_extended_trust.sql +33 -0
  126. package/server/models/adapters/index.js +33 -33
  127. package/server/models/adapters/mysql.js +183 -183
  128. package/server/models/adapters/postgresql.js +172 -172
  129. package/server/models/adapters/sqlite.js +7 -7
  130. package/server/models/db.js +740 -681
  131. package/server/observability/failure-analysis.js +337 -337
  132. package/server/observability/index.js +394 -394
  133. package/server/protocol/capabilities.js +223 -223
  134. package/server/protocol/index.js +243 -243
  135. package/server/protocol/schema.js +584 -584
  136. package/server/registry/certification.js +271 -271
  137. package/server/registry/index.js +326 -326
  138. package/server/routes/admin-plans.js +76 -0
  139. package/server/routes/admin-premium.js +673 -671
  140. package/server/routes/admin-shieldqr.js +90 -0
  141. package/server/routes/admin-trust-monitor.js +83 -0
  142. package/server/routes/admin.js +549 -261
  143. package/server/routes/ads.js +130 -130
  144. package/server/routes/agent-workspace.js +540 -540
  145. package/server/routes/api.js +150 -150
  146. package/server/routes/auth.js +71 -71
  147. package/server/routes/billing.js +57 -45
  148. package/server/routes/commander.js +316 -316
  149. package/server/routes/demo-showcase.js +332 -332
  150. package/server/routes/demo-store.js +154 -0
  151. package/server/routes/discovery.js +2348 -417
  152. package/server/routes/gateway.js +173 -157
  153. package/server/routes/governance.js +208 -0
  154. package/server/routes/license.js +251 -240
  155. package/server/routes/mesh.js +469 -469
  156. package/server/routes/noscript.js +543 -543
  157. package/server/routes/plans.js +33 -0
  158. package/server/routes/premium-v2.js +686 -686
  159. package/server/routes/premium.js +724 -724
  160. package/server/routes/providers.js +650 -0
  161. package/server/routes/runtime.js +2148 -2147
  162. package/server/routes/shieldqr.js +88 -0
  163. package/server/routes/sovereign.js +465 -385
  164. package/server/routes/universal.js +200 -185
  165. package/server/routes/wab-api.js +850 -501
  166. package/server/runtime/container-worker.js +111 -111
  167. package/server/runtime/container.js +448 -448
  168. package/server/runtime/distributed-worker.js +362 -362
  169. package/server/runtime/event-bus.js +210 -210
  170. package/server/runtime/index.js +253 -253
  171. package/server/runtime/queue.js +599 -599
  172. package/server/runtime/replay.js +666 -666
  173. package/server/runtime/sandbox.js +266 -266
  174. package/server/runtime/scheduler.js +534 -534
  175. package/server/runtime/session-engine.js +293 -293
  176. package/server/runtime/state-manager.js +188 -188
  177. package/server/security/cross-site-redactor.js +196 -0
  178. package/server/security/dry-run.js +180 -0
  179. package/server/security/human-gate-rate-limit.js +147 -0
  180. package/server/security/human-gate-transports.js +178 -0
  181. package/server/security/human-gate.js +281 -0
  182. package/server/security/index.js +368 -368
  183. package/server/security/intent-engine.js +245 -0
  184. package/server/security/reward-guard.js +171 -0
  185. package/server/security/rollback-store.js +239 -0
  186. package/server/security/token-scope.js +404 -0
  187. package/server/security/url-policy.js +139 -0
  188. package/server/services/agent-chat.js +506 -506
  189. package/server/services/agent-learning.js +601 -575
  190. package/server/services/agent-memory.js +625 -625
  191. package/server/services/agent-mesh.js +555 -539
  192. package/server/services/agent-symphony.js +717 -717
  193. package/server/services/agent-tasks.js +1807 -1807
  194. package/server/services/api-key-engine.js +292 -261
  195. package/server/services/cluster.js +894 -894
  196. package/server/services/commander.js +738 -738
  197. package/server/services/edge-compute.js +440 -440
  198. package/server/services/email.js +233 -204
  199. package/server/services/governance.js +466 -0
  200. package/server/services/hosted-runtime.js +205 -205
  201. package/server/services/lfd.js +635 -635
  202. package/server/services/local-ai.js +389 -389
  203. package/server/services/marketplace.js +270 -270
  204. package/server/services/metering.js +182 -182
  205. package/server/services/modules/affiliate-intelligence.js +93 -93
  206. package/server/services/modules/agent-firewall.js +90 -90
  207. package/server/services/modules/bounty.js +89 -89
  208. package/server/services/modules/collective-bargaining.js +92 -92
  209. package/server/services/modules/dark-pattern.js +66 -66
  210. package/server/services/modules/gov-intelligence.js +45 -45
  211. package/server/services/modules/neural.js +55 -55
  212. package/server/services/modules/notary.js +49 -49
  213. package/server/services/modules/price-time-machine.js +86 -86
  214. package/server/services/modules/protocol.js +104 -104
  215. package/server/services/negotiation.js +439 -439
  216. package/server/services/plans.js +214 -0
  217. package/server/services/plugins.js +771 -771
  218. package/server/services/premium.js +1 -1
  219. package/server/services/price-intelligence.js +566 -566
  220. package/server/services/price-shield.js +1137 -1137
  221. package/server/services/provider-clients.js +740 -0
  222. package/server/services/reputation.js +465 -465
  223. package/server/services/search-engine.js +357 -357
  224. package/server/services/security.js +513 -513
  225. package/server/services/self-healing.js +843 -843
  226. package/server/services/shieldqr.js +322 -0
  227. package/server/services/sovereign-shield.js +542 -0
  228. package/server/services/ssl-inspector.js +42 -0
  229. package/server/services/ssl-monitor.js +167 -0
  230. package/server/services/stripe.js +205 -192
  231. package/server/services/swarm.js +788 -788
  232. package/server/services/universal-scraper.js +662 -661
  233. package/server/services/verification.js +481 -481
  234. package/server/services/vision.js +1163 -1163
  235. package/server/services/wab-crypto.js +178 -0
  236. package/server/utils/cache.js +125 -125
  237. package/server/utils/migrate.js +81 -81
  238. package/server/utils/safe-fetch.js +228 -0
  239. package/server/utils/secureFields.js +50 -50
  240. package/server/ws.js +161 -161
  241. package/templates/artisan-marketplace.yaml +104 -104
  242. package/templates/book-price-scout.yaml +98 -98
  243. package/templates/electronics-price-tracker.yaml +108 -108
  244. package/templates/flight-deal-hunter.yaml +113 -113
  245. package/templates/freelancer-direct.yaml +116 -116
  246. package/templates/grocery-price-compare.yaml +93 -93
  247. package/templates/hotel-direct-booking.yaml +113 -113
  248. package/templates/local-services.yaml +98 -98
  249. package/templates/olive-oil-tunisia.yaml +88 -88
  250. package/templates/organic-farm-fresh.yaml +101 -101
  251. package/templates/restaurant-direct.yaml +97 -97
  252. package/public/score.html +0 -263
  253. package/server/migrations/006_growth_suite.sql +0 -138
  254. package/server/routes/growth.js +0 -962
  255. package/server/services/fairness-engine.js +0 -409
  256. package/server/services/fairness.js +0 -420
@@ -1,108 +1,108 @@
1
- /**
2
- * Example: Basic AI Agent using Puppeteer + WAB
3
- *
4
- * This agent connects to a website that has the Web Agent Bridge script installed,
5
- * discovers available actions, and executes them.
6
- *
7
- * Prerequisites:
8
- * npm install puppeteer
9
- *
10
- * Usage:
11
- * node examples/puppeteer-agent.js <url>
12
- */
13
-
14
- const puppeteer = require('puppeteer');
15
-
16
- const TARGET_URL = process.argv[2] || 'http://localhost:3000';
17
-
18
- async function main() {
19
- console.log(`\n🤖 WAB Puppeteer Agent`);
20
- console.log(` Target: ${TARGET_URL}\n`);
21
-
22
- const browser = await puppeteer.launch({ headless: true });
23
- const page = await browser.newPage();
24
-
25
- // Navigate to the target site
26
- await page.goto(TARGET_URL, { waitUntil: 'networkidle2' });
27
- console.log(`✓ Page loaded: ${await page.title()}`);
28
-
29
- // Wait for WAB bridge to be ready
30
- const hasBridge = await page.evaluate(() => {
31
- return new Promise((resolve) => {
32
- if (window.AICommands && window.AICommands._ready) {
33
- resolve(true);
34
- } else {
35
- // Wait up to 5 seconds for bridge
36
- const timeout = setTimeout(() => resolve(false), 5000);
37
- document.addEventListener('wab:ready', () => {
38
- clearTimeout(timeout);
39
- resolve(true);
40
- });
41
- }
42
- });
43
- });
44
-
45
- if (!hasBridge) {
46
- console.log('✗ Web Agent Bridge not found on this page.');
47
- await browser.close();
48
- return;
49
- }
50
-
51
- console.log('✓ Web Agent Bridge detected\n');
52
-
53
- // Step 1: Get page info
54
- const pageInfo = await page.evaluate(() => window.AICommands.getPageInfo());
55
- console.log('📄 Page Info:');
56
- console.log(` Title: ${pageInfo.title}`);
57
- console.log(` URL: ${pageInfo.url}`);
58
- console.log(` Bridge Version: ${pageInfo.bridgeVersion}`);
59
- console.log(` Tier: ${pageInfo.tier}`);
60
- console.log(` Actions Available: ${pageInfo.actionsCount}`);
61
- console.log(` Rate Limit Remaining: ${pageInfo.rateLimitRemaining}\n`);
62
-
63
- // Step 2: Discover all available actions
64
- const actions = await page.evaluate(() => window.AICommands.getActions());
65
- console.log(`🔍 Discovered ${actions.length} actions:`);
66
- actions.forEach((action) => {
67
- console.log(` • ${action.name} (${action.trigger}) — ${action.description}`);
68
- if (action.fields) {
69
- action.fields.forEach((f) => {
70
- console.log(` └─ ${f.name}: ${f.type}${f.required ? ' (required)' : ''}`);
71
- });
72
- }
73
- });
74
-
75
- // Step 3: Read content from the page
76
- const content = await page.evaluate(() => {
77
- return window.AICommands.readContent('h1') || window.AICommands.readContent('title');
78
- });
79
- if (content && content.success) {
80
- console.log(`\n📖 Page heading: "${content.text}"`);
81
- }
82
-
83
- // Step 4: Execute a click action (first available)
84
- const clickAction = actions.find((a) => a.trigger === 'click');
85
- if (clickAction) {
86
- console.log(`\n▶ Executing action: "${clickAction.name}"`);
87
- const result = await page.evaluate(
88
- (name) => window.AICommands.execute(name),
89
- clickAction.name
90
- );
91
- console.log(` Result: ${result.success ? '✓ Success' : '✗ ' + result.error}`);
92
- }
93
-
94
- // Step 5: List permissions
95
- const permissions = pageInfo.permissions;
96
- console.log('\n🔐 Permissions:');
97
- Object.entries(permissions).forEach(([key, value]) => {
98
- console.log(` ${value ? '✓' : '✗'} ${key}`);
99
- });
100
-
101
- console.log('\n✓ Agent session complete.');
102
- await browser.close();
103
- }
104
-
105
- main().catch((err) => {
106
- console.error('Agent error:', err.message);
107
- process.exit(1);
108
- });
1
+ /**
2
+ * Example: Basic AI Agent using Puppeteer + WAB
3
+ *
4
+ * This agent connects to a website that has the Web Agent Bridge script installed,
5
+ * discovers available actions, and executes them.
6
+ *
7
+ * Prerequisites:
8
+ * npm install puppeteer
9
+ *
10
+ * Usage:
11
+ * node examples/puppeteer-agent.js <url>
12
+ */
13
+
14
+ const puppeteer = require('puppeteer');
15
+
16
+ const TARGET_URL = process.argv[2] || 'http://localhost:3000';
17
+
18
+ async function main() {
19
+ console.log(`\n🤖 WAB Puppeteer Agent`);
20
+ console.log(` Target: ${TARGET_URL}\n`);
21
+
22
+ const browser = await puppeteer.launch({ headless: true });
23
+ const page = await browser.newPage();
24
+
25
+ // Navigate to the target site
26
+ await page.goto(TARGET_URL, { waitUntil: 'networkidle2' });
27
+ console.log(`✓ Page loaded: ${await page.title()}`);
28
+
29
+ // Wait for WAB bridge to be ready
30
+ const hasBridge = await page.evaluate(() => {
31
+ return new Promise((resolve) => {
32
+ if (window.AICommands && window.AICommands._ready) {
33
+ resolve(true);
34
+ } else {
35
+ // Wait up to 5 seconds for bridge
36
+ const timeout = setTimeout(() => resolve(false), 5000);
37
+ document.addEventListener('wab:ready', () => {
38
+ clearTimeout(timeout);
39
+ resolve(true);
40
+ });
41
+ }
42
+ });
43
+ });
44
+
45
+ if (!hasBridge) {
46
+ console.log('✗ Web Agent Bridge not found on this page.');
47
+ await browser.close();
48
+ return;
49
+ }
50
+
51
+ console.log('✓ Web Agent Bridge detected\n');
52
+
53
+ // Step 1: Get page info
54
+ const pageInfo = await page.evaluate(() => window.AICommands.getPageInfo());
55
+ console.log('📄 Page Info:');
56
+ console.log(` Title: ${pageInfo.title}`);
57
+ console.log(` URL: ${pageInfo.url}`);
58
+ console.log(` Bridge Version: ${pageInfo.bridgeVersion}`);
59
+ console.log(` Tier: ${pageInfo.tier}`);
60
+ console.log(` Actions Available: ${pageInfo.actionsCount}`);
61
+ console.log(` Rate Limit Remaining: ${pageInfo.rateLimitRemaining}\n`);
62
+
63
+ // Step 2: Discover all available actions
64
+ const actions = await page.evaluate(() => window.AICommands.getActions());
65
+ console.log(`🔍 Discovered ${actions.length} actions:`);
66
+ actions.forEach((action) => {
67
+ console.log(` • ${action.name} (${action.trigger}) — ${action.description}`);
68
+ if (action.fields) {
69
+ action.fields.forEach((f) => {
70
+ console.log(` └─ ${f.name}: ${f.type}${f.required ? ' (required)' : ''}`);
71
+ });
72
+ }
73
+ });
74
+
75
+ // Step 3: Read content from the page
76
+ const content = await page.evaluate(() => {
77
+ return window.AICommands.readContent('h1') || window.AICommands.readContent('title');
78
+ });
79
+ if (content && content.success) {
80
+ console.log(`\n📖 Page heading: "${content.text}"`);
81
+ }
82
+
83
+ // Step 4: Execute a click action (first available)
84
+ const clickAction = actions.find((a) => a.trigger === 'click');
85
+ if (clickAction) {
86
+ console.log(`\n▶ Executing action: "${clickAction.name}"`);
87
+ const result = await page.evaluate(
88
+ (name) => window.AICommands.execute(name),
89
+ clickAction.name
90
+ );
91
+ console.log(` Result: ${result.success ? '✓ Success' : '✗ ' + result.error}`);
92
+ }
93
+
94
+ // Step 5: List permissions
95
+ const permissions = pageInfo.permissions;
96
+ console.log('\n🔐 Permissions:');
97
+ Object.entries(permissions).forEach(([key, value]) => {
98
+ console.log(` ${value ? '✓' : '✗'} ${key}`);
99
+ });
100
+
101
+ console.log('\n✓ Agent session complete.');
102
+ await browser.close();
103
+ }
104
+
105
+ main().catch((err) => {
106
+ console.error('Agent error:', err.message);
107
+ process.exit(1);
108
+ });
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * route53-wab-dns.js
4
+ * -------------------
5
+ * CLI tool: enable or disable WAB DNS Discovery TXT record on AWS Route 53.
6
+ *
7
+ * Usage:
8
+ * AWS_ACCESS_KEY_ID=… AWS_SECRET_ACCESS_KEY=… \
9
+ * node route53-wab-dns.js enable example.com [HOSTED_ZONE_ID]
10
+ *
11
+ * AWS_ACCESS_KEY_ID=… AWS_SECRET_ACCESS_KEY=… \
12
+ * node route53-wab-dns.js disable example.com [HOSTED_ZONE_ID]
13
+ *
14
+ * node route53-wab-dns.js status example.com
15
+ *
16
+ * Optional env vars:
17
+ * AWS_REGION (default: us-east-1)
18
+ * WAB_BASE_URL (default: https://www.webagentbridge.com)
19
+ * WAB_ENDPOINT (override the wab.json URL in the TXT record)
20
+ *
21
+ * Required: @aws-sdk/client-route-53
22
+ * npm install @aws-sdk/client-route-53
23
+ */
24
+
25
+ 'use strict';
26
+
27
+ const {
28
+ Route53Client,
29
+ ChangeResourceRecordSetsCommand,
30
+ ListHostedZonesByNameCommand,
31
+ ListResourceRecordSetsCommand,
32
+ } = require('@aws-sdk/client-route-53');
33
+
34
+ const fetch = (() => {
35
+ try { return require('node-fetch'); }
36
+ catch { return globalThis.fetch; }
37
+ })();
38
+
39
+ const [,, action, domain, zoneIdArg] = process.argv;
40
+
41
+ const REGION = process.env.AWS_REGION || 'us-east-1';
42
+ const WAB_BASE = process.env.WAB_BASE_URL || 'https://www.webagentbridge.com';
43
+ const ENDPOINT = process.env.WAB_ENDPOINT || `https://${domain}/.well-known/wab.json`;
44
+
45
+ if (!action || !domain) {
46
+ console.error('Usage: node route53-wab-dns.js <enable|disable|status> <domain> [zone-id]');
47
+ process.exit(1);
48
+ }
49
+ if (!['enable','disable','status'].includes(action)) {
50
+ console.error('Action must be: enable | disable | status');
51
+ process.exit(1);
52
+ }
53
+ if (action !== 'status' && (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY)) {
54
+ console.error('Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env variables');
55
+ process.exit(1);
56
+ }
57
+
58
+ const client = new Route53Client({ region: REGION });
59
+
60
+ async function getRecordTemplate() {
61
+ const url = `${WAB_BASE}/api/discovery/provider/record-template?domain=${encodeURIComponent(domain)}&endpoint=${encodeURIComponent(ENDPOINT)}`;
62
+ const j = await (await fetch(url)).json();
63
+ if (!j.record || !j.record.value) throw new Error('Could not fetch WAB record template');
64
+ // Route 53 requires double-quoted TXT value
65
+ const v = j.record.value;
66
+ return v.startsWith('"') ? v : `"${v}"`;
67
+ }
68
+
69
+ async function resolveZoneId() {
70
+ if (zoneIdArg) return zoneIdArg;
71
+ console.log(`[R53] Resolving hosted zone for ${domain}…`);
72
+ const r = await client.send(new ListHostedZonesByNameCommand({ DNSName: domain, MaxItems: '1' }));
73
+ const zone = (r.HostedZones || []).find(z => z.Name === `${domain}.`);
74
+ if (!zone) throw new Error(`No hosted zone found for "${domain}"`);
75
+ return zone.Id.replace('/hostedzone/', '');
76
+ }
77
+
78
+ async function getCurrentRecord(zoneId) {
79
+ const r = await client.send(new ListResourceRecordSetsCommand({
80
+ HostedZoneId: zoneId,
81
+ StartRecordName: `_wab.${domain}`,
82
+ StartRecordType: 'TXT',
83
+ MaxItems: '1',
84
+ }));
85
+ return (r.ResourceRecordSets || []).find(
86
+ rr => rr.Name === `_wab.${domain}.` && rr.Type === 'TXT'
87
+ ) || null;
88
+ }
89
+
90
+ async function main() {
91
+ console.log(`[WAB] Action: ${action} | Domain: ${domain}`);
92
+
93
+ if (action === 'status') {
94
+ const j = await (await fetch(`${WAB_BASE}/api/discovery/provider/status?domain=${encodeURIComponent(domain)}`)).json();
95
+ console.log(`[WAB] Status: ${j.status}`);
96
+ console.log(JSON.stringify(j, null, 2));
97
+ return;
98
+ }
99
+
100
+ const zoneId = await resolveZoneId();
101
+ console.log(`[R53] Zone ID: ${zoneId}`);
102
+
103
+ if (action === 'enable') {
104
+ const txtVal = await getRecordTemplate();
105
+ console.log(`[WAB] TXT value: ${txtVal}`);
106
+
107
+ await client.send(new ChangeResourceRecordSetsCommand({
108
+ HostedZoneId: zoneId,
109
+ ChangeBatch: {
110
+ Comment: 'WAB DNS Discovery enable',
111
+ Changes: [{
112
+ Action: 'UPSERT',
113
+ ResourceRecordSet: {
114
+ Name: `_wab.${domain}`,
115
+ Type: 'TXT',
116
+ TTL: 3600,
117
+ ResourceRecords: [{ Value: txtVal }],
118
+ },
119
+ }],
120
+ },
121
+ }));
122
+ console.log('[R53] UPSERT applied');
123
+ console.log('[WAB] WAB Discovery ENABLED. Propagation may take up to 60 s.');
124
+ }
125
+
126
+ if (action === 'disable') {
127
+ const existing = await getCurrentRecord(zoneId);
128
+ if (!existing) {
129
+ console.log('[R53] No _wab TXT record found — already disabled.');
130
+ return;
131
+ }
132
+ await client.send(new ChangeResourceRecordSetsCommand({
133
+ HostedZoneId: zoneId,
134
+ ChangeBatch: {
135
+ Comment: 'WAB DNS Discovery disable',
136
+ Changes: [{ Action: 'DELETE', ResourceRecordSet: existing }],
137
+ },
138
+ }));
139
+ console.log('[R53] Record deleted');
140
+ console.log('[WAB] WAB Discovery DISABLED.');
141
+ }
142
+ }
143
+
144
+ main().catch(err => { console.error('[ERROR]', err.message); process.exit(1); });
@@ -1,55 +1,55 @@
1
- # SaaS Dashboard Example (Notion-style)
2
-
3
- A practical setup for internal dashboards where agents read KPIs and trigger safe workflows.
4
-
5
- ## Embed
6
-
7
- ```html
8
- <script src="https://webagentbridge.com/script/wab.min.js"></script>
9
- <script>
10
- window.WAB.init({
11
- name: 'Acme SaaS Dashboard',
12
- actions: {
13
- getKpiCards: {
14
- description: 'Return KPI card values from dashboard widgets',
15
- run: function () {
16
- var cards = Array.from(document.querySelectorAll('[data-kpi-card]')).map(function (card) {
17
- return {
18
- key: card.getAttribute('data-kpi-card'),
19
- label: (card.querySelector('[data-kpi-label]') || {}).textContent || null,
20
- value: (card.querySelector('[data-kpi-value]') || {}).textContent || null
21
- };
22
- });
23
- return { success: true, cards: cards };
24
- }
25
- },
26
- openCustomerById: {
27
- description: 'Open customer panel using data-customer-id selector',
28
- params: [{ name: 'customerId', type: 'string', required: true }],
29
- run: function (params) {
30
- var id = String(params.customerId || '').trim();
31
- if (!id) return { success: false, error: 'customerId is required' };
32
- var row = document.querySelector('[data-customer-id="' + CSS.escape(id) + '"]');
33
- if (!row) return { success: false, error: 'Customer not found' };
34
- row.click();
35
- return { success: true, customerId: id };
36
- }
37
- },
38
- triggerInvoiceReminder: {
39
- description: 'Trigger existing invoice reminder button from dashboard row',
40
- params: [{ name: 'invoiceId', type: 'string', required: true }],
41
- run: function (params) {
42
- var id = String(params.invoiceId || '').trim();
43
- if (!id) return { success: false, error: 'invoiceId is required' };
44
- var btn = document.querySelector('[data-invoice-id="' + CSS.escape(id) + '"] [data-action="send-reminder"]');
45
- if (!btn) return { success: false, error: 'Reminder action not found for invoice' };
46
- btn.click();
47
- return { success: true, invoiceId: id };
48
- }
49
- }
50
- }
51
- });
52
- </script>
53
- ```
54
-
55
- The selectors use data attributes so actions stay stable across UI redesigns.
1
+ # SaaS Dashboard Example (Notion-style)
2
+
3
+ A practical setup for internal dashboards where agents read KPIs and trigger safe workflows.
4
+
5
+ ## Embed
6
+
7
+ ```html
8
+ <script src="https://webagentbridge.com/script/wab.min.js"></script>
9
+ <script>
10
+ window.WAB.init({
11
+ name: 'Acme SaaS Dashboard',
12
+ actions: {
13
+ getKpiCards: {
14
+ description: 'Return KPI card values from dashboard widgets',
15
+ run: function () {
16
+ var cards = Array.from(document.querySelectorAll('[data-kpi-card]')).map(function (card) {
17
+ return {
18
+ key: card.getAttribute('data-kpi-card'),
19
+ label: (card.querySelector('[data-kpi-label]') || {}).textContent || null,
20
+ value: (card.querySelector('[data-kpi-value]') || {}).textContent || null
21
+ };
22
+ });
23
+ return { success: true, cards: cards };
24
+ }
25
+ },
26
+ openCustomerById: {
27
+ description: 'Open customer panel using data-customer-id selector',
28
+ params: [{ name: 'customerId', type: 'string', required: true }],
29
+ run: function (params) {
30
+ var id = String(params.customerId || '').trim();
31
+ if (!id) return { success: false, error: 'customerId is required' };
32
+ var row = document.querySelector('[data-customer-id="' + CSS.escape(id) + '"]');
33
+ if (!row) return { success: false, error: 'Customer not found' };
34
+ row.click();
35
+ return { success: true, customerId: id };
36
+ }
37
+ },
38
+ triggerInvoiceReminder: {
39
+ description: 'Trigger existing invoice reminder button from dashboard row',
40
+ params: [{ name: 'invoiceId', type: 'string', required: true }],
41
+ run: function (params) {
42
+ var id = String(params.invoiceId || '').trim();
43
+ if (!id) return { success: false, error: 'invoiceId is required' };
44
+ var btn = document.querySelector('[data-invoice-id="' + CSS.escape(id) + '"] [data-action="send-reminder"]');
45
+ if (!btn) return { success: false, error: 'Reminder action not found for invoice' };
46
+ btn.click();
47
+ return { success: true, invoiceId: id };
48
+ }
49
+ }
50
+ }
51
+ });
52
+ </script>
53
+ ```
54
+
55
+ The selectors use data attributes so actions stay stable across UI redesigns.
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Demo3 — Safe Mode Agent
3
+ *
4
+ * Shows the difference between a domain that has WAB enabled (full trust,
5
+ * full execute) and one that doesn't (read-only / blocked).
6
+ *
7
+ * node examples/safe-mode-agent.js wab-site.com untrusted-site.com
8
+ *
9
+ * Or pass --policy=strict|standard|permissive to change the gate.
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const { WABSafeMode } = require('../sdk');
15
+
16
+ const args = process.argv.slice(2);
17
+ const flags = {};
18
+ const domains = [];
19
+ for (const a of args) {
20
+ if (a.startsWith('--')) {
21
+ const [k, v] = a.replace(/^--/, '').split('=');
22
+ flags[k] = v ?? true;
23
+ } else domains.push(a);
24
+ }
25
+ if (domains.length === 0) {
26
+ console.error('Usage: node examples/safe-mode-agent.js <domain1> [<domain2> ...] [--policy=standard]');
27
+ console.error(' [--api=https://your-wab.example.com]');
28
+ process.exit(2);
29
+ }
30
+
31
+ const safe = new WABSafeMode({
32
+ apiBase: flags.api || process.env.WAB_API_BASE || 'https://webagentbridge.com',
33
+ policy: flags.policy || 'standard',
34
+ });
35
+
36
+ const COLOR = {
37
+ reset: '\x1b[0m', dim: '\x1b[2m', bold: '\x1b[1m',
38
+ green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m', cyan: '\x1b[36m',
39
+ };
40
+ function color(c, s) { return process.stdout.isTTY ? `${COLOR[c]}${s}${COLOR.reset}` : s; }
41
+ function levelColor(l) { return l >= 3 ? 'green' : l === 2 ? 'cyan' : l === 1 ? 'yellow' : 'red'; }
42
+
43
+ async function checkOne(d) {
44
+ const t0 = Date.now();
45
+ const v = await safe.evaluate(d, { live: !!flags.live });
46
+ const elapsed = Date.now() - t0;
47
+
48
+ console.log('');
49
+ console.log(color('bold', `── ${v.domain} ──────────────────────────────`));
50
+ console.log(`Level : ${color(levelColor(v.level), `L${v.level}`)} (${v.score_label} ${v.score})`);
51
+ console.log(`Verdict : ${color(v.verdict === 'allow' ? 'green' : v.verdict === 'restrict' ? 'yellow' : 'red', v.verdict.toUpperCase())}`);
52
+ console.log(`Execute : ${v.allow_execute ? color('green', '✓ allowed') : color('red', '✗ blocked')}`);
53
+ console.log(`Read : ${v.allow_read ? color('green', '✓ allowed') : color('red', '✗ blocked')}`);
54
+ console.log(`Reason : ${v.reason}`);
55
+ if (v.reasons && v.reasons.length) {
56
+ for (const r of v.reasons) {
57
+ const sev = r.severity === 'deny' ? 'red' : r.severity === 'restrict' ? 'yellow' : 'dim';
58
+ console.log(color('dim', ' · ') + color(sev, `[${r.severity}] ${r.code}`) + ' ' + (r.message || ''));
59
+ }
60
+ }
61
+ console.log(color('dim', ` (policy=${v.policy}, ${elapsed}ms)`));
62
+
63
+ // Simulate the agent acting under Safe Mode
64
+ try {
65
+ if (v.allow_execute) {
66
+ await safe.guardExecute(v.domain, async () => {
67
+ console.log(color('green', ` → Agent: executing full action on ${v.domain}`));
68
+ });
69
+ } else if (v.allow_read) {
70
+ await safe.guardRead(v.domain, async () => {
71
+ console.log(color('yellow', ` → Agent: read-only mode on ${v.domain}`));
72
+ });
73
+ } else {
74
+ console.log(color('red', ` → Agent: refusing to interact with ${v.domain}`));
75
+ }
76
+ } catch (err) {
77
+ console.log(color('red', ` → ${err.message}`));
78
+ }
79
+ }
80
+
81
+ (async () => {
82
+ console.log(color('bold', `WAB Safe Mode demo — policy=${safe.policy} api=${safe.apiBase}`));
83
+ for (const d of domains) {
84
+ try { await checkOne(d); } catch (e) { console.error(`Error checking ${d}: ${e.message}`); }
85
+ }
86
+ console.log('');
87
+
88
+ // Pick the most trusted target if multiple were given
89
+ if (domains.length > 1) {
90
+ const best = await safe.pickBest(domains);
91
+ if (best) {
92
+ console.log(color('bold', `Recommended target: `) + color(levelColor(best.level), best.domain) +
93
+ color('dim', ` (L${best.level}, score ${best.score})`));
94
+ }
95
+ }
96
+ })();