@dupecom/botcha-cloudflare 0.11.0 → 0.13.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/dist/static.js CHANGED
@@ -77,6 +77,16 @@ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
77
77
  | \`GET\` | \`/v1/agents/:id\` | Get agent by ID (public, no auth) |
78
78
  | \`GET\` | \`/v1/agents\` | List all agents for your app (auth required) |
79
79
 
80
+ ### TAP (Trusted Agent Protocol)
81
+
82
+ | Method | Path | Description |
83
+ |--------|------|-------------|
84
+ | \`POST\` | \`/v1/agents/register/tap\` | Register TAP agent with public key + capabilities |
85
+ | \`GET\` | \`/v1/agents/:id/tap\` | Get TAP agent details (includes public key) |
86
+ | \`GET\` | \`/v1/agents/tap\` | List TAP-enabled agents for app |
87
+ | \`POST\` | \`/v1/sessions/tap\` | Create TAP session with intent validation |
88
+ | \`GET\` | \`/v1/sessions/:id/tap\` | Get TAP session info |
89
+
80
90
  ### Challenges
81
91
 
82
92
  | Method | Path | Description |
@@ -272,6 +282,9 @@ Feature: Email-Tied App Creation (email required, 6-digit verification, account
272
282
  Feature: Secret Rotation (rotate app_secret with email notification)
273
283
  Feature: Agent-First Dashboard Auth (challenge-based login + device code handoff)
274
284
  Feature: Agent Registry (persistent agent identities with name, operator, version)
285
+ Feature: Trusted Agent Protocol (TAP) — cryptographic agent auth with HTTP Message Signatures (RFC 9421)
286
+ Feature: TAP Capabilities (action + resource scoping for agent sessions)
287
+ Feature: TAP Trust Levels (basic, verified, enterprise)
275
288
 
276
289
  # Endpoints
277
290
  # Challenge Endpoints
@@ -310,11 +323,22 @@ Endpoint: GET https://botcha.ai/dashboard/login - Dashboard login page
310
323
  Endpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret
311
324
  Endpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)
312
325
 
326
+ # Code Redemption (Unified)
327
+ Endpoint: GET https://botcha.ai/go/:code - Unified code redemption — handles gate codes (from /v1/token/verify) AND device codes (from /v1/auth/device-code/verify)
328
+ Endpoint: POST https://botcha.ai/gate - Submit code form, redirects to /go/:code
329
+
313
330
  # Agent Registry Endpoints
314
331
  Endpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)
315
332
  Endpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)
316
333
  Endpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app
317
334
 
335
+ # TAP (Trusted Agent Protocol) Endpoints
336
+ Endpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities
337
+ Endpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key)
338
+ Endpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app
339
+ Endpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation
340
+ Endpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info
341
+
318
342
  # Legacy Endpoints
319
343
  Endpoint: GET https://botcha.ai/api/challenge - Generate standard challenge
320
344
  Endpoint: POST https://botcha.ai/api/challenge - Verify standard challenge
@@ -350,7 +374,8 @@ Content-Negotiation-Example: curl https://botcha.ai -H "Accept: text/markdown"
350
374
  Content-Negotiation-Benefit: 80% fewer tokens vs HTML — ideal for LLM context windows
351
375
 
352
376
  # JWT TOKEN SECURITY
353
- Token-Flow: 1. GET /v1/token (get challenge) → 2. Solve → 3. POST /v1/token/verify (get tokens)
377
+ Token-Flow: 1. GET /v1/token (get challenge) → 2. Solve → 3. POST /v1/token/verify (get tokens + human_link)
378
+ Token-Human-Link: /v1/token/verify response includes human_link — give this URL to your human for one-click browser access
354
379
  Token-Access-Expiry: 5 minutes (short-lived for security)
355
380
  Token-Refresh-Expiry: 1 hour (use to get new access tokens)
356
381
  Token-Refresh: POST /v1/token/refresh with {"refresh_token": "<token>"}
@@ -381,6 +406,18 @@ SDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verifica
381
406
  Multi-Tenant-Rate-Limit: Each app gets isolated rate limit bucket
382
407
  Multi-Tenant-Token-Claim: Tokens include app_id claim when app_id provided
383
408
 
409
+ # TRUSTED AGENT PROTOCOL (TAP)
410
+ TAP-Description: Enterprise-grade cryptographic agent auth using HTTP Message Signatures (RFC 9421)
411
+ TAP-Register: POST /v1/agents/register/tap with {name, public_key, signature_algorithm, capabilities, trust_level}
412
+ TAP-Algorithms: ecdsa-p256-sha256, rsa-pss-sha256
413
+ TAP-Trust-Levels: basic, verified, enterprise
414
+ TAP-Capabilities: Array of {action, resource, constraints} — scoped access control
415
+ TAP-Session-Create: POST /v1/sessions/tap with {agent_id, user_context, intent}
416
+ TAP-Session-Get: GET /v1/sessions/:id/tap — includes time_remaining
417
+ TAP-Get-Agent: GET /v1/agents/:id/tap — includes public_key for verification
418
+ TAP-List-Agents: GET /v1/agents/tap?app_id=...&tap_only=true
419
+ TAP-Middleware-Modes: tap, signature-only, challenge-only, flexible
420
+
384
421
  # EMBEDDED CHALLENGE (for bots visiting HTML pages)
385
422
  Embedded-Challenge: <script type="application/botcha+json">
386
423
  Embedded-Challenge-Location: In <head> of HTML pages
@@ -1099,6 +1136,159 @@ export function getOpenApiSpec(version) {
1099
1136
  "401": { description: "Unauthorized - app_id required" }
1100
1137
  }
1101
1138
  }
1139
+ },
1140
+ "/v1/agents/register/tap": {
1141
+ post: {
1142
+ summary: "Register a TAP-enabled agent",
1143
+ description: "Register an agent with Trusted Agent Protocol (TAP) capabilities including public key, signature algorithm, capabilities, and trust level. Requires app_id.",
1144
+ operationId: "registerTAPAgent",
1145
+ parameters: [
1146
+ {
1147
+ name: "app_id",
1148
+ in: "query",
1149
+ schema: { type: "string" },
1150
+ description: "Multi-tenant app ID (or use JWT Bearer token with app_id claim)"
1151
+ }
1152
+ ],
1153
+ requestBody: {
1154
+ required: true,
1155
+ content: {
1156
+ "application/json": {
1157
+ schema: {
1158
+ type: "object",
1159
+ required: ["name"],
1160
+ properties: {
1161
+ "name": { type: "string", description: "Agent name" },
1162
+ "operator": { type: "string", description: "Operator/organization name" },
1163
+ "version": { type: "string", description: "Agent version" },
1164
+ "public_key": { type: "string", description: "PEM-encoded public key" },
1165
+ "signature_algorithm": { type: "string", enum: ["ecdsa-p256-sha256", "rsa-pss-sha256"], description: "Signature algorithm (required if public_key provided)" },
1166
+ "trust_level": { type: "string", enum: ["basic", "verified", "enterprise"], description: "Agent trust level (default: basic)" },
1167
+ "capabilities": {
1168
+ type: "array",
1169
+ items: {
1170
+ type: "object",
1171
+ properties: {
1172
+ "action": { type: "string", description: "Capability action (e.g., read, write, execute)" },
1173
+ "resource": { type: "string", description: "Resource path" },
1174
+ "constraints": { type: "object", description: "Optional constraints" }
1175
+ }
1176
+ },
1177
+ description: "Agent capabilities (action + resource pairs)"
1178
+ }
1179
+ }
1180
+ }
1181
+ }
1182
+ }
1183
+ },
1184
+ responses: {
1185
+ "201": { description: "TAP agent registered successfully" },
1186
+ "400": { description: "Invalid request (missing fields, bad key format, invalid algorithm)" },
1187
+ "401": { description: "Unauthorized - app_id required" }
1188
+ }
1189
+ }
1190
+ },
1191
+ "/v1/agents/{id}/tap": {
1192
+ get: {
1193
+ summary: "Get TAP agent details",
1194
+ description: "Retrieve TAP-enhanced agent information including public key, capabilities, and trust level.",
1195
+ operationId: "getTAPAgent",
1196
+ parameters: [
1197
+ {
1198
+ name: "id",
1199
+ in: "path",
1200
+ required: true,
1201
+ schema: { type: "string" },
1202
+ description: "The agent_id to retrieve"
1203
+ }
1204
+ ],
1205
+ responses: {
1206
+ "200": { description: "TAP agent details including public key and capabilities" },
1207
+ "404": { description: "Agent not found" }
1208
+ }
1209
+ }
1210
+ },
1211
+ "/v1/agents/tap": {
1212
+ get: {
1213
+ summary: "List TAP-enabled agents",
1214
+ description: "List all TAP-enabled agents for the authenticated app. Use ?tap_only=true to filter to TAP-enabled agents only.",
1215
+ operationId: "listTAPAgents",
1216
+ parameters: [
1217
+ {
1218
+ name: "app_id",
1219
+ in: "query",
1220
+ schema: { type: "string" },
1221
+ description: "Multi-tenant app ID"
1222
+ },
1223
+ {
1224
+ name: "tap_only",
1225
+ in: "query",
1226
+ schema: { type: "string", enum: ["true", "false"] },
1227
+ description: "Filter to TAP-enabled agents only"
1228
+ }
1229
+ ],
1230
+ responses: {
1231
+ "200": { description: "List of TAP agents with capabilities and trust levels" },
1232
+ "401": { description: "Unauthorized - app_id required" }
1233
+ }
1234
+ }
1235
+ },
1236
+ "/v1/sessions/tap": {
1237
+ post: {
1238
+ summary: "Create a TAP session",
1239
+ description: "Create a capability-scoped session after validating the agent's intent against its registered capabilities.",
1240
+ operationId: "createTAPSession",
1241
+ requestBody: {
1242
+ required: true,
1243
+ content: {
1244
+ "application/json": {
1245
+ schema: {
1246
+ type: "object",
1247
+ required: ["agent_id", "user_context", "intent"],
1248
+ properties: {
1249
+ "agent_id": { type: "string", description: "Registered TAP agent ID" },
1250
+ "user_context": { type: "string", description: "User context identifier" },
1251
+ "intent": {
1252
+ type: "object",
1253
+ properties: {
1254
+ "action": { type: "string", description: "Intended action (e.g., read, write)" },
1255
+ "resource": { type: "string", description: "Target resource path" },
1256
+ "purpose": { type: "string", description: "Human-readable purpose" }
1257
+ },
1258
+ description: "Declared intent for the session"
1259
+ }
1260
+ }
1261
+ }
1262
+ }
1263
+ }
1264
+ },
1265
+ responses: {
1266
+ "201": { description: "TAP session created with capabilities and expiry" },
1267
+ "400": { description: "Missing required fields or invalid intent" },
1268
+ "403": { description: "Agent lacks required capability for declared intent" },
1269
+ "404": { description: "Agent not found" }
1270
+ }
1271
+ }
1272
+ },
1273
+ "/v1/sessions/{id}/tap": {
1274
+ get: {
1275
+ summary: "Get TAP session info",
1276
+ description: "Retrieve TAP session details including capabilities, intent, and time remaining.",
1277
+ operationId: "getTAPSession",
1278
+ parameters: [
1279
+ {
1280
+ name: "id",
1281
+ in: "path",
1282
+ required: true,
1283
+ schema: { type: "string" },
1284
+ description: "The session_id to retrieve"
1285
+ }
1286
+ ],
1287
+ responses: {
1288
+ "200": { description: "TAP session details with time remaining" },
1289
+ "404": { description: "Session not found or expired" }
1290
+ }
1291
+ }
1102
1292
  }
1103
1293
  },
1104
1294
  components: {
@@ -0,0 +1,120 @@
1
+ /**
2
+ * TAP-Enhanced Agent Registry
3
+ * Extends the basic BOTCHA agent registry with Trusted Agent Protocol features
4
+ *
5
+ * Provides enterprise-grade cryptographic agent authentication with:
6
+ * - HTTP Message Signatures (RFC 9421)
7
+ * - Capability-based access control
8
+ * - Intent declaration and validation
9
+ * - Session management with expiration
10
+ */
11
+ import { Agent, KVNamespace } from './agents.js';
12
+ /**
13
+ * TAP-enhanced agent record (backward compatible with Agent)
14
+ */
15
+ export interface TAPAgent extends Agent {
16
+ public_key?: string;
17
+ signature_algorithm?: 'ecdsa-p256-sha256' | 'rsa-pss-sha256';
18
+ key_created_at?: number;
19
+ capabilities?: TAPCapability[];
20
+ trust_level?: 'basic' | 'verified' | 'enterprise';
21
+ issuer?: string;
22
+ tap_enabled?: boolean;
23
+ last_verified_at?: number;
24
+ }
25
+ /** Valid TAP capability actions — single source of truth */
26
+ export declare const TAP_VALID_ACTIONS: readonly ["browse", "compare", "purchase", "audit", "search"];
27
+ export type TAPAction = typeof TAP_VALID_ACTIONS[number];
28
+ export interface TAPCapability {
29
+ action: TAPAction;
30
+ scope?: string[];
31
+ restrictions?: {
32
+ max_amount?: number;
33
+ rate_limit?: number;
34
+ [key: string]: any;
35
+ };
36
+ }
37
+ export interface TAPSession {
38
+ session_id: string;
39
+ agent_id: string;
40
+ app_id: string;
41
+ user_context: string;
42
+ capabilities: TAPCapability[];
43
+ intent: TAPIntent;
44
+ created_at: number;
45
+ expires_at: number;
46
+ }
47
+ export interface TAPIntent {
48
+ action: string;
49
+ resource?: string;
50
+ scope?: string[];
51
+ duration?: number;
52
+ }
53
+ /**
54
+ * Register an agent with TAP capabilities
55
+ */
56
+ export declare function registerTAPAgent(agents: KVNamespace, appId: string, registration: {
57
+ name: string;
58
+ operator?: string;
59
+ version?: string;
60
+ public_key?: string;
61
+ signature_algorithm?: 'ecdsa-p256-sha256' | 'rsa-pss-sha256';
62
+ capabilities?: TAPCapability[];
63
+ trust_level?: 'basic' | 'verified' | 'enterprise';
64
+ issuer?: string;
65
+ }): Promise<{
66
+ success: boolean;
67
+ agent?: TAPAgent;
68
+ error?: string;
69
+ }>;
70
+ /**
71
+ * Get agent with TAP capabilities
72
+ */
73
+ export declare function getTAPAgent(agents: KVNamespace, agentId: string): Promise<{
74
+ success: boolean;
75
+ agent?: TAPAgent;
76
+ error?: string;
77
+ }>;
78
+ /**
79
+ * Update agent's last verification timestamp
80
+ */
81
+ export declare function updateAgentVerification(agents: KVNamespace, agentId: string, verificationSuccess: boolean): Promise<void>;
82
+ /**
83
+ * List TAP-enabled agents for an app
84
+ */
85
+ export declare function listTAPAgents(agents: KVNamespace, appId: string, tapOnly?: boolean): Promise<{
86
+ success: boolean;
87
+ agents?: TAPAgent[];
88
+ error?: string;
89
+ }>;
90
+ /**
91
+ * Create a TAP session after successful verification
92
+ */
93
+ export declare function createTAPSession(sessions: KVNamespace, agentId: string, appId: string, userContext: string, capabilities: TAPCapability[], intent: TAPIntent): Promise<{
94
+ success: boolean;
95
+ session?: TAPSession;
96
+ error?: string;
97
+ }>;
98
+ /**
99
+ * Get and validate TAP session
100
+ */
101
+ export declare function getTAPSession(sessions: KVNamespace, sessionId: string): Promise<{
102
+ success: boolean;
103
+ session?: TAPSession;
104
+ error?: string;
105
+ }>;
106
+ export declare function validateCapability(agentCapabilities: TAPCapability[], requiredAction: string, requiredScope?: string): {
107
+ valid: boolean;
108
+ error?: string;
109
+ };
110
+ declare const _default: {
111
+ registerTAPAgent: typeof registerTAPAgent;
112
+ getTAPAgent: typeof getTAPAgent;
113
+ listTAPAgents: typeof listTAPAgents;
114
+ updateAgentVerification: typeof updateAgentVerification;
115
+ createTAPSession: typeof createTAPSession;
116
+ getTAPSession: typeof getTAPSession;
117
+ validateCapability: typeof validateCapability;
118
+ };
119
+ export default _default;
120
+ //# sourceMappingURL=tap-agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tap-agents.d.ts","sourceRoot":"","sources":["../src/tap-agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAC;AAIlE;;GAEG;AACH,MAAM,WAAW,QAAS,SAAQ,KAAK;IAErC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,gBAAgB,CAAC;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;IAGlD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,+DAAgE,CAAC;AAC/F,MAAM,MAAM,SAAS,GAAG,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,gBAAgB,CAAC;IAC7D,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgDjE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAcjE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,OAAO,GAC3B,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,OAAe,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBpE;AAID;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,aAAa,EAAE,EAC7B,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA+BrE;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBrE;AA2CD,wBAAgB,kBAAkB,CAChC,iBAAiB,EAAE,aAAa,EAAE,EAClC,cAAc,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAsBpC;;;;;;;;;;AAED,wBAQE"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * TAP-Enhanced Agent Registry
3
+ * Extends the basic BOTCHA agent registry with Trusted Agent Protocol features
4
+ *
5
+ * Provides enterprise-grade cryptographic agent authentication with:
6
+ * - HTTP Message Signatures (RFC 9421)
7
+ * - Capability-based access control
8
+ * - Intent declaration and validation
9
+ * - Session management with expiration
10
+ */
11
+ import { generateAgentId } from './agents.js';
12
+ /** Valid TAP capability actions — single source of truth */
13
+ export const TAP_VALID_ACTIONS = ['browse', 'compare', 'purchase', 'audit', 'search'];
14
+ // ============ TAP AGENT MANAGEMENT ============
15
+ /**
16
+ * Register an agent with TAP capabilities
17
+ */
18
+ export async function registerTAPAgent(agents, appId, registration) {
19
+ try {
20
+ const agentId = generateAgentId();
21
+ const now = Date.now();
22
+ const agent = {
23
+ agent_id: agentId,
24
+ app_id: appId,
25
+ name: registration.name,
26
+ operator: registration.operator,
27
+ version: registration.version,
28
+ created_at: now,
29
+ // TAP fields
30
+ public_key: registration.public_key,
31
+ signature_algorithm: registration.signature_algorithm,
32
+ key_created_at: registration.public_key ? now : undefined,
33
+ capabilities: registration.capabilities || [],
34
+ trust_level: registration.trust_level || 'basic',
35
+ issuer: registration.issuer,
36
+ tap_enabled: Boolean(registration.public_key),
37
+ last_verified_at: undefined
38
+ };
39
+ // Validate TAP configuration
40
+ if (agent.public_key) {
41
+ if (!agent.signature_algorithm) {
42
+ return { success: false, error: 'signature_algorithm required when public_key provided' };
43
+ }
44
+ // Validate public key format
45
+ if (!isValidPEMPublicKey(agent.public_key)) {
46
+ return { success: false, error: 'Invalid PEM public key format' };
47
+ }
48
+ }
49
+ // Store agent
50
+ await agents.put(`agent:${agentId}`, JSON.stringify(agent));
51
+ // Update app's agent index
52
+ await updateAppAgentIndex(agents, appId, agentId, 'add');
53
+ return { success: true, agent };
54
+ }
55
+ catch (error) {
56
+ console.error('Failed to register TAP agent:', error);
57
+ return { success: false, error: 'Internal server error' };
58
+ }
59
+ }
60
+ /**
61
+ * Get agent with TAP capabilities
62
+ */
63
+ export async function getTAPAgent(agents, agentId) {
64
+ try {
65
+ const agentData = await agents.get(`agent:${agentId}`, 'text');
66
+ if (!agentData) {
67
+ return { success: false, error: 'Agent not found' };
68
+ }
69
+ const agent = JSON.parse(agentData);
70
+ return { success: true, agent };
71
+ }
72
+ catch (error) {
73
+ console.error('Failed to get TAP agent:', error);
74
+ return { success: false, error: 'Internal server error' };
75
+ }
76
+ }
77
+ /**
78
+ * Update agent's last verification timestamp
79
+ */
80
+ export async function updateAgentVerification(agents, agentId, verificationSuccess) {
81
+ try {
82
+ const result = await getTAPAgent(agents, agentId);
83
+ if (result.success && result.agent) {
84
+ result.agent.last_verified_at = verificationSuccess ? Date.now() : result.agent.last_verified_at;
85
+ await agents.put(`agent:${agentId}`, JSON.stringify(result.agent));
86
+ }
87
+ }
88
+ catch (error) {
89
+ console.error('Failed to update agent verification:', error);
90
+ // Fail silently - verification updates are not critical
91
+ }
92
+ }
93
+ /**
94
+ * List TAP-enabled agents for an app
95
+ */
96
+ export async function listTAPAgents(agents, appId, tapOnly = false) {
97
+ try {
98
+ const indexData = await agents.get(`app_agents:${appId}`, 'text');
99
+ if (!indexData) {
100
+ return { success: true, agents: [] };
101
+ }
102
+ const agentIds = JSON.parse(indexData);
103
+ const agentPromises = agentIds.map(id => getTAPAgent(agents, id));
104
+ const results = await Promise.all(agentPromises);
105
+ const tapAgents = results
106
+ .filter(r => r.success && r.agent)
107
+ .map(r => r.agent)
108
+ .filter(agent => !tapOnly || agent.tap_enabled);
109
+ return { success: true, agents: tapAgents };
110
+ }
111
+ catch (error) {
112
+ console.error('Failed to list TAP agents:', error);
113
+ return { success: false, error: 'Internal server error' };
114
+ }
115
+ }
116
+ // ============ TAP SESSION MANAGEMENT ============
117
+ /**
118
+ * Create a TAP session after successful verification
119
+ */
120
+ export async function createTAPSession(sessions, agentId, appId, userContext, capabilities, intent) {
121
+ try {
122
+ const sessionId = generateSessionId();
123
+ const now = Date.now();
124
+ const MAX_SESSION_DURATION = 86400; // 24 hours max
125
+ const duration = Math.min(intent.duration || 3600, MAX_SESSION_DURATION);
126
+ const expiresAt = now + duration * 1000;
127
+ const session = {
128
+ session_id: sessionId,
129
+ agent_id: agentId,
130
+ app_id: appId,
131
+ user_context: userContext,
132
+ capabilities,
133
+ intent,
134
+ created_at: now,
135
+ expires_at: expiresAt
136
+ };
137
+ // Store session with TTL
138
+ const ttlSeconds = Math.floor((expiresAt - now) / 1000);
139
+ await sessions.put(`session:${sessionId}`, JSON.stringify(session), {
140
+ expirationTtl: ttlSeconds
141
+ });
142
+ return { success: true, session };
143
+ }
144
+ catch (error) {
145
+ console.error('Failed to create TAP session:', error);
146
+ return { success: false, error: 'Internal server error' };
147
+ }
148
+ }
149
+ /**
150
+ * Get and validate TAP session
151
+ */
152
+ export async function getTAPSession(sessions, sessionId) {
153
+ try {
154
+ const sessionData = await sessions.get(`session:${sessionId}`, 'text');
155
+ if (!sessionData) {
156
+ return { success: false, error: 'Session not found or expired' };
157
+ }
158
+ const session = JSON.parse(sessionData);
159
+ // Double-check expiration
160
+ if (Date.now() > session.expires_at) {
161
+ return { success: false, error: 'Session expired' };
162
+ }
163
+ return { success: true, session };
164
+ }
165
+ catch (error) {
166
+ console.error('Failed to get TAP session:', error);
167
+ return { success: false, error: 'Internal server error' };
168
+ }
169
+ }
170
+ // ============ UTILITY FUNCTIONS ============
171
+ function generateSessionId() {
172
+ const bytes = new Uint8Array(16);
173
+ crypto.getRandomValues(bytes);
174
+ return Array.from(bytes)
175
+ .map(b => b.toString(16).padStart(2, '0'))
176
+ .join('');
177
+ }
178
+ function isValidPEMPublicKey(pemKey) {
179
+ return pemKey.includes('BEGIN PUBLIC KEY') &&
180
+ pemKey.includes('END PUBLIC KEY') &&
181
+ pemKey.length > 100; // Basic sanity check
182
+ }
183
+ async function updateAppAgentIndex(agents, appId, agentId, operation) {
184
+ try {
185
+ const indexData = await agents.get(`app_agents:${appId}`, 'text');
186
+ let agentIds = indexData ? JSON.parse(indexData) : [];
187
+ if (operation === 'add' && !agentIds.includes(agentId)) {
188
+ agentIds.push(agentId);
189
+ }
190
+ else if (operation === 'remove') {
191
+ agentIds = agentIds.filter(id => id !== agentId);
192
+ }
193
+ await agents.put(`app_agents:${appId}`, JSON.stringify(agentIds));
194
+ }
195
+ catch (error) {
196
+ console.error('Failed to update agent index:', error);
197
+ // Fail silently - index updates are not critical
198
+ }
199
+ }
200
+ // ============ CAPABILITY VALIDATION ============
201
+ export function validateCapability(agentCapabilities, requiredAction, requiredScope) {
202
+ const matchingCaps = agentCapabilities.filter(cap => cap.action === requiredAction);
203
+ if (matchingCaps.length === 0) {
204
+ return { valid: false, error: `Agent lacks capability: ${requiredAction}` };
205
+ }
206
+ if (!requiredScope) {
207
+ return { valid: true };
208
+ }
209
+ const hasScope = matchingCaps.some(cap => !cap.scope ||
210
+ cap.scope.includes('*') ||
211
+ cap.scope.includes(requiredScope));
212
+ if (!hasScope) {
213
+ return { valid: false, error: `Agent lacks scope '${requiredScope}' for action '${requiredAction}'` };
214
+ }
215
+ return { valid: true };
216
+ }
217
+ export default {
218
+ registerTAPAgent,
219
+ getTAPAgent,
220
+ listTAPAgents,
221
+ updateAgentVerification,
222
+ createTAPSession,
223
+ getTAPSession,
224
+ validateCapability
225
+ };