@dupecom/botcha-cloudflare 0.16.0 → 0.18.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,490 @@
1
+ /**
2
+ * TAP Delegation Chains
3
+ *
4
+ * "User X authorized Agent Y to do Z until time T."
5
+ *
6
+ * Signed, auditable chains of trust between TAP agents. A delegation grants
7
+ * a subset of one agent's capabilities to another agent, with time bounds
8
+ * and depth limits. Delegations can be chained (A→B→C) with each link
9
+ * only narrowing capabilities, never expanding them.
10
+ *
11
+ * Key invariants:
12
+ * - Capabilities can only be narrowed (subset enforcement)
13
+ * - Chain depth is capped (default max: 3)
14
+ * - Revoking a delegation cascades to all sub-delegations
15
+ * - Expired delegations are automatically invalid
16
+ * - Both grantor and grantee must belong to the same app
17
+ */
18
+ import { TAP_VALID_ACTIONS, getTAPAgent } from './tap-agents.js';
19
+ // ============ CONSTANTS ============
20
+ const MAX_DELEGATION_DEPTH = 10; // Absolute max depth
21
+ const DEFAULT_MAX_DEPTH = 3; // Default max depth
22
+ const DEFAULT_DURATION = 3600; // 1 hour in seconds
23
+ const MAX_DURATION = 86400 * 30; // 30 days max
24
+ const DELEGATION_PREFIX = 'del_';
25
+ // ============ CORE FUNCTIONS ============
26
+ /**
27
+ * Generate a unique delegation ID
28
+ */
29
+ function generateDelegationId() {
30
+ const bytes = new Uint8Array(16);
31
+ crypto.getRandomValues(bytes);
32
+ return DELEGATION_PREFIX + Array.from(bytes)
33
+ .map(b => b.toString(16).padStart(2, '0'))
34
+ .join('');
35
+ }
36
+ /**
37
+ * Check if capabilitiesB is a subset of capabilitiesA.
38
+ *
39
+ * A capability in B is valid if there exists a capability in A with the same
40
+ * action, and B's scope is a subset of A's scope (or A has wildcard scope).
41
+ * B's restrictions must be equal or stricter.
42
+ */
43
+ export function isCapabilitySubset(parent, child) {
44
+ for (const childCap of child) {
45
+ // Find matching parent capability by action
46
+ const parentCap = parent.find(p => p.action === childCap.action);
47
+ if (!parentCap) {
48
+ return {
49
+ valid: false,
50
+ error: `Cannot delegate capability '${childCap.action}': grantor does not have it`
51
+ };
52
+ }
53
+ // Check scope subset
54
+ if (childCap.scope && childCap.scope.length > 0) {
55
+ // If parent has no scope or wildcard, child's scope is valid
56
+ if (parentCap.scope && !parentCap.scope.includes('*')) {
57
+ for (const s of childCap.scope) {
58
+ if (s !== '*' && !parentCap.scope.includes(s)) {
59
+ return {
60
+ valid: false,
61
+ error: `Cannot delegate scope '${s}' for '${childCap.action}': grantor lacks it`
62
+ };
63
+ }
64
+ // Child requesting wildcard but parent doesn't have it
65
+ if (s === '*') {
66
+ return {
67
+ valid: false,
68
+ error: `Cannot delegate wildcard scope for '${childCap.action}': grantor has restricted scope`
69
+ };
70
+ }
71
+ }
72
+ }
73
+ }
74
+ // Check restrictions — child must be equal or stricter
75
+ if (parentCap.restrictions) {
76
+ if (!childCap.restrictions) {
77
+ // Parent has restrictions but child doesn't — child is less restrictive
78
+ // This is NOT allowed: delegated capabilities must be at least as restrictive
79
+ return {
80
+ valid: false,
81
+ error: `Cannot delegate '${childCap.action}' without restrictions: grantor has restrictions`
82
+ };
83
+ }
84
+ // max_amount: child's must be <= parent's
85
+ if (parentCap.restrictions.max_amount !== undefined) {
86
+ if (childCap.restrictions.max_amount === undefined ||
87
+ childCap.restrictions.max_amount > parentCap.restrictions.max_amount) {
88
+ return {
89
+ valid: false,
90
+ error: `Cannot delegate max_amount > ${parentCap.restrictions.max_amount} for '${childCap.action}'`
91
+ };
92
+ }
93
+ }
94
+ // rate_limit: child's must be <= parent's
95
+ if (parentCap.restrictions.rate_limit !== undefined) {
96
+ if (childCap.restrictions.rate_limit === undefined ||
97
+ childCap.restrictions.rate_limit > parentCap.restrictions.rate_limit) {
98
+ return {
99
+ valid: false,
100
+ error: `Cannot delegate rate_limit > ${parentCap.restrictions.rate_limit} for '${childCap.action}'`
101
+ };
102
+ }
103
+ }
104
+ }
105
+ }
106
+ return { valid: true };
107
+ }
108
+ /**
109
+ * Create a delegation from one agent to another.
110
+ *
111
+ * Validates:
112
+ * - Both agents exist and belong to the same app
113
+ * - Grantor has the capabilities being delegated
114
+ * - Capabilities are a valid subset (never expanded)
115
+ * - Chain depth is within limits
116
+ * - Parent delegation (if sub-delegation) is valid and not revoked/expired
117
+ */
118
+ export async function createDelegation(agents, sessions, appId, options) {
119
+ try {
120
+ // Validate basic inputs
121
+ if (!options.grantor_id || !options.grantee_id) {
122
+ return { success: false, error: 'grantor_id and grantee_id are required' };
123
+ }
124
+ if (options.grantor_id === options.grantee_id) {
125
+ return { success: false, error: 'Cannot delegate to self' };
126
+ }
127
+ if (!options.capabilities || options.capabilities.length === 0) {
128
+ return { success: false, error: 'At least one capability is required' };
129
+ }
130
+ // Validate capability actions
131
+ for (const cap of options.capabilities) {
132
+ if (!TAP_VALID_ACTIONS.includes(cap.action)) {
133
+ return { success: false, error: `Invalid capability action: ${cap.action}` };
134
+ }
135
+ }
136
+ // Validate max_depth (will be overridden for sub-delegations below)
137
+ let maxDepth = Math.min(options.max_depth ?? DEFAULT_MAX_DEPTH, MAX_DELEGATION_DEPTH);
138
+ // Get grantor agent
139
+ const grantorResult = await getTAPAgent(agents, options.grantor_id);
140
+ if (!grantorResult.success || !grantorResult.agent) {
141
+ return { success: false, error: 'Grantor agent not found' };
142
+ }
143
+ const grantor = grantorResult.agent;
144
+ // Get grantee agent
145
+ const granteeResult = await getTAPAgent(agents, options.grantee_id);
146
+ if (!granteeResult.success || !granteeResult.agent) {
147
+ return { success: false, error: 'Grantee agent not found' };
148
+ }
149
+ const grantee = granteeResult.agent;
150
+ // Verify same app
151
+ if (grantor.app_id !== appId) {
152
+ return { success: false, error: 'Grantor does not belong to this app' };
153
+ }
154
+ if (grantee.app_id !== appId) {
155
+ return { success: false, error: 'Grantee does not belong to this app' };
156
+ }
157
+ // Determine effective capabilities of the grantor
158
+ let grantorCapabilities = grantor.capabilities || [];
159
+ let chain = [options.grantor_id, options.grantee_id];
160
+ let depth = 0;
161
+ // If this is a sub-delegation, validate the parent delegation
162
+ if (options.parent_delegation_id) {
163
+ const parentDel = await getDelegation(sessions, options.parent_delegation_id);
164
+ if (!parentDel.success || !parentDel.delegation) {
165
+ return { success: false, error: 'Parent delegation not found' };
166
+ }
167
+ const parent = parentDel.delegation;
168
+ // Parent must not be revoked
169
+ if (parent.revoked) {
170
+ return { success: false, error: 'Parent delegation has been revoked' };
171
+ }
172
+ // Parent must not be expired
173
+ if (Date.now() > parent.expires_at) {
174
+ return { success: false, error: 'Parent delegation has expired' };
175
+ }
176
+ // Grantor must be the grantee of the parent delegation
177
+ if (parent.grantee_id !== options.grantor_id) {
178
+ return { success: false, error: 'Grantor is not the grantee of the parent delegation' };
179
+ }
180
+ // Must be same app
181
+ if (parent.app_id !== appId) {
182
+ return { success: false, error: 'Parent delegation belongs to a different app' };
183
+ }
184
+ // Check depth limits — inherit max_depth from parent chain
185
+ depth = parent.depth + 1;
186
+ maxDepth = parent.max_depth; // Always inherit from parent
187
+ if (depth >= maxDepth) {
188
+ return { success: false, error: `Delegation depth limit reached (max: ${maxDepth})` };
189
+ }
190
+ // For sub-delegations, the effective capabilities come from the parent
191
+ grantorCapabilities = parent.capabilities;
192
+ chain = [...parent.chain, options.grantee_id];
193
+ // Prevent cycles
194
+ if (parent.chain.includes(options.grantee_id)) {
195
+ return { success: false, error: 'Delegation would create a cycle' };
196
+ }
197
+ }
198
+ // Validate capability subset
199
+ const subsetCheck = isCapabilitySubset(grantorCapabilities, options.capabilities);
200
+ if (!subsetCheck.valid) {
201
+ return { success: false, error: subsetCheck.error };
202
+ }
203
+ // Calculate expiration
204
+ const durationSeconds = Math.min(options.duration_seconds ?? DEFAULT_DURATION, MAX_DURATION);
205
+ // If sub-delegation, cannot outlive parent
206
+ const now = Date.now();
207
+ let expiresAt = now + durationSeconds * 1000;
208
+ if (options.parent_delegation_id) {
209
+ const parentDel = await getDelegation(sessions, options.parent_delegation_id);
210
+ if (parentDel.delegation) {
211
+ expiresAt = Math.min(expiresAt, parentDel.delegation.expires_at);
212
+ }
213
+ }
214
+ // Create the delegation
215
+ const delegationId = generateDelegationId();
216
+ const delegation = {
217
+ delegation_id: delegationId,
218
+ grantor_id: options.grantor_id,
219
+ grantee_id: options.grantee_id,
220
+ app_id: appId,
221
+ capabilities: options.capabilities,
222
+ parent_delegation_id: options.parent_delegation_id,
223
+ chain,
224
+ depth,
225
+ max_depth: maxDepth,
226
+ created_at: now,
227
+ expires_at: expiresAt,
228
+ revoked: false,
229
+ metadata: options.metadata,
230
+ };
231
+ // Store delegation with TTL
232
+ const ttlSeconds = Math.max(1, Math.floor((expiresAt - now) / 1000));
233
+ await sessions.put(`delegation:${delegationId}`, JSON.stringify(delegation), { expirationTtl: ttlSeconds });
234
+ // Update grantor's outbound index
235
+ await updateDelegationIndex(sessions, `agent_delegations_out:${options.grantor_id}`, delegationId, 'add');
236
+ // Update grantee's inbound index
237
+ await updateDelegationIndex(sessions, `agent_delegations_in:${options.grantee_id}`, delegationId, 'add');
238
+ return { success: true, delegation };
239
+ }
240
+ catch (error) {
241
+ console.error('Failed to create delegation:', error);
242
+ return { success: false, error: 'Internal server error' };
243
+ }
244
+ }
245
+ /**
246
+ * Get a delegation by ID
247
+ */
248
+ export async function getDelegation(sessions, delegationId) {
249
+ try {
250
+ const data = await sessions.get(`delegation:${delegationId}`, 'text');
251
+ if (!data) {
252
+ return { success: false, error: 'Delegation not found or expired' };
253
+ }
254
+ const delegation = JSON.parse(data);
255
+ return { success: true, delegation };
256
+ }
257
+ catch (error) {
258
+ console.error('Failed to get delegation:', error);
259
+ return { success: false, error: 'Internal server error' };
260
+ }
261
+ }
262
+ /**
263
+ * List delegations for an agent (inbound, outbound, or both)
264
+ */
265
+ export async function listDelegations(sessions, options) {
266
+ try {
267
+ const delegationIds = new Set();
268
+ const direction = options.direction || 'both';
269
+ if (options.agent_id) {
270
+ // Get delegations by agent
271
+ if (direction === 'out' || direction === 'both') {
272
+ const outData = await sessions.get(`agent_delegations_out:${options.agent_id}`, 'text');
273
+ if (outData) {
274
+ for (const id of JSON.parse(outData)) {
275
+ delegationIds.add(id);
276
+ }
277
+ }
278
+ }
279
+ if (direction === 'in' || direction === 'both') {
280
+ const inData = await sessions.get(`agent_delegations_in:${options.agent_id}`, 'text');
281
+ if (inData) {
282
+ for (const id of JSON.parse(inData)) {
283
+ delegationIds.add(id);
284
+ }
285
+ }
286
+ }
287
+ }
288
+ if (delegationIds.size === 0) {
289
+ return { success: true, delegations: [] };
290
+ }
291
+ // Fetch all delegations
292
+ const now = Date.now();
293
+ const delegations = [];
294
+ for (const id of delegationIds) {
295
+ const result = await getDelegation(sessions, id);
296
+ if (result.success && result.delegation) {
297
+ const d = result.delegation;
298
+ // Filter by app_id if specified
299
+ if (options.app_id && d.app_id !== options.app_id)
300
+ continue;
301
+ // Filter out revoked unless requested
302
+ if (d.revoked && !options.include_revoked)
303
+ continue;
304
+ // Filter out expired unless requested
305
+ if (now > d.expires_at && !options.include_expired)
306
+ continue;
307
+ delegations.push(d);
308
+ }
309
+ }
310
+ // Sort by created_at descending (newest first)
311
+ delegations.sort((a, b) => b.created_at - a.created_at);
312
+ return { success: true, delegations };
313
+ }
314
+ catch (error) {
315
+ console.error('Failed to list delegations:', error);
316
+ return { success: false, error: 'Internal server error' };
317
+ }
318
+ }
319
+ /**
320
+ * Revoke a delegation and cascade to all sub-delegations.
321
+ *
322
+ * When a delegation is revoked, all delegations that have it as a parent
323
+ * (directly or transitively) are also revoked. This is enforced by marking
324
+ * each delegation record as revoked.
325
+ */
326
+ export async function revokeDelegation(sessions, delegationId, reason) {
327
+ try {
328
+ const result = await getDelegation(sessions, delegationId);
329
+ if (!result.success || !result.delegation) {
330
+ return { success: false, error: 'Delegation not found' };
331
+ }
332
+ const delegation = result.delegation;
333
+ if (delegation.revoked) {
334
+ return { success: true, delegation }; // Already revoked, idempotent
335
+ }
336
+ // Mark as revoked
337
+ delegation.revoked = true;
338
+ delegation.revoked_at = Date.now();
339
+ delegation.revocation_reason = reason;
340
+ // Re-store with remaining TTL (or short TTL if already expired)
341
+ const remainingTtl = Math.max(60, Math.floor((delegation.expires_at - Date.now()) / 1000));
342
+ await sessions.put(`delegation:${delegationId}`, JSON.stringify(delegation), { expirationTtl: remainingTtl });
343
+ // Cascade: find and revoke sub-delegations
344
+ // We search the grantee's outbound delegations for any that reference this as parent
345
+ await cascadeRevocation(sessions, delegationId, reason);
346
+ return { success: true, delegation };
347
+ }
348
+ catch (error) {
349
+ console.error('Failed to revoke delegation:', error);
350
+ return { success: false, error: 'Internal server error' };
351
+ }
352
+ }
353
+ /**
354
+ * Recursively revoke all sub-delegations of a given delegation.
355
+ */
356
+ async function cascadeRevocation(sessions, parentDelegationId, reason) {
357
+ // Get the parent delegation to find the grantee
358
+ const parentResult = await getDelegation(sessions, parentDelegationId);
359
+ if (!parentResult.success || !parentResult.delegation)
360
+ return;
361
+ const granteeId = parentResult.delegation.grantee_id;
362
+ // Get grantee's outbound delegations
363
+ const outData = await sessions.get(`agent_delegations_out:${granteeId}`, 'text');
364
+ if (!outData)
365
+ return;
366
+ const outIds = JSON.parse(outData);
367
+ for (const childId of outIds) {
368
+ const childResult = await getDelegation(sessions, childId);
369
+ if (!childResult.success || !childResult.delegation)
370
+ continue;
371
+ const child = childResult.delegation;
372
+ // Only revoke if this child's parent is our delegation
373
+ if (child.parent_delegation_id === parentDelegationId && !child.revoked) {
374
+ // Revoke this child (which will cascade further)
375
+ await revokeDelegation(sessions, childId, reason || `Parent delegation ${parentDelegationId} revoked`);
376
+ }
377
+ }
378
+ }
379
+ /**
380
+ * Verify an entire delegation chain is valid.
381
+ *
382
+ * Walks from the leaf delegation up through parent delegations to the root,
383
+ * verifying each link is:
384
+ * - Not revoked
385
+ * - Not expired
386
+ * - Capabilities are valid subsets
387
+ *
388
+ * Returns the full chain and effective (intersected) capabilities.
389
+ */
390
+ export async function verifyDelegationChain(agents, sessions, delegationId) {
391
+ try {
392
+ const chain = [];
393
+ let currentId = delegationId;
394
+ const now = Date.now();
395
+ // Walk up the chain
396
+ while (currentId) {
397
+ const result = await getDelegation(sessions, currentId);
398
+ if (!result.success || !result.delegation) {
399
+ return { valid: false, error: `Delegation ${currentId} not found or expired` };
400
+ }
401
+ const del = result.delegation;
402
+ // Check revocation
403
+ if (del.revoked) {
404
+ return {
405
+ valid: false,
406
+ error: `Delegation ${currentId} has been revoked${del.revocation_reason ? ': ' + del.revocation_reason : ''}`
407
+ };
408
+ }
409
+ // Check expiration
410
+ if (now > del.expires_at) {
411
+ return { valid: false, error: `Delegation ${currentId} has expired` };
412
+ }
413
+ // Verify grantor agent exists
414
+ const grantorResult = await getTAPAgent(agents, del.grantor_id);
415
+ if (!grantorResult.success) {
416
+ return { valid: false, error: `Grantor agent ${del.grantor_id} not found` };
417
+ }
418
+ chain.unshift(del); // Add to front (building root→leaf order)
419
+ currentId = del.parent_delegation_id;
420
+ }
421
+ if (chain.length === 0) {
422
+ return { valid: false, error: 'Empty delegation chain' };
423
+ }
424
+ // Verify capability narrowing at each step
425
+ // The root delegation's capabilities must be a subset of the root grantor's capabilities
426
+ const rootDel = chain[0];
427
+ const rootGrantorResult = await getTAPAgent(agents, rootDel.grantor_id);
428
+ if (!rootGrantorResult.success || !rootGrantorResult.agent) {
429
+ return { valid: false, error: 'Root grantor agent not found' };
430
+ }
431
+ const rootCheck = isCapabilitySubset(rootGrantorResult.agent.capabilities || [], rootDel.capabilities);
432
+ if (!rootCheck.valid) {
433
+ return { valid: false, error: `Root delegation invalid: ${rootCheck.error}` };
434
+ }
435
+ // Verify each subsequent link narrows from its parent
436
+ for (let i = 1; i < chain.length; i++) {
437
+ const parentCaps = chain[i - 1].capabilities;
438
+ const childCaps = chain[i].capabilities;
439
+ const check = isCapabilitySubset(parentCaps, childCaps);
440
+ if (!check.valid) {
441
+ return {
442
+ valid: false,
443
+ error: `Chain link ${i} invalid: ${check.error}`
444
+ };
445
+ }
446
+ }
447
+ // Effective capabilities = leaf delegation's capabilities
448
+ // (since each step only narrows, the leaf is the most restricted)
449
+ const effectiveCapabilities = chain[chain.length - 1].capabilities;
450
+ return {
451
+ valid: true,
452
+ chain,
453
+ effective_capabilities: effectiveCapabilities,
454
+ };
455
+ }
456
+ catch (error) {
457
+ console.error('Failed to verify delegation chain:', error);
458
+ return { valid: false, error: 'Internal server error' };
459
+ }
460
+ }
461
+ // ============ UTILITY FUNCTIONS ============
462
+ /**
463
+ * Update an agent's delegation index (inbound or outbound)
464
+ */
465
+ async function updateDelegationIndex(sessions, key, delegationId, operation) {
466
+ try {
467
+ const data = await sessions.get(key, 'text');
468
+ let ids = data ? JSON.parse(data) : [];
469
+ if (operation === 'add' && !ids.includes(delegationId)) {
470
+ ids.push(delegationId);
471
+ }
472
+ else if (operation === 'remove') {
473
+ ids = ids.filter(id => id !== delegationId);
474
+ }
475
+ // No TTL on indexes — they reference delegations which have their own TTL
476
+ await sessions.put(key, JSON.stringify(ids));
477
+ }
478
+ catch (error) {
479
+ console.error('Failed to update delegation index:', error);
480
+ // Fail silently — index updates are not critical
481
+ }
482
+ }
483
+ export default {
484
+ createDelegation,
485
+ getDelegation,
486
+ listDelegations,
487
+ revokeDelegation,
488
+ verifyDelegationChain,
489
+ isCapabilitySubset,
490
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * TAP Agent Reputation Scoring API Routes
3
+ *
4
+ * Endpoints for querying agent reputation scores, recording events,
5
+ * listing event history, and resetting scores.
6
+ *
7
+ * Routes:
8
+ * GET /v1/reputation/:agent_id — Get agent reputation score
9
+ * POST /v1/reputation/events — Record a reputation event
10
+ * GET /v1/reputation/:agent_id/events — List reputation events
11
+ * POST /v1/reputation/:agent_id/reset — Reset agent reputation (admin)
12
+ */
13
+ import type { Context } from 'hono';
14
+ import { type ReputationEventCategory, type ReputationEventAction } from './tap-reputation.js';
15
+ /**
16
+ * GET /v1/reputation/:agent_id
17
+ * Get agent reputation score
18
+ */
19
+ export declare function getReputationRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
20
+ success: false;
21
+ error: string | undefined;
22
+ message: string;
23
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
24
+ success: false;
25
+ error: string;
26
+ message: string | undefined;
27
+ }, any, "json">) | (Response & import("hono").TypedResponse<{
28
+ success: true;
29
+ agent_id: string;
30
+ app_id: string;
31
+ score: number;
32
+ tier: import("./tap-reputation.js").ReputationTier;
33
+ event_count: number;
34
+ positive_events: number;
35
+ negative_events: number;
36
+ last_event_at: string | null;
37
+ created_at: string;
38
+ updated_at: string;
39
+ category_scores: {
40
+ verification: number;
41
+ attestation: number;
42
+ delegation: number;
43
+ session: number;
44
+ violation: number;
45
+ endorsement: number;
46
+ };
47
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
48
+ /**
49
+ * POST /v1/reputation/events
50
+ * Record a reputation event for an agent
51
+ *
52
+ * Body:
53
+ * agent_id — required
54
+ * category — required (verification, attestation, delegation, session, violation, endorsement)
55
+ * action — required (e.g. "challenge_solved", "attestation_issued")
56
+ * source_agent_id — optional (for endorsements)
57
+ * metadata — optional key/value pairs
58
+ */
59
+ export declare function recordReputationEventRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
60
+ success: false;
61
+ error: string | undefined;
62
+ message: string;
63
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
64
+ success: false;
65
+ error: string;
66
+ message: string | undefined;
67
+ }, any, "json">) | (Response & import("hono").TypedResponse<{
68
+ success: true;
69
+ event: {
70
+ event_id: string;
71
+ agent_id: string;
72
+ category: ReputationEventCategory;
73
+ action: ReputationEventAction;
74
+ delta: number;
75
+ score_before: number;
76
+ score_after: number;
77
+ source_agent_id: string | null;
78
+ metadata: {
79
+ [x: string]: string;
80
+ } | null;
81
+ created_at: string;
82
+ };
83
+ score: {
84
+ score: number;
85
+ tier: import("./tap-reputation.js").ReputationTier;
86
+ event_count: number;
87
+ };
88
+ }, 201, "json">)>;
89
+ /**
90
+ * GET /v1/reputation/:agent_id/events
91
+ * List reputation events for an agent
92
+ *
93
+ * Query params:
94
+ * category — optional, filter by category
95
+ * limit — optional, max events to return (default 50, max 100)
96
+ */
97
+ export declare function listReputationEventsRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
98
+ success: false;
99
+ error: string;
100
+ message: string;
101
+ }, 400, "json">) | (Response & import("hono").TypedResponse<{
102
+ success: false;
103
+ error: string | undefined;
104
+ message: string;
105
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
106
+ success: false;
107
+ error: string;
108
+ message: string | undefined;
109
+ }, 500, "json">) | (Response & import("hono").TypedResponse<{
110
+ success: true;
111
+ events: {
112
+ event_id: string;
113
+ agent_id: string;
114
+ category: ReputationEventCategory;
115
+ action: ReputationEventAction;
116
+ delta: number;
117
+ score_before: number;
118
+ score_after: number;
119
+ source_agent_id: string | null;
120
+ metadata: {
121
+ [x: string]: string;
122
+ } | null;
123
+ created_at: string;
124
+ }[];
125
+ count: number;
126
+ agent_id: string;
127
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
128
+ /**
129
+ * POST /v1/reputation/:agent_id/reset
130
+ * Reset agent reputation to default (admin action)
131
+ */
132
+ export declare function resetReputationRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
133
+ success: false;
134
+ error: string | undefined;
135
+ message: string;
136
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
137
+ success: false;
138
+ error: string;
139
+ message: string | undefined;
140
+ }, any, "json">) | (Response & import("hono").TypedResponse<{
141
+ success: true;
142
+ agent_id: string;
143
+ score: number;
144
+ tier: import("./tap-reputation.js").ReputationTier;
145
+ message: string;
146
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
147
+ declare const _default: {
148
+ getReputationRoute: typeof getReputationRoute;
149
+ recordReputationEventRoute: typeof recordReputationEventRoute;
150
+ listReputationEventsRoute: typeof listReputationEventsRoute;
151
+ resetReputationRoute: typeof resetReputationRoute;
152
+ };
153
+ export default _default;
154
+ //# sourceMappingURL=tap-reputation-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tap-reputation-routes.d.ts","sourceRoot":"","sources":["../src/tap-reputation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EASL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAkC7B;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEA6DlD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2H1D;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEA4EzD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;oEAyDpD;;;;;;;AAED,wBAKE"}