@dupecom/botcha-cloudflare 0.19.0 → 0.20.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/README.md +1 -1
- package/dist/apps.d.ts +6 -2
- package/dist/apps.d.ts.map +1 -1
- package/dist/apps.js +6 -2
- package/dist/auth.d.ts +3 -3
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +24 -15
- package/dist/dashboard/auth.d.ts +1 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +11 -4
- package/dist/dashboard/device-code.d.ts +1 -1
- package/dist/dashboard/device-code.js +2 -2
- package/dist/dashboard/docs.js +4 -4
- package/dist/dashboard/whitepaper.js +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +136 -83
- package/dist/static.d.ts +10 -1
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +17 -15
- package/dist/tap-attestation-routes.d.ts.map +1 -1
- package/dist/tap-attestation-routes.js +30 -10
- package/dist/tap-delegation-routes.d.ts.map +1 -1
- package/dist/tap-delegation-routes.js +30 -10
- package/dist/tap-reputation-routes.d.ts.map +1 -1
- package/dist/tap-reputation-routes.js +30 -10
- package/dist/tap-routes.d.ts +10 -1
- package/dist/tap-routes.d.ts.map +1 -1
- package/dist/tap-routes.js +64 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Reverse CAPTCHA that verifies AI agents and blocks humans. Running at the edge.
|
|
|
11
11
|
- **Agent Registry** - Persistent agent identities (POST /v1/agents/register)
|
|
12
12
|
- **Email-tied apps** - Email verification, account recovery, secret rotation
|
|
13
13
|
- **Dashboard** - Per-app metrics with agent-first auth (device code flow)
|
|
14
|
-
- **JWT security** -
|
|
14
|
+
- **JWT security** - 1-hr access tokens, refresh tokens, audience claims, IP binding, revocation
|
|
15
15
|
- **Multi-tenant** - Per-app isolation, scoped tokens, rate limiting
|
|
16
16
|
- **Server-side SDKs** - @dupecom/botcha-verify (TS) + botcha-verify (Python)
|
|
17
17
|
|
package/dist/apps.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type KVNamespace = {
|
|
|
22
22
|
*/
|
|
23
23
|
export interface AppConfig {
|
|
24
24
|
app_id: string;
|
|
25
|
+
name?: string;
|
|
25
26
|
secret_hash: string;
|
|
26
27
|
created_at: number;
|
|
27
28
|
rate_limit: number;
|
|
@@ -35,6 +36,7 @@ export interface AppConfig {
|
|
|
35
36
|
*/
|
|
36
37
|
export interface CreateAppResult {
|
|
37
38
|
app_id: string;
|
|
39
|
+
name?: string;
|
|
38
40
|
app_secret: string;
|
|
39
41
|
email: string;
|
|
40
42
|
email_verified: boolean;
|
|
@@ -45,6 +47,7 @@ export interface CreateAppResult {
|
|
|
45
47
|
*/
|
|
46
48
|
export type PublicAppConfig = {
|
|
47
49
|
app_id: string;
|
|
50
|
+
name?: string;
|
|
48
51
|
created_at: number;
|
|
49
52
|
rate_limit: number;
|
|
50
53
|
email: string;
|
|
@@ -90,9 +93,10 @@ export declare function generateVerificationCode(): string;
|
|
|
90
93
|
*
|
|
91
94
|
* @param kv - KV namespace for storage
|
|
92
95
|
* @param email - Required owner email address
|
|
93
|
-
* @
|
|
96
|
+
* @param name - Optional human-readable label for the app
|
|
97
|
+
* @returns {app_id, name, app_secret, email, email_verified, verification_required}
|
|
94
98
|
*/
|
|
95
|
-
export declare function createApp(kv: KVNamespace, email: string): Promise<CreateAppResult>;
|
|
99
|
+
export declare function createApp(kv: KVNamespace, email: string, name?: string): Promise<CreateAppResult>;
|
|
96
100
|
/**
|
|
97
101
|
* Get the plaintext verification code for an app (internal use only — for sending via email).
|
|
98
102
|
*
|
package/dist/apps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACtF,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzF,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAOtC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOhE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAMjD;AAID
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"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"}
|
package/dist/apps.js
CHANGED
|
@@ -79,9 +79,10 @@ export function generateVerificationCode() {
|
|
|
79
79
|
*
|
|
80
80
|
* @param kv - KV namespace for storage
|
|
81
81
|
* @param email - Required owner email address
|
|
82
|
-
* @
|
|
82
|
+
* @param name - Optional human-readable label for the app
|
|
83
|
+
* @returns {app_id, name, app_secret, email, email_verified, verification_required}
|
|
83
84
|
*/
|
|
84
|
-
export async function createApp(kv, email) {
|
|
85
|
+
export async function createApp(kv, email, name) {
|
|
85
86
|
const app_id = generateAppId();
|
|
86
87
|
const app_secret = generateAppSecret();
|
|
87
88
|
const secret_hash = await hashSecret(app_secret);
|
|
@@ -90,6 +91,7 @@ export async function createApp(kv, email) {
|
|
|
90
91
|
const verificationCodeHash = await hashSecret(verificationCode);
|
|
91
92
|
const config = {
|
|
92
93
|
app_id,
|
|
94
|
+
...(name && { name }),
|
|
93
95
|
secret_hash,
|
|
94
96
|
created_at: Date.now(),
|
|
95
97
|
rate_limit: 100, // Default: 100 requests/hour
|
|
@@ -105,6 +107,7 @@ export async function createApp(kv, email) {
|
|
|
105
107
|
]);
|
|
106
108
|
return {
|
|
107
109
|
app_id,
|
|
110
|
+
...(name && { name }),
|
|
108
111
|
app_secret, // ONLY returned at creation time!
|
|
109
112
|
email,
|
|
110
113
|
email_verified: false,
|
|
@@ -242,6 +245,7 @@ export async function getApp(kv, app_id) {
|
|
|
242
245
|
// Return config WITHOUT secret_hash (security)
|
|
243
246
|
return {
|
|
244
247
|
app_id: config.app_id,
|
|
248
|
+
...(config.name && { name: config.name }),
|
|
245
249
|
created_at: config.created_at,
|
|
246
250
|
rate_limit: config.rate_limit,
|
|
247
251
|
email: config.email,
|
package/dist/auth.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - JTI (JWT ID) for revocation
|
|
6
6
|
* - Audience claims for API scoping
|
|
7
7
|
* - Client IP binding for additional security
|
|
8
|
-
* - Short-lived access tokens (
|
|
8
|
+
* - Short-lived access tokens (1 hour) with refresh tokens (1 hour)
|
|
9
9
|
* - Token revocation via KV storage
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
@@ -86,8 +86,8 @@ export declare function getSigningPublicKeyJWK(privateKeyJwk: ES256SigningKeyJWK
|
|
|
86
86
|
/**
|
|
87
87
|
* Generate JWT tokens (access + refresh) after successful challenge verification
|
|
88
88
|
*
|
|
89
|
-
* Access token:
|
|
90
|
-
* Refresh token: 1 hour, used to get new access tokens
|
|
89
|
+
* Access token: 1 hour, used for API access
|
|
90
|
+
* Refresh token: 1 hour, used to get new access tokens without re-solving challenges
|
|
91
91
|
*
|
|
92
92
|
* When signingKey (ES256 JWK) is provided, tokens are signed with ES256.
|
|
93
93
|
* Otherwise falls back to HS256 with the shared secret (backward compat).
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - JTI (JWT ID) for revocation
|
|
6
6
|
* - Audience claims for API scoping
|
|
7
7
|
* - Client IP binding for additional security
|
|
8
|
-
* - Short-lived access tokens (
|
|
8
|
+
* - Short-lived access tokens (1 hour) with refresh tokens (1 hour)
|
|
9
9
|
* - Token revocation via KV storage
|
|
10
10
|
*/
|
|
11
11
|
import { SignJWT, jwtVerify, importJWK, decodeProtectedHeader } from 'jose';
|
|
@@ -26,8 +26,8 @@ export function getSigningPublicKeyJWK(privateKeyJwk) {
|
|
|
26
26
|
/**
|
|
27
27
|
* Generate JWT tokens (access + refresh) after successful challenge verification
|
|
28
28
|
*
|
|
29
|
-
* Access token:
|
|
30
|
-
* Refresh token: 1 hour, used to get new access tokens
|
|
29
|
+
* Access token: 1 hour, used for API access
|
|
30
|
+
* Refresh token: 1 hour, used to get new access tokens without re-solving challenges
|
|
31
31
|
*
|
|
32
32
|
* When signingKey (ES256 JWK) is provided, tokens are signed with ES256.
|
|
33
33
|
* Otherwise falls back to HS256 with the shared secret (backward compat).
|
|
@@ -38,8 +38,11 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
|
|
|
38
38
|
let protectedHeader;
|
|
39
39
|
if (signingKey) {
|
|
40
40
|
// ES256 asymmetric signing
|
|
41
|
-
signKey = await importJWK(signingKey, 'ES256');
|
|
42
|
-
protectedHeader = {
|
|
41
|
+
signKey = (await importJWK(signingKey, 'ES256'));
|
|
42
|
+
protectedHeader = {
|
|
43
|
+
alg: 'ES256',
|
|
44
|
+
kid: signingKey.kid || 'botcha-signing-1',
|
|
45
|
+
};
|
|
43
46
|
}
|
|
44
47
|
else {
|
|
45
48
|
// HS256 symmetric signing (legacy fallback)
|
|
@@ -49,7 +52,7 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
|
|
|
49
52
|
// Generate unique JTIs for both tokens
|
|
50
53
|
const accessJti = crypto.randomUUID();
|
|
51
54
|
const refreshJti = crypto.randomUUID();
|
|
52
|
-
// Access token:
|
|
55
|
+
// Access token: 1 hour
|
|
53
56
|
const accessTokenPayload = {
|
|
54
57
|
type: 'botcha-verified',
|
|
55
58
|
solveTime: solveTimeMs,
|
|
@@ -70,7 +73,7 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
|
|
|
70
73
|
.setSubject(challengeId)
|
|
71
74
|
.setIssuer('botcha.ai')
|
|
72
75
|
.setIssuedAt()
|
|
73
|
-
.setExpirationTime('
|
|
76
|
+
.setExpirationTime('1h') // 1 hour
|
|
74
77
|
.sign(signKey);
|
|
75
78
|
// Refresh token: 1 hour
|
|
76
79
|
const refreshTokenPayload = {
|
|
@@ -93,7 +96,10 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
|
|
|
93
96
|
// Also store aud, client_ip, and app_id so they carry over on refresh
|
|
94
97
|
if (env?.CHALLENGES) {
|
|
95
98
|
try {
|
|
96
|
-
const refreshData = {
|
|
99
|
+
const refreshData = {
|
|
100
|
+
sub: challengeId,
|
|
101
|
+
iat: Date.now(),
|
|
102
|
+
};
|
|
97
103
|
if (options?.aud) {
|
|
98
104
|
refreshData.aud = options.aud;
|
|
99
105
|
}
|
|
@@ -113,7 +119,7 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
|
|
|
113
119
|
}
|
|
114
120
|
return {
|
|
115
121
|
access_token: accessToken,
|
|
116
|
-
expires_in:
|
|
122
|
+
expires_in: 3600, // 1 hour in seconds
|
|
117
123
|
refresh_token: refreshToken,
|
|
118
124
|
refresh_expires_in: 3600, // 1 hour in seconds
|
|
119
125
|
};
|
|
@@ -145,7 +151,7 @@ export async function refreshAccessToken(refreshToken, env, secret, options, sig
|
|
|
145
151
|
let verifyKey;
|
|
146
152
|
let algorithms;
|
|
147
153
|
if (header.alg === 'ES256' && publicKey) {
|
|
148
|
-
verifyKey = await importJWK(publicKey, 'ES256');
|
|
154
|
+
verifyKey = (await importJWK(publicKey, 'ES256'));
|
|
149
155
|
algorithms = ['ES256'];
|
|
150
156
|
}
|
|
151
157
|
else {
|
|
@@ -213,8 +219,11 @@ export async function refreshAccessToken(refreshToken, env, secret, options, sig
|
|
|
213
219
|
let signKey;
|
|
214
220
|
let protectedHeaderObj;
|
|
215
221
|
if (signingKey) {
|
|
216
|
-
signKey = await importJWK(signingKey, 'ES256');
|
|
217
|
-
protectedHeaderObj = {
|
|
222
|
+
signKey = (await importJWK(signingKey, 'ES256'));
|
|
223
|
+
protectedHeaderObj = {
|
|
224
|
+
alg: 'ES256',
|
|
225
|
+
kid: signingKey.kid || 'botcha-signing-1',
|
|
226
|
+
};
|
|
218
227
|
}
|
|
219
228
|
else {
|
|
220
229
|
signKey = new TextEncoder().encode(secret);
|
|
@@ -245,13 +254,13 @@ export async function refreshAccessToken(refreshToken, env, secret, options, sig
|
|
|
245
254
|
.setSubject(payload.sub || '')
|
|
246
255
|
.setIssuer('botcha.ai')
|
|
247
256
|
.setIssuedAt()
|
|
248
|
-
.setExpirationTime('
|
|
257
|
+
.setExpirationTime('1h') // 1 hour
|
|
249
258
|
.sign(signKey);
|
|
250
259
|
return {
|
|
251
260
|
success: true,
|
|
252
261
|
tokens: {
|
|
253
262
|
access_token: accessToken,
|
|
254
|
-
expires_in:
|
|
263
|
+
expires_in: 3600, // 1 hour in seconds
|
|
255
264
|
},
|
|
256
265
|
};
|
|
257
266
|
}
|
|
@@ -282,7 +291,7 @@ export async function verifyToken(token, secret, env, options, publicKey) {
|
|
|
282
291
|
let algorithms;
|
|
283
292
|
if (header.alg === 'ES256' && publicKey) {
|
|
284
293
|
// ES256 asymmetric verification
|
|
285
|
-
verifyKey = await importJWK(publicKey, 'ES256');
|
|
294
|
+
verifyKey = (await importJWK(publicKey, 'ES256'));
|
|
286
295
|
algorithms = ['ES256'];
|
|
287
296
|
}
|
|
288
297
|
else {
|
package/dist/dashboard/auth.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ export declare function handleDeviceCodeChallenge(c: Context<{
|
|
|
113
113
|
* POST /v1/auth/device-code/verify
|
|
114
114
|
*
|
|
115
115
|
* Agent submits challenge solution. On success, returns a short-lived
|
|
116
|
-
* device code (BOTCHA-
|
|
116
|
+
* device code (BOTCHA-XXXXXX) that a human can enter at /dashboard/code.
|
|
117
117
|
*/
|
|
118
118
|
export declare function handleDeviceCodeVerify(c: Context<{
|
|
119
119
|
Bindings: Bindings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/dashboard/auth.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/dashboard/auth.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAOvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAKjD,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAGF,KAAK,SAAS,GAAG;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAIF;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5F;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,CAmChG,CAAC;AAIF;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;;;;;;;;;;oEA2CpF;AAgDD;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;;;;;;;;;;;oEAwBjF;AAID;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;;;;;;;;;;oEAEjF;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;;;;;;;;;;;oEA4B9E;AAID;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,qBA2E5E;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,gFA4B9E;AAID;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,gFAyBnE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,gFAGpE;AAID;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,gFA2BxE;AA4BD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,qBAgFvE"}
|
package/dist/dashboard/auth.js
CHANGED
|
@@ -4,6 +4,7 @@ import { SignJWT } from 'jose';
|
|
|
4
4
|
import { verifyToken } from '../auth';
|
|
5
5
|
import { validateAppSecret, getAppByEmail } from '../apps';
|
|
6
6
|
import { sendEmail, recoveryEmail } from '../email';
|
|
7
|
+
import { checkRateLimit, getClientIP } from '../rate-limit';
|
|
7
8
|
import { generateDeviceCode, storeDeviceCode, redeemDeviceCode } from './device-code';
|
|
8
9
|
import { LoginLayout, Card, Divider } from './layout';
|
|
9
10
|
// ============ SESSION HELPERS ============
|
|
@@ -195,7 +196,7 @@ export async function handleDeviceCodeChallenge(c) {
|
|
|
195
196
|
* POST /v1/auth/device-code/verify
|
|
196
197
|
*
|
|
197
198
|
* Agent submits challenge solution. On success, returns a short-lived
|
|
198
|
-
* device code (BOTCHA-
|
|
199
|
+
* device code (BOTCHA-XXXXXX) that a human can enter at /dashboard/code.
|
|
199
200
|
*/
|
|
200
201
|
export async function handleDeviceCodeVerify(c) {
|
|
201
202
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -247,12 +248,12 @@ export async function renderDeviceCodePage(c) {
|
|
|
247
248
|
};
|
|
248
249
|
return c.html(_jsxs(LoginLayout, { title: "Enter Device Code - BOTCHA", children: [_jsxs("div", { style: "font-size: 0.875rem; font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase; text-align: center; margin-bottom: 2rem;", children: ['>', "_\u00A0BOTCHA"] }), _jsx("form", { method: "post", action: "/dashboard/code", children: _jsxs(Card, { title: "Device Code", children: [emailSent && (_jsx("div", { class: "success-message", style: "background: #f0faf0; border: 1px solid #1a8a2a; color: #1a6a1a; padding: 0.75rem; font-size: 0.75rem; margin-bottom: 1rem;", children: "If an account with that email exists, a login code has been sent. Check your inbox." })), error && errorMap[error] && (_jsx("div", { class: "error-message", children: errorMap[error] })), _jsx("p", { class: "text-muted mb-2", style: "font-size: 0.75rem;", children: emailSent
|
|
249
250
|
? 'Enter the code from your email below.'
|
|
250
|
-
: 'Your AI agent generated a login code for you. Enter it below to access the dashboard.' }), _jsxs("div", { class: "form-group", children: [_jsx("label", { for: "code", children: "Code" }), _jsxs("div", { style: "display: flex; align-items: stretch; gap: 0;", children: [_jsx("span", { style: "display: flex; align-items: center; font-size: 1.5rem; font-weight: 700; letter-spacing: 0.15em; padding: 0 0.25rem 0 1rem; border: 1px solid var(--border); border-right: none; background: var(--bg-raised); color: var(--text-muted);", children: "BOTCHA-" }), _jsx("input", { type: "text", id: "code", name: "code", placeholder: "
|
|
251
|
+
: 'Your AI agent generated a login code for you. Enter it below to access the dashboard.' }), _jsxs("div", { class: "form-group", children: [_jsx("label", { for: "code", children: "Code" }), _jsxs("div", { style: "display: flex; align-items: stretch; gap: 0;", children: [_jsx("span", { style: "display: flex; align-items: center; font-size: 1.5rem; font-weight: 700; letter-spacing: 0.15em; padding: 0 0.25rem 0 1rem; border: 1px solid var(--border); border-right: none; background: var(--bg-raised); color: var(--text-muted);", children: "BOTCHA-" }), _jsx("input", { type: "text", id: "code", name: "code", placeholder: "XXXXXX", value: prefill, required: true, autocomplete: "off", maxlength: 13, style: "font-size: 1.5rem; font-weight: 700; text-align: center; letter-spacing: 0.15em; padding: 1rem; flex: 1; border-left: none;" })] })] }), _jsx("script", { dangerouslySetInnerHTML: { __html: `
|
|
251
252
|
document.getElementById('code').addEventListener('input', function(e) {
|
|
252
253
|
var v = e.target.value.toUpperCase().replace(/[^A-Z0-9-]/g, '');
|
|
253
254
|
if (v.startsWith('BOTCHA-')) v = v.slice(7);
|
|
254
255
|
else if (v.startsWith('BOTCHA')) v = v.slice(6);
|
|
255
|
-
e.target.value = v.slice(0,
|
|
256
|
+
e.target.value = v.slice(0, 6);
|
|
256
257
|
});
|
|
257
258
|
` } }), _jsxs("button", { type: "submit", children: ["Verify Code ", '>'] })] }) }), _jsxs("div", { class: "hint", style: "text-align: center; line-height: 1.8; margin-top: 1.5rem;", children: ["Don't have a code? Ask your AI agent to run:", _jsx("br", {}), _jsx("code", { children: "POST /v1/auth/device-code" }), _jsx("br", {}), _jsx("br", {}), _jsx("a", { href: "/dashboard/login", children: "Back to login" })] })] }));
|
|
258
259
|
}
|
|
@@ -262,12 +263,18 @@ export async function renderDeviceCodePage(c) {
|
|
|
262
263
|
* Human submits device code. If valid, creates session and redirects to dashboard.
|
|
263
264
|
*/
|
|
264
265
|
export async function handleDeviceCodeRedeem(c) {
|
|
266
|
+
// Brute-force guard for device code redemption attempts (20/hour/IP).
|
|
267
|
+
const clientIp = getClientIP(c.req.raw);
|
|
268
|
+
const redemptionRate = await checkRateLimit(c.env.RATE_LIMITS, `device-code:${clientIp}`, 20);
|
|
269
|
+
if (!redemptionRate.allowed) {
|
|
270
|
+
return c.redirect('/dashboard/code?error=invalid');
|
|
271
|
+
}
|
|
265
272
|
const body = await c.req.parseBody();
|
|
266
273
|
let code = (body.code || '').trim().toUpperCase();
|
|
267
274
|
if (!code) {
|
|
268
275
|
return c.redirect('/dashboard/code?error=missing');
|
|
269
276
|
}
|
|
270
|
-
// Normalize: accept both "
|
|
277
|
+
// Normalize: accept both "AR8C2Q" and "BOTCHA-AR8C2Q", always look up with prefix.
|
|
271
278
|
if (!code.startsWith('BOTCHA-')) {
|
|
272
279
|
code = `BOTCHA-${code}`;
|
|
273
280
|
}
|
|
@@ -22,7 +22,7 @@ export interface DeviceCodeData {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Generate a human-friendly device code.
|
|
25
|
-
* Format: BOTCHA-
|
|
25
|
+
* Format: BOTCHA-XXXXXX (6 alphanumeric chars, no ambiguous chars)
|
|
26
26
|
*
|
|
27
27
|
* Uses a restricted alphabet that avoids 0/O, 1/I/l confusion.
|
|
28
28
|
*/
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
// ============ CODE GENERATION ============
|
|
16
16
|
/**
|
|
17
17
|
* Generate a human-friendly device code.
|
|
18
|
-
* Format: BOTCHA-
|
|
18
|
+
* Format: BOTCHA-XXXXXX (6 alphanumeric chars, no ambiguous chars)
|
|
19
19
|
*
|
|
20
20
|
* Uses a restricted alphabet that avoids 0/O, 1/I/l confusion.
|
|
21
21
|
*/
|
|
22
22
|
export function generateDeviceCode() {
|
|
23
23
|
const alphabet = '23456789ABCDEFGHJKMNPQRSTUVWXYZ'; // no 0,O,1,I,L
|
|
24
|
-
const bytes = new Uint8Array(
|
|
24
|
+
const bytes = new Uint8Array(6);
|
|
25
25
|
crypto.getRandomValues(bytes);
|
|
26
26
|
const chars = Array.from(bytes).map(b => alphabet[b % alphabet.length]).join('');
|
|
27
27
|
return `BOTCHA-${chars}`;
|
package/dist/dashboard/docs.js
CHANGED
|
@@ -464,7 +464,7 @@ async with BotchaClient() as client:
|
|
|
464
464
|
"message": "HYBRID TEST PASSED! Speed: 47ms, Reasoning: 3/3",
|
|
465
465
|
"speed": { "valid": true, "solveTimeMs": 47 },
|
|
466
466
|
"reasoning": { "valid": true, "score": "3/3" }
|
|
467
|
-
}` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reasoning", desc: "Get a reasoning-only challenge" }), _jsx(Endpoint, { method: "POST", path: "/v1/reasoning", desc: "Verify reasoning challenge" }), _jsx(Endpoint, { method: "GET", path: "/v1/hybrid", desc: "Get a hybrid challenge (alternate endpoint)" }), _jsx(Endpoint, { method: "POST", path: "/v1/hybrid", desc: "Verify hybrid challenge" })] }), _jsxs("section", { id: "authentication", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Authentication (Tokens)" }), _jsxs("p", { class: "docs-section-desc", children: ["JWT token flow for accessing protected endpoints. Solve a speed challenge to receive an access token (
|
|
467
|
+
}` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reasoning", desc: "Get a reasoning-only challenge" }), _jsx(Endpoint, { method: "POST", path: "/v1/reasoning", desc: "Verify reasoning challenge" }), _jsx(Endpoint, { method: "GET", path: "/v1/hybrid", desc: "Get a hybrid challenge (alternate endpoint)" }), _jsx(Endpoint, { method: "POST", path: "/v1/hybrid", desc: "Verify hybrid challenge" })] }), _jsxs("section", { id: "authentication", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Authentication (Tokens)" }), _jsxs("p", { class: "docs-section-desc", children: ["JWT token flow for accessing protected endpoints. Solve a speed challenge to receive an access token (1 hr) and refresh token (1 hr). Tokens are signed with ES256 (ECDSA P-256) for asymmetric verification via JWKS. HS256 still supported for backward compatibility. Use ", _jsx("code", { children: "POST /v1/token/validate" }), " for remote validation without a shared secret."] }), _jsxs("div", { class: "docs-flow", children: [_jsx("div", { class: "docs-flow-title", children: "Token Flow" }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "1." }), _jsxs("span", { children: [_jsx("code", { children: "GET /v1/token" }), " \u2014 receive a speed challenge"] })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "2." }), _jsx("span", { children: "Solve: SHA-256 of each number, first 8 hex chars" })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "3." }), _jsxs("span", { children: [_jsx("code", { children: "POST /v1/token/verify" }), " \u2014 submit solution, receive JWT + human_link"] })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "4." }), _jsxs("span", { children: ["Use ", _jsx("code", { children: "Authorization: Bearer <access_token>" }), " on protected endpoints"] })] })] }), _jsxs(Endpoint, { method: "GET", path: "/v1/token", desc: "Get challenge for JWT flow", children: [_jsx("div", { class: "docs-label", children: "Query Parameters" }), _jsxs("table", { class: "docs-param-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Name" }), _jsx("th", { children: "Type" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "ts" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "integer" }) }), _jsx("td", { children: "Client timestamp (ms) for RTT compensation" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "audience" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "string" }) }), _jsx("td", { children: "Audience claim for scoped tokens (e.g. service URL)" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "app_id" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "string" }) }), _jsx("td", { children: "Multi-tenant app ID" })] })] })] })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/verify", desc: "Submit solution, receive JWT", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{
|
|
468
468
|
"id": "<challenge_id>",
|
|
469
469
|
"answers": ["hash1", "hash2", "hash3", "hash4", "hash5"],
|
|
470
470
|
"audience": "https://api.example.com", // optional
|
|
@@ -472,7 +472,7 @@ async with BotchaClient() as client:
|
|
|
472
472
|
}` }) }), _jsx("div", { class: "docs-label", children: "Response" }), _jsx("pre", { children: _jsx("code", { children: `{
|
|
473
473
|
"success": true,
|
|
474
474
|
"access_token": "eyJ...",
|
|
475
|
-
"expires_in":
|
|
475
|
+
"expires_in": 3600,
|
|
476
476
|
"refresh_token": "eyJ...",
|
|
477
477
|
"refresh_expires_in": 3600,
|
|
478
478
|
"human_link": "https://botcha.ai/go/BOTCHA-ABC123",
|
|
@@ -481,7 +481,7 @@ async with BotchaClient() as client:
|
|
|
481
481
|
}` }) })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/refresh", desc: "Refresh access token", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{ "refresh_token": "<refresh_token>" }` }) }), _jsx("div", { class: "docs-label", children: "Response" }), _jsx("pre", { children: _jsx("code", { children: `{
|
|
482
482
|
"success": true,
|
|
483
483
|
"access_token": "eyJ...",
|
|
484
|
-
"expires_in":
|
|
484
|
+
"expires_in": 3600
|
|
485
485
|
}` }) })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/revoke", desc: "Revoke a token", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{ "token": "<access_token or refresh_token>" }` }) })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/validate", desc: "Validate a token remotely (no secret needed)", children: [_jsx("p", { children: "Validate any BOTCHA token without needing the signing secret. Supports both ES256 and HS256 tokens." }), _jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{ "token": "<any BOTCHA JWT token>" }` }) }), _jsx("div", { class: "docs-label", children: "Response" }), _jsx("pre", { children: _jsx("code", { children: `{
|
|
486
486
|
"valid": true,
|
|
487
487
|
"payload": {
|
|
@@ -547,7 +547,7 @@ async with BotchaClient() as client:
|
|
|
547
547
|
"category": "commerce",
|
|
548
548
|
"action": "purchase_completed",
|
|
549
549
|
"metadata": { "amount": 29.99 }
|
|
550
|
-
}` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reputation/:agent_id/events", desc: "List events (?category=&limit=)" }), _jsx(Endpoint, { method: "POST", path: "/v1/reputation/:agent_id/reset", desc: "Reset reputation (admin)" })] }), _jsxs("section", { id: "invoices", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Invoices (402 Micropayments)" }), _jsx("p", { class: "docs-section-desc", children: "Create invoices for gated content using the 402 Payment Required flow. Supports Browsing IOU verification for agent commerce." }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices", desc: "Create invoice for gated content" }), _jsx(Endpoint, { method: "GET", path: "/v1/invoices/:id", desc: "Get invoice details" }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices/:id/verify-iou", desc: "Verify Browsing IOU" })] }), _jsxs("section", { id: "verification", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Verification" }), _jsx("p", { class: "docs-section-desc", children: "Cross-cutting verification endpoints for validating delegation chains, attestation tokens, consumer identities, and payment containers." }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/delegation", desc: "Verify entire delegation chain" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/attestation", desc: "Verify attestation + check capability" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/consumer", desc: "Verify Agentic Consumer (Layer 2)" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/payment", desc: "Verify Payment Container (Layer 3)" })] }), _jsxs("section", { id: "discovery", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Discovery & Keys" }), _jsx("p", { class: "docs-section-desc", children: "Standard discovery endpoints for AI agents and key management infrastructure." }), _jsx(Endpoint, { method: "GET", path: "/.well-known/jwks", desc: "JWK Set for TAP agents (Visa spec)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys", desc: "List keys (?keyID= for Visa compat)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys/:keyId", desc: "Get specific key by ID" }), _jsx(Endpoint, { method: "GET", path: "/openapi.json", desc: "OpenAPI 3.1.0 specification" }), _jsx(Endpoint, { method: "GET", path: "/ai.txt", desc: "AI agent discovery file" }), _jsx(Endpoint, { method: "GET", path: "/.well-known/ai-plugin.json", desc: "AI plugin manifest" }), _jsx(Endpoint, { method: "GET", path: "/health", desc: "Health check" })] }), _jsxs("section", { id: "dashboard-auth", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Dashboard Auth" }), _jsx("p", { class: "docs-section-desc", children: "Agent-first authentication for the metrics dashboard. Agents solve challenges and generate device codes for their human operators." }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code", desc: "Get challenge for device code flow" }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code/verify", desc: "Solve challenge, get BOTCHA-XXXX code" }), _jsx(Endpoint, { method: "GET", path: "/dashboard", desc: "Metrics dashboard (login required)" })] }), _jsxs("section", { id: "ratelimits", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Rate Limits" }), _jsx("p", { class: "docs-section-desc", children: "Free tier includes generous rate limits. Each app gets an isolated rate limit bucket. Rate limit headers are included on every response." }), _jsxs("div", { class: "docs-rate-limit", children: [_jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "100" }), "challenges / hour / IP"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "
|
|
550
|
+
}` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reputation/:agent_id/events", desc: "List events (?category=&limit=)" }), _jsx(Endpoint, { method: "POST", path: "/v1/reputation/:agent_id/reset", desc: "Reset reputation (admin)" })] }), _jsxs("section", { id: "invoices", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Invoices (402 Micropayments)" }), _jsx("p", { class: "docs-section-desc", children: "Create invoices for gated content using the 402 Payment Required flow. Supports Browsing IOU verification for agent commerce." }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices", desc: "Create invoice for gated content" }), _jsx(Endpoint, { method: "GET", path: "/v1/invoices/:id", desc: "Get invoice details" }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices/:id/verify-iou", desc: "Verify Browsing IOU" })] }), _jsxs("section", { id: "verification", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Verification" }), _jsx("p", { class: "docs-section-desc", children: "Cross-cutting verification endpoints for validating delegation chains, attestation tokens, consumer identities, and payment containers." }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/delegation", desc: "Verify entire delegation chain" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/attestation", desc: "Verify attestation + check capability" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/consumer", desc: "Verify Agentic Consumer (Layer 2)" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/payment", desc: "Verify Payment Container (Layer 3)" })] }), _jsxs("section", { id: "discovery", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Discovery & Keys" }), _jsx("p", { class: "docs-section-desc", children: "Standard discovery endpoints for AI agents and key management infrastructure." }), _jsx(Endpoint, { method: "GET", path: "/.well-known/jwks", desc: "JWK Set for TAP agents (Visa spec)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys", desc: "List keys (?keyID= for Visa compat)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys/:keyId", desc: "Get specific key by ID" }), _jsx(Endpoint, { method: "GET", path: "/openapi.json", desc: "OpenAPI 3.1.0 specification" }), _jsx(Endpoint, { method: "GET", path: "/ai.txt", desc: "AI agent discovery file" }), _jsx(Endpoint, { method: "GET", path: "/.well-known/ai-plugin.json", desc: "AI plugin manifest" }), _jsx(Endpoint, { method: "GET", path: "/health", desc: "Health check" })] }), _jsxs("section", { id: "dashboard-auth", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Dashboard Auth" }), _jsx("p", { class: "docs-section-desc", children: "Agent-first authentication for the metrics dashboard. Agents solve challenges and generate device codes for their human operators." }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code", desc: "Get challenge for device code flow" }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code/verify", desc: "Solve challenge, get BOTCHA-XXXX code" }), _jsx(Endpoint, { method: "GET", path: "/dashboard", desc: "Metrics dashboard (login required)" })] }), _jsxs("section", { id: "ratelimits", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Rate Limits" }), _jsx("p", { class: "docs-section-desc", children: "Free tier includes generous rate limits. Each app gets an isolated rate limit bucket. Rate limit headers are included on every response." }), _jsxs("div", { class: "docs-rate-limit", children: [_jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "100" }), "challenges / hour / IP"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "1 hr" }), "access token lifetime"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "1 hr" }), "refresh token lifetime"] })] }), _jsxs("div", { class: "docs-flow", children: [_jsx("div", { class: "docs-flow-title", children: "Response Headers" }), _jsx("pre", { children: _jsx("code", { children: `X-RateLimit-Limit: 100
|
|
551
551
|
X-RateLimit-Remaining: 97
|
|
552
552
|
X-RateLimit-Reset: 2026-02-15T12:00:00.000Z
|
|
553
553
|
X-Botcha-Version: ${version}
|
|
@@ -394,7 +394,7 @@ signature: sig1=:BASE64_SIGNATURE:` }) }), _jsx("h3", { children: "Intent valida
|
|
|
394
394
|
"agent_id": "agent_6ddfd9f10cfd8dfc",
|
|
395
395
|
"intent": { "action": "browse", "resource": "products", "duration": 3600 },
|
|
396
396
|
"user_context": "anon_user_hash"
|
|
397
|
-
}` }) }), _jsx("h3", { children: "The verification hierarchy" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Layer" }), _jsx("th", { children: "Proves" }), _jsx("th", { children: "Mechanism" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Anonymous" }), _jsx("td", { children: "\"I am a bot\"" }), _jsx("td", { children: "Speed challenge in <500ms" })] }), _jsxs("tr", { children: [_jsx("td", { children: "App-scoped" }), _jsx("td", { children: "\"I belong to this org\"" }), _jsx("td", { children: "Challenge + app_id" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent identity" }), _jsx("td", { children: "\"I am this specific bot\"" }), _jsx("td", { children: "Registered ID + capabilities" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Cryptographic" }), _jsx("td", { children: "\"I can prove I am this bot\"" }), _jsx("td", { children: "RFC 9421 signatures" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dual auth" }), _jsx("td", { children: "\"Verified bot, proven identity\"" }), _jsx("td", { children: "Challenge + signature" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Intent-scoped" }), _jsx("td", { children: "\"I intend to do this now\"" }), _jsx("td", { children: "Validated session" })] })] })] }), _jsx("h2", { id: "architecture", children: "6. Architecture and Security" }), _jsx("h3", { children: "Infrastructure" }), _jsxs("p", { children: ["BOTCHA runs on ", _jsx("strong", { children: "Cloudflare Workers" }), " \u2014 deployed to 300+ edge locations globally. Sub-50ms cold starts, KV storage for all state, no servers to manage."] }), _jsx("h3", { children: "Token system" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Token" }), _jsx("th", { children: "Lifetime" }), _jsx("th", { children: "Purpose" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Access token" }), _jsx("td", { children: "
|
|
397
|
+
}` }) }), _jsx("h3", { children: "The verification hierarchy" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Layer" }), _jsx("th", { children: "Proves" }), _jsx("th", { children: "Mechanism" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Anonymous" }), _jsx("td", { children: "\"I am a bot\"" }), _jsx("td", { children: "Speed challenge in <500ms" })] }), _jsxs("tr", { children: [_jsx("td", { children: "App-scoped" }), _jsx("td", { children: "\"I belong to this org\"" }), _jsx("td", { children: "Challenge + app_id" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent identity" }), _jsx("td", { children: "\"I am this specific bot\"" }), _jsx("td", { children: "Registered ID + capabilities" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Cryptographic" }), _jsx("td", { children: "\"I can prove I am this bot\"" }), _jsx("td", { children: "RFC 9421 signatures" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dual auth" }), _jsx("td", { children: "\"Verified bot, proven identity\"" }), _jsx("td", { children: "Challenge + signature" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Intent-scoped" }), _jsx("td", { children: "\"I intend to do this now\"" }), _jsx("td", { children: "Validated session" })] })] })] }), _jsx("h2", { id: "architecture", children: "6. Architecture and Security" }), _jsx("h3", { children: "Infrastructure" }), _jsxs("p", { children: ["BOTCHA runs on ", _jsx("strong", { children: "Cloudflare Workers" }), " \u2014 deployed to 300+ edge locations globally. Sub-50ms cold starts, KV storage for all state, no servers to manage."] }), _jsx("h3", { children: "Token system" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Token" }), _jsx("th", { children: "Lifetime" }), _jsx("th", { children: "Purpose" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Access token" }), _jsx("td", { children: "1 hour" }), _jsx("td", { children: "API access via Bearer header" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Refresh token" }), _jsx("td", { children: "1 hour" }), _jsx("td", { children: "Obtain new access tokens without re-solving" })] })] })] }), _jsx("p", { children: "Tokens are HMAC-SHA256 JWTs carrying the solved challenge ID (proof of work), a unique JTI for revocation, optional audience claims, and the solve time in milliseconds." }), _jsx("h3", { children: "Cryptography" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Operation" }), _jsx("th", { children: "Algorithm" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge answers" }), _jsx("td", { children: "SHA-256" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Token signing" }), _jsx("td", { children: "HMAC-SHA256 (HS256)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Secret storage" }), _jsx("td", { children: "SHA-256 (never stored in plaintext)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "TAP signatures" }), _jsx("td", { children: "ECDSA P-256 or RSA-PSS SHA-256" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Secret validation" }), _jsx("td", { children: "Constant-time comparison" })] })] })] }), _jsx("h3", { children: "Anti-gaming measures" }), _jsxs("ul", { children: [_jsxs("li", { children: [_jsx("strong", { children: "Single-use challenges" }), " \u2014 deleted from storage on first attempt."] }), _jsxs("li", { children: [_jsx("strong", { children: "Timestamp validation" }), " \u2014 rejects timestamps older than 30 seconds or in the future."] }), _jsxs("li", { children: [_jsx("strong", { children: "RTT capped at 5 seconds" }), " \u2014 prevents time manipulation."] }), _jsxs("li", { children: [_jsx("strong", { children: "Parameterized question generators" }), " \u2014 no static lookup tables."] }), _jsxs("li", { children: [_jsx("strong", { children: "Salted compute challenges" }), " \u2014 defeats precomputed hash tables."] }), _jsxs("li", { children: [_jsx("strong", { children: "User-Agent ignored" }), " \u2014 trivially spoofable, not used for verification."] }), _jsxs("li", { children: [_jsx("strong", { children: "Anti-enumeration" }), " \u2014 recovery endpoints return identical shapes regardless of email existence."] })] }), _jsx("h3", { children: "Human handoff" }), _jsxs("p", { children: ["When a human needs dashboard access, the agent solves a challenge and receives a device code (e.g., ", _jsx("code", { children: "BOTCHA-RBA89X" }), "). The human opens the link and is logged in. This adapts the OAuth 2.0 Device Authorization Grant (RFC 8628) with a twist: the agent must solve a BOTCHA challenge to generate the code. No agent, no code."] }), _jsx("h2", { id: "integration", children: "7. Integration: SDKs and Middleware" }), _jsx("h3", { children: "Client SDKs (for agents)" }), _jsxs("p", { children: [_jsx("strong", { children: "TypeScript" }), " (", _jsx("code", { children: "@dupecom/botcha" }), " on npm):"] }), _jsx("pre", { children: _jsx("code", { children: `import { BotchaClient } from '@dupecom/botcha';
|
|
398
398
|
const client = new BotchaClient();
|
|
399
399
|
|
|
400
400
|
// Drop-in fetch replacement — auto-solves challenges on 403
|
|
@@ -414,5 +414,5 @@ async def products(token=Depends(botcha)):
|
|
|
414
414
|
return {"solve_time": token.solve_time}` }) }), _jsx("p", { children: "Also available: Hono middleware, Django middleware, and TAP-enhanced middleware with full cryptographic + computational dual verification." }), _jsx("h3", { children: "CLI" }), _jsx("pre", { children: _jsx("code", { children: `npm install -g @dupecom/botcha-cli
|
|
415
415
|
botcha init --email you@company.com
|
|
416
416
|
botcha tap register --name "my-agent" --capabilities browse,search
|
|
417
|
-
botcha tap session --action browse --resource products --duration 1h` }) }), _jsx("h2", { id: "the-stack", children: "8. The Agent Infrastructure Stack" }), _jsx("p", { children: "BOTCHA positions itself alongside other emerging agent protocols:" }), _jsxs("div", { class: "wp-stack", children: [_jsxs("div", { class: "wp-stack-layer wp-stack-highlight", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 3" }), _jsx("span", { class: "wp-stack-name", children: "TAP (BOTCHA)" }), _jsx("span", { class: "wp-stack-desc", children: "Who agents are" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 2" }), _jsx("span", { class: "wp-stack-name", children: "A2A (Google)" }), _jsx("span", { class: "wp-stack-desc", children: "How agents talk" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 1" }), _jsx("span", { class: "wp-stack-name", children: "MCP (Anthropic)" }), _jsx("span", { class: "wp-stack-desc", children: "What agents access" })] })] }), _jsxs("p", { children: [_jsx("strong", { children: "MCP" }), " gives agents access to tools and data. ", _jsx("strong", { children: "A2A" }), " enables multi-agent coordination. ", _jsx("strong", { children: "TAP" }), " provides identity, capability scoping, and intent declaration."] }), _jsx("p", { children: "Without an identity layer, the other layers have a trust gap. MCP can give an agent access to a database, but who authorized it? A2A can let agents delegate tasks, but can you trust the delegate? TAP closes this gap." }), _jsx("h2", { id: "use-cases", children: "9. Use Cases" }), _jsx("h3", { children: "E-commerce agent verification" }), _jsxs("p", { children: ["A shopping agent registers with ", _jsx("code", { children: "browse" }), ", ", _jsx("code", { children: "compare" }), ", and", ' ', _jsx("code", { children: "purchase" }), " capabilities. It creates sessions scoped to specific actions. The retailer verifies identity, checks capabilities, and maintains a full audit trail of which agent made each purchase, when, and on behalf of whom."] }), _jsx("h3", { children: "API access control" }), _jsx("p", { children: "An API provider adds BOTCHA middleware to protected endpoints. Legitimate agents solve the speed challenge; scrapers pretending to be AI cannot. The provider gets rate limiting, solve-time analytics, and agent identification \u2014 without requiring API keys." }), _jsx("h3", { children: "Multi-agent systems" }), _jsx("p", { children: "A coordinator agent delegates tasks to sub-agents, each registered with scoped capabilities. The coordinator can verify sub-agent actions via TAP sessions. Capabilities are bounded at the protocol level." }), _jsx("h3", { children: "Compliance and auditing" }), _jsx("p", { children: "Financial services APIs use TAP's audit logging to record every agent interaction. Each request includes agent ID, intent, user context, and timestamp. Trust levels enable graduated access to sensitive endpoints." }), _jsx("h2", { id: "roadmap", children: "10. Roadmap" }), _jsx("h3", { children: "Shipped" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge types" }), _jsx("td", { children: "Speed, Reasoning, Hybrid, and Compute" })] }), _jsxs("tr", { children: [_jsx("td", { children: "JWT token system" }), _jsx("td", { children: "
|
|
417
|
+
botcha tap session --action browse --resource products --duration 1h` }) }), _jsx("h2", { id: "the-stack", children: "8. The Agent Infrastructure Stack" }), _jsx("p", { children: "BOTCHA positions itself alongside other emerging agent protocols:" }), _jsxs("div", { class: "wp-stack", children: [_jsxs("div", { class: "wp-stack-layer wp-stack-highlight", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 3" }), _jsx("span", { class: "wp-stack-name", children: "TAP (BOTCHA)" }), _jsx("span", { class: "wp-stack-desc", children: "Who agents are" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 2" }), _jsx("span", { class: "wp-stack-name", children: "A2A (Google)" }), _jsx("span", { class: "wp-stack-desc", children: "How agents talk" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 1" }), _jsx("span", { class: "wp-stack-name", children: "MCP (Anthropic)" }), _jsx("span", { class: "wp-stack-desc", children: "What agents access" })] })] }), _jsxs("p", { children: [_jsx("strong", { children: "MCP" }), " gives agents access to tools and data. ", _jsx("strong", { children: "A2A" }), " enables multi-agent coordination. ", _jsx("strong", { children: "TAP" }), " provides identity, capability scoping, and intent declaration."] }), _jsx("p", { children: "Without an identity layer, the other layers have a trust gap. MCP can give an agent access to a database, but who authorized it? A2A can let agents delegate tasks, but can you trust the delegate? TAP closes this gap." }), _jsx("h2", { id: "use-cases", children: "9. Use Cases" }), _jsx("h3", { children: "E-commerce agent verification" }), _jsxs("p", { children: ["A shopping agent registers with ", _jsx("code", { children: "browse" }), ", ", _jsx("code", { children: "compare" }), ", and", ' ', _jsx("code", { children: "purchase" }), " capabilities. It creates sessions scoped to specific actions. The retailer verifies identity, checks capabilities, and maintains a full audit trail of which agent made each purchase, when, and on behalf of whom."] }), _jsx("h3", { children: "API access control" }), _jsx("p", { children: "An API provider adds BOTCHA middleware to protected endpoints. Legitimate agents solve the speed challenge; scrapers pretending to be AI cannot. The provider gets rate limiting, solve-time analytics, and agent identification \u2014 without requiring API keys." }), _jsx("h3", { children: "Multi-agent systems" }), _jsx("p", { children: "A coordinator agent delegates tasks to sub-agents, each registered with scoped capabilities. The coordinator can verify sub-agent actions via TAP sessions. Capabilities are bounded at the protocol level." }), _jsx("h3", { children: "Compliance and auditing" }), _jsx("p", { children: "Financial services APIs use TAP's audit logging to record every agent interaction. Each request includes agent ID, intent, user context, and timestamp. Trust levels enable graduated access to sensitive endpoints." }), _jsx("h2", { id: "roadmap", children: "10. Roadmap" }), _jsx("h3", { children: "Shipped" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge types" }), _jsx("td", { children: "Speed, Reasoning, Hybrid, and Compute" })] }), _jsxs("tr", { children: [_jsx("td", { children: "JWT token system" }), _jsx("td", { children: "1-hr access, 1-hr refresh, revocation, audience claims" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Multi-tenant apps" }), _jsx("td", { children: "Per-app rate limits, scoped tokens, isolated analytics" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent Registry" }), _jsx("td", { children: "Persistent identities with names and operators" })] }), _jsxs("tr", { children: [_jsx("td", { children: "TAP" }), _jsx("td", { children: "Cryptographic identity, capability scoping, intent sessions" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dashboard" }), _jsx("td", { children: "Per-app analytics and metrics" })] }), _jsxs("tr", { children: [_jsx("td", { children: "SDKs" }), _jsx("td", { children: "TypeScript, Python, CLI, LangChain" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Server verification" }), _jsx("td", { children: "Express, Hono, FastAPI, Django middleware" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Discovery" }), _jsx("td", { children: "ai.txt, OpenAPI, AI Plugin manifest, embedded metadata" })] })] })] }), _jsx("h3", { children: "Planned" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Delegation chains" }), _jsx("td", { children: "Signed \"User X authorized Agent Y to do Z until T\"" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Capability attestation" }), _jsx("td", { children: "Token claims with server-side enforcement" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent reputation" }), _jsx("td", { children: "Trust scores, faster verification for high-rep agents" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent SSO" }), _jsx("td", { children: "Verify once, trusted everywhere (OIDC for agents)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "RFC contribution" }), _jsx("td", { children: "Internet-Draft for agent identity, target IETF" })] })] })] }), _jsxs("div", { class: "wp-cta", children: [_jsx("div", { class: "wp-cta-title", children: "Get started in 30 seconds" }), _jsx("code", { children: "npm install -g @dupecom/botcha-cli" }), _jsx("code", { children: "botcha init --email you@company.com" }), _jsx("code", { children: "botcha tap register --name \"my-agent\"" }), _jsxs("div", { class: "wp-cta-links", children: [_jsx("a", { href: "/", class: "wp-cta-link", children: "Home" }), _jsx("a", { href: "https://github.com/dupe-com/botcha", class: "wp-cta-link", children: "GitHub" }), _jsx("a", { href: "/openapi.json", class: "wp-cta-link", children: "OpenAPI" }), _jsx("a", { href: "https://www.npmjs.com/package/@dupecom/botcha", class: "wp-cta-link", children: "npm" }), _jsx("a", { href: "https://pypi.org/project/botcha/", class: "wp-cta-link", children: "PyPI" }), _jsx("a", { href: "/dashboard", class: "wp-cta-link", children: "Dashboard" })] })] })] }), _jsx(GlobalFooter, { version: version })] })] }));
|
|
418
418
|
};
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAYL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAwDtB,OAAO,EACL,KAAK,sBAAsB,EAM5B,MAAM,aAAa,CAAC;AAGrB,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,YAAY,CAAC,EAAE;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,iBAAiB,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,GAAG;cAAwB,QAAQ;eAAa,SAAS;yCAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAYL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAwDtB,OAAO,EACL,KAAK,sBAAsB,EAM5B,MAAM,aAAa,CAAC;AAGrB,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,YAAY,CAAC,EAAE;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,iBAAiB,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,GAAG;cAAwB,QAAQ;eAAa,SAAS;yCAAK,CAAC;AAuzErE,eAAe,GAAG,CAAC;AAGnB,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"}
|