web-agent-bridge 3.3.0 → 3.8.1
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/LICENSE +84 -72
- package/README.ar.md +1563 -1286
- package/README.md +137 -1764
- package/bin/agent-runner.js +474 -474
- package/bin/cli.js +237 -237
- package/bin/wab-init.js +244 -0
- package/bin/wab.js +80 -80
- package/examples/azure-dns-wab.js +83 -0
- package/examples/bidi-agent.js +119 -119
- package/examples/cloudflare-wab-dns.js +121 -0
- package/examples/cpanel-wab-dns.js +114 -0
- package/examples/cross-site-agent.js +91 -91
- package/examples/dns-discovery-agent.js +166 -0
- package/examples/gcp-dns-wab.js +76 -0
- package/examples/governance-agent.js +169 -0
- package/examples/mcp-agent.js +94 -94
- package/examples/next-app-router/README.md +44 -44
- package/examples/plesk-wab-dns.js +103 -0
- package/examples/puppeteer-agent.js +108 -108
- package/examples/route53-wab-dns.js +144 -0
- package/examples/saas-dashboard/README.md +55 -55
- package/examples/safe-mode-agent.js +96 -0
- package/examples/self-discovery.js +106 -0
- package/examples/shopify-hydrogen/README.md +74 -74
- package/examples/vision-agent.js +171 -171
- package/examples/wab-sign.js +74 -0
- package/examples/wab-verify.js +60 -0
- package/examples/wordpress-elementor/README.md +77 -77
- package/package.json +93 -93
- package/public/.well-known/agent-tools.json +180 -180
- package/public/.well-known/ai-assets.json +59 -59
- package/public/.well-known/security.txt +8 -8
- package/public/.well-known/wab.json +28 -0
- package/public/activate.html +448 -0
- package/public/adopt.html +236 -0
- package/public/adoption-metrics.html +188 -0
- package/public/agent-workspace.html +359 -349
- package/public/ai.html +198 -198
- package/public/api.html +397 -413
- package/public/azure-dns-integration.html +289 -0
- package/public/browser.html +486 -486
- package/public/cloudflare-integration.html +380 -0
- package/public/commander-dashboard.html +243 -243
- package/public/cookies.html +210 -210
- package/public/cpanel-integration.html +398 -0
- package/public/css/agent-workspace.css +1713 -1713
- package/public/css/premium.css +317 -317
- package/public/css/styles.css +1401 -1235
- package/public/dashboard-shieldlink.html +295 -0
- package/public/dashboard.html +711 -706
- package/public/dns.html +436 -507
- package/public/docs.html +588 -587
- package/public/enterprise-mesh.ar.html +80 -0
- package/public/enterprise-mesh.html +81 -0
- package/public/feed.xml +89 -89
- package/public/gcp-dns-integration.html +318 -0
- package/public/governance.ar.html +70 -0
- package/public/governance.html +69 -0
- package/public/growth.html +465 -463
- package/public/index.html +1372 -1070
- package/public/integrations.html +556 -556
- package/public/js/activate.js +449 -0
- package/public/js/agent-workspace.js +1740 -1740
- package/public/js/auth-nav.js +117 -31
- package/public/js/auth-redirect.js +12 -12
- package/public/js/cookie-consent.js +56 -56
- package/public/js/dns.js +438 -0
- package/public/js/wab-demo-page.js +721 -721
- package/public/js/ws-client.js +74 -74
- package/public/l-preview.html +242 -0
- package/public/llms-full.txt +360 -360
- package/public/llms.txt +125 -125
- package/public/login.html +85 -85
- package/public/mesh-dashboard.html +328 -328
- package/public/milestones.html +346 -0
- package/public/one-click.html +779 -0
- package/public/openapi.json +669 -580
- package/public/partners.ar.html +145 -0
- package/public/partners.html +143 -0
- package/public/phone-shield.html +281 -281
- package/public/plesk-integration.html +375 -0
- package/public/premium-dashboard.html +2489 -2489
- package/public/premium.html +793 -793
- package/public/privacy.html +297 -297
- package/public/provider-onboarding.html +172 -0
- package/public/provider-sandbox.html +134 -0
- package/public/providers.html +359 -0
- package/public/refusals.html +172 -0
- package/public/register.html +105 -105
- package/public/registrar-integrations.html +141 -0
- package/public/ring4.html +292 -0
- package/public/robots.txt +99 -87
- package/public/route53-integration.html +531 -0
- package/public/score.html +263 -0
- package/public/script/wab-consent.d.ts +36 -36
- package/public/script/wab-consent.js +104 -104
- package/public/script/wab-schema.js +131 -131
- package/public/script/wab.d.ts +108 -108
- package/public/script/wab.min.js +580 -580
- package/public/security.txt +8 -8
- package/public/shieldlink.html +244 -0
- package/public/shieldqr.html +231 -0
- package/public/sitemap.xml +19 -1
- package/public/terms.html +256 -256
- package/public/trust-graph-api.ar.html +92 -0
- package/public/trust-graph-api.html +91 -0
- package/public/wab-features.html +560 -0
- package/public/wab-trust.html +200 -0
- package/public/wab-truth.html +375 -0
- package/public/wab-vs-protocols.html +210 -0
- package/public/whitepaper.html +449 -0
- package/script/ai-agent-bridge.js +1754 -1754
- package/sdk/README.md +99 -99
- package/sdk/agent-mesh.js +449 -449
- package/sdk/auto-discovery.js +301 -0
- package/sdk/commander.js +262 -262
- package/sdk/governance.js +262 -0
- package/sdk/index.d.ts +464 -464
- package/sdk/index.js +649 -636
- package/sdk/multi-agent.js +318 -318
- package/sdk/package.json +2 -2
- package/sdk/safe-mode.js +221 -0
- package/sdk/safety-shield.js +219 -219
- package/sdk/schema-discovery.js +83 -83
- package/server/adapters/index.js +520 -520
- package/server/config/plans.js +412 -367
- package/server/config/secrets.js +102 -102
- package/server/control-plane/index.js +301 -301
- package/server/data-plane/index.js +354 -354
- package/server/index.js +790 -531
- package/server/llm/index.js +404 -404
- package/server/middleware/adminAuth.js +35 -35
- package/server/middleware/api-tier.js +170 -0
- package/server/middleware/auth.js +50 -50
- package/server/middleware/featureGate.js +88 -88
- package/server/middleware/rateLimits.js +100 -100
- package/server/middleware/sensitiveAction.js +157 -157
- package/server/middleware/wab-trust.js +141 -0
- package/server/migrations/001_add_analytics_indexes.sql +7 -7
- package/server/migrations/002_premium_features.sql +418 -418
- package/server/migrations/003_ads_integer_cents.sql +33 -33
- package/server/migrations/004_agent_os.sql +158 -158
- package/server/migrations/005_marketplace_metering.sql +126 -126
- package/server/migrations/006_growth_suite.sql +138 -0
- package/server/migrations/007_governance.sql +106 -0
- package/server/migrations/008_plans.sql +144 -0
- package/server/migrations/009_shieldqr.sql +30 -0
- package/server/migrations/010_extended_trust.sql +33 -0
- package/server/migrations/011_outreach.sql +47 -0
- package/server/migrations/012_shieldlink.sql +116 -0
- package/server/migrations/013_ct_monitor.sql +13 -0
- package/server/migrations/014_wab_advanced_features.sql +128 -0
- package/server/migrations/015_wab_truth_layer.sql +101 -0
- package/server/migrations/016_ring4_external_trust.sql +84 -0
- package/server/migrations/017_ring4_extensions.sql +69 -0
- package/server/migrations/018_commercial_foundations.sql +167 -0
- package/server/migrations/019_unify_tier_constraints.sql +133 -0
- package/server/models/adapters/index.js +33 -33
- package/server/models/adapters/mysql.js +183 -183
- package/server/models/adapters/postgresql.js +172 -172
- package/server/models/adapters/sqlite.js +7 -7
- package/server/models/db.js +740 -681
- package/server/observability/failure-analysis.js +337 -337
- package/server/observability/index.js +394 -394
- package/server/protocol/capabilities.js +223 -223
- package/server/protocol/index.js +243 -243
- package/server/protocol/schema.js +584 -584
- package/server/registry/certification.js +271 -271
- package/server/registry/index.js +326 -326
- package/server/routes/activate.js +478 -0
- package/server/routes/admin-outreach.js +239 -0
- package/server/routes/admin-plans.js +76 -0
- package/server/routes/admin-premium.js +674 -671
- package/server/routes/admin-shieldlink.js +137 -0
- package/server/routes/admin-shieldqr.js +90 -0
- package/server/routes/admin-trust-monitor.js +139 -0
- package/server/routes/admin.js +550 -261
- package/server/routes/adopt.js +61 -0
- package/server/routes/ads.js +130 -130
- package/server/routes/agent-workspace.js +540 -540
- package/server/routes/api-keys.js +127 -0
- package/server/routes/api.js +150 -150
- package/server/routes/auth.js +71 -71
- package/server/routes/billing.js +57 -45
- package/server/routes/commander.js +316 -316
- package/server/routes/customer-shieldlink.js +133 -0
- package/server/routes/demo-showcase.js +332 -332
- package/server/routes/demo-store.js +154 -154
- package/server/routes/diagnose.js +373 -0
- package/server/routes/discovery.js +2348 -417
- package/server/routes/enterprise-mesh.js +170 -0
- package/server/routes/gateway.js +173 -173
- package/server/routes/governance-saas.js +203 -0
- package/server/routes/governance.js +208 -0
- package/server/routes/growth.js +1048 -0
- package/server/routes/intent.js +328 -0
- package/server/routes/license.js +251 -251
- package/server/routes/mesh.js +469 -469
- package/server/routes/noscript.js +543 -543
- package/server/routes/partners.js +201 -0
- package/server/routes/plans.js +33 -0
- package/server/routes/premium-v2.js +686 -686
- package/server/routes/premium.js +724 -724
- package/server/routes/providers.js +650 -0
- package/server/routes/reputation.js +411 -0
- package/server/routes/ring4.js +885 -0
- package/server/routes/runtime.js +2148 -2148
- package/server/routes/shieldlink.js +70 -0
- package/server/routes/shieldqr.js +88 -0
- package/server/routes/sovereign.js +465 -465
- package/server/routes/truth-layer.js +670 -0
- package/server/routes/universal.js +200 -200
- package/server/routes/unsubscribe.js +51 -0
- package/server/routes/wab-api.js +850 -850
- package/server/routes/wab-cache.js +282 -0
- package/server/runtime/container-worker.js +111 -111
- package/server/runtime/container.js +448 -448
- package/server/runtime/distributed-worker.js +362 -362
- package/server/runtime/event-bus.js +210 -210
- package/server/runtime/index.js +253 -253
- package/server/runtime/queue.js +599 -599
- package/server/runtime/replay.js +666 -666
- package/server/runtime/sandbox.js +266 -266
- package/server/runtime/scheduler.js +534 -534
- package/server/runtime/session-engine.js +293 -293
- package/server/runtime/state-manager.js +188 -188
- package/server/secrets/wab-signing-key.pem +3 -0
- package/server/secrets/wab-signing-pub.pem +3 -0
- package/server/security/cross-site-redactor.js +196 -196
- package/server/security/dry-run.js +180 -180
- package/server/security/human-gate-rate-limit.js +147 -147
- package/server/security/human-gate-transports.js +178 -178
- package/server/security/human-gate.js +281 -281
- package/server/security/index.js +368 -368
- package/server/security/intent-engine.js +245 -245
- package/server/security/reward-guard.js +171 -171
- package/server/security/rollback-store.js +239 -239
- package/server/security/token-scope.js +404 -404
- package/server/security/url-policy.js +139 -139
- package/server/services/adoption-agent.js +182 -0
- package/server/services/agent-chat.js +506 -506
- package/server/services/agent-learning.js +601 -601
- package/server/services/agent-memory.js +625 -625
- package/server/services/agent-mesh.js +555 -555
- package/server/services/agent-symphony.js +717 -717
- package/server/services/agent-tasks.js +1807 -1807
- package/server/services/api-key-engine.js +292 -292
- package/server/services/cluster.js +894 -894
- package/server/services/commander.js +738 -738
- package/server/services/edge-compute.js +440 -440
- package/server/services/email.js +233 -204
- package/server/services/fairness-engine.js +409 -0
- package/server/services/fairness.js +420 -0
- package/server/services/governance.js +466 -0
- package/server/services/hosted-runtime.js +205 -205
- package/server/services/lfd.js +635 -635
- package/server/services/local-ai.js +389 -389
- package/server/services/marketplace.js +270 -270
- package/server/services/metering.js +182 -182
- package/server/services/modules/affiliate-intelligence.js +93 -93
- package/server/services/modules/agent-firewall.js +90 -90
- package/server/services/modules/bounty.js +89 -89
- package/server/services/modules/collective-bargaining.js +92 -92
- package/server/services/modules/dark-pattern.js +66 -66
- package/server/services/modules/gov-intelligence.js +45 -45
- package/server/services/modules/neural.js +55 -55
- package/server/services/modules/notary.js +49 -49
- package/server/services/modules/price-time-machine.js +86 -86
- package/server/services/modules/protocol.js +104 -104
- package/server/services/negotiation.js +439 -439
- package/server/services/outreach-agent.js +312 -0
- package/server/services/plans.js +214 -0
- package/server/services/plugins.js +771 -771
- package/server/services/premium.js +1 -1
- package/server/services/price-intelligence.js +566 -566
- package/server/services/price-shield.js +1137 -1137
- package/server/services/provider-clients.js +740 -0
- package/server/services/reputation.js +465 -465
- package/server/services/search-engine.js +357 -357
- package/server/services/security.js +513 -513
- package/server/services/self-healing.js +843 -843
- package/server/services/shieldlink.js +492 -0
- package/server/services/shieldqr.js +322 -0
- package/server/services/sovereign-shield.js +542 -542
- package/server/services/ssl-ct-monitor.js +224 -0
- package/server/services/ssl-inspector.js +42 -0
- package/server/services/ssl-monitor.js +167 -0
- package/server/services/stripe.js +206 -192
- package/server/services/swarm.js +788 -788
- package/server/services/universal-scraper.js +662 -662
- package/server/services/verification.js +481 -481
- package/server/services/vision.js +1163 -1163
- package/server/services/wab-crypto.js +178 -0
- package/server/utils/cache.js +125 -125
- package/server/utils/migrate.js +81 -81
- package/server/utils/safe-fetch.js +228 -228
- package/server/utils/secureFields.js +50 -50
- package/server/ws.js +161 -161
- package/templates/artisan-marketplace.yaml +104 -104
- package/templates/book-price-scout.yaml +98 -98
- package/templates/electronics-price-tracker.yaml +108 -108
- package/templates/flight-deal-hunter.yaml +113 -113
- package/templates/freelancer-direct.yaml +116 -116
- package/templates/grocery-price-compare.yaml +93 -93
- package/templates/hotel-direct-booking.yaml +113 -113
- package/templates/local-services.yaml +98 -98
- package/templates/olive-oil-tunisia.yaml +88 -88
- package/templates/organic-farm-fresh.yaml +101 -101
- package/templates/restaurant-direct.yaml +97 -97
- package/templates/ring4/banking-sovereign.yaml +55 -0
- package/templates/ring4/ecommerce-sovereign.yaml +58 -0
- package/templates/ring4/healthcare-sovereign.yaml +60 -0
|
@@ -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
|
+
})();
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Dogfood demo: WAB uses its own SDK to discover itself.
|
|
4
|
+
*
|
|
5
|
+
* node examples/self-discovery.js # runs against webagentbridge.com
|
|
6
|
+
* node examples/self-discovery.js https://acme.com
|
|
7
|
+
*
|
|
8
|
+
* Demonstrates:
|
|
9
|
+
* • discover() — pulls /.well-known/wab.json (preferred) or falls back to
|
|
10
|
+
* JSON-LD / OpenGraph / sitemap.xml / robots.txt.
|
|
11
|
+
* • Trust validation via the published Ed25519 signature + DNS pin.
|
|
12
|
+
* • SSL fingerprint comparison.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { discover } = require('../sdk/auto-discovery');
|
|
16
|
+
const tls = require('node:tls');
|
|
17
|
+
const dns = require('node:dns').promises;
|
|
18
|
+
const crypto = require('node:crypto');
|
|
19
|
+
|
|
20
|
+
const target = process.argv[2] || 'https://www.webagentbridge.com';
|
|
21
|
+
|
|
22
|
+
function pad(s, n) { return String(s).padEnd(n); }
|
|
23
|
+
|
|
24
|
+
async function fetchTlsFingerprint(host) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
const sock = tls.connect({ host, port: 443, servername: host, rejectUnauthorized: false }, () => {
|
|
27
|
+
const cert = sock.getPeerCertificate(false);
|
|
28
|
+
sock.end();
|
|
29
|
+
const fp = (cert.fingerprint256 || '').replace(/:/g, '').toLowerCase();
|
|
30
|
+
resolve({ fp, valid_to: cert.valid_to, issuer: cert.issuer && cert.issuer.O });
|
|
31
|
+
});
|
|
32
|
+
sock.on('error', () => resolve({ fp: null }));
|
|
33
|
+
sock.setTimeout(8000, () => { sock.destroy(); resolve({ fp: null }); });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function dnsTxt(host) {
|
|
38
|
+
try { return (await dns.resolveTxt(`_wab.${host}`)).map((r) => r.join('')); }
|
|
39
|
+
catch { return []; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function verifyEd25519(payload, signatureB64, pkB64) {
|
|
43
|
+
try {
|
|
44
|
+
const pkRaw = Buffer.from(pkB64, 'base64');
|
|
45
|
+
const der = Buffer.concat([Buffer.from('302a300506032b6570032100', 'hex'), pkRaw]);
|
|
46
|
+
const pk = crypto.createPublicKey({ key: der, format: 'der', type: 'spki' });
|
|
47
|
+
const canon = canonicalJson(payload);
|
|
48
|
+
return crypto.verify(null, Buffer.from(canon, 'utf8'), pk, Buffer.from(signatureB64, 'base64'));
|
|
49
|
+
} catch (e) { return false; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function canonicalJson(obj) {
|
|
53
|
+
if (obj === null || typeof obj !== 'object') return JSON.stringify(obj);
|
|
54
|
+
if (Array.isArray(obj)) return '[' + obj.map(canonicalJson).join(',') + ']';
|
|
55
|
+
const keys = Object.keys(obj).sort();
|
|
56
|
+
return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalJson(obj[k])).join(',') + '}';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
(async () => {
|
|
60
|
+
console.log(`\n Web Agent Bridge — Self-Discovery Demo`);
|
|
61
|
+
console.log(` Target: ${target}\n`);
|
|
62
|
+
|
|
63
|
+
const env = await discover(target);
|
|
64
|
+
|
|
65
|
+
console.log(` ${pad('source', 14)} ${env.source}`);
|
|
66
|
+
console.log(` ${pad('site', 14)} ${env.site && env.site.name}`);
|
|
67
|
+
console.log(` ${pad('description', 14)} ${(env.site && env.site.description) || '—'}`);
|
|
68
|
+
console.log(` ${pad('actions', 14)} ${env.actions.length}`);
|
|
69
|
+
for (const a of env.actions.slice(0, 6)) console.log(` • ${a.name} — ${a.description || ''}`);
|
|
70
|
+
console.log(` ${pad('sitemap urls', 14)} ${env.sitemap.length}`);
|
|
71
|
+
|
|
72
|
+
// Signed wab.json branch
|
|
73
|
+
if (env.source === 'wab.json' && env.raw) {
|
|
74
|
+
const { payload, signature } = env.raw;
|
|
75
|
+
if (payload && signature) {
|
|
76
|
+
const host = new URL(target).hostname;
|
|
77
|
+
const txt = (await dnsTxt(host))[0] || (await dnsTxt(host.replace(/^www\./, '')))[0] || '';
|
|
78
|
+
const pkMatch = txt.match(/pk=ed25519:([A-Za-z0-9+/=]+)/);
|
|
79
|
+
const sslDnsMatch = txt.match(/ssl_thumbprint=([0-9a-f]+)/i);
|
|
80
|
+
const pkB64 = pkMatch ? pkMatch[1] : (payload.trust && payload.trust.pk || '').replace(/^ed25519:/, '');
|
|
81
|
+
const sigB64 = String(signature).replace(/^ed25519:/, '');
|
|
82
|
+
|
|
83
|
+
const sigOk = verifyEd25519(payload, sigB64, pkB64);
|
|
84
|
+
console.log(`\n Trust:`);
|
|
85
|
+
console.log(` ed25519 signature ${sigOk ? 'VALID ✓' : 'INVALID ✗'}`);
|
|
86
|
+
console.log(` dns pk source ${pkMatch ? '_wab DNS TXT' : 'wab.json'}`);
|
|
87
|
+
|
|
88
|
+
// SSL pin check
|
|
89
|
+
const live = await fetchTlsFingerprint(host);
|
|
90
|
+
const pinned = (payload.trust && payload.trust.ssl && payload.trust.ssl.thumbprint) || sslDnsMatch && sslDnsMatch[1];
|
|
91
|
+
if (live.fp) {
|
|
92
|
+
const match = pinned && live.fp.toLowerCase() === pinned.toLowerCase();
|
|
93
|
+
console.log(` ssl fingerprint ${match ? 'PINNED MATCH ✓' : (pinned ? 'MISMATCH ✗' : 'no pin')}`);
|
|
94
|
+
console.log(` live ${live.fp.slice(0, 32)}…`);
|
|
95
|
+
if (pinned) console.log(` pinned ${pinned.slice(0, 32)}…`);
|
|
96
|
+
if (live.valid_to) console.log(` valid_to ${live.valid_to}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
console.log(`\n No /.well-known/wab.json found — auto-discovery returned a normalized envelope.`);
|
|
101
|
+
if (env.products && env.products.length) console.log(` ${env.products.length} schema.org Product nodes detected`);
|
|
102
|
+
if (env.meta && env.meta.og && env.meta.og.site_name) console.log(` OpenGraph site_name: ${env.meta.og.site_name}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.log('');
|
|
106
|
+
})().catch((e) => { console.error('demo failed:', e); process.exit(1); });
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
# Shopify Hydrogen + WAB
|
|
2
|
-
|
|
3
|
-
This example wires WAB into a Hydrogen storefront client component and exposes practical commerce actions.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @web-agent-bridge/react
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Component
|
|
12
|
-
|
|
13
|
-
Create `app/components/WabHydrogenBridge.tsx`:
|
|
14
|
-
|
|
15
|
-
```tsx
|
|
16
|
-
'use client';
|
|
17
|
-
|
|
18
|
-
import { useEffect } from 'react';
|
|
19
|
-
import { WABProvider, useWAB, useWABAction } from '@web-agent-bridge/react';
|
|
20
|
-
|
|
21
|
-
function BridgeInner() {
|
|
22
|
-
const { ready, discover, instance } = useWAB({
|
|
23
|
-
name: 'Hydrogen Storefront',
|
|
24
|
-
actions: {
|
|
25
|
-
getCartCount: {
|
|
26
|
-
description: 'Return cart item count from cart badge',
|
|
27
|
-
run: () => {
|
|
28
|
-
const badge = document.querySelector('[data-cart-count], .cart-count');
|
|
29
|
-
const value = Number((badge?.textContent || '0').trim()) || 0;
|
|
30
|
-
return { count: value };
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
addFirstVisibleProductToCart: {
|
|
34
|
-
description: 'Click the first visible add-to-cart button on the page',
|
|
35
|
-
run: () => {
|
|
36
|
-
const btn = Array.from(document.querySelectorAll('button, a')).find((el) =>
|
|
37
|
-
/add\s*to\s*cart/i.test((el.textContent || '').trim())
|
|
38
|
-
);
|
|
39
|
-
if (!btn) return { success: false, error: 'No add-to-cart button found' };
|
|
40
|
-
(btn as HTMLElement).click();
|
|
41
|
-
return { success: true };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const { run: runGetCartCount, result: cartCount } = useWABAction<{ count: number }>('getCartCount', {
|
|
48
|
-
instance
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
if (!ready) return;
|
|
53
|
-
discover().then((doc) => console.log('WAB discover:', doc));
|
|
54
|
-
runGetCartCount().catch(() => {});
|
|
55
|
-
}, [ready, discover, runGetCartCount]);
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div>
|
|
59
|
-
<p>WAB status: {ready ? 'ready' : 'loading'}</p>
|
|
60
|
-
<p>Cart count: {cartCount?.count ?? 0}</p>
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export default function WabHydrogenBridge() {
|
|
66
|
-
return (
|
|
67
|
-
<WABProvider scriptSrc="https://webagentbridge.com/script/wab.min.js">
|
|
68
|
-
<BridgeInner />
|
|
69
|
-
</WABProvider>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Import this component inside any Hydrogen page so WAB is available to agents.
|
|
1
|
+
# Shopify Hydrogen + WAB
|
|
2
|
+
|
|
3
|
+
This example wires WAB into a Hydrogen storefront client component and exposes practical commerce actions.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @web-agent-bridge/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Component
|
|
12
|
+
|
|
13
|
+
Create `app/components/WabHydrogenBridge.tsx`:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
'use client';
|
|
17
|
+
|
|
18
|
+
import { useEffect } from 'react';
|
|
19
|
+
import { WABProvider, useWAB, useWABAction } from '@web-agent-bridge/react';
|
|
20
|
+
|
|
21
|
+
function BridgeInner() {
|
|
22
|
+
const { ready, discover, instance } = useWAB({
|
|
23
|
+
name: 'Hydrogen Storefront',
|
|
24
|
+
actions: {
|
|
25
|
+
getCartCount: {
|
|
26
|
+
description: 'Return cart item count from cart badge',
|
|
27
|
+
run: () => {
|
|
28
|
+
const badge = document.querySelector('[data-cart-count], .cart-count');
|
|
29
|
+
const value = Number((badge?.textContent || '0').trim()) || 0;
|
|
30
|
+
return { count: value };
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
addFirstVisibleProductToCart: {
|
|
34
|
+
description: 'Click the first visible add-to-cart button on the page',
|
|
35
|
+
run: () => {
|
|
36
|
+
const btn = Array.from(document.querySelectorAll('button, a')).find((el) =>
|
|
37
|
+
/add\s*to\s*cart/i.test((el.textContent || '').trim())
|
|
38
|
+
);
|
|
39
|
+
if (!btn) return { success: false, error: 'No add-to-cart button found' };
|
|
40
|
+
(btn as HTMLElement).click();
|
|
41
|
+
return { success: true };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const { run: runGetCartCount, result: cartCount } = useWABAction<{ count: number }>('getCartCount', {
|
|
48
|
+
instance
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!ready) return;
|
|
53
|
+
discover().then((doc) => console.log('WAB discover:', doc));
|
|
54
|
+
runGetCartCount().catch(() => {});
|
|
55
|
+
}, [ready, discover, runGetCartCount]);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div>
|
|
59
|
+
<p>WAB status: {ready ? 'ready' : 'loading'}</p>
|
|
60
|
+
<p>Cart count: {cartCount?.count ?? 0}</p>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default function WabHydrogenBridge() {
|
|
66
|
+
return (
|
|
67
|
+
<WABProvider scriptSrc="https://webagentbridge.com/script/wab.min.js">
|
|
68
|
+
<BridgeInner />
|
|
69
|
+
</WABProvider>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Import this component inside any Hydrogen page so WAB is available to agents.
|