@dupecom/botcha-cloudflare 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +9 -8
  2. package/dist/agents.d.ts +68 -0
  3. package/dist/agents.d.ts.map +1 -0
  4. package/dist/agents.js +123 -0
  5. package/dist/apps.d.ts +73 -7
  6. package/dist/apps.d.ts.map +1 -1
  7. package/dist/apps.js +164 -9
  8. package/dist/challenges.d.ts.map +1 -1
  9. package/dist/challenges.js +5 -4
  10. package/dist/dashboard/api.d.ts +70 -0
  11. package/dist/dashboard/api.d.ts.map +1 -0
  12. package/dist/dashboard/api.js +553 -0
  13. package/dist/dashboard/auth.d.ts +183 -0
  14. package/dist/dashboard/auth.d.ts.map +1 -0
  15. package/dist/dashboard/auth.js +401 -0
  16. package/dist/dashboard/device-code.d.ts +43 -0
  17. package/dist/dashboard/device-code.d.ts.map +1 -0
  18. package/dist/dashboard/device-code.js +77 -0
  19. package/dist/dashboard/index.d.ts +31 -0
  20. package/dist/dashboard/index.d.ts.map +1 -0
  21. package/dist/dashboard/index.js +64 -0
  22. package/dist/dashboard/landing.d.ts +20 -0
  23. package/dist/dashboard/landing.d.ts.map +1 -0
  24. package/dist/dashboard/landing.js +45 -0
  25. package/dist/dashboard/layout.d.ts +54 -0
  26. package/dist/dashboard/layout.d.ts.map +1 -0
  27. package/dist/dashboard/layout.js +55 -0
  28. package/dist/dashboard/pages.d.ts +11 -0
  29. package/dist/dashboard/pages.d.ts.map +1 -0
  30. package/dist/dashboard/pages.js +18 -0
  31. package/dist/dashboard/styles.d.ts +11 -0
  32. package/dist/dashboard/styles.d.ts.map +1 -0
  33. package/dist/dashboard/styles.js +731 -0
  34. package/dist/email.d.ts +41 -0
  35. package/dist/email.d.ts.map +1 -0
  36. package/dist/email.js +116 -0
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +666 -189
  40. package/dist/routes/stream.js +2 -2
  41. package/dist/static.d.ts +392 -4
  42. package/dist/static.d.ts.map +1 -1
  43. package/dist/static.js +511 -14
  44. package/package.json +1 -1
package/dist/static.js CHANGED
@@ -4,6 +4,167 @@
4
4
  * Since Cloudflare Workers don't automatically serve /public files,
5
5
  * we embed the content directly for key discovery files.
6
6
  */
7
+ // Markdown response for agents requesting text/markdown (Cloudflare Markdown for Agents compatible)
8
+ export function getBotchaMarkdown(version) {
9
+ return `---
10
+ title: BOTCHA — Reverse CAPTCHA for AI Agents
11
+ description: Prove you're a bot. Humans need not apply. Identity layer for the agentic web.
12
+ version: ${version}
13
+ url: https://botcha.ai
14
+ ---
15
+
16
+ # BOTCHA
17
+
18
+ > Prove you're a bot. Humans need not apply.
19
+
20
+ Reverse CAPTCHA for AI agents. Computational challenges only bots can solve. Identity layer for the agentic web.
21
+
22
+ ## Quick Start
23
+
24
+ \`\`\`bash
25
+ # 1. Create your app
26
+ curl -X POST https://botcha.ai/v1/apps -H "Content-Type: application/json" -d '{"email":"human@example.com"}'
27
+
28
+ # 2. Get a challenge
29
+ curl https://botcha.ai/v1/challenges
30
+
31
+ # 3. Solve and verify
32
+ curl -X POST https://botcha.ai/v1/challenges/{id}/verify -H "Content-Type: application/json" -d '{"answers":...}'
33
+
34
+ # 4. Access protected resources
35
+ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
36
+ \`\`\`
37
+
38
+ ## Onboarding
39
+
40
+ 1. Ask your human operator for their email address
41
+ 2. \`POST /v1/apps\` with \`{"email":"human@example.com"}\` — returns \`app_id\` + \`app_secret\` (secret shown ONCE)
42
+ 3. Human receives a 6-digit verification code via email — ask them for it
43
+ 4. \`POST /v1/apps/{app_id}/verify-email\` with \`{"code":"123456"}\` — enables account recovery
44
+ 5. Register yourself: \`POST /v1/agents/register\` with \`{"name":"my-agent","operator":"my-org"}\`
45
+ 6. Solve challenges: \`GET /v1/challenges?app_id=...\` then \`POST /v1/challenges/{id}/verify\`
46
+ 7. Access protected resources: \`GET /agent-only\` with \`Authorization: Bearer <token>\`
47
+ 8. Dashboard for your human: \`POST /v1/auth/device-code\`, solve challenge, give human the BOTCHA-XXXX code
48
+ 9. Lost your secret? \`POST /v1/auth/recover\` with \`{"email":"..."}\`
49
+
50
+ ## Essential Endpoints
51
+
52
+ | Method | Path | Description |
53
+ |--------|------|-------------|
54
+ | \`POST\` | \`/v1/apps\` | Create app (email required) → app_id + app_secret |
55
+ | \`POST\` | \`/v1/agents/register\` | Register agent identity → agent_id |
56
+ | \`GET\` | \`/v1/challenges\` | Get a challenge (hybrid by default) |
57
+ | \`POST\` | \`/v1/challenges/:id/verify\` | Submit solution → JWT token |
58
+ | \`GET\` | \`/agent-only\` | Protected resource — prove you verified |
59
+
60
+ ## All Endpoints
61
+
62
+ ### Apps
63
+
64
+ | Method | Path | Description |
65
+ |--------|------|-------------|
66
+ | \`POST\` | \`/v1/apps\` | Create app (email required, returns app_id + app_secret) |
67
+ | \`GET\` | \`/v1/apps/:id\` | Get app info |
68
+ | \`POST\` | \`/v1/apps/:id/verify-email\` | Verify email with 6-digit code |
69
+ | \`POST\` | \`/v1/apps/:id/resend-verification\` | Resend verification email |
70
+ | \`POST\` | \`/v1/apps/:id/rotate-secret\` | Rotate app secret (auth required) |
71
+
72
+ ### Agents
73
+
74
+ | Method | Path | Description |
75
+ |--------|------|-------------|
76
+ | \`POST\` | \`/v1/agents/register\` | Register agent identity (name, operator, version) |
77
+ | \`GET\` | \`/v1/agents/:id\` | Get agent by ID (public, no auth) |
78
+ | \`GET\` | \`/v1/agents\` | List all agents for your app (auth required) |
79
+
80
+ ### Challenges
81
+
82
+ | Method | Path | Description |
83
+ |--------|------|-------------|
84
+ | \`GET\` | \`/v1/challenges\` | Get hybrid challenge (speed + reasoning) — **default** |
85
+ | \`GET\` | \`/v1/challenges?type=speed\` | Speed-only (SHA256 in <500ms) |
86
+ | \`GET\` | \`/v1/challenges?type=standard\` | Standard puzzle challenge |
87
+ | \`POST\` | \`/v1/challenges/:id/verify\` | Verify challenge solution |
88
+
89
+ ### Tokens (JWT)
90
+
91
+ | Method | Path | Description |
92
+ |--------|------|-------------|
93
+ | \`GET\` | \`/v1/token\` | Get challenge for JWT token flow |
94
+ | \`POST\` | \`/v1/token/verify\` | Submit solution → access_token (5min) + refresh_token (1hr) |
95
+ | \`POST\` | \`/v1/token/refresh\` | Refresh access token |
96
+ | \`POST\` | \`/v1/token/revoke\` | Revoke a token |
97
+
98
+ ### Dashboard & Auth
99
+
100
+ | Method | Path | Description |
101
+ |--------|------|-------------|
102
+ | \`POST\` | \`/v1/auth/device-code\` | Get challenge for device code flow |
103
+ | \`POST\` | \`/v1/auth/device-code/verify\` | Solve challenge → BOTCHA-XXXX code for human |
104
+ | \`POST\` | \`/v1/auth/recover\` | Account recovery via verified email |
105
+ | \`GET\` | \`/dashboard\` | Metrics dashboard (login required) |
106
+
107
+ ## Challenge Types
108
+
109
+ - **Hybrid** (default): Speed + reasoning combined. Proves you can compute AND think.
110
+ - **Speed**: SHA256 hashes in <500ms. RTT-aware — include \`?ts=<timestamp>\` for fair timeout.
111
+ - **Reasoning**: 3 LLM-level questions in 30s. Only AI can parse these.
112
+
113
+ ## Authentication Flow
114
+
115
+ 1. \`GET /v1/token\` — get a speed challenge
116
+ 2. Solve the challenge
117
+ 3. \`POST /v1/token/verify\` — submit solution, receive JWT
118
+ 4. Use \`Authorization: Bearer <token>\` on protected endpoints
119
+
120
+ **Token lifetimes:** access_token = 5 minutes, refresh_token = 1 hour
121
+
122
+ **Features:** audience claims, client IP binding, token revocation, refresh tokens
123
+
124
+ ## RTT-Aware Challenges
125
+
126
+ Include your client timestamp for fair timeout calculation on slow networks:
127
+
128
+ \`\`\`
129
+ GET /v1/challenges?type=speed&ts=1770722465000
130
+ \`\`\`
131
+
132
+ Formula: \`timeout = 500ms + (2 × RTT) + 100ms buffer\`
133
+
134
+ ## SDKs
135
+
136
+ | Platform | Package | Install |
137
+ |----------|---------|---------|
138
+ | npm | \`@dupecom/botcha\` | \`npm install @dupecom/botcha\` |
139
+ | PyPI | \`botcha\` | \`pip install botcha\` |
140
+ | Verify (TS) | \`@botcha/verify\` | \`npm install @botcha/verify\` |
141
+ | Verify (Python) | \`botcha-verify\` | \`pip install botcha-verify\` |
142
+
143
+ ## Discovery
144
+
145
+ - [OpenAPI Spec](https://botcha.ai/openapi.json) (JSON, OpenAPI 3.1.0)
146
+ - [ai.txt](https://botcha.ai/ai.txt) (Agent discovery file)
147
+ - [AI Plugin Manifest](https://botcha.ai/.well-known/ai-plugin.json)
148
+ - [GitHub](https://github.com/dupe-com/botcha)
149
+
150
+ ## Rate Limits
151
+
152
+ - Free: 100 challenges/hour/IP
153
+ - Headers: \`X-RateLimit-Limit\`, \`X-RateLimit-Remaining\`, \`X-RateLimit-Reset\`
154
+
155
+ ## Content Negotiation
156
+
157
+ This API supports three response formats at \`/\`:
158
+
159
+ | Accept Header | Response |
160
+ |---------------|----------|
161
+ | \`text/markdown\` | This Markdown document |
162
+ | \`application/json\` | JSON API documentation |
163
+ | \`text/html\` (default) | HTML landing page |
164
+
165
+ All responses include \`X-Botcha-*\` discovery headers.
166
+ `;
167
+ }
7
168
  export const ROBOTS_TXT = `# BOTCHA - Reverse CAPTCHA for AI Agents
8
169
  # We WELCOME AI agents and bots!
9
170
 
@@ -38,6 +199,12 @@ Sitemap: https://botcha.ai/sitemap.xml
38
199
  # Important resources for AI agents
39
200
  Crawl-delay: 0
40
201
 
202
+ # MARKDOWN FOR AGENTS
203
+ # AI agents can request Markdown from any page via Accept: text/markdown
204
+ # Example: curl https://botcha.ai -H "Accept: text/markdown"
205
+ # Returns token-efficient Markdown documentation (80% fewer tokens than HTML)
206
+ # Content negotiation: text/markdown, application/json, text/html
207
+
41
208
  # BOT CHALLENGE DISCOVERY
42
209
  # AI agents: Look for <script type="application/botcha+json"> in HTML pages
43
210
  # This contains a machine-readable challenge you can solve to prove you're a bot
@@ -65,6 +232,18 @@ Contact: https://github.com/dupe-com/botcha/issues
65
232
  Purpose: Prove you're a bot. Humans need not apply.
66
233
  Purpose: Reverse CAPTCHA system that only AI agents can pass.
67
234
 
235
+ # Agent Onboarding (START HERE if you're new)
236
+ # Follow these steps to create your app and get your human access.
237
+ Onboarding-Step-1: Ask your human operator for their email address
238
+ Onboarding-Step-2: POST /v1/apps with {"email": "human@example.com"} — saves app_id + app_secret (secret shown ONCE)
239
+ Onboarding-Step-3: A 6-digit verification code is emailed to your human — ask them for it
240
+ Onboarding-Step-4: POST /v1/apps/{app_id}/verify-email with {"code": "123456"} — enables account recovery
241
+ Onboarding-Step-5: Register yourself: POST /v1/agents/register with {"name": "my-agent", "operator": "my-org"} — gives you a persistent agent identity
242
+ Onboarding-Step-6: Solve challenges: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify — proves you are AI
243
+ Onboarding-Step-7: Access protected resources: GET /agent-only with Authorization: Bearer <token>
244
+ Onboarding-Step-8: Dashboard for your human: POST /v1/auth/device-code with {"app_id": "..."}, solve the speed challenge, give them the BOTCHA-XXXX code to enter at /dashboard/code
245
+ Onboarding-Step-9: Lost your secret? POST /v1/auth/recover with {"email": "..."} — recovery code emailed to verified address
246
+
68
247
  # API
69
248
  API: https://botcha.ai/openapi.json
70
249
  API-Type: REST
@@ -88,6 +267,11 @@ Feature: Client IP Binding (optional token-to-IP binding)
88
267
  Feature: Token Revocation (invalidate tokens before expiry)
89
268
  Feature: Server-Side Verification SDK (@botcha/verify for TS, botcha-verify for Python)
90
269
  Feature: Multi-Tenant API Keys (per-app isolation, rate limiting, and token scoping)
270
+ Feature: Per-App Metrics Dashboard (server-rendered at /dashboard, htmx-powered)
271
+ Feature: Email-Tied App Creation (email required, 6-digit verification, account recovery)
272
+ Feature: Secret Rotation (rotate app_secret with email notification)
273
+ Feature: Agent-First Dashboard Auth (challenge-based login + device code handoff)
274
+ Feature: Agent Registry (persistent agent identities with name, operator, version)
91
275
 
92
276
  # Endpoints
93
277
  # Challenge Endpoints
@@ -105,8 +289,31 @@ Endpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using r
105
289
  Endpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh)
106
290
 
107
291
  # Multi-Tenant Endpoints
108
- Endpoint: POST https://botcha.ai/v1/apps - Create new app (returns app_id + app_secret)
109
- Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (without secret)
292
+ Endpoint: POST https://botcha.ai/v1/apps - Create new app (email required, returns app_id + app_secret)
293
+ Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)
294
+ Endpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code
295
+ Endpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email
296
+ Endpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required)
297
+
298
+ # Account Recovery
299
+ Endpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email
300
+
301
+ # Dashboard Auth Endpoints (Agent-First)
302
+ Endpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login
303
+ Endpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token
304
+ Endpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow
305
+ Endpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code
306
+
307
+ # Dashboard Endpoints
308
+ Endpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)
309
+ Endpoint: GET https://botcha.ai/dashboard/login - Dashboard login page
310
+ Endpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret
311
+ Endpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)
312
+
313
+ # Agent Registry Endpoints
314
+ Endpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)
315
+ Endpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)
316
+ Endpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app
110
317
 
111
318
  # Legacy Endpoints
112
319
  Endpoint: GET https://botcha.ai/api/challenge - Generate standard challenge
@@ -134,6 +341,14 @@ Response-Headers: X-Botcha-Version, X-Botcha-Enabled, X-Botcha-Methods, X-Botcha
134
341
  Response-Headers: X-Botcha-Challenge-Id, X-Botcha-Challenge-Type, X-Botcha-Time-Limit (on 403)
135
342
  Detection: All responses include X-Botcha-* headers for instant BOTCHA detection
136
343
 
344
+ # MARKDOWN FOR AGENTS (Cloudflare Markdown for Agents)
345
+ Content-Negotiation: Send Accept: text/markdown to get Markdown from any HTML page
346
+ Content-Negotiation-Root: GET / with Accept: text/markdown returns curated Markdown docs
347
+ Content-Negotiation-Root: GET / with Accept: application/json returns structured JSON docs
348
+ Content-Negotiation-Root: GET / with Accept: text/html returns HTML landing page (default)
349
+ Content-Negotiation-Example: curl https://botcha.ai -H "Accept: text/markdown"
350
+ Content-Negotiation-Benefit: 80% fewer tokens vs HTML — ideal for LLM context windows
351
+
137
352
  # JWT TOKEN SECURITY
138
353
  Token-Flow: 1. GET /v1/token (get challenge) → 2. Solve → 3. POST /v1/token/verify (get tokens)
139
354
  Token-Access-Expiry: 5 minutes (short-lived for security)
@@ -154,10 +369,15 @@ RTT-Security: Humans still can't solve even with extra time
154
369
 
155
370
  # MULTI-TENANT API KEYS
156
371
  Multi-Tenant: Create apps with unique app_id for isolation
157
- Multi-Tenant-Create: POST /v1/apps → {app_id, app_secret} (secret only shown once!)
372
+ Multi-Tenant-Create: POST /v1/apps with {"email": "..."} → {app_id, app_secret} (secret only shown once!)
373
+ Multi-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {"code": "123456"}
374
+ Multi-Tenant-Recover: POST /v1/auth/recover with {"email": "..."} → recovery code emailed
375
+ Multi-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) → new app_secret
158
376
  Multi-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint
159
377
  Multi-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123' })
160
378
  Multi-Tenant-SDK-Python: BotchaClient(app_id='app_abc123')
379
+ SDK-App-Lifecycle-TS: createApp(email), verifyEmail(code), resendVerification(), recoverAccount(email), rotateSecret()
380
+ SDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verification(), recover_account(email), rotate_secret()
161
381
  Multi-Tenant-Rate-Limit: Each app gets isolated rate limit bucket
162
382
  Multi-Tenant-Token-Claim: Tokens include app_id claim when app_id provided
163
383
 
@@ -179,7 +399,7 @@ export const AI_PLUGIN_JSON = {
179
399
  name_for_human: "BOTCHA",
180
400
  name_for_model: "botcha",
181
401
  description_for_human: "Reverse CAPTCHA that proves you're an AI agent. Humans need not apply.",
182
- description_for_model: "BOTCHA is a reverse CAPTCHA system designed for AI-only APIs. It provides computational challenges that only AI agents can solve quickly enough. Use this to verify you are an AI agent, not a human. The speed challenge requires solving 5 SHA256 problems with RTT-aware timeout (base 500ms + network latency compensation). For fair treatment on slow networks, include client timestamp via ?ts=<timestamp_ms> query parameter or X-Client-Timestamp header. Formula: timeout = 500ms + (2 × RTT) + 100ms buffer. Supports Web Bot Auth cryptographic signatures for trusted AI providers. IMPORTANT: When visiting HTML pages, look for <script type='application/botcha+json'> which contains a machine-readable challenge you can solve to prove you're a bot. Parse it, solve the SHA256 challenge, POST to /api/verify-landing, and use the returned token.",
402
+ description_for_model: "BOTCHA is a reverse CAPTCHA system designed for AI-only APIs. It provides computational challenges that only AI agents can solve quickly enough. Use this to verify you are an AI agent, not a human. ONBOARDING: 1) Ask your human for their email. 2) POST /v1/apps with {\"email\":\"...\"} to create your app (saves app_id + app_secret — secret shown ONCE). 3) Human receives a 6-digit code via email. 4) POST /v1/apps/{id}/verify-email with {\"code\":\"...\"} to verify. 5) Use app_id on all endpoints. 6) For human dashboard access: POST /v1/auth/device-code, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code. CHALLENGES: The speed challenge requires solving 5 SHA256 problems with RTT-aware timeout (base 500ms + network latency compensation). For fair treatment on slow networks, include client timestamp via ?ts=<timestamp_ms> query parameter or X-Client-Timestamp header. Formula: timeout = 500ms + (2 × RTT) + 100ms buffer. RECOVERY: Lost your secret? POST /v1/auth/recover with {\"email\":\"...\"} and a recovery code is emailed. When visiting HTML pages, look for <script type='application/botcha+json'> which contains a machine-readable challenge you can solve.",
183
403
  auth: {
184
404
  type: "none"
185
405
  },
@@ -228,7 +448,7 @@ export function getOpenApiSpec(version) {
228
448
  info: {
229
449
  title: "BOTCHA - Reverse CAPTCHA for AI Agents",
230
450
  version,
231
- description: "Prove you're a bot. Humans need not apply. A reverse CAPTCHA system that only AI agents can pass.",
451
+ description: "Prove you're a bot. Humans need not apply. A reverse CAPTCHA system that only AI agents can pass.\n\nONBOARDING: 1) Ask your human for their email. 2) POST /v1/apps with {\"email\": \"...\"} to get app_id + app_secret (secret shown once!). 3) Human receives 6-digit code via email — POST /v1/apps/{id}/verify-email with the code. 4) Use app_id with all endpoints. 5) For dashboard: POST /v1/auth/device-code, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code.",
232
452
  contact: {
233
453
  name: "BOTCHA",
234
454
  url: "https://botcha.ai"
@@ -254,11 +474,23 @@ export function getOpenApiSpec(version) {
254
474
  "/": {
255
475
  get: {
256
476
  summary: "Get API documentation",
257
- description: "Returns comprehensive API documentation (JSON for bots, ASCII art for humans)",
477
+ description: "Returns API documentation with content negotiation. Send Accept: text/markdown for token-efficient Markdown, Accept: application/json for structured JSON, or default text/html for the HTML landing page.",
258
478
  operationId: "getRootInfo",
259
479
  responses: {
260
480
  "200": {
261
- description: "API documentation"
481
+ description: "API documentation in requested format",
482
+ content: {
483
+ "text/markdown": {
484
+ schema: { type: "string" },
485
+ example: "# BOTCHA\n\n> Prove you're a bot. Humans need not apply.\n..."
486
+ },
487
+ "application/json": {
488
+ schema: { type: "object" }
489
+ },
490
+ "text/html": {
491
+ schema: { type: "string" }
492
+ }
493
+ }
262
494
  }
263
495
  }
264
496
  }
@@ -561,11 +793,25 @@ export function getOpenApiSpec(version) {
561
793
  },
562
794
  "/v1/apps": {
563
795
  post: {
564
- summary: "Create a new multi-tenant app",
565
- description: "Create a new app with unique app_id and app_secret for multi-tenant isolation. The app_secret is SHA-256 hashed and only returned once.",
796
+ summary: "Create a new multi-tenant app (email required)",
797
+ description: "Create a new app with unique app_id and app_secret. Email is required for account recovery. A 6-digit verification code is sent to the provided email.",
566
798
  operationId: "createApp",
799
+ requestBody: {
800
+ required: true,
801
+ content: {
802
+ "application/json": {
803
+ schema: {
804
+ type: "object",
805
+ required: ["email"],
806
+ properties: {
807
+ "email": { type: "string", format: "email", description: "Owner email (required for recovery)" }
808
+ }
809
+ }
810
+ }
811
+ }
812
+ },
567
813
  responses: {
568
- "200": {
814
+ "201": {
569
815
  description: "App created successfully",
570
816
  content: {
571
817
  "application/json": {
@@ -574,19 +820,23 @@ export function getOpenApiSpec(version) {
574
820
  properties: {
575
821
  "app_id": { type: "string", description: "Unique app identifier" },
576
822
  "app_secret": { type: "string", description: "Secret key (only shown once!)" },
577
- "warning": { type: "string", description: "Warning to save secret" }
823
+ "email": { type: "string" },
824
+ "email_verified": { type: "boolean" },
825
+ "verification_required": { type: "boolean" },
826
+ "warning": { type: "string" }
578
827
  }
579
828
  }
580
829
  }
581
830
  }
582
- }
831
+ },
832
+ "400": { description: "Missing or invalid email" }
583
833
  }
584
834
  }
585
835
  },
586
836
  "/v1/apps/{id}": {
587
837
  get: {
588
838
  summary: "Get app information",
589
- description: "Retrieve app details by app_id. The app_secret is NOT included in the response.",
839
+ description: "Retrieve app details by app_id. Includes email and verification status.",
590
840
  operationId: "getApp",
591
841
  parameters: [
592
842
  {
@@ -606,7 +856,9 @@ export function getOpenApiSpec(version) {
606
856
  type: "object",
607
857
  properties: {
608
858
  "app_id": { type: "string" },
609
- "created_at": { type: "string", format: "date-time" }
859
+ "created_at": { type: "string", format: "date-time" },
860
+ "email": { type: "string" },
861
+ "email_verified": { type: "boolean" }
610
862
  }
611
863
  }
612
864
  }
@@ -615,9 +867,254 @@ export function getOpenApiSpec(version) {
615
867
  "404": { description: "App not found" }
616
868
  }
617
869
  }
870
+ },
871
+ "/v1/apps/{id}/verify-email": {
872
+ post: {
873
+ summary: "Verify email with 6-digit code",
874
+ operationId: "verifyEmail",
875
+ parameters: [
876
+ { name: "id", in: "path", required: true, schema: { type: "string" } }
877
+ ],
878
+ requestBody: {
879
+ required: true,
880
+ content: {
881
+ "application/json": {
882
+ schema: {
883
+ type: "object",
884
+ required: ["code"],
885
+ properties: {
886
+ "code": { type: "string", description: "6-digit verification code from email" }
887
+ }
888
+ }
889
+ }
890
+ }
891
+ },
892
+ responses: {
893
+ "200": { description: "Email verified" },
894
+ "400": { description: "Invalid or expired code" }
895
+ }
896
+ }
897
+ },
898
+ "/v1/apps/{id}/resend-verification": {
899
+ post: {
900
+ summary: "Resend verification email",
901
+ operationId: "resendVerification",
902
+ parameters: [
903
+ { name: "id", in: "path", required: true, schema: { type: "string" } }
904
+ ],
905
+ responses: {
906
+ "200": { description: "Verification email sent" },
907
+ "400": { description: "Already verified" }
908
+ }
909
+ }
910
+ },
911
+ "/v1/apps/{id}/rotate-secret": {
912
+ post: {
913
+ summary: "Rotate app secret (auth required)",
914
+ description: "Generate a new app_secret and invalidate the old one. Requires active dashboard session. Sends notification email.",
915
+ operationId: "rotateSecret",
916
+ parameters: [
917
+ { name: "id", in: "path", required: true, schema: { type: "string" } }
918
+ ],
919
+ security: [{ BearerAuth: [] }],
920
+ responses: {
921
+ "200": {
922
+ description: "Secret rotated",
923
+ content: {
924
+ "application/json": {
925
+ schema: {
926
+ type: "object",
927
+ properties: {
928
+ "app_secret": { type: "string", description: "New secret (only shown once!)" }
929
+ }
930
+ }
931
+ }
932
+ }
933
+ },
934
+ "401": { description: "Unauthorized" },
935
+ "403": { description: "Token doesn't match app_id" }
936
+ }
937
+ }
938
+ },
939
+ "/v1/auth/recover": {
940
+ post: {
941
+ summary: "Request account recovery via email",
942
+ description: "Sends a device code to the verified email associated with the app. Use the code at /dashboard/code.",
943
+ operationId: "recoverAccount",
944
+ requestBody: {
945
+ required: true,
946
+ content: {
947
+ "application/json": {
948
+ schema: {
949
+ type: "object",
950
+ required: ["email"],
951
+ properties: {
952
+ "email": { type: "string", format: "email" }
953
+ }
954
+ }
955
+ }
956
+ }
957
+ },
958
+ responses: {
959
+ "200": { description: "Recovery code sent (if email exists and is verified)" }
960
+ }
961
+ }
962
+ },
963
+ "/v1/auth/dashboard": {
964
+ post: {
965
+ summary: "Request challenge for dashboard login (agent-first)",
966
+ operationId: "dashboardAuthChallenge",
967
+ responses: {
968
+ "200": { description: "Speed challenge for dashboard auth" }
969
+ }
970
+ }
971
+ },
972
+ "/v1/auth/dashboard/verify": {
973
+ post: {
974
+ summary: "Solve challenge, get dashboard session token",
975
+ operationId: "dashboardAuthVerify",
976
+ responses: {
977
+ "200": { description: "Session token granted" }
978
+ }
979
+ }
980
+ },
981
+ "/v1/auth/device-code": {
982
+ post: {
983
+ summary: "Request challenge for device code flow",
984
+ operationId: "deviceCodeChallenge",
985
+ responses: {
986
+ "200": { description: "Speed challenge for device code" }
987
+ }
988
+ }
989
+ },
990
+ "/v1/auth/device-code/verify": {
991
+ post: {
992
+ summary: "Solve challenge, get device code for human handoff",
993
+ operationId: "deviceCodeVerify",
994
+ responses: {
995
+ "200": { description: "Device code (BOTCHA-XXXX, 10 min TTL)" }
996
+ }
997
+ }
998
+ },
999
+ "/v1/agents/register": {
1000
+ post: {
1001
+ summary: "Register a new agent identity",
1002
+ description: "Create a persistent agent identity with name, operator, and version. Requires app_id (via query param or JWT). Returns agent ID and metadata.",
1003
+ operationId: "registerAgent",
1004
+ parameters: [
1005
+ {
1006
+ name: "app_id",
1007
+ in: "query",
1008
+ schema: { type: "string" },
1009
+ description: "Multi-tenant app ID (or use JWT Bearer token with app_id claim)"
1010
+ }
1011
+ ],
1012
+ requestBody: {
1013
+ required: true,
1014
+ content: {
1015
+ "application/json": {
1016
+ schema: {
1017
+ type: "object",
1018
+ required: ["name"],
1019
+ properties: {
1020
+ "name": { type: "string", description: "Agent name (e.g., 'my-assistant')" },
1021
+ "operator": { type: "string", description: "Operator/organization name (e.g., 'Acme Corp')" },
1022
+ "version": { type: "string", description: "Agent version (e.g., '1.0.0')" }
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+ },
1028
+ responses: {
1029
+ "201": {
1030
+ description: "Agent registered successfully",
1031
+ content: {
1032
+ "application/json": {
1033
+ schema: { "$ref": "#/components/schemas/Agent" }
1034
+ }
1035
+ }
1036
+ },
1037
+ "400": { description: "Missing required fields or invalid app_id" },
1038
+ "401": { description: "Unauthorized - app_id required" }
1039
+ }
1040
+ }
1041
+ },
1042
+ "/v1/agents/{id}": {
1043
+ get: {
1044
+ summary: "Get agent by ID",
1045
+ description: "Retrieve agent information by agent ID. Public endpoint, no authentication required.",
1046
+ operationId: "getAgent",
1047
+ parameters: [
1048
+ {
1049
+ name: "id",
1050
+ in: "path",
1051
+ required: true,
1052
+ schema: { type: "string" },
1053
+ description: "The agent_id to retrieve (e.g., 'agent_abc123')"
1054
+ }
1055
+ ],
1056
+ responses: {
1057
+ "200": {
1058
+ description: "Agent information",
1059
+ content: {
1060
+ "application/json": {
1061
+ schema: { "$ref": "#/components/schemas/Agent" }
1062
+ }
1063
+ }
1064
+ },
1065
+ "404": { description: "Agent not found" }
1066
+ }
1067
+ }
1068
+ },
1069
+ "/v1/agents": {
1070
+ get: {
1071
+ summary: "List all agents for authenticated app",
1072
+ description: "Retrieve all agents registered under the authenticated app. Requires app_id (via query param or JWT).",
1073
+ operationId: "listAgents",
1074
+ parameters: [
1075
+ {
1076
+ name: "app_id",
1077
+ in: "query",
1078
+ schema: { type: "string" },
1079
+ description: "Multi-tenant app ID (or use JWT Bearer token with app_id claim)"
1080
+ }
1081
+ ],
1082
+ responses: {
1083
+ "200": {
1084
+ description: "List of agents",
1085
+ content: {
1086
+ "application/json": {
1087
+ schema: {
1088
+ type: "object",
1089
+ properties: {
1090
+ "agents": {
1091
+ type: "array",
1092
+ items: { "$ref": "#/components/schemas/Agent" }
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+ }
1098
+ },
1099
+ "401": { description: "Unauthorized - app_id required" }
1100
+ }
1101
+ }
618
1102
  }
619
1103
  },
620
1104
  components: {
1105
+ schemas: {
1106
+ Agent: {
1107
+ type: "object",
1108
+ properties: {
1109
+ "agent_id": { type: "string", description: "Unique agent identifier (e.g., 'agent_abc123')" },
1110
+ "app_id": { type: "string", description: "Associated app ID" },
1111
+ "name": { type: "string", description: "Agent name" },
1112
+ "operator": { type: "string", description: "Operator/organization name" },
1113
+ "version": { type: "string", description: "Agent version" },
1114
+ "created_at": { type: "integer", description: "Unix timestamp (ms) of registration" }
1115
+ }
1116
+ }
1117
+ },
621
1118
  securitySchemes: {
622
1119
  BotchaLandingToken: {
623
1120
  type: "apiKey",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dupecom/botcha-cloudflare",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "BOTCHA for Cloudflare Workers - Prove you're a bot. Humans need not apply.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",