web-agent-bridge 3.4.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 -84
- package/README.ar.md +1563 -1304
- package/README.md +137 -298
- package/bin/agent-runner.js +474 -474
- package/bin/cli.js +237 -237
- package/bin/wab-init.js +244 -223
- package/bin/wab.js +80 -80
- package/examples/azure-dns-wab.js +83 -83
- package/examples/bidi-agent.js +119 -119
- package/examples/cloudflare-wab-dns.js +121 -121
- package/examples/cpanel-wab-dns.js +114 -114
- package/examples/cross-site-agent.js +91 -91
- package/examples/dns-discovery-agent.js +166 -166
- package/examples/gcp-dns-wab.js +76 -76
- package/examples/governance-agent.js +169 -169
- package/examples/mcp-agent.js +94 -94
- package/examples/next-app-router/README.md +44 -44
- package/examples/plesk-wab-dns.js +103 -103
- package/examples/puppeteer-agent.js +108 -108
- package/examples/route53-wab-dns.js +144 -144
- package/examples/saas-dashboard/README.md +55 -55
- package/examples/safe-mode-agent.js +96 -96
- 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 -74
- package/examples/wab-verify.js +60 -60
- 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 -28
- package/public/activate.html +448 -368
- package/public/adopt.html +236 -0
- package/public/adoption-metrics.html +188 -188
- 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 -289
- package/public/browser.html +486 -486
- package/public/cloudflare-integration.html +380 -380
- package/public/commander-dashboard.html +243 -243
- package/public/cookies.html +210 -210
- package/public/cpanel-integration.html +398 -398
- package/public/css/agent-workspace.css +1713 -1713
- package/public/css/premium.css +317 -317
- package/public/css/styles.css +1401 -1263
- package/public/dashboard-shieldlink.html +295 -0
- package/public/dashboard.html +711 -707
- package/public/dns.html +436 -436
- package/public/docs.html +588 -588
- 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 -318
- package/public/governance.ar.html +70 -0
- package/public/governance.html +69 -0
- package/public/growth.html +465 -465
- package/public/index.html +1372 -1266
- package/public/integrations.html +556 -556
- package/public/js/activate.js +449 -145
- package/public/js/agent-workspace.js +1740 -1740
- package/public/js/auth-nav.js +117 -65
- package/public/js/auth-redirect.js +12 -12
- package/public/js/cookie-consent.js +56 -56
- package/public/js/dns.js +438 -438
- 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 -669
- 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 -375
- 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 -172
- package/public/provider-sandbox.html +134 -134
- package/public/providers.html +359 -359
- package/public/refusals.html +172 -0
- package/public/register.html +105 -105
- package/public/registrar-integrations.html +141 -141
- package/public/ring4.html +292 -0
- package/public/robots.txt +99 -99
- package/public/route53-integration.html +531 -531
- 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 -231
- package/public/sitemap.xml +13 -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 -200
- package/public/wab-truth.html +375 -0
- package/public/wab-vs-protocols.html +210 -210
- package/public/whitepaper.html +449 -449
- 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 -288
- package/sdk/commander.js +262 -262
- package/sdk/governance.js +262 -262
- package/sdk/index.d.ts +464 -464
- package/sdk/index.js +649 -649
- package/sdk/multi-agent.js +318 -318
- package/sdk/safe-mode.js +221 -221
- 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 -670
- 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 -106
- package/server/migrations/008_plans.sql +144 -144
- package/server/migrations/009_shieldqr.sql +30 -30
- package/server/migrations/010_extended_trust.sql +33 -33
- 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 -740
- 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 -76
- package/server/routes/admin-premium.js +674 -673
- package/server/routes/admin-shieldlink.js +137 -0
- package/server/routes/admin-shieldqr.js +90 -90
- package/server/routes/admin-trust-monitor.js +139 -83
- package/server/routes/admin.js +550 -549
- 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 -57
- 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 -2348
- 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 -208
- 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 -33
- package/server/routes/premium-v2.js +686 -686
- package/server/routes/premium.js +724 -724
- package/server/routes/providers.js +650 -650
- 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 -88
- 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 -233
- package/server/services/fairness-engine.js +409 -0
- package/server/services/fairness.js +420 -0
- package/server/services/governance.js +466 -466
- 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 -214
- package/server/services/plugins.js +771 -771
- package/server/services/price-intelligence.js +566 -566
- package/server/services/price-shield.js +1137 -1137
- package/server/services/provider-clients.js +740 -740
- 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 -322
- package/server/services/sovereign-shield.js +542 -542
- package/server/services/ssl-ct-monitor.js +224 -0
- package/server/services/ssl-inspector.js +42 -42
- package/server/services/ssl-monitor.js +167 -167
- package/server/services/stripe.js +206 -205
- 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 -178
- 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,236 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" dir="ltr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Agent-Driven Adoption — Web Agent Bridge</title>
|
|
7
|
+
<meta name="description" content="Drop in a URL; our adoption agent crafts a ready-to-deploy wab.json, DNS TXT record, and platform snippets in seconds.">
|
|
8
|
+
<link rel="canonical" href="https://www.webagentbridge.com/adopt">
|
|
9
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/images/wab-logo-32.png">
|
|
10
|
+
<link rel="icon" type="image/x-icon" href="/images/favicon.ico">
|
|
11
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png">
|
|
12
|
+
<meta property="og:title" content="Agent-Driven Adoption — Web Agent Bridge">
|
|
13
|
+
<meta property="og:description" content="Paste a URL — get a deployable wab.json, DNS TXT, and platform snippets instantly.">
|
|
14
|
+
<meta property="og:image" content="https://www.webagentbridge.com/images/og-image.png">
|
|
15
|
+
<meta property="og:type" content="website">
|
|
16
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
17
|
+
<style>
|
|
18
|
+
:root{--bg:#0a0e1a;--panel:#0f1626;--panel2:#131c30;--border:#1f2a44;--text:#e8eeff;--muted:#8a94b0;--accent:#7c5cff;--accent2:#22d3ee;--ok:#22c55e;--warn:#f59e0b;--err:#ef4444}
|
|
19
|
+
*{box-sizing:border-box}
|
|
20
|
+
body{margin:0;background:var(--bg);color:var(--text);font:15px/1.55 Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;min-height:100vh}
|
|
21
|
+
a{color:var(--accent2)}
|
|
22
|
+
header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;gap:16px}
|
|
23
|
+
header .brand{display:flex;align-items:center;gap:10px;font-weight:800}
|
|
24
|
+
header .brand .ic{width:30px;height:30px;border-radius:8px;background:linear-gradient(135deg,var(--accent),var(--accent2));display:grid;place-items:center;color:#0a0e1a;font-weight:900}
|
|
25
|
+
main{max-width:1080px;margin:0 auto;padding:32px 20px 80px}
|
|
26
|
+
h1{font-size:34px;margin:0 0 8px;letter-spacing:-.02em}
|
|
27
|
+
.lede{color:var(--muted);max-width:720px;margin:0 0 28px}
|
|
28
|
+
.card{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:20px}
|
|
29
|
+
.card + .card{margin-top:18px}
|
|
30
|
+
.row{display:flex;gap:10px;flex-wrap:wrap}
|
|
31
|
+
input[type=url],input[type=text]{flex:1;min-width:260px;background:var(--panel2);border:1px solid var(--border);color:var(--text);padding:12px 14px;border-radius:10px;font:inherit;outline:none}
|
|
32
|
+
input[type=url]:focus,input[type=text]:focus{border-color:var(--accent)}
|
|
33
|
+
button.btn{background:linear-gradient(135deg,var(--accent),var(--accent2));color:#0a0e1a;border:0;padding:12px 18px;border-radius:10px;font-weight:700;cursor:pointer;font:inherit}
|
|
34
|
+
button.btn:disabled{opacity:.6;cursor:not-allowed}
|
|
35
|
+
button.ghost{background:transparent;border:1px solid var(--border);color:var(--text);padding:8px 12px;border-radius:8px;cursor:pointer;font:inherit;font-size:13px}
|
|
36
|
+
button.ghost:hover{border-color:var(--accent)}
|
|
37
|
+
pre{background:#070b15;border:1px solid var(--border);border-radius:10px;padding:14px;overflow:auto;font:13px/1.5 'JetBrains Mono',ui-monospace,monospace;color:#cfe7ff;max-height:520px}
|
|
38
|
+
.pill{display:inline-block;padding:3px 10px;border-radius:999px;font-size:12px;font-weight:600;background:var(--panel2);border:1px solid var(--border);color:var(--muted)}
|
|
39
|
+
.pill.ok{background:rgba(34,197,94,.12);color:#86efac;border-color:rgba(34,197,94,.3)}
|
|
40
|
+
.pill.warn{background:rgba(245,158,11,.12);color:#fcd34d;border-color:rgba(245,158,11,.3)}
|
|
41
|
+
.pill.err{background:rgba(239,68,68,.12);color:#fca5a5;border-color:rgba(239,68,68,.3)}
|
|
42
|
+
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
|
|
43
|
+
.kv{background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:12px}
|
|
44
|
+
.kv .k{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}
|
|
45
|
+
.kv .v{margin-top:4px;font-weight:600;word-break:break-all}
|
|
46
|
+
.tabs{display:flex;gap:6px;border-bottom:1px solid var(--border);margin-bottom:14px;flex-wrap:wrap}
|
|
47
|
+
.tabs button{background:transparent;border:0;color:var(--muted);padding:10px 14px;border-bottom:2px solid transparent;cursor:pointer;font:inherit;font-weight:600}
|
|
48
|
+
.tabs button.active{color:var(--text);border-bottom-color:var(--accent)}
|
|
49
|
+
.panel-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
|
|
50
|
+
.panel-head h3{margin:0;font-size:15px}
|
|
51
|
+
.muted{color:var(--muted)}
|
|
52
|
+
.hide{display:none}
|
|
53
|
+
.err-box{background:rgba(239,68,68,.08);border:1px solid rgba(239,68,68,.3);color:#fca5a5;padding:12px 14px;border-radius:10px}
|
|
54
|
+
.footnote{color:var(--muted);font-size:12px;margin-top:18px}
|
|
55
|
+
code.inline{background:var(--panel2);padding:2px 6px;border-radius:6px;border:1px solid var(--border);font:12px 'JetBrains Mono',monospace}
|
|
56
|
+
.links{margin-top:8px;display:flex;gap:14px;flex-wrap:wrap;font-size:13px}
|
|
57
|
+
.spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#0a0e1a;border-radius:50%;animation:spin .8s linear infinite;vertical-align:-2px;margin-right:6px}
|
|
58
|
+
@keyframes spin{to{transform:rotate(360deg)}}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<header>
|
|
63
|
+
<a href="/" class="brand" style="text-decoration:none;color:inherit">
|
|
64
|
+
<img src="/images/wab-logo-64.png" alt="WAB" width="32" height="32" style="width:32px;height:32px;border-radius:8px;display:block"><div>Web Agent Bridge</div>
|
|
65
|
+
</a>
|
|
66
|
+
<div class="links">
|
|
67
|
+
<a href="/check">/check</a>
|
|
68
|
+
<a href="/docs">Docs</a>
|
|
69
|
+
<a href="/dashboard">Dashboard</a>
|
|
70
|
+
</div>
|
|
71
|
+
</header>
|
|
72
|
+
|
|
73
|
+
<main>
|
|
74
|
+
<h1>Agent-Driven Adoption</h1>
|
|
75
|
+
<p class="lede">Paste a public URL. Our adoption agent inspects the site (HTML, sitemap, robots, JSON-LD, TLS) and drafts a deployable <code class="inline">wab.json</code>, DNS TXT record, and platform snippets — all in one shot.</p>
|
|
76
|
+
|
|
77
|
+
<div class="card">
|
|
78
|
+
<form id="form" class="row">
|
|
79
|
+
<input id="url" type="url" placeholder="https://example.com" required autocomplete="off" autofocus>
|
|
80
|
+
<button class="btn" id="go" type="submit">Analyze</button>
|
|
81
|
+
</form>
|
|
82
|
+
<div class="footnote">Public sites only. The agent fetches HTML and TLS metadata; it never stores your data.</div>
|
|
83
|
+
<div id="error" class="err-box hide" style="margin-top:14px"></div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div id="results" class="hide">
|
|
87
|
+
<div class="card">
|
|
88
|
+
<div class="panel-head">
|
|
89
|
+
<h3>Detected</h3>
|
|
90
|
+
<span id="ok-pill" class="pill ok hide">analysis complete</span>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="grid" id="kv"></div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div class="card">
|
|
96
|
+
<div class="panel-head">
|
|
97
|
+
<h3>Generated <code class="inline">wab.json</code></h3>
|
|
98
|
+
<div>
|
|
99
|
+
<button class="ghost" data-copy="#wabjson">Copy</button>
|
|
100
|
+
<button class="ghost" id="dl-btn">Download</button>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
<pre id="wabjson"></pre>
|
|
104
|
+
<div class="footnote">Place this file at <code class="inline">/.well-known/wab.json</code> on your domain (or use a snippet below).</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="card">
|
|
108
|
+
<div class="panel-head">
|
|
109
|
+
<h3>DNS TXT record</h3>
|
|
110
|
+
<button class="ghost" data-copy="#dns">Copy</button>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="grid">
|
|
113
|
+
<div class="kv"><div class="k">Type</div><div class="v">TXT</div></div>
|
|
114
|
+
<div class="kv"><div class="k">Name / Host</div><div class="v" id="dns-name">_wab</div></div>
|
|
115
|
+
<div class="kv"><div class="k">TTL</div><div class="v">300</div></div>
|
|
116
|
+
</div>
|
|
117
|
+
<pre id="dns" style="margin-top:10px"></pre>
|
|
118
|
+
<div class="footnote">Add this record at your DNS provider (Cloudflare, Route53, GoDaddy, etc.) so AI agents can discover your endpoint without HTML.</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="card">
|
|
122
|
+
<div class="panel-head"><h3>Deploy snippets</h3></div>
|
|
123
|
+
<div class="tabs" id="tabs"></div>
|
|
124
|
+
<pre id="snippet"></pre>
|
|
125
|
+
<div class="footnote" id="snippet-install"></div>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div class="footnote">
|
|
130
|
+
Powered by the open Web Agent Bridge protocol. CLI alternative:
|
|
131
|
+
<code class="inline">npx wab-init --auto-from https://example.com</code>
|
|
132
|
+
</div>
|
|
133
|
+
</main>
|
|
134
|
+
|
|
135
|
+
<script>
|
|
136
|
+
const $ = (s)=>document.querySelector(s);
|
|
137
|
+
const form = $('#form'), urlIn = $('#url'), btn = $('#go');
|
|
138
|
+
const results = $('#results'), errBox = $('#error');
|
|
139
|
+
let lastSnippets = {}, lastUrl = '';
|
|
140
|
+
|
|
141
|
+
function setError(msg){ errBox.textContent = msg; errBox.classList.remove('hide'); results.classList.add('hide'); }
|
|
142
|
+
function clearError(){ errBox.classList.add('hide'); errBox.textContent=''; }
|
|
143
|
+
|
|
144
|
+
function copy(text){
|
|
145
|
+
navigator.clipboard.writeText(text).then(()=>{
|
|
146
|
+
// brief feedback
|
|
147
|
+
}).catch(()=>{});
|
|
148
|
+
}
|
|
149
|
+
document.addEventListener('click',(e)=>{
|
|
150
|
+
const t = e.target.closest('[data-copy]');
|
|
151
|
+
if(!t) return;
|
|
152
|
+
const sel = t.getAttribute('data-copy');
|
|
153
|
+
const el = document.querySelector(sel);
|
|
154
|
+
if(el) copy(el.textContent);
|
|
155
|
+
const orig = t.textContent; t.textContent='Copied!'; setTimeout(()=>t.textContent=orig,1100);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
function renderKV(parent, items){
|
|
159
|
+
parent.innerHTML = items.map(([k,v])=>`<div class="kv"><div class="k">${k}</div><div class="v">${v}</div></div>`).join('');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function renderTabs(snippets){
|
|
163
|
+
const tabs = $('#tabs'); tabs.innerHTML='';
|
|
164
|
+
const keys = Object.keys(snippets).filter(k => k !== 'inline_wab_json' && typeof snippets[k] === 'object');
|
|
165
|
+
if(!keys.length){ $('#snippet').textContent=''; $('#snippet-install').textContent=''; return; }
|
|
166
|
+
keys.forEach((k,i)=>{
|
|
167
|
+
const b = document.createElement('button');
|
|
168
|
+
b.textContent = (snippets[k] && snippets[k].title) || k;
|
|
169
|
+
if(i===0) b.classList.add('active');
|
|
170
|
+
b.addEventListener('click',()=>{
|
|
171
|
+
tabs.querySelectorAll('button').forEach(x=>x.classList.remove('active'));
|
|
172
|
+
b.classList.add('active');
|
|
173
|
+
showSnippet(k);
|
|
174
|
+
});
|
|
175
|
+
tabs.appendChild(b);
|
|
176
|
+
});
|
|
177
|
+
showSnippet(keys[0]);
|
|
178
|
+
}
|
|
179
|
+
function showSnippet(k){
|
|
180
|
+
const s = lastSnippets[k] || {};
|
|
181
|
+
const parts = [];
|
|
182
|
+
if(s.instructions) parts.push(s.instructions);
|
|
183
|
+
if(s.file) parts.push('// File: ' + s.file);
|
|
184
|
+
if(s.content) parts.push(s.content);
|
|
185
|
+
if(s.toml) parts.push('# netlify.toml\n' + s.toml);
|
|
186
|
+
if(s.env) parts.push('# wrangler.toml [vars]\n' + Object.entries(s.env).map(([k,v])=>`${k} = ${JSON.stringify(v)}`).join('\n'));
|
|
187
|
+
if(s.command) parts.push('$ ' + s.command);
|
|
188
|
+
$('#snippet').textContent = parts.join('\n\n') || JSON.stringify(s, null, 2);
|
|
189
|
+
$('#snippet-install').innerHTML = s.install ? `Install: <code class="inline">${s.install}</code>` : '';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
form.addEventListener('submit', async (e)=>{
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
clearError();
|
|
195
|
+
const url = urlIn.value.trim();
|
|
196
|
+
if(!url) return;
|
|
197
|
+
btn.disabled = true; btn.innerHTML = '<span class="spinner"></span>Analyzing…';
|
|
198
|
+
try{
|
|
199
|
+
const r = await fetch('/api/adopt/suggest?url='+encodeURIComponent(url));
|
|
200
|
+
const j = await r.json();
|
|
201
|
+
if(!r.ok || !j || j.error){ throw new Error((j && j.error) || ('HTTP '+r.status)); }
|
|
202
|
+
lastUrl = url;
|
|
203
|
+
lastSnippets = j.deploy || {};
|
|
204
|
+
const detected = [
|
|
205
|
+
['Site', (j.wab_json && j.wab_json.site) || j.host || '—'],
|
|
206
|
+
['Stack', (j.stack && j.stack.type) || 'unknown'],
|
|
207
|
+
['Actions', String((j.wab_json && j.wab_json.actions ? j.wab_json.actions.length : 0))],
|
|
208
|
+
['SSL fingerprint', j.ssl && j.ssl.fingerprint_sha256 ? (j.ssl.fingerprint_sha256.slice(0,32)+'…') : '—'],
|
|
209
|
+
['Source', (j.env_summary && j.env_summary.source) || '—'],
|
|
210
|
+
['Signals', (j.stack && j.stack.signals && j.stack.signals.length) ? j.stack.signals.join(', ') : '—']
|
|
211
|
+
];
|
|
212
|
+
renderKV($('#kv'), detected);
|
|
213
|
+
$('#ok-pill').classList.remove('hide');
|
|
214
|
+
$('#wabjson').textContent = JSON.stringify(j.wab_json, null, 2);
|
|
215
|
+
$('#dns-name').textContent = (j.dns_txt && j.dns_txt.name) || '_wab';
|
|
216
|
+
$('#dns').textContent = (j.dns_txt && j.dns_txt.value) || '';
|
|
217
|
+
renderTabs(lastSnippets);
|
|
218
|
+
results.classList.remove('hide');
|
|
219
|
+
}catch(err){
|
|
220
|
+
setError('Could not analyze: '+(err.message||err));
|
|
221
|
+
}finally{
|
|
222
|
+
btn.disabled = false; btn.textContent='Analyze';
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
$('#dl-btn').addEventListener('click',()=>{
|
|
227
|
+
if(!lastUrl) return;
|
|
228
|
+
window.location = '/api/adopt/wab.json?url='+encodeURIComponent(lastUrl);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// auto-fill from ?url=
|
|
232
|
+
const params = new URLSearchParams(location.search);
|
|
233
|
+
if(params.get('url')){ urlIn.value = params.get('url'); form.requestSubmit(); }
|
|
234
|
+
</script>
|
|
235
|
+
</body>
|
|
236
|
+
</html>
|
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en" dir="ltr">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>WAB Adoption Metrics — Live Dashboard</title>
|
|
7
|
-
<meta name="description" content="Live adoption metrics for the WAB DNS Discovery protocol: domain coverage, readiness rates, value scores, use-case distribution, and trend data over 30 days.">
|
|
8
|
-
<link rel="stylesheet" href="/css/styles.css?v=3.3.0">
|
|
9
|
-
<style>
|
|
10
|
-
body { background:#081123; color:#e8efff; }
|
|
11
|
-
.hero { padding:100px 20px 24px; text-align:center; }
|
|
12
|
-
.hero h1 { font-size:clamp(1.8rem,4vw,2.6rem); margin-bottom:6px; }
|
|
13
|
-
.hero p { color:#9eb1d8; max-width:820px; margin:0 auto; }
|
|
14
|
-
.wrap { max-width:1180px; margin:0 auto; padding:0 18px 70px; }
|
|
15
|
-
.kpis { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:12px; margin-bottom:18px; }
|
|
16
|
-
.kpi { background:linear-gradient(180deg,rgba(17,24,39,.92),rgba(10,16,30,.96)); border:1px solid rgba(148,163,184,.2); border-radius:14px; padding:14px; text-align:center; }
|
|
17
|
-
.kpi .v { font-size:1.7rem; font-weight:800; color:#fcd34d; line-height:1.1; }
|
|
18
|
-
.kpi .l { font-size:.78rem; color:#9eb1d8; margin-top:6px; text-transform:uppercase; letter-spacing:.6px; }
|
|
19
|
-
.panel { background:linear-gradient(180deg,rgba(17,24,39,.92),rgba(10,16,30,.96)); border:1px solid rgba(148,163,184,.2); border-radius:14px; padding:16px; margin-bottom:16px; }
|
|
20
|
-
.panel h3 { margin:0 0 10px; color:#fcd34d; font-size:1rem; }
|
|
21
|
-
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:14px; }
|
|
22
|
-
@media (max-width:760px) { .grid2 { grid-template-columns:1fr; } }
|
|
23
|
-
table { width:100%; border-collapse:collapse; font-size:.84rem; }
|
|
24
|
-
th, td { padding:8px 10px; text-align:left; border-bottom:1px solid rgba(148,163,184,.14); }
|
|
25
|
-
th { color:#a8b7d7; font-weight:600; font-size:.74rem; text-transform:uppercase; letter-spacing:.5px; }
|
|
26
|
-
td.num { text-align:right; font-variant-numeric:tabular-nums; color:#c4b5fd; }
|
|
27
|
-
.bar { display:inline-block; height:10px; background:linear-gradient(90deg,#f59e0b,#b45309); border-radius:6px; vertical-align:middle; }
|
|
28
|
-
.pill { display:inline-block; padding:2px 8px; border-radius:999px; background:#1f2937; color:#a8b7d7; font-size:.72rem; }
|
|
29
|
-
.pill.ok { background:#064e3b; color:#a7f3d0; }
|
|
30
|
-
.pill.warn { background:#78350f; color:#fcd34d; }
|
|
31
|
-
.empty { color:#7a8db0; font-size:.84rem; padding:14px; text-align:center; }
|
|
32
|
-
.meta { color:#7a8db0; font-size:.78rem; text-align:right; margin-bottom:8px; }
|
|
33
|
-
.spark { display:flex; gap:2px; align-items:flex-end; height:60px; padding-top:6px; }
|
|
34
|
-
.spark .b { flex:1; background:#fcd34d; min-height:2px; border-radius:2px 2px 0 0; }
|
|
35
|
-
.spark .b:hover { background:#fef3c7; }
|
|
36
|
-
.day-row { display:flex; align-items:center; gap:8px; font-size:.78rem; padding:3px 0; }
|
|
37
|
-
.day-row .d { width:90px; color:#9eb1d8; font-variant-numeric:tabular-nums; }
|
|
38
|
-
.day-row .n { width:38px; text-align:right; color:#c4b5fd; font-variant-numeric:tabular-nums; }
|
|
39
|
-
.day-row .b-track { flex:1; background:rgba(148,163,184,.1); border-radius:4px; overflow:hidden; height:8px; }
|
|
40
|
-
.day-row .b-fill { height:100%; background:linear-gradient(90deg,#f59e0b,#fcd34d); }
|
|
41
|
-
a { color:#fcd34d; }
|
|
42
|
-
</style>
|
|
43
|
-
</head>
|
|
44
|
-
<body>
|
|
45
|
-
<section class="hero">
|
|
46
|
-
<h1>WAB Adoption Metrics</h1>
|
|
47
|
-
<p>Live dashboard powered by every <code>/api/discovery/usage-proof</code> run. Tracks domain coverage, agent readiness, end-to-end value, and use-case distribution across the WAB DNS Discovery protocol.</p>
|
|
48
|
-
</section>
|
|
49
|
-
|
|
50
|
-
<div class="wrap">
|
|
51
|
-
<div class="meta" id="meta">Loading…</div>
|
|
52
|
-
|
|
53
|
-
<div class="kpis" id="kpis"></div>
|
|
54
|
-
|
|
55
|
-
<div class="grid2">
|
|
56
|
-
<div class="panel">
|
|
57
|
-
<h3>Daily activity (last 30 days)</h3>
|
|
58
|
-
<div id="daily" class="empty">Loading…</div>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<div class="panel">
|
|
62
|
-
<h3>Top use-cases</h3>
|
|
63
|
-
<div id="useCases" class="empty">Loading…</div>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
<div class="grid2">
|
|
68
|
-
<div class="panel">
|
|
69
|
-
<h3>Top domains</h3>
|
|
70
|
-
<div id="topDomains" class="empty">Loading…</div>
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
<div class="panel">
|
|
74
|
-
<h3>Recent runs</h3>
|
|
75
|
-
<div id="recent" class="empty">Loading…</div>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
<div class="panel" style="text-align:center;color:#9eb1d8;font-size:.86rem;">
|
|
80
|
-
Want your domain on this dashboard? Run any <a href="/dns">WAB DNS</a> usage proof —
|
|
81
|
-
verify cryptographic trust at <a href="/wab-trust">/wab-trust</a> —
|
|
82
|
-
or one-click enable via
|
|
83
|
-
<a href="/cloudflare-integration">Cloudflare</a>,
|
|
84
|
-
<a href="/route53-integration">Route 53</a>,
|
|
85
|
-
<a href="/azure-dns-integration">Azure DNS</a>,
|
|
86
|
-
<a href="/gcp-dns-integration">Google Cloud DNS</a>,
|
|
87
|
-
<a href="/cpanel-integration">cPanel</a>,
|
|
88
|
-
<a href="/plesk-integration">Plesk</a>, or
|
|
89
|
-
<a href="/registrar-integrations">GoDaddy / Namecheap</a>.
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
<script>
|
|
94
|
-
const fmt = (n, d = 0) => Number(n || 0).toLocaleString(undefined, { maximumFractionDigits: d });
|
|
95
|
-
const pct = (n) => (Number(n || 0) * 100).toFixed(1) + '%';
|
|
96
|
-
|
|
97
|
-
function kpi(label, value) {
|
|
98
|
-
return `<div class="kpi"><div class="v">${value}</div><div class="l">${label}</div></div>`;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function renderDaily(rows) {
|
|
102
|
-
if (!rows || !rows.length) { return '<div class="empty">No runs in the last 30 days yet.</div>'; }
|
|
103
|
-
const max = Math.max(...rows.map(r => r.runs), 1);
|
|
104
|
-
return rows.map(r => `
|
|
105
|
-
<div class="day-row">
|
|
106
|
-
<div class="d">${r.day}</div>
|
|
107
|
-
<div class="b-track"><div class="b-fill" style="width:${(r.runs / max) * 100}%"></div></div>
|
|
108
|
-
<div class="n">${r.runs}</div>
|
|
109
|
-
</div>
|
|
110
|
-
`).join('');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function renderUseCases(rows) {
|
|
114
|
-
if (!rows || !rows.length) { return '<div class="empty">No use-case data yet.</div>'; }
|
|
115
|
-
const max = Math.max(...rows.map(r => r.runs), 1);
|
|
116
|
-
return `<table>
|
|
117
|
-
<thead><tr><th>Use case</th><th class="num">Runs</th><th class="num">Ready</th><th class="num">Avg score</th></tr></thead>
|
|
118
|
-
<tbody>${rows.map(r => `
|
|
119
|
-
<tr>
|
|
120
|
-
<td>${r.use_case || '—'}</td>
|
|
121
|
-
<td class="num">${fmt(r.runs)}</td>
|
|
122
|
-
<td class="num">${fmt(r.ready)}</td>
|
|
123
|
-
<td class="num">${fmt(r.avg_value_score, 2)}</td>
|
|
124
|
-
</tr>
|
|
125
|
-
`).join('')}</tbody>
|
|
126
|
-
</table>`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function renderTopDomains(rows) {
|
|
130
|
-
if (!rows || !rows.length) { return '<div class="empty">No domains tracked yet.</div>'; }
|
|
131
|
-
return `<table>
|
|
132
|
-
<thead><tr><th>Domain</th><th class="num">Runs</th><th class="num">Ready</th><th class="num">Avg score</th></tr></thead>
|
|
133
|
-
<tbody>${rows.map(r => `
|
|
134
|
-
<tr>
|
|
135
|
-
<td>${r.domain}</td>
|
|
136
|
-
<td class="num">${fmt(r.runs)}</td>
|
|
137
|
-
<td class="num">${fmt(r.ready)}</td>
|
|
138
|
-
<td class="num">${fmt(r.avg_value_score, 2)}</td>
|
|
139
|
-
</tr>
|
|
140
|
-
`).join('')}</tbody>
|
|
141
|
-
</table>`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function renderRecent(rows) {
|
|
145
|
-
if (!rows || !rows.length) { return '<div class="empty">No recent runs.</div>'; }
|
|
146
|
-
return `<table>
|
|
147
|
-
<thead><tr><th>Domain</th><th>Use case</th><th class="num">Score</th><th class="num">When</th></tr></thead>
|
|
148
|
-
<tbody>${rows.map(r => `
|
|
149
|
-
<tr>
|
|
150
|
-
<td>${r.domain}</td>
|
|
151
|
-
<td>${r.preferred_use_case || '—'} ${r.readiness_ok ? '<span class="pill ok">ready</span>' : '<span class="pill warn">pending</span>'}</td>
|
|
152
|
-
<td class="num">${fmt(r.value_score, 2)}</td>
|
|
153
|
-
<td class="num">${r.created_at ? r.created_at.replace('T',' ').slice(0,16) : ''}</td>
|
|
154
|
-
</tr>
|
|
155
|
-
`).join('')}</tbody>
|
|
156
|
-
</table>`;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async function load() {
|
|
160
|
-
const r = await fetch('/api/discovery/adoption-metrics');
|
|
161
|
-
if (!r.ok) {
|
|
162
|
-
document.getElementById('meta').textContent = 'Failed to load metrics: HTTP ' + r.status;
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
const data = await r.json();
|
|
166
|
-
const t = data.totals || {};
|
|
167
|
-
document.getElementById('kpis').innerHTML = [
|
|
168
|
-
kpi('Total runs', fmt(t.total_runs)),
|
|
169
|
-
kpi('Unique domains', fmt(t.unique_domains)),
|
|
170
|
-
kpi('Readiness rate', pct(t.readiness_rate)),
|
|
171
|
-
kpi('Avg value score', fmt(t.avg_value_score, 2)),
|
|
172
|
-
kpi('Avg end-to-end', fmt(t.avg_end_to_end_ms) + ' ms'),
|
|
173
|
-
kpi('Exec success rate', pct(t.success_rate)),
|
|
174
|
-
].join('');
|
|
175
|
-
|
|
176
|
-
document.getElementById('daily').innerHTML = renderDaily(data.daily_last_30);
|
|
177
|
-
document.getElementById('useCases').innerHTML = renderUseCases(data.by_use_case);
|
|
178
|
-
document.getElementById('topDomains').innerHTML = renderTopDomains(data.top_domains);
|
|
179
|
-
document.getElementById('recent').innerHTML = renderRecent(data.recent_runs);
|
|
180
|
-
document.getElementById('meta').textContent = 'Live · generated ' + (data.generated_at || '').replace('T',' ').slice(0,19) + ' UTC';
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
load().catch(err => {
|
|
184
|
-
document.getElementById('meta').textContent = 'Error loading metrics: ' + err.message;
|
|
185
|
-
});
|
|
186
|
-
</script>
|
|
187
|
-
</body>
|
|
188
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" dir="ltr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>WAB Adoption Metrics — Live Dashboard</title>
|
|
7
|
+
<meta name="description" content="Live adoption metrics for the WAB DNS Discovery protocol: domain coverage, readiness rates, value scores, use-case distribution, and trend data over 30 days.">
|
|
8
|
+
<link rel="stylesheet" href="/css/styles.css?v=3.3.0">
|
|
9
|
+
<style>
|
|
10
|
+
body { background:#081123; color:#e8efff; }
|
|
11
|
+
.hero { padding:100px 20px 24px; text-align:center; }
|
|
12
|
+
.hero h1 { font-size:clamp(1.8rem,4vw,2.6rem); margin-bottom:6px; }
|
|
13
|
+
.hero p { color:#9eb1d8; max-width:820px; margin:0 auto; }
|
|
14
|
+
.wrap { max-width:1180px; margin:0 auto; padding:0 18px 70px; }
|
|
15
|
+
.kpis { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:12px; margin-bottom:18px; }
|
|
16
|
+
.kpi { background:linear-gradient(180deg,rgba(17,24,39,.92),rgba(10,16,30,.96)); border:1px solid rgba(148,163,184,.2); border-radius:14px; padding:14px; text-align:center; }
|
|
17
|
+
.kpi .v { font-size:1.7rem; font-weight:800; color:#fcd34d; line-height:1.1; }
|
|
18
|
+
.kpi .l { font-size:.78rem; color:#9eb1d8; margin-top:6px; text-transform:uppercase; letter-spacing:.6px; }
|
|
19
|
+
.panel { background:linear-gradient(180deg,rgba(17,24,39,.92),rgba(10,16,30,.96)); border:1px solid rgba(148,163,184,.2); border-radius:14px; padding:16px; margin-bottom:16px; }
|
|
20
|
+
.panel h3 { margin:0 0 10px; color:#fcd34d; font-size:1rem; }
|
|
21
|
+
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:14px; }
|
|
22
|
+
@media (max-width:760px) { .grid2 { grid-template-columns:1fr; } }
|
|
23
|
+
table { width:100%; border-collapse:collapse; font-size:.84rem; }
|
|
24
|
+
th, td { padding:8px 10px; text-align:left; border-bottom:1px solid rgba(148,163,184,.14); }
|
|
25
|
+
th { color:#a8b7d7; font-weight:600; font-size:.74rem; text-transform:uppercase; letter-spacing:.5px; }
|
|
26
|
+
td.num { text-align:right; font-variant-numeric:tabular-nums; color:#c4b5fd; }
|
|
27
|
+
.bar { display:inline-block; height:10px; background:linear-gradient(90deg,#f59e0b,#b45309); border-radius:6px; vertical-align:middle; }
|
|
28
|
+
.pill { display:inline-block; padding:2px 8px; border-radius:999px; background:#1f2937; color:#a8b7d7; font-size:.72rem; }
|
|
29
|
+
.pill.ok { background:#064e3b; color:#a7f3d0; }
|
|
30
|
+
.pill.warn { background:#78350f; color:#fcd34d; }
|
|
31
|
+
.empty { color:#7a8db0; font-size:.84rem; padding:14px; text-align:center; }
|
|
32
|
+
.meta { color:#7a8db0; font-size:.78rem; text-align:right; margin-bottom:8px; }
|
|
33
|
+
.spark { display:flex; gap:2px; align-items:flex-end; height:60px; padding-top:6px; }
|
|
34
|
+
.spark .b { flex:1; background:#fcd34d; min-height:2px; border-radius:2px 2px 0 0; }
|
|
35
|
+
.spark .b:hover { background:#fef3c7; }
|
|
36
|
+
.day-row { display:flex; align-items:center; gap:8px; font-size:.78rem; padding:3px 0; }
|
|
37
|
+
.day-row .d { width:90px; color:#9eb1d8; font-variant-numeric:tabular-nums; }
|
|
38
|
+
.day-row .n { width:38px; text-align:right; color:#c4b5fd; font-variant-numeric:tabular-nums; }
|
|
39
|
+
.day-row .b-track { flex:1; background:rgba(148,163,184,.1); border-radius:4px; overflow:hidden; height:8px; }
|
|
40
|
+
.day-row .b-fill { height:100%; background:linear-gradient(90deg,#f59e0b,#fcd34d); }
|
|
41
|
+
a { color:#fcd34d; }
|
|
42
|
+
</style>
|
|
43
|
+
</head>
|
|
44
|
+
<body>
|
|
45
|
+
<section class="hero">
|
|
46
|
+
<h1>WAB Adoption Metrics</h1>
|
|
47
|
+
<p>Live dashboard powered by every <code>/api/discovery/usage-proof</code> run. Tracks domain coverage, agent readiness, end-to-end value, and use-case distribution across the WAB DNS Discovery protocol.</p>
|
|
48
|
+
</section>
|
|
49
|
+
|
|
50
|
+
<div class="wrap">
|
|
51
|
+
<div class="meta" id="meta">Loading…</div>
|
|
52
|
+
|
|
53
|
+
<div class="kpis" id="kpis"></div>
|
|
54
|
+
|
|
55
|
+
<div class="grid2">
|
|
56
|
+
<div class="panel">
|
|
57
|
+
<h3>Daily activity (last 30 days)</h3>
|
|
58
|
+
<div id="daily" class="empty">Loading…</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div class="panel">
|
|
62
|
+
<h3>Top use-cases</h3>
|
|
63
|
+
<div id="useCases" class="empty">Loading…</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="grid2">
|
|
68
|
+
<div class="panel">
|
|
69
|
+
<h3>Top domains</h3>
|
|
70
|
+
<div id="topDomains" class="empty">Loading…</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="panel">
|
|
74
|
+
<h3>Recent runs</h3>
|
|
75
|
+
<div id="recent" class="empty">Loading…</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="panel" style="text-align:center;color:#9eb1d8;font-size:.86rem;">
|
|
80
|
+
Want your domain on this dashboard? Run any <a href="/dns">WAB DNS</a> usage proof —
|
|
81
|
+
verify cryptographic trust at <a href="/wab-trust">/wab-trust</a> —
|
|
82
|
+
or one-click enable via
|
|
83
|
+
<a href="/cloudflare-integration">Cloudflare</a>,
|
|
84
|
+
<a href="/route53-integration">Route 53</a>,
|
|
85
|
+
<a href="/azure-dns-integration">Azure DNS</a>,
|
|
86
|
+
<a href="/gcp-dns-integration">Google Cloud DNS</a>,
|
|
87
|
+
<a href="/cpanel-integration">cPanel</a>,
|
|
88
|
+
<a href="/plesk-integration">Plesk</a>, or
|
|
89
|
+
<a href="/registrar-integrations">GoDaddy / Namecheap</a>.
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<script>
|
|
94
|
+
const fmt = (n, d = 0) => Number(n || 0).toLocaleString(undefined, { maximumFractionDigits: d });
|
|
95
|
+
const pct = (n) => (Number(n || 0) * 100).toFixed(1) + '%';
|
|
96
|
+
|
|
97
|
+
function kpi(label, value) {
|
|
98
|
+
return `<div class="kpi"><div class="v">${value}</div><div class="l">${label}</div></div>`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function renderDaily(rows) {
|
|
102
|
+
if (!rows || !rows.length) { return '<div class="empty">No runs in the last 30 days yet.</div>'; }
|
|
103
|
+
const max = Math.max(...rows.map(r => r.runs), 1);
|
|
104
|
+
return rows.map(r => `
|
|
105
|
+
<div class="day-row">
|
|
106
|
+
<div class="d">${r.day}</div>
|
|
107
|
+
<div class="b-track"><div class="b-fill" style="width:${(r.runs / max) * 100}%"></div></div>
|
|
108
|
+
<div class="n">${r.runs}</div>
|
|
109
|
+
</div>
|
|
110
|
+
`).join('');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function renderUseCases(rows) {
|
|
114
|
+
if (!rows || !rows.length) { return '<div class="empty">No use-case data yet.</div>'; }
|
|
115
|
+
const max = Math.max(...rows.map(r => r.runs), 1);
|
|
116
|
+
return `<table>
|
|
117
|
+
<thead><tr><th>Use case</th><th class="num">Runs</th><th class="num">Ready</th><th class="num">Avg score</th></tr></thead>
|
|
118
|
+
<tbody>${rows.map(r => `
|
|
119
|
+
<tr>
|
|
120
|
+
<td>${r.use_case || '—'}</td>
|
|
121
|
+
<td class="num">${fmt(r.runs)}</td>
|
|
122
|
+
<td class="num">${fmt(r.ready)}</td>
|
|
123
|
+
<td class="num">${fmt(r.avg_value_score, 2)}</td>
|
|
124
|
+
</tr>
|
|
125
|
+
`).join('')}</tbody>
|
|
126
|
+
</table>`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renderTopDomains(rows) {
|
|
130
|
+
if (!rows || !rows.length) { return '<div class="empty">No domains tracked yet.</div>'; }
|
|
131
|
+
return `<table>
|
|
132
|
+
<thead><tr><th>Domain</th><th class="num">Runs</th><th class="num">Ready</th><th class="num">Avg score</th></tr></thead>
|
|
133
|
+
<tbody>${rows.map(r => `
|
|
134
|
+
<tr>
|
|
135
|
+
<td>${r.domain}</td>
|
|
136
|
+
<td class="num">${fmt(r.runs)}</td>
|
|
137
|
+
<td class="num">${fmt(r.ready)}</td>
|
|
138
|
+
<td class="num">${fmt(r.avg_value_score, 2)}</td>
|
|
139
|
+
</tr>
|
|
140
|
+
`).join('')}</tbody>
|
|
141
|
+
</table>`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function renderRecent(rows) {
|
|
145
|
+
if (!rows || !rows.length) { return '<div class="empty">No recent runs.</div>'; }
|
|
146
|
+
return `<table>
|
|
147
|
+
<thead><tr><th>Domain</th><th>Use case</th><th class="num">Score</th><th class="num">When</th></tr></thead>
|
|
148
|
+
<tbody>${rows.map(r => `
|
|
149
|
+
<tr>
|
|
150
|
+
<td>${r.domain}</td>
|
|
151
|
+
<td>${r.preferred_use_case || '—'} ${r.readiness_ok ? '<span class="pill ok">ready</span>' : '<span class="pill warn">pending</span>'}</td>
|
|
152
|
+
<td class="num">${fmt(r.value_score, 2)}</td>
|
|
153
|
+
<td class="num">${r.created_at ? r.created_at.replace('T',' ').slice(0,16) : ''}</td>
|
|
154
|
+
</tr>
|
|
155
|
+
`).join('')}</tbody>
|
|
156
|
+
</table>`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function load() {
|
|
160
|
+
const r = await fetch('/api/discovery/adoption-metrics');
|
|
161
|
+
if (!r.ok) {
|
|
162
|
+
document.getElementById('meta').textContent = 'Failed to load metrics: HTTP ' + r.status;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const data = await r.json();
|
|
166
|
+
const t = data.totals || {};
|
|
167
|
+
document.getElementById('kpis').innerHTML = [
|
|
168
|
+
kpi('Total runs', fmt(t.total_runs)),
|
|
169
|
+
kpi('Unique domains', fmt(t.unique_domains)),
|
|
170
|
+
kpi('Readiness rate', pct(t.readiness_rate)),
|
|
171
|
+
kpi('Avg value score', fmt(t.avg_value_score, 2)),
|
|
172
|
+
kpi('Avg end-to-end', fmt(t.avg_end_to_end_ms) + ' ms'),
|
|
173
|
+
kpi('Exec success rate', pct(t.success_rate)),
|
|
174
|
+
].join('');
|
|
175
|
+
|
|
176
|
+
document.getElementById('daily').innerHTML = renderDaily(data.daily_last_30);
|
|
177
|
+
document.getElementById('useCases').innerHTML = renderUseCases(data.by_use_case);
|
|
178
|
+
document.getElementById('topDomains').innerHTML = renderTopDomains(data.top_domains);
|
|
179
|
+
document.getElementById('recent').innerHTML = renderRecent(data.recent_runs);
|
|
180
|
+
document.getElementById('meta').textContent = 'Live · generated ' + (data.generated_at || '').replace('T',' ').slice(0,19) + ' UTC';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
load().catch(err => {
|
|
184
|
+
document.getElementById('meta').textContent = 'Error loading metrics: ' + err.message;
|
|
185
|
+
});
|
|
186
|
+
</script>
|
|
187
|
+
</body>
|
|
188
|
+
</html>
|