web-agent-bridge 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,307 @@
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
+
16
+ // ═══════════════════════════════════════════════════════════════════════
17
+ // REPUTATION API
18
+ // ═══════════════════════════════════════════════════════════════════════
19
+
20
+ // Register an agent for the reputation network
21
+ router.post('/reputation/agents', (req, res) => {
22
+ const { agentKey } = req.body;
23
+ if (!agentKey || agentKey.length < 16) {
24
+ return res.status(400).json({ error: 'agentKey must be at least 16 characters' });
25
+ }
26
+ const result = reputation.registerAgent(agentKey);
27
+ res.json(result);
28
+ });
29
+
30
+ // Submit a trust attestation
31
+ router.post('/reputation/attestations', (req, res) => {
32
+ const { siteId, agentId, interactionType, outcome,
33
+ priceAccuracy, responseTimeMs, dataIntegrity, visionVerified, details } = req.body;
34
+
35
+ if (!siteId || !agentId || !interactionType || !outcome) {
36
+ return res.status(400).json({ error: 'siteId, agentId, interactionType, and outcome are required' });
37
+ }
38
+
39
+ const result = reputation.createAttestation({
40
+ siteId, agentId, interactionType, outcome,
41
+ priceAccuracy, responseTimeMs, dataIntegrity, visionVerified, details
42
+ });
43
+
44
+ if (result.error) return res.status(429).json(result);
45
+ res.json(result);
46
+ });
47
+
48
+ // Get site reputation
49
+ router.get('/reputation/sites/:siteId', (req, res) => {
50
+ const result = reputation.getReputation(req.params.siteId);
51
+ res.json(result);
52
+ });
53
+
54
+ // Reputation leaderboard
55
+ router.get('/reputation/leaderboard', (req, res) => {
56
+ const limit = Math.min(parseInt(req.query.limit) || 20, 100);
57
+ const result = reputation.getReputationLeaderboard(limit);
58
+ res.json(result);
59
+ });
60
+
61
+ // Search by reputation
62
+ router.get('/reputation/search', (req, res) => {
63
+ const { category = 'all', minScore = 60 } = req.query;
64
+ const result = reputation.searchByReputation(category, parseFloat(minScore));
65
+ res.json(result);
66
+ });
67
+
68
+ // Verify an attestation
69
+ router.get('/reputation/verify/:attestationId', (req, res) => {
70
+ const result = reputation.verifyAttestation(req.params.attestationId);
71
+ res.json(result);
72
+ });
73
+
74
+ // Challenge a site's reputation
75
+ router.post('/reputation/challenges', (req, res) => {
76
+ const { siteId, challengerAgent, reason, evidence } = req.body;
77
+ if (!siteId || !challengerAgent || !reason) {
78
+ return res.status(400).json({ error: 'siteId, challengerAgent, and reason are required' });
79
+ }
80
+ const result = reputation.challengeReputation(siteId, challengerAgent, reason, evidence);
81
+ res.json(result);
82
+ });
83
+
84
+ // ═══════════════════════════════════════════════════════════════════════
85
+ // NEGOTIATION API
86
+ // ═══════════════════════════════════════════════════════════════════════
87
+
88
+ // Create negotiation rules (site owner)
89
+ router.post('/negotiation/rules', authenticateToken, (req, res) => {
90
+ const { siteId, ruleName, conditionType, discountType, discountValue,
91
+ maxDiscountPct, minOrderValue, requiresAgentReputation } = req.body;
92
+
93
+ if (!siteId || !ruleName || !conditionType || !discountType || discountValue == null) {
94
+ return res.status(400).json({ error: 'siteId, ruleName, conditionType, discountType, and discountValue are required' });
95
+ }
96
+
97
+ const result = negotiation.createRule(siteId, {
98
+ ruleName, conditionType, discountType, discountValue,
99
+ maxDiscountPct, minOrderValue, requiresAgentReputation
100
+ });
101
+ res.json(result);
102
+ });
103
+
104
+ // Get negotiation rules for a site
105
+ router.get('/negotiation/rules/:siteId', (req, res) => {
106
+ const rules = negotiation.getRules(req.params.siteId);
107
+ res.json(rules);
108
+ });
109
+
110
+ // Update a negotiation rule
111
+ router.put('/negotiation/rules/:ruleId', authenticateToken, (req, res) => {
112
+ negotiation.updateRule(req.params.ruleId, req.body);
113
+ res.json({ updated: true });
114
+ });
115
+
116
+ // Open negotiation session (agent)
117
+ router.post('/negotiation/sessions', (req, res) => {
118
+ const { siteId, agentId, itemId, itemName, originalPrice } = req.body;
119
+ if (!siteId || !agentId || !originalPrice) {
120
+ return res.status(400).json({ error: 'siteId, agentId, and originalPrice are required' });
121
+ }
122
+
123
+ const result = negotiation.openSession(siteId, agentId, { itemId, itemName, originalPrice });
124
+ res.json(result);
125
+ });
126
+
127
+ // Agent makes a proposal
128
+ router.post('/negotiation/sessions/:sessionId/propose', (req, res) => {
129
+ const { strategy, proposedDiscount, arguments: args } = req.body;
130
+ if (!strategy || proposedDiscount == null) {
131
+ return res.status(400).json({ error: 'strategy and proposedDiscount are required' });
132
+ }
133
+
134
+ const result = negotiation.agentPropose(req.params.sessionId, {
135
+ strategy, proposedDiscount, arguments: args
136
+ });
137
+
138
+ if (result.error) return res.status(400).json(result);
139
+ res.json(result);
140
+ });
141
+
142
+ // Confirm a deal
143
+ router.post('/negotiation/sessions/:sessionId/confirm', (req, res) => {
144
+ const result = negotiation.confirmDeal(req.params.sessionId);
145
+ if (result.error) return res.status(400).json(result);
146
+ res.json(result);
147
+ });
148
+
149
+ // Get negotiation stats for a site
150
+ router.get('/negotiation/stats/:siteId', authenticateToken, (req, res) => {
151
+ const stats = negotiation.getNegotiationStats(req.params.siteId);
152
+ res.json(stats);
153
+ });
154
+
155
+ // Get agent savings
156
+ router.get('/negotiation/savings/:agentId', (req, res) => {
157
+ const savings = negotiation.getAgentSavings(req.params.agentId);
158
+ res.json(savings);
159
+ });
160
+
161
+ // ═══════════════════════════════════════════════════════════════════════
162
+ // VERIFICATION (Anti-Hallucination Shield) API
163
+ // ═══════════════════════════════════════════════════════════════════════
164
+
165
+ // Verify a price (DOM vs Vision)
166
+ router.post('/verify/price', (req, res) => {
167
+ const { siteId, agentId, url, domValue, visionValue, category, itemName } = req.body;
168
+ if (!siteId || !domValue) {
169
+ return res.status(400).json({ error: 'siteId and domValue are required' });
170
+ }
171
+
172
+ const result = verification.verifyPrice({
173
+ siteId, agentId, url, domValue, visionValue, category, itemName
174
+ });
175
+ res.json(result);
176
+ });
177
+
178
+ // Verify text
179
+ router.post('/verify/text', (req, res) => {
180
+ const { siteId, agentId, url, domValue, visionValue, fieldName } = req.body;
181
+ if (!siteId || !domValue) {
182
+ return res.status(400).json({ error: 'siteId and domValue are required' });
183
+ }
184
+
185
+ const result = verification.verifyText({
186
+ siteId, agentId, url, domValue, visionValue, fieldName
187
+ });
188
+ res.json(result);
189
+ });
190
+
191
+ // Full page verification
192
+ router.post('/verify/page', (req, res) => {
193
+ const { siteId, agentId, url, domData, visionData } = req.body;
194
+ if (!siteId || !domData) {
195
+ return res.status(400).json({ error: 'siteId and domData are required' });
196
+ }
197
+
198
+ const result = verification.verifyPage({
199
+ siteId, agentId, url, domData, visionData: visionData || {}
200
+ });
201
+ res.json(result);
202
+ });
203
+
204
+ // Human confirmation for a verification result
205
+ router.post('/verify/:verificationId/confirm', (req, res) => {
206
+ const { approved } = req.body;
207
+ const result = verification.confirmVerification(req.params.verificationId, approved);
208
+ res.json(result);
209
+ });
210
+
211
+ // Get shield stats for a site
212
+ router.get('/verify/stats/:siteId', (req, res) => {
213
+ const stats = verification.getShieldStats(req.params.siteId);
214
+ res.json(stats);
215
+ });
216
+
217
+ // Get global shield stats
218
+ router.get('/verify/stats', (req, res) => {
219
+ const stats = verification.getGlobalShieldStats();
220
+ res.json(stats);
221
+ });
222
+
223
+ // Update price benchmark
224
+ router.post('/verify/benchmarks', (req, res) => {
225
+ const { category, itemPattern, price } = req.body;
226
+ if (!category || !itemPattern || price == null) {
227
+ return res.status(400).json({ error: 'category, itemPattern, and price are required' });
228
+ }
229
+ verification.updateBenchmark(category, itemPattern, price);
230
+ res.json({ updated: true });
231
+ });
232
+
233
+ // ═══════════════════════════════════════════════════════════════════════
234
+ // SOVEREIGN DASHBOARD DATA API
235
+ // ═══════════════════════════════════════════════════════════════════════
236
+
237
+ router.get('/dashboard/sovereign', authenticateToken, (req, res) => {
238
+ const userId = req.user.id;
239
+
240
+ // Get user's sites
241
+ const { db: database } = require('../models/db');
242
+ const sites = database.prepare('SELECT id, domain FROM sites WHERE user_id = ?').all(userId);
243
+
244
+ const dashboardData = {
245
+ overview: {
246
+ sitesProtected: sites.length,
247
+ shieldStatus: 'active'
248
+ },
249
+ reputation: {},
250
+ negotiation: {},
251
+ shield: {},
252
+ privacy: { trackingAttempts: 0, intentionsEncrypted: 0, dataShielded: 0 }
253
+ };
254
+
255
+ // Aggregate data across all user's sites
256
+ let totalAttestations = 0, totalDeals = 0, totalSaved = 0;
257
+ let totalChecks = 0, totalBlocked = 0;
258
+ const siteDetails = [];
259
+
260
+ for (const site of sites) {
261
+ const rep = reputation.getReputation(site.id);
262
+ const negStats = negotiation.getNegotiationStats(site.id);
263
+ const shieldStats = verification.getShieldStats(site.id);
264
+
265
+ totalAttestations += rep.totalAttestations || 0;
266
+ totalDeals += negStats.deals_made || 0;
267
+ totalSaved += negStats.total_discount_given || 0;
268
+ totalChecks += shieldStats.total_checks || 0;
269
+ totalBlocked += (shieldStats.halted_operations || 0) + (shieldStats.blocked_operations || 0);
270
+
271
+ siteDetails.push({
272
+ siteId: site.id,
273
+ domain: site.domain,
274
+ reputationScore: rep.reputationScore,
275
+ trustLevel: rep.trustLevel,
276
+ dealsMade: negStats.deals_made || 0,
277
+ avgSavings: negStats.avg_savings || 0,
278
+ integrityRating: shieldStats.integrity_rating
279
+ });
280
+ }
281
+
282
+ dashboardData.reputation = {
283
+ totalAttestations,
284
+ avgReputationScore: siteDetails.length > 0
285
+ ? Math.round(siteDetails.reduce((s, d) => s + d.reputationScore, 0) / siteDetails.length)
286
+ : 50
287
+ };
288
+
289
+ dashboardData.negotiation = {
290
+ totalDeals,
291
+ totalSaved: Math.round(totalSaved * 100) / 100
292
+ };
293
+
294
+ dashboardData.shield = {
295
+ totalChecks,
296
+ threatsBlocked: totalBlocked,
297
+ integrityScore: siteDetails.length > 0
298
+ ? Math.round(siteDetails.reduce((s, d) => s + d.integrityRating, 0) / siteDetails.length)
299
+ : 100
300
+ };
301
+
302
+ dashboardData.sites = siteDetails;
303
+
304
+ res.json(dashboardData);
305
+ });
306
+
307
+ module.exports = router;