@dupecom/botcha-cloudflare 0.20.2 → 0.23.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.
Files changed (88) hide show
  1. package/README.md +74 -9
  2. package/dist/agent-auth.d.ts +129 -0
  3. package/dist/agent-auth.d.ts.map +1 -0
  4. package/dist/agent-auth.js +210 -0
  5. package/dist/agents.d.ts +10 -0
  6. package/dist/agents.d.ts.map +1 -1
  7. package/dist/agents.js +51 -1
  8. package/dist/app-gate.d.ts +6 -0
  9. package/dist/app-gate.d.ts.map +1 -0
  10. package/dist/app-gate.js +69 -0
  11. package/dist/apps.d.ts +13 -4
  12. package/dist/apps.d.ts.map +1 -1
  13. package/dist/apps.js +30 -4
  14. package/dist/dashboard/account.d.ts +63 -0
  15. package/dist/dashboard/account.d.ts.map +1 -0
  16. package/dist/dashboard/account.js +488 -0
  17. package/dist/dashboard/api.js +15 -68
  18. package/dist/dashboard/auth.d.ts.map +1 -1
  19. package/dist/dashboard/auth.js +14 -14
  20. package/dist/dashboard/docs.d.ts.map +1 -1
  21. package/dist/dashboard/docs.js +146 -3
  22. package/dist/dashboard/layout.d.ts.map +1 -1
  23. package/dist/dashboard/layout.js +2 -2
  24. package/dist/dashboard/mcp-setup.d.ts +15 -0
  25. package/dist/dashboard/mcp-setup.d.ts.map +1 -0
  26. package/dist/dashboard/mcp-setup.js +391 -0
  27. package/dist/dashboard/showcase.d.ts +6 -10
  28. package/dist/dashboard/showcase.d.ts.map +1 -1
  29. package/dist/dashboard/showcase.js +67 -991
  30. package/dist/dashboard/whitepaper.d.ts.map +1 -1
  31. package/dist/dashboard/whitepaper.js +42 -4
  32. package/dist/index.d.ts +5 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +660 -83
  35. package/dist/mcp.d.ts +20 -0
  36. package/dist/mcp.d.ts.map +1 -0
  37. package/dist/mcp.js +1290 -0
  38. package/dist/oauth-agent.d.ts +130 -0
  39. package/dist/oauth-agent.d.ts.map +1 -0
  40. package/dist/oauth-agent.js +194 -0
  41. package/dist/static.d.ts +781 -5
  42. package/dist/static.d.ts.map +1 -1
  43. package/dist/static.js +790 -111
  44. package/dist/tap-a2a-routes.d.ts +355 -0
  45. package/dist/tap-a2a-routes.d.ts.map +1 -0
  46. package/dist/tap-a2a-routes.js +475 -0
  47. package/dist/tap-a2a.d.ts +199 -0
  48. package/dist/tap-a2a.d.ts.map +1 -0
  49. package/dist/tap-a2a.js +502 -0
  50. package/dist/tap-agents.d.ts +15 -0
  51. package/dist/tap-agents.d.ts.map +1 -1
  52. package/dist/tap-agents.js +31 -1
  53. package/dist/tap-ans-routes.d.ts +302 -0
  54. package/dist/tap-ans-routes.d.ts.map +1 -0
  55. package/dist/tap-ans-routes.js +535 -0
  56. package/dist/tap-ans.d.ts +241 -0
  57. package/dist/tap-ans.d.ts.map +1 -0
  58. package/dist/tap-ans.js +481 -0
  59. package/dist/tap-delegation-routes.d.ts.map +1 -1
  60. package/dist/tap-delegation-routes.js +11 -0
  61. package/dist/tap-did.d.ts +140 -0
  62. package/dist/tap-did.d.ts.map +1 -0
  63. package/dist/tap-did.js +262 -0
  64. package/dist/tap-oidca-routes.d.ts +383 -0
  65. package/dist/tap-oidca-routes.d.ts.map +1 -0
  66. package/dist/tap-oidca-routes.js +597 -0
  67. package/dist/tap-oidca.d.ts +288 -0
  68. package/dist/tap-oidca.d.ts.map +1 -0
  69. package/dist/tap-oidca.js +461 -0
  70. package/dist/tap-routes.d.ts +24 -8
  71. package/dist/tap-routes.d.ts.map +1 -1
  72. package/dist/tap-routes.js +169 -23
  73. package/dist/tap-vc-routes.d.ts +358 -0
  74. package/dist/tap-vc-routes.d.ts.map +1 -0
  75. package/dist/tap-vc-routes.js +367 -0
  76. package/dist/tap-vc.d.ts +125 -0
  77. package/dist/tap-vc.d.ts.map +1 -0
  78. package/dist/tap-vc.js +245 -0
  79. package/dist/tap-x402-routes.d.ts +89 -0
  80. package/dist/tap-x402-routes.d.ts.map +1 -0
  81. package/dist/tap-x402-routes.js +579 -0
  82. package/dist/tap-x402.d.ts +222 -0
  83. package/dist/tap-x402.d.ts.map +1 -0
  84. package/dist/tap-x402.js +546 -0
  85. package/dist/webhooks.d.ts +99 -0
  86. package/dist/webhooks.d.ts.map +1 -0
  87. package/dist/webhooks.js +642 -0
  88. package/package.json +3 -1
@@ -0,0 +1,461 @@
1
+ /**
2
+ * BOTCHA OIDC-A Attestation Module
3
+ *
4
+ * Implements OIDC-A (OpenID Connect for Agents) attestation:
5
+ * - EAT (Entity Attestation Token) issuance per draft-ietf-rats-eat-25
6
+ * - OIDC-A compatible claims per draft-aap-oauth-profile (Feb 2026)
7
+ * - OAuth 2.0 AS metadata discovery per RFC 8414
8
+ * - Agent Authorization Grant per draft-rosenberg-oauth-aauth
9
+ * - OIDC-A UserInfo endpoint
10
+ *
11
+ * EAT tokens make BOTCHA an `agent_attestation` endpoint that enterprise
12
+ * auth servers embed in OpenID Connect for Agents token chains.
13
+ */
14
+ import { SignJWT, jwtVerify, importJWK } from 'jose';
15
+ // ============ CONSTANTS ============
16
+ export const BOTCHA_EAT_PROFILE = 'https://botcha.ai/eat-profile/v1';
17
+ export const BOTCHA_ISSUER = 'botcha.ai';
18
+ export const EAT_TOKEN_TTL_SECONDS = 3600; // 1 hour
19
+ export const OIDC_CLAIMS_TTL_SECONDS = 3600; // 1 hour
20
+ export const AGENT_GRANT_TTL_SECONDS = 3600; // 1 hour
21
+ /**
22
+ * Well-known BOTCHA agent capabilities
23
+ * Enterprise auth servers can use these to filter agents by capability.
24
+ */
25
+ export const BOTCHA_AGENT_CAPABILITIES = [
26
+ 'botcha:verified', // Core — agent passed BOTCHA challenge
27
+ 'botcha:speed-challenge', // Can solve SHA256 speed challenges
28
+ 'botcha:hybrid-challenge', // Can solve hybrid (speed + reasoning) challenges
29
+ 'botcha:reasoning-challenge', // Can solve LLM-level reasoning challenges
30
+ 'agent:autonomous', // Can operate autonomously
31
+ 'agent:tool-use', // Can invoke external tools/APIs
32
+ 'agent:multi-step', // Can execute multi-step workflows
33
+ ];
34
+ // ============ CORE FUNCTIONS ============
35
+ /**
36
+ * Derive a Universal Entity ID (UEID) from an agent identifier.
37
+ *
38
+ * Per draft-ietf-rats-eat-25 §4.2.1: UEID is a binary identifier
39
+ * unique to the entity. For software agents, we use SHA-256(agent_id)
40
+ * truncated to 33 bytes, base64url-encoded.
41
+ */
42
+ async function deriveUEID(agentId) {
43
+ const encoder = new TextEncoder();
44
+ const data = encoder.encode(agentId);
45
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
46
+ const hashArray = new Uint8Array(hashBuffer).slice(0, 33); // 33 bytes per spec
47
+ return btoa(String.fromCharCode(...hashArray))
48
+ .replace(/\+/g, '-')
49
+ .replace(/\//g, '_')
50
+ .replace(/=/g, '');
51
+ }
52
+ /**
53
+ * Generate a cryptographically random nonce for eat_nonce.
54
+ * Returns base64url-encoded 32 bytes.
55
+ */
56
+ function generateEATNonce() {
57
+ const bytes = crypto.getRandomValues(new Uint8Array(32));
58
+ return btoa(String.fromCharCode(...bytes))
59
+ .replace(/\+/g, '-')
60
+ .replace(/\//g, '_')
61
+ .replace(/=/g, '');
62
+ }
63
+ /**
64
+ * Issue an EAT (Entity Attestation Token) from a valid BOTCHA access token.
65
+ *
66
+ * The EAT proves:
67
+ * 1. The agent solved a computational challenge (proving it is a bot)
68
+ * 2. The challenge was issued by botcha.ai
69
+ * 3. The solution time demonstrates AI-speed computation
70
+ * 4. The agent is registered with a specific app
71
+ *
72
+ * This token can be embedded as `agent_attestation` in OIDC-A tokens.
73
+ *
74
+ * @param botchaPayload - Verified BOTCHA access token payload
75
+ * @param signingKey - ES256 private key for signing (required for EAT)
76
+ * @param options - Optional parameters
77
+ * @returns Signed EAT JWT
78
+ */
79
+ export async function issueEAT(botchaPayload, signingKey, options) {
80
+ const now = Math.floor(Date.now() / 1000);
81
+ const ttl = options?.ttlSeconds ?? EAT_TOKEN_TTL_SECONDS;
82
+ const agentId = botchaPayload.app_id
83
+ ? `${botchaPayload.app_id}:${botchaPayload.sub}`
84
+ : botchaPayload.sub;
85
+ const ueid = await deriveUEID(agentId);
86
+ const eatNonce = options?.nonce ?? generateEATNonce();
87
+ const eatPayload = {
88
+ iss: BOTCHA_ISSUER,
89
+ sub: agentId,
90
+ iat: now,
91
+ exp: now + ttl,
92
+ // EAT standard claims
93
+ eat_profile: BOTCHA_EAT_PROFILE,
94
+ eat_nonce: eatNonce,
95
+ ueid,
96
+ oemid: BOTCHA_ISSUER,
97
+ swname: 'BOTCHA',
98
+ swversion: '0.21.0',
99
+ dbgstat: 'Disabled',
100
+ intuse: 'generic',
101
+ // BOTCHA private claims
102
+ botcha_verified: true,
103
+ botcha_challenge_id: botchaPayload.sub,
104
+ botcha_solve_time_ms: botchaPayload.solveTime,
105
+ botcha_app_id: botchaPayload.app_id,
106
+ botcha_verification_method: options?.verificationMethod ?? 'speed-challenge',
107
+ };
108
+ const cryptoKey = (await importJWK(signingKey, 'ES256'));
109
+ const kid = signingKey.kid || 'botcha-signing-1';
110
+ const token = await new SignJWT(eatPayload)
111
+ .setProtectedHeader({
112
+ alg: 'ES256',
113
+ kid,
114
+ typ: 'JWT+EAT', // RFC 9334 recommends typ claim for EAT
115
+ })
116
+ .sign(cryptoKey);
117
+ return token;
118
+ }
119
+ /**
120
+ * Build OIDC-A compatible agent claims block.
121
+ *
122
+ * This is the full claims object that enterprise auth servers embed in their
123
+ * ID tokens for agent grants. It includes the EAT token as `agent_attestation`.
124
+ *
125
+ * @param botchaPayload - Verified BOTCHA access token payload
126
+ * @param eatToken - Signed EAT JWT (from issueEAT)
127
+ * @param signingKey - ES256 signing key
128
+ * @param options - Agent metadata and OIDC-A options
129
+ * @returns Signed OIDC-A claims JWT + plain claims object
130
+ */
131
+ export async function buildOIDCAgentClaims(botchaPayload, eatToken, signingKey, options) {
132
+ const now = Math.floor(Date.now() / 1000);
133
+ const ttl = options?.ttlSeconds ?? OIDC_CLAIMS_TTL_SECONDS;
134
+ const agentId = botchaPayload.app_id
135
+ ? `${botchaPayload.app_id}:${botchaPayload.sub}`
136
+ : botchaPayload.sub;
137
+ // Derive the BOTCHA verification method capability from the actual method used
138
+ const verificationMethod = options?.verificationMethod ?? 'speed-challenge';
139
+ const methodCapability = `botcha:${verificationMethod}`;
140
+ // Build the capability set: always include BOTCHA core + the actual method used
141
+ const capabilities = [
142
+ 'botcha:verified',
143
+ methodCapability,
144
+ ...(options?.agentCapabilities ?? []).filter(c => c !== methodCapability),
145
+ ];
146
+ const claims = {
147
+ // OIDC-A core
148
+ agent_model: options?.agentModel ?? 'botcha-verified-agent',
149
+ agent_version: options?.agentVersion,
150
+ agent_capabilities: capabilities,
151
+ agent_attestation: eatToken,
152
+ delegation_chain: options?.delegationChain ?? [],
153
+ // Identity
154
+ agent_id: agentId,
155
+ agent_operator: options?.agentOperator,
156
+ // Verification metadata — reflect the actual challenge type used
157
+ agent_verification: {
158
+ method: `botcha-${verificationMethod}`,
159
+ solve_time_ms: botchaPayload.solveTime,
160
+ verified_at: new Date(botchaPayload.iat * 1000).toISOString(),
161
+ issuer: BOTCHA_ISSUER,
162
+ challenge_id: botchaPayload.sub,
163
+ },
164
+ // Oversight
165
+ human_oversight_required: options?.humanOversightRequired ?? false,
166
+ oversight_contact: options?.oversightContact,
167
+ // Task binding
168
+ task_id: options?.taskId,
169
+ task_purpose: options?.taskPurpose,
170
+ // Token metadata
171
+ iat: now,
172
+ exp: now + ttl,
173
+ iss: BOTCHA_ISSUER,
174
+ };
175
+ // Remove undefined fields for a clean JWT
176
+ const cleanClaims = JSON.parse(JSON.stringify(claims));
177
+ const cryptoKey = (await importJWK(signingKey, 'ES256'));
178
+ const kid = signingKey.kid || 'botcha-signing-1';
179
+ const claimsJwt = await new SignJWT(cleanClaims)
180
+ .setProtectedHeader({
181
+ alg: 'ES256',
182
+ kid,
183
+ typ: 'JWT+OIDCA', // OIDC-A claims token type
184
+ })
185
+ .sign(cryptoKey);
186
+ return { claims: cleanClaims, claimsJwt };
187
+ }
188
+ /**
189
+ * Issue an Agent Authorization Grant.
190
+ *
191
+ * Implements draft-rosenberg-oauth-aauth "Agent Authorization Grant":
192
+ * - Agent presents BOTCHA access token as credential
193
+ * - Server issues a scoped grant JWT bound to the agent's identity
194
+ * - Optionally queued for human-in-the-loop approval
195
+ *
196
+ * Grant token is a signed JWT with AAP claims (draft-aap-oauth-profile §5).
197
+ *
198
+ * @param botchaPayload - Verified BOTCHA access token payload
199
+ * @param eatToken - EAT JWT from issueEAT
200
+ * @param oidcClaims - OIDC-A claims object from buildOIDCAgentClaims
201
+ * @param signingKey - ES256 signing key
202
+ * @param kv - KV namespace for storing pending grants (for HITL polling)
203
+ * @param options - Grant options
204
+ * @returns AgentGrantResult
205
+ */
206
+ export async function issueAgentGrant(botchaPayload, eatToken, oidcClaims, signingKey, kv, baseUrl, options) {
207
+ const now = Math.floor(Date.now() / 1000);
208
+ const ttl = options?.ttlSeconds ?? AGENT_GRANT_TTL_SECONDS;
209
+ const scope = options?.scope ?? 'agent:read agent:attest openid';
210
+ const humanOversight = options?.humanOversightRequired ?? false;
211
+ const agentId = botchaPayload.app_id
212
+ ? `${botchaPayload.app_id}:${botchaPayload.sub}`
213
+ : botchaPayload.sub;
214
+ // Generate grant ID for tracking
215
+ const grantId = crypto.randomUUID();
216
+ // AAP JWT payload (draft-aap-oauth-profile §5)
217
+ const grantPayload = {
218
+ // Standard JWT
219
+ iss: BOTCHA_ISSUER,
220
+ sub: agentId,
221
+ iat: now,
222
+ exp: now + ttl,
223
+ jti: grantId,
224
+ // OAuth grant type indicator
225
+ grant_type: 'urn:ietf:params:oauth:grant-type:agent_authorization',
226
+ // AAP §5.2 — Agent Identity Section
227
+ agent: {
228
+ id: agentId,
229
+ model: oidcClaims.agent_model,
230
+ version: oidcClaims.agent_version,
231
+ operator: oidcClaims.agent_operator,
232
+ },
233
+ // AAP §5.2 — Capabilities Section
234
+ capabilities: oidcClaims.agent_capabilities,
235
+ scope,
236
+ // AAP §5.2 — Attestation
237
+ attestation: {
238
+ eat_token: eatToken,
239
+ issuer: BOTCHA_ISSUER,
240
+ verified_at: oidcClaims.agent_verification.verified_at,
241
+ method: oidcClaims.agent_verification.method,
242
+ },
243
+ // AAP §5.2 — Oversight
244
+ oversight: {
245
+ human_in_the_loop: humanOversight,
246
+ status: humanOversight ? 'pending' : 'none',
247
+ grant_id: grantId,
248
+ },
249
+ // AAP §5.2 — Task binding (if provided)
250
+ ...(options?.taskId && {
251
+ task: {
252
+ id: options.taskId,
253
+ purpose: options.taskPurpose,
254
+ },
255
+ }),
256
+ // AAP §5.2 — Delegation chain
257
+ delegation_chain: oidcClaims.delegation_chain,
258
+ // AAP §5.2 — Contextual constraints
259
+ ...(options?.constraints && { constraints: options.constraints }),
260
+ // BOTCHA-specific: embed the full OIDC-A claims
261
+ agent_claims_ref: agentId,
262
+ };
263
+ const cryptoKey = (await importJWK(signingKey, 'ES256'));
264
+ const kid = signingKey.kid || 'botcha-signing-1';
265
+ const grantToken = await new SignJWT(grantPayload)
266
+ .setProtectedHeader({ alg: 'ES256', kid, typ: 'JWT+AGENT-GRANT' })
267
+ .sign(cryptoKey);
268
+ // If HITL required, store the pending grant in KV for polling
269
+ let oversightPollingUrl;
270
+ if (humanOversight) {
271
+ const pendingGrant = {
272
+ grant_id: grantId,
273
+ agent_id: agentId,
274
+ app_id: botchaPayload.app_id,
275
+ scope,
276
+ requested_at: Date.now(),
277
+ status: 'pending',
278
+ };
279
+ await kv.put(`agent_grant:${grantId}`, JSON.stringify(pendingGrant), { expirationTtl: ttl });
280
+ oversightPollingUrl = `${baseUrl}/v1/auth/agent-grant/${grantId}/status`;
281
+ }
282
+ return {
283
+ grant_type: 'urn:ietf:params:oauth:grant-type:agent_authorization',
284
+ access_token: grantToken,
285
+ token_type: 'Bearer',
286
+ expires_in: ttl,
287
+ scope,
288
+ agent_id: agentId,
289
+ app_id: botchaPayload.app_id,
290
+ human_oversight_required: humanOversight,
291
+ oversight_status: humanOversight ? 'pending' : 'none',
292
+ oversight_polling_url: oversightPollingUrl,
293
+ agent_claims: oidcClaims,
294
+ eat_token: eatToken,
295
+ };
296
+ }
297
+ /**
298
+ * Build OAuth 2.0 Authorization Server metadata (RFC 8414).
299
+ *
300
+ * This makes BOTCHA discoverable as an OAuth AS by enterprise auth servers
301
+ * that implement RFC 8414 auto-configuration.
302
+ *
303
+ * Extended with OIDC-A specific metadata for agent auth servers.
304
+ */
305
+ export function buildOAuthASMetadata(baseUrl) {
306
+ return {
307
+ // RFC 8414 §2 — Required
308
+ issuer: baseUrl,
309
+ // Token endpoint (agent grant flow)
310
+ token_endpoint: `${baseUrl}/v1/auth/agent-grant`,
311
+ // JWKS for signature verification
312
+ jwks_uri: `${baseUrl}/.well-known/jwks`,
313
+ // RFC 8414 §2 — Optional but widely expected
314
+ scopes_supported: [
315
+ 'openid',
316
+ 'profile',
317
+ 'agent:read',
318
+ 'agent:write',
319
+ 'agent:attest',
320
+ 'agent:delegate',
321
+ 'agent:oversight',
322
+ ],
323
+ // Grant types — includes the AAP agent authorization grant
324
+ grant_types_supported: [
325
+ 'urn:ietf:params:oauth:grant-type:agent_authorization',
326
+ 'urn:ietf:params:oauth:grant-type:token-exchange',
327
+ 'client_credentials',
328
+ ],
329
+ // Token endpoint auth methods
330
+ token_endpoint_auth_methods_supported: [
331
+ 'botcha_token', // BOTCHA-specific: Bearer token from challenge
332
+ 'private_key_jwt', // RFC 7523 — for clients with registered keys
333
+ ],
334
+ // Response types (if acting as OIDC provider)
335
+ response_types_supported: ['token', 'id_token', 'token id_token'],
336
+ // Subject types
337
+ subject_types_supported: ['public'],
338
+ // ID token signing algorithms
339
+ id_token_signing_alg_values_supported: ['ES256'],
340
+ // Token lifetime
341
+ access_token_lifetime: AGENT_GRANT_TTL_SECONDS,
342
+ // ====== OIDC-A / BOTCHA Extensions ======
343
+ // BOTCHA-specific agent attestation endpoint
344
+ agent_attestation_endpoint: `${baseUrl}/v1/attestation/eat`,
345
+ // OIDC-A enrichment endpoint for auth servers
346
+ oidc_agent_claims_endpoint: `${baseUrl}/v1/attestation/oidc-agent-claims`,
347
+ // UserInfo endpoint (OIDC-A compliant)
348
+ userinfo_endpoint: `${baseUrl}/v1/oidc/userinfo`,
349
+ // EAT profile URI
350
+ eat_profile: BOTCHA_EAT_PROFILE,
351
+ // Well-known agent capabilities this AS can attest
352
+ agent_capabilities_supported: BOTCHA_AGENT_CAPABILITIES,
353
+ // Verification methods BOTCHA uses
354
+ agent_verification_methods_supported: [
355
+ 'botcha:speed-challenge',
356
+ 'botcha:hybrid-challenge',
357
+ 'botcha:reasoning-challenge',
358
+ ],
359
+ // Human oversight support
360
+ human_oversight_supported: true,
361
+ oversight_polling_endpoint: `${baseUrl}/v1/auth/agent-grant/{id}/status`,
362
+ // draft-aap-oauth-profile compliance
363
+ aap_version: 'draft-aap-oauth-profile-00',
364
+ // OIDC-A compliance indicator
365
+ oidca_supported: true,
366
+ // Delegation chain support
367
+ delegation_supported: true,
368
+ max_delegation_depth: 5,
369
+ // Integration metadata
370
+ integration: {
371
+ documentation: `${baseUrl}/docs`,
372
+ openapi: `${baseUrl}/openapi.json`,
373
+ ai_txt: `${baseUrl}/ai.txt`,
374
+ whitepaper: `${baseUrl}/whitepaper`,
375
+ },
376
+ };
377
+ }
378
+ /**
379
+ * Verify and decode a BOTCHA EAT token.
380
+ * Used by the UserInfo endpoint to extract agent identity.
381
+ *
382
+ * @param eatJwt - The EAT JWT to verify
383
+ * @param publicKey - ES256 public key JWK
384
+ * @returns Verified EAT payload or null
385
+ */
386
+ export async function verifyEAT(eatJwt, publicKey) {
387
+ try {
388
+ const cryptoKey = (await importJWK(publicKey, 'ES256'));
389
+ const { payload } = await jwtVerify(eatJwt, cryptoKey, {
390
+ algorithms: ['ES256'],
391
+ issuer: BOTCHA_ISSUER,
392
+ });
393
+ // Validate required EAT claims
394
+ if (!payload.eat_profile || !payload.eat_nonce || !payload.ueid) {
395
+ return null;
396
+ }
397
+ return payload;
398
+ }
399
+ catch {
400
+ return null;
401
+ }
402
+ }
403
+ /**
404
+ * Poll the status of a pending human-in-the-loop grant.
405
+ *
406
+ * @param grantId - The grant ID to poll
407
+ * @param kv - KV namespace
408
+ * @returns Current grant status or null if not found
409
+ */
410
+ export async function getGrantStatus(grantId, kv) {
411
+ try {
412
+ const data = await kv.get(`agent_grant:${grantId}`);
413
+ if (!data)
414
+ return null;
415
+ return JSON.parse(data);
416
+ }
417
+ catch {
418
+ return null;
419
+ }
420
+ }
421
+ /**
422
+ * Approve or deny a pending agent grant (admin action).
423
+ *
424
+ * @param grantId - The grant ID
425
+ * @param decision - 'approved' or 'denied'
426
+ * @param reason - Optional denial reason
427
+ * @param kv - KV namespace
428
+ */
429
+ export async function resolveGrant(grantId, decision, reason, kv) {
430
+ const grant = await getGrantStatus(grantId, kv);
431
+ if (!grant) {
432
+ return { success: false, error: 'Grant not found or expired' };
433
+ }
434
+ if (grant.status !== 'pending') {
435
+ return { success: false, error: `Grant is already ${grant.status}` };
436
+ }
437
+ const updated = {
438
+ ...grant,
439
+ status: decision,
440
+ approved_at: decision === 'approved' ? Date.now() : undefined,
441
+ denied_at: decision === 'denied' ? Date.now() : undefined,
442
+ denial_reason: decision === 'denied' ? reason : undefined,
443
+ };
444
+ // Preserve the original grant expiry rather than resetting to the full TTL.
445
+ // requested_at is stored in ms; KV expirationTtl is in seconds.
446
+ const elapsedSeconds = Math.floor((Date.now() - grant.requested_at) / 1000);
447
+ const remainingTtl = Math.max(1, AGENT_GRANT_TTL_SECONDS - elapsedSeconds);
448
+ await kv.put(`agent_grant:${grantId}`, JSON.stringify(updated), {
449
+ expirationTtl: remainingTtl,
450
+ });
451
+ return { success: true, grant: updated };
452
+ }
453
+ export default {
454
+ issueEAT,
455
+ buildOIDCAgentClaims,
456
+ issueAgentGrant,
457
+ buildOAuthASMetadata,
458
+ verifyEAT,
459
+ getGrantStatus,
460
+ resolveGrant,
461
+ };
@@ -21,6 +21,14 @@ export declare function registerTAPAgentRoute(c: Context): Promise<(Response & i
21
21
  success: false;
22
22
  error: string;
23
23
  message: string;
24
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
25
+ success: false;
26
+ error: string;
27
+ message: string;
28
+ }, 403, "json">) | (Response & import("hono").TypedResponse<{
29
+ success: false;
30
+ error: string;
31
+ message: string;
24
32
  }, 500, "json">) | (Response & import("hono").TypedResponse<{
25
33
  success: true;
26
34
  agent_id: string;
@@ -30,7 +38,7 @@ export declare function registerTAPAgentRoute(c: Context): Promise<(Response & i
30
38
  version: string | undefined;
31
39
  created_at: string;
32
40
  tap_enabled: boolean | undefined;
33
- trust_level: "verified" | "basic" | "enterprise" | undefined;
41
+ trust_level: "basic" | "verified" | "enterprise" | undefined;
34
42
  capabilities: {
35
43
  action: import("./tap-agents.js").TAPAction;
36
44
  scope?: string[] | undefined;
@@ -40,8 +48,12 @@ export declare function registerTAPAgentRoute(c: Context): Promise<(Response & i
40
48
  rate_limit?: number | undefined;
41
49
  } | undefined;
42
50
  }[] | undefined;
43
- signature_algorithm: "ed25519" | "ecdsa-p256-sha256" | "rsa-pss-sha256" | undefined;
51
+ signature_algorithm: "ecdsa-p256-sha256" | "rsa-pss-sha256" | "ed25519" | undefined;
44
52
  issuer: string | undefined;
53
+ did: string | null;
54
+ ans_name: string | null;
55
+ ans_badge_id: string | null;
56
+ ans_trust_level: "domain-validated" | "key-validated" | "behavior-validated" | null;
45
57
  has_public_key: boolean;
46
58
  key_fingerprint: string | undefined;
47
59
  }, 201, "json">)>;
@@ -66,7 +78,7 @@ export declare function getTAPAgentRoute(c: Context): Promise<(Response & import
66
78
  version: string | undefined;
67
79
  created_at: string;
68
80
  tap_enabled: boolean | undefined;
69
- trust_level: "verified" | "basic" | "enterprise" | undefined;
81
+ trust_level: "basic" | "verified" | "enterprise" | undefined;
70
82
  capabilities: {
71
83
  action: import("./tap-agents.js").TAPAction;
72
84
  scope?: string[] | undefined;
@@ -76,9 +88,13 @@ export declare function getTAPAgentRoute(c: Context): Promise<(Response & import
76
88
  rate_limit?: number | undefined;
77
89
  } | undefined;
78
90
  }[] | undefined;
79
- signature_algorithm: "ed25519" | "ecdsa-p256-sha256" | "rsa-pss-sha256" | undefined;
91
+ signature_algorithm: "ecdsa-p256-sha256" | "rsa-pss-sha256" | "ed25519" | undefined;
80
92
  issuer: string | undefined;
81
93
  last_verified_at: string | null;
94
+ ans_name: string | null;
95
+ ans_badge_id: string | null;
96
+ ans_trust_level: "domain-validated" | "key-validated" | "behavior-validated" | null;
97
+ ans_verified_at: string | null;
82
98
  has_public_key: boolean;
83
99
  key_fingerprint: string | undefined;
84
100
  public_key: string | undefined;
@@ -108,7 +124,7 @@ export declare function listTAPAgentsRoute(c: Context): Promise<(Response & impo
108
124
  version: string | undefined;
109
125
  created_at: string;
110
126
  tap_enabled: boolean | undefined;
111
- trust_level: "verified" | "basic" | "enterprise" | undefined;
127
+ trust_level: "basic" | "verified" | "enterprise" | undefined;
112
128
  capabilities: {
113
129
  action: import("./tap-agents.js").TAPAction;
114
130
  scope?: string[] | undefined;
@@ -229,7 +245,7 @@ export declare function rotateKeyRoute(c: Context): Promise<(Response & import("
229
245
  agent_id: string;
230
246
  message: string;
231
247
  has_public_key: true;
232
- signature_algorithm: "ed25519" | "ecdsa-p256-sha256" | "rsa-pss-sha256" | undefined;
248
+ signature_algorithm: "ecdsa-p256-sha256" | "rsa-pss-sha256" | "ed25519" | undefined;
233
249
  key_created_at: string;
234
250
  key_expires_at: string | null;
235
251
  key_fingerprint: string | undefined;
@@ -264,7 +280,7 @@ export declare function createInvoiceRoute(c: Context): Promise<(Response & impo
264
280
  currency?: string | undefined;
265
281
  card_acceptor_id?: string | undefined;
266
282
  description?: string | undefined;
267
- status?: "pending" | "fulfilled" | "expired" | undefined;
283
+ status?: "fulfilled" | "pending" | "expired" | undefined;
268
284
  success: true;
269
285
  }, 201, "json">)>;
270
286
  /**
@@ -289,7 +305,7 @@ export declare function getInvoiceRoute(c: Context): Promise<(Response & import(
289
305
  currency?: string | undefined;
290
306
  card_acceptor_id?: string | undefined;
291
307
  description?: string | undefined;
292
- status?: "pending" | "fulfilled" | "expired" | undefined;
308
+ status?: "fulfilled" | "pending" | "expired" | undefined;
293
309
  success: true;
294
310
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
295
311
  success: false;
@@ -1 +1 @@
1
- {"version":3,"file":"tap-routes.d.ts","sourceRoot":"","sources":["../src/tap-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAmKpC;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwErD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwDhD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAmDlD;AAID;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsFrD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2ClD;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4D9C;AAID;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kBAwClD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kBAuB/C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6E9C;AAID;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqCnD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsClD;;;;;;;;;;;;;;AAaD,wBAYE"}
1
+ {"version":3,"file":"tap-routes.d.ts","sourceRoot":"","sources":["../src/tap-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAoNpC;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkIrD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA+DhD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAmDlD;AAID;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoHrD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2ClD;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAuF9C;AAID;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kBAwClD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kBAuB/C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6E9C;AAID;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqCnD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsClD;;;;;;;;;;;;;;AAaD,wBAYE"}