web-agent-bridge 2.0.0 → 2.1.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.
- package/README.ar.md +126 -0
- package/README.md +189 -1
- package/bin/agent-runner.js +465 -0
- package/bin/cli.js +58 -0
- package/package.json +4 -2
- package/public/index.html +86 -0
- package/public/script/wab.min.js +172 -1
- package/public/sovereign.html +660 -0
- package/sdk/package.json +1 -1
- package/server/index.js +2 -0
- package/server/routes/sovereign.js +307 -0
- package/server/services/negotiation.js +439 -0
- package/server/services/reputation.js +465 -0
- package/server/services/verification.js +481 -0
- package/templates/artisan-marketplace.yaml +104 -0
- package/templates/book-price-scout.yaml +98 -0
- package/templates/electronics-price-tracker.yaml +108 -0
- package/templates/flight-deal-hunter.yaml +113 -0
- package/templates/freelancer-direct.yaml +116 -0
- package/templates/grocery-price-compare.yaml +93 -0
- package/templates/hotel-direct-booking.yaml +113 -0
- package/templates/local-services.yaml +98 -0
- package/templates/olive-oil-tunisia.yaml +88 -0
- package/templates/organic-farm-fresh.yaml +101 -0
- package/templates/restaurant-direct.yaml +97 -0
package/server/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const apiRoutes = require('./routes/api');
|
|
|
18
18
|
const licenseRoutes = require('./routes/license');
|
|
19
19
|
const adminRoutes = require('./routes/admin');
|
|
20
20
|
const billingRoutes = require('./routes/billing');
|
|
21
|
+
const sovereignRoutes = require('./routes/sovereign');
|
|
21
22
|
const { handleWebhookRequest } = require('./services/stripe');
|
|
22
23
|
|
|
23
24
|
const app = express();
|
|
@@ -111,6 +112,7 @@ app.use('/api', apiLimiter, apiRoutes);
|
|
|
111
112
|
app.use('/api/license', licenseLimiter, licenseRoutes);
|
|
112
113
|
app.use('/api/admin', apiLimiter, adminRoutes);
|
|
113
114
|
app.use('/api/billing', apiLimiter, billingRoutes);
|
|
115
|
+
app.use('/api/sovereign', apiLimiter, sovereignRoutes);
|
|
114
116
|
|
|
115
117
|
app.get('/dashboard', (req, res) => {
|
|
116
118
|
res.sendFile(path.join(__dirname, '..', 'public', 'dashboard.html'));
|
|
@@ -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;
|