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
|
@@ -1,465 +1,465 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sovereign API Routes
|
|
3
|
-
* ════════════════════════════════════════════════════════════════════════
|
|
4
|
-
* Routes for: Decentralized Reputation, Real-time Negotiation,
|
|
5
|
-
* Anti-Hallucination Shield, and Sovereign Dashboard data.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const express = require('express');
|
|
9
|
-
const router = express.Router();
|
|
10
|
-
const { authenticateToken } = require('../middleware/auth');
|
|
11
|
-
|
|
12
|
-
const reputation = require('../services/reputation');
|
|
13
|
-
const negotiation = require('../services/negotiation');
|
|
14
|
-
const verification = require('../services/verification');
|
|
15
|
-
const priceShield = require('../services/price-shield');
|
|
16
|
-
const sovereignShield = require('../services/sovereign-shield');
|
|
17
|
-
|
|
18
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
19
|
-
// REPUTATION API
|
|
20
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
21
|
-
|
|
22
|
-
// Register an agent for the reputation network
|
|
23
|
-
router.post('/reputation/agents', (req, res) => {
|
|
24
|
-
const { agentKey } = req.body;
|
|
25
|
-
if (!agentKey || agentKey.length < 16) {
|
|
26
|
-
return res.status(400).json({ error: 'agentKey must be at least 16 characters' });
|
|
27
|
-
}
|
|
28
|
-
const result = reputation.registerAgent(agentKey);
|
|
29
|
-
res.json(result);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// Submit a trust attestation
|
|
33
|
-
router.post('/reputation/attestations', (req, res) => {
|
|
34
|
-
const { siteId, agentId, interactionType, outcome,
|
|
35
|
-
priceAccuracy, responseTimeMs, dataIntegrity, visionVerified, details } = req.body;
|
|
36
|
-
|
|
37
|
-
if (!siteId || !agentId || !interactionType || !outcome) {
|
|
38
|
-
return res.status(400).json({ error: 'siteId, agentId, interactionType, and outcome are required' });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const result = reputation.createAttestation({
|
|
42
|
-
siteId, agentId, interactionType, outcome,
|
|
43
|
-
priceAccuracy, responseTimeMs, dataIntegrity, visionVerified, details
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (result.error) return res.status(429).json(result);
|
|
47
|
-
res.json(result);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Get site reputation
|
|
51
|
-
router.get('/reputation/sites/:siteId', (req, res) => {
|
|
52
|
-
const result = reputation.getReputation(req.params.siteId);
|
|
53
|
-
res.json(result);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Reputation leaderboard
|
|
57
|
-
router.get('/reputation/leaderboard', (req, res) => {
|
|
58
|
-
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
|
|
59
|
-
const result = reputation.getReputationLeaderboard(limit);
|
|
60
|
-
res.json(result);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Search by reputation
|
|
64
|
-
router.get('/reputation/search', (req, res) => {
|
|
65
|
-
const { category = 'all', minScore = 60 } = req.query;
|
|
66
|
-
const result = reputation.searchByReputation(category, parseFloat(minScore));
|
|
67
|
-
res.json(result);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Verify an attestation
|
|
71
|
-
router.get('/reputation/verify/:attestationId', (req, res) => {
|
|
72
|
-
const result = reputation.verifyAttestation(req.params.attestationId);
|
|
73
|
-
res.json(result);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Challenge a site's reputation
|
|
77
|
-
router.post('/reputation/challenges', (req, res) => {
|
|
78
|
-
const { siteId, challengerAgent, reason, evidence } = req.body;
|
|
79
|
-
if (!siteId || !challengerAgent || !reason) {
|
|
80
|
-
return res.status(400).json({ error: 'siteId, challengerAgent, and reason are required' });
|
|
81
|
-
}
|
|
82
|
-
const result = reputation.challengeReputation(siteId, challengerAgent, reason, evidence);
|
|
83
|
-
res.json(result);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
87
|
-
// NEGOTIATION API
|
|
88
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
89
|
-
|
|
90
|
-
// Create negotiation rules (site owner)
|
|
91
|
-
router.post('/negotiation/rules', authenticateToken, (req, res) => {
|
|
92
|
-
const { siteId, ruleName, conditionType, discountType, discountValue,
|
|
93
|
-
maxDiscountPct, minOrderValue, requiresAgentReputation } = req.body;
|
|
94
|
-
|
|
95
|
-
if (!siteId || !ruleName || !conditionType || !discountType || discountValue == null) {
|
|
96
|
-
return res.status(400).json({ error: 'siteId, ruleName, conditionType, discountType, and discountValue are required' });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const result = negotiation.createRule(siteId, {
|
|
100
|
-
ruleName, conditionType, discountType, discountValue,
|
|
101
|
-
maxDiscountPct, minOrderValue, requiresAgentReputation
|
|
102
|
-
});
|
|
103
|
-
res.json(result);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Get negotiation rules for a site
|
|
107
|
-
router.get('/negotiation/rules/:siteId', (req, res) => {
|
|
108
|
-
const rules = negotiation.getRules(req.params.siteId);
|
|
109
|
-
res.json(rules);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Update a negotiation rule
|
|
113
|
-
router.put('/negotiation/rules/:ruleId', authenticateToken, (req, res) => {
|
|
114
|
-
negotiation.updateRule(req.params.ruleId, req.body);
|
|
115
|
-
res.json({ updated: true });
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Open negotiation session (agent)
|
|
119
|
-
router.post('/negotiation/sessions', (req, res) => {
|
|
120
|
-
const { siteId, agentId, itemId, itemName, originalPrice } = req.body;
|
|
121
|
-
if (!siteId || !agentId || !originalPrice) {
|
|
122
|
-
return res.status(400).json({ error: 'siteId, agentId, and originalPrice are required' });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const result = negotiation.openSession(siteId, agentId, { itemId, itemName, originalPrice });
|
|
126
|
-
res.json(result);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Agent makes a proposal
|
|
130
|
-
router.post('/negotiation/sessions/:sessionId/propose', (req, res) => {
|
|
131
|
-
const { strategy, proposedDiscount, arguments: args } = req.body;
|
|
132
|
-
if (!strategy || proposedDiscount == null) {
|
|
133
|
-
return res.status(400).json({ error: 'strategy and proposedDiscount are required' });
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const result = negotiation.agentPropose(req.params.sessionId, {
|
|
137
|
-
strategy, proposedDiscount, arguments: args
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
if (result.error) return res.status(400).json(result);
|
|
141
|
-
res.json(result);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// Confirm a deal
|
|
145
|
-
router.post('/negotiation/sessions/:sessionId/confirm', (req, res) => {
|
|
146
|
-
const result = negotiation.confirmDeal(req.params.sessionId);
|
|
147
|
-
if (result.error) return res.status(400).json(result);
|
|
148
|
-
res.json(result);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Get negotiation stats for a site
|
|
152
|
-
router.get('/negotiation/stats/:siteId', authenticateToken, (req, res) => {
|
|
153
|
-
const stats = negotiation.getNegotiationStats(req.params.siteId);
|
|
154
|
-
res.json(stats);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// Get agent savings
|
|
158
|
-
router.get('/negotiation/savings/:agentId', (req, res) => {
|
|
159
|
-
const savings = negotiation.getAgentSavings(req.params.agentId);
|
|
160
|
-
res.json(savings);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
164
|
-
// VERIFICATION (Anti-Hallucination Shield) API
|
|
165
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
166
|
-
|
|
167
|
-
// Verify a price (DOM vs Vision)
|
|
168
|
-
router.post('/verify/price', (req, res) => {
|
|
169
|
-
const { siteId, agentId, url, domValue, visionValue, category, itemName } = req.body;
|
|
170
|
-
if (!siteId || !domValue) {
|
|
171
|
-
return res.status(400).json({ error: 'siteId and domValue are required' });
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const result = verification.verifyPrice({
|
|
175
|
-
siteId, agentId, url, domValue, visionValue, category, itemName
|
|
176
|
-
});
|
|
177
|
-
res.json(result);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Verify text
|
|
181
|
-
router.post('/verify/text', (req, res) => {
|
|
182
|
-
const { siteId, agentId, url, domValue, visionValue, fieldName } = req.body;
|
|
183
|
-
if (!siteId || !domValue) {
|
|
184
|
-
return res.status(400).json({ error: 'siteId and domValue are required' });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const result = verification.verifyText({
|
|
188
|
-
siteId, agentId, url, domValue, visionValue, fieldName
|
|
189
|
-
});
|
|
190
|
-
res.json(result);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Full page verification
|
|
194
|
-
router.post('/verify/page', (req, res) => {
|
|
195
|
-
const { siteId, agentId, url, domData, visionData } = req.body;
|
|
196
|
-
if (!siteId || !domData) {
|
|
197
|
-
return res.status(400).json({ error: 'siteId and domData are required' });
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const result = verification.verifyPage({
|
|
201
|
-
siteId, agentId, url, domData, visionData: visionData || {}
|
|
202
|
-
});
|
|
203
|
-
res.json(result);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// Human confirmation for a verification result
|
|
207
|
-
router.post('/verify/:verificationId/confirm', (req, res) => {
|
|
208
|
-
const { approved } = req.body;
|
|
209
|
-
const result = verification.confirmVerification(req.params.verificationId, approved);
|
|
210
|
-
res.json(result);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// Get shield stats for a site
|
|
214
|
-
router.get('/verify/stats/:siteId', (req, res) => {
|
|
215
|
-
const stats = verification.getShieldStats(req.params.siteId);
|
|
216
|
-
res.json(stats);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Get global shield stats
|
|
220
|
-
router.get('/verify/stats', (req, res) => {
|
|
221
|
-
const stats = verification.getGlobalShieldStats();
|
|
222
|
-
res.json(stats);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
// Update price benchmark
|
|
226
|
-
router.post('/verify/benchmarks', (req, res) => {
|
|
227
|
-
const { category, itemPattern, price } = req.body;
|
|
228
|
-
if (!category || !itemPattern || price == null) {
|
|
229
|
-
return res.status(400).json({ error: 'category, itemPattern, and price are required' });
|
|
230
|
-
}
|
|
231
|
-
verification.updateBenchmark(category, itemPattern, price);
|
|
232
|
-
res.json({ updated: true });
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
236
|
-
// SOVEREIGN DASHBOARD DATA API
|
|
237
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
238
|
-
|
|
239
|
-
router.get('/dashboard/sovereign', authenticateToken, (req, res) => {
|
|
240
|
-
const userId = req.user.id;
|
|
241
|
-
|
|
242
|
-
// Get user's sites
|
|
243
|
-
const { db: database } = require('../models/db');
|
|
244
|
-
const sites = database.prepare('SELECT id, domain FROM sites WHERE user_id = ?').all(userId);
|
|
245
|
-
|
|
246
|
-
const dashboardData = {
|
|
247
|
-
overview: {
|
|
248
|
-
sitesProtected: sites.length,
|
|
249
|
-
shieldStatus: 'active'
|
|
250
|
-
},
|
|
251
|
-
reputation: {},
|
|
252
|
-
negotiation: {},
|
|
253
|
-
shield: {},
|
|
254
|
-
privacy: { trackingAttempts: 0, intentionsEncrypted: 0, dataShielded: 0 }
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
// Aggregate data across all user's sites
|
|
258
|
-
let totalAttestations = 0, totalDeals = 0, totalSaved = 0;
|
|
259
|
-
let totalChecks = 0, totalBlocked = 0;
|
|
260
|
-
const siteDetails = [];
|
|
261
|
-
|
|
262
|
-
for (const site of sites) {
|
|
263
|
-
const rep = reputation.getReputation(site.id);
|
|
264
|
-
const negStats = negotiation.getNegotiationStats(site.id);
|
|
265
|
-
const shieldStats = verification.getShieldStats(site.id);
|
|
266
|
-
|
|
267
|
-
totalAttestations += rep.totalAttestations || 0;
|
|
268
|
-
totalDeals += negStats.deals_made || 0;
|
|
269
|
-
totalSaved += negStats.total_discount_given || 0;
|
|
270
|
-
totalChecks += shieldStats.total_checks || 0;
|
|
271
|
-
totalBlocked += (shieldStats.halted_operations || 0) + (shieldStats.blocked_operations || 0);
|
|
272
|
-
|
|
273
|
-
siteDetails.push({
|
|
274
|
-
siteId: site.id,
|
|
275
|
-
domain: site.domain,
|
|
276
|
-
reputationScore: rep.reputationScore,
|
|
277
|
-
trustLevel: rep.trustLevel,
|
|
278
|
-
dealsMade: negStats.deals_made || 0,
|
|
279
|
-
avgSavings: negStats.avg_savings || 0,
|
|
280
|
-
integrityRating: shieldStats.integrity_rating
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
dashboardData.reputation = {
|
|
285
|
-
totalAttestations,
|
|
286
|
-
avgReputationScore: siteDetails.length > 0
|
|
287
|
-
? Math.round(siteDetails.reduce((s, d) => s + d.reputationScore, 0) / siteDetails.length)
|
|
288
|
-
: 50
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
dashboardData.negotiation = {
|
|
292
|
-
totalDeals,
|
|
293
|
-
totalSaved: Math.round(totalSaved * 100) / 100
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
dashboardData.shield = {
|
|
297
|
-
totalChecks,
|
|
298
|
-
threatsBlocked: totalBlocked,
|
|
299
|
-
integrityScore: siteDetails.length > 0
|
|
300
|
-
? Math.round(siteDetails.reduce((s, d) => s + d.integrityRating, 0) / siteDetails.length)
|
|
301
|
-
: 100
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
dashboardData.sites = siteDetails;
|
|
305
|
-
|
|
306
|
-
res.json(dashboardData);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
310
|
-
// DYNAMIC PRICING SHIELD API
|
|
311
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
312
|
-
|
|
313
|
-
// Get available identity personas
|
|
314
|
-
router.get('/price-shield/personas', (req, res) => {
|
|
315
|
-
res.json(priceShield.getPersonas());
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
// Create a new price scan
|
|
319
|
-
router.post('/price-shield/scans', (req, res) => {
|
|
320
|
-
const { siteId, url, itemName, category } = req.body;
|
|
321
|
-
if (!url) {
|
|
322
|
-
return res.status(400).json({ error: 'url is required' });
|
|
323
|
-
}
|
|
324
|
-
const result = priceShield.createScan({ siteId, url, itemName, category });
|
|
325
|
-
res.json(result);
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
// Record a probe result for a scan
|
|
329
|
-
router.post('/price-shield/scans/:scanId/probes', (req, res) => {
|
|
330
|
-
const { personaId, priceText, currency, responseHeaders, cookiesReceived, durationMs } = req.body;
|
|
331
|
-
if (!personaId || !priceText) {
|
|
332
|
-
return res.status(400).json({ error: 'personaId and priceText are required' });
|
|
333
|
-
}
|
|
334
|
-
const result = priceShield.recordProbe(req.params.scanId, {
|
|
335
|
-
personaId, priceText, currency, responseHeaders, cookiesReceived, durationMs
|
|
336
|
-
});
|
|
337
|
-
if (result.error) return res.status(400).json(result);
|
|
338
|
-
res.json(result);
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
// Analyze a scan (after probes are recorded)
|
|
342
|
-
router.post('/price-shield/scans/:scanId/analyze', (req, res) => {
|
|
343
|
-
const result = priceShield.analyzeScan(req.params.scanId);
|
|
344
|
-
if (result.error) return res.status(400).json(result);
|
|
345
|
-
res.json(result);
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Quick scan — all-in-one (provide probes + get analysis)
|
|
349
|
-
router.post('/price-shield/quick-scan', (req, res) => {
|
|
350
|
-
const { url, itemName, siteId, category, probes } = req.body;
|
|
351
|
-
if (!url || !probes || !Array.isArray(probes) || probes.length < 2) {
|
|
352
|
-
return res.status(400).json({ error: 'url and at least 2 probes are required' });
|
|
353
|
-
}
|
|
354
|
-
const result = priceShield.quickScan({ url, itemName, siteId, category, probes });
|
|
355
|
-
if (result.error) return res.status(400).json(result);
|
|
356
|
-
res.json(result);
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
// Get scan report
|
|
360
|
-
router.get('/price-shield/scans/:scanId', (req, res) => {
|
|
361
|
-
const result = priceShield.getScanReport(req.params.scanId);
|
|
362
|
-
if (result.error) return res.status(404).json(result);
|
|
363
|
-
res.json(result);
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// Get global price shield statistics
|
|
367
|
-
router.get('/price-shield/stats', (req, res) => {
|
|
368
|
-
res.json(priceShield.getGlobalStats());
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
// Get price history for a URL
|
|
372
|
-
router.get('/price-shield/history', (req, res) => {
|
|
373
|
-
const url = req.query.url;
|
|
374
|
-
if (!url) return res.status(400).json({ error: 'url query parameter is required' });
|
|
375
|
-
const limit = Math.min(parseInt(req.query.limit) || 30, 100);
|
|
376
|
-
res.json(priceShield.getPriceHistory(url, limit));
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// Get manipulation log for a site
|
|
380
|
-
router.get('/price-shield/manipulations/:siteId', (req, res) => {
|
|
381
|
-
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
|
|
382
|
-
const result = priceShield.getGlobalStats();
|
|
383
|
-
res.json(result.topManipulators.find(m => m.siteId === req.params.siteId) || { siteId: req.params.siteId, incidents: 0 });
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
387
|
-
// SOVEREIGN PHONE SHIELD API
|
|
388
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
389
|
-
|
|
390
|
-
// Threat intelligence feed for browser/clients
|
|
391
|
-
router.get('/shield/intel-feed', (req, res) => {
|
|
392
|
-
res.json(sovereignShield.getIntelFeed());
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
// Analyze a live connection/event from client telemetry
|
|
396
|
-
router.post('/shield/analyze-connection', (req, res) => {
|
|
397
|
-
const result = sovereignShield.analyzeConnection(req.body || {});
|
|
398
|
-
if (result.error) return res.status(400).json(result);
|
|
399
|
-
res.json(result);
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// Community threat report (Bounty-Network style)
|
|
403
|
-
router.post('/shield/report', (req, res) => {
|
|
404
|
-
const result = sovereignShield.submitThreatReport(req.body || {});
|
|
405
|
-
if (result.error) return res.status(400).json(result);
|
|
406
|
-
res.json(result);
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
// Stats + recent events for dashboard
|
|
410
|
-
router.get('/shield/stats', (req, res) => {
|
|
411
|
-
res.json(sovereignShield.getStats());
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
router.get('/shield/events', (req, res) => {
|
|
415
|
-
const limit = Math.min(parseInt(req.query.limit) || 50, 200);
|
|
416
|
-
res.json({ events: sovereignShield.getRecentEvents(limit) });
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
// Personal Cloud Vault crypto endpoints
|
|
420
|
-
router.post('/shield/vault/encrypt', (req, res) => {
|
|
421
|
-
const { plaintext, passphrase } = req.body || {};
|
|
422
|
-
const result = sovereignShield.encryptVault(plaintext, passphrase);
|
|
423
|
-
if (result.error) return res.status(400).json(result);
|
|
424
|
-
res.json(result);
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
router.post('/shield/vault/decrypt', (req, res) => {
|
|
428
|
-
const { payload, passphrase } = req.body || {};
|
|
429
|
-
const result = sovereignShield.decryptVault(payload, passphrase);
|
|
430
|
-
if (result.error) return res.status(400).json(result);
|
|
431
|
-
res.json(result);
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
// Device registration + heartbeat for Android/iOS local tunnel clients
|
|
435
|
-
router.post('/shield/devices/register', (req, res) => {
|
|
436
|
-
const result = sovereignShield.registerDevice(req.body || {});
|
|
437
|
-
if (result.error) return res.status(400).json(result);
|
|
438
|
-
res.json(result);
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
router.post('/shield/devices/heartbeat', (req, res) => {
|
|
442
|
-
const result = sovereignShield.heartbeat(req.body || {});
|
|
443
|
-
if (result.error) return res.status(400).json(result);
|
|
444
|
-
res.json(result);
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
// Batch telemetry ingestion from mobile local VPN / proxy layer
|
|
448
|
-
router.post('/shield/devices/telemetry', (req, res) => {
|
|
449
|
-
const result = sovereignShield.ingestTelemetryBatch(req.body || {});
|
|
450
|
-
if (result.error) return res.status(400).json(result);
|
|
451
|
-
res.json(result);
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
router.get('/shield/devices', (req, res) => {
|
|
455
|
-
const limit = Math.min(parseInt(req.query.limit) || 100, 500);
|
|
456
|
-
res.json({ devices: sovereignShield.getDevices(limit) });
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
router.get('/shield/devices/:deviceFingerprint', (req, res) => {
|
|
460
|
-
const result = sovereignShield.getDevice(req.params.deviceFingerprint);
|
|
461
|
-
if (result.error) return res.status(404).json(result);
|
|
462
|
-
res.json(result);
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
module.exports = router;
|
|
1
|
+
/**
|
|
2
|
+
* Sovereign API Routes
|
|
3
|
+
* ════════════════════════════════════════════════════════════════════════
|
|
4
|
+
* Routes for: Decentralized Reputation, Real-time Negotiation,
|
|
5
|
+
* Anti-Hallucination Shield, and Sovereign Dashboard data.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const express = require('express');
|
|
9
|
+
const router = express.Router();
|
|
10
|
+
const { authenticateToken } = require('../middleware/auth');
|
|
11
|
+
|
|
12
|
+
const reputation = require('../services/reputation');
|
|
13
|
+
const negotiation = require('../services/negotiation');
|
|
14
|
+
const verification = require('../services/verification');
|
|
15
|
+
const priceShield = require('../services/price-shield');
|
|
16
|
+
const sovereignShield = require('../services/sovereign-shield');
|
|
17
|
+
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
19
|
+
// REPUTATION API
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
// Register an agent for the reputation network
|
|
23
|
+
router.post('/reputation/agents', (req, res) => {
|
|
24
|
+
const { agentKey } = req.body;
|
|
25
|
+
if (!agentKey || agentKey.length < 16) {
|
|
26
|
+
return res.status(400).json({ error: 'agentKey must be at least 16 characters' });
|
|
27
|
+
}
|
|
28
|
+
const result = reputation.registerAgent(agentKey);
|
|
29
|
+
res.json(result);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Submit a trust attestation
|
|
33
|
+
router.post('/reputation/attestations', (req, res) => {
|
|
34
|
+
const { siteId, agentId, interactionType, outcome,
|
|
35
|
+
priceAccuracy, responseTimeMs, dataIntegrity, visionVerified, details } = req.body;
|
|
36
|
+
|
|
37
|
+
if (!siteId || !agentId || !interactionType || !outcome) {
|
|
38
|
+
return res.status(400).json({ error: 'siteId, agentId, interactionType, and outcome are required' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = reputation.createAttestation({
|
|
42
|
+
siteId, agentId, interactionType, outcome,
|
|
43
|
+
priceAccuracy, responseTimeMs, dataIntegrity, visionVerified, details
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (result.error) return res.status(429).json(result);
|
|
47
|
+
res.json(result);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Get site reputation
|
|
51
|
+
router.get('/reputation/sites/:siteId', (req, res) => {
|
|
52
|
+
const result = reputation.getReputation(req.params.siteId);
|
|
53
|
+
res.json(result);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Reputation leaderboard
|
|
57
|
+
router.get('/reputation/leaderboard', (req, res) => {
|
|
58
|
+
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
|
|
59
|
+
const result = reputation.getReputationLeaderboard(limit);
|
|
60
|
+
res.json(result);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Search by reputation
|
|
64
|
+
router.get('/reputation/search', (req, res) => {
|
|
65
|
+
const { category = 'all', minScore = 60 } = req.query;
|
|
66
|
+
const result = reputation.searchByReputation(category, parseFloat(minScore));
|
|
67
|
+
res.json(result);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Verify an attestation
|
|
71
|
+
router.get('/reputation/verify/:attestationId', (req, res) => {
|
|
72
|
+
const result = reputation.verifyAttestation(req.params.attestationId);
|
|
73
|
+
res.json(result);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Challenge a site's reputation
|
|
77
|
+
router.post('/reputation/challenges', (req, res) => {
|
|
78
|
+
const { siteId, challengerAgent, reason, evidence } = req.body;
|
|
79
|
+
if (!siteId || !challengerAgent || !reason) {
|
|
80
|
+
return res.status(400).json({ error: 'siteId, challengerAgent, and reason are required' });
|
|
81
|
+
}
|
|
82
|
+
const result = reputation.challengeReputation(siteId, challengerAgent, reason, evidence);
|
|
83
|
+
res.json(result);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
87
|
+
// NEGOTIATION API
|
|
88
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
89
|
+
|
|
90
|
+
// Create negotiation rules (site owner)
|
|
91
|
+
router.post('/negotiation/rules', authenticateToken, (req, res) => {
|
|
92
|
+
const { siteId, ruleName, conditionType, discountType, discountValue,
|
|
93
|
+
maxDiscountPct, minOrderValue, requiresAgentReputation } = req.body;
|
|
94
|
+
|
|
95
|
+
if (!siteId || !ruleName || !conditionType || !discountType || discountValue == null) {
|
|
96
|
+
return res.status(400).json({ error: 'siteId, ruleName, conditionType, discountType, and discountValue are required' });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = negotiation.createRule(siteId, {
|
|
100
|
+
ruleName, conditionType, discountType, discountValue,
|
|
101
|
+
maxDiscountPct, minOrderValue, requiresAgentReputation
|
|
102
|
+
});
|
|
103
|
+
res.json(result);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Get negotiation rules for a site
|
|
107
|
+
router.get('/negotiation/rules/:siteId', (req, res) => {
|
|
108
|
+
const rules = negotiation.getRules(req.params.siteId);
|
|
109
|
+
res.json(rules);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Update a negotiation rule
|
|
113
|
+
router.put('/negotiation/rules/:ruleId', authenticateToken, (req, res) => {
|
|
114
|
+
negotiation.updateRule(req.params.ruleId, req.body);
|
|
115
|
+
res.json({ updated: true });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Open negotiation session (agent)
|
|
119
|
+
router.post('/negotiation/sessions', (req, res) => {
|
|
120
|
+
const { siteId, agentId, itemId, itemName, originalPrice } = req.body;
|
|
121
|
+
if (!siteId || !agentId || !originalPrice) {
|
|
122
|
+
return res.status(400).json({ error: 'siteId, agentId, and originalPrice are required' });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const result = negotiation.openSession(siteId, agentId, { itemId, itemName, originalPrice });
|
|
126
|
+
res.json(result);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Agent makes a proposal
|
|
130
|
+
router.post('/negotiation/sessions/:sessionId/propose', (req, res) => {
|
|
131
|
+
const { strategy, proposedDiscount, arguments: args } = req.body;
|
|
132
|
+
if (!strategy || proposedDiscount == null) {
|
|
133
|
+
return res.status(400).json({ error: 'strategy and proposedDiscount are required' });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const result = negotiation.agentPropose(req.params.sessionId, {
|
|
137
|
+
strategy, proposedDiscount, arguments: args
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (result.error) return res.status(400).json(result);
|
|
141
|
+
res.json(result);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Confirm a deal
|
|
145
|
+
router.post('/negotiation/sessions/:sessionId/confirm', (req, res) => {
|
|
146
|
+
const result = negotiation.confirmDeal(req.params.sessionId);
|
|
147
|
+
if (result.error) return res.status(400).json(result);
|
|
148
|
+
res.json(result);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Get negotiation stats for a site
|
|
152
|
+
router.get('/negotiation/stats/:siteId', authenticateToken, (req, res) => {
|
|
153
|
+
const stats = negotiation.getNegotiationStats(req.params.siteId);
|
|
154
|
+
res.json(stats);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Get agent savings
|
|
158
|
+
router.get('/negotiation/savings/:agentId', (req, res) => {
|
|
159
|
+
const savings = negotiation.getAgentSavings(req.params.agentId);
|
|
160
|
+
res.json(savings);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
164
|
+
// VERIFICATION (Anti-Hallucination Shield) API
|
|
165
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
166
|
+
|
|
167
|
+
// Verify a price (DOM vs Vision)
|
|
168
|
+
router.post('/verify/price', (req, res) => {
|
|
169
|
+
const { siteId, agentId, url, domValue, visionValue, category, itemName } = req.body;
|
|
170
|
+
if (!siteId || !domValue) {
|
|
171
|
+
return res.status(400).json({ error: 'siteId and domValue are required' });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const result = verification.verifyPrice({
|
|
175
|
+
siteId, agentId, url, domValue, visionValue, category, itemName
|
|
176
|
+
});
|
|
177
|
+
res.json(result);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Verify text
|
|
181
|
+
router.post('/verify/text', (req, res) => {
|
|
182
|
+
const { siteId, agentId, url, domValue, visionValue, fieldName } = req.body;
|
|
183
|
+
if (!siteId || !domValue) {
|
|
184
|
+
return res.status(400).json({ error: 'siteId and domValue are required' });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const result = verification.verifyText({
|
|
188
|
+
siteId, agentId, url, domValue, visionValue, fieldName
|
|
189
|
+
});
|
|
190
|
+
res.json(result);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Full page verification
|
|
194
|
+
router.post('/verify/page', (req, res) => {
|
|
195
|
+
const { siteId, agentId, url, domData, visionData } = req.body;
|
|
196
|
+
if (!siteId || !domData) {
|
|
197
|
+
return res.status(400).json({ error: 'siteId and domData are required' });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const result = verification.verifyPage({
|
|
201
|
+
siteId, agentId, url, domData, visionData: visionData || {}
|
|
202
|
+
});
|
|
203
|
+
res.json(result);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Human confirmation for a verification result
|
|
207
|
+
router.post('/verify/:verificationId/confirm', (req, res) => {
|
|
208
|
+
const { approved } = req.body;
|
|
209
|
+
const result = verification.confirmVerification(req.params.verificationId, approved);
|
|
210
|
+
res.json(result);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Get shield stats for a site
|
|
214
|
+
router.get('/verify/stats/:siteId', (req, res) => {
|
|
215
|
+
const stats = verification.getShieldStats(req.params.siteId);
|
|
216
|
+
res.json(stats);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Get global shield stats
|
|
220
|
+
router.get('/verify/stats', (req, res) => {
|
|
221
|
+
const stats = verification.getGlobalShieldStats();
|
|
222
|
+
res.json(stats);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Update price benchmark
|
|
226
|
+
router.post('/verify/benchmarks', (req, res) => {
|
|
227
|
+
const { category, itemPattern, price } = req.body;
|
|
228
|
+
if (!category || !itemPattern || price == null) {
|
|
229
|
+
return res.status(400).json({ error: 'category, itemPattern, and price are required' });
|
|
230
|
+
}
|
|
231
|
+
verification.updateBenchmark(category, itemPattern, price);
|
|
232
|
+
res.json({ updated: true });
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
236
|
+
// SOVEREIGN DASHBOARD DATA API
|
|
237
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
238
|
+
|
|
239
|
+
router.get('/dashboard/sovereign', authenticateToken, (req, res) => {
|
|
240
|
+
const userId = req.user.id;
|
|
241
|
+
|
|
242
|
+
// Get user's sites
|
|
243
|
+
const { db: database } = require('../models/db');
|
|
244
|
+
const sites = database.prepare('SELECT id, domain FROM sites WHERE user_id = ?').all(userId);
|
|
245
|
+
|
|
246
|
+
const dashboardData = {
|
|
247
|
+
overview: {
|
|
248
|
+
sitesProtected: sites.length,
|
|
249
|
+
shieldStatus: 'active'
|
|
250
|
+
},
|
|
251
|
+
reputation: {},
|
|
252
|
+
negotiation: {},
|
|
253
|
+
shield: {},
|
|
254
|
+
privacy: { trackingAttempts: 0, intentionsEncrypted: 0, dataShielded: 0 }
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// Aggregate data across all user's sites
|
|
258
|
+
let totalAttestations = 0, totalDeals = 0, totalSaved = 0;
|
|
259
|
+
let totalChecks = 0, totalBlocked = 0;
|
|
260
|
+
const siteDetails = [];
|
|
261
|
+
|
|
262
|
+
for (const site of sites) {
|
|
263
|
+
const rep = reputation.getReputation(site.id);
|
|
264
|
+
const negStats = negotiation.getNegotiationStats(site.id);
|
|
265
|
+
const shieldStats = verification.getShieldStats(site.id);
|
|
266
|
+
|
|
267
|
+
totalAttestations += rep.totalAttestations || 0;
|
|
268
|
+
totalDeals += negStats.deals_made || 0;
|
|
269
|
+
totalSaved += negStats.total_discount_given || 0;
|
|
270
|
+
totalChecks += shieldStats.total_checks || 0;
|
|
271
|
+
totalBlocked += (shieldStats.halted_operations || 0) + (shieldStats.blocked_operations || 0);
|
|
272
|
+
|
|
273
|
+
siteDetails.push({
|
|
274
|
+
siteId: site.id,
|
|
275
|
+
domain: site.domain,
|
|
276
|
+
reputationScore: rep.reputationScore,
|
|
277
|
+
trustLevel: rep.trustLevel,
|
|
278
|
+
dealsMade: negStats.deals_made || 0,
|
|
279
|
+
avgSavings: negStats.avg_savings || 0,
|
|
280
|
+
integrityRating: shieldStats.integrity_rating
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
dashboardData.reputation = {
|
|
285
|
+
totalAttestations,
|
|
286
|
+
avgReputationScore: siteDetails.length > 0
|
|
287
|
+
? Math.round(siteDetails.reduce((s, d) => s + d.reputationScore, 0) / siteDetails.length)
|
|
288
|
+
: 50
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
dashboardData.negotiation = {
|
|
292
|
+
totalDeals,
|
|
293
|
+
totalSaved: Math.round(totalSaved * 100) / 100
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
dashboardData.shield = {
|
|
297
|
+
totalChecks,
|
|
298
|
+
threatsBlocked: totalBlocked,
|
|
299
|
+
integrityScore: siteDetails.length > 0
|
|
300
|
+
? Math.round(siteDetails.reduce((s, d) => s + d.integrityRating, 0) / siteDetails.length)
|
|
301
|
+
: 100
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
dashboardData.sites = siteDetails;
|
|
305
|
+
|
|
306
|
+
res.json(dashboardData);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
310
|
+
// DYNAMIC PRICING SHIELD API
|
|
311
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
312
|
+
|
|
313
|
+
// Get available identity personas
|
|
314
|
+
router.get('/price-shield/personas', (req, res) => {
|
|
315
|
+
res.json(priceShield.getPersonas());
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Create a new price scan
|
|
319
|
+
router.post('/price-shield/scans', (req, res) => {
|
|
320
|
+
const { siteId, url, itemName, category } = req.body;
|
|
321
|
+
if (!url) {
|
|
322
|
+
return res.status(400).json({ error: 'url is required' });
|
|
323
|
+
}
|
|
324
|
+
const result = priceShield.createScan({ siteId, url, itemName, category });
|
|
325
|
+
res.json(result);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Record a probe result for a scan
|
|
329
|
+
router.post('/price-shield/scans/:scanId/probes', (req, res) => {
|
|
330
|
+
const { personaId, priceText, currency, responseHeaders, cookiesReceived, durationMs } = req.body;
|
|
331
|
+
if (!personaId || !priceText) {
|
|
332
|
+
return res.status(400).json({ error: 'personaId and priceText are required' });
|
|
333
|
+
}
|
|
334
|
+
const result = priceShield.recordProbe(req.params.scanId, {
|
|
335
|
+
personaId, priceText, currency, responseHeaders, cookiesReceived, durationMs
|
|
336
|
+
});
|
|
337
|
+
if (result.error) return res.status(400).json(result);
|
|
338
|
+
res.json(result);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Analyze a scan (after probes are recorded)
|
|
342
|
+
router.post('/price-shield/scans/:scanId/analyze', (req, res) => {
|
|
343
|
+
const result = priceShield.analyzeScan(req.params.scanId);
|
|
344
|
+
if (result.error) return res.status(400).json(result);
|
|
345
|
+
res.json(result);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Quick scan — all-in-one (provide probes + get analysis)
|
|
349
|
+
router.post('/price-shield/quick-scan', (req, res) => {
|
|
350
|
+
const { url, itemName, siteId, category, probes } = req.body;
|
|
351
|
+
if (!url || !probes || !Array.isArray(probes) || probes.length < 2) {
|
|
352
|
+
return res.status(400).json({ error: 'url and at least 2 probes are required' });
|
|
353
|
+
}
|
|
354
|
+
const result = priceShield.quickScan({ url, itemName, siteId, category, probes });
|
|
355
|
+
if (result.error) return res.status(400).json(result);
|
|
356
|
+
res.json(result);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Get scan report
|
|
360
|
+
router.get('/price-shield/scans/:scanId', (req, res) => {
|
|
361
|
+
const result = priceShield.getScanReport(req.params.scanId);
|
|
362
|
+
if (result.error) return res.status(404).json(result);
|
|
363
|
+
res.json(result);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Get global price shield statistics
|
|
367
|
+
router.get('/price-shield/stats', (req, res) => {
|
|
368
|
+
res.json(priceShield.getGlobalStats());
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Get price history for a URL
|
|
372
|
+
router.get('/price-shield/history', (req, res) => {
|
|
373
|
+
const url = req.query.url;
|
|
374
|
+
if (!url) return res.status(400).json({ error: 'url query parameter is required' });
|
|
375
|
+
const limit = Math.min(parseInt(req.query.limit) || 30, 100);
|
|
376
|
+
res.json(priceShield.getPriceHistory(url, limit));
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Get manipulation log for a site
|
|
380
|
+
router.get('/price-shield/manipulations/:siteId', (req, res) => {
|
|
381
|
+
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
|
|
382
|
+
const result = priceShield.getGlobalStats();
|
|
383
|
+
res.json(result.topManipulators.find(m => m.siteId === req.params.siteId) || { siteId: req.params.siteId, incidents: 0 });
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
387
|
+
// SOVEREIGN PHONE SHIELD API
|
|
388
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
389
|
+
|
|
390
|
+
// Threat intelligence feed for browser/clients
|
|
391
|
+
router.get('/shield/intel-feed', (req, res) => {
|
|
392
|
+
res.json(sovereignShield.getIntelFeed());
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Analyze a live connection/event from client telemetry
|
|
396
|
+
router.post('/shield/analyze-connection', (req, res) => {
|
|
397
|
+
const result = sovereignShield.analyzeConnection(req.body || {});
|
|
398
|
+
if (result.error) return res.status(400).json(result);
|
|
399
|
+
res.json(result);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Community threat report (Bounty-Network style)
|
|
403
|
+
router.post('/shield/report', (req, res) => {
|
|
404
|
+
const result = sovereignShield.submitThreatReport(req.body || {});
|
|
405
|
+
if (result.error) return res.status(400).json(result);
|
|
406
|
+
res.json(result);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Stats + recent events for dashboard
|
|
410
|
+
router.get('/shield/stats', (req, res) => {
|
|
411
|
+
res.json(sovereignShield.getStats());
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
router.get('/shield/events', (req, res) => {
|
|
415
|
+
const limit = Math.min(parseInt(req.query.limit) || 50, 200);
|
|
416
|
+
res.json({ events: sovereignShield.getRecentEvents(limit) });
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Personal Cloud Vault crypto endpoints
|
|
420
|
+
router.post('/shield/vault/encrypt', (req, res) => {
|
|
421
|
+
const { plaintext, passphrase } = req.body || {};
|
|
422
|
+
const result = sovereignShield.encryptVault(plaintext, passphrase);
|
|
423
|
+
if (result.error) return res.status(400).json(result);
|
|
424
|
+
res.json(result);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
router.post('/shield/vault/decrypt', (req, res) => {
|
|
428
|
+
const { payload, passphrase } = req.body || {};
|
|
429
|
+
const result = sovereignShield.decryptVault(payload, passphrase);
|
|
430
|
+
if (result.error) return res.status(400).json(result);
|
|
431
|
+
res.json(result);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Device registration + heartbeat for Android/iOS local tunnel clients
|
|
435
|
+
router.post('/shield/devices/register', (req, res) => {
|
|
436
|
+
const result = sovereignShield.registerDevice(req.body || {});
|
|
437
|
+
if (result.error) return res.status(400).json(result);
|
|
438
|
+
res.json(result);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
router.post('/shield/devices/heartbeat', (req, res) => {
|
|
442
|
+
const result = sovereignShield.heartbeat(req.body || {});
|
|
443
|
+
if (result.error) return res.status(400).json(result);
|
|
444
|
+
res.json(result);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// Batch telemetry ingestion from mobile local VPN / proxy layer
|
|
448
|
+
router.post('/shield/devices/telemetry', (req, res) => {
|
|
449
|
+
const result = sovereignShield.ingestTelemetryBatch(req.body || {});
|
|
450
|
+
if (result.error) return res.status(400).json(result);
|
|
451
|
+
res.json(result);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
router.get('/shield/devices', (req, res) => {
|
|
455
|
+
const limit = Math.min(parseInt(req.query.limit) || 100, 500);
|
|
456
|
+
res.json({ devices: sovereignShield.getDevices(limit) });
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
router.get('/shield/devices/:deviceFingerprint', (req, res) => {
|
|
460
|
+
const result = sovereignShield.getDevice(req.params.deviceFingerprint);
|
|
461
|
+
if (result.error) return res.status(404).json(result);
|
|
462
|
+
res.json(result);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
module.exports = router;
|