@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.
- package/README.md +74 -9
- package/dist/agent-auth.d.ts +129 -0
- package/dist/agent-auth.d.ts.map +1 -0
- package/dist/agent-auth.js +210 -0
- package/dist/agents.d.ts +10 -0
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +51 -1
- package/dist/app-gate.d.ts +6 -0
- package/dist/app-gate.d.ts.map +1 -0
- package/dist/app-gate.js +69 -0
- package/dist/apps.d.ts +13 -4
- package/dist/apps.d.ts.map +1 -1
- package/dist/apps.js +30 -4
- package/dist/dashboard/account.d.ts +63 -0
- package/dist/dashboard/account.d.ts.map +1 -0
- package/dist/dashboard/account.js +488 -0
- package/dist/dashboard/api.js +15 -68
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +14 -14
- package/dist/dashboard/docs.d.ts.map +1 -1
- package/dist/dashboard/docs.js +146 -3
- package/dist/dashboard/layout.d.ts.map +1 -1
- package/dist/dashboard/layout.js +2 -2
- package/dist/dashboard/mcp-setup.d.ts +15 -0
- package/dist/dashboard/mcp-setup.d.ts.map +1 -0
- package/dist/dashboard/mcp-setup.js +391 -0
- package/dist/dashboard/showcase.d.ts +6 -10
- package/dist/dashboard/showcase.d.ts.map +1 -1
- package/dist/dashboard/showcase.js +67 -991
- package/dist/dashboard/whitepaper.d.ts.map +1 -1
- package/dist/dashboard/whitepaper.js +42 -4
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +660 -83
- package/dist/mcp.d.ts +20 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +1290 -0
- package/dist/oauth-agent.d.ts +130 -0
- package/dist/oauth-agent.d.ts.map +1 -0
- package/dist/oauth-agent.js +194 -0
- package/dist/static.d.ts +781 -5
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +790 -111
- package/dist/tap-a2a-routes.d.ts +355 -0
- package/dist/tap-a2a-routes.d.ts.map +1 -0
- package/dist/tap-a2a-routes.js +475 -0
- package/dist/tap-a2a.d.ts +199 -0
- package/dist/tap-a2a.d.ts.map +1 -0
- package/dist/tap-a2a.js +502 -0
- package/dist/tap-agents.d.ts +15 -0
- package/dist/tap-agents.d.ts.map +1 -1
- package/dist/tap-agents.js +31 -1
- package/dist/tap-ans-routes.d.ts +302 -0
- package/dist/tap-ans-routes.d.ts.map +1 -0
- package/dist/tap-ans-routes.js +535 -0
- package/dist/tap-ans.d.ts +241 -0
- package/dist/tap-ans.d.ts.map +1 -0
- package/dist/tap-ans.js +481 -0
- package/dist/tap-delegation-routes.d.ts.map +1 -1
- package/dist/tap-delegation-routes.js +11 -0
- package/dist/tap-did.d.ts +140 -0
- package/dist/tap-did.d.ts.map +1 -0
- package/dist/tap-did.js +262 -0
- package/dist/tap-oidca-routes.d.ts +383 -0
- package/dist/tap-oidca-routes.d.ts.map +1 -0
- package/dist/tap-oidca-routes.js +597 -0
- package/dist/tap-oidca.d.ts +288 -0
- package/dist/tap-oidca.d.ts.map +1 -0
- package/dist/tap-oidca.js +461 -0
- package/dist/tap-routes.d.ts +24 -8
- package/dist/tap-routes.d.ts.map +1 -1
- package/dist/tap-routes.js +169 -23
- package/dist/tap-vc-routes.d.ts +358 -0
- package/dist/tap-vc-routes.d.ts.map +1 -0
- package/dist/tap-vc-routes.js +367 -0
- package/dist/tap-vc.d.ts +125 -0
- package/dist/tap-vc.d.ts.map +1 -0
- package/dist/tap-vc.js +245 -0
- package/dist/tap-x402-routes.d.ts +89 -0
- package/dist/tap-x402-routes.d.ts.map +1 -0
- package/dist/tap-x402-routes.js +579 -0
- package/dist/tap-x402.d.ts +222 -0
- package/dist/tap-x402.d.ts.map +1 -0
- package/dist/tap-x402.js +546 -0
- package/dist/webhooks.d.ts +99 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +642 -0
- package/package.json +3 -1
package/dist/tap-routes.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* Provides backward-compatible endpoints with optional TAP functionality
|
|
6
6
|
*/
|
|
7
7
|
import { extractBearerToken, verifyToken, getSigningPublicKeyJWK } from './auth.js';
|
|
8
|
-
import {
|
|
8
|
+
import { validateAppSecret } from './apps.js';
|
|
9
|
+
import { triggerWebhook } from './webhooks.js';
|
|
10
|
+
import { registerTAPAgent, getTAPAgent, listTAPAgents, createTAPSession, getTAPSession, updateAgentVerification, validateCapability, isValidJWK, TAP_VALID_ACTIONS } from './tap-agents.js';
|
|
9
11
|
import { parseTAPIntent } from './tap-verify.js';
|
|
10
12
|
import { createInvoice, getInvoice, verifyPaymentContainer, verifyBrowsingIOU, fulfillInvoice, parsePaymentContainer } from './tap-payment.js';
|
|
11
13
|
import { parseAgenticConsumer, verifyAgenticConsumer } from './tap-consumer.js';
|
|
@@ -67,8 +69,13 @@ function validateTAPRegistration(body) {
|
|
|
67
69
|
if (!body.name || typeof body.name !== 'string') {
|
|
68
70
|
return { valid: false, error: 'Agent name is required' };
|
|
69
71
|
}
|
|
72
|
+
// Normalize public_key: accept JWK objects by serializing them to JSON strings
|
|
73
|
+
let publicKey = body.public_key;
|
|
74
|
+
if (publicKey && typeof publicKey === 'object') {
|
|
75
|
+
publicKey = JSON.stringify(publicKey);
|
|
76
|
+
}
|
|
70
77
|
// Validate public key if provided
|
|
71
|
-
if (
|
|
78
|
+
if (publicKey) {
|
|
72
79
|
if (!body.signature_algorithm) {
|
|
73
80
|
return { valid: false, error: 'signature_algorithm required when public_key provided' };
|
|
74
81
|
}
|
|
@@ -76,11 +83,12 @@ function validateTAPRegistration(body) {
|
|
|
76
83
|
if (!validAlgorithms.includes(body.signature_algorithm)) {
|
|
77
84
|
return { valid: false, error: `Unsupported algorithm. Supported: ${validAlgorithms.join(', ')}` };
|
|
78
85
|
}
|
|
79
|
-
// PEM
|
|
80
|
-
const isPEM =
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
// Accept: PEM, JWK JSON string, or raw Ed25519 base64 key
|
|
87
|
+
const isPEM = typeof publicKey === 'string' && publicKey.includes('BEGIN PUBLIC KEY');
|
|
88
|
+
const isJWK = isValidJWK(publicKey);
|
|
89
|
+
const isRawEd25519 = body.signature_algorithm === 'ed25519' && !isPEM && !isJWK;
|
|
90
|
+
if (!isPEM && !isJWK && !isRawEd25519) {
|
|
91
|
+
return { valid: false, error: 'Invalid public key format. Provide a PEM key, JWK object/JSON, or raw Ed25519 base64 key.' };
|
|
84
92
|
}
|
|
85
93
|
}
|
|
86
94
|
// Validate capabilities if provided
|
|
@@ -94,17 +102,48 @@ function validateTAPRegistration(body) {
|
|
|
94
102
|
}
|
|
95
103
|
}
|
|
96
104
|
}
|
|
105
|
+
// Validate ANS name format if provided
|
|
106
|
+
if (body.ans_name !== undefined && body.ans_name !== null) {
|
|
107
|
+
if (typeof body.ans_name !== 'string') {
|
|
108
|
+
return { valid: false, error: 'ans_name must be a string (e.g. "ans://v1.0.myagent.example.com")' };
|
|
109
|
+
}
|
|
110
|
+
// Basic format check — full validation happens in tap-ans module
|
|
111
|
+
const clean = body.ans_name.trim().replace(/^ans:\/\//, '');
|
|
112
|
+
if (clean.split('.').length < 2) {
|
|
113
|
+
return { valid: false, error: 'ans_name must include at least a label and domain (e.g. "myagent.example.com")' };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Validate optional DID field
|
|
117
|
+
if (body.did !== undefined) {
|
|
118
|
+
if (typeof body.did !== 'string' || !body.did.startsWith('did:')) {
|
|
119
|
+
return { valid: false, error: 'Invalid did field: must be a valid DID string (e.g. did:web:example.com)' };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Validate provider if provided
|
|
123
|
+
const SUPPORTED_PROVIDERS = ['anthropic', 'openai', 'google', 'mistral', 'cohere', 'other'];
|
|
124
|
+
if (body.provider !== undefined) {
|
|
125
|
+
if (!SUPPORTED_PROVIDERS.includes(body.provider)) {
|
|
126
|
+
return { valid: false, error: `Unsupported provider. Use one of: ${SUPPORTED_PROVIDERS.join(', ')}` };
|
|
127
|
+
}
|
|
128
|
+
if (!body.api_key || typeof body.api_key !== 'string') {
|
|
129
|
+
return { valid: false, error: 'api_key is required when provider is specified' };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
97
132
|
return {
|
|
98
133
|
valid: true,
|
|
99
134
|
data: {
|
|
100
135
|
name: body.name,
|
|
101
136
|
operator: body.operator,
|
|
102
137
|
version: body.version,
|
|
103
|
-
public_key:
|
|
138
|
+
public_key: publicKey,
|
|
104
139
|
signature_algorithm: body.signature_algorithm,
|
|
105
140
|
capabilities: body.capabilities,
|
|
106
141
|
trust_level: body.trust_level || 'basic',
|
|
107
|
-
issuer: body.issuer
|
|
142
|
+
issuer: body.issuer,
|
|
143
|
+
ans_name: body.ans_name,
|
|
144
|
+
did: body.did,
|
|
145
|
+
provider: body.provider,
|
|
146
|
+
api_key: body.api_key, // plaintext — hashed in route handler, never persisted
|
|
108
147
|
}
|
|
109
148
|
};
|
|
110
149
|
}
|
|
@@ -134,16 +173,64 @@ export async function registerTAPAgentRoute(c) {
|
|
|
134
173
|
message: validation.error
|
|
135
174
|
}, 400);
|
|
136
175
|
}
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
176
|
+
// If agent_id provided, update existing agent with TAP fields instead of creating a new one
|
|
177
|
+
let agent;
|
|
178
|
+
if (body.agent_id) {
|
|
179
|
+
const existing = await getTAPAgent(c.env.AGENTS, body.agent_id);
|
|
180
|
+
if (!existing.success || !existing.agent) {
|
|
181
|
+
return c.json({
|
|
182
|
+
success: false,
|
|
183
|
+
error: 'AGENT_NOT_FOUND',
|
|
184
|
+
message: `Agent '${body.agent_id}' not found`
|
|
185
|
+
}, 404);
|
|
186
|
+
}
|
|
187
|
+
if (existing.agent.app_id !== appAccess.appId) {
|
|
188
|
+
return c.json({
|
|
189
|
+
success: false,
|
|
190
|
+
error: 'UNAUTHORIZED',
|
|
191
|
+
message: 'Agent does not belong to this app'
|
|
192
|
+
}, 403);
|
|
193
|
+
}
|
|
194
|
+
const now = Date.now();
|
|
195
|
+
// Hash provider API key if provided — never store plaintext
|
|
196
|
+
let providerKeyHash = existing.agent.provider_key_hash;
|
|
197
|
+
if (validation.data.api_key) {
|
|
198
|
+
const hashBuf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(validation.data.api_key.trim()));
|
|
199
|
+
providerKeyHash = Array.from(new Uint8Array(hashBuf)).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
200
|
+
}
|
|
201
|
+
agent = {
|
|
202
|
+
...existing.agent,
|
|
203
|
+
public_key: validation.data.public_key ?? existing.agent.public_key,
|
|
204
|
+
signature_algorithm: validation.data.signature_algorithm ?? existing.agent.signature_algorithm,
|
|
205
|
+
capabilities: validation.data.capabilities ?? existing.agent.capabilities,
|
|
206
|
+
trust_level: validation.data.trust_level ?? existing.agent.trust_level ?? 'basic',
|
|
207
|
+
tap_enabled: Boolean(validation.data.public_key ?? existing.agent.public_key),
|
|
208
|
+
key_created_at: validation.data.public_key ? now : existing.agent.key_created_at,
|
|
209
|
+
ans_name: validation.data.ans_name ?? existing.agent.ans_name,
|
|
210
|
+
did: validation.data.did ?? existing.agent.did,
|
|
211
|
+
provider: validation.data.provider ?? existing.agent.provider,
|
|
212
|
+
provider_key_hash: providerKeyHash,
|
|
213
|
+
};
|
|
214
|
+
await c.env.AGENTS.put(`agent:${agent.agent_id}`, JSON.stringify(agent));
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// Create new agent
|
|
218
|
+
const result = await registerTAPAgent(c.env.AGENTS, appAccess.appId, validation.data);
|
|
219
|
+
if (!result.success) {
|
|
220
|
+
return c.json({
|
|
221
|
+
success: false,
|
|
222
|
+
error: 'AGENT_CREATION_FAILED',
|
|
223
|
+
message: result.error || 'Failed to create agent'
|
|
224
|
+
}, 500);
|
|
225
|
+
}
|
|
226
|
+
agent = result.agent;
|
|
227
|
+
}
|
|
228
|
+
;
|
|
229
|
+
// Webhook: agent.tap.registered
|
|
230
|
+
const tapRegCtx = c.executionCtx;
|
|
231
|
+
if (tapRegCtx?.waitUntil) {
|
|
232
|
+
tapRegCtx.waitUntil(triggerWebhook(c.env.AGENTS, appAccess.appId, 'agent.tap.registered', { agent_id: agent.agent_id, name: agent.name, trust_level: agent.trust_level }));
|
|
145
233
|
}
|
|
146
|
-
const agent = result.agent;
|
|
147
234
|
// Return enhanced agent info
|
|
148
235
|
return c.json({
|
|
149
236
|
success: true,
|
|
@@ -159,6 +246,12 @@ export async function registerTAPAgentRoute(c) {
|
|
|
159
246
|
capabilities: agent.capabilities,
|
|
160
247
|
signature_algorithm: agent.signature_algorithm,
|
|
161
248
|
issuer: agent.issuer,
|
|
249
|
+
// W3C DID (optional)
|
|
250
|
+
did: agent.did || null,
|
|
251
|
+
// ANS fields
|
|
252
|
+
ans_name: agent.ans_name || null,
|
|
253
|
+
ans_badge_id: agent.ans_badge_id || null,
|
|
254
|
+
ans_trust_level: agent.ans_trust_level || null,
|
|
162
255
|
// Security info (don't expose full public key)
|
|
163
256
|
has_public_key: Boolean(agent.public_key),
|
|
164
257
|
key_fingerprint: agent.public_key ?
|
|
@@ -213,6 +306,12 @@ export async function getTAPAgentRoute(c) {
|
|
|
213
306
|
issuer: agent.issuer,
|
|
214
307
|
last_verified_at: agent.last_verified_at ?
|
|
215
308
|
new Date(agent.last_verified_at).toISOString() : null,
|
|
309
|
+
// ANS identity
|
|
310
|
+
ans_name: agent.ans_name || null,
|
|
311
|
+
ans_badge_id: agent.ans_badge_id || null,
|
|
312
|
+
ans_trust_level: agent.ans_trust_level || null,
|
|
313
|
+
ans_verified_at: agent.ans_verified_at
|
|
314
|
+
? new Date(agent.ans_verified_at).toISOString() : null,
|
|
216
315
|
// Public key info (secure)
|
|
217
316
|
has_public_key: Boolean(agent.public_key),
|
|
218
317
|
key_fingerprint: agent.public_key ?
|
|
@@ -305,6 +404,18 @@ export async function createTAPSessionRoute(c) {
|
|
|
305
404
|
}, 404);
|
|
306
405
|
}
|
|
307
406
|
const agent = agentResult.agent;
|
|
407
|
+
// Gate: agent must have TAP enabled (i.e. a registered public key).
|
|
408
|
+
// tap_enabled is set to true only when a public key is registered, so this
|
|
409
|
+
// check is the canonical guard. Without cryptographic identity, a TAP
|
|
410
|
+
// session has no trust anchor and would silently bypass the entire
|
|
411
|
+
// verification model.
|
|
412
|
+
if (!agent.tap_enabled) {
|
|
413
|
+
return c.json({
|
|
414
|
+
success: false,
|
|
415
|
+
error: 'TAP_NOT_ENABLED',
|
|
416
|
+
message: 'Agent does not have TAP enabled. Register a public key via POST /v1/agents/register/tap (with public_key field) or POST /v1/agents/:id/tap/rotate-key to enable TAP sessions.'
|
|
417
|
+
}, 403);
|
|
418
|
+
}
|
|
308
419
|
// Parse intent
|
|
309
420
|
const intentResult = parseTAPIntent(JSON.stringify(body.intent));
|
|
310
421
|
if (!intentResult.valid) {
|
|
@@ -333,6 +444,16 @@ export async function createTAPSessionRoute(c) {
|
|
|
333
444
|
}, 500);
|
|
334
445
|
}
|
|
335
446
|
const session = sessionResult.session;
|
|
447
|
+
// Update last_verified_at — session creation is a successful TAP verification event.
|
|
448
|
+
// updateAgentVerification catches and logs internally; void signals intentional fire-and-forget.
|
|
449
|
+
// Note: this does a read-modify-write on the full agent KV record. A concurrent key rotation
|
|
450
|
+
// could clobber that write. Future work: store last_verified_at in a separate KV key.
|
|
451
|
+
void updateAgentVerification(c.env.AGENTS, agent.agent_id, true);
|
|
452
|
+
// Webhook: tap.session.created
|
|
453
|
+
const tapSessCtx = c.executionCtx;
|
|
454
|
+
if (tapSessCtx?.waitUntil) {
|
|
455
|
+
tapSessCtx.waitUntil(triggerWebhook(c.env.AGENTS, agent.app_id, 'tap.session.created', { session_id: session.session_id, agent_id: agent.agent_id, intent: session.intent }));
|
|
456
|
+
}
|
|
336
457
|
return c.json({
|
|
337
458
|
success: true,
|
|
338
459
|
session_id: session.session_id,
|
|
@@ -406,19 +527,44 @@ export async function rotateKeyRoute(c) {
|
|
|
406
527
|
if (!agentId) {
|
|
407
528
|
return c.json({ success: false, error: 'MISSING_AGENT_ID', message: 'Agent ID is required' }, 400);
|
|
408
529
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
530
|
+
// Accept either a Bearer JWT (normal flow) or x-app-secret header (recovery flow)
|
|
531
|
+
const queryAppId = c.req.query('app_id');
|
|
532
|
+
const appSecretHeader = c.req.header('x-app-secret');
|
|
533
|
+
let resolvedAppId;
|
|
534
|
+
if (appSecretHeader && queryAppId) {
|
|
535
|
+
const valid = await validateAppSecret(c.env.APPS, queryAppId, appSecretHeader);
|
|
536
|
+
if (!valid) {
|
|
537
|
+
return c.json({ success: false, error: 'UNAUTHORIZED', message: 'Invalid app_secret' }, 401);
|
|
538
|
+
}
|
|
539
|
+
resolvedAppId = queryAppId;
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
const appAccess = await validateAppAccess(c, true);
|
|
543
|
+
if (!appAccess.valid) {
|
|
544
|
+
return c.json({ success: false, error: appAccess.error, message: 'Authentication required. Provide a Bearer token or x-app-secret + app_id.' }, (appAccess.status || 401));
|
|
545
|
+
}
|
|
546
|
+
resolvedAppId = appAccess.appId;
|
|
412
547
|
}
|
|
413
548
|
const body = await c.req.json().catch(() => ({}));
|
|
414
549
|
if (!body.public_key || !body.signature_algorithm) {
|
|
415
550
|
return c.json({ success: false, error: 'MISSING_FIELDS', message: 'public_key and signature_algorithm are required' }, 400);
|
|
416
551
|
}
|
|
552
|
+
// Normalize public_key: accept JWK objects by serializing to JSON
|
|
553
|
+
const newPublicKey = typeof body.public_key === 'object'
|
|
554
|
+
? JSON.stringify(body.public_key)
|
|
555
|
+
: body.public_key;
|
|
417
556
|
// Validate algorithm
|
|
418
557
|
const validAlgorithms = ['ecdsa-p256-sha256', 'rsa-pss-sha256', 'ed25519'];
|
|
419
558
|
if (!validAlgorithms.includes(body.signature_algorithm)) {
|
|
420
559
|
return c.json({ success: false, error: 'INVALID_ALGORITHM', message: `Unsupported algorithm. Supported: ${validAlgorithms.join(', ')}` }, 400);
|
|
421
560
|
}
|
|
561
|
+
// Validate key format (PEM, JWK, or raw Ed25519)
|
|
562
|
+
const isPEM = typeof newPublicKey === 'string' && newPublicKey.includes('BEGIN PUBLIC KEY');
|
|
563
|
+
const isJWK = isValidJWK(newPublicKey);
|
|
564
|
+
const isRawEd25519 = body.signature_algorithm === 'ed25519' && !isPEM && !isJWK;
|
|
565
|
+
if (!isPEM && !isJWK && !isRawEd25519) {
|
|
566
|
+
return c.json({ success: false, error: 'INVALID_KEY_FORMAT', message: 'Invalid public key format. Provide a PEM key, JWK object/JSON, or raw Ed25519 base64 key.' }, 400);
|
|
567
|
+
}
|
|
422
568
|
// Get existing agent
|
|
423
569
|
const agentResult = await getTAPAgent(c.env.AGENTS, agentId);
|
|
424
570
|
if (!agentResult.success || !agentResult.agent) {
|
|
@@ -426,11 +572,11 @@ export async function rotateKeyRoute(c) {
|
|
|
426
572
|
}
|
|
427
573
|
const agent = agentResult.agent;
|
|
428
574
|
// Verify agent belongs to this app
|
|
429
|
-
if (agent.app_id !==
|
|
575
|
+
if (agent.app_id !== resolvedAppId) {
|
|
430
576
|
return c.json({ success: false, error: 'UNAUTHORIZED', message: 'Agent does not belong to this app' }, 403);
|
|
431
577
|
}
|
|
432
578
|
// Update agent with new key
|
|
433
|
-
agent.public_key =
|
|
579
|
+
agent.public_key = newPublicKey;
|
|
434
580
|
agent.signature_algorithm = body.signature_algorithm;
|
|
435
581
|
agent.key_created_at = Date.now();
|
|
436
582
|
agent.key_expires_at = body.key_expires_at ? new Date(body.key_expires_at).getTime() : undefined;
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DID/VC API Routes
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* GET /.well-known/did.json — BOTCHA DID Document (did:web:botcha.ai)
|
|
6
|
+
* POST /v1/credentials/issue — Issue VC from a valid BOTCHA access_token
|
|
7
|
+
* POST /v1/credentials/verify — Verify a VC JWT
|
|
8
|
+
* GET /v1/dids/:did/resolve — Resolve a did:web DID Document
|
|
9
|
+
*
|
|
10
|
+
* All credential issuance requires a valid BOTCHA access_token in the
|
|
11
|
+
* Authorization header (Bearer <token>). The token is the result of a
|
|
12
|
+
* successful BOTCHA challenge solve (/v1/token/verify).
|
|
13
|
+
*/
|
|
14
|
+
import type { Context } from 'hono';
|
|
15
|
+
/**
|
|
16
|
+
* GET /.well-known/did.json
|
|
17
|
+
*
|
|
18
|
+
* Returns the BOTCHA DID Document for did:web:botcha.ai.
|
|
19
|
+
* This is a public endpoint — no auth required.
|
|
20
|
+
* Resolvers use this to discover BOTCHA's public keys for VC verification.
|
|
21
|
+
*/
|
|
22
|
+
export declare function didDocumentRoute(c: Context): Promise<Response>;
|
|
23
|
+
/**
|
|
24
|
+
* POST /v1/credentials/issue
|
|
25
|
+
*
|
|
26
|
+
* Exchange a valid BOTCHA access_token for a W3C Verifiable Credential.
|
|
27
|
+
*
|
|
28
|
+
* Request (body, all optional):
|
|
29
|
+
* {
|
|
30
|
+
* "agent_id": "agent_xxx", // Override agent identity in VC
|
|
31
|
+
* "duration_seconds": 86400, // VC validity period (default: 24h, max: 30d)
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* Headers:
|
|
35
|
+
* Authorization: Bearer <access_token> (required — from /v1/token/verify)
|
|
36
|
+
*
|
|
37
|
+
* Response:
|
|
38
|
+
* {
|
|
39
|
+
* "success": true,
|
|
40
|
+
* "credential_id": "urn:botcha:vc:...",
|
|
41
|
+
* "vc": { ...W3C JSON-LD credential... },
|
|
42
|
+
* "vc_jwt": "eyJ...",
|
|
43
|
+
* "issued_at": "2026-...",
|
|
44
|
+
* "expires_at": "2026-...",
|
|
45
|
+
* }
|
|
46
|
+
*/
|
|
47
|
+
export declare function issueVCRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
|
|
48
|
+
success: false;
|
|
49
|
+
error: string;
|
|
50
|
+
message: string;
|
|
51
|
+
}, 401, "json">) | (Response & import("hono").TypedResponse<{
|
|
52
|
+
success: false;
|
|
53
|
+
error: string;
|
|
54
|
+
message: string;
|
|
55
|
+
}, 403, "json">) | (Response & import("hono").TypedResponse<{
|
|
56
|
+
success: false;
|
|
57
|
+
error: string;
|
|
58
|
+
message: string;
|
|
59
|
+
}, 404, "json">) | (Response & import("hono").TypedResponse<{
|
|
60
|
+
success: false;
|
|
61
|
+
error: string;
|
|
62
|
+
message: string;
|
|
63
|
+
}, 500, "json">) | (Response & import("hono").TypedResponse<{
|
|
64
|
+
success: true;
|
|
65
|
+
credential_id: string | undefined;
|
|
66
|
+
vc: {
|
|
67
|
+
'@context': string[];
|
|
68
|
+
type: string[];
|
|
69
|
+
id: string;
|
|
70
|
+
issuer: string;
|
|
71
|
+
credentialSubject: {
|
|
72
|
+
id?: string | undefined;
|
|
73
|
+
agent_id: string;
|
|
74
|
+
app_id: string;
|
|
75
|
+
challenge_type: string;
|
|
76
|
+
solve_time_ms: number;
|
|
77
|
+
trust_level: "basic" | "verified" | "enterprise";
|
|
78
|
+
capabilities?: string[] | undefined;
|
|
79
|
+
};
|
|
80
|
+
validFrom: string;
|
|
81
|
+
validUntil: string;
|
|
82
|
+
} | undefined;
|
|
83
|
+
vc_jwt: string | undefined;
|
|
84
|
+
issued_at: string | undefined;
|
|
85
|
+
expires_at: string | undefined;
|
|
86
|
+
issuer: string;
|
|
87
|
+
usage: {
|
|
88
|
+
note: string;
|
|
89
|
+
verify_endpoint: string;
|
|
90
|
+
offline_verify: string;
|
|
91
|
+
did_document: string;
|
|
92
|
+
};
|
|
93
|
+
}, 201, "json">)>;
|
|
94
|
+
/**
|
|
95
|
+
* POST /v1/credentials/verify
|
|
96
|
+
*
|
|
97
|
+
* Verify a BOTCHA VC JWT. No auth required — the VC is the credential.
|
|
98
|
+
*
|
|
99
|
+
* Request body:
|
|
100
|
+
* { "vc_jwt": "eyJ..." }
|
|
101
|
+
*
|
|
102
|
+
* Response (valid):
|
|
103
|
+
* {
|
|
104
|
+
* "valid": true,
|
|
105
|
+
* "issuer": "did:web:botcha.ai",
|
|
106
|
+
* "credential_id": "urn:botcha:vc:...",
|
|
107
|
+
* "credential_subject": { ... },
|
|
108
|
+
* "issued_at": "...",
|
|
109
|
+
* "expires_at": "...",
|
|
110
|
+
* }
|
|
111
|
+
*
|
|
112
|
+
* Response (invalid):
|
|
113
|
+
* { "valid": false, "error": "..." }
|
|
114
|
+
*/
|
|
115
|
+
export declare function verifyVCRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
|
|
116
|
+
valid: false;
|
|
117
|
+
error: string;
|
|
118
|
+
message: string;
|
|
119
|
+
}, 400, "json">) | (Response & import("hono").TypedResponse<{
|
|
120
|
+
valid: false;
|
|
121
|
+
error: string;
|
|
122
|
+
message: string;
|
|
123
|
+
}, 503, "json">) | (Response & import("hono").TypedResponse<{
|
|
124
|
+
valid: false;
|
|
125
|
+
error: string;
|
|
126
|
+
}, 200, "json">) | (Response & import("hono").TypedResponse<{
|
|
127
|
+
valid: true;
|
|
128
|
+
issuer: string | undefined;
|
|
129
|
+
credential_id: string | undefined;
|
|
130
|
+
credential_subject: {
|
|
131
|
+
id?: string | undefined;
|
|
132
|
+
agent_id: string;
|
|
133
|
+
app_id: string;
|
|
134
|
+
challenge_type: string;
|
|
135
|
+
solve_time_ms: number;
|
|
136
|
+
trust_level: "basic" | "verified" | "enterprise";
|
|
137
|
+
capabilities?: string[] | undefined;
|
|
138
|
+
} | undefined;
|
|
139
|
+
vc: {
|
|
140
|
+
'@context': string[];
|
|
141
|
+
type: string[];
|
|
142
|
+
id: string;
|
|
143
|
+
issuer: string;
|
|
144
|
+
credentialSubject: {
|
|
145
|
+
id?: string | undefined;
|
|
146
|
+
agent_id: string;
|
|
147
|
+
app_id: string;
|
|
148
|
+
challenge_type: string;
|
|
149
|
+
solve_time_ms: number;
|
|
150
|
+
trust_level: "basic" | "verified" | "enterprise";
|
|
151
|
+
capabilities?: string[] | undefined;
|
|
152
|
+
};
|
|
153
|
+
validFrom: string;
|
|
154
|
+
validUntil: string;
|
|
155
|
+
} | undefined;
|
|
156
|
+
issued_at: string | undefined;
|
|
157
|
+
expires_at: string | undefined;
|
|
158
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
159
|
+
valid: false;
|
|
160
|
+
error: string;
|
|
161
|
+
message: string;
|
|
162
|
+
}, 500, "json">)>;
|
|
163
|
+
/**
|
|
164
|
+
* GET /v1/dids/:did/resolve
|
|
165
|
+
*
|
|
166
|
+
* Resolve a did:web DID Document.
|
|
167
|
+
* This is a public endpoint — no auth required.
|
|
168
|
+
*
|
|
169
|
+
* Supports: did:web:* only (other methods return methodNotSupported)
|
|
170
|
+
*
|
|
171
|
+
* Special case: did:web:botcha.ai is resolved locally (no outbound fetch).
|
|
172
|
+
*
|
|
173
|
+
* Query params:
|
|
174
|
+
* (none currently)
|
|
175
|
+
*
|
|
176
|
+
* Response:
|
|
177
|
+
* W3C DID Resolution Result object
|
|
178
|
+
*/
|
|
179
|
+
export declare function resolveDIDRoute(c: Context): Promise<(Response & import("hono").TypedResponse<{
|
|
180
|
+
'@context': string;
|
|
181
|
+
didDocument: null;
|
|
182
|
+
didResolutionMetadata: {
|
|
183
|
+
error: string;
|
|
184
|
+
};
|
|
185
|
+
didDocumentMetadata: {};
|
|
186
|
+
}, 400, "json">) | (Response & import("hono").TypedResponse<{
|
|
187
|
+
'@context': string;
|
|
188
|
+
didDocument: {
|
|
189
|
+
[x: string]: import("hono/utils/types").JSONValue;
|
|
190
|
+
'@context': string | string[];
|
|
191
|
+
id: string;
|
|
192
|
+
controller?: string | string[] | undefined;
|
|
193
|
+
verificationMethod?: {
|
|
194
|
+
id: string;
|
|
195
|
+
type: string;
|
|
196
|
+
controller: string;
|
|
197
|
+
publicKeyJwk?: {
|
|
198
|
+
[x: string]: string | undefined;
|
|
199
|
+
} | undefined;
|
|
200
|
+
publicKeyMultibase?: string | undefined;
|
|
201
|
+
}[] | undefined;
|
|
202
|
+
authentication?: (string | {
|
|
203
|
+
id: string;
|
|
204
|
+
type: string;
|
|
205
|
+
controller: string;
|
|
206
|
+
publicKeyJwk?: {
|
|
207
|
+
[x: string]: string | undefined;
|
|
208
|
+
} | undefined;
|
|
209
|
+
publicKeyMultibase?: string | undefined;
|
|
210
|
+
})[] | undefined;
|
|
211
|
+
assertionMethod?: (string | {
|
|
212
|
+
id: string;
|
|
213
|
+
type: string;
|
|
214
|
+
controller: string;
|
|
215
|
+
publicKeyJwk?: {
|
|
216
|
+
[x: string]: string | undefined;
|
|
217
|
+
} | undefined;
|
|
218
|
+
publicKeyMultibase?: string | undefined;
|
|
219
|
+
})[] | undefined;
|
|
220
|
+
keyAgreement?: (string | {
|
|
221
|
+
id: string;
|
|
222
|
+
type: string;
|
|
223
|
+
controller: string;
|
|
224
|
+
publicKeyJwk?: {
|
|
225
|
+
[x: string]: string | undefined;
|
|
226
|
+
} | undefined;
|
|
227
|
+
publicKeyMultibase?: string | undefined;
|
|
228
|
+
})[] | undefined;
|
|
229
|
+
capabilityInvocation?: (string | {
|
|
230
|
+
id: string;
|
|
231
|
+
type: string;
|
|
232
|
+
controller: string;
|
|
233
|
+
publicKeyJwk?: {
|
|
234
|
+
[x: string]: string | undefined;
|
|
235
|
+
} | undefined;
|
|
236
|
+
publicKeyMultibase?: string | undefined;
|
|
237
|
+
})[] | undefined;
|
|
238
|
+
capabilityDelegation?: (string | {
|
|
239
|
+
id: string;
|
|
240
|
+
type: string;
|
|
241
|
+
controller: string;
|
|
242
|
+
publicKeyJwk?: {
|
|
243
|
+
[x: string]: string | undefined;
|
|
244
|
+
} | undefined;
|
|
245
|
+
publicKeyMultibase?: string | undefined;
|
|
246
|
+
})[] | undefined;
|
|
247
|
+
service?: {
|
|
248
|
+
id: string;
|
|
249
|
+
type: string;
|
|
250
|
+
serviceEndpoint: string | string[] | {
|
|
251
|
+
[x: string]: string;
|
|
252
|
+
};
|
|
253
|
+
description?: string | undefined;
|
|
254
|
+
}[] | undefined;
|
|
255
|
+
};
|
|
256
|
+
didResolutionMetadata: {
|
|
257
|
+
contentType: string;
|
|
258
|
+
retrieved: string;
|
|
259
|
+
duration: number;
|
|
260
|
+
};
|
|
261
|
+
didDocumentMetadata: {};
|
|
262
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
263
|
+
'@context': string;
|
|
264
|
+
didDocument: {
|
|
265
|
+
[x: string]: import("hono/utils/types").JSONValue;
|
|
266
|
+
'@context': string | string[];
|
|
267
|
+
id: string;
|
|
268
|
+
controller?: string | string[] | undefined;
|
|
269
|
+
verificationMethod?: {
|
|
270
|
+
id: string;
|
|
271
|
+
type: string;
|
|
272
|
+
controller: string;
|
|
273
|
+
publicKeyJwk?: {
|
|
274
|
+
[x: string]: string | undefined;
|
|
275
|
+
} | undefined;
|
|
276
|
+
publicKeyMultibase?: string | undefined;
|
|
277
|
+
}[] | undefined;
|
|
278
|
+
authentication?: (string | {
|
|
279
|
+
id: string;
|
|
280
|
+
type: string;
|
|
281
|
+
controller: string;
|
|
282
|
+
publicKeyJwk?: {
|
|
283
|
+
[x: string]: string | undefined;
|
|
284
|
+
} | undefined;
|
|
285
|
+
publicKeyMultibase?: string | undefined;
|
|
286
|
+
})[] | undefined;
|
|
287
|
+
assertionMethod?: (string | {
|
|
288
|
+
id: string;
|
|
289
|
+
type: string;
|
|
290
|
+
controller: string;
|
|
291
|
+
publicKeyJwk?: {
|
|
292
|
+
[x: string]: string | undefined;
|
|
293
|
+
} | undefined;
|
|
294
|
+
publicKeyMultibase?: string | undefined;
|
|
295
|
+
})[] | undefined;
|
|
296
|
+
keyAgreement?: (string | {
|
|
297
|
+
id: string;
|
|
298
|
+
type: string;
|
|
299
|
+
controller: string;
|
|
300
|
+
publicKeyJwk?: {
|
|
301
|
+
[x: string]: string | undefined;
|
|
302
|
+
} | undefined;
|
|
303
|
+
publicKeyMultibase?: string | undefined;
|
|
304
|
+
})[] | undefined;
|
|
305
|
+
capabilityInvocation?: (string | {
|
|
306
|
+
id: string;
|
|
307
|
+
type: string;
|
|
308
|
+
controller: string;
|
|
309
|
+
publicKeyJwk?: {
|
|
310
|
+
[x: string]: string | undefined;
|
|
311
|
+
} | undefined;
|
|
312
|
+
publicKeyMultibase?: string | undefined;
|
|
313
|
+
})[] | undefined;
|
|
314
|
+
capabilityDelegation?: (string | {
|
|
315
|
+
id: string;
|
|
316
|
+
type: string;
|
|
317
|
+
controller: string;
|
|
318
|
+
publicKeyJwk?: {
|
|
319
|
+
[x: string]: string | undefined;
|
|
320
|
+
} | undefined;
|
|
321
|
+
publicKeyMultibase?: string | undefined;
|
|
322
|
+
})[] | undefined;
|
|
323
|
+
service?: {
|
|
324
|
+
id: string;
|
|
325
|
+
type: string;
|
|
326
|
+
serviceEndpoint: string | string[] | {
|
|
327
|
+
[x: string]: string;
|
|
328
|
+
};
|
|
329
|
+
description?: string | undefined;
|
|
330
|
+
}[] | undefined;
|
|
331
|
+
} | null;
|
|
332
|
+
didResolutionMetadata: {
|
|
333
|
+
contentType?: string | undefined;
|
|
334
|
+
error?: string | undefined;
|
|
335
|
+
retrieved?: string | undefined;
|
|
336
|
+
duration?: number | undefined;
|
|
337
|
+
};
|
|
338
|
+
didDocumentMetadata: {
|
|
339
|
+
created?: string | undefined;
|
|
340
|
+
updated?: string | undefined;
|
|
341
|
+
deactivated?: boolean | undefined;
|
|
342
|
+
};
|
|
343
|
+
}, 200 | 404, "json">) | (Response & import("hono").TypedResponse<{
|
|
344
|
+
'@context': string;
|
|
345
|
+
didDocument: null;
|
|
346
|
+
didResolutionMetadata: {
|
|
347
|
+
error: string;
|
|
348
|
+
};
|
|
349
|
+
didDocumentMetadata: {};
|
|
350
|
+
}, 500, "json">)>;
|
|
351
|
+
declare const _default: {
|
|
352
|
+
didDocumentRoute: typeof didDocumentRoute;
|
|
353
|
+
issueVCRoute: typeof issueVCRoute;
|
|
354
|
+
verifyVCRoute: typeof verifyVCRoute;
|
|
355
|
+
resolveDIDRoute: typeof resolveDIDRoute;
|
|
356
|
+
};
|
|
357
|
+
export default _default;
|
|
358
|
+
//# sourceMappingURL=tap-vc-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tap-vc-routes.d.ts","sourceRoot":"","sources":["../src/tap-vc-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAoCpC;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO,qBAkBhD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA8I5C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,aAAa,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwD7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsE/C;;;;;;;AAED,wBAKE"}
|